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