@lark-apaas/coding-steering 0.1.61 → 0.1.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-steering",
3
- "version": "0.1.61",
3
+ "version": "0.1.63",
4
4
  "description": "Stack-specific steering content for miaoda-coding templates",
5
5
  "type": "module",
6
6
  "files": [
@@ -88,7 +88,7 @@ interface UserSimpleDTO {
88
88
  larkUserID?: number; // 飞书内部数字 ID,禁用(飞书 API 不认)
89
89
  department?: DepartmentSimpleDTO;
90
90
  employeeID?: string; // 飞书企业内 user_id,调飞书开放平台 API 用它
91
- larkID?: string; // 飞书用户全局唯一 ID(larkUserID 别名),禁用
91
+ larkID?: string; // 飞书用户全局唯一 ID(larkUserID 别名),禁传飞书 API;转妙搭 userId 用 AuthNPaasService.getBatchMiaodaUserIdsByLarkIds
92
92
  miaodaUserID?: string; // 妙搭用户 ID(userID 别名)
93
93
  }
94
94
 
@@ -198,7 +198,7 @@ interface SearchUserEntity {
198
198
  email?: string;
199
199
  userStatus?: number;
200
200
  employeeID?: string; // 飞书企业内 user_id,调飞书开放平台 API 用它
201
- larkID?: string; // larkUserID 别名,禁用
201
+ larkID?: string; // larkUserID 别名,禁传飞书 API(转妙搭 userId 见上)
202
202
  miaodaUserID?: string; // userID 别名
203
203
  }
204
204
 
@@ -704,6 +704,11 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
704
704
  - **全栈项目禁止 mock 数据**:只要有服务端接口就当全栈对待,严禁 mock。纯前端项目(静态展示、无后端)可以使用 mock
705
705
  - **提交前检查 mock 残留**:禁止硬编码用户 ID、项目 ID 等 mock 数据。提交前确认无 `"user_xxx"`、`"project_1"` 等占位值
706
706
 
707
+
708
+ ### 后端异常响应与前端错误提示
709
+ - 后端异常结构为 `{ "error": { "code": "CONFLICT", "message": "具体错误信息", "fieldErrors": { "字段": ["错误"] } } }`,顶层没有 `message`。
710
+ - 前端展示接口错误(catch、`toast.error`、页面错误态)读 `error.response?.data?.error?.message`,取不到再用第一条 `fieldErrors` 文案或调用方的兜底文案,不用 axios 的 `error.message`;403 按 authz-guide 统一处理,不在业务 catch 里判断。
711
+
707
712
  ## 日志与错误处理
708
713
 
709
714
  - **日志**: 必须用 `logger` from `@lark-apaas/client-toolkit/logger`,**禁止所有 console 方法**
@@ -60,11 +60,11 @@ match-template-name: nestjs-react-fullstack
60
60
 
61
61
  | 兼容字段 | 标准替代 | 为什么禁用 |
62
62
  |---|---|---|
63
- | **lark_id** | employee_id | 纯数字内部 ID,飞书开放平台 API 无法识别,传入报错或返回空 |
63
+ | **lark_id** | employee_id | 纯数字 LarkID(飞书全局 ID),飞书开放平台 API 无法识别,传入报错或返回空。**唯一例外**:要把 LarkID 转成妙搭 userId 时,用 `AuthNPaasService.getBatchMiaodaUserIdsByLarkIds`(见 `user-identity`) |
64
64
  | **lark_department_id** | open_department_id | 纯数字内部 ID,飞书 API 只接受 od- 格式 |
65
65
  | **lark_chat_id** | open_chat_id | 纯数字内部 ID,飞书 IM API 只接受 oc_ 格式 |
66
66
 
67
- > 搜人返回里同时有 `lark_id` 和 `employee_id` 时,**必须取 `employee_id`**;用户提到 lark_id 时主动纠正。
67
+ > 搜人返回里同时有 `lark_id` 和 `employee_id` 时,调飞书 API **必须取 `employee_id`**;用户提到 lark_id 时先问用途:调飞书 API → 纠正为 employee_id;要转妙搭 userId(或反向)→ 按 `user-identity` 用 `AuthNPaasService` 的 LarkID 方法。
68
68
 
69
69
  ### 1.5 废弃名称映射
70
70
 
@@ -139,7 +139,7 @@ match-template-name: nestjs-react-fullstack
139
139
 
140
140
  ### ID 转换接口
141
141
 
142
- 外部用户 / 取 open_id·union_id 时用 `id_convert`,详见 [`feishu` skill › references/id-convert.md](../../../feishu/references/id-convert.md)。
142
+ 外部用户 / 取 open_id·union_id:模板内用 `AuthNPaasService.getBatchOpenIds` / `getBatchUnionIds`(反向 `getBatchMiaodaUserIdsByOpenIds` / `ByUnionIds`,见 `user-identity`);模板外才用 [`feishu` › id-convert.md](../../../feishu/references/id-convert.md)。
143
143
 
144
144
  ---
145
145
 
@@ -160,7 +160,7 @@ match-template-name: nestjs-react-fullstack
160
160
 
161
161
  | 字段 | 获取方式 |
162
162
  |---|---|
163
- | open_id / union_id | id_convert 接口 + 开放平台应用凭证(见 feishu › id-convert.md) |
163
+ | open_id / union_id | 模板内 `AuthNPaasService.getBatchOpenIds` / `getBatchUnionIds`(`feishuClientId` 传 open_id 所属飞书应用 App ID,见 `user-identity`);模板外 id_convert + 开放平台应用凭证 |
164
164
 
165
165
  ### Level 4 — 搜人拿不到的字段(需开放平台通讯录 API + 字段权限)
166
166
 
@@ -197,7 +197,7 @@ match-template-name: nestjs-react-fullstack
197
197
  |---|---|
198
198
  | 工号 / 手机号 / 职位 / 性别 / 直属上级 | 搜人带 **needFullFields=true**(Level 2,无需开平,follow admin 权限) |
199
199
  | 在职状态 / 入职时间 / 自定义字段 | 引导开平应用 → 通讯录 API(场景 B,Level 4) |
200
- | open_id / union_id | 引导配置应用 → id_convert(场景 A,Level 3) |
200
+ | open_id / union_id | 模板内 `AuthNPaasService`(Level 3),无需引导配置开平应用 |
201
201
  | 部门信息 | 直接取 open_department_id |
202
202
  | 发消息给某人 | 取 miaoda_user_id 传插件 |
203
203
  | 批量同步部门/全员、定时同步 | 引导配置应用 → 通讯录 API(场景 A) |
@@ -276,7 +276,7 @@ export class TicketService {
276
276
  ---
277
277
 
278
278
  ## 七、禁止行为
279
- 1. **禁用兼容字段**:任何调用不得用 lark_id / lark_department_id / lark_chat_id
279
+ 1. **禁用兼容字段**:调飞书 API / 插件不得用 lark_id / lark_department_id / lark_chat_id(LarkID ↔ 妙搭 userId 互转除外,见 `user-identity`)
280
280
  2. **禁止混用废弃名**:不得用 userID / suda_user_id / larkUserId 等旧名
281
281
  3. **禁止给飞书内置插件传 employee_id**:插件入参必须是 miaoda_user_id
282
282
  4. **禁止让用户手动做 ID 转换**:Agent 自动判断并执行
@@ -290,7 +290,7 @@ export class TicketService {
290
290
  |---|---|
291
291
  | 用户说"获取 user_id" | 追问:妙搭 miaoda_user_id 还是飞书 employee_id? |
292
292
  | 用户说要 `lark_user_id` / "飞书用户ID" / "飞书 ID" | 多数指**可用的飞书 user_id = `employee_id`**。搜人/选择器结果里**没有**叫 lark_user_id 的字段、可用的就是 `employee_id`,**别返回禁用的纯数字 `lark_id`**;当前登录用户场景取 `useCurrentUserProfile().lark_user_id`(== employee_id)。歧义时确认"是调飞书 API 用吗",是则一律 employee_id |
293
- | 用户用了 lark_id | 纠正:"lark_id 是禁用兼容字段,飞书 API 不认,请用 employee_id(搜人已默认返回)" |
293
+ | 用户用了 lark_id | 若是传飞书 API:纠正"lark_id 飞书 API 不认,请用 employee_id(搜人已默认返回)";若是要转成妙搭 userId:用 `AuthNPaasService.getBatchMiaodaUserIdsByLarkIds`(见 `user-identity`) |
294
294
  | 用户用了 lark_department_id | 纠正:"请用 open_department_id(od- 格式)" |
295
295
  | 用户用了 lark_chat_id | 纠正:"请用 open_chat_id(oc_ 格式)" |
296
296
  | 外部用户请求 employee_id | 说明外部用户无 employee_id,建议 open_id(需 id_convert) |
@@ -43,16 +43,16 @@ metadata:
43
43
 
44
44
  索引只帮助初步选择,不表示某类应用只能使用某个风格。同一种应用通常有多个合理候选。比较候选时,先按主要界面机制缩小范围,而不是按行业名称决定:
45
45
 
46
- - 高频操作、表格和表单为主:区分标准组件化软件、温和紧凑的指标工作台、开阔的数据分析画布、绿色轻影的任务与指标面板。
47
- - 报告、知识和连续阅读为主:区分冷静的纸面规格文档、人文研究编辑界面、杂志式纸张层次、新闻印刷结构。
46
+ - 高频操作、表格和表单为主:区分标准组件化软件、冷白平面与企业蓝焦点的紧凑组件系统、温和紧凑的指标工作台、开阔的数据分析画布、绿色轻影的任务与指标面板。
47
+ - 报告、知识和连续阅读为主:区分冷静的纸面规格文档、米白纸面与等宽台账构成的数据报告、人文研究编辑界面、杂志式纸张层次、新闻印刷结构。
48
48
  - 强视觉展示或沉浸浏览为主:区分深色技术面板、毛玻璃舞台、明暗叙事区块、粗边硬影或漫画拼贴。
49
49
  - 轻量查询、填写或个人工具:只有大留白、超大圆角、自然色和稀疏结构确实适合主要操作时,才使用对应的有机方向;需要密集表格或连续高频操作时,回到操作型候选。
50
50
 
51
51
  在相邻候选之间,按下面的视觉机制完成最后比较;这些差异只解释已有索引,不改变各风格含义:
52
52
 
53
- - 明亮操作与数据界面:区分标准化中圆角组件与完整明暗模式、暖米白细边无影的紧凑指标台、绿色轻影指标卡、开阔浅蓝分析区域、直角蓝线编号结构和工程图纸标记。
53
+ - 明亮操作与数据界面:区分标准化中圆角组件与完整明暗模式、冷白浅灰平面与企业蓝焦点、暖米白细边无影、草绿浅影卡片、白色与浅蓝静区、直角蓝线编号结构和工程图纸标记。
54
54
  - 深色技术与分析界面:区分绿色终端语法、蓝黑圆角嵌套面板、紫色紧凑直角面板、红色毛玻璃舞台和明暗交替的深红叙事区块。
55
- - 文档与编辑界面:区分冷灰蓝单栏规格纸、人文奶油研究界面、旋转纸卡杂志层次和黑白新闻印刷结构。
55
+ - 文档与编辑界面:区分冷灰蓝规格纸、米白纸面上的衬线数字与等宽台账、人文奶油研究界面、旋转纸卡杂志层次和黑白新闻印刷结构。
56
56
  - 轻量与表达型界面:区分白底超大圆角自然留白、暖黄渐变与深浅卡片、手写纸张、黑白橙粗边硬影和高饱和漫画拼贴。
57
57
 
58
58
  采用一个风格,需要能说明需求中的哪些特征与该风格的布局密度、组件几何、主要配色关系、排版、材质、交互方式或标志性细节相呼应。清晰层级、熟悉控件、现代、专业、简洁、易用和响应式属于所有合格界面的基础质量,只用于检查可用性,不能单独作为区分预置风格的证据。一个颜色、一个形容词,或登录、保存、增删改查、统计等单个普通功能也不能单独决定风格。
@@ -125,8 +125,11 @@ frontend-design 自定义方向没有可复制的源文件,只把基础设计
125
125
 
126
126
  索引只概括视觉特征,不限定业务场景。具体规格与例外以对应风格文件为准。
127
127
 
128
- - `phosphor-hud` **赛博光幕**
129
- 视觉:近黑背景与深灰表面,霓虹绿通过透明度变化建立层级 / 等宽正文、超粗标题、全大写标签与方括号语法 / 主体组件零圆角,细线边框、L 型转角与发光效果 / CRT 扫描线、胶片噪点、终端式标记 / 机械、冷峻、工业化
128
+ - `sap-fiori-horizon` **晨光远航**
129
+ 视觉:冷白画布、浅灰分组面与深蓝文字,企业蓝仅标记主操作、链接、选中态和焦点 / Inter 与中文无衬线兜底,14px 正文、等宽数字 / 6px 控件、8px 卡片、1px 边框,普通卡片无阴影 / 紧凑表格、表单、工具栏与明确状态反馈 / 窄屏重排并保留操作能力
130
+
131
+ - `finance-report` **财报纸本**
132
+ 视觉:米白画布、白色内容面与近黑文字,青蓝仅标记图表主序列、进度和关键结论 / 衬线标题与关键数字、无衬线正文、等宽标签和右对齐数字列 / 内部数据块无阴影,仅外层纸面使用单层柔影 / 细行线、粗表头线、墨线合计行与单个淡蓝结论框
130
133
 
131
134
  - `industry` **工业图纸**
132
135
  视觉:冷灰白图纸底与单一钢蓝构成技术色调,深钢蓝仅作分节强调 / Barlow Condensed 压缩标题搭配 Barlow 正文和等宽标记 / 直角发丝线框,卡片与图框可带四角套准十字 / 内容照片双色化、工程编号和制图标记增强识别 / 冷静、工程化、精确
@@ -147,10 +150,10 @@ frontend-design 自定义方向没有可复制的源文件,只把基础设计
147
150
  视觉:暖米白底、纯白卡片与暖黑文字,陶土橙集中于主按钮和主图表,次级图表采用中性色 / 系统无衬线字体,常规正文与中等字重小标题,大数字收紧字距,小标签全大写宽字距 / 10px 圆角卡片、6px 圆角控件,1px 暖灰边框,无投影 / 疏朗的指标面板与细线表格,以灰度、大小写和字距建立层级 / 温润、干净、克制
148
151
 
149
152
  - `minimal-jade` **简约翡翠**
150
- 视觉:浅灰蓝底、纯白卡片、草绿主强调,次级图表系列用灰阶,深绿和红色用于限定的趋势与状态表达 / 无衬线粗体大标题,JetBrains Mono 等宽数字与表格数字对齐 / 12px 圆角白卡、浅阴影,边框悬停时由透明转浅灰 / 卡片轻微上浮,首要图表系列草绿、其余按黑色透明度递减,局部草绿装饰条 / 简洁、清晰、理性
153
+ 视觉:浅灰蓝底、独立白卡与草绿强调,首要图表序列用草绿、次级序列按黑色透明度递减 / 无衬线超大粗标题,JetBrains Mono 对齐指标和表格数字 / 12px 圆角、浅阴影与悬停上浮,边框由透明转浅灰 / 草绿装饰条、图标和进度形成连续识别线索
151
154
 
152
155
  - `metabase` **湖光蓝调**
153
- 视觉:纯白与极浅蓝平面,深蓝墨字,明亮蓝色用于主按钮和交互焦点 / Lato 人文无衬线字体,粗体标题与常规正文形成清晰层级 / 小到中圆角,1px 半透明中性边框,平铺卡片轻投影,浮层采用更深漫射阴影 / 浅蓝静区、实底蓝主按钮与描边次按钮 / 通透、清爽、平和
156
+ 视觉:纯白主面与大块极浅蓝静区,深蓝文字配明亮蓝主按钮和交互焦点 / Lato 人文无衬线字体,粗体标题、常规正文和弱化元信息 / 4–12px 圆角、1px 半透明边框,平铺卡片使用轻投影,浮层使用更深漫射阴影 / 实底蓝主按钮、描边次按钮和浅蓝筛选区形成层级
154
157
 
155
158
  - `pm-spec` **规格蓝本**
156
159
  视觉:冷灰蓝底、白色纸面与深墨文字,靛紫用于小面积结构性强调 / Charter 衬线标题与引用,无衬线正文,等宽体承载全大写微标签 / 10px 圆角卡片、1px 细边框,无投影,引用块配强调色左边线 / 单栏纸面文档流、紧凑正文、元信息条与局部分栏信息块 / 严肃、克制、秩序感
@@ -0,0 +1,169 @@
1
+ ---
2
+ version: alpha
3
+ name: finance-report
4
+ name_zh: 财报纸本
5
+ description: >-
6
+ 米白画布、白色内容面与近黑文字,青蓝仅标记图表主序列、进度和关键结论。
7
+ 衬线标题和关键数字、等宽标签和右对齐数字列、无阴影数据块、粗表头线和墨线合计行构成报告层级。
8
+ colors:
9
+ bg: "#F7F6F2"
10
+ paper: "#FFFFFF"
11
+ ink: "#11141A"
12
+ muted: "#5F6573"
13
+ line: "#E6E3DD"
14
+ lineStrong: "#C8C2B6"
15
+ accent: "#1F6E8C"
16
+ accentSecondary: "#2C98C5"
17
+ accentSoft: "#E7F0F4"
18
+ positive: "#1F8C5C"
19
+ negative: "#B13B3B"
20
+ warning: "#8A6912"
21
+ typography:
22
+ display:
23
+ fontFamily: "'Iowan Old Style', 'Charter', Georgia, 'Songti SC', 'Noto Serif SC', serif"
24
+ fontSize: 32px
25
+ fontWeight: 700
26
+ lineHeight: 1.15
27
+ heading:
28
+ fontFamily: "'Iowan Old Style', 'Charter', Georgia, 'Songti SC', 'Noto Serif SC', serif"
29
+ fontSize: 19px
30
+ fontWeight: 700
31
+ metric:
32
+ fontFamily: "'Iowan Old Style', 'Charter', Georgia, 'Songti SC', 'Noto Serif SC', serif"
33
+ fontSize: 28px
34
+ fontWeight: 700
35
+ lineHeight: 1
36
+ body:
37
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, 'PingFang SC', 'Microsoft YaHei', sans-serif"
38
+ fontSize: 14px
39
+ lineHeight: 1.55
40
+ label:
41
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace"
42
+ fontSize: 11px
43
+ letterSpacing: 0.06em
44
+ number:
45
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace"
46
+ fontSize: 13px
47
+ fontVariantNumeric: tabular-nums
48
+ rounded:
49
+ paper: 12px
50
+ card: 8px
51
+ callout: 6px
52
+ tag: 999px
53
+ spacing:
54
+ compact-gap: 8px
55
+ content-gap: 14px
56
+ section-gap: 32px
57
+ card-padding: 18px
58
+ page-padding: "clamp(20px, 5vw, 56px)"
59
+ components:
60
+ paper:
61
+ background: "{colors.paper}"
62
+ border: "1px solid {colors.line}"
63
+ borderRadius: "{rounded.paper}"
64
+ boxShadow: "0 16px 40px rgba(28, 27, 26, 0.06)"
65
+ reportHeader:
66
+ borderBottom: "2px solid {colors.ink}"
67
+ description: 衬线标题配等宽期间或版本信息
68
+ metric:
69
+ background: "{colors.paper}"
70
+ border: "1px solid {colors.line}"
71
+ borderRadius: "{rounded.card}"
72
+ description: 等宽标签、衬线数值和等宽变化量
73
+ ledgerTable:
74
+ rowBorder: "1px solid {colors.line}"
75
+ description: 等宽数字右对齐;表头使用强分隔线,合计行使用 2px 墨线上边界
76
+ callout:
77
+ background: "{colors.accentSoft}"
78
+ borderLeft: "3px solid {colors.accent}"
79
+ borderRadius: "{rounded.callout}"
80
+ description: 每个视图最多一个,用于关键结论
81
+ status:
82
+ borderRadius: "{rounded.tag}"
83
+ description: 颜色必须配文字、符号或方向标记
84
+ anchors:
85
+ - id: paper-and-ink
86
+ type: token
87
+ desc: 米白画布、白色内容面、近黑文字、细线和单层纸面柔影
88
+ - id: serif-metric-hierarchy
89
+ type: token
90
+ desc: 衬线体用于标题和关键数字,无衬线体用于正文,等宽体用于标签和数字列
91
+ - id: ledger-table
92
+ type: component
93
+ desc: 细行线、强表头线、右对齐数字和墨线合计行
94
+ - id: restrained-accent
95
+ type: pattern
96
+ desc: 青蓝只用于图表主序列、进度和关键结论强调
97
+ - id: flat-report-sections
98
+ type: pattern
99
+ desc: 内容块不使用阴影,以边框、留白和粗细线建立层级
100
+ ---
101
+
102
+ ## Overview
103
+
104
+ 报告型界面。米白画布承托白色内容面,近黑文字与细线组织高密度数据,青蓝只用于少量重点。标题和关键数字使用衬线体,正文使用无衬线体,标签和数字列使用等宽体。
105
+
106
+ ## Colors
107
+
108
+ | 角色 | Token | 用法 |
109
+ |------|-------|------|
110
+ | 画布 | `{colors.bg}` | 内容面外部背景 |
111
+ | 内容面 | `{colors.paper}` | 正文、表格和数据块背景 |
112
+ | 主文字 | `{colors.ink}` | 标题、正文、关键数字和粗分隔线 |
113
+ | 次文字 | `{colors.muted}` | 标签、说明和元信息 |
114
+ | 细线 | `{colors.line}` | 普通边框和行分隔 |
115
+ | 强线 | `{colors.lineStrong}` | 表头和主要分组边界 |
116
+ | 青蓝 | `{colors.accent}` | 图表主序列、进度和关键结论 |
117
+ | 淡蓝 | `{colors.accentSoft}` | 结论框和进度底槽 |
118
+ | 语义色 | `{colors.positive}` / `{colors.negative}` / `{colors.warning}` | 涨跌、风险和状态 |
119
+
120
+ 除语义状态外,图表优先使用青蓝同色阶;不增加无语义的高饱和色。
121
+
122
+ ## Typography
123
+
124
+ ```css
125
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
126
+ ```
127
+
128
+ - 标题和关键数字使用 display 衬线栈;正文和操作使用系统无衬线栈。
129
+ - 标签、表头、期间和数字列使用等宽栈;数字启用等宽数字并右对齐。
130
+ - 英文短标签可使用大写和 0.06em 字距;中文标签不转大写。
131
+ - 保持 display、body、label 三种角色,不要求固定标题级数或模块数量。
132
+
133
+ ## Layout
134
+
135
+ - 内容面宽度、分栏和区块顺序由内容决定,不固定页面宽高或纸张比例。
136
+ - 使用 `{spacing.page-padding}` 作为响应式内边距;窄屏减少列数,不缩小正文维持多列。
137
+ - 指标、图表、表格和结论按信息依赖组合,不固定数量或位置。
138
+ - 宽表格可在自身容器内横向滚动,页面本身不得横向滚动。
139
+ - 不固定报头、侧栏、Hero、双栏比例或结尾模块。
140
+
141
+ ## Elevation & Depth
142
+
143
+ - 最外层纸面可使用 `{components.paper}` 的单层柔影。
144
+ - 内部数据块、指标和表格不使用阴影,以 1px 细线和留白分层。
145
+ - 报告标题分隔和表格合计行可使用 2px `{colors.ink}` 墨线。
146
+
147
+ ## Shapes
148
+
149
+ - 纸面使用 12px 圆角,普通内容块使用 8px,结论框使用 6px。
150
+ - 状态标签可使用全圆角;表格、图表和普通数据不使用胶囊容器。
151
+
152
+ ## Components
153
+
154
+ - **报头** `{components.reportHeader}`:需要标题和期间信息时使用,不固定位置。
155
+ - **指标** `{components.metric}`:等宽标签、衬线数值、等宽变化量;数量与列数由数据决定。
156
+ - **台账表** `{components.ledgerTable}`:数字右对齐,普通行用细线,合计行用 2px 墨线上边界。
157
+ - **结论框** `{components.callout}`:淡蓝底和青蓝左线,每个视图最多一个。
158
+ - **状态** `{components.status}`:涨跌、风险和状态同时使用颜色与文字、符号或方向。
159
+ - **图表**:主序列使用青蓝,对比序列使用近黑透明色;多分类使用青蓝同色阶和必要的语义色。
160
+
161
+ ## Hard Rules
162
+
163
+ 1. 保持米白画布、白色内容面、近黑文字和克制青蓝的颜色角色。
164
+ 2. 衬线体只用于标题和关键数字,无衬线体用于正文,等宽体用于标签和数字列。
165
+ 3. 青蓝只用于图表主序列、进度和关键结论,不用于正文或大面积背景。
166
+ 4. 内部数据块、指标和表格禁止阴影;只有最外层纸面可使用一层柔影。
167
+ 5. 数字列使用等宽数字并右对齐;涨跌和状态不得只靠颜色表达。
168
+ 6. 禁止固定页面宽高、指标数量、分栏比例、区块顺序、报头位置或结尾模块。
169
+ 7. 禁止为装饰增加无语义色、重复结论框或额外卡片层级。
@@ -2,7 +2,7 @@
2
2
  version: alpha
3
3
  name: metabase
4
4
  name_zh: 湖光蓝调
5
- description: "简洁数据驱动的开源分析仪表盘:纯白底 + 深蓝墨字 + 醒目主色蓝强调,人文无衬线全局承载(标题 700 字重),标准居中容器 + 清晰分节线;柔和漫射阴影 + 纤细半透明中性边框定义卡片,开放通透、专业可靠,让数据与可视化成为焦点。"
5
+ description: "纯白主面与大块极浅蓝静区,深蓝文字配明亮蓝主按钮和焦点;Lato 人文无衬线字体,4–12px 圆角、半透明边框、轻投影平铺卡片和较深漫射浮层构成层级。"
6
6
 
7
7
  colors:
8
8
  bg: "#FFFFFF"
@@ -2,7 +2,7 @@
2
2
  version: alpha
3
3
  name: minimal-jade
4
4
  name_zh: 简约翡翠
5
- description: 简约商务数据看板风——浅灰蓝底上排布纯白卡片(圆角 rounded-xl+浅阴影 shadow-sm),单一草绿主色贯穿图标/图表/装饰条,不叠加额外强调色;KPI 数值与趋势数字统一等宽字体(JetBrains Mono)+tabular-nums 对齐;图表排名数据用黑色透明度递减渐变区分名次,仅首位保留主色;页面主标题超大字号(text-5xl/6xl)建立层级,卡片 hover 时上浮+边框转浅灰。专业、可信赖、数据驱动。
5
+ description: 浅灰蓝底、独立白卡与草绿强调;首要图表序列用草绿,次级序列按黑色透明度递减;无衬线超大粗标题,JetBrains Mono 对齐指标和表格数字;12px 圆角卡片带浅阴影和悬停上浮。
6
6
  colors:
7
7
  bg: "#F5F7FA"
8
8
  surface: "#FFFFFF"
@@ -0,0 +1,152 @@
1
+ ---
2
+ version: alpha
3
+ name: sap-fiori-horizon
4
+ name_zh: 晨光远航
5
+ description: >-
6
+ 冷白画布、浅灰分组面与深蓝文字,企业蓝仅标记主操作、链接、选中态和焦点。
7
+ 使用 6–8px 圆角、1px 边框、无阴影普通卡片、紧凑表格和表单,并在窄屏重排内容。
8
+ colors:
9
+ bg: "#FFFFFF"
10
+ surface: "#F5F6F7"
11
+ surfaceRaised: "#FFFFFF"
12
+ ink: "#1D2D3E"
13
+ muted: "#556B82"
14
+ line: "#D9D9D9"
15
+ accent: "#0A6ED1"
16
+ accentSoft: "rgba(10, 110, 209, 0.10)"
17
+ focus: "#0A6ED1"
18
+ typography:
19
+ heading:
20
+ fontFamily: '"Inter", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif'
21
+ fontWeight: 600
22
+ body:
23
+ fontFamily: '"Inter", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif'
24
+ fontSize: 14px
25
+ lineHeight: 1.5
26
+ fontWeight: 400
27
+ label:
28
+ fontFamily: '"Inter", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif'
29
+ fontSize: 12px
30
+ lineHeight: 1.35
31
+ fontWeight: 500
32
+ number:
33
+ fontFamily: '"Inter", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif'
34
+ fontVariantNumeric: tabular-nums
35
+ rounded:
36
+ control: 6px
37
+ card: 8px
38
+ pill: 999px
39
+ spacing:
40
+ compact-gap: 8px
41
+ control-gap: 12px
42
+ content-gap: 16px
43
+ section-gap: 24px
44
+ card-padding: 16px
45
+ components:
46
+ primaryButton:
47
+ background: "{colors.accent}"
48
+ color: "{colors.bg}"
49
+ border: "1px solid {colors.accent}"
50
+ borderRadius: "{rounded.control}"
51
+ description: 每个操作组只设一个蓝色主操作
52
+ secondaryButton:
53
+ background: "{colors.bg}"
54
+ color: "{colors.accent}"
55
+ border: "1px solid {colors.line}"
56
+ borderRadius: "{rounded.control}"
57
+ card:
58
+ background: "{colors.surfaceRaised}"
59
+ border: "1px solid {colors.line}"
60
+ borderRadius: "{rounded.card}"
61
+ description: 使用明度差和边框分层,不使用常驻阴影
62
+ field:
63
+ background: "{colors.bg}"
64
+ color: "{colors.ink}"
65
+ border: "1px solid {colors.line}"
66
+ borderRadius: "{rounded.control}"
67
+ focus: "2px solid {colors.focus}"
68
+ table:
69
+ headerBackground: "{colors.surface}"
70
+ rowBorder: "1px solid {colors.line}"
71
+ description: 浅灰表头、紧凑行高、稳定列对齐和等宽数字
72
+ status:
73
+ borderRadius: "{rounded.pill}"
74
+ description: 状态色必须配文字或图标
75
+ anchors:
76
+ - id: enterprise-neutral-palette
77
+ type: token
78
+ desc: 白色画布、浅灰表面、深蓝文字和单一企业蓝强调
79
+ - id: coherent-component-language
80
+ type: pattern
81
+ desc: 表单、表格、卡片和反馈使用相同的边框、圆角、间距与状态规则
82
+ - id: dense-task-layout
83
+ type: pattern
84
+ desc: 高密度信息通过对齐、分组和紧凑间距组织,不依赖装饰性容器
85
+ - id: adaptive-accessibility
86
+ type: pattern
87
+ desc: 窄屏重排内容,并保留键盘焦点、触控尺寸和非颜色状态提示
88
+ ---
89
+
90
+ ## Overview
91
+
92
+ 高密度企业界面。白色画布与浅灰表面分层,深蓝文字承载信息,企业蓝只标记操作、链接、选中态和焦点。
93
+
94
+ ## Colors
95
+
96
+ | 角色 | Token | 用法 |
97
+ |------|-------|------|
98
+ | 画布 | `{colors.bg}` | 页面与输入区域 |
99
+ | 次级表面 | `{colors.surface}` | 表头、分组、弱选中态 |
100
+ | 独立表面 | `{colors.surfaceRaised}` | 卡片与浮层 |
101
+ | 主文字 | `{colors.ink}` | 标题、正文、数字、图标 |
102
+ | 次文字 | `{colors.muted}` | 说明和元信息 |
103
+ | 分隔线 | `{colors.line}` | 控件、表格和分组边界 |
104
+ | 企业蓝 | `{colors.accent}` | 主操作、链接、选中态和焦点 |
105
+ | 弱强调 | `{colors.accentSoft}` | 当前行、轻提示和弱选中背景 |
106
+
107
+ 企业蓝不用于普通正文、卡片底色或大面积背景。信息层级优先使用字重、间距、表面和边框。
108
+
109
+ ## Typography
110
+
111
+ ```css
112
+ @import url('https://miaoda.feishu.cn/fonts/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;700&display=swap');
113
+ ```
114
+
115
+ - 标题使用 600 字重;正文默认 14px / 1.5;标签使用 12px / 1.35。
116
+ - 数字启用 `font-variant-numeric: tabular-nums`。
117
+ - 中文多行标题行高不低于 1.1,不使用负字距。
118
+
119
+ ## Layout
120
+
121
+ - 以信息依赖和操作频率决定分组、顺序与操作位置。
122
+ - 桌面端保持紧凑行高、稳定对齐和清晰分组;窄屏重排内容、折叠次要列并收纳导航。
123
+ - 列数、分栏比例和导航形式由内容与视口决定。
124
+ - 不固定侧栏、Hero、KPI 数量、首页结构或区块顺序。
125
+
126
+ ## Elevation & Depth
127
+
128
+ - 页面、次级表面和独立表面通过明度差与 1px 边框分层。
129
+ - 普通卡片不使用阴影;菜单、弹层等覆盖型表面可使用一层低透明度柔影。
130
+
131
+ ## Shapes
132
+
133
+ - 控件使用 6px 圆角,卡片使用 8px 圆角,状态标签可使用全圆角。
134
+ - 同级组件保持相同圆角和边框;普通按钮与输入框不使用胶囊形。
135
+
136
+ ## Components
137
+
138
+ - **主按钮** `{components.primaryButton}`:蓝底白字,每个操作组只设一个。
139
+ - **次按钮** `{components.secondaryButton}`:白底细边框,不与主操作竞争。
140
+ - **字段** `{components.field}`:标签常驻,错误信息紧邻字段,键盘焦点使用 2px 蓝色轮廓。
141
+ - **卡片** `{components.card}`:仅包裹独立信息组,不把每行内容卡片化。
142
+ - **表格** `{components.table}`:浅灰表头、细行分隔、稳定列对齐;数字使用等宽数字。
143
+ - **状态** `{components.status}`:同时使用颜色和文字或图标。
144
+
145
+ ## Hard Rules
146
+
147
+ 1. 保持白色画布、浅灰表面、深蓝文字和单一企业蓝强调的颜色角色。
148
+ 2. 企业蓝只用于操作、链接、选中态和焦点。
149
+ 3. 表单、表格和交互状态必须提供清晰键盘焦点及非颜色提示。
150
+ 4. 同级组件使用一致的圆角、边框、间距和反馈状态。
151
+ 5. 禁止固定侧栏、Hero、KPI 数量、分栏比例或区块顺序。
152
+ 6. 字体使用 Inter 与中文兜底栈,数字使用等宽数字特性。
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: user-identity
3
- description: "当前登录用户「我是谁」+ 妙搭 ↔ 飞书 ID 转换。Use when getting current user info/profile, displaying user name/avatar/email, converting miaoda userId ↔ lark_user_id (both directions via AuthNPaasService ID-conversion methods), or reading req.userContext fields (userId/roles/tenantId): useCurrentUserProfile, FeishuID conversion. ⚠️ 按 userId 查他人姓名/头像请用 contacts-service 第六节。触发词:用户身份, 用户信息, 用户资料, 当前用户, userProfile, useCurrentUserProfile, 飞书ID, FeishuID, 飞书用户ID, lark_user_id, 用户ID转换, AuthNPaasService ID 转换, getCurrentUserLarkUserId, getBatchLarkUserIds, getBatchMiaodaUserIds, 飞书ID转妙搭, employee_id 转 userId, 用户上下文, userContext, userContext.roles, 用户角色, 当前用户角色, 获取请求者角色, 展示当前用户, 我是谁"
3
+ description: "当前登录用户「我是谁」+ 妙搭 ↔ 飞书 ID 转换。Use when getting current user info/profile, displaying user name/avatar/email, converting miaoda userId ↔ lark_user_id / LarkID / open_id / union_id (both directions via AuthNPaasService ID-conversion methods), or reading req.userContext fields (userId/roles/tenantId): useCurrentUserProfile, FeishuID conversion. ⚠️ 按 userId 查他人姓名/头像请用 contacts-service 第六节。触发词:用户身份, 用户信息, 用户资料, 当前用户, userProfile, useCurrentUserProfile, 飞书ID, FeishuID, 飞书用户ID, lark_user_id, 用户ID转换, AuthNPaasService ID 转换, getCurrentUserLarkUserId, getBatchLarkUserIds, getBatchMiaodaUserIds, 飞书ID转妙搭, employee_id 转 userId, LarkID, lark_id, larkID, LarkID转妙搭用户ID, lark_id 转 userId, getBatchLarkIds, getBatchMiaodaUserIdsByLarkIds, open_id 转妙搭, union_id 转妙搭, 妙搭ID转open_id, getBatchOpenIds, getBatchUnionIds, getBatchMiaodaUserIdsByOpenIds, getBatchMiaodaUserIdsByUnionIds, 用户上下文, userContext, userContext.roles, 用户角色, 当前用户角色, 获取请求者角色, 展示当前用户, 我是谁"
4
4
  steering: true
5
5
  steering-topic: user_identity
6
6
  match-template-name: nestjs-react-fullstack
@@ -18,7 +18,7 @@ match-template-name: nestjs-react-fullstack
18
18
 
19
19
  ## 零、ID 体系警告(CRITICAL)
20
20
 
21
- ⚠️ "user_id" 这个字面在本项目里指**三个不同的东西**,必须先区分清楚再写代码:
21
+ ⚠️ "user_id" 这个字面在本项目里指**多个不同的东西**,必须先区分清楚再写代码:
22
22
 
23
23
  **作为身份 ID 字段名(指代具体某个用户的 ID 值):**
24
24
 
@@ -26,6 +26,7 @@ match-template-name: nestjs-react-fullstack
26
26
  |---|---|---|
27
27
  | `useCurrentUserProfile().user_id`、`req.userContext.userId` | 妙搭用户 ID(纯数字字符串) | 妙搭 |
28
28
  | `useCurrentUserProfile().lark_user_id`、`AuthNPaasService.getCurrentUserLarkUserId()` 返回值 | 飞书 user_id(== `employee_id`,企业内身份,**无固定前缀**) | 飞书 |
29
+ | 搜人返回的 `lark_id`、SDK 类型的 `larkID`、用户说的"LarkID" | **LarkID**:飞书全局用户 ID(纯数字,如 `7311528002225963027`),≠ employee_id,飞书 OpenAPI 不认。⚠️ `lark_user_id` / `getBatchLarkUserIds` 名字带 LarkUserId,值却是 employee_id,**不是** LarkID | 飞书 |
29
30
 
30
31
  **作为 API 参数的取值(不是一个 ID,而是告诉接口"我传入哪种类型的 ID"):**
31
32
 
@@ -78,17 +79,20 @@ match-template-name: nestjs-react-fullstack
78
79
  │ └─ 是 ──→ AuthNPaasService.getBatchLarkUserIds()(第三节)
79
80
  │
80
81
  ├─ 需要 飞书 open_id(`ou_` 开头)/ union_id(`on_` 开头)?
81
- │ └─ ⚠️ **AuthNPaasService 不产出 open_id/union_id**,只能 user_id
82
- │ └─ 跳到 `feishu` skill 的 `references/id-convert.md`(spark id_convert type 10/11)
82
+ │ └─ 后端 ──→ `getBatchOpenIds()` / `getBatchUnionIds()`(第三节,convertType 10/11),open_id 属于哪个飞书应用就传 `{ feishuClientId: '<该应用 App ID,cli_ 开头>' }`
83
+ │ (复用 `FeishuService` 源码里的 `FEISHU_APP_ID` **常量**,不是环境变量,别用 `process.env` / `ConfigService` 读;不传 = 妙搭应用视角,拿去调你自己应用的 OpenAPI 会不认)
83
84
  │
84
85
  ├─ 需要把 飞书 open_id / union_id 反查成 妙搭 userId?
85
- │ └─ 跳到 `feishu` skill 的 `references/id-convert.md`(spark id_convert type 20/21)
86
+ │ └─ 后端 ──→ `getBatchMiaodaUserIdsByOpenIds()` / `getBatchMiaodaUserIdsByUnionIds()`(convertType 20/21),`feishuClientId` 同上;模板外才走 `feishu` skill 的 spark id_convert
86
87
  │
87
88
  ├─ 需要把 飞书 user_id(employee_id)反查成 妙搭 userId?
88
89
  │ └─ 后端 ──→ `AuthNPaasService.getBatchMiaodaUserIds()`(第三节,SDK 一步,convertType 31);非模板项目 ──→ `feishu` skill 两步兜底
89
90
  │
91
+ ├─ **LarkID**(`lark_id` / `larkID`,纯数字全局 ID)↔ 妙搭 userId?(不要用上面 employee_id 的方法)
92
+ │ └─ 后端 ──→ LarkID → 妙搭 userId 用 `getBatchMiaodaUserIdsByLarkIds()`,反向用 `getBatchLarkIds()`(第三节,convertType 41 / 40)
93
+ │
90
94
  └─ 需要自定义飞书 ID 转换接口?
91
- └─ 是 ──→ 注入 AuthNPaasService 编写 Controller(第四节,仅适用于 user_id)
95
+ └─ 是 ──→ 注入 AuthNPaasService 编写 Controller(第四节,适用于所有转换方向)
92
96
  ```
93
97
 
94
98
  > **相关技能**:接口认证/守卫/401 参见 `authn-guide`;登录/登出/获取用户信息等 Dataloom SDK 操作参见 `client-builtins-user-service`;**搜人 / 人员·部门·群组选择器返回的 ID 处理与字段获取**(employee_id / open_department_id、禁用字段、id_convert)参见 `contacts-service`;**"用户能做什么"**(角色/权限点位鉴权)参见 `authz-guide`。本 skill 只解决**"用户是谁"**(当前登录用户),其 `lark_user_id` == `employee_id`。
@@ -133,9 +137,9 @@ Controller 将校验后的 `roles` 显式传给 Service。`AuthorizationSDK.role
133
137
 
134
138
  妙搭平台的用户 ID(`userId`)与飞书用户 ID 是两套独立体系。调用飞书 OpenAPI 时需要传入某种飞书侧 ID(`open_id` / `union_id` / `user_id` 任选其一,具体通过哪个参数指定取决于 API:消息 API 用 `receive_id_type`,多数其他 API 用 `user_id_type`,文档协作者用 `member_id_type`)。
135
139
 
136
- `AuthNPaasService` 暴露的飞书 ID 是 **`user_id`**(即 `employee_id`,飞书企业内的用户标识)这一种,支持 **妙搭 userId ↔ 飞书 user_id 双向**转换(正向 `getBatchLarkUserIds`/`getCurrentUserLarkUserId`,反向 `getBatchMiaodaUserIds`)。
140
+ `AuthNPaasService` 支持飞书 ID 与妙搭 userId 双向互转:**飞书 user_id**(即 `employee_id`)正向 `getBatchLarkUserIds` / `getCurrentUserLarkUserId`、反向 `getBatchMiaodaUserIds`;**LarkID**(搜人返回里的 `lark_id`)正向 `getBatchLarkIds`、反向 `getBatchMiaodaUserIdsByLarkIds`;**open_id / union_id** 正向 `getBatchOpenIds` / `getBatchUnionIds`、反向 `getBatchMiaodaUserIdsByOpenIds` / `getBatchMiaodaUserIdsByUnionIds`。
137
141
 
138
- > 如果需要 `open_id` / `union_id`(无论正反向),请改用飞书开放平台 `spark id_convert` 接口,参见 `feishu` skill 的 `references/id-convert.md`。`employee_id` ↔ 妙搭 userId 双向都在本 SDK 内(见下方方法表)。
142
+ > 模板内所有方向都走本 SDK(见下方方法表),**不要**再手写 spark `id_convert`(它要开放平台应用凭证 + 额外权限);只有不在 nestjs-react-fullstack 模板内的项目才参见 `feishu` skill 的 `references/id-convert.md`。
139
143
 
140
144
  ### 后端 API
141
145
 
@@ -168,6 +172,8 @@ export class MyService {
168
172
  | `getCurrentUserLarkUserId` | `() → Promise<string \| null>` | 从请求上下文获取当前用户的飞书 ID |
169
173
  | `getBatchLarkUserIds` | `(userIds: string[]) → Promise<(string \| null)[]>` | 批量转换,最多 100 个,与输入顺序一一对应 |
170
174
  | `getBatchMiaodaUserIds` | `(employeeIds: string[]) → Promise<(string \| null)[]>` | 反向:批量把飞书 user_id(employee_id)转为妙搭 userId,最多 100 个,顺序一一对应,失败项 `null`(底层 convertType 31) |
175
+ | `getBatchLarkIds` / `getBatchMiaodaUserIdsByLarkIds` | `(ids: string[]) → Promise<(string \| null)[]>` | 妙搭 userId → LarkID / LarkID → 妙搭 userId,最多 100 个,顺序一一对应,失败项 `null`(底层 convertType 40 / 41);**不要**把 LarkID 传给 `getBatchMiaodaUserIds`(只收 employee_id) |
176
+ | `getBatchOpenIds` / `getBatchUnionIds` / `getBatchMiaodaUserIdsByOpenIds` / `getBatchMiaodaUserIdsByUnionIds` | `(ids: string[], options?: { feishuClientId?: string }) → Promise<(string \| null)[]>` | 妙搭 userId ↔ open_id / union_id(convertType 10 / 11 / 20 / 21),最多 100 个,顺序一一对应,失败项 `null`;`feishuClientId` = open_id 所属飞书应用的 App ID(`cli_`),不传用妙搭应用 |
171
177
 
172
178
  ### 内置接口
173
179
 
@@ -241,7 +247,7 @@ export class FeishuIdController {
241
247
  }
242
248
  ```
243
249
 
244
- > 反向转换(employee_id → 妙搭 userId)同理,把 `getBatchLarkUserIds` 换成 `getBatchMiaodaUserIds` 即可,无需新增 Controller。
250
+ > 其他方向同理,把 `getBatchLarkUserIds` 换成对应方法即可:employee_id → 妙搭 userId 用 `getBatchMiaodaUserIds`,LarkID → 妙搭 userId 用 `getBatchMiaodaUserIdsByLarkIds`,妙搭 userId → LarkID 用 `getBatchLarkIds`。
245
251
 
246
252
  前端调用示例:
247
253
 
@@ -272,8 +278,8 @@ const { larkUserIds } = await request<{ larkUserIds: (string | null)[] }>({
272
278
  | 用 `if (!userInfo)` 判断加载状态 | 初始值为空对象(truthy),必须用 `if (!userInfo?.user_id)` |
273
279
  | 手动实例化 `AuthNPaasService` | 通过 NestJS 依赖注入获取:`constructor(private readonly authnService: AuthNPaasService)` |
274
280
  | 单独注册 `AuthNPaasModule.forRoot()` | 已通过 `PlatformModule.forRoot()` 自动注册,无需手动导入 |
275
- | 自行调用平台 `/v1/app/{appId}/account/user/convert` 接口 | 必须使用 `AuthNPaasService` 的方法,内置错误处理和可观测性 |
276
- | `getBatchLarkUserIds` 传入超过 100 个 ID | 分批调用,每批最多 100 个 |
281
+ | 自行调用平台 `/v1/app/{appId}/account/user/convert` 接口,或模板内手写 spark `id_convert` | 必须使用 `AuthNPaasService` 的方法,内置错误处理和可观测性。LarkID / open_id / union_id 方法 TS 报不存在时把 `@lark-apaas/fullstack-nestjs-core` 升到最新,仍没有就**报告阻塞**,不要加直接依赖绕过 |
282
+ | 批量转换方法传入超过 100 个 ID | 分批调用,每批最多 100 个 |
277
283
  | 在前端自行封装飞书 ID 转换请求 | 使用 `useCurrentUserProfile()` 获取当前用户飞书 ID;批量转换通过后端接口 |
278
284
 
279
285
  ---
@@ -88,7 +88,7 @@ interface UserSimpleDTO {
88
88
  larkUserID?: number; // 飞书内部数字 ID,禁用(飞书 API 不认)
89
89
  department?: DepartmentSimpleDTO;
90
90
  employeeID?: string; // 飞书企业内 user_id,调飞书开放平台 API 用它
91
- larkID?: string; // 飞书用户全局唯一 ID(larkUserID 别名),禁用
91
+ larkID?: string; // 飞书用户全局唯一 ID(larkUserID 别名),禁传飞书 API;转妙搭 userId 用 AuthNPaasService.getBatchMiaodaUserIdsByLarkIds
92
92
  miaodaUserID?: string; // 妙搭用户 ID(userID 别名)
93
93
  }
94
94
 
@@ -198,7 +198,7 @@ interface SearchUserEntity {
198
198
  email?: string;
199
199
  userStatus?: number;
200
200
  employeeID?: string; // 飞书企业内 user_id,调飞书开放平台 API 用它
201
- larkID?: string; // larkUserID 别名,禁用
201
+ larkID?: string; // larkUserID 别名,禁传飞书 API(转妙搭 userId 见上)
202
202
  miaodaUserID?: string; // userID 别名
203
203
  }
204
204
 
@@ -186,6 +186,7 @@ shared/
186
186
  2. 改动服务端代码 → 进行接口测试,确保新增接口测试通过
187
187
  3. 提交前 **必须** 读取相关日志确认无错误(服务端: server/server-devserver 日志;客户端: client-devserver 日志)
188
188
 
189
+
189
190
  如果用户反馈编译失败、服务无法启动:
190
191
 
191
192
  1. 跑 `tsc --noEmit` / `eslint` 等代码检查
@@ -529,6 +530,11 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
529
530
  - **全栈项目禁止 mock 数据**:只要有服务端接口就当全栈对待,严禁 mock。纯前端项目(静态展示、无后端)可以使用 mock
530
531
  - **提交前检查 mock 残留**:禁止硬编码用户 ID、项目 ID 等 mock 数据。提交前确认无 `"user_xxx"`、`"project_1"` 等占位值
531
532
 
533
+
534
+ ### 后端异常响应与前端错误提示
535
+ - 后端异常结构为 `{ "error": { "code": "CONFLICT", "message": "具体错误信息", "fieldErrors": { "字段": ["错误"] } } }`,顶层没有 `message`。
536
+ - 前端展示接口错误(catch、`toast.error`、页面错误态)读 `error.response?.data?.error?.message`,取不到再用第一条 `fieldErrors` 文案或调用方的兜底文案,不用 axios 的 `error.message`;403 按 authz-guide 统一处理,不在业务 catch 里判断。
537
+
532
538
  ## 日志与错误处理
533
539
 
534
540
  - **日志**: 必须用 `logger` from `@lark-apaas/client-toolkit/logger`,**禁止所有 console 方法**
@@ -1,214 +0,0 @@
1
- ---
2
- version: alpha
3
- name: phosphor-hud
4
- name_zh: 赛博光幕
5
- description: 纯黑底色+单一霓虹绿色相的赛博朋克/军事级 HUD 终端风格,通过 primary 10 级透明度建立全部视觉层级(不引入第二色相,含风险/预警等语义状态色);CRT 扫描线+胶片噪点叠加、等宽字体全大写+方括号语法(模拟终端命令行)、L 型转角方括号取代传统圆角(全局零圆角)、发光效果(text-shadow/box-shadow)营造深度;情绪基调工业化、机械感、矩阵终端压迫感。
6
- colors:
7
- bg: "hsl(0 0% 4%)"
8
- surface: "hsl(0 0% 7%)"
9
- header: "hsl(0 0% 0%)"
10
- text: "hsl(0 0% 100%)"
11
- textMuted: "hsla(137 100% 50% / 0.4)"
12
- primary: "hsl(137 100% 50%)"
13
- accent: "hsla(137 100% 50% / 0.1)"
14
- border: "hsla(137 100% 50% / 0.3)"
15
- inverse: "hsl(0 0% 0%)"
16
- typography:
17
- mono:
18
- fontFamily: '"Space Mono", monospace'
19
- usage: 主字体/正文/代码等宽基础字体(Tailwind font-mono)
20
- heading:
21
- fontFamily: '"Inter", "Space Mono", monospace'
22
- fontWeight: 900
23
- usage: 标题黑体字重(Tailwind font-black)
24
- rounded:
25
- none: "0px"
26
- scrollbar-thumb: "3px"
27
- spacing:
28
- container-wide: "1400px"
29
- container-standard: "1280px"
30
- container-narrow: "896px"
31
- container-text: "672px"
32
- section-gap: "96px"
33
- hero-pt: "160px"
34
- hero-pb: "80px"
35
- cta-gap: "128px"
36
- heading-gap: "80px"
37
- card-padding: "32px~48px"
38
- components:
39
- hud-card:
40
- border: "1px solid {colors.primary}/30"
41
- background: "{colors.surface}"
42
- padding: "{spacing.card-padding}"
43
- corner: "四角 10px×10px,border 2px solid {colors.primary}(L 型方括号,取代圆角)"
44
- hover: "bg-{colors.primary}/5"
45
- highlight-variant: "border-{colors.primary}(实色)+发光阴影(见 Elevation)+bg-{colors.primary}/5"
46
- button:
47
- primary: "bg-{colors.primary} text-{colors.inverse} font-black uppercase tracking-[0.2em] px-10 py-5,零圆角"
48
- secondary: "border border-{colors.primary}/50 text-{colors.primary} hover:bg-{colors.primary}/10,零圆角"
49
- full-width: "w-full py-5 tracking-[0.3em]~[0.4em]"
50
- disabled: "bg-{colors.primary}/20 text-{colors.primary}/40"
51
- navbar:
52
- position: "fixed top-0 z-[110]"
53
- idle: "py-6 bg-transparent"
54
- scrolled: "py-4 bg-{colors.header}/90 border-b border-{colors.primary}/30 transition-all duration-300"
55
- badge:
56
- base: "px-4 py-1 border border-{colors.primary}/50 bg-{colors.primary}/10 text-{colors.primary} text-[10px] font-bold tracking-[0.3em] uppercase"
57
- icon-box:
58
- base: "w-16 h-16 border border-{colors.primary}/30 flex items-center justify-center text-{colors.primary}"
59
- hover: "group-hover:bg-{colors.primary} group-hover:text-{colors.inverse}"
60
- divider:
61
- horizontal: "h-px w-full bg-{colors.primary}/20 shadow-[0_0_15px_hsla(137,100%,50%,0.2)]"
62
- left-accent: "border-l-2 border-{colors.primary}"
63
- list-dot: "w-1.5 h-1.5 bg-{colors.primary} mr-3"
64
- data-status:
65
- critical: "bg-{colors.primary} text-{colors.inverse} px-2 py-0.5 text-[10px] font-bold uppercase tracking-[0.15em],前缀方括号文字标签「[高危]」/「[异常]」,复用 button.primary 反转配色,禁止红色底"
66
- warning: "border border-{colors.primary}/50 text-{colors.primary} px-2 py-0.5 text-[10px] font-bold uppercase tracking-[0.15em],前缀方括号文字标签「[预警]」,禁止黄/橙色底"
67
- normal: "border border-{colors.primary}/20 text-{colors.textMuted} px-2 py-0.5 text-[10px] uppercase tracking-[0.15em],前缀方括号文字标签「[正常]」"
68
- anchors:
69
- - id: pure-black-neon-primary
70
- type: token
71
- desc: 页面主背景为近纯黑(colors.bg)搭配霓虹绿(colors.primary)作为唯一强调色相,靠透明度分层
72
- - id: crt-scanline-overlay
73
- type: pattern
74
- desc: 全屏固定扫描线+胶片噪点叠加层模拟 CRT 显示器质感
75
- - id: hud-corner-bracket
76
- type: component
77
- desc: 卡片四角 L 型方括号装饰(见 components.hud-card)取代传统圆角边框
78
- - id: zero-radius-global
79
- type: token
80
- desc: 全局卡片/按钮圆角归零(见 rounded.none),唯一例外是滚动条滑块
81
- - id: uppercase-mono-typography
82
- type: pattern
83
- desc: 标题/标签/按钮统一大写等宽字体+宽字距排版(见 typography),正文段落保持常规大小写
84
- - id: bracket-nav-syntax
85
- type: component
86
- desc: 导航链接与区段小标签使用方括号语法包裹,模拟终端命令行界面
87
- - id: cta-color-inversion
88
- type: pattern
89
- desc: 页面末尾 CTA 区段整体色彩反转为主色实底+反转文字色,形成全页唯一强对比锚点
90
- - id: grayscale-imagery
91
- type: token
92
- desc: 全部图片统一去色处理(灰度+提升对比度),呼应终端灰阶氛围
93
- gaps:
94
- - 无 deck 画布/幻灯片专属排版规格(源为单页营销落地页,非幻灯片场景)
95
- - 无暗色/亮色双模式定义(本身即暗色单模式风格)
96
- - 无图表/ECharts 组件规格(源未提及数据可视化组件);图表序列色若需多序列,一律用 primary 不同不透明度分级,不引入第二色相
97
- - 无表单控件(input/select 等)规范
98
- exceptions:
99
- - 滚动条滑块使用 rounded.scrollbar-thumb(3px),是全局零圆角的唯一例外
100
- - 高亮卡片(highlight variant)边框改为 primary 实色+发光阴影,而非默认 primary/30
101
- - CTA 反转区段允许 primary 作大面积实色底,是全局黑底外唯一的大面积主色应用场景
102
- - 按钮/CTA 上的反转文字色使用 colors.inverse(纯黑),是 primary 填充区域上文字色的唯一例外
103
- - components.data-status 的 critical 等级复用 button.primary 反转配色(非新增色彩,与 CTA 反转同源),不算引入第二色相
104
- ---
105
-
106
- ## Overview
107
-
108
- 赛博朋克 × 军事级 HUD(抬头显示器)终端风格。纯黑背景模拟 CRT 显示器环境,霓虹绿(primary)作为唯一色相,通过 10 级透明度建立严格视觉层级,不引入第二色相。视觉信号:CRT 扫描线+胶片噪点叠加、等宽字体全大写+方括号语法(模拟终端命令行)、L 型转角方括号 HUD 边框取代传统圆角、图片统一 grayscale 去色。情绪基调:工业化、机械感、矩阵终端压迫感。
109
-
110
- ## Colors
111
-
112
- | 角色 | 值 | 用法 |
113
- |-----|-----|-----|
114
- | bg | {colors.bg} | 页面主背景,近纯黑 |
115
- | surface | {colors.surface} | 卡片/面板底色 |
116
- | header | {colors.header} | 导航栏滚动后背景 |
117
- | text | {colors.text} | 标题、姓名等高层级白色文字;**不含 KPI/统计数字**(后者固定用 primary,见 Hard Rules) |
118
- | textMuted | {colors.textMuted} | 低透明度绿,标签、辅助说明、脚注、data-status normal 态文字 |
119
- | primary | {colors.primary} | 霓虹绿:主交互、主按钮、激活边框、品牌标识、KPI 数字、风险/预警等级标签,视觉权重最高 |
120
- | accent | {colors.accent} | 极弱绿色着色:hover 底色、区段微着色,权重低于 primary |
121
- | border | {colors.border} | 卡片边框(HUD 边框线) |
122
- | inverse | {colors.inverse} | primary 填充区域上的反转文字色(按钮/CTA 反转区段/data-status critical 态) |
123
-
124
- 透明度层级:primary 通过 10 级透明度(5%~100%)建立完整视觉层次;正文描述用 primary/80;边框默认 primary/30(卡片描边)、primary/50(标签/Badge 边框)。发光效果:`text-shadow: 0 0 8px hsla(137,100%,50%,0.6)` 模拟 CRT 自发光;关键元素 `box-shadow: 0 0 50px hsla(137,100%,50%,0.1)` 霓虹绿光晕。选中态:`selection:bg-{colors.primary} selection:text-{colors.inverse}`。
125
-
126
- **风险/预警/异常/VIP 等级、表格状态标签等仪表盘常见语义状态,禁止套用红=危险/黄=警告/绿=正常的通用配色惯例**,一律用 `components.data-status`(primary 不同强度 + 方括号文字标签)表达,见 Components 与 Hard Rules。
127
-
128
- ## Typography
129
-
130
- 全局样式首行原样写入(HARD REQUIREMENT,禁止替换):
131
-
132
- ```css
133
- @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap');
134
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap');
135
- ```
136
-
137
- | 用途 | 字体栈 |
138
- |-----|-------|
139
- | 主字体/正文/代码 | {typography.mono.fontFamily} |
140
- | 标题(黑体) | {typography.heading.fontFamily} |
141
-
142
- | 层级 | 样式(Tailwind) | 颜色 |
143
- |-----|-----|-----|
144
- | 品牌名 | text-xl font-black tracking-widest + scanline 发光 | primary |
145
- | 页面主标题 H1 | text-6xl~text-8xl font-black tracking-tighter uppercase leading-none + scanline | text |
146
- | 区段标题 H2 | text-5xl~text-6xl font-black tracking-tighter uppercase | text |
147
- | 卡片标题 H3 | text-xl~text-2xl font-black tracking-[0.2em] uppercase | text |
148
- | 区段小标签 | text-[10px] font-bold tracking-[0.3em]~[0.5em] uppercase | primary |
149
- | 导航链接 | text-[10px] font-bold tracking-[0.2em] uppercase,方括号包裹 | primary/70 |
150
- | 正文段落 | text-lg~text-xl font-mono tracking-tight leading-relaxed,前缀「[系统信息]:」 | primary/80 |
151
- | 统计数字 | text-3xl~text-5xl font-black,禁止用 text(白色) | primary |
152
-
153
- ## Layout
154
-
155
- - 可按内容层级选择宽幅、标准、窄幅或文字容器,容器 token 是尺度参考,不绑定 Navbar、Hero、Pricing 等业务区块。
156
- - 区段纵向间距参考 {spacing.section-gap},标题与内容间参考 {spacing.heading-gap},卡片内边距使用 {spacing.card-padding};具体模块顺序和列数由任务决定。
157
- - 主色反转面可作为一次强对比锚点出现在最重要的行动或状态区域,不要求位于页面末尾。
158
- - 窄屏减少列数、缩小间距并保证按钮可操作;HUD 转角装饰可在空间不足时简化,但不影响内容可读性。
159
-
160
- ## Elevation & Depth
161
-
162
- 无常规投影分级(纯平面终端美学),仅两类发光效果:
163
-
164
- | 效果 | 值 | 用途 |
165
- |-----|-----|-----|
166
- | 关键元素光晕 | box-shadow: 0 0 50px hsla(137,100%,50%,0.1) | 高亮卡片、CTA |
167
- | 文字发光 | text-shadow: 0 0 8px hsla(137,100%,50%,0.6) | 品牌名、H1,模拟 CRT 自发光 |
168
-
169
- 不使用模糊常规投影(偏移+blur 阴影);深度感全靠边框(border)+发光(glow)+HUD 转角装饰营造。
170
-
171
- ## Shapes
172
-
173
- - 圆角:全局 {rounded.none}(border-radius: 0),唯一例外滚动条滑块 {rounded.scrollbar-thumb}。
174
- - HUD 转角:四角 L 型方括号装饰,`position: absolute; width: 10px; height: 10px; border: 2px solid {colors.primary}`,取代传统圆角边框。
175
- - CRT 特效:扫描线叠加(fixed inset-0 z-100,4px 横线+3px RGB 竖线);噪点纹理(fixed inset-0 z-99 opacity-0.05 stardust 图案);扫描动画(2px h-full 绿色线条,animation: scan 4s linear infinite);图片去色(grayscale + contrast-125)。
176
-
177
- ## Components
178
-
179
- 组件规格见 frontmatter components(hud-card / button / navbar / badge / icon-box / divider / data-status)。补充说明:
180
-
181
- - **hud-card**:所有卡片的基座,四角 L 型方括号取代圆角(见 Shapes)。highlight 变体边框升级为 primary 实色并叠加光晕阴影。
182
- - **button**:主按钮反转配色(primary 底+inverse 字),次按钮描边;disabled 态整体降低 primary 透明度。
183
- - **navbar**:滚动前透明,滚动后切换为 header 底色+底部描边,300ms 过渡。
184
- - **badge**:方括号标签语义的载体,搭配区段小标签使用。
185
- - **icon-box**:默认描边容器,hover 反转为 primary 实底+inverse 图标色。
186
- - **divider**:水平分隔线自带霓虹光晕阴影;左侧强调用实色竖线;列表项用小方点(非圆点)标记,呼应零圆角基调。
187
- - **data-status**:仪表盘/报表场景的风险等级、表格异常状态、预警提示专用,替代传统红/黄/绿语义配色约定——critical(实底反转)、warning(描边)、normal(弱描边)三级仅靠 primary 强度 + 方括号文字标签(如「[高危]」「[预警]」「[正常]」)区分,不引入红/黄/橙。
188
-
189
- ## Do's and Don'ts
190
-
191
- - 方括号语法建议用于导航链接/区段小标签,强化终端命令行感,非强制所有文本元素都包裹方括号。
192
- - CTA 反转区段建议全页仅在末尾使用一次,避免削弱纯黑底的整体氛围。
193
- - 扫描线/噪点叠加层建议保持低透明度(噪点 opacity 0.05 量级),避免影响正文可读性。
194
- - 发光效果(box-shadow/text-shadow)建议只用于关键元素(高亮卡片、品牌名、主标题),避免全局滥用打断视觉层级。
195
-
196
- ## Hard Rules
197
-
198
- - 全局仅使用 primary 单一色相区分视觉层级,**禁止引入第二色相,包括红/黄/橙等语义状态色**;层级差异只靠 primary 透明度与字号区分。
199
- - 风险/预警/异常/VIP 等级、表格状态标签等仪表盘常见语义状态,一律用 `components.data-status`(primary 不同强度 + 方括号文字标签)表达,**禁止套用红=危险/黄=警告/绿=正常的通用配色惯例**,即使内容语境(如"高危""异常""缺口")在常见仪表盘中习惯用红黄标注。
200
- - KPI/统计数字(仪表盘核心指标大数字)必须使用 primary 色,**禁止使用 text(白色)作为强调数字色**;text 仅用于页面标题、姓名等非数据类文字。
201
- - 卡片与按钮统一零圆角(border-radius: 0),唯一例外是滚动条滑块 3px 圆角。
202
- - 卡片四角必须保留 L 型 HUD 转角方括号装饰,不得省略或替换为传统圆角。
203
- - 标题、区段标签、导航链接、按钮统一 uppercase + tracking-widest/[0.2em]~[0.5em] 宽字距;正文段落保持常规大小写。
204
- - 所有图片必须应用 grayscale + contrast-125 去色处理,禁止彩色图片直出。
205
- - 字体 @import 必须原样写入全局样式首行,禁止替换或省略(HARD REQUIREMENT)。
206
- - Primary 用于所有交互与视觉焦点(按钮/边框/品牌),Accent 仅用于 hover 微光底色/区段极弱着色,不可互换用途。
207
-
208
- ## Exceptions
209
-
210
- - 滚动条滑块:{rounded.scrollbar-thumb} 圆角,是全局零圆角的唯一例外。
211
- - 高亮卡片(highlight variant):边框改为 primary 实色+发光阴影,非默认 primary/30 描边。
212
- - CTA 反转区段:允许 primary 作大面积实色底,是全局黑底外唯一的大面积主色应用场景。
213
- - 按钮/CTA 反转文字色使用 colors.inverse(纯黑),是 primary 填充区域上文字色的唯一例外。
214
- - data-status.critical 复用 button.primary 反转配色(primary 底+inverse 字),与 CTA 反转同源,不算引入第二色相。