Преглед на файлове

docs(readme): 三步定稿重写——技术栈(UMD自托管OSS+本地编译)/目录结构/编码规范

第1步 技术栈(2026-11-06 拍板):
- 框架层 7 项 UMD 全局脚本(Vue3/Router4/Pinia/EP JS+CSS+zh-cn locale/axios)自托管自有 OSS,禁第三方 CDN
- 业务层 TS strict + Vite 6 本地编译;版本事实 = index.html 版本表 + 仓库 vendor/(入库)
- 默认简体中文(lang=zh-CN + EP locale 双注入),不引入 vue-i18n
- 框架升级五步流程(下载→vendor commit→OSS→index.html→回归)+ 只增不删回滚规则

第2步 目录结构:
- 双层:index.html+vendor/(框架层)/ src/(业务层)
- src 十目录:views 四域分包(academic/teaching/org/system)+ components/api/router/store/composables/utils/styles/types
- 新增 utils(纯函数,零 Vue 依赖)与 styles(全局 token,组件禁硬编码色值)

第3步 编码规范:
- 命名表(API 字段一律 camelCase、权限码 域.资源.动作 三段式、禁旧系统混用命名)
- SFC 骨架八段顺序 + 域目录组织约定
- 组件十条(禁 import 框架全走 UMD 全局 / 作用域只从 useScope 取 / 权限码指令 / 三态 / 脱敏直显)
- 接口契约重申(HTTP 恒 200 + PageData 分页)+ TS strict 禁 any
- 质量门禁新增:dist 不得含框架运行时(grep)+ vendor 与 OSS md5 对账
Q преди 4 дни
родител
ревизия
4ac0061c12
променени са 1 файла, в които са добавени 163 реда и са изтрити 61 реда
  1. 163 61
      README.md

+ 163 - 61
README.md

@@ -2,6 +2,7 @@
 
 > Vue3 管理端,承载**教务域重写** + **教学 admin 复用**两块页面,统一走 nginx 入口 + 统一 Go 后端 SSO。
 > 本文档覆盖四块:**技术栈 / 目录结构与用途 / 编码规范 / 构建**。接口契约与角色权限见工作区文档库 `unified/`、`academic/05-architecture/`、`teaching/05-architecture/`(本仓库不复制契约原文)。
+> 框架层选型(2026-11-06 定稿):**UMD 全局脚本 + 自托管 OSS + 业务层本地编译 + 默认简体中文**。
 
 ## 定位
 
@@ -9,108 +10,209 @@
 
 ## 1. 技术栈
 
-| 关注点 | 选型 | 说明 / 依据 |
+### 1.1 资源双层结构(核心选型)
+
+| 层 | 内容 | 引入方式 | 版本管理 |
+|---|---|---|---|
+| **框架层** | Vue 3 / Vue Router 4 / Pinia / Element Plus(JS + CSS + zh-cn locale)/ axios,共 7 项 UMD 资源 | `index.html` 内 `<link>`/`<script>` 按**固定顺序**引入,源文件**自托管到自有 OSS**(自定义域名 + SSL,不用第三方 CDN) | 版本事实 = `index.html` 头部"vendor 版本表"(钉死次版本)+ 仓库 `vendor/` 源文件(git 入库) |
+| **业务层** | 本项目全部业务代码(TS 编写) | 本地 `pnpm` 工具链编译(Vite/vue-tsc/ESLint/Prettier 为 dev 依赖),产物 `dist/` 经 nginx 部署 | `pnpm-lock.yaml` 入库(只锁工具链,不含框架) |
+
+- **开发测试**:`pnpm dev` 起 Vite 本地服务(HMR 只热更业务代码,框架层从自托管 OSS 加载);`/api` 代理到后端 dev 地址。
+- **构建**:`pnpm build` 只打包业务代码 → `dist/`;**产物禁止包含框架运行时**(质量门禁 grep 抽查,防 external 配错)。
+
+### 1.2 框架层 UMD 资源清单(加载顺序固定,版本以 `index.html` 版本表为准)
+
+| # | 资源 | OSS 路径模板 | 全局变量 | 用途 |
+|---|---|---|---|---|
+| 1 | Vue 3(prod UMD) | `vue/{v}/vue.global.prod.js` | `Vue` | 框架本体 |
+| 2 | Vue Router 4 | `vue-router/{v}/vue-router.global.js` | `VueRouter` | 路由(按端组织 + 守卫链) |
+| 3 | Pinia | `pinia/{v}/pinia.iife.prod.js` | `Pinia` | 状态(login / scope 两 store) |
+| 4 | Element Plus CSS | `element-plus/{v}/index.css` | — | UI 样式(走自托管,不打包) |
+| 5 | Element Plus(full UMD) | `element-plus/{v}/index.full.min.js` | `ElementPlus` | UI 组件(表格/表单/日期等全量) |
+| 6 | Element Plus 中文 locale | `element-plus/{v}/locale/zh-cn.js` | `ElementPlusLocaleZhCn` | 默认简体中文 |
+| 7 | axios | `axios/{v}/axios.min.js` | `axios` | HTTP(统一封装于 `src/api/`) |
+
+> OSS 根路径固定:`https://<自有OSS域名>/static/vendor/<库名>/<版本号>/<文件名>/`,**只增不删**(旧版本路径保留,回滚 = 改回 index.html 版本号)。
+
+### 1.3 业务层工具链(本地编译)
+
+| 关注点 | 选型 | 理由 / 依据 |
 |---|---|---|
-| 框架 | **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 |
+| 构建 | **Vite 6.x** | 业务代码 HMR + 产物构建;框架 external 后主 chunk 只剩业务代码 |
+| 语言 | **TypeScript strict** | 契约类型化:`R<T>` / `PageData<T>` / 各域 DTO;UMD 全局经 `src/types/globals.d.ts` 声明类型 |
+| UI 组件库 | **Element Plus 2.x**(UMD 自托管) | 教学 admin 现有栈,复用成本最低;zhCn locale 双注入 |
+| 状态 | **Pinia** | `login`(token/角色/权限码)+ `scope`(institution/campus 作用域) |
+| 路由 | **Vue Router 4** | 按端组织 + 守卫链(登录态 → 静默刷新 → 权限码 → 作用域就绪) |
+| HTTP | **axios 1.x**(UMD 自托管,封装于 `src/api/`) | 统一信封处理 + 401 refresh 单例重放;业务错误**不** reject |
+| 鉴权 | SSO token(access 30min + refresh 30 天,ADR-014) | 统一 identity 签发;菜单/按钮按**权限码**显隐,禁 `role == N` 硬编码 |
+| 包管理 | **pnpm 10.12.1**(lockfile 入库) | 本机已装;与移动端仓同栈 |
+| 代码风格 | ESLint 9 + Prettier 3 | 提交前 lint;`no-explicit-any` 强制 |
+| 类型检查 | vue-tsc `--noEmit` | 质量门禁 0 错误 |
+
+### 1.4 默认简体中文
+
+- `<html lang="zh-CN">`;页面文案、placeholder、提示一律中文,**默认且唯一**语言。
+- Element Plus **locale 双注入**(教务实战铁律):`app.use(ElementPlus, { locale: ElementPlusLocaleZhCn })`(命令式 ElMessageBox/Notification)+ `<el-config-provider :locale="ElementPlusLocaleZhCn">`(声明式),单用其一必有遗漏。
+- **不引入 vue-i18n**(7 角色全中文、无多语言需求);将来真需多语言再上 i18n 框架,属另立决策。
+
+### 1.5 框架升级规则(自托管五步,缺一不可)
+
+1. 下载新版本 UMD 文件 → 2. 覆盖仓库 `vendor/` 对应目录并 commit → 3. 上传 OSS 对应路径 → 4. 改 `index.html` 版本表 → 5. 全量回归(vue-tsc + build + 端点联调)。
+> 版本升级不再受 lockfile 保护,靠仓库 diff + 回归兜底;发布前 `vendor/` 与 OSS 内容 md5 对账。
 
 ## 2. 目录结构与用途
 
 ```
 .
-├── 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
+├── index.html                 ← 【框架层挂载点】lang="zh-CN";7 项 vendor 资源按固定顺序引入;
+│                                  头部注释含"vendor 版本表"(库 → OSS 路径 → 版本,一处维护);
+│                                  <div id="app"> + 业务入口 <script type="module" src="/src/main.ts">
+├── vendor/                    ← 【框架层自托管源文件】git 入库的版本事实(升级五步流程落点)
+│   ├── vue@x.y/                 vue.global.prod.js
+│   ├── vue-router@x.y/          vue-router.global.js
+│   ├── pinia@x.y/               pinia.iife.prod.js
+│   ├── element-plus@x.y/        index.full.min.js + index.css + locale/zh-cn.js
+│   └── axios@x.y/               axios.min.js
+│                                  (上传 OSS 经 /static/vendor/<库名>/<版本号>/ 暴露;只增不删)
+├── package.json               ← 仅【业务层工具链】:vite / @vitejs/plugin-vue / vue-tsc / eslint / prettier / typescript
+├── pnpm-lock.yaml             ← 工具链版本锁定(入库)
+├── vite.config.ts             ← ① rollup external:vue/vue-router/pinia/axios → 全局变量映射(运行时只认 UMD 全局)
+│                                  ② dev server:/api 代理 → 后端 dev 地址  ③ 产物 chunk 拆分(业务代码)
+├── tsconfig.json              ← strict 基线 + paths 别名(@ → src/)
+├── .env.example               ← 环境变量模板(VITE_API_BASE 等;实际 .env.* 走 .gitignore)
+└── src/                       ← 【业务层】全部业务代码(本地编译进 dist/)
+    ├── main.ts                ← 业务装配入口:取 UMD 全局 Vue.createApp + Element Plus locale 双注入
+    │                              + Pinia + Router 挂载;不 import 框架运行时
+    ├── types/
+    │   ├── globals.d.ts       ←   UMD 全局变量类型声明(declare global:Vue/VueRouter/Pinia/ElementPlus/axios)
+    │   └── api.d.ts           ←   契约类型:R<T> 信封 / PageData<T>(list,total,page,pageSize,pages)/ 角色与权限码
+    ├── views/                 ← 页面层(只放视图与页面级状态;禁散写 axios)
+    │   ├── academic/          ←   教务域:排班/费用/打卡/充值/报课 ——【新写】(旧 jQuery 视图全部重写)
+    │   ├── teaching/          ←   教学 admin:备课/题库/组卷/练习分析 ——【按现有 Vue3 逐步迁入】
+    │   ├── org/               ←   机构/校区/班级/成员管理
+    │   └── system/            ←   系统:用户/角色/字典/任务监控/日志
+    ├── components/            ← 跨页面复用组件:ListPage(表格+分页+筛选+批量收口)、作用域选择器
+    │                              (institution·campus 联动)、GradeBadge/SubjectBadge(色板纯数据零 Vue 依赖)
+    ├── api/                   ← 接口封装(一域一目录、一资源一文件):axios 实例 + 统一信封处理 +
+    │                              401 refresh 单例重放 + 分页统一解构 res.data.{list,total,page,pageSize,pages}
+    ├── router/                ← 路由表按端组织 + 守卫链:登录态 → 静默刷新 → 权限码 → 作用域就绪
+    ├── store/                 ← Pinia:login(token/角色/权限码)、scope(institution/campus)——唯一 token 存取点
+    ├── composables/           ← 可组合逻辑:useListPage<T>(列表页唯一规范入口)等
+    ├── utils/                 ← 纯函数工具集(无 Vue 依赖):日期/金额格式化、脱敏回显、下载/导出辅助
+    └── styles/                ← 全局样式:variables.scss(色板/间距 token)+ reset + Element Plus 主题覆盖
 ```
 
 **目录用途约定**:
 
 | 目录 | 用途 | 约束 |
 |---|---|---|
-| `src/views/{域}/` | 页面层,只放视图与页面级状态 | 禁止散写 fetch/axios;只经 `src/api/` |
+| `index.html` | 框架层挂载 + 版本表 | 7 项 vendor 引用**顺序固定**;版本号只改这里,禁止散落 src |
+| `vendor/` | 框架层源文件版本事实 | 与 OSS 内容一致(提交前 diff 核对);只增不删,禁止覆盖已发布旧版本路径 |
+| `src/views/{域}/` | 页面层(四域分包:academic/teaching/org/system) | 只经 `src/api/` 发请求;views 之间互引禁止(复用 → 上提 components/) |
 | `src/components/` | 跨页面复用组件 | 零业务耦合(作用域感知组件除外,从 store 读) |
-| `src/api/{域}/` | 接口封装(一域一目录,一资源一文件) | 统一信封处理收口在此;返回类型化 DTO |
+| `src/api/{域}/` | 接口封装(一域一目录,一资源一文件) | 信封处理与分页解构**只在此**;返回类型化 DTO |
 | `src/router/` | 路由与守卫 | 权限码驱动;不写 `role == N` 硬编码 |
-| `src/store/` | 全局状态(登录态/作用域) | 唯一 token 存取点(禁 localStorage 散写) |
+| `src/store/` | 全局状态(登录态/作用域) | 唯一 token 存取点(禁 localStorage 散写);scope 未就绪时守卫拦截 |
 | `src/composables/` | 可组合逻辑 | 列表页一律复用 `useListPage<T>` |
-| `src/types/` | 契约类型 | 与后端 DTO camelCase 对齐;`R<T>` 泛型 |
+| `src/utils/` | 纯函数工具集 | 文件内零组件、零 store 依赖;可被 composables/api/views 任意引用,反向禁止 |
+| `src/styles/` | 全局样式与 token | 业务组件 `<style>` 禁硬编码色值/尺寸,必须引 variables token;页面级局部样式留组件内 `<style scoped>` |
+| `src/types/` | 契约类型 | `R<T>`/`PageData<T>` 只在此定义一次;UMD 全局声明全覆盖(新增框架资源先补声明后写业务) |
 
 ## 3. 编码规范
 
-### 3.1 结构铁律
+### 3.1 命名规则
 
-1. **作用域(institution/campus)是全局状态**:所有业务页面查询必须带作用域,由 `store/scope` 统一注入,禁止页面各自拼 `schoolid/campusid`(对齐清单 §3:消灭控制器隐式参数)。
-2. **权限码驱动显隐**:菜单/按钮/路由守卫读统一 RBAC 权限码,不写 `role == N` 硬编码(对齐清单 §3 超管判据收敛)。
-3. **教务域页面为新写**(旧 DataTables/视图 jQuery 全部重写);**教学 admin 页面按现有 Vue3 逐步迁入**,契约不变。
-4. 接口调用只经 `src/api/`,禁止页面里散写 fetch/axios。
+| 对象 | 规则 | 示例 |
+|---|---|---|
+| 文件 | 组件 `PascalCase.vue`;其余 `kebab-case.ts` | `ListPage.vue`、`use-list-page.ts`、`grade-badge.ts` |
+| 组件 | 注册名 PascalCase,模板里 kebab-case | `<list-page>` / `ListPage` |
+| 组合式函数 | `useXxx` | `useListPage<T>()`、`useScope()` |
+| 变量/函数 | `camelCase` | `institutionId`、`handleSubmitRefund` |
+| 常量 | 模块内 `UPPER_SNAKE`(仅真常量:错误码段、权限码枚举) | `PERM_CODE` |
+| 接口/类型 | 名词 PascalCase,DTO 带域前缀 | `PageData<T>`、`AcademicFeeDTO`、`TeachingQuestionDTO` |
+| **API 字段** | **一律 `camelCase`**,与后端 DTO 严格对齐(`institutionId` 非 `institution_id`);禁止前端自造映射层 | — |
+| 路由 path | `kebab-case`,与后端端点一致(`/{端}/{模块}/{资源}`) | `/admin/academic/fees` |
+| 路由 name | PascalCase 页名 | `AcademicFeeList` |
+| 权限码 | **`域.资源.动作` 三段式**(点分) | `academic.fee.refund` |
+| 事件/方法 | 内部回调 `onXxx`;用户触发的提交类 `handleXxx` | `onScopeChange`、`handleDelete` |
+| 禁词 | 禁用 `userid/schoolid/campusid` 类旧系统无下划线混用命名 | — |
+
+### 3.2 文件组织
+
+**组件 SFC 骨架(顺序固定)**:
 
-### 3.2 接口与响应契约
+```
+<script setup lang="ts">   ← ① 类型 import(仅类型与本地 DTO,禁 import 框架运行时)
+                            ← ② defineProps/defineEmits 显式类型(禁 any,unknown 收窄)
+                            ← ③ store 注入(useLogin/useScope)
+                            ← ④ 响应式状态(ref/computed,单一数据源)
+                            ← ⑤ 生命周期(onMounted 拉数据)
+                            ← ⑥ 方法(handleXxx 在前,onXxx 在后)
+</script>
+<template>                  ← ⑦ 结构;列表页一律 <list-page> 收口
+</template>
+<style scoped>              ← ⑧ 局部样式;色值/尺寸引 @/styles/variables token
+```
 
-- 统一「**HTTP 恒 200 + body `code`**」信封 `{code, data, message, success}`;判成功读 `code === 200`,错误文案读 `message`,**不靠**拦截器 reject、**不靠** HTTP status(源自教务 Go 重构在产验证)。
-- 错误码分段(与后端一致):`1xxx` 认证/权限 · `2xxx` 参数 · `3xxx` 数据 · `4xxx` 依赖 · `5xxx` 系统;`1001/1002` 统一跳登录(refresh 失败才跳,access 过期先静默 refresh)。
-- **统一分页**:请求 `page`/`pageSize`(默认 1/10,上限 200);响应 `data` 恒为 `PageData` 对象 `{list, total, page, pageSize, pages}`,前端统一读 `res.data.list` / `res.data.total`(`useListPage<T>` 收口,不再区分分页/非分页两套读法)。
-- 命名:入参/出参 `camelCase`;组件 `PascalCase`;组合式函数 `useXxx`。
+**域目录内约定**:
+- `views/{域}/{模块}/`:`list.vue`(列表)+ `detail.vue`(详情)+ 页内私有子组件 `{模块}-xxx.vue`(私有组件**不放** `components/`);
+- `api/{域}/{资源}.ts`:一资源一文件,只导出该资源的请求函数 + 对应 DTO 类型;
+- 跨域引用只允许经 `api/` 与 `components/`。
 
-### 3.3 路由与鉴权
+### 3.3 组件编写
 
-- 路由守卫顺序:登录态(access 有效?)→ 刷新(过期且有 refresh 则静默换)→ 角色/权限码 → 作用域就绪(scope 已注入)。
-- 刷新单例:并发 401/过期只触发一次 refresh(Promise 复用),成功后重放原请求。
-- 敏感操作(充值/退款/改密)二次确认 + 操作留痕(后端审计)。
+1. **框架运行时全走 UMD 全局**:`src/` 内**禁止** `import Vue/VueRouter/Pinia/ElementPlus/axios`;组合 API 标识符经 vite `define` 注入映射到 UMD 全局(或统一 `const { ref } = Vue` 解构,两种写法脚手架定稿时二选一),规范条文恒为"禁 import 框架"。
+2. **Props**:显式 `interface` 类型;可选项给默认值;禁内联 `any`。
+3. **状态最小化**:能用 store 的(token/scope/权限码)不本地存;列表状态收口 `useListPage<T>`(page/pageSize/total/loading 全在里面,组件只传 fetcher)。
+4. **作用域纪律**:业务查询参数里的 `institutionId/campusId` **只从 `useScope()` 取**,禁止页面自拼(对齐后端"作用域强制注入",消灭旧系统隐式 `schoolid` 坑)。
+5. **表单**:`el-form` + 显式 `rules`(提交前 `validate()`);服务端 2001 错误 message 直接 toast,前端规则只拦格式。
+6. **表格**:列定义数组化(`prop/label/width/formatter` 数据驱动),新增列不改模板结构。
+7. **权限**:按钮级 `v-perm="'域.资源.动作'"` 自定义指令(读 login store 权限码集);**禁止 `role === N` 硬编码**。
+8. **三态**:所有异步区域必须有 loading + 空态 + 错误态;错误态展示后端 message(已脱敏),不二次包装文案。
+9. **敏感操作**(充值/退款/改密/删除):`ElMessageBox.confirm` 二次确认 + 操作后刷新 + 后端留痕。
+10. **脱敏**:手机号/身份证直接展示后端已脱敏值,前端不存明文、不二次处理。
 
-### 3.4 可复用资产与惯例(源自教务 Go 重构实战)
+### 3.4 接口与响应契约(前后端统一,2026-11-05 拍板)
 
-- **列表页规范**:`useListPage<T>` + `ListPage.vue`(分页/筛选/批量操作收口);年级 `<GradeBadge>`(数字=年级 id + 学段色系)、科目 `<SubjectBadge>`(首字简称 + 独立色系)——色板纯数据零 Vue 依赖,新增列表页一律复用。
-- **locale 双注入**:Element Plus 默认英文,需 `app.use(ElementPlus, {locale: zhCn})`(命令式 ElMessageBox/Notification)+ `<el-config-provider :locale>`(声明式)**双注入**,单用其一必有遗漏;locale 引 `element-plus/es/locale/lang/zh-cn`。
-- **脱敏展示**:手机号/身份证按后端已脱敏值展示,前端不再二次处理(源头脱敏)。
+- 统一「**HTTP 恒 200 + body `code`**」信封 `{code, data, message, success}`;判成功读 `code === 200`,错误文案读 `message`,**不靠**拦截器 reject、**不靠** HTTP status(源自教务 Go 重构在产验证)。
+- 错误码分段(与后端一致):`1xxx` 认证/权限 · `2xxx` 参数 · `3xxx` 数据 · `4xxx` 依赖 · `5xxx` 系统;`1001/1002` 统一走 refresh 单例(并发只刷一次,Promise 复用),成功后重放原请求;refresh 失败才清 login store 跳登录。错误 toast 去重:同一 message 1s 内不重复弹。
+- **统一分页**:请求 `page`/`pageSize`(默认 1/10,上限 200);响应 `data` 恒为 `PageData` 对象 `{list, total, page, pageSize, pages}`,`useListPage<T>` 统一解构 `res.data.{list, total, page, pageSize, pages}`,组件层只见 `rows/total` 两个绑定(不再区分分页/非分页两套读法)。
+
+### 3.5 类型纪律(TS strict)
 
-### 3.5 质量门禁
+- `any` 全面禁用(vue-tsc + ESLint `no-explicit-any` 双卡);未知结构用 `unknown` + 类型收窄。
+- DTO 与后端字段**逐字段**对齐:新增接口先补 `api/{域}/{资源}.ts` 类型定义再写调用;禁止"先 any 后补类型"。
+- `R<T>`/`PageData<T>` 泛型只在 `types/api.d.ts` 定义一次,全仓引用。
 
-| 门禁 | 命令 | 基线 |
+### 3.6 质量门禁
+
+| 门禁 | 命令 / 做法 | 基线 |
 |---|---|---|
 | 类型检查 | `vue-tsc --noEmit` | 0 错误 |
-| 构建 | `pnpm build`(vite) | 主 chunk < 1024KB |
+| 构建 | `pnpm build`(vite) | 0 错误;主 chunk < 1024KB;**dist/ 产物 grep 不得含 vue/element-plus 运行时**(防 external 配错回退成本地打包) |
 | Lint | `pnpm lint`(eslint + prettier) | 0 错误 |
+| vendor 一致性 | 发布前 `vendor/` 与 OSS 路径内容 md5 对账 | 一致方可发布 |
+| 端点联调 | 真实登录 token → 页面操作 → 断言 body code + 结构 | 结构不符先查后端路由重复注册 |
 
-### 3.6 Git 与提交规范
+### 3.7 Git 与提交规范
 
 - **工程纪律**:本地 commit 可执行;**脚手架搭建与 `git push` 前必须经用户确认**(逐次确认)。
-- 提交信息:conventional commits(`feat:` / `fix:` / `chore:` / `docs:` / `refactor:`)。
-- 提交前自检:`vue-tsc` + `pnpm build` 通过;敏感值未入库(`.env` 走 .gitignore,仅 `.env.example` 入库)。
+- 提交信息:conventional commits(`feat:` / `fix:` / `chore:` / `docs:` / `refactor:`),正文写清影响域。
+- 提交前自检:`vue-tsc` + `pnpm build` 通过;敏感值未入库(`.env` 走 .gitignore,仅 `.env.example` 入库);**vendor 变更必须与 index.html 版本表同步提交**。
 
 ## 4. 构建与本地运行
 
 ```bash
-pnpm install          # 依赖(pnpm 10.x;lockfile 入库)
-pnpm dev              # 本地开发(vite dev,/api 代理到后端 dev 地址)
-pnpm build            # 产物 → dist/(部署经 nginx)
+pnpm install          # 工具链依赖(pnpm 10.12.1;lockfile 入库)
+pnpm dev              # 本地开发(vite dev,业务代码 HMR;框架层自 OSS 加载;/api 代理到后端 dev 地址)
+pnpm build            # 产物 → dist/(仅业务代码;部署经 nginx 按 location 分发,ADR-010)
 ```
 
 **环境变量**(`.env.example` 入库,实际 `.env.*` 不入库):`VITE_API_BASE`(后端 base,dev 走 vite proxy 时可省)。
 
+**框架层升级**:执行 §1.5 五步流程(下载 → 覆盖 vendor/ 并 commit → 上传 OSS → 改 index.html 版本表 → 全量回归)。
+
 ## 5. 与文档目录的关系
 
 - 本仓库**只放前端代码**;接口契约、端点清单、错误码见工作区文档库 `academic/05-architecture/` 与 `teaching/05-architecture/`;前端策略(重写 vs 复用)见 `unified/00-planning/cross-system-reconciliation.md` §5。
-- 与移动端仓库共享编码惯例(统一信封/脱敏/权限码/commit 规范),差异仅在 UI 库与路由形态。
+- 与移动端仓库共享编码惯例(统一信封/统一分页 PageData/脱敏/权限码三段式/commit 规范),差异:PC 端为 UMD 自托管 + 单项目,移动端为 pnpm monorepo + Vant 4。