xto-fronted 0.4.72 → 0.4.74
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/index-BcEjdbz_.js +515 -0
- package/dist/index-CWMpaJJ6.js +3267 -0
- package/dist/index-DkHXkwpw.js +479 -0
- package/dist/index-Pg_OaPt4.js +641 -0
- package/dist/index-dVHlrUjM.js +189 -0
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/App.vue +30 -1
- package/src/assets/styles/_root.scss +141 -97
- package/src/assets/styles/_variables.scss +44 -19
- package/src/assets/styles/index.scss +267 -42
- package/src/views/dashboard/index.vue +417 -155
- package/src/views/error/403.vue +251 -56
- package/src/views/error/404.vue +253 -56
- package/src/views/login/index.vue +586 -194
- package/src/views/system/menu/index.vue +403 -94
- package/src/views/system/role/index.vue +348 -69
- package/src/views/system/user/index.vue +402 -73
- package/dist/index-48G2-eqi.js +0 -475
- package/dist/index-BhtcPIRK.js +0 -3169
- package/dist/index-CZKP8fOP.js +0 -372
- package/dist/index-JouxgO84.js +0 -142
- package/dist/index-qlKXxfT9.js +0 -345
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, reactive, computed, onMounted } from 'vue'
|
|
3
3
|
import { Form, FormItem, Input, Select, Switch } from '@xto/form'
|
|
4
|
-
import { Tag,
|
|
4
|
+
import { Tag, Pagination } from '@xto/data'
|
|
5
5
|
import { Modal, Message, Popconfirm } from '@xto/feedback'
|
|
6
6
|
import { Space, Button } from '@xto/base'
|
|
7
7
|
import { Status, StatusOptions } from '@/enums'
|
|
@@ -132,6 +132,11 @@ const handleSubmit = async () => {
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
// 状态切换
|
|
136
|
+
const handleStatusChange = (row: Role) => {
|
|
137
|
+
Message.success(`已${row.status === Status.ENABLED ? '启用' : '禁用'}角色 ${row.name}`)
|
|
138
|
+
}
|
|
139
|
+
|
|
135
140
|
onMounted(() => {
|
|
136
141
|
getRoleList()
|
|
137
142
|
})
|
|
@@ -140,8 +145,8 @@ onMounted(() => {
|
|
|
140
145
|
<template>
|
|
141
146
|
<div class="role-page">
|
|
142
147
|
<!-- 搜索栏 -->
|
|
143
|
-
<
|
|
144
|
-
<Form :model="searchForm" inline>
|
|
148
|
+
<div class="search-section">
|
|
149
|
+
<Form :model="searchForm" inline class="search-form">
|
|
145
150
|
<FormItem label="关键词">
|
|
146
151
|
<Input
|
|
147
152
|
v-model="searchForm.keyword"
|
|
@@ -160,64 +165,145 @@ onMounted(() => {
|
|
|
160
165
|
</FormItem>
|
|
161
166
|
<FormItem>
|
|
162
167
|
<Space>
|
|
163
|
-
<Button type="primary" @click="handleSearch"
|
|
164
|
-
|
|
168
|
+
<Button type="primary" @click="handleSearch">
|
|
169
|
+
<template #icon>
|
|
170
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
171
|
+
<circle cx="11" cy="11" r="8"/>
|
|
172
|
+
<path d="M21 21l-4.35-4.35"/>
|
|
173
|
+
</svg>
|
|
174
|
+
</template>
|
|
175
|
+
搜索
|
|
176
|
+
</Button>
|
|
177
|
+
<Button @click="handleReset">
|
|
178
|
+
<template #icon>
|
|
179
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
180
|
+
<path d="M3 12a9 9 0 109-9 9.75 9.75 0 00-6.74 2.74L3 8"/>
|
|
181
|
+
<path d="M3 3v5h5"/>
|
|
182
|
+
</svg>
|
|
183
|
+
</template>
|
|
184
|
+
重置
|
|
185
|
+
</Button>
|
|
165
186
|
</Space>
|
|
166
187
|
</FormItem>
|
|
167
188
|
</Form>
|
|
168
|
-
</
|
|
189
|
+
</div>
|
|
169
190
|
|
|
170
191
|
<!-- 表格 -->
|
|
171
|
-
<
|
|
192
|
+
<div class="table-section">
|
|
172
193
|
<!-- 工具栏 -->
|
|
173
|
-
<div class="toolbar">
|
|
174
|
-
<
|
|
194
|
+
<div class="table-toolbar">
|
|
195
|
+
<div class="toolbar-left">
|
|
196
|
+
<Button type="primary" @click="handleAdd">
|
|
197
|
+
<template #icon>
|
|
198
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
199
|
+
<line x1="12" y1="5" x2="12" y2="19"/>
|
|
200
|
+
<line x1="5" y1="12" x2="19" y2="12"/>
|
|
201
|
+
</svg>
|
|
202
|
+
</template>
|
|
203
|
+
新增角色
|
|
204
|
+
</Button>
|
|
205
|
+
</div>
|
|
206
|
+
<div class="toolbar-right">
|
|
207
|
+
<span class="table-count">共 {{ total }} 条数据</span>
|
|
208
|
+
</div>
|
|
175
209
|
</div>
|
|
176
210
|
|
|
177
211
|
<!-- 表格 -->
|
|
178
|
-
<
|
|
179
|
-
<
|
|
180
|
-
<
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
<
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
<
|
|
201
|
-
<
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
212
|
+
<div class="table-wrapper">
|
|
213
|
+
<table class="data-table">
|
|
214
|
+
<thead>
|
|
215
|
+
<tr>
|
|
216
|
+
<th class="col-id">ID</th>
|
|
217
|
+
<th class="col-name">角色名称</th>
|
|
218
|
+
<th class="col-code">角色编码</th>
|
|
219
|
+
<th class="col-desc">描述</th>
|
|
220
|
+
<th class="col-status">状态</th>
|
|
221
|
+
<th class="col-time">创建时间</th>
|
|
222
|
+
<th class="col-actions">操作</th>
|
|
223
|
+
</tr>
|
|
224
|
+
</thead>
|
|
225
|
+
<tbody>
|
|
226
|
+
<tr v-if="loading">
|
|
227
|
+
<td colspan="7" class="loading-cell">
|
|
228
|
+
<div class="loading-content">
|
|
229
|
+
<div class="loading-spinner"></div>
|
|
230
|
+
<span>加载中...</span>
|
|
231
|
+
</div>
|
|
232
|
+
</td>
|
|
233
|
+
</tr>
|
|
234
|
+
<tr v-else-if="roleList.length === 0">
|
|
235
|
+
<td colspan="7" class="empty-cell">
|
|
236
|
+
<div class="empty-content">
|
|
237
|
+
<svg viewBox="0 0 64 41" fill="none">
|
|
238
|
+
<g transform="translate(0 1)">
|
|
239
|
+
<ellipse fill="#f5f5f5" cx="32" cy="33" rx="32" ry="7"/>
|
|
240
|
+
<g stroke="var(--color-text-placeholder)" stroke-width="2">
|
|
241
|
+
<path d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"/>
|
|
242
|
+
<path d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35H11.95C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" fill="var(--color-fill)"/>
|
|
243
|
+
</g>
|
|
244
|
+
</g>
|
|
245
|
+
</svg>
|
|
246
|
+
<span>暂无数据</span>
|
|
247
|
+
</div>
|
|
248
|
+
</td>
|
|
249
|
+
</tr>
|
|
250
|
+
<tr v-else v-for="row in roleList" :key="row.id" class="data-row">
|
|
251
|
+
<td class="col-id">
|
|
252
|
+
<span class="id-badge">{{ row.id }}</span>
|
|
253
|
+
</td>
|
|
254
|
+
<td class="col-name">
|
|
255
|
+
<span class="role-name">{{ row.name }}</span>
|
|
256
|
+
</td>
|
|
257
|
+
<td class="col-code">
|
|
258
|
+
<Tag type="primary" size="small">{{ row.code }}</Tag>
|
|
259
|
+
</td>
|
|
260
|
+
<td class="col-desc">
|
|
261
|
+
<span class="desc-text">{{ row.description }}</span>
|
|
262
|
+
</td>
|
|
263
|
+
<td class="col-status">
|
|
264
|
+
<div class="status-switch">
|
|
265
|
+
<Switch
|
|
266
|
+
:model-value="row.status === Status.ENABLED"
|
|
267
|
+
@update:model-value="row.status = $event ? Status.ENABLED : Status.DISABLED; handleStatusChange(row)"
|
|
268
|
+
/>
|
|
269
|
+
<span class="status-text" :class="{ enabled: row.status === Status.ENABLED }">
|
|
270
|
+
{{ row.status === Status.ENABLED ? '已启用' : '已禁用' }}
|
|
271
|
+
</span>
|
|
272
|
+
</div>
|
|
273
|
+
</td>
|
|
274
|
+
<td class="col-time">
|
|
275
|
+
<span class="time-text">{{ row.createTime }}</span>
|
|
276
|
+
</td>
|
|
277
|
+
<td class="col-actions">
|
|
278
|
+
<Space class="action-buttons">
|
|
279
|
+
<Button type="primary" link size="small" @click="handleEdit(row)">
|
|
280
|
+
<template #icon>
|
|
281
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
282
|
+
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
|
283
|
+
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
284
|
+
</svg>
|
|
285
|
+
</template>
|
|
286
|
+
编辑
|
|
287
|
+
</Button>
|
|
288
|
+
<Popconfirm title="确定删除该角色吗?" @confirm="handleDelete(row.id)">
|
|
289
|
+
<Button type="danger" link size="small">
|
|
290
|
+
<template #icon>
|
|
291
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
292
|
+
<polyline points="3,6 5,6 21,6"/>
|
|
293
|
+
<path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
|
|
294
|
+
<line x1="10" y1="11" x2="10" y2="17"/>
|
|
295
|
+
<line x1="14" y1="11" x2="14" y2="17"/>
|
|
296
|
+
</svg>
|
|
297
|
+
</template>
|
|
298
|
+
删除
|
|
299
|
+
</Button>
|
|
300
|
+
</Popconfirm>
|
|
301
|
+
</Space>
|
|
302
|
+
</td>
|
|
303
|
+
</tr>
|
|
304
|
+
</tbody>
|
|
305
|
+
</table>
|
|
306
|
+
</div>
|
|
221
307
|
|
|
222
308
|
<!-- 分页 -->
|
|
223
309
|
<div class="pagination-wrapper">
|
|
@@ -231,11 +317,11 @@ onMounted(() => {
|
|
|
231
317
|
@size-change="getRoleList"
|
|
232
318
|
/>
|
|
233
319
|
</div>
|
|
234
|
-
</
|
|
320
|
+
</div>
|
|
235
321
|
|
|
236
322
|
<!-- 编辑弹窗 -->
|
|
237
|
-
<Modal v-model="modalVisible" :title="modalTitle" width="
|
|
238
|
-
<Form ref="formRef" :model="formData" :rules="rules" label-width="80px">
|
|
323
|
+
<Modal v-model="modalVisible" :title="modalTitle" width="520px" class="role-modal">
|
|
324
|
+
<Form ref="formRef" :model="formData" :rules="rules" label-width="80px" class="role-form">
|
|
239
325
|
<FormItem label="角色名称" prop="name">
|
|
240
326
|
<Input v-model="formData.name" placeholder="请输入角色名称" />
|
|
241
327
|
</FormItem>
|
|
@@ -246,7 +332,10 @@ onMounted(() => {
|
|
|
246
332
|
<Input v-model="formData.description" placeholder="请输入描述" />
|
|
247
333
|
</FormItem>
|
|
248
334
|
<FormItem label="状态">
|
|
249
|
-
<
|
|
335
|
+
<div class="status-field">
|
|
336
|
+
<Switch v-model="formData.status" :active-value="Status.ENABLED" :inactive-value="Status.DISABLED" />
|
|
337
|
+
<span class="status-label">{{ formData.status === Status.ENABLED ? '启用' : '禁用' }}</span>
|
|
338
|
+
</div>
|
|
250
339
|
</FormItem>
|
|
251
340
|
</Form>
|
|
252
341
|
<template #footer>
|
|
@@ -261,44 +350,234 @@ onMounted(() => {
|
|
|
261
350
|
|
|
262
351
|
<style lang="scss" scoped>
|
|
263
352
|
.role-page {
|
|
264
|
-
padding:
|
|
353
|
+
padding: 24px;
|
|
354
|
+
background: var(--bg-color-page);
|
|
355
|
+
min-height: 100%;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// 搜索区域
|
|
359
|
+
.search-section {
|
|
360
|
+
background: var(--bg-color);
|
|
361
|
+
border-radius: var(--border-radius-large);
|
|
362
|
+
padding: 20px 24px;
|
|
363
|
+
margin-bottom: 16px;
|
|
364
|
+
box-shadow: var(--box-shadow-card);
|
|
265
365
|
|
|
266
|
-
.search-
|
|
267
|
-
|
|
366
|
+
.search-form {
|
|
367
|
+
display: flex;
|
|
368
|
+
flex-wrap: wrap;
|
|
369
|
+
gap: 16px;
|
|
370
|
+
|
|
371
|
+
:deep(.x-form-item) {
|
|
372
|
+
margin-bottom: 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
:deep(.x-input),
|
|
376
|
+
:deep(.x-select) {
|
|
377
|
+
width: 200px;
|
|
378
|
+
}
|
|
268
379
|
}
|
|
380
|
+
}
|
|
269
381
|
|
|
270
|
-
|
|
271
|
-
|
|
382
|
+
// 表格区域
|
|
383
|
+
.table-section {
|
|
384
|
+
background: var(--bg-color);
|
|
385
|
+
border-radius: var(--border-radius-large);
|
|
386
|
+
box-shadow: var(--box-shadow-card);
|
|
387
|
+
overflow: hidden;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.table-toolbar {
|
|
391
|
+
display: flex;
|
|
392
|
+
justify-content: space-between;
|
|
393
|
+
align-items: center;
|
|
394
|
+
padding: 16px 24px;
|
|
395
|
+
border-bottom: 1px solid var(--color-border-lighter);
|
|
396
|
+
|
|
397
|
+
.toolbar-left {
|
|
398
|
+
display: flex;
|
|
399
|
+
gap: 12px;
|
|
272
400
|
}
|
|
401
|
+
|
|
402
|
+
.table-count {
|
|
403
|
+
font-size: 14px;
|
|
404
|
+
color: var(--color-text-secondary);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.table-wrapper {
|
|
409
|
+
overflow-x: auto;
|
|
273
410
|
}
|
|
274
411
|
|
|
412
|
+
// 表格样式
|
|
275
413
|
.data-table {
|
|
276
414
|
width: 100%;
|
|
277
415
|
border-collapse: collapse;
|
|
278
416
|
|
|
279
417
|
th, td {
|
|
280
|
-
padding:
|
|
418
|
+
padding: 14px 16px;
|
|
281
419
|
text-align: left;
|
|
282
420
|
border-bottom: 1px solid var(--color-border-lighter);
|
|
283
421
|
}
|
|
284
422
|
|
|
285
423
|
th {
|
|
424
|
+
font-size: 14px;
|
|
286
425
|
font-weight: 500;
|
|
287
|
-
color: var(--color-text-
|
|
288
|
-
background
|
|
426
|
+
color: var(--color-text-secondary);
|
|
427
|
+
background: var(--color-fill-light);
|
|
428
|
+
white-space: nowrap;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.data-row {
|
|
432
|
+
transition: background-color 0.2s;
|
|
433
|
+
|
|
434
|
+
&:hover {
|
|
435
|
+
background: var(--color-primary-light-6);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
td {
|
|
440
|
+
vertical-align: middle;
|
|
289
441
|
}
|
|
290
442
|
|
|
291
443
|
.loading-cell,
|
|
292
444
|
.empty-cell {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
445
|
+
padding: 60px 20px;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.loading-content,
|
|
449
|
+
.empty-content {
|
|
450
|
+
display: flex;
|
|
451
|
+
flex-direction: column;
|
|
452
|
+
align-items: center;
|
|
453
|
+
gap: 16px;
|
|
454
|
+
color: var(--color-text-placeholder);
|
|
455
|
+
|
|
456
|
+
svg {
|
|
457
|
+
width: 64px;
|
|
458
|
+
height: 41px;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.loading-spinner {
|
|
463
|
+
width: 32px;
|
|
464
|
+
height: 32px;
|
|
465
|
+
border: 3px solid var(--color-border-lighter);
|
|
466
|
+
border-top-color: var(--color-primary);
|
|
467
|
+
border-radius: 50%;
|
|
468
|
+
animation: spin 0.8s linear infinite;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
@keyframes spin {
|
|
473
|
+
to { transform: rotate(360deg); }
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// 列样式
|
|
477
|
+
.col-id {
|
|
478
|
+
width: 80px;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.id-badge {
|
|
482
|
+
display: inline-block;
|
|
483
|
+
min-width: 32px;
|
|
484
|
+
padding: 4px 10px;
|
|
485
|
+
background: var(--color-fill);
|
|
486
|
+
border-radius: 12px;
|
|
487
|
+
font-size: 12px;
|
|
488
|
+
font-weight: 500;
|
|
489
|
+
color: var(--color-text-secondary);
|
|
490
|
+
text-align: center;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.col-name {
|
|
494
|
+
min-width: 120px;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.role-name {
|
|
498
|
+
font-size: 14px;
|
|
499
|
+
font-weight: 500;
|
|
500
|
+
color: var(--color-text-primary);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.col-code {
|
|
504
|
+
min-width: 100px;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.col-desc {
|
|
508
|
+
min-width: 150px;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.desc-text {
|
|
512
|
+
font-size: 14px;
|
|
513
|
+
color: var(--color-text-secondary);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.col-status {
|
|
517
|
+
min-width: 120px;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.status-switch {
|
|
521
|
+
display: flex;
|
|
522
|
+
align-items: center;
|
|
523
|
+
gap: 8px;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.status-text {
|
|
527
|
+
font-size: 13px;
|
|
528
|
+
color: var(--color-text-secondary);
|
|
529
|
+
|
|
530
|
+
&.enabled {
|
|
531
|
+
color: var(--color-success);
|
|
296
532
|
}
|
|
297
533
|
}
|
|
298
534
|
|
|
535
|
+
.col-time {
|
|
536
|
+
min-width: 160px;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.time-text {
|
|
540
|
+
font-size: 13px;
|
|
541
|
+
color: var(--color-text-secondary);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.col-actions {
|
|
545
|
+
min-width: 140px;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.action-buttons {
|
|
549
|
+
:deep(.x-button) {
|
|
550
|
+
padding: 4px 8px;
|
|
551
|
+
|
|
552
|
+
svg {
|
|
553
|
+
width: 14px;
|
|
554
|
+
height: 14px;
|
|
555
|
+
margin-right: 4px;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// 分页
|
|
299
561
|
.pagination-wrapper {
|
|
300
562
|
display: flex;
|
|
301
563
|
justify-content: flex-end;
|
|
302
|
-
|
|
564
|
+
padding: 16px 24px;
|
|
565
|
+
border-top: 1px solid var(--color-border-lighter);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// 弹窗表单
|
|
569
|
+
.role-form {
|
|
570
|
+
padding: 16px 0;
|
|
571
|
+
|
|
572
|
+
.status-field {
|
|
573
|
+
display: flex;
|
|
574
|
+
align-items: center;
|
|
575
|
+
gap: 12px;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.status-label {
|
|
579
|
+
font-size: 14px;
|
|
580
|
+
color: var(--color-text-secondary);
|
|
581
|
+
}
|
|
303
582
|
}
|
|
304
|
-
</style>
|
|
583
|
+
</style>
|