|
|
4 dagen geleden | |
|---|---|---|
| .gitignore | 4 dagen geleden | |
| README.md | 4 dagen geleden |
Vue3 管理端,承载教务域重写 + 教学 admin 复用两块页面,统一走 nginx 入口 + 统一 Go 后端 SSO。 本文档覆盖四块:技术栈 / 目录结构与用途 / 编码规范 / 构建。接口契约与角色权限见工作区文档库
unified/、academic/05-architecture/、teaching/05-architecture/(本仓库不复制契约原文)。
单一 Vue3 项目,面向登录角色中的 超管/教务/财务/老师(管理侧) 等 PC 端角色(市场角色登录入口暂禁用——不建市场端入口/路由,后续启用时再单独拍板)。学生/家长日常操作走移动端仓库 DEV-MERGE-LEGACY-MOBILE-FRONTEND-2026。
| 关注点 | 选型 | 说明 / 依据 |
|---|---|---|
| 框架 | Vue 3(<script setup> + Composition API) |
与教学 admin 现有栈一致,复用成本低 |
| 语言 | TypeScript(strict) | 接口契约类型化;统一信封 R<T> 泛型 |
| 构建 | Vite | dev HMR + 产物构建;主 chunk < 1024KB(质量门禁) |
| UI | Element Plus(含 el-config-provider 中文 locale) |
管理端组件库;locale 双注入(见编码规范 §3.4) |
| 状态 | Pinia | login(token/角色)+ scope(institution/campus 作用域) |
| 路由 | Vue Router 4 | 按端组织 + 角色/权限码守卫 |
| HTTP | axios(统一封装于 src/api/) |
统一 {code, data, message} 信封处理;拦截器只注入 token/trace,不 reject 业务错误 |
| 鉴权 | SSO(最小可行)token:access 30min + refresh 30 天 | 统一 identity 签发(ADR-014);菜单/按钮按权限码显隐 |
| 包管理 | pnpm(lockfile 入库) | 与移动端同栈,依赖可对齐 |
| 代码风格 | ESLint + Prettier(vue3 官方推荐配置) | 提交前 lint |
.
├── README.md ← 本文件
├── package.json / pnpm-lock.yaml
├── vite.config.ts ← Vite 配置(proxy /api → 后端;chunk 拆分)
├── tsconfig.json
├── .env.example ← 环境变量模板(VITE_API_BASE 等;实际 .env.* 走 .gitignore)
└── src/
├── main.ts ← 装配:Element Plus 双 locale 注入 + Pinia + Router + 作用域/权限守卫挂载
├── views/ ← 页面:按域分子目录(见用途表)
│ ├── academic/ ← 教务域(排班/费用/打卡/充值/报课)——**新写**(旧 jQuery 视图全部重写)
│ ├── teaching/ ← 教学 admin(备课/题库/组卷/练习分析)——**按现有 Vue3 逐步迁入**
│ ├── org/ ← 机构/校区/班级/成员管理
│ └── system/ ← 系统(用户/角色/字典/任务监控/日志)
├── components/ ← 复用组件:表格/表单/作用域选择器(institution·campus 联动)/Badge 色板
├── api/ ← 接口封装:统一信封 + 错误码处理;按域分子目录(academic/teaching/org/…)
├── router/ ← 路由:按端组织 + 角色/权限码守卫
├── store/ ← Pinia:login(token/角色)、scope(institution/campus)
├── composables/ ← 可组合逻辑:useListPage(列表页规范)等
└── types/ ← 契约类型:R<T> 信封、角色/权限码、各域 DTO
目录用途约定:
| 目录 | 用途 | 约束 |
|---|---|---|
src/views/{域}/ |
页面层,只放视图与页面级状态 | 禁止散写 fetch/axios;只经 src/api/ |
src/components/ |
跨页面复用组件 | 零业务耦合(作用域感知组件除外,从 store 读) |
src/api/{域}/ |
接口封装(一域一目录,一资源一文件) | 统一信封处理收口在此;返回类型化 DTO |
src/router/ |
路由与守卫 | 权限码驱动;不写 role == N 硬编码 |
src/store/ |
全局状态(登录态/作用域) | 唯一 token 存取点(禁 localStorage 散写) |
src/composables/ |
可组合逻辑 | 列表页一律复用 useListPage<T> |
src/types/ |
契约类型 | 与后端 DTO camelCase 对齐;R<T> 泛型 |
store/scope 统一注入,禁止页面各自拼 schoolid/campusid(对齐清单 §3:消灭控制器隐式参数)。role == N 硬编码(对齐清单 §3 超管判据收敛)。src/api/,禁止页面里散写 fetch/axios。code」信封 {code, data, message, total?, success};判成功读 code === 200,错误文案读 message,不靠拦截器 reject、不靠 HTTP status(源自教务 Go 重构在产验证)。1xxx 认证/权限 · 2xxx 参数 · 3xxx 数据 · 4xxx 依赖 · 5xxx 系统;1001/1002 统一跳登录(refresh 失败才跳,access 过期先静默 refresh)。page/pageSize(上限 200);列表读顶层 total。camelCase;组件 PascalCase;组合式函数 useXxx。useListPage<T> + ListPage.vue(分页/筛选/批量操作收口);年级 <GradeBadge>(数字=年级 id + 学段色系)、科目 <SubjectBadge>(首字简称 + 独立色系)——色板纯数据零 Vue 依赖,新增列表页一律复用。app.use(ElementPlus, {locale: zhCn})(命令式 ElMessageBox/Notification)+ <el-config-provider :locale>(声明式)双注入,单用其一必有遗漏;locale 引 element-plus/es/locale/lang/zh-cn。| 门禁 | 命令 | 基线 |
|---|---|---|
| 类型检查 | vue-tsc --noEmit |
0 错误 |
| 构建 | pnpm build(vite) |
主 chunk < 1024KB |
| Lint | pnpm lint(eslint + prettier) |
0 错误 |
git push 前必须经用户确认(逐次确认)。feat: / fix: / chore: / docs: / refactor:)。vue-tsc + pnpm build 通过;敏感值未入库(.env 走 .gitignore,仅 .env.example 入库)。pnpm install # 依赖(pnpm 10.x;lockfile 入库)
pnpm dev # 本地开发(vite dev,/api 代理到后端 dev 地址)
pnpm build # 产物 → dist/(部署经 nginx)
环境变量(.env.example 入库,实际 .env.* 不入库):VITE_API_BASE(后端 base,dev 走 vite proxy 时可省)。
academic/05-architecture/ 与 teaching/05-architecture/;前端策略(重写 vs 复用)见 unified/00-planning/cross-system-reconciliation.md §5。