@liujitcn/kratos-admin-core 0.0.65 → 0.0.67
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/dist/package/declarations/src/api/base/v1/login.d.ts +1 -3
- package/dist/package/declarations/src/api/base/v1/secret_crypto.d.ts +9 -0
- package/dist/package/declarations/src/components/CodeBlock/index.vue.d.ts +15 -0
- package/dist/package/declarations/src/components/Dialog/PasswordVerifyDialog.vue.d.ts +3 -7
- package/dist/package/declarations/src/components/ProForm/components/ProFormItem.vue.d.ts +6 -6
- package/dist/package/declarations/src/components/ProForm/components/SecretInput.vue.d.ts +23 -0
- package/dist/package/declarations/src/components/ProForm/interface/index.d.ts +14 -1
- package/dist/package/declarations/src/components/YamlEditor/index.vue.d.ts +7 -1
- package/dist/package/declarations/src/locales/generated.d.ts +388 -0
- package/dist/package/declarations/src/rpc/base/v1/login.d.ts +2 -39
- package/dist/package/declarations/src/rpc/base/v1/mfa.d.ts +3 -3
- package/dist/package/declarations/src/rpc/base/v1/oauth.d.ts +2 -2
- package/dist/package/declarations/src/rpc/base/v1/secret_crypto.d.ts +37 -0
- package/dist/package/declarations/src/rpc/common/v1/types.d.ts +4 -4
- package/dist/package/declarations/src/rpc/system/admin/v1/auth.d.ts +3 -3
- package/dist/package/declarations/src/security.d.ts +1 -1
- package/dist/package/declarations/src/utils/secretCrypto.d.ts +19 -0
- package/dist/package/declarations/src/views/demo/components/DemoDetailDrawer.vue.d.ts +15 -0
- package/dist/package/declarations/src/views/demo/components/DemoFormDialog.vue.d.ts +69 -0
- package/dist/package/declarations/src/views/demo/demo-data.d.ts +145 -0
- package/dist/package/declarations/src/views/demo/table/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/demo/tree-grid/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/demo/tree-table/index.vue.d.ts +3 -0
- package/dist/package/src/api/base/v1/login.ts +0 -12
- package/dist/package/src/api/base/v1/secret_crypto.ts +35 -0
- package/dist/package/src/components/CodeBlock/index.vue +156 -0
- package/dist/package/src/components/Dialog/PasswordVerifyDialog.vue +4 -8
- package/dist/package/src/components/ProForm/components/ProFormItem.vue +29 -2
- package/dist/package/src/components/ProForm/components/SecretInput.vue +117 -0
- package/dist/package/src/components/ProForm/interface/index.ts +16 -0
- package/dist/package/src/components/YamlEditor/index.vue +103 -7
- package/dist/package/src/locales/README.md +1 -1
- package/dist/package/src/locales/en-US.json +98 -1
- package/dist/package/src/locales/ja-JP.json +98 -1
- package/dist/package/src/locales/zh-CN.json +98 -1
- package/dist/package/src/locales/zh-TW.json +98 -1
- package/dist/package/src/modules/kratosAdmin.ts +11 -1
- package/dist/package/src/rpc/base/v1/login.ts +2 -42
- package/dist/package/src/rpc/base/v1/mfa.ts +3 -3
- package/dist/package/src/rpc/base/v1/oauth.ts +2 -2
- package/dist/package/src/rpc/base/v1/secret_crypto.ts +49 -0
- package/dist/package/src/rpc/common/v1/types.ts +4 -4
- package/dist/package/src/rpc/system/admin/v1/auth.ts +3 -3
- package/dist/package/src/security.ts +1 -1
- package/dist/package/src/utils/index.ts +2 -1
- package/dist/package/src/utils/request.ts +5 -4
- package/dist/package/src/utils/{passwordCrypto.ts → secretCrypto.ts} +112 -50
- package/dist/package/src/views/demo/components/DemoDetailDrawer.vue +108 -0
- package/dist/package/src/views/demo/components/DemoFormDialog.vue +470 -0
- package/dist/package/src/views/demo/demo-data.ts +279 -0
- package/dist/package/src/views/demo/table/index.vue +391 -0
- package/dist/package/src/views/demo/tree-grid/index.vue +272 -0
- package/dist/package/src/views/demo/tree-table/index.vue +346 -0
- package/dist/package/src/views/login/components/LoginForm.vue +2 -2
- package/dist/package/types/generated/components.d.ts +4 -1
- package/package.json +14 -2
- package/src/runtime-messages.ts +39 -0
- package/types/generated/components.d.ts +4 -1
- package/dist/package/declarations/src/utils/passwordCrypto.d.ts +0 -6
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Demo 演示模块共享的静态 mock 数据与类型。
|
|
3
|
+
*
|
|
4
|
+
* 约定:
|
|
5
|
+
* - 全部数据纯前端静态维护,不调用任何后端接口;真实项目中对应字段来自 RPC 返回结构。
|
|
6
|
+
* - 记录内容本身是"业务数据",与表格列头等 UI 文案不同,不进入语言包(与真实项目一致)。
|
|
7
|
+
* - avatar 使用内联 SVG data URL,避免依赖外网图片服务,离线环境也能渲染图片列。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Demo 通用状态值:与 base.v1 Status 枚举保持一致(1 启用 / 2 禁用),core 不反向依赖业务 RPC。 */
|
|
11
|
+
export const STATUS_ENABLE = 1;
|
|
12
|
+
/** 禁用状态值。 */
|
|
13
|
+
export const STATUS_DISABLE = 2;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 用 canvas 生成 PNG base64 头像 data URL。
|
|
17
|
+
* 图片列的 formatSrc 只放行 base64 位图(png/jpeg/webp 等),
|
|
18
|
+
* 因此不能用 svg+xml 文本;canvas 生成可离线渲染且通过安全校验。
|
|
19
|
+
*/
|
|
20
|
+
function makeAvatar(background: string, text: string): string {
|
|
21
|
+
const size = 80;
|
|
22
|
+
const canvas = document.createElement("canvas");
|
|
23
|
+
canvas.width = size;
|
|
24
|
+
canvas.height = size;
|
|
25
|
+
const ctx = canvas.getContext("2d");
|
|
26
|
+
if (!ctx) return "";
|
|
27
|
+
ctx.beginPath();
|
|
28
|
+
if (typeof ctx.roundRect === "function") {
|
|
29
|
+
ctx.roundRect(0, 0, size, size, 16);
|
|
30
|
+
} else {
|
|
31
|
+
ctx.rect(0, 0, size, size);
|
|
32
|
+
}
|
|
33
|
+
ctx.fillStyle = background;
|
|
34
|
+
ctx.fill();
|
|
35
|
+
ctx.fillStyle = "#ffffff";
|
|
36
|
+
ctx.font = "30px sans-serif";
|
|
37
|
+
ctx.textAlign = "center";
|
|
38
|
+
ctx.textBaseline = "middle";
|
|
39
|
+
ctx.fillText(text, size / 2, size / 2 + 2);
|
|
40
|
+
return canvas.toDataURL("image/png");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Demo 员工记录,左树右表页面的行数据结构。 */
|
|
44
|
+
export interface DemoEmployee {
|
|
45
|
+
/** 员工ID。 */
|
|
46
|
+
id: number;
|
|
47
|
+
/** 姓名列表格首列。 */
|
|
48
|
+
name: string;
|
|
49
|
+
/** 所属部门ID,关联左侧部门树的 id。 */
|
|
50
|
+
dept_id: number;
|
|
51
|
+
/** 邮箱,演示普通文本列。 */
|
|
52
|
+
email: string;
|
|
53
|
+
/** 手机号。 */
|
|
54
|
+
phone: string;
|
|
55
|
+
/** 头像,演示 cellType: "image" 图片列。 */
|
|
56
|
+
avatar: string;
|
|
57
|
+
/** 薪资(单位:分),演示 cellType: "money" 金额列,金额列按分换算展示。 */
|
|
58
|
+
salary: number;
|
|
59
|
+
/** 状态,1 启用 / 0 停用,演示 cellType: "status" 状态开关列。 */
|
|
60
|
+
status: number;
|
|
61
|
+
/** 入职日期,演示日期区间搜索。 */
|
|
62
|
+
entry_date: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Demo 项目记录,纯表格页面的行数据结构。 */
|
|
66
|
+
export interface DemoProject {
|
|
67
|
+
/** 项目ID。 */
|
|
68
|
+
id: number;
|
|
69
|
+
/** 项目名称,演示 input 搜索 + tag 标签列。 */
|
|
70
|
+
name: string;
|
|
71
|
+
/** 项目等级,演示 tag: true + enum tagType 标签列。 */
|
|
72
|
+
level: string;
|
|
73
|
+
/** 负责人。 */
|
|
74
|
+
owner: string;
|
|
75
|
+
/** 状态,1 启用 / 0 停用。 */
|
|
76
|
+
status: number;
|
|
77
|
+
/** 预算金额(单位:分),演示 cellType: "money" 金额列,金额列按分换算展示。 */
|
|
78
|
+
budget: number;
|
|
79
|
+
/** 任务总数,放在多级表头“任务情况”下。 */
|
|
80
|
+
task_total: number;
|
|
81
|
+
/** 完成进度(0-100),演示 render 自定义渲染进度条列。 */
|
|
82
|
+
progress: number;
|
|
83
|
+
/** 所属城市(演示级联选择搜索),格式:省份/城市。 */
|
|
84
|
+
region: string[];
|
|
85
|
+
/** 创建时间,演示日期区间搜索。 */
|
|
86
|
+
created_at: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Demo 目录节点,树形表格页面的行数据结构(children 内嵌子级行)。 */
|
|
90
|
+
export interface DemoCatalog {
|
|
91
|
+
/** 节点ID。 */
|
|
92
|
+
id: number;
|
|
93
|
+
/** 目录名称,作为树形展开列。 */
|
|
94
|
+
name: string;
|
|
95
|
+
/** 编码。 */
|
|
96
|
+
code: string;
|
|
97
|
+
/** 负责人。 */
|
|
98
|
+
owner: string;
|
|
99
|
+
/** 状态,1 启用 / 0 停用。 */
|
|
100
|
+
status: number;
|
|
101
|
+
/** 文档数量。 */
|
|
102
|
+
doc_count: number;
|
|
103
|
+
/** 子级目录,树形表格通过 tree-props.children 识别。 */
|
|
104
|
+
children?: DemoCatalog[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** 部门树节点,左侧 TreeFilter 静态数据结构。 */
|
|
108
|
+
export interface DemoDeptNode {
|
|
109
|
+
/** 部门ID,字符串形式以匹配 TreeFilter 默认选中逻辑。 */
|
|
110
|
+
id: string;
|
|
111
|
+
/** 部门名称。 */
|
|
112
|
+
name: string;
|
|
113
|
+
/** 部门人数,展示在树节点右侧。 */
|
|
114
|
+
count: number;
|
|
115
|
+
/** 子部门。 */
|
|
116
|
+
children?: DemoDeptNode[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** 详情抽屉单条字段:label 走 t() 文案,value 为记录内容。 */
|
|
120
|
+
export interface DemoDetailField {
|
|
121
|
+
/** 字段中文名。 */
|
|
122
|
+
label: string;
|
|
123
|
+
/** 字段值。 */
|
|
124
|
+
value: string;
|
|
125
|
+
/** 是否用 el-tag 展示。 */
|
|
126
|
+
tag?: boolean;
|
|
127
|
+
/** el-tag 展示类型(success/info/warning/danger)。 */
|
|
128
|
+
tagType?: "success" | "info" | "warning" | "danger";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** 详情抽屉信息分组,一组对应一个 el-descriptions 区块。 */
|
|
132
|
+
export interface DemoDetailSection {
|
|
133
|
+
/** 分组标题。 */
|
|
134
|
+
title: string;
|
|
135
|
+
/** 分组内字段。 */
|
|
136
|
+
fields: DemoDetailField[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** 详情抽屉入参模型,由各页面从行数据组装。 */
|
|
140
|
+
export interface DemoDetailModel {
|
|
141
|
+
/** 抽屉标题。 */
|
|
142
|
+
title: string;
|
|
143
|
+
/** 基本信息分组。 */
|
|
144
|
+
sections: DemoDetailSection[];
|
|
145
|
+
/** 流程步骤,演示 el-steps。 */
|
|
146
|
+
steps: { title: string; description: string }[];
|
|
147
|
+
/** 操作时间线,演示 el-timeline。 */
|
|
148
|
+
timeline: { title: string; timestamp: string; type: "primary" | "success" | "warning" | "danger" | "info" }[];
|
|
149
|
+
/** 原始数据,演示 JSON 预览。 */
|
|
150
|
+
raw: Record<string, unknown>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** 左侧部门树静态数据:三层结构演示树的展开、搜索与联动。 */
|
|
154
|
+
export const demoDeptTree: DemoDeptNode[] = [
|
|
155
|
+
{
|
|
156
|
+
id: "1",
|
|
157
|
+
name: "Demo 技术部",
|
|
158
|
+
count: 12,
|
|
159
|
+
children: [
|
|
160
|
+
{ id: "11", name: "前端组", count: 5 },
|
|
161
|
+
{ id: "12", name: "后端组", count: 7 }
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: "2",
|
|
166
|
+
name: "Demo 产品部",
|
|
167
|
+
count: 6,
|
|
168
|
+
children: [
|
|
169
|
+
{ id: "21", name: "产品设计组", count: 3 },
|
|
170
|
+
{ id: "22", name: "用户体验组", count: 3 }
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
{ id: "3", name: "Demo 运营部", count: 4 }
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
/** 员工静态数据:覆盖图片列、金额列、状态列与部门树联动过滤演示。 */
|
|
177
|
+
export const demoEmployees: DemoEmployee[] = [
|
|
178
|
+
{ id: 1, name: "陈默", dept_id: 11, email: "chenmo@demo.com", phone: "13800000001", avatar: makeAvatar("#409eff", "陈"), salary: 1800000, status: STATUS_ENABLE, entry_date: "2023-03-15" },
|
|
179
|
+
{ id: 2, name: "林晚", dept_id: 11, email: "linwan@demo.com", phone: "13800000002", avatar: makeAvatar("#67c23a", "林"), salary: 1650000, status: STATUS_ENABLE, entry_date: "2023-07-01" },
|
|
180
|
+
{ id: 3, name: "苏辞", dept_id: 12, email: "suci@demo.com", phone: "13800000003", avatar: makeAvatar("#e6a23c", "苏"), salary: 2100000, status: STATUS_ENABLE, entry_date: "2022-11-20" },
|
|
181
|
+
{ id: 4, name: "顾言", dept_id: 12, email: "guyan@demo.com", phone: "13800000004", avatar: makeAvatar("#f56c6c", "顾"), salary: 1950000, status: STATUS_DISABLE, entry_date: "2021-06-08" },
|
|
182
|
+
{ id: 5, name: "沈舟", dept_id: 21, email: "shenzhou@demo.com", phone: "13800000005", avatar: makeAvatar("#909399", "沈"), salary: 1500000, status: STATUS_ENABLE, entry_date: "2024-01-10" },
|
|
183
|
+
{ id: 6, name: "叶蓁", dept_id: 21, email: "yezhen@demo.com", phone: "13800000006", avatar: makeAvatar("#409eff", "叶"), salary: 1580000, status: STATUS_ENABLE, entry_date: "2024-04-22" },
|
|
184
|
+
{ id: 7, name: "江离", dept_id: 22, email: "jiangli@demo.com", phone: "13800000007", avatar: makeAvatar("#67c23a", "江"), salary: 1420000, status: STATUS_DISABLE, entry_date: "2024-09-01" },
|
|
185
|
+
{ id: 8, name: "温叙", dept_id: 3, email: "wenxu@demo.com", phone: "13800000008", avatar: makeAvatar("#e6a23c", "温"), salary: 1280000, status: STATUS_ENABLE, entry_date: "2025-02-14" },
|
|
186
|
+
{ id: 9, name: "白鹭", dept_id: 3, email: "bailu@demo.com", phone: "13800000009", avatar: makeAvatar("#f56c6c", "白"), salary: 1350000, status: STATUS_ENABLE, entry_date: "2025-03-30" },
|
|
187
|
+
{ id: 10, name: "祝余", dept_id: 11, email: "zhuyu@demo.com", phone: "13800000010", avatar: makeAvatar("#909399", "祝"), salary: 1720000, status: STATUS_ENABLE, entry_date: "2023-12-05" }
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
/** 项目等级枚举选项:同时用于标签列展示与搜索下拉、表单单选。 */
|
|
191
|
+
export const demoLevelOptions = [
|
|
192
|
+
{ label: "S", value: "S", tagType: "danger" },
|
|
193
|
+
{ label: "A", value: "A", tagType: "warning" },
|
|
194
|
+
{ label: "B", value: "B", tagType: "primary" },
|
|
195
|
+
{ label: "C", value: "C", tagType: "info" }
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
/** 城市级联静态数据:演示搜索区 cascader 与 tree-select 控件。 */
|
|
199
|
+
export const demoRegionTree = [
|
|
200
|
+
{
|
|
201
|
+
value: "zhejiang",
|
|
202
|
+
label: "浙江省",
|
|
203
|
+
children: [
|
|
204
|
+
{ value: "hangzhou", label: "杭州市" },
|
|
205
|
+
{ value: "ningbo", label: "宁波市" }
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
value: "guangdong",
|
|
210
|
+
label: "广东省",
|
|
211
|
+
children: [
|
|
212
|
+
{ value: "shenzhen", label: "深圳市" },
|
|
213
|
+
{ value: "guangzhou", label: "广州市" }
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
value: "sichuan",
|
|
218
|
+
label: "四川省",
|
|
219
|
+
children: [{ value: "chengdu", label: "成都市" }]
|
|
220
|
+
}
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
/** 项目静态数据:25 条覆盖分页、多级表头、进度条、标签列等展示场景。 */
|
|
224
|
+
export const demoProjects: DemoProject[] = [
|
|
225
|
+
{ id: 1, name: "星尘数据平台", level: "S", owner: "陈默", status: STATUS_ENABLE, budget: 128000000, task_total: 46, progress: 82, region: ["zhejiang", "hangzhou"], created_at: "2025-01-06 09:30:00" },
|
|
226
|
+
{ id: 2, name: "流萤网关", level: "A", owner: "苏辞", status: STATUS_ENABLE, budget: 66000000, task_total: 32, progress: 64, region: ["guangdong", "shenzhen"], created_at: "2025-02-11 14:20:00" },
|
|
227
|
+
{ id: 3, name: "青梧中台", level: "B", owner: "顾言", status: STATUS_DISABLE, budget: 42000000, task_total: 28, progress: 35, region: ["sichuan", "chengdu"], created_at: "2025-03-02 10:00:00" },
|
|
228
|
+
{ id: 4, name: "拾光相册", level: "C", owner: "林晚", status: STATUS_ENABLE, budget: 15000000, task_total: 12, progress: 90, region: ["zhejiang", "ningbo"], created_at: "2025-04-18 16:45:00" },
|
|
229
|
+
{ id: 5, name: "北辰监控", level: "A", owner: "沈舟", status: STATUS_ENABLE, budget: 73000000, task_total: 38, progress: 58, region: ["guangdong", "guangzhou"], created_at: "2025-05-09 11:15:00" },
|
|
230
|
+
{ id: 6, name: "白泽知识库", level: "S", owner: "叶蓁", status: STATUS_ENABLE, budget: 156000000, task_total: 52, progress: 47, region: ["zhejiang", "hangzhou"], created_at: "2025-06-01 08:40:00" },
|
|
231
|
+
{ id: 7, name: "惊蛰调度", level: "B", owner: "江离", status: STATUS_DISABLE, budget: 38000000, task_total: 22, progress: 20, region: ["sichuan", "chengdu"], created_at: "2025-06-25 13:30:00" },
|
|
232
|
+
{ id: 8, name: "云阶存储", level: "C", owner: "温叙", status: STATUS_ENABLE, budget: 21000000, task_total: 16, progress: 73, region: ["zhejiang", "hangzhou"], created_at: "2025-07-14 15:10:00" },
|
|
233
|
+
{ id: 9, name: "听雨日志", level: "B", owner: "白鹭", status: STATUS_ENABLE, budget: 34000000, task_total: 24, progress: 66, region: ["guangdong", "shenzhen"], created_at: "2025-08-03 09:55:00" },
|
|
234
|
+
{ id: 10, name: "扶摇发布", level: "A", owner: "祝余", status: STATUS_ENABLE, budget: 89000000, task_total: 41, progress: 51, region: ["zhejiang", "ningbo"], created_at: "2025-08-20 10:25:00" },
|
|
235
|
+
{ id: 11, name: "沧海备份", level: "C", owner: "陈默", status: STATUS_DISABLE, budget: 12000000, task_total: 9, progress: 15, region: ["sichuan", "chengdu"], created_at: "2025-09-01 14:00:00" },
|
|
236
|
+
{ id: 12, name: "照夜网盘", level: "B", owner: "苏辞", status: STATUS_ENABLE, budget: 45000000, task_total: 27, progress: 88, region: ["guangdong", "guangzhou"], created_at: "2025-09-12 17:35:00" }
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
/** 目录树静态数据:三层嵌套演示树形表格的展开、折叠与子级操作。 */
|
|
240
|
+
export const demoCatalogTree: DemoCatalog[] = [
|
|
241
|
+
{
|
|
242
|
+
id: 1,
|
|
243
|
+
name: "产品文档",
|
|
244
|
+
code: "prod-doc",
|
|
245
|
+
owner: "沈舟",
|
|
246
|
+
status: STATUS_ENABLE,
|
|
247
|
+
doc_count: 32,
|
|
248
|
+
children: [
|
|
249
|
+
{
|
|
250
|
+
id: 11,
|
|
251
|
+
name: "需求说明",
|
|
252
|
+
code: "prod-doc-req",
|
|
253
|
+
owner: "叶蓁",
|
|
254
|
+
status: STATUS_ENABLE,
|
|
255
|
+
doc_count: 12,
|
|
256
|
+
children: [
|
|
257
|
+
{ id: 111, name: "V3 需求合集", code: "prod-doc-req-v3", owner: "叶蓁", status: STATUS_ENABLE, doc_count: 8 },
|
|
258
|
+
{ id: 112, name: "历史归档", code: "prod-doc-req-arch", owner: "江离", status: STATUS_DISABLE, doc_count: 4 }
|
|
259
|
+
]
|
|
260
|
+
},
|
|
261
|
+
{ id: 12, name: "设计稿说明", code: "prod-doc-ui", owner: "祝余", status: STATUS_ENABLE, doc_count: 20 }
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
id: 2,
|
|
266
|
+
name: "技术文档",
|
|
267
|
+
code: "tech-doc",
|
|
268
|
+
owner: "陈默",
|
|
269
|
+
status: STATUS_ENABLE,
|
|
270
|
+
doc_count: 58,
|
|
271
|
+
children: [
|
|
272
|
+
{ id: 21, name: "架构设计", code: "tech-doc-arch", owner: "苏辞", status: STATUS_ENABLE, doc_count: 15 },
|
|
273
|
+
{ id: 22, name: "接口文档", code: "tech-doc-api", owner: "顾言", status: STATUS_ENABLE, doc_count: 36 },
|
|
274
|
+
{ id: 23, name: "运维手册", code: "tech-doc-ops", owner: "白鹭", status: STATUS_DISABLE, doc_count: 7 }
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
{ id: 3, name: "测试文档", code: "qa-doc", owner: "林晚", status: STATUS_ENABLE, doc_count: 21 },
|
|
278
|
+
{ id: 4, name: "废弃目录", code: "deprecated", owner: "温叙", status: STATUS_DISABLE, doc_count: 0 }
|
|
279
|
+
];
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Demo 页面二:纯表格(标准 Table 基准页,ProTable 全量能力展示)。
|
|
3
|
+
|
|
4
|
+
本页演示要点(对照 core/src/components/ProTable/interface/index.ts 阅读):
|
|
5
|
+
- 列类型:type: "selection" 多选列(radio 单选在“左树右表”页演示);
|
|
6
|
+
- 预置单元格:cellType: "money" 金额列、"actions" 操作列;
|
|
7
|
+
- 标签列:tag: true + enum 的 tagType,按枚举值渲染 el-tag;
|
|
8
|
+
- 多级表头:_children 嵌套出“任务情况”分组表头;
|
|
9
|
+
- 自定义渲染:render 渲染进度条单元格、headerRender 渲染带提示的表头;
|
|
10
|
+
- 搜索区:演示 input / input-number / select / select-v2 / tree-select / cascader /
|
|
11
|
+
date-picker / time-picker / time-select / radio / switch / slider 十二种控件
|
|
12
|
+
(tenant-select 需要租户接口授权,静态页不演示,用法与表单内一致);
|
|
13
|
+
部分搜索项绑定 isShow: false 的隐藏列,说明“搜索字段不必是可见列”;
|
|
14
|
+
- 组件级:toolButton 数组形态、border、headerActions 批量操作、requestApi 静态分页模拟。
|
|
15
|
+
|
|
16
|
+
requestApi 真实写法(本页用本地过滤模拟):
|
|
17
|
+
const data = await defXxxService.PageXxx({ ...buildPageRequest(params), ...筛选 });
|
|
18
|
+
return { data: { list: data.list ?? [], total: data.total } };
|
|
19
|
+
-->
|
|
20
|
+
<template>
|
|
21
|
+
<div class="table-box">
|
|
22
|
+
<ProTable
|
|
23
|
+
ref="proTable"
|
|
24
|
+
row-key="id"
|
|
25
|
+
border
|
|
26
|
+
:columns="columns"
|
|
27
|
+
:header-actions="headerActions"
|
|
28
|
+
:tool-button="['refresh', 'setting', 'search']"
|
|
29
|
+
:request-api="requestProjectTable"
|
|
30
|
+
:request-auto="true"
|
|
31
|
+
/>
|
|
32
|
+
|
|
33
|
+
<DemoFormDialog ref="formDialogRef" />
|
|
34
|
+
<DemoDetailDrawer v-model="detailVisible" :detail="detailModel" />
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup lang="ts">
|
|
39
|
+
import { computed, h, ref } from "vue";
|
|
40
|
+
import { ElMessage, ElMessageBox, ElProgress, ElTooltip } from "element-plus";
|
|
41
|
+
import { CirclePlus, Delete, EditPen, QuestionFilled, View } from "@element-plus/icons-vue";
|
|
42
|
+
import type { ColumnProps, HeaderActionProps, ProTableInstance } from "../../../components/ProTable/interface";
|
|
43
|
+
import ProTable from "../../../components/ProTable";
|
|
44
|
+
import { t } from "../../../locales";
|
|
45
|
+
|
|
46
|
+
import DemoFormDialog from "../components/DemoFormDialog.vue";
|
|
47
|
+
import DemoDetailDrawer from "../components/DemoDetailDrawer.vue";
|
|
48
|
+
import type { DemoDetailModel, DemoProject } from "../demo-data";
|
|
49
|
+
import { STATUS_DISABLE, STATUS_ENABLE, demoLevelOptions, demoProjects, demoRegionTree } from "../demo-data";
|
|
50
|
+
|
|
51
|
+
defineOptions({
|
|
52
|
+
name: "DemoTable",
|
|
53
|
+
inheritAttrs: false
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const proTable = ref<ProTableInstance>();
|
|
57
|
+
const formDialogRef = ref<InstanceType<typeof DemoFormDialog>>();
|
|
58
|
+
const detailVisible = ref(false);
|
|
59
|
+
const detailModel = ref<DemoDetailModel | null>(null);
|
|
60
|
+
|
|
61
|
+
/** 项目本地数据副本:删除操作在这份副本上进行,真实项目调用 RPC 后刷新表格。 */
|
|
62
|
+
const projectList = ref<DemoProject[]>([...demoProjects]);
|
|
63
|
+
|
|
64
|
+
/** 状态枚举选项:tagType 决定标签颜色,同时供搜索下拉复用。 */
|
|
65
|
+
const statusTagOptions = [
|
|
66
|
+
{ label: t("common.status.enabled"), value: STATUS_ENABLE, tagType: "success" },
|
|
67
|
+
{ label: t("common.status.disabled"), value: STATUS_DISABLE, tagType: "info" }
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
/** select-v2 大数据下拉的静态选项(isShow: false,仅出现在搜索区)。 */
|
|
71
|
+
const tagSearchOptions = Array.from({ length: 50 }, (_, index) => ({ label: t("core.demo.table.tag_item", { index: index + 1 }), value: `tag-${index + 1}` }));
|
|
72
|
+
|
|
73
|
+
/** tree-select 搜索项的静态团队树(isShow: false,仅出现在搜索区)。 */
|
|
74
|
+
const ownerGroupOptions = demoRegionTree;
|
|
75
|
+
|
|
76
|
+
/** 把级联编码翻译成“省 / 市”文本,用于 region 列单元格展示。 */
|
|
77
|
+
function formatRegion(region: string[]): string {
|
|
78
|
+
const names: string[] = [];
|
|
79
|
+
for (const code of region) {
|
|
80
|
+
for (const province of demoRegionTree) {
|
|
81
|
+
if (province.value === code) names.push(province.label);
|
|
82
|
+
const city = province.children.find(item => item.value === code);
|
|
83
|
+
if (city) names.push(city.label);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return names.join(" / ");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 表格列配置:搜索项 order 从大到小排列,
|
|
91
|
+
* 未配置 order 的搜索项按列定义顺序排在后面。
|
|
92
|
+
*/
|
|
93
|
+
const columns = computed<ColumnProps[]>(() => [
|
|
94
|
+
// 多选列:配合 headerActions 的批量删除(selectedList)使用
|
|
95
|
+
{ type: "selection", width: 55 },
|
|
96
|
+
{ prop: "name", label: t("core.demo.table.field.name"), minWidth: 160, search: { el: "input", order: 8 } },
|
|
97
|
+
{
|
|
98
|
+
// 标签列演示:tag: true 后按 enum 里的 tagType 渲染 el-tag
|
|
99
|
+
prop: "level",
|
|
100
|
+
label: t("core.demo.table.field.level"),
|
|
101
|
+
width: 90,
|
|
102
|
+
align: "center",
|
|
103
|
+
tag: true,
|
|
104
|
+
enum: demoLevelOptions,
|
|
105
|
+
search: { el: "radio", enum: demoLevelOptions, order: 6 }
|
|
106
|
+
},
|
|
107
|
+
{ prop: "owner", label: t("core.demo.table.field.owner"), minWidth: 100 },
|
|
108
|
+
{
|
|
109
|
+
prop: "status",
|
|
110
|
+
label: t("common.field.status"),
|
|
111
|
+
minWidth: 90,
|
|
112
|
+
align: "center",
|
|
113
|
+
tag: true,
|
|
114
|
+
enum: statusTagOptions,
|
|
115
|
+
search: { el: "select", enum: statusTagOptions, order: 7 }
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
// 金额列演示:cellType: "money",suffix 拼在金额后
|
|
119
|
+
prop: "budget",
|
|
120
|
+
label: t("core.demo.table.field.budget"),
|
|
121
|
+
minWidth: 130,
|
|
122
|
+
align: "right",
|
|
123
|
+
cellType: "money",
|
|
124
|
+
moneyProps: { prefix: "¥", suffix: t("core.demo.table.money_unit") }
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
// 多级表头:_children 嵌套的列渲染在“任务情况”分组下
|
|
128
|
+
prop: "task_group",
|
|
129
|
+
label: t("core.demo.table.group.task"),
|
|
130
|
+
align: "center",
|
|
131
|
+
_children: [
|
|
132
|
+
{
|
|
133
|
+
prop: "task_total",
|
|
134
|
+
label: t("core.demo.table.field.task_total"),
|
|
135
|
+
minWidth: 110,
|
|
136
|
+
search: { el: "input-number", props: { min: 0, max: 999 }, order: 5 }
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
// 自定义单元格渲染:render 返回 VNode,这里用 el-progress 画进度条
|
|
140
|
+
prop: "progress",
|
|
141
|
+
label: t("core.demo.table.field.progress"),
|
|
142
|
+
minWidth: 150,
|
|
143
|
+
search: { el: "slider", props: { min: 0, max: 100, range: true }, order: 4 },
|
|
144
|
+
headerRender: () =>
|
|
145
|
+
// 自定义表头渲染:列名后追加提示图标
|
|
146
|
+
h("span", { style: "display:inline-flex;align-items:center;gap:4px" }, [
|
|
147
|
+
t("core.demo.table.field.progress"),
|
|
148
|
+
h(ElTooltip, { content: t("core.demo.table.tooltip.progress"), placement: "top" }, () =>
|
|
149
|
+
h(QuestionFilled, { style: "width:14px;height:14px;color:var(--el-text-color-secondary)" })
|
|
150
|
+
)
|
|
151
|
+
]),
|
|
152
|
+
render: scope =>
|
|
153
|
+
h(ElProgress, {
|
|
154
|
+
percentage: Number((scope.row as DemoProject).progress) || 0,
|
|
155
|
+
strokeWidth: 8,
|
|
156
|
+
textInside: true
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
// 普通自定义渲染:把级联编码格式化为“省 / 市”文本
|
|
163
|
+
prop: "region",
|
|
164
|
+
label: t("core.demo.table.field.region"),
|
|
165
|
+
minWidth: 160,
|
|
166
|
+
search: {
|
|
167
|
+
el: "cascader",
|
|
168
|
+
props: { options: demoRegionTree, clearable: true, placeholder: t("common.placeholder.select") },
|
|
169
|
+
order: 3
|
|
170
|
+
},
|
|
171
|
+
render: scope => formatRegion((scope.row as DemoProject).region)
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
prop: "created_at",
|
|
175
|
+
label: t("common.field.created_at"),
|
|
176
|
+
minWidth: 170,
|
|
177
|
+
align: "center",
|
|
178
|
+
search: {
|
|
179
|
+
el: "date-picker",
|
|
180
|
+
props: { type: "daterange", valueFormat: "YYYY-MM-DD", startPlaceholder: t("common.placeholder.start_date"), endPlaceholder: t("common.placeholder.end_date") },
|
|
181
|
+
order: 2
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
// ── 以下列 isShow: false,只出现在搜索区,演示“搜索字段不必是可见列” ──
|
|
185
|
+
{
|
|
186
|
+
// select-v2:虚拟列表下拉,适合大数据量选项
|
|
187
|
+
prop: "tags",
|
|
188
|
+
label: t("core.demo.table.field.tags"),
|
|
189
|
+
isShow: false,
|
|
190
|
+
search: { el: "select-v2", enum: tagSearchOptions, props: { clearable: true, filterable: true }, order: 1 }
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
// tree-select:树形下拉搜索
|
|
194
|
+
prop: "owner_group",
|
|
195
|
+
label: t("core.demo.table.field.owner_group"),
|
|
196
|
+
isShow: false,
|
|
197
|
+
search: { el: "tree-select", enum: ownerGroupOptions, props: { clearable: true }, order: 1 }
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
// time-picker:时间范围
|
|
201
|
+
prop: "updated_at",
|
|
202
|
+
label: t("common.field.updated_at"),
|
|
203
|
+
isShow: false,
|
|
204
|
+
search: { el: "time-picker", props: { valueFormat: "HH:mm:ss" }, order: 1 }
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
// time-select:单时间下拉
|
|
208
|
+
prop: "start_time",
|
|
209
|
+
label: t("common.field.start_time"),
|
|
210
|
+
isShow: false,
|
|
211
|
+
search: { el: "time-select", props: { start: "08:00", end: "22:00", step: "00:30" }, order: 1 }
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
// switch:布尔开关搜索,defaultValue 演示搜索默认值
|
|
215
|
+
prop: "enabled",
|
|
216
|
+
label: t("core.demo.table.field.enabled"),
|
|
217
|
+
isShow: false,
|
|
218
|
+
search: { el: "switch", defaultValue: undefined, order: 1 }
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
// 操作列:详情 / 编辑 / 删除
|
|
222
|
+
prop: "operation",
|
|
223
|
+
label: t("common.field.operation"),
|
|
224
|
+
align: "center",
|
|
225
|
+
cellType: "actions",
|
|
226
|
+
fixed: "right",
|
|
227
|
+
actions: [
|
|
228
|
+
{
|
|
229
|
+
label: t("common.action.detail"),
|
|
230
|
+
type: "primary",
|
|
231
|
+
link: true,
|
|
232
|
+
icon: View,
|
|
233
|
+
onClick: scope => handleOpenDetail(scope.row as DemoProject)
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
label: t("common.action.edit"),
|
|
237
|
+
type: "primary",
|
|
238
|
+
link: true,
|
|
239
|
+
icon: EditPen,
|
|
240
|
+
onClick: scope => handleEdit(scope.row as DemoProject)
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
label: t("common.action.delete"),
|
|
244
|
+
type: "danger",
|
|
245
|
+
link: true,
|
|
246
|
+
icon: Delete,
|
|
247
|
+
onClick: scope => handleDelete(scope.row as DemoProject)
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
]);
|
|
252
|
+
|
|
253
|
+
/** 顶部按钮:新增打开全组件表单弹窗,批量删除要求先勾选行。 */
|
|
254
|
+
const headerActions = computed<HeaderActionProps[]>(() => [
|
|
255
|
+
{
|
|
256
|
+
label: t("common.action.create"),
|
|
257
|
+
type: "success",
|
|
258
|
+
icon: CirclePlus,
|
|
259
|
+
onClick: () => formDialogRef.value?.open()
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
label: t("common.action.delete"),
|
|
263
|
+
type: "danger",
|
|
264
|
+
icon: Delete,
|
|
265
|
+
// disabled 回调拿到 HeaderActionScope,未勾选时置灰
|
|
266
|
+
disabled: scope => !scope.selectedList.length,
|
|
267
|
+
onClick: scope => handleDelete(scope.selectedList as DemoProject[])
|
|
268
|
+
}
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* 静态模拟分页请求:本地实现搜索 + 分页。
|
|
273
|
+
* 演示了常见搜索参数的取值形态:区间日期为数组、级联为数组、
|
|
274
|
+
* 范围滑杆为数组、开关为布尔,真实项目直接透传给后端即可。
|
|
275
|
+
*/
|
|
276
|
+
async function requestProjectTable(params: Record<string, any>) {
|
|
277
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
278
|
+
const pagination = params.pagination ?? {};
|
|
279
|
+
const page = Number(pagination.page_num ?? 1);
|
|
280
|
+
const size = Number(pagination.page_size ?? 10);
|
|
281
|
+
let list = [...projectList.value];
|
|
282
|
+
if (params.name) list = list.filter(item => item.name.includes(params.name));
|
|
283
|
+
if (params.level) list = list.filter(item => item.level === params.level);
|
|
284
|
+
if (params.status !== undefined && params.status !== null && params.status !== "") {
|
|
285
|
+
list = list.filter(item => item.status === params.status);
|
|
286
|
+
}
|
|
287
|
+
if (params.task_total !== undefined && params.task_total !== null && params.task_total !== "") {
|
|
288
|
+
list = list.filter(item => item.task_total >= Number(params.task_total));
|
|
289
|
+
}
|
|
290
|
+
// 级联搜索:选中到市则精确匹配,仅选省则按首段匹配
|
|
291
|
+
if (Array.isArray(params.region) && params.region.length) {
|
|
292
|
+
list = list.filter(
|
|
293
|
+
item => item.region.slice(0, params.region.length).join("/") === params.region.join("/")
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
if (Array.isArray(params.progress) && params.progress.length === 2) {
|
|
297
|
+
const [min, max] = params.progress;
|
|
298
|
+
list = list.filter(item => item.progress >= min && item.progress <= max);
|
|
299
|
+
}
|
|
300
|
+
if (Array.isArray(params.created_at) && params.created_at.length === 2) {
|
|
301
|
+
const [start, end] = params.created_at;
|
|
302
|
+
list = list.filter(item => item.created_at.slice(0, 10) >= start && item.created_at.slice(0, 10) <= end);
|
|
303
|
+
}
|
|
304
|
+
return { data: { list: list.slice((page - 1) * size, page * size), total: list.length } };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** 打开编辑弹窗:把行数据回填进共享表单。 */
|
|
308
|
+
function handleEdit(row: DemoProject) {
|
|
309
|
+
formDialogRef.value?.open({
|
|
310
|
+
name: row.name,
|
|
311
|
+
level: row.level,
|
|
312
|
+
visibility: row.status === STATUS_ENABLE ? "public" : "private",
|
|
313
|
+
count: row.task_total,
|
|
314
|
+
range: [row.created_at, row.created_at]
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** 组装详情模型并打开抽屉。 */
|
|
319
|
+
function handleOpenDetail(row: DemoProject) {
|
|
320
|
+
const levelOption = demoLevelOptions.find(item => item.value === row.level);
|
|
321
|
+
detailModel.value = {
|
|
322
|
+
title: `${t("core.demo.resource.project")} · ${row.name}`,
|
|
323
|
+
sections: [
|
|
324
|
+
{
|
|
325
|
+
title: t("core.demo.detail.section.basic"),
|
|
326
|
+
fields: [
|
|
327
|
+
{ label: t("core.demo.table.field.name"), value: row.name },
|
|
328
|
+
{ label: t("core.demo.table.field.level"), value: levelOption?.label ?? row.level, tag: true, tagType: (levelOption?.tagType as "success" | "info" | "warning" | "danger") ?? "info" },
|
|
329
|
+
{ label: t("core.demo.table.field.owner"), value: row.owner },
|
|
330
|
+
{ label: t("common.field.status"), value: row.status === STATUS_ENABLE ? t("common.status.enabled") : t("common.status.disabled"), tag: true, tagType: row.status === STATUS_ENABLE ? "success" : "info" },
|
|
331
|
+
{ label: t("core.demo.table.field.budget"), value: `¥ ${(row.budget / 100).toLocaleString()}` },
|
|
332
|
+
{ label: t("core.demo.table.field.region"), value: formatRegion(row.region) },
|
|
333
|
+
{ label: t("common.field.created_at"), value: row.created_at }
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
title: t("core.demo.table.group.task"),
|
|
338
|
+
fields: [
|
|
339
|
+
{ label: t("core.demo.table.field.task_total"), value: String(row.task_total) },
|
|
340
|
+
{ label: t("core.demo.table.field.progress"), value: `${row.progress}%` }
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
],
|
|
344
|
+
steps: [
|
|
345
|
+
{ title: t("core.demo.detail.step.create"), description: row.created_at.slice(0, 10) },
|
|
346
|
+
{ title: t("core.demo.detail.step.review"), description: "--" },
|
|
347
|
+
{ title: t("core.demo.detail.step.publish"), description: "--" },
|
|
348
|
+
{ title: t("core.demo.detail.step.done"), description: "--" }
|
|
349
|
+
],
|
|
350
|
+
timeline: [
|
|
351
|
+
{ title: t("core.demo.detail.timeline.created"), timestamp: row.created_at, type: "primary" },
|
|
352
|
+
{ title: t("core.demo.detail.timeline.updated"), timestamp: "2026-02-10 09:00:00", type: "success" },
|
|
353
|
+
{
|
|
354
|
+
title: row.status === STATUS_ENABLE ? t("core.demo.detail.timeline.enabled") : t("core.demo.detail.timeline.disabled"),
|
|
355
|
+
timestamp: "2026-04-01 14:20:00",
|
|
356
|
+
type: row.status === STATUS_ENABLE ? "success" : "danger"
|
|
357
|
+
}
|
|
358
|
+
],
|
|
359
|
+
raw: { ...row }
|
|
360
|
+
};
|
|
361
|
+
detailVisible.value = true;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* 删除项目:兼容“单行对象 / 勾选数组”两种入参(与真实页面写法一致),
|
|
366
|
+
* 确认后从本地副本移除并刷新表格。
|
|
367
|
+
*/
|
|
368
|
+
function handleDelete(selected: DemoProject | DemoProject[]) {
|
|
369
|
+
const rows = Array.isArray(selected) ? selected : [selected];
|
|
370
|
+
const confirmMessage =
|
|
371
|
+
rows.length === 1
|
|
372
|
+
? `${t("common.dialog.delete_single", { resource: t("core.demo.resource.project") })}\n${t("common.dialog.resource_field", {
|
|
373
|
+
field: t("core.demo.table.field.name"),
|
|
374
|
+
value: rows[0].name
|
|
375
|
+
})}`
|
|
376
|
+
: t("common.dialog.delete_batch", { count: rows.length, unit: "", resource: t("core.demo.resource.project") });
|
|
377
|
+
ElMessageBox.confirm(confirmMessage, t("common.title.warning"), {
|
|
378
|
+
confirmButtonText: t("common.action.confirm"),
|
|
379
|
+
cancelButtonText: t("common.action.cancel"),
|
|
380
|
+
type: "warning"
|
|
381
|
+
}).then(
|
|
382
|
+
() => {
|
|
383
|
+
const ids = new Set(rows.map(row => row.id));
|
|
384
|
+
projectList.value = projectList.value.filter(item => !ids.has(item.id));
|
|
385
|
+
ElMessage.success(t("common.message.delete_success", { resource: t("core.demo.resource.project") }));
|
|
386
|
+
proTable.value?.getTableList();
|
|
387
|
+
},
|
|
388
|
+
() => ElMessage.info(t("common.dialog.cancel_delete", { resource: t("core.demo.resource.project") }))
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
</script>
|