前端规范(Angular + fmode-ng 数据访问)
定位:Angular 前端工程纪律(目录/组件/服务/数据访问/表单/性能/Mock)。UI 视觉与交互见 18-UI设计规范.md。
负面清单(Do Not)
- [禁止] 组件模板中使用 *ngIf/*ngFor/*ngSwitch(用新控制流 @if/@for/@switch)
- [禁止] 组件模板内直接 .subscribe()(用 async pipe 或信号)
- [禁止] 组件/服务裸 fetch(必须走 shared/utils/api.ts 的 apiFetch/apiFetchSse)
- [禁止] 绕过 fmode-ng 裸调官方 parse SDK(数据访问统一 FmodeParse.with() 实例)
- [禁止] 重复 FmodeParse.initialize 或在业务代码中硬编码 serverURL
- [禁止] 类型使用 any(用 unknown 收窄或明确类型)
- [禁止] bypassSecurityTrustHtml / innerHTML 渲染用户输入(XSS)
- [禁止] 手动 new 服务(用依赖注入)
- [禁止] 硬编码远程地址、密钥、魔法数字/字符串
- [禁止] 订阅不取消导致内存泄漏(必须 takeUntilDestroyed / 手动取消)
- [禁止] 忽略 OnPush 变更检测策略
- [禁止] 绕过包内官方 UI 组件底座(ui-kit)自写同功能组件(组件唯一来源,见 18-UI设计规范.md 二)
必须规则(目录与组件)
- [必须] 目录边界:core(单例)全局守卫/拦截器/全局服务/应用级配置,仅入口引用一次,禁止在 feature 重复 import;shared(无业务状态)纯展示组件/管道/directive/工具函数/图标白名单;features(业务域)域内自含 pages/components/services/models,域与域禁止互 import,公共部分上提 shared。
- [必须] 文件命名:xxx.component.ts/.service.ts/.guard.ts/.pipe.ts/.directive.ts/.model.ts;目录 kebab-case。
- [必须] Standalone + OnPush:新代码一律 standalone 组件 + ChangeDetectionStrategy.OnPush。
- [必须] Signals:状态用 signal()、派生状态用 computed()、副作用少用 effect();对外暴露 asReadonly();不引入 NgRx/Redux 等重型状态库。
- [必须] 组件职责:组件只做展示与交互,业务逻辑一律下沉服务;组件间通信用 input()/output(),禁止直接操作全局状态。
- [必须] 模板质量:模板保持简洁(超 200 行拆子组件);复杂表达式移入 computed/方法;列表渲染必须 @for ... track 唯一键;长列表用 CDK Virtual Scroll。
必须规则(服务与数据)
- [必须] 服务职责单一:数据服务(HTTP)与状态服务分开;默认 provideIn: 'root'。
- [必须] 统一请求封装:所有 HTTP 走 shared/utils/api.ts(apiFetch/apiFetchSse/getAuthHeaders/ApiError);loading/error 状态统一处理(信号 + 统一错误展示组件)。
- [必须] 会话失效统一处理:apiFetch 统一拦截 401 → 清除本地会话 → 跳转登录页;token 过期不静默失败。
- [必须] 类型集中:数据接口类型集中在 models;前后端共享类型走 packages/shared(workspace 协议引用),前端私有类型放 apps/web/src/app/core/models。
必须规则(数据访问 fmode-ng)
- [必须] 初始化唯一入口:FmodeParse.initialize 只在 app.config 初始化阶段执行一次,serverURL 只在这里配置;其余服务/组件用 FmodeParse.with('dev') 取实例(见 05-数据访问与数据库.md)。
- [必须] 数据获取走 fmode-ng 查询:列表/详情用 new Parse.Query('Xxx') + 租户过滤(equalTo('company', ...)) + 软删过滤(notEqualTo('isDeleted', true));渲染直接用 FmodeObject,模板里 obj?.get('field') 取值,不必 toJSON();@for 必须 track item.id。
- [必须] 加载状态管理:数据加载 loading/error 状态用信号管理 + 统一错误展示组件;切换 Mock 与真实数据只改一个开关/服务,不改 UI 组件。
必须规则(表单/路由/样式)
- [必须] Reactive Forms:表单一律响应式表单;错误提示用统一指令/组件,禁止每页自写;提交中禁用按钮防重复提交。
- [必须] 路由:路由懒加载 + 守卫;敏感页面加 canActivate: [AuthGuard];路径/参数 kebab-case;query 参数必须显式类型转换。
- [必须] 样式:Tailwind 优先,组件样式 scoped;禁止全局样式污染;主题变量集中定义(直接继承包内 ui-kit 的 styles.css token 与 tailwind.config.js 映射,见 18-UI设计规范.md 一)。
必须规则(性能/安全/缓存)
- [必须] 订阅管理:组件内订阅用 takeUntilDestroyed();async pipe 优先。
- [必须] 时间统一:展示用统一日期格式化管道;存储统一 ISO 字符串,本地化展示。
- [必须] 缓存规范:localStorage 统一命名空间+版本化(key 前缀+版本,升级时清理旧缓存);图片缓存复用 image-cache 工具;远程数据缓存需考虑失效策略。
- [必须] 图标按需:新增图标必须登记到 icon-set.ts 白名单,禁止全量引入 FontAwesome 图标包。
必须规则(Mock 数据)
- [必须] Mock 先行:开发与演示阶段先用 Mock 数据让界面可见,再切换真实数据;Mock 与真实数据共用同一套类型/字段结构,切换只改数据源开关(一个开关/服务),禁止改 UI 组件。
- [必须] 关联型 Mock:Mock 数据必须像真实业务一样相互关联,禁止散落孤立的随意假数据——跨表引用 ID 一致(引用的 objectId 必须能在对应 Mock 文件中找到,Pointer 用 { __type, className, objectId } 结构与真实 Parse 一致);字段名/类型与 docs/schema/ 范式及 FmodeSchema 定义完全一致(含 objectId/company/isDeleted/createdAt);同一份 Mock 用同一个 company ID 串起体现租户隔离;覆盖正常态/边界态(空值/超长/极端值)/异常态便于 UI 兜底验证;数据脱敏并标注「示例数据」,不得伪造真实个人/企业敏感信息。
建议规则
- [建议] 组件复用门槛:同一 UI 模式出现 ≥2 处才抽取公共组件(避免过早抽象)。
- [建议] 性能基线:首屏懒加载控制包体积;列表数据量级大时前端分页或虚拟滚动,禁止一次渲染万级 DOM。