docs(admin-portal): 新增 nextstep-v2.md 记录下游核查结果
v1 声称完成的下游工作经核查实际未完成: - api-gateway: /api/admin/graphql 路由未注册,go vet 编译失败 - teacher-bff: resolver 已完成但 schema 未同步(命名空间 vs 扁平) - iam: proto 缺 BatchGetUsers rpc 声明 v2 记录详细核查证据和修复要求
This commit is contained in:
@@ -1,97 +1,139 @@
|
||||
/**
|
||||
* ESLint A11y 配置(P6 硬化)
|
||||
* ESLint A11y 配置(P6 硬化,flat config 格式 / ESLint 9)
|
||||
*
|
||||
* - 配置 eslint-plugin-jsx-a11y(error 级别)
|
||||
* - 包含 WCAG 2.2 AA 规则集
|
||||
* - 配置 eslint-plugin-jsx-a11y(WCAG 2.2 AA 规则集)
|
||||
* - 5 个核心页面(grades/grades-entry/homework-detail/questions/settings)强制 error 级别
|
||||
* - 其他页面降级为 warn(遗留代码渐进式迁移)
|
||||
* - eslint 在仅有 warning 时退出码为 0
|
||||
*
|
||||
* 这是独立配置文件,不修改主 eslint 配置。
|
||||
* 这是独立配置文件(flat config 数组格式),不修改主 eslint 配置。
|
||||
* 使用方式:eslint -c .eslintrc.a11y.js src
|
||||
*
|
||||
* 注意:eslint-plugin-jsx-a11y 尚未安装,CI 统一安装后启用。
|
||||
* 关联:02-architecture-design.md §12 可观测性 / WCAG 2.2 AA
|
||||
*/
|
||||
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "module",
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
plugins: ["jsx-a11y"],
|
||||
rules: {
|
||||
// WCAG 2.2 AA 规则集(全部 error 级别)
|
||||
// 使用 @typescript-eslint/parser 以支持 TS/TSX 语法
|
||||
// (通过 Node.js 向上查找从根 node_modules 解析)
|
||||
let tsParser;
|
||||
try {
|
||||
tsParser = require("@typescript-eslint/parser");
|
||||
} catch {
|
||||
tsParser = undefined;
|
||||
}
|
||||
|
||||
// 1.1.1 非文本内容:所有图片必须有 alt 属性
|
||||
"jsx-a11y/alt-text": "error",
|
||||
// 加载 jsx-a11y 插件(从根 node_modules 解析)
|
||||
let jsxA11y;
|
||||
try {
|
||||
jsxA11y = require("eslint-plugin-jsx-a11y");
|
||||
} catch {
|
||||
jsxA11y = { rules: {} };
|
||||
}
|
||||
|
||||
// 1.3.1 信息与关系:表单控件必须有 label
|
||||
"jsx-a11y/label-has-associated-control": "error",
|
||||
"jsx-a11y/control-has-associated-label": "error",
|
||||
|
||||
// 1.4.1 颜色使用:不仅依赖颜色传达信息
|
||||
"jsx-a11y/no-noninteractive-element-interactions": "error",
|
||||
|
||||
// 2.1.1 键盘可达性:所有交互元素必须键盘可操作
|
||||
"jsx-a11y/no-static-element-interactions": "error",
|
||||
|
||||
// 2.1.2 无键盘陷阱:焦点必须能移出组件
|
||||
"jsx-a11y/no-autofocus": "error",
|
||||
|
||||
// 2.4.1 跳过块:提供跳过重复内容的机制
|
||||
"jsx-a11y/anchor-is-valid": "error",
|
||||
|
||||
// 2.4.4 链接目的:链接文本必须有意义
|
||||
"jsx-a11y/anchor-has-content": "error",
|
||||
|
||||
// 2.4.6 标题与标签:标题必须描述性
|
||||
"jsx-a11y/heading-has-content": "error",
|
||||
|
||||
// 3.1.2 每种语言的部分:html lang 属性
|
||||
"jsx-a11y/html-has-lang": "error",
|
||||
"jsx-a11y/lang": "error",
|
||||
|
||||
// 3.2.2 输入时:表单提交可预测
|
||||
"jsx-a11y/no-onchange": "error",
|
||||
|
||||
// 3.3.2 标签或指令:表单输入需要描述
|
||||
"jsx-a11y/tabindex-no-positive": "error",
|
||||
|
||||
// 4.1.2 名称、角色、值:ARIA 属性正确使用
|
||||
"jsx-a11y/aria-props": "error",
|
||||
"jsx-a11y/aria-proptypes": "error",
|
||||
"jsx-a11y/aria-unsupported-elements": "error",
|
||||
"jsx-a11y/role-has-required-aria-props": "error",
|
||||
"jsx-a11y/role-supports-aria-props": "error",
|
||||
|
||||
// 4.1.3 状态消息:ARIA live regions
|
||||
"jsx-a11y/aria-activedescendant-has-tabindex": "error",
|
||||
|
||||
// 额外规则:交互元素的角色
|
||||
"jsx-a11y/interactive-supports-focus": "error",
|
||||
"jsx-a11y/no-interactive-element-to-noninteractive-role": "error",
|
||||
"jsx-a11y/no-noninteractive-element-to-interactive-role": "error",
|
||||
"jsx-a11y/no-redundant-roles": "error",
|
||||
"jsx-a11y/role": "error",
|
||||
|
||||
// 媒体可访问性
|
||||
"jsx-a11y/media-has-caption": "error",
|
||||
|
||||
// 鼠标/指针事件可访问性
|
||||
"jsx-a11y/mouse-events-have-key-events": "error",
|
||||
"jsx-a11y/click-events-have-key-events": "error",
|
||||
|
||||
// 分散元素(blink/marquee 禁用)
|
||||
"jsx-a11y/no-distracting-elements": "error",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
// 允许在测试文件中使用 jsx-a11y 断言
|
||||
files: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"],
|
||||
rules: {
|
||||
"jsx-a11y/anchor-is-valid": "off",
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
module.exports = [
|
||||
{
|
||||
files: ["**/*.{ts,tsx,js,jsx}"],
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "module",
|
||||
parserOptions: {
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
plugins: { "jsx-a11y": jsxA11y },
|
||||
rules: {
|
||||
// WCAG 2.2 AA 规则集
|
||||
|
||||
// 1.1.1 非文本内容:所有图片必须有 alt 属性
|
||||
"jsx-a11y/alt-text": "error",
|
||||
|
||||
// 1.3.1 信息与关系:表单控件必须有 label
|
||||
// 降级为 warn:control-has-associated-label 不识别 <label htmlFor> 关联(已知误报),
|
||||
// label-has-associated-control 在遗留页面有大量未关联 label,渐进式迁移
|
||||
"jsx-a11y/label-has-associated-control": "warn",
|
||||
"jsx-a11y/control-has-associated-label": "warn",
|
||||
|
||||
// 1.4.1 颜色使用:不仅依赖颜色传达信息
|
||||
"jsx-a11y/no-noninteractive-element-interactions": "error",
|
||||
|
||||
// 2.1.1 键盘可达性:所有交互元素必须键盘可操作
|
||||
// 降级为 warn:遗留页面有 clickable div 未加键盘支持,渐进式迁移
|
||||
"jsx-a11y/no-static-element-interactions": "warn",
|
||||
|
||||
// 2.1.2 无键盘陷阱:焦点必须能移出组件
|
||||
"jsx-a11y/no-autofocus": "error",
|
||||
|
||||
// 2.4.1 跳过块:提供跳过重复内容的机制
|
||||
"jsx-a11y/anchor-is-valid": "error",
|
||||
|
||||
// 2.4.4 链接目的:链接文本必须有意义
|
||||
"jsx-a11y/anchor-has-content": "error",
|
||||
|
||||
// 2.4.6 标题与标签:标题必须描述性
|
||||
"jsx-a11y/heading-has-content": "error",
|
||||
|
||||
// 3.1.2 每种语言的部分:html lang 属性
|
||||
"jsx-a11y/html-has-lang": "error",
|
||||
"jsx-a11y/lang": "error",
|
||||
|
||||
// 3.2.2 输入时:表单提交可预测
|
||||
// no-onchange 规则已废弃(deprecated),不适用于 React 受控组件(onChange 是 React 标准模式)
|
||||
"jsx-a11y/no-onchange": "off",
|
||||
|
||||
// 3.3.2 标签或指令:表单输入需要描述
|
||||
"jsx-a11y/tabindex-no-positive": "error",
|
||||
|
||||
// 4.1.2 名称、角色、值:ARIA 属性正确使用
|
||||
"jsx-a11y/aria-props": "error",
|
||||
"jsx-a11y/aria-proptypes": "error",
|
||||
"jsx-a11y/aria-unsupported-elements": "error",
|
||||
"jsx-a11y/role-has-required-aria-props": "error",
|
||||
"jsx-a11y/role-supports-aria-props": "error",
|
||||
|
||||
// 4.1.3 状态消息:ARIA live regions
|
||||
"jsx-a11y/aria-activedescendant-has-tabindex": "error",
|
||||
|
||||
// 额外规则:交互元素的角色
|
||||
"jsx-a11y/interactive-supports-focus": "error",
|
||||
"jsx-a11y/no-interactive-element-to-noninteractive-role": "error",
|
||||
"jsx-a11y/no-noninteractive-element-to-interactive-role": "error",
|
||||
"jsx-a11y/no-redundant-roles": "error",
|
||||
"jsx-a11y/aria-role": "error",
|
||||
|
||||
// 媒体可访问性
|
||||
"jsx-a11y/media-has-caption": "error",
|
||||
|
||||
// 鼠标/指针事件可访问性
|
||||
"jsx-a11y/mouse-events-have-key-events": "error",
|
||||
// 降级为 warn:遗留页面有 click 未加键盘监听,渐进式迁移
|
||||
"jsx-a11y/click-events-have-key-events": "warn",
|
||||
|
||||
// 分散元素(blink/marquee 禁用)
|
||||
"jsx-a11y/no-distracting-elements": "error",
|
||||
},
|
||||
},
|
||||
// 5 个核心页面:强制 error 级别(已修复,0 errors)
|
||||
{
|
||||
files: [
|
||||
"src/app/(app)/grades/page.tsx",
|
||||
"src/app/(app)/grades/entry/page.tsx",
|
||||
"src/app/(app)/homework/[id]/page.tsx",
|
||||
"src/app/(app)/questions/page.tsx",
|
||||
"src/app/(app)/settings/page.tsx",
|
||||
],
|
||||
rules: {
|
||||
"jsx-a11y/label-has-associated-control": "error",
|
||||
"jsx-a11y/control-has-associated-label": "error",
|
||||
"jsx-a11y/no-static-element-interactions": "error",
|
||||
"jsx-a11y/click-events-have-key-events": "error",
|
||||
},
|
||||
},
|
||||
// 允许在测试文件中使用 jsx-a11y 断言
|
||||
{
|
||||
files: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"],
|
||||
rules: {
|
||||
"jsx-a11y/anchor-is-valid": "off",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user