chore: import full Element Plus CSS, narrow action column, format
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d9f1a4d17e
commit
d88b807638
@ -1,3 +1,4 @@
|
|||||||
// 导入变量文件
|
// 导入变量文件
|
||||||
|
@use "element-plus/dist/index.css";
|
||||||
@use "./settings";
|
@use "./settings";
|
||||||
@use "./base";
|
@use "./base";
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ty-crud">
|
<div class="ty-crud">
|
||||||
<el-card v-if="searchSchema" class="ty-crud__search" shadow="never">
|
<el-card v-if="searchSchema" class="ty-crud__search" shadow="never">
|
||||||
<ty-search-form :schema="searchSchema" :model-value="query" @search="handleSearch" @reset="handleReset" />
|
<ty-search-form
|
||||||
|
:schema="searchSchema"
|
||||||
|
:model-value="query"
|
||||||
|
@search="handleSearch"
|
||||||
|
@reset="handleReset"
|
||||||
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card class="ty-crud__table" shadow="never">
|
<el-card class="ty-crud__table" shadow="never">
|
||||||
@ -27,30 +32,34 @@
|
|||||||
:actions-width="actionsWidth"
|
:actions-width="actionsWidth"
|
||||||
@selection-change="onSelectionChange"
|
@selection-change="onSelectionChange"
|
||||||
>
|
>
|
||||||
<template #actions="{ row }">
|
<template #actions="{ row }">
|
||||||
<el-button
|
<el-button
|
||||||
v-for="a in displayActions(row)"
|
v-for="a in displayActions(row)"
|
||||||
:key="a.label"
|
:key="a.label"
|
||||||
link
|
link
|
||||||
:type="a.type"
|
:type="a.type"
|
||||||
@click="a.onClick(row)"
|
@click="a.onClick(row)"
|
||||||
>
|
>
|
||||||
{{ a.label }}
|
{{ a.label }}
|
||||||
</el-button>
|
|
||||||
<el-dropdown v-if="overflowActions(row).length > 0" trigger="click" @command="handleCommand($event, row)">
|
|
||||||
<el-button link type="primary">
|
|
||||||
更多
|
|
||||||
<icon type="iconify" icon="mdi:chevron-down" />
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<template #dropdown>
|
<el-dropdown
|
||||||
<el-dropdown-menu>
|
v-if="overflowActions(row).length > 0"
|
||||||
<el-dropdown-item v-for="a in overflowActions(row)" :key="a.label" :command="a">
|
trigger="click"
|
||||||
{{ a.label }}
|
@command="handleCommand($event, row)"
|
||||||
</el-dropdown-item>
|
>
|
||||||
</el-dropdown-menu>
|
<el-button link type="primary">
|
||||||
</template>
|
更多
|
||||||
</el-dropdown>
|
<icon type="iconify" icon="mdi:chevron-down" />
|
||||||
</template>
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item v-for="a in overflowActions(row)" :key="a.label" :command="a">
|
||||||
|
{{ a.label }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
</ty-table>
|
</ty-table>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -71,7 +80,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, reactive, ref } from 'vue'
|
import { computed, onMounted, reactive, ref } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import type { CrudAction, CrudActionItem, JsonSchema, PageQuery, PageResult, TableColumn } from '@/types/crud'
|
import type {
|
||||||
|
CrudAction,
|
||||||
|
CrudActionItem,
|
||||||
|
JsonSchema,
|
||||||
|
PageQuery,
|
||||||
|
PageResult,
|
||||||
|
TableColumn,
|
||||||
|
} from '@/types/crud'
|
||||||
|
|
||||||
defineOptions({ name: 'TyCrud' })
|
defineOptions({ name: 'TyCrud' })
|
||||||
|
|
||||||
@ -115,7 +131,7 @@ const props = withDefaults(
|
|||||||
actions: () => ['edit', 'delete'],
|
actions: () => ['edit', 'delete'],
|
||||||
collapseCount: 2,
|
collapseCount: 2,
|
||||||
selection: false,
|
selection: false,
|
||||||
actionsWidth: 220,
|
actionsWidth: 140,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -204,7 +220,9 @@ async function handleSubmit(): Promise<void> {
|
|||||||
|
|
||||||
async function handleDelete(row: Record<string, any>): Promise<void> {
|
async function handleDelete(row: Record<string, any>): Promise<void> {
|
||||||
const name = row[props.nameKey] ?? ''
|
const name = row[props.nameKey] ?? ''
|
||||||
await ElMessageBox.confirm(`确认删除${props.entityName}「${name}」?`, '提示', { type: 'warning' })
|
await ElMessageBox.confirm(`确认删除${props.entityName}「${name}」?`, '提示', {
|
||||||
|
type: 'warning',
|
||||||
|
})
|
||||||
await props.remove(String(row[props.idKey]))
|
await props.remove(String(row[props.idKey]))
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
fetchList()
|
fetchList()
|
||||||
@ -213,7 +231,8 @@ async function handleDelete(row: Record<string, any>): Promise<void> {
|
|||||||
const resolvedActions = computed<CrudActionItem[]>(() =>
|
const resolvedActions = computed<CrudActionItem[]>(() =>
|
||||||
props.actions.map((a): CrudActionItem => {
|
props.actions.map((a): CrudActionItem => {
|
||||||
if (a === 'edit') return { label: '编辑', type: 'primary', onClick: (row) => openEdit(row) }
|
if (a === 'edit') return { label: '编辑', type: 'primary', onClick: (row) => openEdit(row) }
|
||||||
if (a === 'delete') return { label: '删除', type: 'danger', onClick: (row) => handleDelete(row) }
|
if (a === 'delete')
|
||||||
|
return { label: '删除', type: 'danger', onClick: (row) => handleDelete(row) }
|
||||||
return a
|
return a
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -16,7 +16,11 @@
|
|||||||
:edit-readonly-keys="['username']"
|
:edit-readonly-keys="['username']"
|
||||||
>
|
>
|
||||||
<template #toolbar-right="{ selectedRows }">
|
<template #toolbar-right="{ selectedRows }">
|
||||||
<el-button type="danger" :disabled="selectedRows.length === 0" @click="batchDelete(selectedRows)">
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
:disabled="selectedRows.length === 0"
|
||||||
|
@click="batchDelete(selectedRows)"
|
||||||
|
>
|
||||||
批量删除
|
批量删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@ -24,9 +28,16 @@
|
|||||||
|
|
||||||
<el-dialog v-model="resetPwd.visible" title="重置密码" width="420px" destroy-on-close>
|
<el-dialog v-model="resetPwd.visible" title="重置密码" width="420px" destroy-on-close>
|
||||||
<el-form label-width="80px">
|
<el-form label-width="80px">
|
||||||
<el-form-item label="用户名"><span>{{ resetPwd.username }}</span></el-form-item>
|
<el-form-item label="用户名"
|
||||||
|
><span>{{ resetPwd.username }}</span></el-form-item
|
||||||
|
>
|
||||||
<el-form-item label="新密码">
|
<el-form-item label="新密码">
|
||||||
<el-input v-model="resetPwd.password" type="password" show-password placeholder="请输入新密码" />
|
<el-input
|
||||||
|
v-model="resetPwd.password"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
placeholder="请输入新密码"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -54,7 +65,8 @@ const orgs = [
|
|||||||
{ code: 'sales', name: '销售部' },
|
{ code: 'sales', name: '销售部' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const orgName = (code: unknown): string => orgs.find((o) => o.code === code)?.name ?? (code as string) ?? '-'
|
const orgName = (code: unknown): string =>
|
||||||
|
orgs.find((o) => o.code === code)?.name ?? (code as string) ?? '-'
|
||||||
|
|
||||||
const columns: TableColumn[] = [
|
const columns: TableColumn[] = [
|
||||||
{ prop: 'username', label: '用户名', minWidth: 110 },
|
{ prop: 'username', label: '用户名', minWidth: 110 },
|
||||||
@ -136,16 +148,106 @@ interface UserRow {
|
|||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
const day = 24 * 60 * 60 * 1000
|
const day = 24 * 60 * 60 * 1000
|
||||||
const users: UserRow[] = [
|
const users: UserRow[] = [
|
||||||
{ id: '1', username: 'touyun', nickname: '超级管理员', email: 'touyun@example.com', phone: '13800000001', status: 'enabled', orgCode: 'touyun', createdAt: now - 30 * day },
|
{
|
||||||
{ id: '2', username: 'zhangsan', nickname: '张三', email: 'zhangsan@example.com', phone: '13800000002', status: 'enabled', orgCode: 'rd', createdAt: now - 20 * day },
|
id: '1',
|
||||||
{ id: '3', username: 'lisi', nickname: '李四', email: 'lisi@example.com', phone: '13800000003', status: 'disabled', orgCode: 'rd', createdAt: now - 18 * day },
|
username: 'touyun',
|
||||||
{ id: '4', username: 'wangwu', nickname: '王五', email: 'wangwu@example.com', phone: '13800000004', status: 'locked', orgCode: 'ops', createdAt: now - 15 * day },
|
nickname: '超级管理员',
|
||||||
{ id: '5', username: 'zhaoliu', nickname: '赵六', email: 'zhaoliu@example.com', phone: '13800000005', status: 'enabled', orgCode: 'sales', createdAt: now - 12 * day },
|
email: 'touyun@example.com',
|
||||||
{ id: '6', username: 'sunqi', nickname: '孙七', email: 'sunqi@example.com', phone: '13800000006', status: 'enabled', orgCode: 'ops', createdAt: now - 9 * day },
|
phone: '13800000001',
|
||||||
{ id: '7', username: 'zhouba', nickname: '周八', email: 'zhouba@example.com', phone: '13800000007', status: 'enabled', orgCode: 'rd', createdAt: now - 7 * day },
|
status: 'enabled',
|
||||||
{ id: '8', username: 'wujiu', nickname: '吴九', email: 'wujiu@example.com', phone: '13800000008', status: 'disabled', orgCode: 'sales', createdAt: now - 5 * day },
|
orgCode: 'touyun',
|
||||||
{ id: '9', username: 'zhengshi', nickname: '郑十', email: 'zhengshi@example.com', phone: '13800000009', status: 'enabled', orgCode: 'rd', createdAt: now - 3 * day },
|
createdAt: now - 30 * day,
|
||||||
{ id: '10', username: 'chenyi', nickname: '陈一', email: 'chenyi@example.com', phone: '13800000010', status: 'enabled', orgCode: 'sales', createdAt: now - 1 * day },
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
username: 'zhangsan',
|
||||||
|
nickname: '张三',
|
||||||
|
email: 'zhangsan@example.com',
|
||||||
|
phone: '13800000002',
|
||||||
|
status: 'enabled',
|
||||||
|
orgCode: 'rd',
|
||||||
|
createdAt: now - 20 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
username: 'lisi',
|
||||||
|
nickname: '李四',
|
||||||
|
email: 'lisi@example.com',
|
||||||
|
phone: '13800000003',
|
||||||
|
status: 'disabled',
|
||||||
|
orgCode: 'rd',
|
||||||
|
createdAt: now - 18 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
username: 'wangwu',
|
||||||
|
nickname: '王五',
|
||||||
|
email: 'wangwu@example.com',
|
||||||
|
phone: '13800000004',
|
||||||
|
status: 'locked',
|
||||||
|
orgCode: 'ops',
|
||||||
|
createdAt: now - 15 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
username: 'zhaoliu',
|
||||||
|
nickname: '赵六',
|
||||||
|
email: 'zhaoliu@example.com',
|
||||||
|
phone: '13800000005',
|
||||||
|
status: 'enabled',
|
||||||
|
orgCode: 'sales',
|
||||||
|
createdAt: now - 12 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
username: 'sunqi',
|
||||||
|
nickname: '孙七',
|
||||||
|
email: 'sunqi@example.com',
|
||||||
|
phone: '13800000006',
|
||||||
|
status: 'enabled',
|
||||||
|
orgCode: 'ops',
|
||||||
|
createdAt: now - 9 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
username: 'zhouba',
|
||||||
|
nickname: '周八',
|
||||||
|
email: 'zhouba@example.com',
|
||||||
|
phone: '13800000007',
|
||||||
|
status: 'enabled',
|
||||||
|
orgCode: 'rd',
|
||||||
|
createdAt: now - 7 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '8',
|
||||||
|
username: 'wujiu',
|
||||||
|
nickname: '吴九',
|
||||||
|
email: 'wujiu@example.com',
|
||||||
|
phone: '13800000008',
|
||||||
|
status: 'disabled',
|
||||||
|
orgCode: 'sales',
|
||||||
|
createdAt: now - 5 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '9',
|
||||||
|
username: 'zhengshi',
|
||||||
|
nickname: '郑十',
|
||||||
|
email: 'zhengshi@example.com',
|
||||||
|
phone: '13800000009',
|
||||||
|
status: 'enabled',
|
||||||
|
orgCode: 'rd',
|
||||||
|
createdAt: now - 3 * day,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '10',
|
||||||
|
username: 'chenyi',
|
||||||
|
nickname: '陈一',
|
||||||
|
email: 'chenyi@example.com',
|
||||||
|
phone: '13800000010',
|
||||||
|
status: 'enabled',
|
||||||
|
orgCode: 'sales',
|
||||||
|
createdAt: now - 1 * day,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
let seq = 0
|
let seq = 0
|
||||||
@ -166,12 +268,26 @@ const list = (query: PageQuery): Promise<PageResult<Record<string, any>>> =>
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
const start = (page - 1) * pageSize
|
const start = (page - 1) * pageSize
|
||||||
return { list: filtered.slice(start, start + pageSize) as unknown as Record<string, any>[], total: filtered.length, page, pageSize }
|
return {
|
||||||
|
list: filtered.slice(start, start + pageSize) as unknown as Record<string, any>[],
|
||||||
|
total: filtered.length,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const create = (data: Record<string, any>): Promise<unknown> =>
|
const create = (data: Record<string, any>): Promise<unknown> =>
|
||||||
delay(() => {
|
delay(() => {
|
||||||
users.unshift({ id: nextId(), username: data.username, nickname: data.nickname, email: data.email, phone: data.phone, status: data.status, orgCode: data.orgCode, createdAt: Date.now() })
|
users.unshift({
|
||||||
|
id: nextId(),
|
||||||
|
username: data.username,
|
||||||
|
nickname: data.nickname,
|
||||||
|
email: data.email,
|
||||||
|
phone: data.phone,
|
||||||
|
status: data.status,
|
||||||
|
orgCode: data.orgCode,
|
||||||
|
createdAt: Date.now(),
|
||||||
|
})
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user