@deepstorm/cli 0.11.0 → 0.11.1

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.
Files changed (123) hide show
  1. package/README.md +8 -8
  2. package/dist/build-registry.js +11 -5
  3. package/dist/cli.js +839 -585
  4. package/dist/mcp/code-hosting/github.json +14 -1
  5. package/dist/mcp/docs-reference/context7.json +1 -10
  6. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-read/SKILL.md +8 -5
  7. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-write/SKILL.md +10 -8
  8. package/dist/mcp-skills/deepstorm-mcp-figma-read/SKILL.md +21 -20
  9. package/dist/mcp-skills/deepstorm-mcp-github-read/SKILL.md +17 -17
  10. package/dist/mcp-skills/deepstorm-mcp-github-write/SKILL.md +20 -20
  11. package/dist/mcp-skills/deepstorm-mcp-jira-read/SKILL.md +8 -8
  12. package/dist/mcp-skills/deepstorm-mcp-jira-write/SKILL.md +13 -12
  13. package/dist/mcp-skills/deepstorm-mcp-playwright-read/SKILL.md +10 -10
  14. package/dist/skills/atoll-ops/SKILL.md +4 -0
  15. package/dist/skills/reef-commit/SKILL.md +9 -5
  16. package/dist/skills/reef-commit/scripts/branch-check.mjs +5 -11
  17. package/dist/skills/reef-commit/scripts/check-openspec-status.mjs +6 -12
  18. package/dist/skills/reef-commit/scripts/collect-git-context.mjs +13 -11
  19. package/dist/skills/reef-gen-backend/variants/java/steps.md +7 -7
  20. package/dist/skills/reef-gen-backend/variants/nodejs/steps.md +7 -7
  21. package/dist/skills/reef-gen-backend/variants/python/steps.md +7 -7
  22. package/dist/skills/reef-gen-frontend/variants/angular/steps.md +5 -5
  23. package/dist/skills/reef-gen-frontend/variants/react/steps.md +6 -6
  24. package/dist/skills/reef-gen-frontend/variants/vue/steps.md +6 -6
  25. package/dist/skills/reef-harden/EXAMPLES.md +12 -10
  26. package/dist/skills/reef-harden/SKILL.md +6 -0
  27. package/dist/skills/reef-harden/scripts/find-change-dir.mjs +13 -13
  28. package/dist/skills/reef-pr/SKILL.md +7 -0
  29. package/dist/skills/reef-pr/scripts/create-pr.mjs +31 -29
  30. package/dist/skills/reef-scope/SKILL.md +6 -6
  31. package/dist/skills/reef-start/references/jira-start-subagent.md +7 -7
  32. package/dist/skills/reef-start/references/risk-routing-card.md +28 -25
  33. package/dist/skills/reef-start/references/stage-4-implementation.md +33 -21
  34. package/dist/skills/reef-start/references/superpowers-gate.md +9 -9
  35. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/structured-output.md +2 -2
  36. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/quick-reference.md +11 -0
  37. package/dist/skills/reef-style-backend/fragments/java/api-spec/jackson-polymorphism.md +36 -40
  38. package/dist/skills/reef-style-backend/fragments/java/api-spec/quick-reference.md +11 -10
  39. package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/examples/database-migration.md +7 -7
  40. package/dist/skills/reef-style-backend/fragments/java/dependency-management/quick-reference.md +24 -21
  41. package/dist/skills/reef-style-backend/fragments/java/exception-handling/examples/error-code-enum.md +7 -7
  42. package/dist/skills/reef-style-backend/fragments/java/exception-handling/quick-reference.md +10 -8
  43. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/dto-mapper.md +2 -2
  44. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/service-entity.md +5 -5
  45. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/testing.md +1 -0
  46. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/quick-reference.md +12 -12
  47. package/dist/skills/reef-style-backend/fragments/java/orm/hibernate/quick-reference.md +13 -12
  48. package/dist/skills/reef-style-backend/fragments/java/security-redlines/quick-reference.md +11 -9
  49. package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/quick-reference.md +7 -7
  50. package/dist/skills/reef-style-backend/fragments/java/test/junit5/quick-reference.md +6 -6
  51. package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/quick-reference.md +8 -8
  52. package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/quick-reference.md +8 -7
  53. package/dist/skills/reef-style-backend/fragments/nodejs/eslint-config.json +1 -4
  54. package/dist/skills/reef-style-backend/fragments/nodejs/nestjs-structure.md +9 -9
  55. package/dist/skills/reef-style-backend/fragments/python/alembic-migration/quick-reference.md +2 -1
  56. package/dist/skills/reef-style-backend/fragments/python/api-spec/quick-reference.md +10 -10
  57. package/dist/skills/reef-style-backend/fragments/python/dependency-management/quick-reference.md +24 -22
  58. package/dist/skills/reef-style-backend/fragments/python/exception-handling/quick-reference.md +10 -9
  59. package/dist/skills/reef-style-backend/fragments/python/fastapi-quick-reference/quick-reference.md +3 -0
  60. package/dist/skills/reef-style-backend/fragments/python/langchain/quick-reference.md +10 -7
  61. package/dist/skills/reef-style-backend/fragments/python/pytest-testing/quick-reference.md +2 -0
  62. package/dist/skills/reef-style-backend/fragments/python/ruff-mypy-toolchain/quick-reference.md +2 -0
  63. package/dist/skills/reef-style-backend/fragments/python/security-redlines/quick-reference.md +11 -9
  64. package/dist/skills/reef-style-backend/fragments/python/sqlalchemy-orm/quick-reference.md +3 -0
  65. package/dist/skills/reef-style-backend/variants/java/examples/code-wrapping.md +3 -4
  66. package/dist/skills/reef-style-backend/variants/java/quick-reference.md +31 -29
  67. package/dist/skills/reef-style-backend/variants/nodejs/examples/module-example.md +2 -8
  68. package/dist/skills/reef-style-backend/variants/nodejs/quick-reference.md +35 -36
  69. package/dist/skills/reef-style-backend/variants/python/quick-reference.md +32 -31
  70. package/dist/skills/reef-style-frontend/fragments/css/tailwind/quick-reference.md +9 -7
  71. package/dist/skills/reef-style-frontend/fragments/test/vitest/examples/testing.md +9 -4
  72. package/dist/skills/reef-style-frontend/fragments/test/vitest/quick-reference.md +4 -4
  73. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/examples/testing.md +135 -140
  74. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/quick-reference.md +32 -32
  75. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/examples/testing.md +161 -162
  76. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/quick-reference.md +42 -42
  77. package/dist/skills/reef-style-frontend/fragments/ts-config/strict/quick-reference.md +16 -10
  78. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/examples/ui-components.md +72 -87
  79. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/quick-reference.md +14 -10
  80. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/examples/ui-components.md +93 -111
  81. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/quick-reference.md +29 -33
  82. package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/examples/ui-components.md +14 -23
  83. package/dist/skills/reef-style-frontend/variants/angular/examples/code-wrapping.md +15 -17
  84. package/dist/skills/reef-style-frontend/variants/angular/examples/component-types-pipes.md +22 -5
  85. package/dist/skills/reef-style-frontend/variants/angular/examples/entity-types.md +52 -22
  86. package/dist/skills/reef-style-frontend/variants/angular/examples/forms-layer.md +17 -20
  87. package/dist/skills/reef-style-frontend/variants/angular/examples/service-routing.md +8 -11
  88. package/dist/skills/reef-style-frontend/variants/angular/quick-reference.md +27 -27
  89. package/dist/skills/reef-style-frontend/variants/react/examples/code-wrapping.md +14 -27
  90. package/dist/skills/reef-style-frontend/variants/react/examples/component-types-pipes.md +45 -52
  91. package/dist/skills/reef-style-frontend/variants/react/examples/entity-types.md +44 -44
  92. package/dist/skills/reef-style-frontend/variants/react/examples/forms-layer.md +56 -85
  93. package/dist/skills/reef-style-frontend/variants/react/examples/service-routing.md +114 -88
  94. package/dist/skills/reef-style-frontend/variants/react/quick-reference.md +48 -42
  95. package/dist/skills/reef-style-frontend/variants/vue/examples/code-wrapping.md +24 -43
  96. package/dist/skills/reef-style-frontend/variants/vue/examples/component-types-pipes.md +48 -49
  97. package/dist/skills/reef-style-frontend/variants/vue/examples/entity-types.md +45 -45
  98. package/dist/skills/reef-style-frontend/variants/vue/examples/forms-layer.md +64 -68
  99. package/dist/skills/reef-style-frontend/variants/vue/examples/service-routing.md +85 -84
  100. package/dist/skills/reef-style-frontend/variants/vue/quick-reference.md +46 -51
  101. package/dist/skills/reef-testcase/SKILL.md +19 -19
  102. package/dist/skills/reef-testcase/references/coverage-dimensions.md +8 -0
  103. package/dist/skills/reef-testcase/references/test-case-template.md +16 -16
  104. package/dist/skills/sweep-explore/SKILL.md +129 -100
  105. package/dist/skills/sweep-explore/references/explore-flow-template.md +9 -9
  106. package/dist/skills/sweep-init/SKILL.md +4 -0
  107. package/dist/skills/sweep-init/scripts/flow-selector.mjs +6 -11
  108. package/dist/skills/sweep-init/scripts/init-project.mjs +68 -51
  109. package/dist/skills/sweep-plan/references/test-flow-template.md +12 -6
  110. package/dist/skills/sweep-record/SKILL.md +38 -15
  111. package/dist/skills/sweep-run/SKILL.md +59 -50
  112. package/dist/skills/sweep-run/scripts/env-manager.mjs +4 -5
  113. package/dist/skills/sweep-run/scripts/flow-parser.mjs +7 -6
  114. package/dist/skills/sweep-run/scripts/flow-selector.mjs +4 -15
  115. package/dist/skills/sweep-run/scripts/generate-report.mjs +1 -2
  116. package/dist/skills/sweep-run/scripts/mcp-manager.mjs +107 -14
  117. package/dist/skills/sweep-run/scripts/spec-compiler.mjs +19 -9
  118. package/dist/skills/tide-discuss/references/checklists.md +32 -32
  119. package/dist/skills/tide-discuss/references/data-format.md +85 -77
  120. package/dist/skills/tide-discuss/references/prd-template.md +21 -19
  121. package/dist/skills/tide-discuss/references/publish-flow.md +30 -11
  122. package/dist/skills/tide-discuss/references/role-prompts.md +5 -5
  123. package/package.json +4 -3
@@ -4,8 +4,8 @@
4
4
 
5
5
  ```typescript
6
6
  // vitest.config.ts
7
- import { defineConfig } from 'vitest/config'
8
- import vue from '@vitejs/plugin-vue'
7
+ import { defineConfig } from 'vitest/config';
8
+ import vue from '@vitejs/plugin-vue';
9
9
 
10
10
  export default defineConfig({
11
11
  plugins: [vue()],
@@ -26,12 +26,12 @@ export default defineConfig({
26
26
  },
27
27
  },
28
28
  },
29
- })
29
+ });
30
30
  ```
31
31
 
32
32
  ```typescript
33
33
  // src/test/setup.ts
34
- import '@testing-library/jest-dom'
34
+ import '@testing-library/jest-dom';
35
35
  ```
36
36
 
37
37
  ## 通用原则
@@ -44,18 +44,18 @@ import '@testing-library/jest-dom'
44
44
  ## 组件测试(Vue Test Utils)
45
45
 
46
46
  ```typescript
47
- import { mount } from '@vue/test-utils'
48
- import { describe, it, expect } from 'vitest'
47
+ import { mount } from '@vue/test-utils';
48
+ import { describe, it, expect } from 'vitest';
49
49
 
50
50
  // ✅ 正确:通过文本寻找元素
51
- const wrapper = mount(MyComponent)
52
- expect(wrapper.text()).toContain('提交')
51
+ const wrapper = mount(MyComponent);
52
+ expect(wrapper.text()).toContain('提交');
53
53
 
54
54
  // ✅ 正确:模拟用户交互
55
- await wrapper.find('button').trigger('click')
55
+ await wrapper.find('button').trigger('click');
56
56
 
57
57
  // ✅ 正确:通过 findComponent 查找子组件
58
- expect(wrapper.findComponent({ name: 'AButton' }).exists()).toBe(true)
58
+ expect(wrapper.findComponent({ name: 'AButton' }).exists()).toBe(true);
59
59
 
60
60
  // ❌ 避免:通过 CSS 类名选择
61
61
  // wrapper.find('.btn-primary') // 禁止
@@ -64,19 +64,19 @@ expect(wrapper.findComponent({ name: 'AButton' }).exists()).toBe(true)
64
64
  ## Hook / 组合式函数测试
65
65
 
66
66
  ```typescript
67
- import { describe, it, expect } from 'vitest'
67
+ import { describe, it, expect } from 'vitest';
68
68
 
69
69
  describe('useCounter', () => {
70
70
  it('should increment count', () => {
71
- const { result } = renderHook(() => useCounter())
71
+ const { result } = renderHook(() => useCounter());
72
72
 
73
73
  act(() => {
74
- result.current.increment()
75
- })
74
+ result.current.increment();
75
+ });
76
76
 
77
- expect(result.current.count).toBe(1)
78
- })
79
- })
77
+ expect(result.current.count).toBe(1);
78
+ });
79
+ });
80
80
  ```
81
81
 
82
82
  ## 测试文件命名与位置
@@ -88,22 +88,22 @@ describe('useCounter', () => {
88
88
  ## Mock 策略
89
89
 
90
90
  ```typescript
91
- import { vi } from 'vitest'
91
+ import { vi } from 'vitest';
92
92
 
93
93
  // Mock fetch
94
- global.fetch = vi.fn()
94
+ global.fetch = vi.fn();
95
95
 
96
96
  // Mock 模块
97
97
  vi.mock('ant-design-vue', async () => {
98
- const actual = await vi.importActual('ant-design-vue')
98
+ const actual = await vi.importActual('ant-design-vue');
99
99
  return {
100
100
  ...actual,
101
101
  message: {
102
102
  success: vi.fn(),
103
103
  error: vi.fn(),
104
104
  },
105
- }
106
- })
105
+ };
106
+ });
107
107
 
108
108
  // Mock 组合式函数
109
109
  vi.mock('@/composables/useUsers', () => ({
@@ -113,7 +113,7 @@ vi.mock('@/composables/useUsers', () => ({
113
113
  error: null,
114
114
  refresh: vi.fn(),
115
115
  }),
116
- }))
116
+ }));
117
117
  ```
118
118
 
119
119
  ## 异步测试
@@ -124,39 +124,39 @@ it('should load and display users', async () => {
124
124
  const mockUsers = [
125
125
  { id: '1', username: 'alice', email: 'alice@example.com', role: 'ADMIN' },
126
126
  { id: '2', username: 'bob', email: 'bob@example.com', role: 'EDITOR' },
127
- ]
127
+ ];
128
128
 
129
129
  // 模拟 API 响应
130
130
  const mockFetch = vi.fn().mockResolvedValue({
131
131
  ok: true,
132
132
  json: () => Promise.resolve({ content: mockUsers, totalElements: 2 }),
133
- })
134
- global.fetch = mockFetch
133
+ });
134
+ global.fetch = mockFetch;
135
135
 
136
136
  // Act
137
- const wrapper = mount(UserList)
137
+ const wrapper = mount(UserList);
138
138
 
139
139
  // Assert — 等待异步渲染完成
140
- await nextTick()
141
- expect(wrapper.text()).toContain('alice')
142
- })
140
+ await nextTick();
141
+ expect(wrapper.text()).toContain('alice');
142
+ });
143
143
 
144
144
  // @testing-library/vue 方案(自动等待)
145
- import { render, screen } from '@testing-library/vue'
145
+ import { render, screen } from '@testing-library/vue';
146
146
 
147
147
  it('should display users with testing-library', async () => {
148
- render(UserList)
149
- expect(await screen.findByText('alice')).toBeInTheDocument()
150
- })
148
+ render(UserList);
149
+ expect(await screen.findByText('alice')).toBeInTheDocument();
150
+ });
151
151
  ```
152
152
 
153
153
  ## Pinia 测试
154
154
 
155
155
  ```typescript
156
- import { mount } from '@vue/test-utils'
157
- import { createTestingPinia } from '@pinia/testing'
158
- import { describe, it, expect, vi } from 'vitest'
159
- import UserList from '@/views/UserList.vue'
156
+ import { mount } from '@vue/test-utils';
157
+ import { createTestingPinia } from '@pinia/testing';
158
+ import { describe, it, expect, vi } from 'vitest';
159
+ import UserList from '@/views/UserList.vue';
160
160
 
161
161
  describe('UserList with Pinia', () => {
162
162
  it('renders loading state', () => {
@@ -171,11 +171,11 @@ describe('UserList with Pinia', () => {
171
171
  }),
172
172
  ],
173
173
  },
174
- })
174
+ });
175
175
 
176
- expect(wrapper.findComponent({ name: 'ASpin' }).exists()).toBe(true)
177
- })
178
- })
176
+ expect(wrapper.findComponent({ name: 'ASpin' }).exists()).toBe(true);
177
+ });
178
+ });
179
179
  ```
180
180
 
181
181
  ## 覆盖率要求
@@ -42,19 +42,19 @@ interface Dict {
42
42
  [key: string]: string;
43
43
  }
44
44
 
45
- const dict: Dict = { a: "1" };
45
+ const dict: Dict = { a: '1' };
46
46
 
47
47
  // ❌ 错误 — dict["b"] 可能是 undefined
48
- console.log(dict["b"].toString());
48
+ console.log(dict['b'].toString());
49
49
 
50
50
  // ✅ 正确
51
- const b = dict["b"];
51
+ const b = dict['b'];
52
52
  if (b) {
53
53
  console.log(b.toString());
54
54
  }
55
55
 
56
56
  // 或用可选链
57
- console.log(dict["b"]?.toString());
57
+ console.log(dict['b']?.toString());
58
58
  ```
59
59
 
60
60
  ### noImplicitOverride
@@ -63,15 +63,21 @@ console.log(dict["b"]?.toString());
63
63
 
64
64
  ```typescript
65
65
  class Base {
66
- save(): void { /* ... */ }
66
+ save(): void {
67
+ /* ... */
68
+ }
67
69
  }
68
70
 
69
71
  class Derived extends Base {
70
72
  // ❌ 错误 — 缺少 override
71
- save(): void { /* ... */ }
73
+ save(): void {
74
+ /* ... */
75
+ }
72
76
 
73
77
  // ✅ 正确
74
- override save(): void { /* ... */ }
78
+ override save(): void {
79
+ /* ... */
80
+ }
75
81
  }
76
82
  ```
77
83
 
@@ -80,14 +86,14 @@ class Derived extends Base {
80
86
  ### 数组查找
81
87
 
82
88
  ```typescript
83
- const items: string[] = ["a", "b", "c"];
89
+ const items: string[] = ['a', 'b', 'c'];
84
90
 
85
91
  // ❌ 错误 — find 返回 T | undefined
86
- const item = items.find(x => x === "d");
92
+ const item = items.find((x) => x === 'd');
87
93
  console.log(item.length);
88
94
 
89
95
  // ✅ 正确
90
- const item = items.find(x => x === "d");
96
+ const item = items.find((x) => x === 'd');
91
97
  if (item) {
92
98
  console.log(item.length);
93
99
  }
@@ -3,40 +3,40 @@
3
3
  ## 完整数据表格(搜索 + 分页 + 操作列)
4
4
 
5
5
  ```tsx
6
- import { useState, useEffect } from 'react'
7
- import { Table, Button, Space, Input, Tag, Modal, message } from 'antd'
8
- import { SearchOutlined, PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'
9
- import type { ColumnsType, TablePaginationConfig } from 'antd/es/table'
10
- import type { User, PageResponse } from '../types/user'
11
- import { userService } from '../services/userService'
6
+ import { useState, useEffect } from 'react';
7
+ import { Table, Button, Space, Input, Tag, Modal, message } from 'antd';
8
+ import { SearchOutlined, PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
9
+ import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
10
+ import type { User, PageResponse } from '../types/user';
11
+ import { userService } from '../services/userService';
12
12
 
13
13
  const UserManagement: React.FC = () => {
14
- const [users, setUsers] = useState<User[]>([])
15
- const [loading, setLoading] = useState(false)
16
- const [pagination, setPagination] = useState({ current: 1, pageSize: 20, total: 0 })
17
- const [search, setSearch] = useState('')
14
+ const [users, setUsers] = useState<User[]>([]);
15
+ const [loading, setLoading] = useState(false);
16
+ const [pagination, setPagination] = useState({ current: 1, pageSize: 20, total: 0 });
17
+ const [search, setSearch] = useState('');
18
18
 
19
19
  const fetchUsers = async (page: number, size: number, keyword?: string) => {
20
- setLoading(true)
20
+ setLoading(true);
21
21
  try {
22
- const data: PageResponse<User> = await userService.list({ page, size, search: keyword })
23
- setUsers(data.content)
24
- setPagination(prev => ({ ...prev, current: data.number, total: data.totalElements }))
22
+ const data: PageResponse<User> = await userService.list({ page, size, search: keyword });
23
+ setUsers(data.content);
24
+ setPagination((prev) => ({ ...prev, current: data.number, total: data.totalElements }));
25
25
  } catch {
26
- message.error('加载用户列表失败')
26
+ message.error('加载用户列表失败');
27
27
  } finally {
28
- setLoading(false)
28
+ setLoading(false);
29
29
  }
30
- }
30
+ };
31
31
 
32
32
  useEffect(() => {
33
- fetchUsers(pagination.current, pagination.pageSize, search)
34
- }, [pagination.current, pagination.pageSize])
33
+ fetchUsers(pagination.current, pagination.pageSize, search);
34
+ }, [pagination.current, pagination.pageSize]);
35
35
 
36
36
  const handleSearch = (value: string) => {
37
- setSearch(value)
38
- setPagination(prev => ({ ...prev, current: 1 }))
39
- }
37
+ setSearch(value);
38
+ setPagination((prev) => ({ ...prev, current: 1 }));
39
+ };
40
40
 
41
41
  const handleDelete = (id: string) => {
42
42
  Modal.confirm({
@@ -45,12 +45,12 @@ const UserManagement: React.FC = () => {
45
45
  okText: '删除',
46
46
  okType: 'danger',
47
47
  onOk: async () => {
48
- await userService.delete(id)
49
- message.success('删除成功')
50
- fetchUsers(pagination.current, pagination.pageSize, search)
48
+ await userService.delete(id);
49
+ message.success('删除成功');
50
+ fetchUsers(pagination.current, pagination.pageSize, search);
51
51
  },
52
- })
53
- }
52
+ });
53
+ };
54
54
 
55
55
  const columns: ColumnsType<User> = [
56
56
  { title: '用户名', dataIndex: 'username', key: 'username' },
@@ -60,39 +60,36 @@ const UserManagement: React.FC = () => {
60
60
  dataIndex: 'role',
61
61
  key: 'role',
62
62
  render: (role: string) => {
63
- const color = role === 'ADMIN' ? 'red' : role === 'EDITOR' ? 'blue' : 'default'
64
- return <Tag color={color}>{role}</Tag>
63
+ const color = role === 'ADMIN' ? 'red' : role === 'EDITOR' ? 'blue' : 'default';
64
+ return <Tag color={color}>{role}</Tag>;
65
65
  },
66
66
  },
67
67
  {
68
68
  title: '状态',
69
69
  dataIndex: 'active',
70
70
  key: 'active',
71
- render: (active: boolean) => (
72
- <Tag color={active ? 'green' : 'default'}>{active ? '活跃' : '停用'}</Tag>
73
- ),
71
+ render: (active: boolean) => <Tag color={active ? 'green' : 'default'}>{active ? '活跃' : '停用'}</Tag>,
74
72
  },
75
73
  {
76
74
  title: '操作',
77
75
  key: 'action',
78
76
  render: (_, record) => (
79
77
  <Space>
80
- <Button type="link" icon={<EditOutlined />} onClick={() => handleEdit(record)}>编辑</Button>
81
- <Button type="link" danger icon={<DeleteOutlined />} onClick={() => handleDelete(record.id)}>删除</Button>
78
+ <Button type="link" icon={<EditOutlined />} onClick={() => handleEdit(record)}>
79
+ 编辑
80
+ </Button>
81
+ <Button type="link" danger icon={<DeleteOutlined />} onClick={() => handleDelete(record.id)}>
82
+ 删除
83
+ </Button>
82
84
  </Space>
83
85
  ),
84
86
  },
85
- ]
87
+ ];
86
88
 
87
89
  return (
88
90
  <div>
89
91
  <div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between' }}>
90
- <Input.Search
91
- placeholder="搜索用户名/邮箱"
92
- allowClear
93
- onSearch={handleSearch}
94
- style={{ width: 300 }}
95
- />
92
+ <Input.Search placeholder="搜索用户名/邮箱" allowClear onSearch={handleSearch} style={{ width: 300 }} />
96
93
  <Button type="primary" icon={<PlusOutlined />} onClick={handleCreate}>
97
94
  新增用户
98
95
  </Button>
@@ -109,32 +106,32 @@ const UserManagement: React.FC = () => {
109
106
  showTotal: (total) => `共 ${total} 条`,
110
107
  }}
111
108
  onChange={(pag: TablePaginationConfig) => {
112
- setPagination(prev => ({
109
+ setPagination((prev) => ({
113
110
  ...prev,
114
111
  current: pag.current ?? 1,
115
112
  pageSize: pag.pageSize ?? 20,
116
- }))
113
+ }));
117
114
  }}
118
115
  />
119
116
  </div>
120
- )
121
- }
117
+ );
118
+ };
122
119
  ```
123
120
 
124
121
  ## 表单弹窗(创建/编辑)
125
122
 
126
123
  ```tsx
127
124
  interface UserFormModalProps {
128
- open: boolean
129
- editingUser?: User | null
130
- onClose: () => void
131
- onSuccess: () => void
125
+ open: boolean;
126
+ editingUser?: User | null;
127
+ onClose: () => void;
128
+ onSuccess: () => void;
132
129
  }
133
130
 
134
131
  const UserFormModal: React.FC<UserFormModalProps> = ({ open, editingUser, onClose, onSuccess }) => {
135
- const [form] = Form.useForm()
136
- const [saving, setSaving] = useState(false)
137
- const isEditing = !!editingUser
132
+ const [form] = Form.useForm();
133
+ const [saving, setSaving] = useState(false);
134
+ const isEditing = !!editingUser;
138
135
 
139
136
  useEffect(() => {
140
137
  if (open) {
@@ -143,35 +140,35 @@ const UserFormModal: React.FC<UserFormModalProps> = ({ open, editingUser, onClos
143
140
  displayName: editingUser.displayName,
144
141
  email: editingUser.email,
145
142
  role: editingUser.role,
146
- })
143
+ });
147
144
  } else {
148
- form.resetFields()
145
+ form.resetFields();
149
146
  }
150
147
  }
151
- }, [open, editingUser, form])
148
+ }, [open, editingUser, form]);
152
149
 
153
150
  const handleSubmit = async () => {
154
151
  try {
155
- const values = await form.validateFields()
156
- setSaving(true)
152
+ const values = await form.validateFields();
153
+ setSaving(true);
157
154
  if (isEditing) {
158
- await userService.update(editingUser!.id, values)
159
- message.success('用户信息已更新')
155
+ await userService.update(editingUser!.id, values);
156
+ message.success('用户信息已更新');
160
157
  } else {
161
- await userService.create(values)
162
- message.success('用户创建成功')
158
+ await userService.create(values);
159
+ message.success('用户创建成功');
163
160
  }
164
- onSuccess()
165
- onClose()
161
+ onSuccess();
162
+ onClose();
166
163
  } catch (err) {
167
164
  // Form validateFields 校验失败会自动聚焦到错误字段,不需要额外处理
168
165
  if (err instanceof Error) {
169
- message.error(err.message)
166
+ message.error(err.message);
170
167
  }
171
168
  } finally {
172
- setSaving(false)
169
+ setSaving(false);
173
170
  }
174
- }
171
+ };
175
172
 
176
173
  return (
177
174
  <Modal
@@ -183,16 +180,8 @@ const UserFormModal: React.FC<UserFormModalProps> = ({ open, editingUser, onClos
183
180
  destroyOnClose
184
181
  okText={isEditing ? '保存' : '创建'}
185
182
  >
186
- <Form
187
- form={form}
188
- layout="vertical"
189
- autoComplete="off"
190
- >
191
- <Form.Item
192
- name="displayName"
193
- label="显示名称"
194
- rules={[{ required: true, message: '请输入显示名称' }]}
195
- >
183
+ <Form form={form} layout="vertical" autoComplete="off">
184
+ <Form.Item name="displayName" label="显示名称" rules={[{ required: true, message: '请输入显示名称' }]}>
196
185
  <Input placeholder="请输入显示名称" />
197
186
  </Form.Item>
198
187
 
@@ -207,11 +196,7 @@ const UserFormModal: React.FC<UserFormModalProps> = ({ open, editingUser, onClos
207
196
  <Input placeholder="请输入邮箱" />
208
197
  </Form.Item>
209
198
 
210
- <Form.Item
211
- name="role"
212
- label="角色"
213
- rules={[{ required: true, message: '请选择角色' }]}
214
- >
199
+ <Form.Item name="role" label="角色" rules={[{ required: true, message: '请选择角色' }]}>
215
200
  <Select placeholder="请选择角色">
216
201
  <Select.Option value="ADMIN">管理员</Select.Option>
217
202
  <Select.Option value="EDITOR">编辑</Select.Option>
@@ -220,15 +205,15 @@ const UserFormModal: React.FC<UserFormModalProps> = ({ open, editingUser, onClos
220
205
  </Form.Item>
221
206
  </Form>
222
207
  </Modal>
223
- )
224
- }
208
+ );
209
+ };
225
210
  ```
226
211
 
227
212
  ## 响应式布局
228
213
 
229
214
  ```tsx
230
- import { Row, Col, Card, Statistic } from 'antd'
231
- import { UserOutlined, FileTextOutlined, AuditOutlined } from '@ant-design/icons'
215
+ import { Row, Col, Card, Statistic } from 'antd';
216
+ import { UserOutlined, FileTextOutlined, AuditOutlined } from '@ant-design/icons';
232
217
 
233
218
  const Dashboard: React.FC = () => {
234
219
  return (
@@ -252,6 +237,6 @@ const Dashboard: React.FC = () => {
252
237
  </Col>
253
238
  </Row>
254
239
  </div>
255
- )
256
- }
240
+ );
241
+ };
257
242
  ```
@@ -10,6 +10,7 @@
10
10
  ## 常用组件规范
11
11
 
12
12
  ### Button(按钮)
13
+
13
14
  - 主要操作使用 `type="primary"`,次要操作默认
14
15
  - 危险操作使用 `danger` 属性
15
16
  - 异步操作必须设置 `loading` 状态防重复提交
@@ -24,6 +25,7 @@
24
25
  ```
25
26
 
26
27
  ### Table(表格)
28
+
27
29
  - 始终指定 `rowKey` 为唯一标识字段(如 `id`)
28
30
  - 列表格使用 `pagination` 属性控制分页
29
31
  - 长列表开启 `virtual` 虚拟滚动(>= 1000 行)
@@ -44,14 +46,15 @@
44
46
  showTotal: (total) => `共 ${total} 条`,
45
47
  }}
46
48
  onChange={(pagination) => {
47
- setPage(pagination.current)
48
- setPageSize(pagination.pageSize)
49
+ setPage(pagination.current);
50
+ setPageSize(pagination.pageSize);
49
51
  }}
50
52
  locale={{ emptyText: <Empty description="暂无数据" /> }}
51
53
  />
52
54
  ```
53
55
 
54
56
  ### Form(表单)
57
+
55
58
  - 使用 `layout="vertical"` 默认垂直布局
56
59
  - 所有校验规则集中在 `rules` 中定义,避免使用自定义 `validator`(除非复杂业务)
57
60
  - `Form.Item` 的 `name` 必须与提交数据结构的字段名一致
@@ -59,12 +62,7 @@
59
62
  - 全局校验信息通过 `ConfigProvider` 的 `form.validateMessages` 统一配置
60
63
 
61
64
  ```tsx
62
- <Form
63
- form={form}
64
- layout="vertical"
65
- onFinish={handleSubmit}
66
- autoComplete="off"
67
- >
65
+ <Form form={form} layout="vertical" onFinish={handleSubmit} autoComplete="off">
68
66
  <Form.Item
69
67
  name="email"
70
68
  label="邮箱"
@@ -79,6 +77,7 @@
79
77
  ```
80
78
 
81
79
  ### Modal(弹窗)
80
+
82
81
  - 表单弹窗用 `destroyOnClose` 确保关闭后重置状态
83
82
  - `afterClose` 用于关闭后的清理回调
84
83
  - 确认弹窗用 `Modal.confirm()` 快捷方法
@@ -94,7 +93,7 @@
94
93
  afterClose={() => form.resetFields()}
95
94
  >
96
95
  <UserForm form={form} user={editingUser} />
97
- </Modal>
96
+ </Modal>;
98
97
 
99
98
  // 确认弹窗
100
99
  Modal.confirm({
@@ -103,29 +102,34 @@ Modal.confirm({
103
102
  okText: '确认删除',
104
103
  okType: 'danger',
105
104
  onOk: () => deleteUser(id),
106
- })
105
+ });
107
106
  ```
108
107
 
109
108
  ### Select(选择器)
109
+
110
110
  - 选项少时直接写 `<Select.Option>`;选项多时使用 `options` 数组属性
111
111
  - 远程搜索使用 `showSearch` + `onSearch` + `filterOption` 自定义
112
112
  - 多选用 `mode="multiple"`
113
113
 
114
114
  ### DatePicker(日期选择器)
115
+
115
116
  - 使用 `format` 指定显示格式
116
117
  - 表单中配合 `Form.Item` 使用,值类型为 `dayjs` 对象
117
118
  - 范围选择用 `DatePicker.RangePicker`
118
119
 
119
120
  ### Space(间距)
121
+
120
122
  - 组件间间距优先使用 `<Space>` 包裹,避免手动 `margin`
121
123
  - 默认间距为 `size="small"`(8px),可根据上下文调整
122
124
 
123
125
  ### message / notification(消息提示)
126
+
124
127
  - 操作反馈使用 `message.success()` / `message.error()` 轻量提示
125
128
  - 重要通知使用 `notification.open()` / `notification.info()`
126
129
  - 不要在组件中手动创建 message 实例 — 使用静态方法即可
127
130
 
128
131
  ### Spin(加载中)
132
+
129
133
  - 页面级加载使用 `Spin` 包裹内容区域
130
134
  - 组件级加载使用 Spin 组件的 `spinning` 属性
131
135
  - 全局加载状态使用 `Spin` + Suspense(React.lazy 场景)