45e98a9c82
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>
124 lines
5.4 KiB
Vue
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>
|