feat: art-design-pro 脚手架落地与品牌化(八页骨架/代理配置/权限菜单)

- 模板 art-design-pro(MIT)GitHub 直连克隆后裁剪落地 admin/:删除演示页面/示例数据/mock/未用组件,保留构建与依赖清单
- 品牌化:应用名/标题/侧栏与登录页 logo/浏览器 favicon 全部替换为 all-kefu 自有资源(static/kefu-small.png),中文界面
- 八页骨架:login / force-change-password / dashboard / tenants / conversations / config / stats / settings 占位页 + 6 组路由模块
- 权限菜单:meta.roles 前端过滤,super 全量,tenant 隐藏 租户管理/平台设置(角色值与后端一致)
- 开发代理:/api 直转 + /api/public 与 /static 携带租户 Host 改写(VITE_TENANT_PREVIEW_HOST),适配后端 TenantHostMiddleware
- 认证 API 为开发桩(角色调试开关),Task 3 对接真实登录

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-13 14:51:24 +08:00
parent 0c25287c19
commit 78ff060420
290 changed files with 38981 additions and 0 deletions
@@ -0,0 +1,95 @@
<!-- 强制修改密码(骨架占位页;登录对接与提交逻辑在后续任务实现) -->
<template>
<div class="force-change-password flex-cc w-full h-screen">
<ElCard shadow="never" class="card">
<template #header>
<span class="card-title">首次登录请修改密码</span>
</template>
<ElForm ref="formRef" :model="formData" :rules="rules" label-position="top">
<ElFormItem prop="newPassword" label="新密码">
<ElInput
v-model.trim="formData.newPassword"
type="password"
placeholder="请输入新密码"
show-password
autocomplete="off"
/>
</ElFormItem>
<ElFormItem prop="confirmPassword" label="确认新密码">
<ElInput
v-model.trim="formData.confirmPassword"
type="password"
placeholder="请再次输入新密码"
show-password
autocomplete="off"
/>
</ElFormItem>
<ElButton type="primary" class="w-full" :loading="loading" @click="handleSubmit">
提交修改
</ElButton>
</ElForm>
<p class="tip">密码修改成功后方可进入后台(对接后端 API 在后续任务实现)</p>
</ElCard>
</div>
</template>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
defineOptions({ name: 'ForceChangePassword' })
const formRef = ref<FormInstance>()
const loading = ref(false)
const formData = reactive({
newPassword: '',
confirmPassword: ''
})
const rules: FormRules = {
newPassword: [
{ required: true, message: '请输入新密码', trigger: 'blur' },
{ min: 8, message: '密码长度不少于 8 位', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
{
validator: (_rule, value, callback) => {
if (value !== formData.newPassword) {
callback(new Error('两次输入的密码不一致'))
} else {
callback()
}
},
trigger: 'blur'
}
]
}
// 骨架阶段仅做表单校验,不发起请求(Task 3 对接 /api/platform/auth/*)
const handleSubmit = async () => {
if (!formRef.value) return
const valid = await formRef.value.validate().catch(() => false)
if (!valid) return
loading.value = true
setTimeout(() => {
loading.value = false
}, 600)
}
</script>
<style scoped lang="scss">
.card {
width: 400px;
.card-title {
font-weight: 600;
}
.tip {
margin-top: 12px;
font-size: 12px;
color: var(--art-gray-500);
}
}
</style>