This commit is contained in:
Your Name
2026-03-13 14:08:52 +08:00
parent 08dd9cd307
commit eb283f008b
667 changed files with 8425 additions and 27053 deletions
+187 -51
View File
@@ -25,6 +25,26 @@
</div>
</el-form-item>
<!-- 企业微信绑定 -->
<el-form-item label="企业微信:" v-if="wxWorkEnabled">
<div class="flex items-center gap-3">
<template v-if="formData.work_wechat_userid">
<el-tag type="success" size="large">
<el-icon class="mr-1"><CircleCheck /></el-icon>
已绑定{{ formData.work_wechat_userid }}
</el-tag>
<el-button type="danger" link @click="handleUnbind">解绑</el-button>
</template>
<template v-else>
<el-tag type="info" size="large">未绑定</el-tag>
<el-button type="primary" @click="showBindDialog">
<el-icon class="mr-1"><Connection /></el-icon>
扫码绑定
</el-button>
</template>
</div>
</el-form-item>
<el-form-item label="当前密码:" prop="password_old">
<div class="w-80">
<el-input
@@ -62,97 +82,213 @@
<footer-btns>
<el-button type="primary" @click="handleSubmit">保存</el-button>
</footer-btns>
<!-- 企业微信扫码绑定弹窗 -->
<el-dialog
v-model="bindDialogVisible"
title="扫码绑定企业微信"
width="440px"
:close-on-click-modal="false"
@close="onBindDialogClose"
>
<div class="bind-qrcode-wrap">
<div v-if="bindLoading" class="text-center py-8">
<el-icon class="is-loading" :size="36" color="var(--el-color-primary)">
<Loading />
</el-icon>
<div class="mt-3 text-gray-400">加载企业微信扫码...</div>
</div>
<div v-else id="bind_wxwork_qrcode" class="bind-qrcode"></div>
</div>
<div class="text-center text-sm text-gray-400 mt-2 mb-2">
请使用企业微信扫描二维码完成绑定
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="userSetting">
import type { FormInstance } from 'element-plus'
import { nextTick, onMounted, ref, reactive } from 'vue'
import { Loading, CircleCheck, Connection } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { setUserInfo } from '@/api/user'
import { setUserInfo, getWorkWechatConfig, bindWorkWechat, unbindWorkWechat } from '@/api/user'
import useUserStore from '@/stores/modules/user'
import feedback from '@/utils/feedback'
const formRef = ref<FormInstance>()
const userStore = useUserStore()
// 表单数据
const formData = reactive({
avatar: '', // 头像
account: '', // 账号
name: '', // 名称
password_old: '', // 当前密码
password: '', // 新的密码
password_confirm: '' // 确定密码
avatar: '',
account: '',
name: '',
work_wechat_userid: '',
password_old: '',
password: '',
password_confirm: ''
})
// 表单校验规则
const rules = reactive<object>({
avatar: [
{
required: true,
message: '头像不能为空',
trigger: ['change']
}
],
name: [
{
required: true,
message: '请输入名称',
trigger: ['blur']
}
]
avatar: [{ required: true, message: '头像不能为空', trigger: ['change'] }],
name: [{ required: true, message: '请输入名称', trigger: ['blur'] }]
})
// 企业微信相关
const wxWorkEnabled = ref(false)
const wxWorkConfig = ref<{ corp_id: string; agent_id: string }>({ corp_id: '', agent_id: '' })
const bindDialogVisible = ref(false)
const bindLoading = ref(false)
// 获取个人设置
const getUser = async () => {
const userInfo = userStore.userInfo
for (const key in formData) {
//@ts-ignore
formData[key] = userInfo[key]
if (userInfo[key] !== undefined) formData[key] = userInfo[key]
}
}
// 设置个人设置
const setUser = async () => {
if (formData.password_old || formData.password || formData.password_confirm) {
if (!formData.password_old) {
return feedback.msgError('请输入当前密码')
}
if (!formData.password) {
return feedback.msgError('请输入新的密码')
}
if (!formData.password_confirm) {
return feedback.msgError('请输入确定密码')
}
if (formData.password_confirm != formData.password) {
return feedback.msgError('两次输入的密码不一样')
}
if (!formData.password_old) return feedback.msgError('请输入当前密码')
if (!formData.password) return feedback.msgError('请输入新的密码')
if (!formData.password_confirm) return feedback.msgError('请输入确定密码')
if (formData.password_confirm != formData.password) return feedback.msgError('两次输入的密码不一样')
}
if (formData.password_old && formData.password && formData.password_confirm) {
if (formData.password_old.length < 6 || formData.password_old.length > 32) {
return feedback.msgError('密码长度在6到32之间')
}
if (formData.password.length < 6 || formData.password.length > 32) {
return feedback.msgError('密码长度在6到32之间')
}
if (formData.password_confirm.length < 6 || formData.password_confirm.length > 32) {
return feedback.msgError('密码长度在6到32之间')
}
if (formData.password_old.length < 6 || formData.password_old.length > 32) return feedback.msgError('密码长度在6到32之间')
if (formData.password.length < 6 || formData.password.length > 32) return feedback.msgError('密码长度在6到32之间')
if (formData.password_confirm.length < 6 || formData.password_confirm.length > 32) return feedback.msgError('密码长度在6到32之间')
}
await setUserInfo(formData)
const { work_wechat_userid, ...saveData } = formData
await setUserInfo(saveData)
userStore.getUserInfo()
}
// 提交数据
const handleSubmit = async () => {
await formRef.value?.validate()
setUser()
}
// 生成绑定用的 redirect_uri(带 bind_wxwork=1 标记)
const getBindRedirectUri = () => {
const base = window.location.origin + window.location.pathname
return base + '?bind_wxwork=1'
}
// 打开绑定弹窗,渲染扫码
const showBindDialog = async () => {
bindDialogVisible.value = true
bindLoading.value = true
if (!(window as any).WwLogin) {
await new Promise<void>((resolve, reject) => {
const script = document.createElement('script')
script.src = 'https://wwcdn.weixin.qq.com/node/wework/wwopen/js/wwLogin-1.2.7.js'
script.onload = () => resolve()
script.onerror = () => reject(new Error('加载企业微信JS失败'))
document.head.appendChild(script)
})
}
await nextTick()
bindLoading.value = false
await nextTick()
const redirectUri = encodeURIComponent(getBindRedirectUri())
new (window as any).WwLogin({
id: 'bind_wxwork_qrcode',
appid: wxWorkConfig.value.corp_id,
agentid: wxWorkConfig.value.agent_id,
redirect_uri: redirectUri,
lang: 'zh',
state: 'bind_wxwork',
href: '',
self_redirect: false,
})
}
const onBindDialogClose = () => {
bindLoading.value = false
}
// 解绑
const handleUnbind = async () => {
await feedback.confirm('确定要解绑企业微信吗?解绑后将无法使用企业微信扫码登录。')
try {
await unbindWorkWechat()
formData.work_wechat_userid = ''
ElMessage.success('解绑成功')
userStore.getUserInfo()
} catch (e: any) {
ElMessage.error(e?.msg || '解绑失败')
}
}
// 处理绑定回调 code
const handleBindCallback = async (code: string) => {
try {
const res = await bindWorkWechat({ code })
formData.work_wechat_userid = res?.work_wechat_userid || ''
ElMessage.success('企业微信绑定成功')
userStore.getUserInfo()
} catch (e: any) {
ElMessage.error(e?.msg || e?.message || '绑定失败')
} finally {
// 清除 URL 参数
const cleanUrl = window.location.pathname
window.history.replaceState({}, '', cleanUrl)
}
}
onMounted(async () => {
// 加载企业微信配置
try {
const res = await getWorkWechatConfig()
if (res?.enabled) {
wxWorkEnabled.value = true
wxWorkConfig.value = { corp_id: res.corp_id, agent_id: res.agent_id }
}
} catch (e) {
// 未配置则不显示
}
// 检查是否是绑定回调
const urlParams = new URLSearchParams(window.location.search)
const bindCode = urlParams.get('code')
const state = urlParams.get('state')
const isBind = urlParams.get('bind_wxwork')
if (bindCode && (state === 'bind_wxwork' || isBind === '1')) {
handleBindCallback(bindCode)
}
})
getUser()
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.bind-qrcode-wrap {
display: flex;
justify-content: center;
align-items: center;
min-height: 360px;
}
.bind-qrcode {
width: 340px;
height: 360px;
overflow: hidden;
:deep(iframe) {
width: 340px !important;
height: 360px !important;
border: none;
}
}
</style>