238 lines
6.5 KiB
Vue
238 lines
6.5 KiB
Vue
<template>
|
|
<div class="page-shell">
|
|
<div class="grid min-h-0 flex-1 grid-cols-1 gap-4 lg:grid-cols-2">
|
|
<section class="page-card table-fill">
|
|
<div class="page-toolbar">
|
|
<span class="text-sm font-semibold text-slate-700">字典类型</span>
|
|
<n-button size="small" type="primary" @click="openTypeCreate">新增类型</n-button>
|
|
</div>
|
|
<div class="card-body card-body-fill table-fill">
|
|
<n-data-table
|
|
flex-height
|
|
:columns="typeColumns"
|
|
:data="typeRows"
|
|
:pagination="typePagination"
|
|
remote
|
|
@update:page="onTypePage"
|
|
@update:page-size="onTypePageSize"
|
|
/>
|
|
</div>
|
|
</section>
|
|
<section class="page-card table-fill">
|
|
<div class="page-toolbar">
|
|
<span class="text-sm font-semibold text-slate-700">字典项</span>
|
|
<n-button size="small" type="primary" :disabled="!selectedTypeId" @click="openItemCreate"
|
|
>新增字典项</n-button
|
|
>
|
|
</div>
|
|
<div class="card-body card-body-fill table-fill">
|
|
<n-data-table
|
|
flex-height
|
|
:columns="itemColumns"
|
|
:data="itemRows"
|
|
:pagination="itemPagination"
|
|
remote
|
|
@update:page="onItemPage"
|
|
@update:page-size="onItemPageSize"
|
|
/>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, h, reactive, ref, watch } from 'vue'
|
|
import { NButton, NPopconfirm, NTag, NSpace, useMessage, type DataTableColumns } from 'naive-ui'
|
|
import { useMutation, useQuery } from '@tanstack/vue-query'
|
|
import {
|
|
createDictItemApi,
|
|
createDictTypeApi,
|
|
deleteDictItemApi,
|
|
deleteDictTypeApi,
|
|
listDictItemsApi,
|
|
listDictTypesApi
|
|
} from '@/api/system/dict'
|
|
import type { DictItem, DictTypeItem } from '@/types/system/dict'
|
|
import { statusLabel, statusTagType } from '@/utils/display'
|
|
import { renderPagePrefix } from '@/utils/pagination'
|
|
|
|
const message = useMessage()
|
|
const selectedTypeId = ref<string>('')
|
|
const typeQuery = reactive({ page: 1, pageSize: 10, keyword: '' })
|
|
const itemQuery = reactive({ page: 1, pageSize: 10 })
|
|
const typesReq = useQuery({
|
|
queryKey: computed(() => ['dict-types', { ...typeQuery }]),
|
|
queryFn: () => listDictTypesApi({ ...typeQuery, keyword: typeQuery.keyword || undefined })
|
|
})
|
|
const itemsReq = useQuery({
|
|
queryKey: computed(() => ['dict-items', selectedTypeId.value, { ...itemQuery }]),
|
|
queryFn: () => listDictItemsApi({ ...itemQuery, typeId: selectedTypeId.value || undefined })
|
|
})
|
|
const typeRows = computed(() => typesReq.data.value?.items ?? [])
|
|
const itemRows = computed(() => itemsReq.data.value?.items ?? [])
|
|
const typePagination = computed(() => ({
|
|
page: typeQuery.page,
|
|
pageSize: typeQuery.pageSize,
|
|
itemCount: typesReq.data.value?.total ?? 0,
|
|
showSizePicker: true,
|
|
pageSizes: [10, 20],
|
|
prefix: renderPagePrefix
|
|
}))
|
|
const itemPagination = computed(() => ({
|
|
page: itemQuery.page,
|
|
pageSize: itemQuery.pageSize,
|
|
itemCount: itemsReq.data.value?.total ?? 0,
|
|
showSizePicker: true,
|
|
pageSizes: [10, 20],
|
|
prefix: renderPagePrefix
|
|
}))
|
|
watch(
|
|
typeRows,
|
|
(v) => {
|
|
if (!selectedTypeId.value && v.length > 0) selectedTypeId.value = v[0].id
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
const createTypeMutation = useMutation({
|
|
mutationFn: () =>
|
|
createDictTypeApi({
|
|
code: `TYPE_${Date.now()}`,
|
|
name: `新类型${Date.now().toString().slice(-4)}`,
|
|
status: 'ENABLED'
|
|
}),
|
|
onSuccess: async () => {
|
|
message.success('新增类型成功')
|
|
await typesReq.refetch()
|
|
}
|
|
})
|
|
const createItemMutation = useMutation({
|
|
mutationFn: () =>
|
|
createDictItemApi({
|
|
typeId: selectedTypeId.value,
|
|
label: `新项${Date.now().toString().slice(-4)}`,
|
|
value: `${Date.now()}`,
|
|
sort: 0,
|
|
status: 'ENABLED'
|
|
}),
|
|
onSuccess: async () => {
|
|
message.success('新增字典项成功')
|
|
await itemsReq.refetch()
|
|
}
|
|
})
|
|
const deleteTypeMutation = useMutation({
|
|
mutationFn: deleteDictTypeApi,
|
|
onSuccess: async () => {
|
|
message.success('删除成功')
|
|
selectedTypeId.value = ''
|
|
await typesReq.refetch()
|
|
await itemsReq.refetch()
|
|
}
|
|
})
|
|
const deleteItemMutation = useMutation({
|
|
mutationFn: deleteDictItemApi,
|
|
onSuccess: async () => {
|
|
message.success('删除成功')
|
|
await itemsReq.refetch()
|
|
}
|
|
})
|
|
|
|
function openTypeCreate() {
|
|
createTypeMutation.mutate()
|
|
}
|
|
function openItemCreate() {
|
|
if (!selectedTypeId.value) return
|
|
createItemMutation.mutate()
|
|
}
|
|
function onTypePage(p: number) {
|
|
typeQuery.page = p
|
|
}
|
|
function onTypePageSize(s: number) {
|
|
typeQuery.pageSize = s
|
|
typeQuery.page = 1
|
|
}
|
|
function onItemPage(p: number) {
|
|
itemQuery.page = p
|
|
}
|
|
function onItemPageSize(s: number) {
|
|
itemQuery.pageSize = s
|
|
itemQuery.page = 1
|
|
}
|
|
|
|
const typeColumns = computed<DataTableColumns<DictTypeItem>>(() => [
|
|
{ title: '编码', key: 'code' },
|
|
{
|
|
title: '名称',
|
|
key: 'name',
|
|
render: (r) => h('a', { onClick: () => (selectedTypeId.value = r.id) }, r.name)
|
|
},
|
|
{
|
|
title: '状态',
|
|
key: 'status',
|
|
render: (r) =>
|
|
h(
|
|
NTag,
|
|
{ size: 'small', type: statusTagType(r.status) },
|
|
{ default: () => statusLabel(r.status) }
|
|
)
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'actions',
|
|
render: (r) =>
|
|
h(
|
|
NPopconfirm,
|
|
{ onPositiveClick: () => deleteTypeMutation.mutate(r.id) },
|
|
{
|
|
trigger: () =>
|
|
h(NButton, { size: 'tiny', tertiary: true, type: 'error' }, { default: () => '删除' }),
|
|
default: () => '确认删除?'
|
|
}
|
|
)
|
|
}
|
|
])
|
|
const itemColumns = computed<DataTableColumns<DictItem>>(() => [
|
|
{ title: '标签', key: 'label' },
|
|
{ title: '值', key: 'value' },
|
|
{
|
|
title: '颜色',
|
|
key: 'color',
|
|
render: (r) =>
|
|
r.color
|
|
? h(NTag, { size: 'small', color: { color: r.color } }, { default: () => r.color })
|
|
: '-'
|
|
},
|
|
{
|
|
title: '状态',
|
|
key: 'status',
|
|
render: (r) =>
|
|
h(
|
|
NTag,
|
|
{ size: 'small', type: statusTagType(r.status) },
|
|
{ default: () => statusLabel(r.status) }
|
|
)
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'actions',
|
|
render: (r) =>
|
|
h(NSpace, { size: 6 }, () => [
|
|
h(
|
|
NPopconfirm,
|
|
{ onPositiveClick: () => deleteItemMutation.mutate(r.id) },
|
|
{
|
|
trigger: () =>
|
|
h(
|
|
NButton,
|
|
{ size: 'tiny', tertiary: true, type: 'error' },
|
|
{ default: () => '删除' }
|
|
),
|
|
default: () => '确认删除?'
|
|
}
|
|
)
|
|
])
|
|
}
|
|
])
|
|
</script>
|