@liujitcn/kratos-admin-core 0.0.65 → 0.0.66

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 (32) hide show
  1. package/dist/package/declarations/src/components/CodeBlock/index.vue.d.ts +15 -0
  2. package/dist/package/declarations/src/components/ProForm/components/ProFormItem.vue.d.ts +4 -4
  3. package/dist/package/declarations/src/components/ProForm/interface/index.d.ts +1 -1
  4. package/dist/package/declarations/src/components/YamlEditor/index.vue.d.ts +7 -1
  5. package/dist/package/declarations/src/locales/generated.d.ts +356 -0
  6. package/dist/package/declarations/src/views/demo/components/DemoDetailDrawer.vue.d.ts +15 -0
  7. package/dist/package/declarations/src/views/demo/components/DemoFormDialog.vue.d.ts +69 -0
  8. package/dist/package/declarations/src/views/demo/demo-data.d.ts +145 -0
  9. package/dist/package/declarations/src/views/demo/table/index.vue.d.ts +3 -0
  10. package/dist/package/declarations/src/views/demo/tree-grid/index.vue.d.ts +3 -0
  11. package/dist/package/declarations/src/views/demo/tree-table/index.vue.d.ts +3 -0
  12. package/dist/package/src/components/CodeBlock/index.vue +156 -0
  13. package/dist/package/src/components/ProForm/components/ProFormItem.vue +5 -1
  14. package/dist/package/src/components/ProForm/interface/index.ts +1 -0
  15. package/dist/package/src/components/YamlEditor/index.vue +103 -7
  16. package/dist/package/src/locales/en-US.json +90 -1
  17. package/dist/package/src/locales/ja-JP.json +90 -1
  18. package/dist/package/src/locales/zh-CN.json +90 -1
  19. package/dist/package/src/locales/zh-TW.json +90 -1
  20. package/dist/package/src/modules/kratosAdmin.ts +11 -1
  21. package/dist/package/src/utils/index.ts +2 -1
  22. package/dist/package/src/utils/request.ts +2 -1
  23. package/dist/package/src/views/demo/components/DemoDetailDrawer.vue +108 -0
  24. package/dist/package/src/views/demo/components/DemoFormDialog.vue +470 -0
  25. package/dist/package/src/views/demo/demo-data.ts +279 -0
  26. package/dist/package/src/views/demo/table/index.vue +391 -0
  27. package/dist/package/src/views/demo/tree-grid/index.vue +272 -0
  28. package/dist/package/src/views/demo/tree-table/index.vue +346 -0
  29. package/dist/package/types/generated/components.d.ts +4 -1
  30. package/package.json +9 -1
  31. package/src/runtime-messages.ts +39 -0
  32. package/types/generated/components.d.ts +4 -1
@@ -0,0 +1,470 @@
1
+ <!--
2
+ Demo 共享表单弹窗:一次性覆盖 ProForm 支持的全部字段组件类型。
3
+
4
+ 设计说明:
5
+ - 三个 Demo 表格页的“新增 / 编辑”按钮都打开本弹窗,作为全组件表单的单一演示源。
6
+ - 每个字段都标注了组件类型与关键 props 的作用,真实项目中按需摘取,不要整段照抄。
7
+ - 全部文案走 t() 语言包 key,页面不写中文 UI 字符串。
8
+ - component: "slot" 的分组标题字段演示了如何在字段流中插入自定义内容。
9
+ -->
10
+ <template>
11
+ <FormDialog
12
+ v-model="visible"
13
+ ref="formDialogRef"
14
+ :title="t('core.demo.form.title.demo_form')"
15
+ width="960px"
16
+ label-width="120px"
17
+ :col-span="12"
18
+ :model="formData"
19
+ :fields="formFields"
20
+ :rules="rules"
21
+ @confirm="handleSubmit"
22
+ @close="handleClose"
23
+ >
24
+ <!-- 分组标题插槽:配合 component: "slot" 字段渲染分区标题 -->
25
+ <template #sectionBasic>
26
+ <el-divider content-position="left">{{ t("core.demo.form.group.basic") }}</el-divider>
27
+ </template>
28
+ <template #sectionChoice>
29
+ <el-divider content-position="left">{{ t("core.demo.form.group.choice") }}</el-divider>
30
+ </template>
31
+ <template #sectionAdvanced>
32
+ <el-divider content-position="left">{{ t("core.demo.form.group.advanced") }}</el-divider>
33
+ </template>
34
+ <!-- 后缀插槽:渲染在 name 输入框的 append 位置 -->
35
+ <template #nameSuffix>
36
+ <el-button @click="handleRandomCode">{{ t("core.demo.form.action.random_code") }}</el-button>
37
+ </template>
38
+ </FormDialog>
39
+ </template>
40
+
41
+ <script setup lang="ts">
42
+ import { computed, reactive, ref } from "vue";
43
+ import { ElMessage } from "element-plus";
44
+ import type { UploadUserFile } from "element-plus";
45
+ import FormDialog from "../../../components/Dialog/FormDialog.vue";
46
+ import type { ProFormField, ProFormOption } from "../../../components/ProForm/interface";
47
+ import { t } from "../../../locales";
48
+ import { demoDeptTree, demoLevelOptions } from "../demo-data";
49
+
50
+ defineOptions({
51
+ name: "DemoFormDialog"
52
+ });
53
+
54
+ const emit = defineEmits<{
55
+ /** 校验通过后的提交事件,payload 为表单数据深拷贝。 */
56
+ submit: [data: Record<string, any>];
57
+ }>();
58
+
59
+ /** 表单数据模型:字段名与 formFields 的 prop 一一对应。 */
60
+ const formData = reactive({
61
+ /** 项目名称,input 演示。 */
62
+ name: "",
63
+ /** 访问口令,password 演示。 */
64
+ password: "",
65
+ /** 项目简介,textarea 演示。 */
66
+ intro: "",
67
+ /** 任务数量,input-number 演示。 */
68
+ count: 10,
69
+ /** 主题色,color-picker 演示。 */
70
+ color: "",
71
+ /** 是否启用,switch 演示,同时控制 invite_code 字段显隐。 */
72
+ enabled: true,
73
+ /** 已阅读说明,单checkbox 演示。 */
74
+ agreed: false,
75
+ /** 邀请码,visible 联动演示字段:仅 enabled 打开时显示。 */
76
+ invite_code: "",
77
+ /** 展示模式,segmented 演示。 */
78
+ mode: "card",
79
+ /** 项目等级,select 演示(可搜索、可清空)。 */
80
+ level: "",
81
+ /** 租户,tenant-select 演示(静态 options 形态)。 */
82
+ tenant_id: undefined as number | undefined,
83
+ /** 性别,dict 字典组件演示。 */
84
+ gender: 1,
85
+ /** 可见范围,radio-group 演示。 */
86
+ visibility: "public",
87
+ /** 兴趣标签,checkbox-group 演示。 */
88
+ hobbies: [] as string[],
89
+ /** 所属部门,tree-select 演示。 */
90
+ dept_id: undefined as number | undefined,
91
+ /** 成立日期,date-picker 单日演示。 */
92
+ birthday: "",
93
+ /** 活动区间,date-picker 区间选择演示。 */
94
+ range: [] as string[],
95
+ /** 调度表达式,cron-expression 演示。 */
96
+ cron: "",
97
+ /** 协作成员,transfer 穿梭框演示。 */
98
+ members: [] as number[],
99
+ /** 封面图,image-upload 单图上传演示。 */
100
+ avatar: "",
101
+ /** 相册,images-upload 多图上传演示。 */
102
+ gallery: [],
103
+ /** 附件,file-upload 单文件上传演示(组件 fileInfo 为对象类型,空值用 undefined)。 */
104
+ attachment: undefined as UploadUserFile | undefined,
105
+ /** 附件组,files-upload 多文件上传演示。 */
106
+ attachments: [],
107
+ /** 详细内容,rich-text 富文本演示。 */
108
+ content: "",
109
+ /** 部署配置,yaml-editor 演示。 */
110
+ config: "",
111
+ /** 别名列表,dynamic-list 演示。 */
112
+ aliases: [] as string[],
113
+ /** 环境变量,kv-list 键值对列表演示。 */
114
+ properties: [] as { key: string; value: string }[]
115
+ });
116
+
117
+ /** 部门树静态选项:把 DemoDeptNode 映射成 el-tree-select 需要的 value/label/children 结构。 */
118
+ const deptTreeOptions: ProFormOption[] = demoDeptTree.map(dept => ({
119
+ label: dept.name,
120
+ value: Number(dept.id),
121
+ children: dept.children?.map(child => ({ label: child.name, value: Number(child.id) }))
122
+ }));
123
+
124
+ /** 租户静态选项:tenant-select 传入 options 后不再请求租户接口,纯静态可渲染。 */
125
+ const tenantOptions: ProFormOption[] = [
126
+ { label: "Demo 总租户", value: 1 },
127
+ { label: "Demo 子租户", value: 2 }
128
+ ];
129
+
130
+ /** 协作成员穿梭框数据源:value 即选中后的 key。 */
131
+ const memberOptions: ProFormOption[] = demoDeptTree[0].children!.map((dept, index) => ({
132
+ label: `${dept.name}负责人`,
133
+ value: index + 1
134
+ }));
135
+
136
+ /**
137
+ * 全量字段配置:每个字段注释了组件类型与关键 props,属性透传规则见
138
+ * core/src/components/ProForm/components/ProFormItem.vue。
139
+ */
140
+ const formFields = computed<ProFormField[]>(() => [
141
+ // ── 分组标题:component: "slot" + colSpan 24 渲染通栏插槽 ──
142
+ { prop: "section_basic", label: "", component: "slot", slotName: "sectionBasic", colSpan: 24 },
143
+ {
144
+ // input:suffixSlotName 渲染输入框 append 插槽
145
+ prop: "name",
146
+ label: t("core.demo.form.field.name"),
147
+ component: "input",
148
+ suffixSlotName: "nameSuffix",
149
+ props: { placeholder: t("common.placeholder.input"), clearable: true, maxlength: 30 }
150
+ },
151
+ {
152
+ // password:ProFormItem 内置 show-password,仅需透传占位等 props
153
+ prop: "password",
154
+ label: t("core.demo.form.field.password"),
155
+ component: "password",
156
+ props: { placeholder: t("common.placeholder.input") }
157
+ },
158
+ {
159
+ // textarea:maxlength + show-word-limit 演示字数限制
160
+ prop: "intro",
161
+ label: t("core.demo.form.field.intro"),
162
+ component: "textarea",
163
+ colSpan: 24,
164
+ props: { rows: 3, maxlength: 200, showWordLimit: true, placeholder: t("common.placeholder.input") }
165
+ },
166
+ {
167
+ // input-number:步进、精度与控制按钮位置
168
+ prop: "count",
169
+ label: t("core.demo.form.field.count"),
170
+ component: "input-number",
171
+ labelTooltip: t("core.demo.form.tooltip.count"),
172
+ props: { min: 0, max: 999, step: 5, precision: 0, controlsPosition: "right", style: { width: "100%" } }
173
+ },
174
+ {
175
+ // color-picker:预置色板与透明度
176
+ prop: "color",
177
+ label: t("core.demo.form.field.color"),
178
+ component: "color-picker",
179
+ props: { showAlpha: true, predefine: ["#409eff", "#67c23a", "#e6a23c", "#f56c6c"] }
180
+ },
181
+ {
182
+ // switch:inlinePrompt 文案内嵌;该值同时联动 invite_code 的显隐
183
+ prop: "enabled",
184
+ label: t("core.demo.form.field.enabled"),
185
+ component: "switch",
186
+ props: { inlinePrompt: true, activeText: t("common.status.enabled"), inactiveText: t("common.status.disabled") }
187
+ },
188
+ {
189
+ // checkbox:单个复选框,文案来自 checkboxLabel
190
+ prop: "agreed",
191
+ label: "",
192
+ component: "checkbox",
193
+ checkboxLabel: t("core.demo.form.field.agreed")
194
+ },
195
+ {
196
+ // visible 联动演示:仅 enabled 打开时渲染,随 switch 实时显隐
197
+ prop: "invite_code",
198
+ label: t("core.demo.form.field.invite_code"),
199
+ component: "input",
200
+ visible: model => Boolean(model.enabled),
201
+ props: { placeholder: t("common.placeholder.input"), maxlength: 12 }
202
+ },
203
+ // ── 选择与日期分组 ──
204
+ { prop: "section_choice", label: "", component: "slot", slotName: "sectionChoice", colSpan: 24, rowBreakBefore: true },
205
+ {
206
+ // segmented:分段选择器,block 撑满整行
207
+ prop: "mode",
208
+ label: t("core.demo.form.field.mode"),
209
+ component: "segmented",
210
+ options: [
211
+ { label: t("core.demo.form.mode.card"), value: "card" },
212
+ { label: t("core.demo.form.mode.list"), value: "list" },
213
+ { label: t("core.demo.form.mode.table"), value: "table" }
214
+ ],
215
+ props: { block: true }
216
+ },
217
+ {
218
+ // select:filterable 可搜索、clearable 可清空;options 里的 tagType 仅供标签列使用
219
+ prop: "level",
220
+ label: t("core.demo.form.field.level"),
221
+ component: "select",
222
+ options: demoLevelOptions,
223
+ props: { clearable: true, filterable: true, placeholder: t("common.placeholder.select") }
224
+ },
225
+ {
226
+ // tenant-select:真实项目无需 options(组件自动请求租户接口),
227
+ // Demo 为纯静态页传入固定 options 跳过接口请求。
228
+ prop: "tenant_id",
229
+ label: t("common.field.tenant"),
230
+ component: "tenant-select",
231
+ props: { options: tenantOptions, placeholder: t("common.placeholder.select") }
232
+ },
233
+ {
234
+ // dict:字典组件按 code 拉取字典项(依赖字典接口权限,管理端默认已授权),
235
+ // codeType: "number" 表示字典值为数字。
236
+ prop: "gender",
237
+ label: t("core.demo.form.field.gender"),
238
+ component: "dict",
239
+ props: { code: "base_user_gender", codeType: "number", style: { width: "100%" } }
240
+ },
241
+ {
242
+ // radio-group:单选组
243
+ prop: "visibility",
244
+ label: t("core.demo.form.field.visibility"),
245
+ component: "radio-group",
246
+ options: [
247
+ { label: t("core.demo.form.visibility.public"), value: "public" },
248
+ { label: t("core.demo.form.visibility.private"), value: "private" }
249
+ ]
250
+ },
251
+ {
252
+ // checkbox-group:多选组,绑定数组
253
+ prop: "hobbies",
254
+ label: t("core.demo.form.field.hobbies"),
255
+ component: "checkbox-group",
256
+ options: [
257
+ { label: t("core.demo.form.hobby.review"), value: "review" },
258
+ { label: t("core.demo.form.hobby.deploy"), value: "deploy" },
259
+ { label: t("core.demo.form.hobby.metric"), value: "metric" }
260
+ ]
261
+ },
262
+ {
263
+ // tree-select:树形下拉,checkStrictly 允许选中任意层级
264
+ prop: "dept_id",
265
+ label: t("common.field.department"),
266
+ component: "tree-select",
267
+ options: deptTreeOptions,
268
+ props: {
269
+ clearable: true,
270
+ filterable: true,
271
+ checkStrictly: true,
272
+ renderAfterExpand: false,
273
+ placeholder: t("common.placeholder.select"),
274
+ style: { width: "100%" }
275
+ }
276
+ },
277
+ {
278
+ // date-picker:单日选择,value-format 控制绑定值格式
279
+ prop: "birthday",
280
+ label: t("core.demo.form.field.birthday"),
281
+ component: "date-picker",
282
+ props: { type: "date", valueFormat: "YYYY-MM-DD", placeholder: t("common.placeholder.select"), style: { width: "100%" } }
283
+ },
284
+ {
285
+ // date-picker:区间选择,绑定数组值,通栏展示
286
+ prop: "range",
287
+ label: t("core.demo.form.field.range"),
288
+ component: "date-picker",
289
+ colSpan: 24,
290
+ props: {
291
+ type: "datetimerange",
292
+ valueFormat: "YYYY-MM-DD HH:mm:ss",
293
+ startPlaceholder: t("common.placeholder.start_date"),
294
+ endPlaceholder: t("common.placeholder.end_date")
295
+ }
296
+ },
297
+ // ── 高级组件分组 ──
298
+ { prop: "section_advanced", label: "", component: "slot", slotName: "sectionAdvanced", colSpan: 24, rowBreakBefore: true },
299
+ {
300
+ // cron-expression:Cron 表达式编辑器(弹窗面板生成表达式)
301
+ prop: "cron",
302
+ label: t("core.demo.form.field.cron"),
303
+ component: "cron-expression",
304
+ colSpan: 24,
305
+ rowBreakBefore: true,
306
+ props: { placeholder: t("core.demo.form.placeholder.cron") }
307
+ },
308
+ {
309
+ // transfer:穿梭框,选项 value 即选中 key,通栏展示
310
+ prop: "members",
311
+ label: t("core.demo.form.field.members"),
312
+ component: "transfer",
313
+ colSpan: 24,
314
+ options: memberOptions,
315
+ props: {
316
+ filterable: true,
317
+ targetOrder: "unshift",
318
+ titles: [t("core.demo.form.transfer.candidates"), t("core.demo.form.transfer.selected")]
319
+ }
320
+ },
321
+ {
322
+ // image-upload:单图上传(默认走文件服务上传接口,选择文件后才发起请求)
323
+ prop: "avatar",
324
+ label: t("core.demo.form.field.avatar"),
325
+ component: "image-upload",
326
+ props: { width: "120px", height: "120px" }
327
+ },
328
+ {
329
+ // images-upload:多图上传,limit 限制数量
330
+ prop: "gallery",
331
+ label: t("core.demo.form.field.gallery"),
332
+ component: "images-upload",
333
+ props: { limit: 4, drag: false }
334
+ },
335
+ {
336
+ // file-upload:单文件上传
337
+ prop: "attachment",
338
+ label: t("core.demo.form.field.attachment"),
339
+ component: "file-upload"
340
+ },
341
+ {
342
+ // files-upload:多文件上传,fileSize 单位 MB
343
+ prop: "attachments",
344
+ label: t("core.demo.form.field.attachments"),
345
+ component: "files-upload",
346
+ props: { limit: 3, fileSize: 10 }
347
+ },
348
+ {
349
+ // rich-text:富文本编辑器,通栏展示,height 控制编辑区高度(wangEditor 要求 ≥300px,否则 hoverbar 定位告警)
350
+ prop: "content",
351
+ label: t("core.demo.form.field.content"),
352
+ component: "rich-text",
353
+ colSpan: 24,
354
+ props: { height: "320px" }
355
+ },
356
+ {
357
+ // yaml-editor:YAML 编辑器(CodeMirror + 工具栏),min/maxHeight 控制伸缩范围
358
+ prop: "config",
359
+ label: t("core.demo.form.field.config"),
360
+ component: "yaml-editor",
361
+ colSpan: 24,
362
+ props: { minHeight: "160px", maxHeight: "320px" }
363
+ },
364
+ {
365
+ // dynamic-list:动态行文本列表
366
+ prop: "aliases",
367
+ label: t("core.demo.form.field.aliases"),
368
+ component: "dynamic-list",
369
+ colSpan: 24,
370
+ props: { inputProps: { placeholder: t("common.placeholder.input_content") } }
371
+ },
372
+ {
373
+ // kv-list:键值对列表,addText 自定义新增按钮文案
374
+ prop: "properties",
375
+ label: t("core.demo.form.field.properties"),
376
+ component: "kv-list",
377
+ colSpan: 24,
378
+ props: { addText: t("core.demo.form.action.add_property") }
379
+ }
380
+ ]);
381
+
382
+ /** 校验规则演示:必填、长度与数字范围。 */
383
+ const rules = computed(() => ({
384
+ name: [
385
+ { required: true, message: t("common.validation.required_input", { field: t("core.demo.form.field.name") }), trigger: "blur" }
386
+ ],
387
+ count: [{ required: true, type: "number", min: 0, max: 999, message: t("common.validation.sort_positive"), trigger: "blur" }],
388
+ invite_code: [
389
+ {
390
+ max: 12,
391
+ message: t("common.validation.max_length", { field: t("core.demo.form.field.invite_code"), max: 12 }),
392
+ trigger: "blur"
393
+ }
394
+ ]
395
+ }));
396
+
397
+ const visible = ref(false);
398
+ const formDialogRef = ref<InstanceType<typeof FormDialog>>();
399
+
400
+ /** 恢复表单初始值:打开弹窗前调用,避免新增/编辑之间互相污染。 */
401
+ function resetForm() {
402
+ formDialogRef.value?.resetFields();
403
+ formDialogRef.value?.clearValidate();
404
+ formData.name = "";
405
+ formData.password = "";
406
+ formData.intro = "";
407
+ formData.count = 10;
408
+ formData.color = "";
409
+ formData.enabled = true;
410
+ formData.agreed = false;
411
+ formData.invite_code = "";
412
+ formData.mode = "card";
413
+ formData.level = "";
414
+ formData.tenant_id = undefined;
415
+ formData.gender = 1;
416
+ formData.visibility = "public";
417
+ formData.hobbies = [];
418
+ formData.dept_id = undefined;
419
+ formData.birthday = "";
420
+ formData.range = [];
421
+ formData.cron = "";
422
+ formData.members = [];
423
+ formData.avatar = "";
424
+ formData.gallery = [];
425
+ formData.attachment = undefined;
426
+ formData.attachments = [];
427
+ formData.content = "";
428
+ formData.config = "";
429
+ formData.aliases = [];
430
+ formData.properties = [];
431
+ }
432
+
433
+ /**
434
+ * 打开弹窗:支持传入初始值(编辑回填演示)。
435
+ * 真实项目中可在 open 的 load 回调里请求详情接口后再回填。
436
+ */
437
+ function open(initial?: Partial<typeof formData>) {
438
+ resetForm();
439
+ if (initial) Object.assign(formData, initial);
440
+ visible.value = true;
441
+ }
442
+
443
+ /** 随机生成一个编码填入名称,演示 suffixSlotName 插槽交互。 */
444
+ function handleRandomCode() {
445
+ formData.name = `DEMO-${Math.random().toString(36).slice(2, 8).toUpperCase()}`;
446
+ }
447
+
448
+ /** 提交表单:校验通过后向父组件抛出数据并关闭(纯静态演示,不调用保存接口)。 */
449
+ function handleSubmit() {
450
+ formDialogRef.value?.validate()?.then(valid => {
451
+ if (!valid) return;
452
+ const submitData = JSON.parse(JSON.stringify(formData)) as Record<string, any>;
453
+ // 真实项目在此调用 CreateXxx / UpdateXxx RPC,成功后刷新表格;
454
+ // Demo 中父页面监听 submit 事件演示本地落库(树形表格页的新增子级)。
455
+ emit("submit", submitData);
456
+ // eslint-disable-next-line no-console
457
+ console.log("[DemoFormDialog] 提交数据:", submitData);
458
+ ElMessage.success(t("core.demo.form.message.submit_success"));
459
+ handleClose();
460
+ });
461
+ }
462
+
463
+ /** 关闭弹窗并清理表单状态。 */
464
+ function handleClose() {
465
+ formDialogRef.value?.close();
466
+ resetForm();
467
+ }
468
+
469
+ defineExpose({ open });
470
+ </script>