Files
zyt/admin/src/views/user/setting.vue
T
2026-03-13 14:08:52 +08:00

295 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 个人资料 -->
<template>
<div class="user-setting">
<el-card class="!border-none" shadow="never">
<el-form
ref="formRef"
class="ls-form"
:model="formData"
:rules="rules"
label-width="100px"
>
<el-form-item label="头像:" prop="avatar">
<material-picker v-model="formData.avatar" :limit="1" />
</el-form-item>
<el-form-item label="账号:" prop="account">
<div class="w-80">
<el-input v-model="formData.account" disabled />
</div>
</el-form-item>
<el-form-item label="名称:" prop="name">
<div class="w-80">
<el-input v-model="formData.name" placeholder="请输入名称" />
</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
v-model.trim="formData.password_old"
placeholder="修改密码时必填, 不修改密码时留空"
type="password"
show-password
/>
</div>
</el-form-item>
<el-form-item label="新的密码:" prop="password">
<div class="w-80">
<el-input
v-model.trim="formData.password"
placeholder="修改密码时必填, 不修改密码时留空"
type="password"
show-password
/>
</div>
</el-form-item>
<el-form-item label="确定密码:" prop="password_confirm">
<div class="w-80">
<el-input
v-model.trim="formData.password_confirm"
placeholder="修改密码时必填, 不修改密码时留空"
type="password"
show-password
/>
</div>
</el-form-item>
</el-form>
</el-card>
<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, 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: '',
work_wechat_userid: '',
password_old: '',
password: '',
password_confirm: ''
})
const rules = reactive<object>({
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
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 && 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之间')
}
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>
.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>