- 删除应用配置页面及相关组件,重构路由为 /developer/config/[id].vue - 移除开发者文档页面及其导航与样式实现 - 清理开发者侧功能完善工作日志文件 - 删除全局.gitignore配置文件,清理无用忽略规则 - 优化应用配置页面的参数读取和路由结构,解决刷新404问题 - 解决数据库配置唯一键冲突,调整保存逻辑避免重复插入 - 移除对后端配置加密字段的 secret 标记,修正加密异常问题
248 lines
8.0 KiB
Vue
248 lines
8.0 KiB
Vue
<script setup lang="ts">
|
||
definePageMeta({ layout: 'admin' })
|
||
|
||
const { user } = useUser()
|
||
|
||
// 个人信息数据
|
||
const profile = reactive({
|
||
username: 'admin',
|
||
nickname: '系统管理员',
|
||
email: 'admin@company.com',
|
||
phone: '138****8888',
|
||
department: '信息技术部',
|
||
position: '系统管理员',
|
||
joinDate: '2024-01-15',
|
||
lastLogin: '2026-04-09 07:00',
|
||
avatar: '',
|
||
})
|
||
|
||
// 安全设置
|
||
const securitySettings = reactive({
|
||
emailVerified: true,
|
||
phoneVerified: true,
|
||
twoFactorEnabled: false,
|
||
loginPwdChanged: '2026-03-15',
|
||
})
|
||
|
||
// 修改密码表单
|
||
const passwordForm = reactive({
|
||
oldPassword: '',
|
||
newPassword: '',
|
||
confirmPassword: '',
|
||
})
|
||
|
||
const passwordRules = {
|
||
newPassword: [{ required: true, message: '请输入新密码', trigger: 'blur' }],
|
||
confirmPassword: [
|
||
{ required: true, message: '请确认新密码', trigger: 'blur' },
|
||
{
|
||
validator: (_rule: any, value: string) => {
|
||
if (value !== passwordForm.newPassword) {
|
||
return Promise.reject('两次输入的密码不一致')
|
||
}
|
||
return Promise.resolve()
|
||
},
|
||
trigger: 'blur',
|
||
},
|
||
],
|
||
}
|
||
|
||
// 操作日志
|
||
const loginHistory = ref([
|
||
{ time: '2026-04-09 07:00:00', ip: '192.168.1.100', device: 'Chrome / Windows 11', location: '广东深圳', status: '成功' },
|
||
{ time: '2026-04-08 18:30:00', ip: '192.168.1.100', device: 'Chrome / macOS', location: '广东深圳', status: '成功' },
|
||
{ time: '2026-04-08 09:15:00', ip: '192.168.1.101', device: 'Safari / iOS', location: '广东广州', status: '成功' },
|
||
{ time: '2026-04-07 16:45:00', ip: '10.0.0.1', device: 'Firefox / Ubuntu', location: '广东深圳', status: '成功' },
|
||
{ time: '2026-04-07 08:00:00', ip: '192.168.1.100', device: 'Chrome / Windows 11', location: '广东深圳', status: '成功' },
|
||
])
|
||
|
||
const activeTab = ref('profile')
|
||
</script>
|
||
|
||
<template>
|
||
<div class="account-page">
|
||
<a-tabs v-model:activeKey="activeTab" class="account-tabs">
|
||
<!-- 基本信息 -->
|
||
<a-tab-pane key="profile" tab="基本信息">
|
||
<a-row :gutter="24">
|
||
<a-col :xs="24" :lg="16">
|
||
<a-card title="个人信息" class="info-card">
|
||
<a-descriptions :column="{ xs: 1, sm: 2 }" bordered>
|
||
<a-descriptions-item label="用户名">{{ profile.username }}</a-descriptions-item>
|
||
<a-descriptions-item label="昵称">{{ profile.nickname }}</a-descriptions-item>
|
||
<a-descriptions-item label="邮箱">
|
||
{{ profile.email }}
|
||
<a-tag v-if="securitySettings.emailVerified" color="success" size="small">已认证</a-tag>
|
||
</a-descriptions-item>
|
||
<a-descriptions-item label="手机号">
|
||
{{ profile.phone }}
|
||
<a-tag v-if="securitySettings.phoneVerified" color="success" size="small">已认证</a-tag>
|
||
</a-descriptions-item>
|
||
<a-descriptions-item label="部门">{{ profile.department }}</a-descriptions-item>
|
||
<a-descriptions-item label="职位">{{ profile.position }}</a-descriptions-item>
|
||
<a-descriptions-item label="入职日期">{{ profile.joinDate }}</a-descriptions-item>
|
||
<a-descriptions-item label="上次登录">{{ profile.lastLogin }}</a-descriptions-item>
|
||
</a-descriptions>
|
||
<div class="mt-4">
|
||
<a-button type="primary">编辑资料</a-button>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
<a-col :xs="24" :lg="8">
|
||
<a-card title="头像设置" class="avatar-card">
|
||
<div class="avatar-upload">
|
||
<a-avatar :size="100" :src="profile.avatar">
|
||
<template #icon><UserOutlined /></template>
|
||
</a-avatar>
|
||
<div class="mt-4">
|
||
<a-button size="small">更换头像</a-button>
|
||
<p class="text-xs text-gray-400 mt-2">支持 JPG、PNG 格式,文件小于 2MB</p>
|
||
</div>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
</a-row>
|
||
</a-tab-pane>
|
||
|
||
<!-- 账号安全 -->
|
||
<a-tab-pane key="security" tab="账号安全">
|
||
<a-row :gutter="24">
|
||
<a-col :xs="24" :lg="16">
|
||
<!-- 登录密码 -->
|
||
<a-card title="登录密码" class="security-card mb-4">
|
||
<div class="security-item">
|
||
<div class="security-info">
|
||
<div class="security-title">登录密码</div>
|
||
<div class="security-desc">上次修改于 {{ securitySettings.loginPwdChanged }}</div>
|
||
</div>
|
||
<a-button>修改密码</a-button>
|
||
</div>
|
||
</a-card>
|
||
|
||
<!-- 邮箱绑定 -->
|
||
<a-card title="邮箱绑定" class="security-card mb-4">
|
||
<div class="security-item">
|
||
<div class="security-info">
|
||
<div class="security-title">{{ profile.email }}</div>
|
||
<div class="security-desc">
|
||
<a-tag v-if="securitySettings.emailVerified" color="success" size="small">已验证</a-tag>
|
||
<span v-else class="text-orange-500">未验证</span>
|
||
</div>
|
||
</div>
|
||
<a-button type="primary" ghost>更换邮箱</a-button>
|
||
</div>
|
||
</a-card>
|
||
|
||
<!-- 手机绑定 -->
|
||
<a-card title="手机绑定" class="security-card mb-4">
|
||
<div class="security-item">
|
||
<div class="security-info">
|
||
<div class="security-title">{{ profile.phone }}</div>
|
||
<div class="security-desc">
|
||
<a-tag v-if="securitySettings.phoneVerified" color="success" size="small">已验证</a-tag>
|
||
</div>
|
||
</div>
|
||
<a-button type="primary" ghost>更换手机</a-button>
|
||
</div>
|
||
</a-card>
|
||
|
||
<!-- 两步验证 -->
|
||
<a-card title="两步验证" class="security-card">
|
||
<div class="security-item">
|
||
<div class="security-info">
|
||
<div class="security-title">开启两步验证</div>
|
||
<div class="security-desc">启用后登录需输入手机验证码,提升账号安全</div>
|
||
</div>
|
||
<a-switch v-model:checked="securitySettings.twoFactorEnabled" />
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
</a-row>
|
||
</a-tab-pane>
|
||
|
||
<!-- 登录历史 -->
|
||
<a-tab-pane key="history" tab="登录历史">
|
||
<a-card title="最近登录记录">
|
||
<a-table :dataSource="loginHistory" :pagination="false" rowKey="time" size="small">
|
||
<a-table-column title="登录时间" dataIndex="time" width="180" />
|
||
<a-table-column title="IP 地址" dataIndex="ip" width="140" />
|
||
<a-table-column title="设备" dataIndex="device" />
|
||
<a-table-column title="位置" dataIndex="location" width="100" />
|
||
<a-table-column title="状态" dataIndex="status" width="80" align="center">
|
||
<template #default="{ text }">
|
||
<a-tag :color="text === '成功' ? 'success' : 'error'">{{ text }}</a-tag>
|
||
</template>
|
||
</a-table-column>
|
||
</a-table>
|
||
</a-card>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.account-page {
|
||
max-width: 1200px;
|
||
}
|
||
|
||
.account-tabs :deep(.ant-tabs-nav) {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.info-card,
|
||
.security-card,
|
||
.avatar-card {
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.avatar-upload {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 20px;
|
||
}
|
||
|
||
.security-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 8px 0;
|
||
}
|
||
|
||
.security-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.security-title {
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
color: #1f2937;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.security-desc {
|
||
font-size: 13px;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.text-xs {
|
||
font-size: 12px;
|
||
}
|
||
|
||
.text-gray-400 {
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.text-orange-500 {
|
||
color: #f97316;
|
||
}
|
||
|
||
.mt-4 {
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.mb-4 {
|
||
margin-bottom: 16px;
|
||
}
|
||
</style>
|