初始化项目
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
<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
|
||||
: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
|
||||
: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>
|
||||
Reference in New Issue
Block a user