Files
trade-assistant/user-frontend/src/views/Profile.vue
T
wlt 45e98a9c82 feat: restructure workspace navigation (sidebar 11->5, merged homepage)
Router reorganized: /workspace is now the landing page (NewHome.vue). Sidebar reduced from 11 items to 5 groups (Home/Customers/Products&Quotes/Translate/More). Profile sub-navigation updated to /workspace/profile/*. Legacy discovery/marketing/followup routes preserved as hidden.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-17 10:48:13 +08:00

124 lines
5.4 KiB
Vue

<template>
<div>
<el-row :gutter="20">
<el-col :xs="24" :sm="8">
<el-card shadow="never">
<div style="text-align:center;padding:20px 0">
<el-avatar :size="72" style="background:#1890ff;font-size:28px">{{ (auth.user?.username || 'U')[0].toUpperCase() }}</el-avatar>
<h3 style="margin:12px 0 4px">{{ auth.user?.username || '用户' }}</h3>
<el-tag size="small" :type="tierType(auth.user?.tier)">{{ auth.user?.tier || 'free' }}</el-tag>
<el-tag v-if="auth.user?.role === 'admin'" type="danger" size="small" style="margin-left:4px">管理员</el-tag>
</div>
<el-divider style="margin:8px 0" />
<div class="profile-menu">
<div class="menu-item" :class="{ active: $route.path === '/workspace/profile' }" @click="$router.push('/workspace/profile')">
<el-icon><User /></el-icon><span>个人资料</span>
</div>
<div class="menu-item" :class="{ active: $route.path === '/workspace/profile/credits' }" @click="$router.push('/workspace/profile/credits')">
<el-icon><Coin /></el-icon><span>购买次数</span>
</div>
<div class="menu-item" :class="{ active: $route.path === '/workspace/profile/certification' }" @click="$router.push('/workspace/profile/certification')">
<el-icon><Stamp /></el-icon><span>实名认证</span>
</div>
<div class="menu-item" :class="{ active: $route.path === '/workspace/profile/invoice' }" @click="$router.push('/workspace/profile/invoice')">
<el-icon><List /></el-icon><span>发票管理</span>
</div>
<div class="menu-item" :class="{ active: $route.path === '/workspace/profile/notifications' }" @click="$router.push('/workspace/profile/notifications')">
<el-icon><Bell /></el-icon><span>通知中心</span>
</div>
<div class="menu-item" :class="{ active: $route.path === '/workspace/profile/feedback' }" @click="$router.push('/workspace/profile/feedback')">
<el-icon><ChatDotSquare /></el-icon><span>意见反馈</span>
</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="16">
<el-card shadow="never">
<template #header><span>编辑资料</span></template>
<el-form :model="form" label-width="80" size="large">
<el-form-item label="用户名">
<el-input v-model="form.username" :disabled="true" />
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" placeholder="输入邮箱" />
</el-form-item>
<el-form-item label="手机">
<el-input v-model="form.phone" :disabled="true" />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="saving" @click="saveProfile">保存</el-button>
<el-button @click="showPassword = true">修改密码</el-button>
</el-form-item>
</el-form>
</el-card>
</el-col>
</el-row>
<el-dialog v-model="showPassword" title="修改密码" width="400">
<el-form :model="pwForm" label-width="80">
<el-form-item label="旧密码"><el-input v-model="pwForm.old_password" type="password" /></el-form-item>
<el-form-item label="新密码"><el-input v-model="pwForm.new_password" type="password" /></el-form-item>
</el-form>
<template #footer>
<el-button @click="showPassword = false">取消</el-button>
<el-button type="primary" :loading="pwLoading" @click="changePw">确认</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { useAuthStore } from '@/stores/auth'
import { updateProfile, changePassword } from '@/api'
import { ElMessage } from 'element-plus'
const route = useRoute()
const auth = useAuthStore()
const saving = ref(false)
const showPassword = ref(false)
const pwLoading = ref(false)
const form = reactive({ username: '', email: '', phone: '' })
const pwForm = reactive({ old_password: '', new_password: '' })
function tierType(t) { return { free: 'warning', pro: 'primary', enterprise: 'success' }[t] || 'info' }
onMounted(() => {
if (auth.user) {
form.username = auth.user.username || ''
form.email = auth.user.email || ''
form.phone = auth.user.phone || ''
}
})
async function saveProfile() {
saving.value = true
try {
await updateProfile({ email: form.email })
ElMessage.success('已保存')
auth.fetchUser()
} catch (e) { ElMessage.error(e?.detail || '保存失败') }
finally { saving.value = false }
}
async function changePw() {
if (!pwForm.old_password || !pwForm.new_password) { ElMessage.warning('请填写完整'); return }
pwLoading.value = true
try {
await changePassword(pwForm)
ElMessage.success('密码已修改')
showPassword.value = false
pwForm.old_password = ''
pwForm.new_password = ''
} catch (e) { ElMessage.error(e?.detail || '修改失败') }
finally { pwLoading.value = false }
}
</script>
<style scoped>
.profile-menu { padding: 0; }
.menu-item { display: flex; align-items: center; gap: 10px; padding: 12px 16px; cursor: pointer; border-radius: 6px; transition: background 0.2s; }
.menu-item:hover { background: #f0f5ff; color: #409eff; }
.menu-item.active { background: #e6f7ff; color: #1890ff; font-weight: 500; }
</style>