347 lines
7.9 KiB
Vue
347 lines
7.9 KiB
Vue
<template>
|
|
<div class="user-card">
|
|
<div class="user-card-head">
|
|
<div class="user-avatar">
|
|
<div class="avatar-wrapper" @click="showAvatarDialog = true">
|
|
<el-avatar :size="56" :src="avatarUrl">
|
|
<img src="@/assets/images/mr.png" />
|
|
</el-avatar>
|
|
<div class="avatar-overlay">
|
|
<el-icon class="upload-icon">
|
|
<Camera />
|
|
</el-icon>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="user-card-head-text">
|
|
<div class="name-row">
|
|
<span class="nickname">{{ userInfo.nickname || '用户信息' }}</span>
|
|
</div>
|
|
<div class="sub-stats">内部论坛 · 已登录</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="user-info">
|
|
<div class="info-item clickable" @click="showNicknameDialog = true">
|
|
<span class="label">昵称</span>
|
|
<span class="value">{{ userInfo.nickname || '-' }}</span>
|
|
<el-icon class="edit-icon">
|
|
<Edit />
|
|
</el-icon>
|
|
</div>
|
|
<div class="info-item">
|
|
<span class="label">账号</span>
|
|
<span class="value">{{ userInfo.account || '-' }}</span>
|
|
</div>
|
|
<div class="info-item">
|
|
<span class="label">姓名</span>
|
|
<span class="value">{{ userInfo.name || '-' }}</span>
|
|
</div>
|
|
<div class="info-item">
|
|
<span class="label">部门</span>
|
|
<span class="value">{{ userInfo.department || '-' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 更换头像对话框 -->
|
|
<ChangeAvatar v-model="showAvatarDialog" title="更换头像" @avatarUpdated="handleAvatarUpdated" />
|
|
|
|
<!-- 编辑昵称对话框 -->
|
|
<el-dialog
|
|
v-model="showNicknameDialog"
|
|
class="luntan-tech-dialog"
|
|
title="编辑昵称"
|
|
width="400px"
|
|
center
|
|
:close-on-click-modal="false"
|
|
>
|
|
<el-form ref="nicknameFormRef" :model="nicknameForm" :rules="nicknameRules" label-width="80px">
|
|
<el-form-item label="昵称" prop="nickname">
|
|
<el-input v-model="nicknameForm.nickname" placeholder="请输入昵称" maxlength="20" show-word-limit />
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="showNicknameDialog = false">取消</el-button>
|
|
<el-button type="primary" @click="handleSaveNickname">保存</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive, computed, onMounted } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { Camera, Edit } from '@element-plus/icons-vue'
|
|
import { getItem, setItem, removeItem } from '@/utils/storage.js'
|
|
import { setAddress } from '@/utils/tools'
|
|
import { tbGsxtXxltTxTxQueryBySfzh, tbGsxtXxltTxTxSave } from '@/api/tbGsxtXxltHf.js'
|
|
import ChangeAvatar from './ChangeAvatar.vue'
|
|
|
|
const showAvatarDialog = ref(false)
|
|
const showNicknameDialog = ref(false)
|
|
const nicknameFormRef = ref()
|
|
|
|
const userInfo = ref({
|
|
avatar: '',
|
|
account: '',
|
|
name: '',
|
|
department: '',
|
|
nickname: ''
|
|
})
|
|
|
|
const nicknameForm = reactive({
|
|
nickname: ''
|
|
})
|
|
|
|
const nicknameRules = {
|
|
nickname: [
|
|
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
|
{ min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
const avatarUrl = computed(() => {
|
|
return userInfo.value.avatar ? setAddress(userInfo.value.avatar) : ''
|
|
})
|
|
|
|
// 加载用户信息
|
|
const loadUserInfo = async () => {
|
|
const sfzh = getItem('idEntityCard')
|
|
let ltmasg = getItem('ltmasg')
|
|
|
|
if (!ltmasg) {
|
|
try {
|
|
const res = await tbGsxtXxltTxTxQueryBySfzh({ sfzh: sfzh })
|
|
console.log(res);
|
|
|
|
const deptId = getItem('deptId')?.[0]
|
|
ltmasg = {
|
|
...res,
|
|
deptName: deptId?.deptName || ''
|
|
}
|
|
setItem('ltmasg', ltmasg)
|
|
} catch (error) {
|
|
console.error('加载用户信息失败:', error)
|
|
}
|
|
}
|
|
|
|
if (ltmasg) {
|
|
userInfo.value = {
|
|
avatar: ltmasg.tx || '',
|
|
account: ltmasg.sfzh || '',
|
|
name: ltmasg.xm || '',
|
|
department: ltmasg.deptName || ltmasg.bm || '',
|
|
nickname: ltmasg.nc || ''
|
|
}
|
|
}
|
|
}
|
|
|
|
// 处理头像更新
|
|
const handleAvatarUpdated = async (newAvatar) => {
|
|
try {
|
|
const ltmasg = getItem('ltmasg')
|
|
const updateData = {
|
|
...ltmasg,
|
|
tx: newAvatar
|
|
}
|
|
|
|
await tbGsxtXxltTxTxSave(updateData)
|
|
removeItem('ltmasg')
|
|
await loadUserInfo()
|
|
ElMessage.success('头像更新成功')
|
|
} catch (error) {
|
|
console.error('更新头像失败:', error)
|
|
ElMessage.error('头像更新失败,请重试')
|
|
}
|
|
}
|
|
|
|
// 处理保存昵称
|
|
const handleSaveNickname = async () => {
|
|
if (!nicknameFormRef.value) return
|
|
|
|
await nicknameFormRef.value.validate(async (valid) => {
|
|
if (valid) {
|
|
try {
|
|
const ltmasg = getItem('ltmasg')
|
|
const updateData = {
|
|
...ltmasg,
|
|
nc: nicknameForm.nickname
|
|
}
|
|
|
|
await tbGsxtXxltTxTxSave(updateData)
|
|
removeItem('ltmasg')
|
|
await loadUserInfo()
|
|
showNicknameDialog.value = false
|
|
ElMessage.success('昵称保存成功')
|
|
} catch (error) {
|
|
console.error('保存昵称失败:', error)
|
|
ElMessage.error('昵称保存失败,请重试')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// 监听昵称对话框打开,初始化表单
|
|
const openNicknameDialog = () => {
|
|
nicknameForm.nickname = userInfo.value.nickname
|
|
}
|
|
|
|
// 监听对话框显示状态
|
|
const unwatchNickname = () => {
|
|
if (showNicknameDialog.value) {
|
|
openNicknameDialog()
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadUserInfo()
|
|
})
|
|
|
|
// 监听昵称对话框
|
|
const stopWatch = () => {
|
|
if (showNicknameDialog.value) {
|
|
nicknameForm.nickname = userInfo.value.nickname
|
|
}
|
|
}
|
|
|
|
// 使用 watch 监听对话框状态
|
|
import { watch } from 'vue'
|
|
watch(showNicknameDialog, (newVal) => {
|
|
if (newVal) {
|
|
nicknameForm.nickname = userInfo.value.nickname
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@import '../styles/luntan-tech.scss';
|
|
|
|
.user-card {
|
|
border-radius: 4px;
|
|
padding: 18px 16px 16px;
|
|
@include lt-panel-frame;
|
|
}
|
|
|
|
.user-card-head {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 14px;
|
|
margin-bottom: 16px;
|
|
padding-bottom: 14px;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
}
|
|
|
|
.user-avatar {
|
|
flex-shrink: 0;
|
|
|
|
.avatar-wrapper {
|
|
position: relative;
|
|
cursor: pointer;
|
|
border-radius: 50%;
|
|
overflow: hidden;
|
|
border: 2px solid rgba(100, 180, 255, 0.35);
|
|
|
|
&:hover .avatar-overlay {
|
|
opacity: 1;
|
|
}
|
|
|
|
.avatar-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.55);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
border-radius: 50%;
|
|
|
|
.upload-icon {
|
|
font-size: 22px;
|
|
color: white;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.user-card-head-text {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.name-row {
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.nickname {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #f0f6ff;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.sub-stats {
|
|
font-size: 12px;
|
|
color: rgba(180, 200, 230, 0.55);
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.user-info {
|
|
.info-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
margin-bottom: 10px;
|
|
font-size: 13px;
|
|
position: relative;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
&.clickable {
|
|
cursor: pointer;
|
|
padding: 6px 8px;
|
|
margin-left: -8px;
|
|
margin-right: -8px;
|
|
border-radius: 6px;
|
|
transition: background-color 0.2s ease;
|
|
|
|
&:hover {
|
|
background-color: rgba(255, 255, 255, 0.06);
|
|
|
|
.edit-icon {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
.label {
|
|
color: rgba(160, 185, 215, 0.55);
|
|
min-width: 40px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.value {
|
|
color: rgba(220, 230, 245, 0.88);
|
|
flex: 1;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.edit-icon {
|
|
margin-left: 6px;
|
|
color: #5eb8ff;
|
|
font-size: 14px;
|
|
opacity: 0;
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss">
|
|
@import '../styles/luntan-dialog-tech.scss';
|
|
</style>
|