@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.
- package/README.md +8 -8
- package/dist/build-registry.js +11 -5
- package/dist/cli.js +839 -585
- package/dist/mcp/code-hosting/github.json +14 -1
- package/dist/mcp/docs-reference/context7.json +1 -10
- package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-read/SKILL.md +8 -5
- package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-write/SKILL.md +10 -8
- package/dist/mcp-skills/deepstorm-mcp-figma-read/SKILL.md +21 -20
- package/dist/mcp-skills/deepstorm-mcp-github-read/SKILL.md +17 -17
- package/dist/mcp-skills/deepstorm-mcp-github-write/SKILL.md +20 -20
- package/dist/mcp-skills/deepstorm-mcp-jira-read/SKILL.md +8 -8
- package/dist/mcp-skills/deepstorm-mcp-jira-write/SKILL.md +13 -12
- package/dist/mcp-skills/deepstorm-mcp-playwright-read/SKILL.md +10 -10
- package/dist/skills/atoll-ops/SKILL.md +4 -0
- package/dist/skills/reef-commit/SKILL.md +9 -5
- package/dist/skills/reef-commit/scripts/branch-check.mjs +5 -11
- package/dist/skills/reef-commit/scripts/check-openspec-status.mjs +6 -12
- package/dist/skills/reef-commit/scripts/collect-git-context.mjs +13 -11
- package/dist/skills/reef-gen-backend/variants/java/steps.md +7 -7
- package/dist/skills/reef-gen-backend/variants/nodejs/steps.md +7 -7
- package/dist/skills/reef-gen-backend/variants/python/steps.md +7 -7
- package/dist/skills/reef-gen-frontend/variants/angular/steps.md +5 -5
- package/dist/skills/reef-gen-frontend/variants/react/steps.md +6 -6
- package/dist/skills/reef-gen-frontend/variants/vue/steps.md +6 -6
- package/dist/skills/reef-harden/EXAMPLES.md +12 -10
- package/dist/skills/reef-harden/SKILL.md +6 -0
- package/dist/skills/reef-harden/scripts/find-change-dir.mjs +13 -13
- package/dist/skills/reef-pr/SKILL.md +7 -0
- package/dist/skills/reef-pr/scripts/create-pr.mjs +31 -29
- package/dist/skills/reef-scope/SKILL.md +6 -6
- package/dist/skills/reef-start/references/jira-start-subagent.md +7 -7
- package/dist/skills/reef-start/references/risk-routing-card.md +28 -25
- package/dist/skills/reef-start/references/stage-4-implementation.md +33 -21
- package/dist/skills/reef-start/references/superpowers-gate.md +9 -9
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/structured-output.md +2 -2
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/quick-reference.md +11 -0
- package/dist/skills/reef-style-backend/fragments/java/api-spec/jackson-polymorphism.md +36 -40
- package/dist/skills/reef-style-backend/fragments/java/api-spec/quick-reference.md +11 -10
- package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/examples/database-migration.md +7 -7
- package/dist/skills/reef-style-backend/fragments/java/dependency-management/quick-reference.md +24 -21
- package/dist/skills/reef-style-backend/fragments/java/exception-handling/examples/error-code-enum.md +7 -7
- package/dist/skills/reef-style-backend/fragments/java/exception-handling/quick-reference.md +10 -8
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/dto-mapper.md +2 -2
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/service-entity.md +5 -5
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/testing.md +1 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/quick-reference.md +12 -12
- package/dist/skills/reef-style-backend/fragments/java/orm/hibernate/quick-reference.md +13 -12
- package/dist/skills/reef-style-backend/fragments/java/security-redlines/quick-reference.md +11 -9
- package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/quick-reference.md +7 -7
- package/dist/skills/reef-style-backend/fragments/java/test/junit5/quick-reference.md +6 -6
- package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/quick-reference.md +8 -8
- package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/quick-reference.md +8 -7
- package/dist/skills/reef-style-backend/fragments/nodejs/eslint-config.json +1 -4
- package/dist/skills/reef-style-backend/fragments/nodejs/nestjs-structure.md +9 -9
- package/dist/skills/reef-style-backend/fragments/python/alembic-migration/quick-reference.md +2 -1
- package/dist/skills/reef-style-backend/fragments/python/api-spec/quick-reference.md +10 -10
- package/dist/skills/reef-style-backend/fragments/python/dependency-management/quick-reference.md +24 -22
- package/dist/skills/reef-style-backend/fragments/python/exception-handling/quick-reference.md +10 -9
- package/dist/skills/reef-style-backend/fragments/python/fastapi-quick-reference/quick-reference.md +3 -0
- package/dist/skills/reef-style-backend/fragments/python/langchain/quick-reference.md +10 -7
- package/dist/skills/reef-style-backend/fragments/python/pytest-testing/quick-reference.md +2 -0
- package/dist/skills/reef-style-backend/fragments/python/ruff-mypy-toolchain/quick-reference.md +2 -0
- package/dist/skills/reef-style-backend/fragments/python/security-redlines/quick-reference.md +11 -9
- package/dist/skills/reef-style-backend/fragments/python/sqlalchemy-orm/quick-reference.md +3 -0
- package/dist/skills/reef-style-backend/variants/java/examples/code-wrapping.md +3 -4
- package/dist/skills/reef-style-backend/variants/java/quick-reference.md +31 -29
- package/dist/skills/reef-style-backend/variants/nodejs/examples/module-example.md +2 -8
- package/dist/skills/reef-style-backend/variants/nodejs/quick-reference.md +35 -36
- package/dist/skills/reef-style-backend/variants/python/quick-reference.md +32 -31
- package/dist/skills/reef-style-frontend/fragments/css/tailwind/quick-reference.md +9 -7
- package/dist/skills/reef-style-frontend/fragments/test/vitest/examples/testing.md +9 -4
- package/dist/skills/reef-style-frontend/fragments/test/vitest/quick-reference.md +4 -4
- package/dist/skills/reef-style-frontend/fragments/test/vitest-react/examples/testing.md +135 -140
- package/dist/skills/reef-style-frontend/fragments/test/vitest-react/quick-reference.md +32 -32
- package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/examples/testing.md +161 -162
- package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/quick-reference.md +42 -42
- package/dist/skills/reef-style-frontend/fragments/ts-config/strict/quick-reference.md +16 -10
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/examples/ui-components.md +72 -87
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/quick-reference.md +14 -10
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/examples/ui-components.md +93 -111
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/quick-reference.md +29 -33
- package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/examples/ui-components.md +14 -23
- package/dist/skills/reef-style-frontend/variants/angular/examples/code-wrapping.md +15 -17
- package/dist/skills/reef-style-frontend/variants/angular/examples/component-types-pipes.md +22 -5
- package/dist/skills/reef-style-frontend/variants/angular/examples/entity-types.md +52 -22
- package/dist/skills/reef-style-frontend/variants/angular/examples/forms-layer.md +17 -20
- package/dist/skills/reef-style-frontend/variants/angular/examples/service-routing.md +8 -11
- package/dist/skills/reef-style-frontend/variants/angular/quick-reference.md +27 -27
- package/dist/skills/reef-style-frontend/variants/react/examples/code-wrapping.md +14 -27
- package/dist/skills/reef-style-frontend/variants/react/examples/component-types-pipes.md +45 -52
- package/dist/skills/reef-style-frontend/variants/react/examples/entity-types.md +44 -44
- package/dist/skills/reef-style-frontend/variants/react/examples/forms-layer.md +56 -85
- package/dist/skills/reef-style-frontend/variants/react/examples/service-routing.md +114 -88
- package/dist/skills/reef-style-frontend/variants/react/quick-reference.md +48 -42
- package/dist/skills/reef-style-frontend/variants/vue/examples/code-wrapping.md +24 -43
- package/dist/skills/reef-style-frontend/variants/vue/examples/component-types-pipes.md +48 -49
- package/dist/skills/reef-style-frontend/variants/vue/examples/entity-types.md +45 -45
- package/dist/skills/reef-style-frontend/variants/vue/examples/forms-layer.md +64 -68
- package/dist/skills/reef-style-frontend/variants/vue/examples/service-routing.md +85 -84
- package/dist/skills/reef-style-frontend/variants/vue/quick-reference.md +46 -51
- package/dist/skills/reef-testcase/SKILL.md +19 -19
- package/dist/skills/reef-testcase/references/coverage-dimensions.md +8 -0
- package/dist/skills/reef-testcase/references/test-case-template.md +16 -16
- package/dist/skills/sweep-explore/SKILL.md +129 -100
- package/dist/skills/sweep-explore/references/explore-flow-template.md +9 -9
- package/dist/skills/sweep-init/SKILL.md +4 -0
- package/dist/skills/sweep-init/scripts/flow-selector.mjs +6 -11
- package/dist/skills/sweep-init/scripts/init-project.mjs +68 -51
- package/dist/skills/sweep-plan/references/test-flow-template.md +12 -6
- package/dist/skills/sweep-record/SKILL.md +38 -15
- package/dist/skills/sweep-run/SKILL.md +59 -50
- package/dist/skills/sweep-run/scripts/env-manager.mjs +4 -5
- package/dist/skills/sweep-run/scripts/flow-parser.mjs +7 -6
- package/dist/skills/sweep-run/scripts/flow-selector.mjs +4 -15
- package/dist/skills/sweep-run/scripts/generate-report.mjs +1 -2
- package/dist/skills/sweep-run/scripts/mcp-manager.mjs +107 -14
- package/dist/skills/sweep-run/scripts/spec-compiler.mjs +19 -9
- package/dist/skills/tide-discuss/references/checklists.md +32 -32
- package/dist/skills/tide-discuss/references/data-format.md +85 -77
- package/dist/skills/tide-discuss/references/prd-template.md +21 -19
- package/dist/skills/tide-discuss/references/publish-flow.md +30 -11
- package/dist/skills/tide-discuss/references/role-prompts.md +5 -5
- package/package.json +4 -3
|
@@ -5,37 +5,37 @@
|
|
|
5
5
|
```vue
|
|
6
6
|
<!-- components/UserTable.vue -->
|
|
7
7
|
<script setup lang="ts">
|
|
8
|
-
import { ref, reactive, watch } from 'vue'
|
|
9
|
-
import { message } from 'ant-design-vue'
|
|
10
|
-
import type { User } from '@/shared/types/user'
|
|
8
|
+
import { ref, reactive, watch } from 'vue';
|
|
9
|
+
import { message } from 'ant-design-vue';
|
|
10
|
+
import type { User } from '@/shared/types/user';
|
|
11
11
|
|
|
12
12
|
interface Filters {
|
|
13
|
-
search: string
|
|
14
|
-
role: string | undefined
|
|
13
|
+
search: string;
|
|
14
|
+
role: string | undefined;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const props = defineProps<{
|
|
18
|
-
users: User[]
|
|
19
|
-
total: number
|
|
20
|
-
loading: boolean
|
|
21
|
-
}>()
|
|
18
|
+
users: User[];
|
|
19
|
+
total: number;
|
|
20
|
+
loading: boolean;
|
|
21
|
+
}>();
|
|
22
22
|
|
|
23
23
|
const emit = defineEmits<{
|
|
24
|
-
search: [filters: Filters]
|
|
25
|
-
pageChange: [page: number, pageSize: number]
|
|
26
|
-
edit: [user: User]
|
|
27
|
-
delete: [userId: string]
|
|
28
|
-
}>()
|
|
24
|
+
search: [filters: Filters];
|
|
25
|
+
pageChange: [page: number, pageSize: number];
|
|
26
|
+
edit: [user: User];
|
|
27
|
+
delete: [userId: string];
|
|
28
|
+
}>();
|
|
29
29
|
|
|
30
30
|
const filters = reactive<Filters>({
|
|
31
31
|
search: '',
|
|
32
32
|
role: undefined,
|
|
33
|
-
})
|
|
33
|
+
});
|
|
34
34
|
|
|
35
35
|
const pagination = reactive({
|
|
36
36
|
current: 1,
|
|
37
37
|
pageSize: 20,
|
|
38
|
-
})
|
|
38
|
+
});
|
|
39
39
|
|
|
40
40
|
// 列定义
|
|
41
41
|
const columns = [
|
|
@@ -56,43 +56,43 @@ const columns = [
|
|
|
56
56
|
</span>
|
|
57
57
|
),
|
|
58
58
|
},
|
|
59
|
-
]
|
|
59
|
+
];
|
|
60
60
|
|
|
61
61
|
// 搜索
|
|
62
|
-
let searchTimer: ReturnType<typeof setTimeout
|
|
62
|
+
let searchTimer: ReturnType<typeof setTimeout>;
|
|
63
63
|
function handleSearch(value: string) {
|
|
64
|
-
clearTimeout(searchTimer)
|
|
64
|
+
clearTimeout(searchTimer);
|
|
65
65
|
searchTimer = setTimeout(() => {
|
|
66
|
-
filters.search = value
|
|
67
|
-
pagination.current = 1
|
|
68
|
-
emit('search', { ...filters })
|
|
69
|
-
}, 300)
|
|
66
|
+
filters.search = value;
|
|
67
|
+
pagination.current = 1;
|
|
68
|
+
emit('search', { ...filters });
|
|
69
|
+
}, 300);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
// 分页变化
|
|
73
73
|
function handleTableChange(pag: { current: number; pageSize: number }) {
|
|
74
|
-
pagination.current = pag.current
|
|
75
|
-
pagination.pageSize = pag.pageSize
|
|
76
|
-
emit('pageChange', pag.current, pag.pageSize)
|
|
74
|
+
pagination.current = pag.current;
|
|
75
|
+
pagination.pageSize = pag.pageSize;
|
|
76
|
+
emit('pageChange', pag.current, pag.pageSize);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// 批量删除
|
|
80
|
-
const selectedRowKeys = ref<string[]>([])
|
|
80
|
+
const selectedRowKeys = ref<string[]>([]);
|
|
81
81
|
|
|
82
82
|
function handleBatchDelete() {
|
|
83
83
|
if (selectedRowKeys.value.length === 0) {
|
|
84
|
-
message.warning('请先选择要删除的用户')
|
|
85
|
-
return
|
|
84
|
+
message.warning('请先选择要删除的用户');
|
|
85
|
+
return;
|
|
86
86
|
}
|
|
87
87
|
Modal.confirm({
|
|
88
88
|
title: '批量删除',
|
|
89
89
|
content: `确定要删除选中的 ${selectedRowKeys.value.length} 名用户吗?`,
|
|
90
90
|
onOk: async () => {
|
|
91
91
|
// 批量删除逻辑
|
|
92
|
-
message.success(`已删除 ${selectedRowKeys.value.length} 名用户`)
|
|
93
|
-
selectedRowKeys.value = []
|
|
92
|
+
message.success(`已删除 ${selectedRowKeys.value.length} 名用户`);
|
|
93
|
+
selectedRowKeys.value = [];
|
|
94
94
|
},
|
|
95
|
-
})
|
|
95
|
+
});
|
|
96
96
|
}
|
|
97
97
|
</script>
|
|
98
98
|
|
|
@@ -100,19 +100,9 @@ function handleBatchDelete() {
|
|
|
100
100
|
<div class="space-y-4">
|
|
101
101
|
<!-- 搜索栏 -->
|
|
102
102
|
<div class="flex justify-between items-center">
|
|
103
|
-
<a-input-search
|
|
104
|
-
placeholder="搜索用户名/邮箱"
|
|
105
|
-
style="width: 300px"
|
|
106
|
-
@search="handleSearch"
|
|
107
|
-
/>
|
|
103
|
+
<a-input-search placeholder="搜索用户名/邮箱" style="width: 300px" @search="handleSearch" />
|
|
108
104
|
<div class="flex gap-2">
|
|
109
|
-
<a-button
|
|
110
|
-
danger
|
|
111
|
-
:disabled="selectedRowKeys.length === 0"
|
|
112
|
-
@click="handleBatchDelete"
|
|
113
|
-
>
|
|
114
|
-
批量删除
|
|
115
|
-
</a-button>
|
|
105
|
+
<a-button danger :disabled="selectedRowKeys.length === 0" @click="handleBatchDelete"> 批量删除 </a-button>
|
|
116
106
|
<a-button type="primary">新增用户</a-button>
|
|
117
107
|
</div>
|
|
118
108
|
</div>
|
|
@@ -130,7 +120,9 @@ function handleBatchDelete() {
|
|
|
130
120
|
}"
|
|
131
121
|
:row-selection="{
|
|
132
122
|
selectedRowKeys,
|
|
133
|
-
onChange: (keys: string[]) => {
|
|
123
|
+
onChange: (keys: string[]) => {
|
|
124
|
+
selectedRowKeys = keys;
|
|
125
|
+
},
|
|
134
126
|
}"
|
|
135
127
|
row-key="id"
|
|
136
128
|
:locale="{ emptyText: '暂无用户数据' }"
|
|
@@ -145,31 +137,31 @@ function handleBatchDelete() {
|
|
|
145
137
|
```vue
|
|
146
138
|
<!-- components/UserFormModal.vue -->
|
|
147
139
|
<script setup lang="ts">
|
|
148
|
-
import { reactive, ref, watch } from 'vue'
|
|
149
|
-
import { message, Modal } from 'ant-design-vue'
|
|
150
|
-
import type { User } from '@/shared/types/user'
|
|
140
|
+
import { reactive, ref, watch } from 'vue';
|
|
141
|
+
import { message, Modal } from 'ant-design-vue';
|
|
142
|
+
import type { User } from '@/shared/types/user';
|
|
151
143
|
|
|
152
144
|
interface FormData {
|
|
153
|
-
username: string
|
|
154
|
-
email: string
|
|
155
|
-
displayName: string
|
|
156
|
-
role: string
|
|
157
|
-
active: boolean
|
|
145
|
+
username: string;
|
|
146
|
+
email: string;
|
|
147
|
+
displayName: string;
|
|
148
|
+
role: string;
|
|
149
|
+
active: boolean;
|
|
158
150
|
}
|
|
159
151
|
|
|
160
152
|
const props = defineProps<{
|
|
161
|
-
visible: boolean
|
|
162
|
-
user: User | null
|
|
163
|
-
}>()
|
|
153
|
+
visible: boolean;
|
|
154
|
+
user: User | null; // null 表示创建模式
|
|
155
|
+
}>();
|
|
164
156
|
|
|
165
157
|
const emit = defineEmits<{
|
|
166
|
-
close: []
|
|
167
|
-
saved: []
|
|
168
|
-
}>()
|
|
158
|
+
close: [];
|
|
159
|
+
saved: [];
|
|
160
|
+
}>();
|
|
169
161
|
|
|
170
|
-
const formRef = ref()
|
|
171
|
-
const loading = ref(false)
|
|
172
|
-
const isEdit = ref(false)
|
|
162
|
+
const formRef = ref();
|
|
163
|
+
const loading = ref(false);
|
|
164
|
+
const isEdit = ref(false);
|
|
173
165
|
|
|
174
166
|
const formData = reactive<FormData>({
|
|
175
167
|
username: '',
|
|
@@ -177,25 +169,29 @@ const formData = reactive<FormData>({
|
|
|
177
169
|
displayName: '',
|
|
178
170
|
role: 'EDITOR',
|
|
179
171
|
active: true,
|
|
180
|
-
})
|
|
172
|
+
});
|
|
181
173
|
|
|
182
174
|
// 编辑模式填充数据
|
|
183
|
-
watch(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
175
|
+
watch(
|
|
176
|
+
() => props.user,
|
|
177
|
+
(user) => {
|
|
178
|
+
isEdit.value = !!user;
|
|
179
|
+
if (user) {
|
|
180
|
+
formData.username = user.username;
|
|
181
|
+
formData.email = user.email;
|
|
182
|
+
formData.displayName = user.displayName;
|
|
183
|
+
formData.role = user.role;
|
|
184
|
+
formData.active = user.active;
|
|
185
|
+
} else {
|
|
186
|
+
formData.username = '';
|
|
187
|
+
formData.email = '';
|
|
188
|
+
formData.displayName = '';
|
|
189
|
+
formData.role = 'EDITOR';
|
|
190
|
+
formData.active = true;
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
{ immediate: true },
|
|
194
|
+
);
|
|
199
195
|
|
|
200
196
|
const rules = {
|
|
201
197
|
username: [
|
|
@@ -206,43 +202,39 @@ const rules = {
|
|
|
206
202
|
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
|
207
203
|
{ type: 'email', message: '请输理有效的邮箱地址', trigger: 'blur' },
|
|
208
204
|
],
|
|
209
|
-
displayName: [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
role: [
|
|
213
|
-
{ required: true, message: '请选择角色', trigger: 'change' },
|
|
214
|
-
],
|
|
215
|
-
}
|
|
205
|
+
displayName: [{ required: true, message: '请输入显示名称', trigger: 'blur' }],
|
|
206
|
+
role: [{ required: true, message: '请选择角色', trigger: 'change' }],
|
|
207
|
+
};
|
|
216
208
|
|
|
217
209
|
async function handleOk() {
|
|
218
210
|
try {
|
|
219
|
-
await formRef.value?.validate()
|
|
220
|
-
loading.value = true
|
|
211
|
+
await formRef.value?.validate();
|
|
212
|
+
loading.value = true;
|
|
221
213
|
|
|
222
|
-
const url = isEdit.value ? `/api/v1/users/${props.user!.id}` : '/api/v1/users'
|
|
223
|
-
const method = isEdit.value ? 'PUT' : 'POST'
|
|
214
|
+
const url = isEdit.value ? `/api/v1/users/${props.user!.id}` : '/api/v1/users';
|
|
215
|
+
const method = isEdit.value ? 'PUT' : 'POST';
|
|
224
216
|
|
|
225
217
|
const res = await fetch(url, {
|
|
226
218
|
method,
|
|
227
219
|
headers: { 'Content-Type': 'application/json' },
|
|
228
220
|
body: JSON.stringify(formData),
|
|
229
|
-
})
|
|
221
|
+
});
|
|
230
222
|
|
|
231
|
-
if (!res.ok) throw new Error(isEdit.value ? '更新失败' : '创建失败')
|
|
223
|
+
if (!res.ok) throw new Error(isEdit.value ? '更新失败' : '创建失败');
|
|
232
224
|
|
|
233
|
-
message.success(isEdit.value ? '更新成功' : '创建成功')
|
|
234
|
-
emit('saved')
|
|
225
|
+
message.success(isEdit.value ? '更新成功' : '创建成功');
|
|
226
|
+
emit('saved');
|
|
235
227
|
} catch (e) {
|
|
236
228
|
if (e instanceof Error) {
|
|
237
|
-
message.error(e.message)
|
|
229
|
+
message.error(e.message);
|
|
238
230
|
}
|
|
239
231
|
} finally {
|
|
240
|
-
loading.value = false
|
|
232
|
+
loading.value = false;
|
|
241
233
|
}
|
|
242
234
|
}
|
|
243
235
|
|
|
244
236
|
function handleCancel() {
|
|
245
|
-
emit('close')
|
|
237
|
+
emit('close');
|
|
246
238
|
}
|
|
247
239
|
</script>
|
|
248
240
|
|
|
@@ -255,19 +247,9 @@ function handleCancel() {
|
|
|
255
247
|
@ok="handleOk"
|
|
256
248
|
@cancel="handleCancel"
|
|
257
249
|
>
|
|
258
|
-
<a-form
|
|
259
|
-
ref="formRef"
|
|
260
|
-
:model="formData"
|
|
261
|
-
:rules="rules"
|
|
262
|
-
:label-col="{ span: 6 }"
|
|
263
|
-
:wrapper-col="{ span: 16 }"
|
|
264
|
-
>
|
|
250
|
+
<a-form ref="formRef" :model="formData" :rules="rules" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
|
|
265
251
|
<a-form-item label="用户名" name="username">
|
|
266
|
-
<a-input
|
|
267
|
-
v-model:value="formData.username"
|
|
268
|
-
:disabled="isEdit"
|
|
269
|
-
placeholder="请输入用户名"
|
|
270
|
-
/>
|
|
252
|
+
<a-input v-model:value="formData.username" :disabled="isEdit" placeholder="请输入用户名" />
|
|
271
253
|
</a-form-item>
|
|
272
254
|
|
|
273
255
|
<a-form-item label="邮箱" name="email">
|
|
@@ -299,14 +281,14 @@ function handleCancel() {
|
|
|
299
281
|
```vue
|
|
300
282
|
<!-- views/Dashboard.vue -->
|
|
301
283
|
<script setup lang="ts">
|
|
302
|
-
import { ref, onMounted } from 'vue'
|
|
284
|
+
import { ref, onMounted } from 'vue';
|
|
303
285
|
|
|
304
286
|
const stats = ref([
|
|
305
287
|
{ title: '用户总数', value: 1284, icon: 'users' },
|
|
306
288
|
{ title: '今日活跃', value: 356, icon: 'activity' },
|
|
307
289
|
{ title: '待处理工单', value: 23, icon: 'clock' },
|
|
308
290
|
{ title: '系统消息', value: 7, icon: 'message' },
|
|
309
|
-
])
|
|
291
|
+
]);
|
|
310
292
|
</script>
|
|
311
293
|
|
|
312
294
|
<template>
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
14
|
// vite.config.ts
|
|
15
|
-
import Components from 'unplugin-vue-components/vite'
|
|
16
|
-
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
|
|
15
|
+
import Components from 'unplugin-vue-components/vite';
|
|
16
|
+
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
|
|
17
17
|
|
|
18
18
|
export default {
|
|
19
19
|
plugins: [
|
|
@@ -21,12 +21,13 @@ export default {
|
|
|
21
21
|
resolvers: [AntDesignVueResolver()],
|
|
22
22
|
}),
|
|
23
23
|
],
|
|
24
|
-
}
|
|
24
|
+
};
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
## 常用组件规范
|
|
28
28
|
|
|
29
29
|
### Button(按钮)
|
|
30
|
+
|
|
30
31
|
- 主要操作使用 `type="primary"`,次要操作默认
|
|
31
32
|
- 危险操作使用 `danger` 属性
|
|
32
33
|
- 异步操作必须设置 `:loading` 状态防重复提交
|
|
@@ -43,6 +44,7 @@ export default {
|
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
### Table(表格)
|
|
47
|
+
|
|
46
48
|
- 始终指定 `row-key` 为唯一标识字段(如 `id`)
|
|
47
49
|
- 列表格使用 `:pagination` 属性控制分页
|
|
48
50
|
- 空数据使用 `:locale` 自定义空状态提示:`{ emptyText: '暂无数据' }`
|
|
@@ -70,6 +72,7 @@ export default {
|
|
|
70
72
|
```
|
|
71
73
|
|
|
72
74
|
### Form(表单)
|
|
75
|
+
|
|
73
76
|
- 使用 `layout="vertical"` 默认垂直布局
|
|
74
77
|
- 所有校验规则集中在 `:rules` 中定义,避免使用自定义 validator(除非复杂业务)
|
|
75
78
|
- `<a-form-item>` 的 `name` 必须与提交数据结构的字段名一致
|
|
@@ -79,27 +82,25 @@ export default {
|
|
|
79
82
|
|
|
80
83
|
```vue
|
|
81
84
|
<script setup lang="ts">
|
|
82
|
-
import { reactive, ref } from 'vue'
|
|
85
|
+
import { reactive, ref } from 'vue';
|
|
83
86
|
|
|
84
87
|
const formState = reactive({
|
|
85
88
|
email: '',
|
|
86
89
|
name: '',
|
|
87
|
-
})
|
|
88
|
-
const formRef = ref()
|
|
90
|
+
});
|
|
91
|
+
const formRef = ref();
|
|
89
92
|
|
|
90
93
|
const rules = {
|
|
91
94
|
email: [
|
|
92
95
|
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
|
93
96
|
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' },
|
|
94
97
|
],
|
|
95
|
-
name: [
|
|
96
|
-
|
|
97
|
-
],
|
|
98
|
-
}
|
|
98
|
+
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
|
99
|
+
};
|
|
99
100
|
|
|
100
101
|
async function handleSubmit() {
|
|
101
102
|
try {
|
|
102
|
-
await formRef.value?.validate()
|
|
103
|
+
await formRef.value?.validate();
|
|
103
104
|
// 提交逻辑
|
|
104
105
|
} catch (e) {
|
|
105
106
|
// 校验失败
|
|
@@ -108,13 +109,7 @@ async function handleSubmit() {
|
|
|
108
109
|
</script>
|
|
109
110
|
|
|
110
111
|
<template>
|
|
111
|
-
<a-form
|
|
112
|
-
ref="formRef"
|
|
113
|
-
:model="formState"
|
|
114
|
-
:rules="rules"
|
|
115
|
-
layout="vertical"
|
|
116
|
-
@finish="handleSubmit"
|
|
117
|
-
>
|
|
112
|
+
<a-form ref="formRef" :model="formState" :rules="rules" layout="vertical" @finish="handleSubmit">
|
|
118
113
|
<a-form-item name="email" label="邮箱">
|
|
119
114
|
<a-input v-model:value="formState.email" placeholder="请输入邮箱" />
|
|
120
115
|
</a-form-item>
|
|
@@ -123,6 +118,7 @@ async function handleSubmit() {
|
|
|
123
118
|
```
|
|
124
119
|
|
|
125
120
|
### Modal(弹窗)
|
|
121
|
+
|
|
126
122
|
- 表单弹窗用 `destroy-on-close` 确保关闭后重置状态
|
|
127
123
|
- `@cancel` 用于关闭回调
|
|
128
124
|
- 确认弹窗用 `Modal.confirm()` 快捷方法
|
|
@@ -141,7 +137,7 @@ async function handleSubmit() {
|
|
|
141
137
|
|
|
142
138
|
<!-- 程序化确认弹窗 -->
|
|
143
139
|
<script setup lang="ts">
|
|
144
|
-
import { Modal } from 'ant-design-vue'
|
|
140
|
+
import { Modal } from 'ant-design-vue';
|
|
145
141
|
|
|
146
142
|
Modal.confirm({
|
|
147
143
|
title: '确认删除',
|
|
@@ -149,11 +145,12 @@ Modal.confirm({
|
|
|
149
145
|
okText: '确认删除',
|
|
150
146
|
okType: 'danger',
|
|
151
147
|
onOk: () => deleteUser(id),
|
|
152
|
-
})
|
|
148
|
+
});
|
|
153
149
|
</script>
|
|
154
150
|
```
|
|
155
151
|
|
|
156
152
|
### Select(选择器)
|
|
153
|
+
|
|
157
154
|
- 选项少时直接写 `<a-select-option>`;选项多时使用 `:options` 数组属性
|
|
158
155
|
- 远程搜索使用 `show-search` + `@search` + `:filter-option` 自定义
|
|
159
156
|
- 多选用 `mode="multiple"`
|
|
@@ -166,12 +163,7 @@ Modal.confirm({
|
|
|
166
163
|
</a-select>
|
|
167
164
|
|
|
168
165
|
<!-- 远程搜索 -->
|
|
169
|
-
<a-select
|
|
170
|
-
v-model:value="selectedUser"
|
|
171
|
-
show-search
|
|
172
|
-
:filter-option="false"
|
|
173
|
-
@search="handleSearch"
|
|
174
|
-
>
|
|
166
|
+
<a-select v-model:value="selectedUser" show-search :filter-option="false" @search="handleSearch">
|
|
175
167
|
<a-select-option v-for="u in users" :key="u.id" :value="u.id">
|
|
176
168
|
{{ u.username }}
|
|
177
169
|
</a-select-option>
|
|
@@ -179,6 +171,7 @@ Modal.confirm({
|
|
|
179
171
|
```
|
|
180
172
|
|
|
181
173
|
### DatePicker(日期选择器)
|
|
174
|
+
|
|
182
175
|
- 使用 `format` 指定显示格式
|
|
183
176
|
- 表单中配合 `<a-form-item>` 使用,值类型为 `dayjs` 对象
|
|
184
177
|
- 使用 `v-model:value` 双向绑定
|
|
@@ -190,29 +183,32 @@ Modal.confirm({
|
|
|
190
183
|
```
|
|
191
184
|
|
|
192
185
|
### Space(间距)
|
|
186
|
+
|
|
193
187
|
- 组件间间距优先使用 `<a-space>` 包裹,避免手动 `margin`
|
|
194
188
|
- 默认间距为 `size="small"`(8px),可根据上下文调整
|
|
195
189
|
|
|
196
190
|
### message / notification(消息提示)
|
|
191
|
+
|
|
197
192
|
- 需从 `ant-design-vue` 包手动导入
|
|
198
193
|
- 操作反馈使用 `message.success()` / `message.error()` 轻量提示
|
|
199
194
|
- 重要通知使用 `notification.open()` / `notification.info()`
|
|
200
195
|
|
|
201
196
|
```vue
|
|
202
197
|
<script setup lang="ts">
|
|
203
|
-
import { message } from 'ant-design-vue'
|
|
198
|
+
import { message } from 'ant-design-vue';
|
|
204
199
|
|
|
205
200
|
function handleSuccess() {
|
|
206
|
-
message.success('操作成功')
|
|
201
|
+
message.success('操作成功');
|
|
207
202
|
}
|
|
208
203
|
|
|
209
204
|
function handleError() {
|
|
210
|
-
message.error('操作失败')
|
|
205
|
+
message.error('操作失败');
|
|
211
206
|
}
|
|
212
207
|
</script>
|
|
213
208
|
```
|
|
214
209
|
|
|
215
210
|
### Spin(加载中)
|
|
211
|
+
|
|
216
212
|
- 页面级加载使用 `<a-spin>` 包裹内容区域
|
|
217
213
|
- 组件级加载使用 Spin 组件的 `:spinning` 属性
|
|
218
214
|
|
|
@@ -246,11 +242,11 @@ function handleError() {
|
|
|
246
242
|
</template>
|
|
247
243
|
|
|
248
244
|
<script setup lang="ts">
|
|
249
|
-
import zhCN from 'ant-design-vue/es/locale/zh_CN'
|
|
250
|
-
import dayjs from 'dayjs'
|
|
251
|
-
import 'dayjs/locale/zh-cn'
|
|
245
|
+
import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
|
246
|
+
import dayjs from 'dayjs';
|
|
247
|
+
import 'dayjs/locale/zh-cn';
|
|
252
248
|
|
|
253
|
-
dayjs.locale('zh-cn')
|
|
249
|
+
dayjs.locale('zh-cn');
|
|
254
250
|
</script>
|
|
255
251
|
```
|
|
256
252
|
|
|
@@ -11,10 +11,11 @@ PrimeNG 的 boolean 属性传 `true` 时直接用属性名,不用 `[prop]="tru
|
|
|
11
11
|
```html
|
|
12
12
|
<!-- ✓ 正确 -->
|
|
13
13
|
<p-dialog [(visible)]="visible" modal (onHide)="onHide()">
|
|
14
|
-
<p-button severity="secondary" outlined loading disabled />
|
|
14
|
+
<p-button severity="secondary" outlined loading disabled />
|
|
15
15
|
|
|
16
|
-
<!-- ✗ 错误 -->
|
|
17
|
-
<p-dialog [(visible)]="visible" [modal]="true"
|
|
16
|
+
<!-- ✗ 错误 -->
|
|
17
|
+
<p-dialog [(visible)]="visible" [modal]="true"></p-dialog
|
|
18
|
+
></p-dialog>
|
|
18
19
|
```
|
|
19
20
|
|
|
20
21
|
### CSS Layer 顺序
|
|
@@ -59,11 +60,10 @@ export class UserListComponent {
|
|
|
59
60
|
readonly totalUsers = signal(0);
|
|
60
61
|
|
|
61
62
|
loadUsers(event: TableLazyLoadEvent) {
|
|
62
|
-
this.authService.listUsers(toPageRequest(event))
|
|
63
|
-
.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
63
|
+
this.authService.listUsers(toPageRequest(event)).subscribe(({ items, totalItems }) => {
|
|
64
|
+
this.users.set(items);
|
|
65
|
+
this.totalUsers.set(totalItems);
|
|
66
|
+
});
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
```
|
|
@@ -86,9 +86,10 @@ export class MyComponent {
|
|
|
86
86
|
|
|
87
87
|
onDelete(id: number) {
|
|
88
88
|
this.confirmationService.confirm({
|
|
89
|
-
accept: () =>
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
accept: () =>
|
|
90
|
+
this.itemService
|
|
91
|
+
.delete(id)
|
|
92
|
+
.subscribe(() => this.messageService.add({ severity: 'success', summary: '删除成功' })),
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
}
|
|
@@ -101,23 +102,13 @@ export class MyComponent {
|
|
|
101
102
|
```typescript
|
|
102
103
|
@Component({
|
|
103
104
|
template: `
|
|
104
|
-
<p-drawer
|
|
105
|
-
styleClass="w-200"
|
|
106
|
-
[(visible)]="visible"
|
|
107
|
-
position="right"
|
|
108
|
-
(onHide)="onHide()"
|
|
109
|
-
>
|
|
105
|
+
<p-drawer styleClass="w-200" [(visible)]="visible" position="right" (onHide)="onHide()">
|
|
110
106
|
<ng-template #header>
|
|
111
107
|
<div class="font-bold text-2xl">标题</div>
|
|
112
108
|
</ng-template>
|
|
113
109
|
<ng-template #footer>
|
|
114
110
|
<div class="flex justify-end items-center gap-2">
|
|
115
|
-
<p-button
|
|
116
|
-
severity="secondary"
|
|
117
|
-
outlined
|
|
118
|
-
label="取消"
|
|
119
|
-
(onClick)="onHide()"
|
|
120
|
-
/>
|
|
111
|
+
<p-button severity="secondary" outlined label="取消" (onClick)="onHide()" />
|
|
121
112
|
<p-button type="submit" label="确定" />
|
|
122
113
|
</div>
|
|
123
114
|
</ng-template>
|
|
@@ -17,11 +17,14 @@ private saveAllSuccessful(
|
|
|
17
17
|
每个算子一行,行首 `.`,2 格缩进:
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
|
-
this.service
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
this.service
|
|
21
|
+
.getData(id)
|
|
22
|
+
.pipe(
|
|
23
|
+
switchMap((data) => this.otherService.process(data)),
|
|
24
|
+
takeUntilDestroyed(this.destroyRef),
|
|
25
|
+
finalize(() => this.loading.set(false)),
|
|
26
|
+
)
|
|
27
|
+
.subscribe((result) => this.data.set(result));
|
|
25
28
|
```
|
|
26
29
|
|
|
27
30
|
## Signal / computed / httpResource
|
|
@@ -195,11 +198,10 @@ readonly state = computed<DialogState>(() => { ... });
|
|
|
195
198
|
## `subscribe()` 回调
|
|
196
199
|
|
|
197
200
|
```typescript
|
|
198
|
-
this.service.list(toPageRequest(event))
|
|
199
|
-
.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
});
|
|
201
|
+
this.service.list(toPageRequest(event)).subscribe(({ items, totalItems }) => {
|
|
202
|
+
this.users.set(items);
|
|
203
|
+
this.totalUsers.set(totalItems);
|
|
204
|
+
});
|
|
203
205
|
|
|
204
206
|
this.service.delete(id).subscribe(() => {
|
|
205
207
|
this.messageService.add({ severity: 'success', summary: '删除成功' });
|
|
@@ -211,11 +213,9 @@ this.service.delete(id).subscribe(() => {
|
|
|
211
213
|
≤ 90 列则一行,超过时回调换行(2 格缩进),回调以 `,` 结尾,`)!` 单独一行:
|
|
212
214
|
|
|
213
215
|
```typescript
|
|
214
|
-
const page = this.pages().find(p => p.id === id)!;
|
|
216
|
+
const page = this.pages().find((p) => p.id === id)!;
|
|
215
217
|
|
|
216
|
-
const selectedForm = this.formService.forms().find(
|
|
217
|
-
form => form.id === menuItem.formId!,
|
|
218
|
-
)!;
|
|
218
|
+
const selectedForm = this.formService.forms().find((form) => form.id === menuItem.formId!)!;
|
|
219
219
|
```
|
|
220
220
|
|
|
221
221
|
## `messageService.add()` 等对象参数
|
|
@@ -246,7 +246,5 @@ loadComponent: () =>
|
|
|
246
246
|
await 右侧超过 90 列时换行(2 格缩进):
|
|
247
247
|
|
|
248
248
|
```typescript
|
|
249
|
-
const user = await lastValueFrom(
|
|
250
|
-
this.authService.createUser(this.form().value())
|
|
251
|
-
);
|
|
249
|
+
const user = await lastValueFrom(this.authService.createUser(this.form().value()));
|
|
252
250
|
```
|