@mingfuyun/star-allinone 0.4.2 → 0.4.4

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": "@mingfuyun/star-allinone",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "星系运维前端能力包",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/scripts/cli.js CHANGED
@@ -19,7 +19,7 @@ function usage() {
19
19
  star-allinone skills sync [--target <dir>] [--dry-run]
20
20
  star-allinone doctor [--target <dir>]
21
21
  star-allinone gen service --operation "GET /api/v1/devices/" [--spec <file>] [--domain Devices] [--mock-file] [--dry-run]
22
- star-allinone gen page --feature Widgets --route /widgets --title 组件管理 --list-operation "GET /api/v1/widgets/" [--create-operation ...] [--update-operation ...] [--delete-operation ...] [--dry-run]
22
+ star-allinone gen page --feature Widgets --route /widgets --title 组件管理 --list-operation "GET /api/v1/widgets/" [--create-operation ...] [--update-operation ...] [--delete-operation ...] [--no-tracking] [--dry-run]
23
23
 
24
24
  Run from a business project containing .star-allinone.json.
25
25
 
@@ -30,7 +30,8 @@ If <project>/AGENTS.md is missing, it copies examples/AGENTS.md once.
30
30
  doctor checks config, OpenAPI, MFRequest, MFProTable, skill sync, and bad imports.
31
31
 
32
32
  gen service writes one MFRequest method and types from OpenAPI/Swagger.
33
- gen page scaffolds a list + drawer + confirm page from OpenAPI schema and can generate services first.`);
33
+ gen page scaffolds a list + drawer + confirm page from OpenAPI schema and can generate services first.
34
+ When src/utils/tracking/index.ts exists, generated pages include getTrackData wiring unless --no-tracking is passed.`);
34
35
  process.exitCode = 1;
35
36
  }
36
37
 
@@ -65,6 +66,7 @@ function parseArgs(args) {
65
66
  if (arg === '--dry-run') options.dryRun = true;
66
67
  else if (arg === '--mock-file') options.mockFile = true;
67
68
  else if (arg === '--force') options.force = true;
69
+ else if (arg === '--no-tracking') options.noTracking = true;
68
70
  else if (arg.startsWith('--')) {
69
71
  const key = arg.slice(2).replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
70
72
  options[key] = args[++index];
@@ -49,6 +49,11 @@ function makeProject() {
49
49
  fs.mkdirSync(path.join(root, 'src/components/CommonTable'), { recursive: true });
50
50
  fs.writeFileSync(path.join(root, 'src/components/CommonTable/MFProTable.tsx'), 'export default function MFProTable() { return null; }\n');
51
51
  fs.mkdirSync(path.join(root, 'src/pages'), { recursive: true });
52
+ fs.mkdirSync(path.join(root, 'src/utils/tracking'), { recursive: true });
53
+ fs.writeFileSync(
54
+ path.join(root, 'src/utils/tracking/index.ts'),
55
+ "export const getTrackData = (...args: unknown[]) => JSON.stringify(args);\n",
56
+ );
52
57
  fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({
53
58
  dependencies: { '@mingfuyun/star-allinone': '^0.3.2' },
54
59
  scripts: { typecheck: 'tsc --noEmit' },
@@ -120,11 +125,19 @@ function main() {
120
125
  assert(columns.includes("dataIndex: 'kind'"), columns);
121
126
  assert(columns.includes("valueType: 'select'"), columns);
122
127
  assert(columns.includes("valueType: 'digit'"), columns);
128
+ assert(columns.includes("getTrackData('create', \"新增\""), columns);
129
+ assert(columns.includes("getTrackData('edit', \"编辑\""), columns);
130
+ assert(columns.includes("getTrackData('delete', \"删除\""), columns);
123
131
  const drawer = fs.readFileSync(path.join(root, 'src/pages/Widgets/components/WidgetsDrawer.tsx'), 'utf8');
124
132
  assert(drawer.includes('ProFormSelect'), drawer);
125
133
  assert(drawer.includes("name=\"status\""), drawer);
126
134
  assert(drawer.includes("name=\"name\""), drawer);
127
135
  assert(drawer.includes('required: true'), drawer);
136
+ assert(drawer.includes('cancelTrack={getTrackData('), drawer);
137
+ assert(drawer.includes('okTrack={getTrackData('), drawer);
138
+ const confirm = fs.readFileSync(path.join(root, 'src/pages/Widgets/components/WidgetsConfirmModal.tsx'), 'utf8');
139
+ assert(confirm.includes("'data-track': getTrackData('cancel', \"取消\""), confirm);
140
+ assert(confirm.includes("'data-track': getTrackData('confirm', \"确定\""), confirm);
128
141
  const route = fs.readFileSync(path.join(root, 'config/route.ts'), 'utf8');
129
142
  assert(route.includes("path: '/widgets'"), route);
130
143
 
@@ -19,6 +19,20 @@ function detectLayout(root) {
19
19
  return { hasPageContainer, hasProTableLess, hasContainerConfig };
20
20
  }
21
21
 
22
+ function hasTracking(root, config) {
23
+ const modulePath = (config.trackingModule || '@/utils/tracking').replace(/^@\//, 'src/');
24
+ return fs.existsSync(path.join(root, `${modulePath}.ts`))
25
+ || fs.existsSync(path.join(root, `${modulePath}/index.ts`));
26
+ }
27
+
28
+ function trackingImport(config) {
29
+ return config.trackingModule || '@/utils/tracking';
30
+ }
31
+
32
+ function emitTrackData(action, label, context) {
33
+ return `getTrackData('${action}', ${JSON.stringify(label)}, ${JSON.stringify(context)})`;
34
+ }
35
+
22
36
  function featureNames(options) {
23
37
  const feature = options.feature.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
24
38
  if (!feature) throw new Error('Missing --feature. Example: --feature Widgets');
@@ -43,7 +57,7 @@ function searchFieldNames(fields) {
43
57
  .map((field) => field.name);
44
58
  }
45
59
 
46
- function emitColumns(names, itemType, fields, permissions, queryNames) {
60
+ function emitColumns(names, itemType, fields, permissions, queryNames, tracking, trackingModule) {
47
61
  const columnFields = fields.length ? fields : [{ name: 'id', title: 'ID', type: 'string' }];
48
62
  const searchable = new Set(
49
63
  queryNames?.length
@@ -74,7 +88,19 @@ function emitColumns(names, itemType, fields, permissions, queryNames) {
74
88
  const permCreate = permissions.create ? ` permission: '${permissions.create}',\n` : '';
75
89
  const permEdit = permissions.edit ? ` permission: '${permissions.edit}',\n` : '';
76
90
  const permDelete = permissions.delete ? ` permission: '${permissions.delete}',\n` : '';
77
- return `import type {
91
+ const trackImport = tracking
92
+ ? `import { getTrackData } from '${trackingModule}';\n`
93
+ : '';
94
+ const trackEdit = tracking
95
+ ? ` track: ${emitTrackData('edit', '编辑', { key: 'action', name: '操作' })},\n`
96
+ : '';
97
+ const trackDelete = tracking
98
+ ? ` track: ${emitTrackData('delete', '删除', { key: 'action', name: '操作' })},\n`
99
+ : '';
100
+ const trackCreate = tracking
101
+ ? ` track: ${emitTrackData('create', '新增', { key: 'toolbar', name: '工具栏' })},\n`
102
+ : '';
103
+ return `${trackImport}import type {
78
104
  ITableProps,
79
105
  TableSearchType,
80
106
  } from '@/components/CommonTable/type';
@@ -99,12 +125,12 @@ export const getActionColumn = ({
99
125
  >['actions'] => [
100
126
  {
101
127
  key: 'edit',
102
- ${permEdit} getText: () => '编辑',
128
+ ${permEdit}${trackEdit} getText: () => '编辑',
103
129
  onClick: handleEdit,
104
130
  },
105
131
  {
106
132
  key: 'delete',
107
- ${permDelete} getText: () => '删除',
133
+ ${permDelete}${trackDelete} getText: () => '删除',
108
134
  onClick: handleDelete,
109
135
  },
110
136
  ];
@@ -116,7 +142,7 @@ export const getToolBarRender = ({
116
142
  key: 'create',
117
143
  text: '新增',
118
144
  type: 'primary',
119
- ${permCreate} onClick: handleCreate,
145
+ ${permCreate}${trackCreate} onClick: handleCreate,
120
146
  },
121
147
  ];
122
148
  `;
@@ -324,7 +350,7 @@ function emitFormItem(field) {
324
350
  />`;
325
351
  }
326
352
 
327
- function emitDrawer(names, types, fns, formFields) {
353
+ function emitDrawer(names, types, fns, formFields, tracking, trackingModule) {
328
354
  const itemType = types.itemType || 'Record<string, unknown>';
329
355
  const fields = formFields.length
330
356
  ? formFields
@@ -336,11 +362,18 @@ function emitDrawer(names, types, fns, formFields) {
336
362
  const updateCall = fns.update
337
363
  ? ` await Service.${fns.update}(record.id, values);`
338
364
  : ' // TODO: call update service';
365
+ const trackImport = tracking
366
+ ? `import { getTrackData } from '${trackingModule}';\n`
367
+ : '';
368
+ const drawerTracks = tracking
369
+ ? `\n cancelTrack={${emitTrackData('cancel', '取消', { key: 'editor', name: names.title })}}\n okTrack={${emitTrackData('confirm', '确定', { key: 'editor', name: names.title })}}`
370
+ : '';
339
371
  return `import Service from '@/services';
340
372
  import { ${components.join(', ')} } from '@ant-design/pro-components';
341
373
  import { CustomDrawer, HocModal } from '@mingfuyun/star-allinone';
342
374
  import { Form, message } from 'antd';
343
375
  import { useEffect, useState } from 'react';
376
+ ${trackImport}
344
377
 
345
378
  type ${names.drawer}Args = {
346
379
  record?: ${itemType};
@@ -397,7 +430,7 @@ ${createCall}
397
430
  loading={loading}
398
431
  open={visible}
399
432
  title={editing ? '编辑${names.title}' : '新增${names.title}'}
400
- width={480}
433
+ width={480}${drawerTracks}
401
434
  onClose={handleCancel}
402
435
  onConfirm={handleConfirm}
403
436
  >
@@ -417,10 +450,17 @@ export default HocModal(${names.drawer});
417
450
  `;
418
451
  }
419
452
 
420
- function emitConfirm(names) {
453
+ function emitConfirm(names, tracking, trackingModule) {
454
+ const trackImport = tracking
455
+ ? `import { getTrackData } from '${trackingModule}';\n`
456
+ : '';
457
+ const modalTracks = tracking
458
+ ? `\n cancelButtonProps={{\n 'data-track': ${emitTrackData('cancel', '取消', { key: 'confirm', name: '确认' })},\n }}\n okButtonProps={{\n 'data-track': ${emitTrackData('confirm', '确定', { key: 'confirm', name: '确认' })},\n }}`
459
+ : '';
421
460
  return `import { BaseModal, HocModal } from '@mingfuyun/star-allinone';
422
461
  import { Typography } from 'antd';
423
462
  import { useState } from 'react';
463
+ ${trackImport}
424
464
 
425
465
  export type ${names.confirm}Args = {
426
466
  title: string;
@@ -466,7 +506,7 @@ const ${names.confirm}: React.FC<Props> = ({
466
506
  maskClosable={false}
467
507
  title={title}
468
508
  visible={visible}
469
- width={480}
509
+ width={480}${modalTracks}
470
510
  onCancel={handleCancel}
471
511
  onOk={handleOk}
472
512
  >
@@ -613,10 +653,16 @@ function generatePage(cwd, options) {
613
653
  };
614
654
 
615
655
  const queryNames = querySearchNames(operationByKey.list?.queryParams);
656
+ const tracking = !options.noTracking && hasTracking(project.root, project.config);
657
+ const trackingModule = trackingImport(project.config);
616
658
  writeFile(files[1], emitLess(layout), project.dryRun);
617
- writeFile(files[2], emitColumns(names, types.itemType, fields, permissions, queryNames), project.dryRun);
618
- writeFile(files[3], emitDrawer(names, types, fns, formFields), project.dryRun);
619
- writeFile(files[4], emitConfirm(names), project.dryRun);
659
+ writeFile(
660
+ files[2],
661
+ emitColumns(names, types.itemType, fields, permissions, queryNames, tracking, trackingModule),
662
+ project.dryRun,
663
+ );
664
+ writeFile(files[3], emitDrawer(names, types, fns, formFields, tracking, trackingModule), project.dryRun);
665
+ writeFile(files[4], emitConfirm(names, tracking, trackingModule), project.dryRun);
620
666
  if (layout.hasContainerConfig) {
621
667
  writeFile(files[0], emitContainerIndex(), project.dryRun);
622
668
  writeFile(files[5], emitIndex(names, layout, types, fns, pagination, 'list'), project.dryRun);
@@ -631,4 +677,4 @@ function generatePage(cwd, options) {
631
677
  return names;
632
678
  }
633
679
 
634
- module.exports = { generatePage, featureNames, patchContainerConfig };
680
+ module.exports = { generatePage, featureNames, patchContainerConfig, hasTracking };
package/skills/README.md CHANGED
@@ -134,11 +134,11 @@ git commit -m "chore(skill): 更新公共 skill"
134
134
  | 入口 | 规则位置 | 覆盖内容 |
135
135
  | --- | --- | --- |
136
136
  | `shared-api-to-service` | SKILL + `references/service-conventions.md`、`api-artifact-generation.md`、`mock.md` | 指定 operation、`MFRequest`、namespace 类型、snake_case、mock |
137
- | `shared-design-to-page` | SKILL + `page-conventions.md`、`overlays.md`、`list-page-template.md` | 页面分层、标准列表 CLI、弹层合同 |
138
- | `shared-review-and-submit` | SKILL + `impact-analysis.md`、`verify.md`、`ai-review.md`、`commit.md` | 影响分析 → 验证 → 确认后提交 |
137
+ | `shared-design-to-page` | SKILL + `page-conventions.md`、`overlays.md`、`list-page-template.md`、`tracking.md` | 页面分层、标准列表 CLI、弹层合同、按钮埋点 |
138
+ | `shared-review-and-submit` | SKILL + `impact-analysis.md`、`verify.md`、`ai-review.md`、`commit.md` | 影响分析 → 验证(含埋点完整性)→ 确认后提交 |
139
139
  | `shared-publish-test` | SKILL + `scripts/publish-current-branch.sh` | 云效测发;只读 `publishPipelineId` |
140
140
  | `shared-tracking` | SKILL | 埋点接入:能力包版本、配置文件、脚本、初始化、失败上报、权限按钮、操作列、抽屉弹层、表单按钮 |
141
- | (非入口)`shared-project-conventions` | `architecture.md`、`mfprotable.md`、`component-contract.md`、`review-checklist.md`、`quality-checklist.md` | 架构、导入合同、质量清单 |
141
+ | (非入口)`shared-project-conventions` | `architecture.md`、`mfprotable.md`、`component-contract.md`、`review-checklist.md`(含埋点审查)、`quality-checklist.md` | 架构、导入合同、质量清单 |
142
142
  | (非入口)`shared-i-have-adhd` | `i-have-adhd.md` | 用户输出格式 |
143
143
 
144
144
  以下内容**不**写进公共 skill 源码:
@@ -15,6 +15,7 @@ Before implementation, read:
15
15
  2. [references/page-conventions.md](references/page-conventions.md)
16
16
  3. [references/overlays.md](references/overlays.md) for any modal, drawer, or confirmation
17
17
  4. `.agents/skills/shared-project-conventions/references/architecture.md`
18
+ 5. [references/tracking.md](references/tracking.md) when `src/utils/tracking/index.ts` exists (or the project tracking path in conventions)
18
19
 
19
20
  If `.agents/project/conventions.md` exists, use it only for extra paths.
20
21
 
@@ -51,6 +52,7 @@ Add `--permission-create`, `--permission-edit`, `--permission-delete` when codes
51
52
  3. The CLI fills columns and drawer fields from the OpenAPI schema (required, enum → `ProFormSelect`, dates/numbers). Review labels and permission codes; do not recreate the file tree. See [references/list-page-template.md](references/list-page-template.md).
52
53
  4. If `src/components/Page/Container/config.tsx` exists, `gen page` writes a Container `index.tsx`, puts the table in `components/List.tsx`, and registers a Tab with `loader: () => import(...)`. Do not invent a second page shell.
53
54
  5. Do not overwrite existing page files. Tell the user the CLI refused, then edit in place.
55
+ 6. **Tracking:** When the project has tracking configured, `gen page` auto-wires default button tracking. Agent must scan and wire **all** in-scope buttons per [references/tracking.md](references/tracking.md) and `$shared-tracking` (permission, drawer/modal footers, action column, ProForm, copy)—do not leave manual steps for the user. If tracking is not set up yet, tell the user to run `$shared-tracking` first; do not invent a second tracking helper.
54
56
 
55
57
  ## Design path
56
58
 
@@ -63,6 +65,7 @@ For non-standard layouts:
63
65
  5. API-backed pages include types, `MFRequest` methods, aggregate exports, and page consumption in the same change. Use `.agents/skills/shared-api-to-service/SKILL.md` for missing services. Use `.agents/skills/shared-api-to-service/references/mock.md` for extra mock scenarios. Do not embed production fake data.
64
66
  6. Compare desktop and narrow layouts against the design. Fix structure and spacing before decoration.
65
67
  7. Run focused verification. Do not claim visual fidelity without inspecting the rendered page.
68
+ 8. When tracking is enabled, Agent applies [references/tracking.md](references/tracking.md) for every toolbar, action, copy, drawer, confirm, form submit, and standalone permission button on the page.
66
69
 
67
70
  ## Hard rules
68
71
 
@@ -76,6 +79,7 @@ For non-standard layouts:
76
79
  - Do not use `Modal.confirm` or feature-level Ant Design `Modal` / `Drawer` shells.
77
80
  - Do not add a UI library, state library, or CSS-in-JS system without approval.
78
81
  - Do not refactor unrelated code.
82
+ - When `src/utils/tracking/index.ts` exists, Agent wires `getTrackData` on every button covered by [references/tracking.md](references/tracking.md) (including copy). Do not call `track()` in handlers. Do not ask the user to add tracks manually.
79
83
 
80
84
  ## Verification
81
85
 
@@ -86,6 +90,8 @@ pnpm typecheck
86
90
 
87
91
  Run `pnpm lint` for broad or shared changes. Run the project's documented build command when routes, entry, or multiple pages change.
88
92
 
93
+ When tracking is configured, scan changed page files: toolbar `track`, action `track`, copy `track`, drawer `cancelTrack` / `okTrack` or custom-footer `data-track`, confirm modal buttons, ProForm submitters, and standalone permission buttons. Agent fixes missing wiring before calling the page done; do not defer to the user.
94
+
89
95
  ## User-facing output
90
96
 
91
97
  Read and apply `.agents/skills/shared-i-have-adhd/i-have-adhd.md` to every response this skill sends to the user.
@@ -27,6 +27,7 @@ When `src/components/Page/Container/config.tsx` exists, `index.tsx` is a Contain
27
27
  - Export `columns`, `getActionColumn`, `getToolBarRender`.
28
28
  - Columns come from the list item schema: types, enums, and the first string fields as search.
29
29
  - Put permission strings on actions and toolbar items when the project uses them.
30
+ - When tracking is configured, add `track: getTrackData(...)` beside each toolbar and action item. See [tracking.md](tracking.md).
30
31
  - Render empty cells as `'-'`.
31
32
 
32
33
  ## Drawer
@@ -36,12 +37,14 @@ When `src/components/Page/Container/config.tsx` exists, `index.tsx` is a Contain
36
37
  - Fields come from the create/update body schema: required rules, `enum` → `ProFormSelect`, numbers → `ProFormDigit`, dates → date pickers.
37
38
  - `validateFields()` in `try`. Create vs update from `record`.
38
39
  - Reset fields when `visible` becomes true.
40
+ - When tracking is configured, set `cancelTrack` and `okTrack` on `CustomDrawer` (default footer). Do not add duplicate submit tracks on `ProForm`.
39
41
 
40
42
  ## Confirm modal
41
43
 
42
44
  - `BaseModal` + `HocModal`.
43
45
  - `confirmLoading` tied to the async `onConfirm`.
44
46
  - Do not use `Modal.confirm`.
47
+ - When tracking is configured, set `cancelButtonProps` and `okButtonProps` with `'data-track'` from `getTrackData`. See [tracking.md](tracking.md).
45
48
 
46
49
  ## Container tabs
47
50
 
@@ -41,6 +41,8 @@ Do not duplicate open/visible, selected-record, and close state in the page when
41
41
 
42
42
  Use `CustomDrawer` confirmation controls and disable the ProForm submitter. Reset or initialize fields whenever the overlay becomes visible.
43
43
 
44
+ When the project has tracking, wire `cancelTrack` / `okTrack` on the default drawer footer, or `data-track` on each button in a custom footer. For `BaseModal`, use `cancelButtonProps` / `okButtonProps`. Details: [tracking.md](tracking.md).
45
+
44
46
  ```tsx
45
47
  const handleConfirm = async () => {
46
48
  try {
@@ -62,6 +62,10 @@ Follow [overlays.md](overlays.md). Use `CustomDrawer`, `BaseModal`, and `HocModa
62
62
  - Do not treat hidden buttons as authorization. Backend enforcement must remain.
63
63
  - Add explicit routes in `config/route.ts` when the page needs navigation. Preserve `/403`, `/404`, and nested menu behavior.
64
64
 
65
+ ## Tracking
66
+
67
+ When `src/utils/tracking/index.ts` exists, every new or changed page wires button tracking in the same PR. Follow [tracking.md](tracking.md) and `.agents/skills/shared-tracking/SKILL.md` for SDK setup. Use `getTrackData`; do not call `track()` in handlers.
68
+
65
69
  ## Async behavior
66
70
 
67
71
  - Every `await` lives in `try-catch`, including handlers, loaders, and submissions.
@@ -0,0 +1,63 @@
1
+ # Page tracking
2
+
3
+ Apply when the business project already has `src/utils/tracking/index.ts` (or the path documented in project conventions). Full SDK setup and **Agent 全站批量补齐规则** live in `.agents/skills/shared-tracking/SKILL.md`. This file covers **page / 生成场景**。
4
+
5
+ **Agent 规则:** 生成或修改页面时,由 Agent 写入全部按钮埋点,**不要**留给用户手工补。与「接入埋点」同一套五类扫描标准(含复制按钮)。
6
+
7
+ Import:
8
+
9
+ ```tsx
10
+ import { getTrackData } from '@/utils/tracking';
11
+ ```
12
+
13
+ Click reporting uses `data-track` JSON from `getTrackData`. Do not call `track()` in business handlers.
14
+
15
+ ## Required on every new or changed page
16
+
17
+ | Surface | Where | Pattern |
18
+ | --- | --- | --- |
19
+ | Toolbar / batch / search extras | `const.tsx` or page `toolBarRender` | `track: getTrackData(..., { key: 'toolbar', name: '工具栏' })` |
20
+ | Permission buttons | `withAuth(Button)` / `AccessButton` | `data-track={getTrackData(...)}` |
21
+ | Row actions | `const.tsx` → `actionColumn` / `TablePermissionActions` | `track: getTrackData(..., { key: 'action', name: '操作' })` |
22
+ | Copy actions | action column / toolbar / custom footer | `getTrackData('copy', '复制', …)` or `复制IP` |
23
+ | Drawer default footer | `<Feature>Drawer.tsx` | `cancelTrack` / `okTrack` on `CustomDrawer` |
24
+ | Drawer / Modal custom footer | each `Button` | `data-track={getTrackData(...)}` |
25
+ | Confirm dialog | `BaseModal` | custom footer + `data-track` when button props unavailable |
26
+ | Inline form submit | `ProForm` / `Form` | `submitButtonProps` / `resetButtonProps` |
27
+
28
+ `MFProTable` query and reset are handled inside the table (`filter_query` / `查询`, `filter_reset` / `重置`). Do not duplicate in page code.
29
+
30
+ ## Drawer with `submitter={false}`
31
+
32
+ Submit lives on `CustomDrawer`. Do not add a second submit track on `ProForm`.
33
+
34
+ ```tsx
35
+ <CustomDrawer
36
+ cancelTrack={getTrackData('cancel', '取消', { key: 'editor', name: '<页面中文名>' })}
37
+ okTrack={getTrackData('confirm', '确定', { key: 'editor', name: '<页面中文名>' })}
38
+ onClose={handleCancel}
39
+ onConfirm={handleConfirm}
40
+ />
41
+ ```
42
+
43
+ ## Custom footer
44
+
45
+ Every business `Button` in custom `footer` needs `data-track`. Do not replace the default footer only to add tracking.
46
+
47
+ ## Do not track
48
+
49
+ - Column settings only.
50
+ - Table overflow 「更多」 ellipsis icon (menu items inside still need `track`).
51
+ - Buttons hidden by permission (no render → no track).
52
+
53
+ **Copy buttons must be tracked** — see shared-tracking §5.
54
+
55
+ ## After `gen page`
56
+
57
+ When `src/utils/tracking/index.ts` exists, `gen page` wires toolbar, action edit/delete, drawer, and modal by default. Agent still reviews and adds tracking for extra buttons (copy, batch, custom footer, ProForm). Pass `--no-tracking` only when user explicitly asks.
58
+
59
+ For pages **not** from `gen page`, Agent scans and wires the full set per shared-tracking — not a user manual task.
60
+
61
+ ## Verification
62
+
63
+ Static scan changed files: every toolbar / action / copy / drawer / modal / form button has `track`, `cancelTrack`, `okTrack`, or `data-track`.
@@ -26,6 +26,19 @@ This checklist is complete for shared review and commit. If `.agents/project/rev
26
26
  - Check loading, empty, error, disabled, long content, and narrow-screen layout.
27
27
  - Table empty values render `'-'` unless the design requires another value.
28
28
 
29
+ ## Tracking
30
+
31
+ Apply when the project has `src/utils/tracking/index.ts` (or the path in project conventions). Read `.agents/skills/shared-tracking/SKILL.md` and `.agents/skills/shared-design-to-page/references/tracking.md`.
32
+
33
+ - Toolbar and batch actions in `getToolBarRender` need `track: getTrackData(...)`.
34
+ - Action column entries need `track` beside `permission` when present.
35
+ - Standalone permission buttons need `data-track={getTrackData(...)}`.
36
+ - `CustomDrawer` with the default footer needs `cancelTrack` and `okTrack`; custom footers need `data-track` on each business button.
37
+ - `BaseModal` confirm dialogs need `cancelButtonProps` / `okButtonProps` with `'data-track'`.
38
+ - `ProForm` with a visible default submitter needs submit/reset button props; when `submitter={false}`, tracking belongs on the overlay footer only.
39
+ - Require tracking on copy actions; do not require tracking on column settings, table overflow ellipsis icon, or buttons hidden by permission.
40
+ - Missing in-scope button tracking on a changed page is **P1**.
41
+
29
42
  ## Shared components and regression
30
43
 
31
44
  - Changes to `MFProTable`, permission components, the request wrapper, or shared hooks must list direct callers.
@@ -30,8 +30,9 @@ Follow [references/impact-analysis.md](references/impact-analysis.md). Output:
30
30
  Follow [references/verify.md](references/verify.md). Output:
31
31
 
32
32
  - P0/P1/P2 blockers
33
- - Completeness of route, permission, API, types, mock, and page states
33
+ - Completeness of route, permission, API, types, mock, page states, and button tracking when the project has tracking configured
34
34
  - Async, loading, overlay, and list-reload behavior
35
+ - Missing `track` / `data-track` / `cancelTrack` / `okTrack` on in-scope buttons per `shared-tracking` and `shared-design-to-page/references/tracking.md` (P1 when tracking is enabled)
35
36
  - Prettier, TypeScript, lint, and build results
36
37
  - Uncovered risks
37
38
 
@@ -6,6 +6,7 @@ Review the current diff plus relevant callers and types. Before reviewing, read:
6
6
 
7
7
  1. `.agents/skills/shared-project-conventions/references/review-checklist.md`
8
8
  2. `.agents/skills/shared-project-conventions/references/quality-checklist.md`
9
+ 3. `.agents/skills/shared-tracking/SKILL.md` and `.agents/skills/shared-design-to-page/references/tracking.md` when the project has tracking configured
9
10
 
10
11
  If `.agents/project/review-rules.md` exists, apply extra domain checks only; do not weaken shared hard rules.
11
12
 
@@ -14,14 +15,15 @@ If `.agents/project/review-rules.md` exists, apply extra domain checks only; do
14
15
  1. React Hooks: stale closures, incomplete dependencies, request races, updates after unmount, unnecessary rerenders.
15
16
  2. API contracts: method/path/params, response unwrapping, pagination, nullability, enum drift, error handling, DTO mismatch.
16
17
  3. Permissions: route access, button visibility, mutation authorization, client-only enforcement.
17
- 4. Forms/tables: validation, reset, duplicate submit, refresh after mutation, column-state, long text, empty/error.
18
- 5. Performance (hard checks):
18
+ 4. **Tracking** (when `src/utils/tracking/index.ts` or project equivalent exists): scan changed pages for missing `track` / `cancelTrack` / `okTrack` / `data-track` on in-scope buttons—toolbar, action column, permission buttons, drawer and confirm footers (default and custom), inline form submitters, and **copy** actions. Flag missing wiring as **P1**. Do not require tracking on column settings, table overflow ellipsis icon, or permission-hidden buttons. Do not flag handlers that call `track()` when `data-track` is the project standard.
19
+ 5. Forms/tables: validation, reset, duplicate submit, refresh after mutation, column-state, long text, empty/error.
20
+ 6. Performance (hard checks):
19
21
  - New or changed files must not statically `import 'xlsx'`, `@uiw/react-codemirror`, `@codemirror/*`, `echarts`, `@ant-design/charts`, or `react-json-view` at module top level. Those must be `import()`.
20
22
  - Do not add heavy modules to `src/app.ts`, `src/global.tsx`, or layout bootstrap.
21
23
  - Flag generated list pages that pull Excel/editor/chart code into the route entry instead of a feature-level dynamic import.
22
24
  - Also check duplicate libraries, large lists without virtualization, unstable columns/handlers, and avoidable requests.
23
- 6. Security/privacy: tokens, user data, URLs, unsafe HTML, sensitive logs, environment config.
24
- 7. Tests and accessibility: critical paths, failure states, keyboard labels, disabled/loading semantics.
25
+ 7. Security/privacy: tokens, user data, URLs, unsafe HTML, sensitive logs, environment config.
26
+ 8. Tests and accessibility: critical paths, failure states, keyboard labels, disabled/loading semantics.
25
27
 
26
28
  ## Output
27
29
 
@@ -6,6 +6,7 @@ Read the current diff, related callers, and:
6
6
 
7
7
  1. `.agents/skills/shared-project-conventions/references/review-checklist.md`
8
8
  2. `.agents/skills/shared-project-conventions/references/architecture.md`
9
+ 3. `.agents/skills/shared-tracking/SKILL.md` when the project has `src/utils/tracking/index.ts` (or the tracking path in project conventions)
9
10
 
10
11
  Do not auto-fix. If `.agents/project/review-rules.md` exists, apply extra domain checks only.
11
12
 
@@ -18,6 +19,7 @@ Do not auto-fix. If `.agents/project/review-rules.md` exists, apply extra domain
18
19
  5. Empty table values, duplicate-submit guards, permission wrappers, and narrow-screen overflow.
19
20
  6. Heavy deps (`xlsx`, editors, charts) are `import()`; nothing new lands in `src/app.ts`.
20
21
  7. No `MFTablePro` / table-from-package imports; overlays come from `@mingfuyun/star-allinone`.
22
+ 8. **Tracking** (when tracking is configured): every in-scope button has `track`, `cancelTrack`, `okTrack`, or `data-track` per `.agents/skills/shared-tracking/SKILL.md` and `.agents/skills/shared-design-to-page/references/tracking.md`. Check toolbar items, action column entries, standalone permission buttons, drawer default or custom footers, confirm modals, inline `ProForm` submitters, and **copy** buttons. Missing wiring is **P1** when the button is user-visible and in scope. Excluded controls (column settings, table overflow ellipsis icon) must not be flagged. Permission-hidden buttons may omit tracking.
21
23
 
22
24
  ## Commands
23
25
 
@@ -36,7 +38,7 @@ Run the project's build script when routes, entry, or shared runtime change.
36
38
  ## Output
37
39
 
38
40
  1. Blocking issues P0–P2, with file, line, impact, and fix direction.
39
- 2. Completeness: route, permission, API, types, mock, page states.
41
+ 2. Completeness: route, permission, API, types, mock, page states, and tracking on in-scope buttons when tracking is configured.
40
42
  3. Command results, distinguishing new, existing, and environment failures.
41
43
  4. Regression list: affected pages, suggested manual paths, uncovered risks.
42
44
 
@@ -9,6 +9,56 @@ description: User-facing. Connect a galaxy admin app to the shared tracking SDK.
9
9
 
10
10
  先确认埋点平台已登记本项目的 `appId`。测试用 `test-<project>`,生产用 `<project>`。不一致时只改配置,不改包。
11
11
 
12
+ ## Agent 必须做的事(不要留给用户手工补)
13
+
14
+ 用户说「接入埋点」「补齐埋点」「全部补齐」时,**Agent 负责扫描业务仓库并写入全部按钮埋点**。不要把 wiring 清单丢给用户,不要说「请你在各页 const.tsx 里手动加 track」。
15
+
16
+ 完成标准:
17
+
18
+ 1. 基础设施(SDK、`tracking/index.ts`、`app.tsx`、请求封装)已就绪。
19
+ 2. **全站**下列五类可点击按钮均已带 `track` / `cancelTrack` / `okTrack` / `data-track`(无权限未渲染的除外)。
20
+ 3. `pnpm typecheck` 通过。
21
+ 4. 向用户汇报已覆盖的文件范围,而不是留 TODO 让用户自己改。
22
+
23
+ ### 必须扫描并补齐的五类按钮
24
+
25
+ | # | 范围 | 扫描位置 | 写法 |
26
+ | --- | --- | --- | --- |
27
+ | 1 | **权限相关按钮** | `withAuth` / `AccessButton`;`TableSearchType` 带 `permission`;`TablePermissionActions` | `data-track` 或 `track:` |
28
+ | 2 | **CustomDrawer / HocModal** | 所有 `CustomDrawer`、`BaseModal`(含 `HocModal` 包裹) | 默认底部:`cancelTrack`/`okTrack`;**自定义 footer 每个 Button** 带 `data-track` |
29
+ | 3 | **MFProTable 操作列** | `actionColumn`、`listActionColumn`、`TableActions`、`TablePermissionActions` | `ActionItem.track` |
30
+ | 4 | **ProForm / Form** | `submitter` 默认栏、`submitter.render`、antd `Form` 提交/重置 | `submitButtonProps` / `resetButtonProps` 的 `data-track` |
31
+ | 5 | **复制相关按钮** | 文案含「复制」「一键复制」、`key` 含 `copy`;含复制 IP | `getTrackData('copy', '…', …)` |
32
+
33
+ 另需覆盖(同属 Agent 批量任务):
34
+
35
+ - 工具栏 / 批量底部 / 搜索附加按钮(`toolBarRender`、`multiFooter`、`searchButton`)
36
+ - `MFProTable` 查询/重置(表格组件内已处理则不要重复)
37
+ - 抽屉 `submitter={false}` 时,提交在 Drawer 底部,不在 Form 重复
38
+
39
+ ### 扫描命令(Agent 自行执行)
40
+
41
+ ```bash
42
+ rg "CustomDrawer|BaseModal|HocModal" src/pages src/components -g "*.tsx"
43
+ rg "toolBarRender|actionColumn|listActionColumn|TablePermissionActions" src/pages -g "*.{tsx,ts}"
44
+ rg "withAuth|AccessButton" src/pages -g "*.tsx"
45
+ rg "ProForm|submitter" src/pages -g "*.tsx"
46
+ rg "复制|copy|Copy" src/pages src/components -g "*.tsx"
47
+ ```
48
+
49
+ 对每个命中文件:**打开、判断是否在五类范围内、补全、保存**。历史页与 `gen page` 新页同一标准。
50
+
51
+ ### 不要做的「半套接入」
52
+
53
+ - ❌ 只建 `tracking/index.ts` 和 SDK,不扫页面按钮
54
+ - ❌ 只改一两个示例页,告诉用户「其余页按同样方式手动加」
55
+ - ❌ 在组件层做 track 自动推断(不改 `withAuth` / `TableActions` 自动生成 track)
56
+ - ❌ 把复制按钮排除在补齐范围外
57
+
58
+ 仍不上报:**列设置**、表格 **「更多」省略号**(仅展开菜单的 icon;菜单内各项仍要 track)。
59
+
60
+ ---
61
+
12
62
  ## 1. 更新能力包
13
63
 
14
64
  依赖至少 `0.4.0`。这一版才有 `createTracking`、`TRACKING_REPORT_URLS`,以及 `CustomDrawer` 的 `cancelTrack` / `okTrack`。
@@ -99,17 +149,15 @@ Umi:
99
149
 
100
150
  在项目自己的请求封装里,业务 `code` 非 0 或 HTTP 失败时调用 `reportApiTracking`。成功不报。字段:去掉 query 的 `url`、大写 `method`、`duration`、`success: false`、`status`、`errorMessage`。保留原来的 `message.error`。页面不要直接调 axios。
101
151
 
102
- ### 按钮
152
+ ### 按钮写法(Agent 批量写入业务代码)
103
153
 
104
- `getTrackData(action, name, { key, name })` 生成 `data-track` JSON。`id` 用下划线,展示名用 `-` 连接。点击由 SDK 监听 `data-track`,业务代码不要再调 `track`。
154
+ `getTrackData(action, name, { key, name })` 生成 `data-track` JSON。`id` 用下划线,展示名用 `-` 连接。点击由 SDK 监听 `data-track`,业务代码不要再调 `track()`。
105
155
 
106
- 权限按钮、操作列、抽屉/弹层底部、表单提交都要上报。复制、列设置、表格「更多」省略号不上报。搜索栏里除查询和重置以外的按钮,除非用户点名,否则不加。
107
-
108
- #### 权限按钮
156
+ #### 1. 权限相关按钮
109
157
 
110
158
  `withAuth` 会把除 `permission`、`fallback` 以外的 props 传给原按钮。无权限时组件不渲染,不会上报。
111
159
 
112
- 工具栏、批量底部、搜索附加按钮已经走 `TableSearchType.track`,`MFProTable` 把它写成 `data-track`。在 `const.tsx` 里和 `permission` 一起写:
160
+ 工具栏、批量底部、搜索附加按钮走 `TableSearchType.track`,`MFProTable` 把它写成 `data-track`:
113
161
 
114
162
  ```tsx
115
163
  {
@@ -122,7 +170,7 @@ Umi:
122
170
  }
123
171
  ```
124
172
 
125
- 页面上单独的 `withAuth(Button)` 直接写 `data-track`,不要为了埋点再包一层:
173
+ 页面上单独的 `withAuth(Button)`:
126
174
 
127
175
  ```tsx
128
176
  <AccessButton
@@ -135,11 +183,13 @@ Umi:
135
183
  </AccessButton>
136
184
  ```
137
185
 
138
- #### CustomDrawer、HocModal
186
+ `TablePermissionActions` 的 `actionList` 每项加 `track`。
187
+
188
+ #### 2. CustomDrawer、HocModal
139
189
 
140
190
  `HocModal` 只控制显隐,不渲染按钮。埋点写在它包住的 `CustomDrawer` 或 `BaseModal` 上。
141
191
 
142
- `CustomDrawer` 默认底部用 `cancelTrack` 和 `okTrack`。不要为了埋点整段替换 `footer`。
192
+ **默认底部** — 用 `cancelTrack` / `okTrack`,不要整段替换 `footer`:
143
193
 
144
194
  ```tsx
145
195
  <CustomDrawer
@@ -150,49 +200,33 @@ Umi:
150
200
  />
151
201
  ```
152
202
 
153
- 自定义 `footer` 会换掉默认底部。每个业务按钮自己带 `data-track`,包括预览、上一步、取消、确定。
203
+ **自定义 footer** — 每个业务 Button 带 `data-track`(取消、确定、关闭、预览、复制 IP 等)。
154
204
 
155
- `BaseModal` 用 antd 的按钮 props。自定义 `footer` 时同样把 `data-track` 写在自己的按钮上。
205
+ `BaseModal` 若无 `cancelButtonProps` 类型,用**自定义 footer** + `data-track`。
156
206
 
157
- ```tsx
158
- <BaseModal
159
- cancelButtonProps={{
160
- 'data-track': getTrackData('cancel', '取消', { key: 'confirm', name: '确认' }),
161
- }}
162
- okButtonProps={{
163
- 'data-track': getTrackData('confirm', '确定', { key: 'confirm', name: '确认' }),
164
- }}
165
- onCancel={handleCancel}
166
- onOk={handleOk}
167
- />
168
- ```
207
+ #### 3. MFProTable 操作列
169
208
 
170
- #### MFProTable 操作列
171
-
172
- `actionColumn` 的配置在页面 `const.tsx`。给 `ActionItem` 增加 `track?: string`,和 `permission` 放在一起。模块固定 `{ key: 'action', name: '操作' }`,`action` 用该项的 `key`,`name` 用按钮文案。
209
+ `actionColumn` 在页面 `const.tsx`。给 `ActionItem` 增加 `track`:
173
210
 
174
211
  ```tsx
175
212
  {
176
- key: 'allocate',
177
- permission: FULL_MENU.example.allocate,
178
- track: getTrackData('allocate', '分配', { key: 'action', name: '操作' }),
179
- getText: () => '分配',
180
- onClick: handleAllocate,
213
+ key: 'edit',
214
+ permission: FULL_MENU.example.edit,
215
+ track: getTrackData('edit', '编辑', { key: 'action', name: '操作' }),
216
+ getText: () => '编辑',
217
+ onClick: handleEdit,
181
218
  }
182
219
  ```
183
220
 
184
- 业务仓的 `TableActions` 要把 `track` 写到可点击节点上:
185
-
186
- - 行内 `<a>` 加 `data-track={action.track}`。
187
- - 超出 `maxCount` 收进下拉时,菜单项 `label` 用 `<span data-track={action.track}>`。不要给「更多」省略号按钮加埋点。
221
+ 业务仓 `TableActions` 已支持 `data-track={action.track}`。不要给「更多」省略号 icon 加埋点;下拉菜单内各项仍要 `track`。
188
222
 
189
- `MFProTable` 查询按钮用 `filter_query` / `查询`,重置按钮用 `filter_reset` / `重置`。ProTable 重置按钮的 key 是 `rest`。
223
+ 查询/重置:`MFProTable` 内为 `filter_query`/`查询`、`filter_reset`/`重置`(ProTable 重置 key 为 `rest`)。
190
224
 
191
- #### ProForm、Form
225
+ #### 4. ProForm、Form
192
226
 
193
- 抽屉里的 `ProForm` 若 `submitter={false}`,提交按钮在抽屉或弹层底部,按上一节上报,不要在表单里再加一套。
227
+ 抽屉内 `ProForm` 若 `submitter={false}`,提交在 `CustomDrawer` 底部,按上一节写,**不要在 Form 里重复**。
194
228
 
195
- `ProForm` 使用默认提交栏时,写在 `submitter` 上:
229
+ 默认提交栏:
196
230
 
197
231
  ```tsx
198
232
  <ProForm
@@ -207,9 +241,24 @@ Umi:
207
241
  />
208
242
  ```
209
243
 
210
- `submitter.render` 换掉默认按钮时,返回的每个提交、重置按钮自己带 `data-track`。
244
+ `submitter.render` 或 antd `Form` 自定义按钮:每个提交/重置 Button 单独 `data-track`。
211
245
 
212
- antd `Form` 的提交、重置按钮同样写 `data-track`。只上报会触发提交或清空表单的按钮,不上报字段里的辅助按钮。
246
+ #### 5. 复制相关按钮
247
+
248
+ **必须上报**。含操作列「复制」、群看板「一键复制」、复制 IP 等。
249
+
250
+ ```tsx
251
+ {
252
+ key: 'action-copy',
253
+ track: getTrackData('copy', '复制', { key: 'action', name: '操作' }),
254
+ getText: () => '复制',
255
+ onClick: handleCopy,
256
+ }
257
+ ```
258
+
259
+ ```tsx
260
+ track: getTrackData('copy', '复制IP', { key: 'toolbar', name: '群看板' })
261
+ ```
213
262
 
214
263
  ## 不要做的事
215
264
 
@@ -218,6 +267,8 @@ antd `Form` 的提交、重置按钮同样写 `data-track`。只上报会触发
218
267
  - 不要在包外重写队列。上限 50 条、失败补报已经在 `createTracking` 里。
219
268
  - 不要上报成功请求。
220
269
  - 不要为了埋点改用户接口或请求错误提示。
270
+ - **不要**在组件层做 track 自动推断。
271
+ - **不要**只完成基础设施就把按钮埋点留给用户。
221
272
 
222
273
  ## 验证
223
274
 
@@ -226,6 +277,6 @@ antd `Form` 的提交、重置按钮同样写 `data-track`。只上报会触发
226
277
  1. 页面请求了 OSS 上的脚本,并且出现 `window.TrackingSDK`。
227
278
  2. 进入业务页、初始状态完成后存在 `window.__tracker`。`/` 上可以还没有。
228
279
  3. 一次失败请求发出事件名 `api_request`。
229
- 4. 查询、重置、权限按钮、操作列、抽屉或弹层底部、表单提交按钮带 `data-track`。无权限而不渲染的按钮可以没有。
280
+ 4. 五类按钮(含复制)带 `data-track` / `cancelTrack` / `okTrack`。
230
281
 
231
282
  `appId` 与平台不一致时,只改 `src/utils/tracking/index.ts`。