Add admin-frontend and user-frontend standalone projects, certification/invoice/discovery features, fix auth header and theme consistency

This commit is contained in:
TradeMate Dev
2026-05-22 18:35:30 +08:00
parent 18c6cf5406
commit 52dba37f22
79 changed files with 10333 additions and 248 deletions
+119
View File
@@ -0,0 +1,119 @@
<template>
<div>
<el-row :gutter="20">
<el-col :span="8">
<el-card shadow="never">
<div style="text-align:center;padding:20px 0">
<el-avatar :size="72" style="background:#409eff;font-size:28px">{{ (user?.username || 'U')[0].toUpperCase() }}</el-avatar>
<h3 style="margin:12px 0 4px">{{ user?.username || '用户' }}</h3>
<el-tag size="small" :type="tierType(user?.tier)">{{ user?.tier || 'free' }}</el-tag>
<el-tag v-if="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" @click="$router.push('/upgrade')">
<el-icon><Crown /></el-icon><span>升级会员</span>
</div>
<div class="menu-item" @click="$router.push('/certification')">
<el-icon><Stamp /></el-icon><span>实名认证</span>
</div>
<div class="menu-item" @click="$router.push('/invoice')">
<el-icon><List /></el-icon><span>发票管理</span>
</div>
<div class="menu-item" @click="$router.push('/notifications')">
<el-icon><Bell /></el-icon><span>通知中心</span>
</div>
<div class="menu-item" @click="$router.push('/feedback')">
<el-icon><ChatDotSquare /></el-icon><span>意见反馈</span>
</div>
</div>
</el-card>
</el-col>
<el-col :span="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 auth = useAuthStore()
const user = auth.user
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 (user.value) {
form.username = user.value.username || ''
form.email = user.value.email || ''
form.phone = user.value.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; }
</style>