@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
@@ -8,34 +8,35 @@ Vue 3 中不直接存在 Pipe 的概念,通过 computed 或工具函数实现
8
8
  <script setup lang="ts">
9
9
  // ✅ 方案1: 纯工具函数(无状态转换)
10
10
  function formatDate(date: string | Date, style: 'short' | 'long' = 'short'): string {
11
- const d = typeof date === 'string' ? new Date(date) : date
11
+ const d = typeof date === 'string' ? new Date(date) : date;
12
12
  if (style === 'short') {
13
- return d.toLocaleDateString('zh-CN')
13
+ return d.toLocaleDateString('zh-CN');
14
14
  }
15
15
  return d.toLocaleDateString('zh-CN', {
16
- year: 'numeric', month: 'long', day: 'numeric',
17
- hour: '2-digit', minute: '2-digit',
18
- })
16
+ year: 'numeric',
17
+ month: 'long',
18
+ day: 'numeric',
19
+ hour: '2-digit',
20
+ minute: '2-digit',
21
+ });
19
22
  }
20
23
 
21
24
  function formatCurrency(amount: number, currency = 'CNY'): string {
22
25
  return new Intl.NumberFormat('zh-CN', {
23
26
  style: 'currency',
24
27
  currency,
25
- }).format(amount)
28
+ }).format(amount);
26
29
  }
27
30
 
28
31
  // ✅ 方案2: computed 属性(有状态转换 — 如搜索/过滤)
29
- const props = defineProps<{ users: User[] }>()
30
- const search = ref('')
32
+ const props = defineProps<{ users: User[] }>();
33
+ const search = ref('');
31
34
 
32
35
  const filteredUsers = computed(() => {
33
- if (!search.value.trim()) return props.users
34
- const q = search.value.toLowerCase()
35
- return props.users.filter(
36
- u => u.username.toLowerCase().includes(q) || u.email.toLowerCase().includes(q)
37
- )
38
- })
36
+ if (!search.value.trim()) return props.users;
37
+ const q = search.value.toLowerCase();
38
+ return props.users.filter((u) => u.username.toLowerCase().includes(q) || u.email.toLowerCase().includes(q));
39
+ });
39
40
  </script>
40
41
 
41
42
  <template>
@@ -76,12 +77,12 @@ const filteredUsers = computed(() => {
76
77
  <!-- components/DataList.vue -->
77
78
  <script setup lang="ts">
78
79
  interface Item {
79
- id: number
80
- name: string
81
- email: string
80
+ id: number;
81
+ name: string;
82
+ email: string;
82
83
  }
83
84
 
84
- defineProps<{ items: Item[] }>()
85
+ defineProps<{ items: Item[] }>();
85
86
  </script>
86
87
 
87
88
  <template>
@@ -110,16 +111,16 @@ defineProps<{ items: Item[] }>()
110
111
 
111
112
  ```vue
112
113
  <script setup lang="ts">
113
- import { shallowRef } from 'vue'
114
- import UserList from '@/views/UserList.vue'
115
- import UserDetail from '@/views/UserDetail.vue'
116
- import Settings from '@/views/Settings.vue'
114
+ import { shallowRef } from 'vue';
115
+ import UserList from '@/views/UserList.vue';
116
+ import UserDetail from '@/views/UserDetail.vue';
117
+ import Settings from '@/views/Settings.vue';
117
118
 
118
- const currentView = shallowRef(UserList)
119
+ const currentView = shallowRef(UserList);
119
120
 
120
121
  function switchView(view: 'list' | 'detail' | 'settings') {
121
- const views = { list: UserList, detail: UserDetail, settings: Settings }
122
- currentView.value = views[view]
122
+ const views = { list: UserList, detail: UserDetail, settings: Settings };
123
+ currentView.value = views[view];
123
124
  }
124
125
  </script>
125
126
 
@@ -150,9 +151,7 @@ function switchView(view: 'list' | 'detail' | 'settings') {
150
151
  </a-button>
151
152
 
152
153
  <Transition name="fade" mode="out-in">
153
- <div v-if="show" key="content">
154
- 内容区域
155
- </div>
154
+ <div v-if="show" key="content">内容区域</div>
156
155
  </Transition>
157
156
  </template>
158
157
 
@@ -172,15 +171,15 @@ function switchView(view: 'list' | 'detail' | 'settings') {
172
171
 
173
172
  ```typescript
174
173
  // components/AsyncWidget.ts
175
- import { defineAsyncComponent } from 'vue'
176
- import { Spin } from 'ant-design-vue'
174
+ import { defineAsyncComponent } from 'vue';
175
+ import { Spin } from 'ant-design-vue';
177
176
 
178
177
  export default defineAsyncComponent({
179
178
  loader: () => import('./HeavyWidget.vue'),
180
179
  loadingComponent: Spin,
181
180
  delay: 200,
182
181
  timeout: 8000,
183
- })
182
+ });
184
183
 
185
184
  // 路由中的异步组件 — 通过动态 import 实现
186
185
  // router/index.ts
@@ -189,34 +188,34 @@ const routes = [
189
188
  path: '/dashboard',
190
189
  component: () => import('@/views/Dashboard.vue'),
191
190
  },
192
- ]
191
+ ];
193
192
  ```
194
193
 
195
194
  ## Provide/Inject 模式
196
195
 
197
196
  ```typescript
198
197
  // injection-keys.ts
199
- import type { InjectionKey, Ref } from 'vue'
198
+ import type { InjectionKey, Ref } from 'vue';
200
199
 
201
200
  export const ThemeKey: InjectionKey<{
202
- theme: Ref<'light' | 'dark'>
203
- toggleTheme: () => void
204
- }> = Symbol('theme')
201
+ theme: Ref<'light' | 'dark'>;
202
+ toggleTheme: () => void;
203
+ }> = Symbol('theme');
205
204
  ```
206
205
 
207
206
  ```vue
208
207
  <!-- 祖先组件:provide -->
209
208
  <script setup lang="ts">
210
- import { provide, ref } from 'vue'
211
- import { ThemeKey } from '@/injection-keys'
209
+ import { provide, ref } from 'vue';
210
+ import { ThemeKey } from '@/injection-keys';
212
211
 
213
- const theme = ref<'light' | 'dark'>('light')
212
+ const theme = ref<'light' | 'dark'>('light');
214
213
 
215
214
  function toggleTheme() {
216
- theme.value = theme.value === 'light' ? 'dark' : 'light'
215
+ theme.value = theme.value === 'light' ? 'dark' : 'light';
217
216
  }
218
217
 
219
- provide(ThemeKey, { theme, toggleTheme })
218
+ provide(ThemeKey, { theme, toggleTheme });
220
219
  </script>
221
220
 
222
221
  <template>
@@ -227,10 +226,10 @@ provide(ThemeKey, { theme, toggleTheme })
227
226
  ```vue
228
227
  <!-- 后代组件:inject -->
229
228
  <script setup lang="ts">
230
- import { inject } from 'vue'
231
- import { ThemeKey } from '@/injection-keys'
229
+ import { inject } from 'vue';
230
+ import { ThemeKey } from '@/injection-keys';
232
231
 
233
- const { theme, toggleTheme } = inject(ThemeKey)!
232
+ const { theme, toggleTheme } = inject(ThemeKey)!;
234
233
  </script>
235
234
 
236
235
  <template>
@@ -246,14 +245,14 @@ const { theme, toggleTheme } = inject(ThemeKey)!
246
245
  ```vue
247
246
  <!-- components/AuthGuard.vue -->
248
247
  <script setup lang="ts">
249
- import { useAuthStore } from '@/stores/auth'
250
- import { useRouter } from 'vue-router'
248
+ import { useAuthStore } from '@/stores/auth';
249
+ import { useRouter } from 'vue-router';
251
250
 
252
- const auth = useAuthStore()
253
- const router = useRouter()
251
+ const auth = useAuthStore();
252
+ const router = useRouter();
254
253
 
255
254
  if (!auth.isAuthenticated) {
256
- router.replace({ name: 'login', query: { redirect: router.currentRoute.value.fullPath } })
255
+ router.replace({ name: 'login', query: { redirect: router.currentRoute.value.fullPath } });
257
256
  }
258
257
  </script>
259
258
 
@@ -5,22 +5,22 @@
5
5
  ```typescript
6
6
  // shared/types/entity.ts
7
7
  export interface ImmutableEntity {
8
- readonly id: string
9
- readonly createdAt: string
10
- readonly updatedAt: string
8
+ readonly id: string;
9
+ readonly createdAt: string;
10
+ readonly updatedAt: string;
11
11
  }
12
12
 
13
13
  export interface Entity extends ImmutableEntity {
14
- version: number
14
+ version: number;
15
15
  }
16
16
 
17
17
  export interface Auditable<T> extends Entity {
18
- createdBy: T
19
- updatedBy: T
18
+ createdBy: T;
19
+ updatedBy: T;
20
20
  }
21
21
 
22
22
  export interface ImmutableAuditable<T> extends ImmutableEntity {
23
- createdBy: T
23
+ createdBy: T;
24
24
  }
25
25
  ```
26
26
 
@@ -29,19 +29,19 @@ export interface ImmutableAuditable<T> extends ImmutableEntity {
29
29
  ```typescript
30
30
  // shared/types/api.ts
31
31
  export interface PageResponse<T> {
32
- content: T[]
33
- totalElements: number
34
- totalPages: number
35
- number: number
36
- size: number
37
- first: boolean
38
- last: boolean
32
+ content: T[];
33
+ totalElements: number;
34
+ totalPages: number;
35
+ number: number;
36
+ size: number;
37
+ first: boolean;
38
+ last: boolean;
39
39
  }
40
40
 
41
41
  export interface ApiError {
42
- code: string
43
- message: string
44
- details?: Record<string, string[]>
42
+ code: string;
43
+ message: string;
44
+ details?: Record<string, string[]>;
45
45
  }
46
46
  ```
47
47
 
@@ -50,12 +50,12 @@ export interface ApiError {
50
50
  ```typescript
51
51
  // shared/types/user.ts
52
52
  export interface User extends Auditable<string> {
53
- username: string
54
- email: string
55
- displayName: string
56
- avatar?: string
57
- role: UserRole
58
- active: boolean
53
+ username: string;
54
+ email: string;
55
+ displayName: string;
56
+ avatar?: string;
57
+ role: UserRole;
58
+ active: boolean;
59
59
  }
60
60
 
61
61
  export enum UserRole {
@@ -65,16 +65,16 @@ export enum UserRole {
65
65
  }
66
66
 
67
67
  export interface CreateUserRequest {
68
- username: string
69
- email: string
70
- displayName: string
71
- role: UserRole
68
+ username: string;
69
+ email: string;
70
+ displayName: string;
71
+ role: UserRole;
72
72
  }
73
73
 
74
74
  export interface UpdateUserRequest {
75
- email?: string
76
- displayName?: string
77
- role?: UserRole
75
+ email?: string;
76
+ displayName?: string;
77
+ role?: UserRole;
78
78
  }
79
79
  ```
80
80
 
@@ -83,25 +83,25 @@ export interface UpdateUserRequest {
83
83
  ```vue
84
84
  <!-- components/UserAvatar.vue -->
85
85
  <script setup lang="ts">
86
- import type { User } from '@/shared/types/user'
86
+ import type { User } from '@/shared/types/user';
87
87
 
88
88
  interface UserAvatarProps {
89
- user: Pick<User, 'username' | 'avatar'>
90
- size?: 'sm' | 'md' | 'lg'
91
- onClick?: () => void
89
+ user: Pick<User, 'username' | 'avatar'>;
90
+ size?: 'sm' | 'md' | 'lg';
91
+ onClick?: () => void;
92
92
  }
93
93
 
94
94
  const props = withDefaults(defineProps<UserAvatarProps>(), {
95
95
  size: 'md',
96
- })
96
+ });
97
97
 
98
98
  const emit = defineEmits<{
99
- click: [user: User]
100
- }>()
99
+ click: [user: User];
100
+ }>();
101
101
 
102
102
  function handleClick() {
103
103
  if (props.onClick) {
104
- props.onClick()
104
+ props.onClick();
105
105
  }
106
106
  }
107
107
  </script>
@@ -120,9 +120,9 @@ function handleClick() {
120
120
  ```vue
121
121
  <!-- views/UserListPage.vue — 页面组件:默认导出 -->
122
122
  <script setup lang="ts">
123
- import { useUsers } from '@/composables/useUsers'
123
+ import { useUsers } from '@/composables/useUsers';
124
124
 
125
- const { users, loading } = useUsers()
125
+ const { users, loading } = useUsers();
126
126
  </script>
127
127
 
128
128
  <template>
@@ -134,12 +134,12 @@ const { users, loading } = useUsers()
134
134
 
135
135
  ```typescript
136
136
  // 用于多状态组件
137
- export type NotificationType = 'success' | 'error' | 'warning' | 'info'
137
+ export type NotificationType = 'success' | 'error' | 'warning' | 'info';
138
138
 
139
139
  export interface NotificationConfig {
140
- type: NotificationType
141
- title: string
142
- message: string
143
- duration?: number
140
+ type: NotificationType;
141
+ title: string;
142
+ message: string;
143
+ duration?: number;
144
144
  }
145
145
  ```
@@ -5,30 +5,30 @@
5
5
  ```vue
6
6
  <!-- components/CreateUserForm.vue -->
7
7
  <script setup lang="ts">
8
- import { reactive, ref } from 'vue'
9
- import { message } from 'ant-design-vue'
10
- import type { UserRole } from '@/shared/types/user'
8
+ import { reactive, ref } from 'vue';
9
+ import { message } from 'ant-design-vue';
10
+ import type { UserRole } from '@/shared/types/user';
11
11
 
12
12
  interface FormState {
13
- username: string
14
- email: string
15
- displayName: string
16
- role: UserRole | undefined
13
+ username: string;
14
+ email: string;
15
+ displayName: string;
16
+ role: UserRole | undefined;
17
17
  }
18
18
 
19
19
  const emit = defineEmits<{
20
- success: [userId: string]
21
- }>()
20
+ success: [userId: string];
21
+ }>();
22
22
 
23
23
  const formState = reactive<FormState>({
24
24
  username: '',
25
25
  email: '',
26
26
  displayName: '',
27
27
  role: undefined,
28
- })
28
+ });
29
29
 
30
- const loading = ref(false)
31
- const formRef = ref()
30
+ const loading = ref(false);
31
+ const formRef = ref();
32
32
 
33
33
  // 校验规则
34
34
  const rules = {
@@ -40,42 +40,38 @@ const rules = {
40
40
  { required: true, message: '请输入邮箱', trigger: 'blur' },
41
41
  { type: 'email', message: '请输入有效的邮箱地址', trigger: 'blur' },
42
42
  ],
43
- displayName: [
44
- { required: true, message: '请输入显示名称', trigger: 'blur' },
45
- ],
46
- role: [
47
- { required: true, message: '请选择角色', trigger: 'change' },
48
- ],
49
- }
43
+ displayName: [{ required: true, message: '请输入显示名称', trigger: 'blur' }],
44
+ role: [{ required: true, message: '请选择角色', trigger: 'change' }],
45
+ };
50
46
 
51
47
  async function handleSubmit() {
52
48
  try {
53
- await formRef.value?.validate()
54
- loading.value = true
49
+ await formRef.value?.validate();
50
+ loading.value = true;
55
51
 
56
52
  const res = await fetch('/api/v1/users', {
57
53
  method: 'POST',
58
54
  headers: { 'Content-Type': 'application/json' },
59
55
  body: JSON.stringify(formState),
60
- })
56
+ });
61
57
 
62
- if (!res.ok) throw new Error('创建失败')
63
- const user = await res.json()
58
+ if (!res.ok) throw new Error('创建失败');
59
+ const user = await res.json();
64
60
 
65
- message.success('用户创建成功')
66
- emit('success', user.id)
67
- formRef.value?.resetFields()
61
+ message.success('用户创建成功');
62
+ emit('success', user.id);
63
+ formRef.value?.resetFields();
68
64
  } catch (e) {
69
65
  if (e instanceof Error) {
70
- message.error(e.message)
66
+ message.error(e.message);
71
67
  }
72
68
  } finally {
73
- loading.value = false
69
+ loading.value = false;
74
70
  }
75
71
  }
76
72
 
77
73
  function handleReset() {
78
- formRef.value?.resetFields()
74
+ formRef.value?.resetFields();
79
75
  }
80
76
  </script>
81
77
 
@@ -112,9 +108,7 @@ function handleReset() {
112
108
  <a-button type="primary" html-type="submit" :loading="loading">
113
109
  {{ loading ? '创建中...' : '创建' }}
114
110
  </a-button>
115
- <a-button style="margin-left: 8px" @click="handleReset">
116
- 重置
117
- </a-button>
111
+ <a-button style="margin-left: 8px" @click="handleReset"> 重置 </a-button>
118
112
  </a-form-item>
119
113
  </a-form>
120
114
  </template>
@@ -125,58 +119,60 @@ function handleReset() {
125
119
  ```vue
126
120
  <!-- components/EditUserModal.vue -->
127
121
  <script setup lang="ts">
128
- import { reactive, ref, watch } from 'vue'
129
- import { message, Modal } from 'ant-design-vue'
130
- import type { User } from '@/shared/types/user'
122
+ import { reactive, ref, watch } from 'vue';
123
+ import { message, Modal } from 'ant-design-vue';
124
+ import type { User } from '@/shared/types/user';
131
125
 
132
126
  interface EditForm {
133
- email: string
134
- displayName: string
135
- active: boolean
127
+ email: string;
128
+ displayName: string;
129
+ active: boolean;
136
130
  }
137
131
 
138
132
  const props = defineProps<{
139
- visible: boolean
140
- user: User | null
141
- }>()
133
+ visible: boolean;
134
+ user: User | null;
135
+ }>();
142
136
 
143
137
  const emit = defineEmits<{
144
- close: []
145
- saved: []
146
- }>()
138
+ close: [];
139
+ saved: [];
140
+ }>();
147
141
 
148
142
  const formState = reactive<EditForm>({
149
143
  email: '',
150
144
  displayName: '',
151
145
  active: true,
152
- })
146
+ });
153
147
 
154
- const formRef = ref()
155
- const loading = ref(false)
148
+ const formRef = ref();
149
+ const loading = ref(false);
156
150
 
157
151
  // 监听 user 变化填充表单
158
- watch(() => props.user, (user) => {
159
- if (user) {
160
- formState.email = user.email
161
- formState.displayName = user.displayName
162
- formState.active = user.active
163
- }
164
- }, { immediate: true })
152
+ watch(
153
+ () => props.user,
154
+ (user) => {
155
+ if (user) {
156
+ formState.email = user.email;
157
+ formState.displayName = user.displayName;
158
+ formState.active = user.active;
159
+ }
160
+ },
161
+ { immediate: true },
162
+ );
165
163
 
166
164
  const rules = {
167
165
  email: [
168
166
  { required: true, message: '请输入邮箱', trigger: 'blur' },
169
167
  { type: 'email', message: '请输入有效的邮箱地址', trigger: 'blur' },
170
168
  ],
171
- displayName: [
172
- { required: true, message: '请输入显示名称', trigger: 'blur' },
173
- ],
174
- }
169
+ displayName: [{ required: true, message: '请输入显示名称', trigger: 'blur' }],
170
+ };
175
171
 
176
172
  async function handleOk() {
177
173
  try {
178
- await formRef.value?.validate()
179
- loading.value = true
174
+ await formRef.value?.validate();
175
+ loading.value = true;
180
176
 
181
177
  const res = await fetch(`/api/v1/users/${props.user!.id}`, {
182
178
  method: 'PUT',
@@ -185,22 +181,22 @@ async function handleOk() {
185
181
  email: formState.email,
186
182
  displayName: formState.displayName,
187
183
  }),
188
- })
184
+ });
189
185
 
190
- if (!res.ok) throw new Error('更新失败')
191
- message.success('更新成功')
192
- emit('saved')
186
+ if (!res.ok) throw new Error('更新失败');
187
+ message.success('更新成功');
188
+ emit('saved');
193
189
  } catch (e) {
194
190
  if (e instanceof Error) {
195
- message.error(e.message)
191
+ message.error(e.message);
196
192
  }
197
193
  } finally {
198
- loading.value = false
194
+ loading.value = false;
199
195
  }
200
196
  }
201
197
 
202
198
  function handleCancel() {
203
- emit('close')
199
+ emit('close');
204
200
  }
205
201
  </script>
206
202