feat-wip(views): 数据字典相关页面代码提交

This commit is contained in:
2025-12-06 16:33:58 +08:00
parent 11747a490c
commit 755e6211c2
6 changed files with 156 additions and 214 deletions

View File

@ -1,26 +1,26 @@
import { request } from '../../../request';
export function fetchPageDictionary(pageRequest: Api.Sys.Core.DictionaryQueryPageRequest) {
return request<Api.Common.PageResponse<Api.Sys.Core.Dictionary>>({
export function fetchDictionaryPaginate(pageRequest: Api.Common.PageRequest<Api.Sys.Core.DictionaryDTO>) {
return request<Api.Common.PageResponse<Api.Sys.Core.DictionaryVO>>({
url: '/dictionary/paginate',
method: 'post',
data: pageRequest
});
}
export function fetchDictionaryAdd(dictionaryOp: Api.Sys.Core.DictionaryOp) {
export function fetchDictionaryInsert(dictionaryDTO: Api.Sys.Core.DictionaryDTO) {
return request({
url: '/dictionary/insert',
method: 'post',
data: dictionaryOp
data: dictionaryDTO
});
}
export function fetchDictionaryEdit(dictionaryOp: Api.Sys.Core.DictionaryOp) {
export function fetchDictionaryUpdate(dictionaryDTO: Api.Sys.Core.DictionaryDTO) {
return request({
url: '/dictionary/update',
method: 'post',
data: dictionaryOp
data: dictionaryDTO
});
}
@ -44,8 +44,8 @@ export function fetchDictionaryDeleteBatch(ids: string[]) {
});
}
export function fetchTreeDictionaryItem(dictionaryId: string) {
return request<Api.Sys.Core.DictionaryItem[]>({
export function fetchDictionaryItemTreeList(dictionaryId: string) {
return request<Api.Sys.Core.DictionaryItemVO[]>({
url: '/dictionaryItem/tree',
method: 'post',
data: {
@ -54,19 +54,19 @@ export function fetchTreeDictionaryItem(dictionaryId: string) {
});
}
export function fetchDictionaryItemAdd(dictionaryOp: Api.Sys.Core.DictionaryItemOp) {
export function fetchDictionaryItemInsert(dictionaryItemDTO: Api.Sys.Core.DictionaryItemDTO) {
return request({
url: '/dictionaryItem/insert',
method: 'post',
data: dictionaryOp
data: dictionaryItemDTO
});
}
export function fetchDictionaryItemEdit(dictionaryOp: Api.Sys.Core.DictionaryItemOp) {
export function fetchDictionaryItemUpdate(dictionaryItemDTO: Api.Sys.Core.DictionaryItemDTO) {
return request({
url: '/dictionaryItem/update',
method: 'post',
data: dictionaryOp
data: dictionaryItemDTO
});
}

View File

@ -3,7 +3,7 @@ declare namespace Api {
namespace Core {
// ******************** sys_core_dictionary ********************
type DictionaryType = 'enum' | 'tree';
interface Dictionary {
interface DictionaryVO {
id: string;
name: string;
code: string;
@ -12,30 +12,25 @@ declare namespace Api {
createTime: string;
updateTime: string;
}
interface DictionaryQuery {
interface DictionaryDTO {
id: string | null;
name: string | null;
code: string | null;
type: string | null;
}
type DictionaryQueryPageRequest = Api.Common.PageRequest<DictionaryQuery>;
interface DictionaryOp {
id: string | null;
name: string;
code: string;
type: DictionaryType;
type: DictionaryType | null;
description: string | null;
}
interface DictionaryItem {
interface DictionaryItemVO {
id: string;
dictionaryId: string | null;
name: string;
code: string;
sort: number;
description: string | null;
createTime: string | null;
updateTime: string | null;
children: DictionaryItem[];
createTime: string;
updateTime: string;
children: DictionaryItemVO[];
}
interface DictionaryItemOp {
interface DictionaryItemDTO {
id: string | null;
dictionaryId: string;
name: string;

View File

@ -2,27 +2,34 @@
import { reactive } from 'vue';
import { NButton, NPopconfirm, NTag } from 'naive-ui';
import { dictionaryTypeRecord } from '@/constants/sys/core/dictionary';
import { fetchDictionaryDelete, fetchDictionaryDeleteBatch, fetchPageDictionary } from '@/service/api';
import { fetchDictionaryDelete, fetchDictionaryDeleteBatch, fetchDictionaryPaginate } from '@/service/api';
import { useAppStore } from '@/store/modules/app';
import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales';
import DictionarySearch from '@/views/sys/core/dictionary/modules/dictionary-search.vue';
import DictionaryOperateDrawer from '@/views/sys/core/dictionary/modules/dictionary-operate-drawer.vue';
import DictionaryDTO = Api.Sys.Core.DictionaryDTO;
// ******************** 数据定义 ********************
const appStore = useAppStore();
const pageRequest: Api.Sys.Core.DictionaryQueryPageRequest = reactive({
// 表格分页请求
const pageRequest: Api.Common.PageRequest<DictionaryDTO> = reactive({
pageIndex: 1,
pageSize: 10,
query: {
id: null,
name: null,
code: null,
type: null
type: null,
description: null
}
});
const { columns, columnChecks, data, loading, getData, getDataByPage, mobilePagination } = useNaivePaginatedTable({
api: () => fetchPageDictionary(pageRequest),
// 表格数据
const { columns, columnChecks, data, loading, getData, getDataByPage, pagination } = useNaivePaginatedTable({
api: () => fetchDictionaryPaginate(pageRequest),
transform: response => defaultTransform(response),
onPaginationParamsChange: params => {
pageRequest.pageIndex = params.page || 1;
@ -100,10 +107,12 @@ const { columns, columnChecks, data, loading, getData, getDataByPage, mobilePagi
}
]
});
// 表格操作
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
useTableOperate(data, 'id', getData);
// ******************** 触发事件 ********************
async function handleBatchDelete() {
fetchDictionaryDeleteBatch(checkedRowKeys.value).then(() => {
onBatchDeleted();
@ -151,7 +160,7 @@ function edit(id: string) {
:loading="loading"
remote
:row-key="row => row.id"
:pagination="mobilePagination"
:pagination="pagination"
class="sm:h-full"
/>
<DictionaryOperateDrawer

View File

@ -1,59 +0,0 @@
<script setup lang="ts">
import { computed } from 'vue';
import { $t } from '@/locales';
defineOptions({
name: 'DictionaryOperateDialog'
});
const props = defineProps<{
/** the type of operation */
operateType: NaiveUI.TableOperateType;
/** the edit row data */
// rowData?: Api.Sys.Core.Dictionary | null;
}>();
const emit = defineEmits<{
(e: 'submitted'): void;
}>();
const visible = defineModel<boolean>('visible', {
default: false
});
const title = computed(() => {
const titles: Record<NaiveUI.TableOperateType, string> = {
add: $t('common.add'),
edit: $t('common.edit')
};
return titles[props.operateType];
});
function closeDialog(): void {
visible.value = false;
}
function handleSubmit() {
window.$message?.success($t('common.updateSuccess'));
closeDialog();
emit('submitted');
}
</script>
<template>
<NModal
v-model:show="visible"
preset="dialog"
:title="title"
@positive-click="handleSubmit"
@negative-click="visible = false"
>
<div class="dialog-wrapper">111</div>
</NModal>
</template>
<style scoped>
.dialog-wrapper {
width: 1000px;
}
</style>

View File

@ -4,43 +4,56 @@ import type { DataTableColumns } from 'naive-ui';
import { jsonClone } from '@sa/utils';
import { dictionaryTypeOptions } from '@/constants/sys/core/dictionary';
import {
fetchDictionaryAdd,
fetchDictionaryEdit,
fetchDictionaryItemAdd,
fetchDictionaryInsert,
fetchDictionaryItemDelete,
fetchDictionaryItemEdit,
fetchTreeDictionaryItem
fetchDictionaryItemInsert,
fetchDictionaryItemTreeList,
fetchDictionaryItemUpdate,
fetchDictionaryUpdate
} from '@/service/api';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
import DictionaryItem = Api.Sys.Core.DictionaryItem;
// ******************** 数据定义 ********************
// 组件定义
defineOptions({
name: 'DictionaryOperateDrawer'
});
// 属性定义
interface Props {
/** the type of operation */
operateType: NaiveUI.TableOperateType;
/** the edit row data */
rowData?: Api.Sys.Core.Dictionary | null;
rowData?: Api.Sys.Core.DictionaryVO | null;
}
const props = defineProps<Props>();
// 事件定义
interface Emits {
(e: 'submitted'): void;
}
const emit = defineEmits<Emits>();
// 可见性定义
const visible = defineModel<boolean>('visible', {
default: false
});
const { formRef, validate, restoreValidation } = useNaiveForm();
const { defaultRequiredRule } = useFormRules();
// Model
const model = ref(createDefaultModel());
function createDefaultModel(): Api.Sys.Core.DictionaryDTO {
return {
id: null,
name: null,
code: null,
type: null,
description: null
};
}
// 抽屉标题
const title = computed(() => {
const titles: Record<NaiveUI.TableOperateType, string> = {
add: $t('common.add'),
@ -49,41 +62,54 @@ const title = computed(() => {
return titles[props.operateType];
});
interface Model {
name: string;
code: string;
type: Api.Sys.Core.DictionaryType;
description: string | null;
children: Api.Sys.Core.DictionaryItem[];
}
// Form校验规则
const { formRef, validate, restoreValidation } = useNaiveForm();
const { defaultRequiredRule } = useFormRules();
type RuleKey = 'name' | 'code' | 'type';
const rules: Record<RuleKey, App.Global.FormRule> = {
name: defaultRequiredRule,
code: defaultRequiredRule,
type: defaultRequiredRule
};
interface ChildrenOperateModel {
id: string | null;
name: string;
code: string;
sort: number;
description: string | null;
}
// ******************** 事件定义 ********************
const model = ref(createDefaultModel());
function handleInitModel() {
model.value = createDefaultModel();
const childrenOperateModel = ref(createDefaultModel2());
const childrenModelVisible = ref(false);
const childrenTitle = ref('');
const childrenModelOperateType = ref('');
function showChildrenModel(operateType: NaiveUI.TableOperateType, row: DictionaryItem | null = null) {
childrenModelOperateType.value = operateType;
childrenTitle.value = operateType === 'edit' ? $t('common.edit') : $t('common.add');
childrenModelVisible.value = true;
childrenOperateModel.value = createDefaultModel2();
if (row) {
Object.assign(childrenOperateModel.value, jsonClone(row));
if (props.operateType === 'edit' && props.rowData) {
Object.assign(model.value, jsonClone(props.rowData));
}
}
const childrenColumns: DataTableColumns<DictionaryItem> = [
async function handleSubmit() {
await validate();
const isEdit = props.operateType === 'edit';
const opFunc = isEdit ? fetchDictionaryUpdate : fetchDictionaryInsert;
opFunc(model.value).then(() => {
window.$message?.success($t('common.updateSuccess'));
visible.value = false;
emit('submitted');
});
}
// ******************** 子项数据定义 ********************
// Model
const childrenModel = ref(createChildrenModel());
function createChildrenModel(): Api.Sys.Core.DictionaryItemDTO {
return {
id: null,
dictionaryId: '',
name: '',
code: '',
sort: 0,
description: null
};
}
// Column
const childrenColumns: DataTableColumns<Api.Sys.Core.DictionaryItemVO> = [
{
key: 'name',
title: $t('page.sys.core.dictionary.item.fields.name'),
@ -143,113 +169,80 @@ const childrenColumns: DataTableColumns<DictionaryItem> = [
}
}
];
function createDefaultModel(): Model {
// Data
const childrenData = ref(createChildrenData());
interface ChildrenData {
records: Api.Sys.Core.DictionaryItemVO[];
}
function createChildrenData(): ChildrenData {
return {
name: '',
code: '',
type: 'enum',
description: null,
children: []
records: []
};
}
// 标题
const childrenModelTitle = ref('');
const childrenModelVisible = ref(false);
const childrenModelOperateType = ref('');
function createDefaultModel2(): ChildrenOperateModel {
return {
id: null,
name: '',
code: '',
sort: 0,
description: null
};
}
// ******************** 子项事件定义 ********************
type RuleKey = 'name' | 'code' | 'type';
const rules: Record<RuleKey, App.Global.FormRule> = {
name: defaultRequiredRule,
code: defaultRequiredRule,
type: defaultRequiredRule
};
function handleInitModel() {
model.value = createDefaultModel();
if (props.operateType === 'edit' && props.rowData) {
Object.assign(model.value, jsonClone(props.rowData));
}
}
function handleInitChildrenModel() {
function handleInitChildrenData() {
if (props.operateType !== 'edit' || !props.rowData?.id) {
return;
}
fetchTreeDictionaryItem(props.rowData.id).then(res => {
fetchDictionaryItemTreeList(props.rowData.id).then(res => {
if (res.data) {
model.value.children = res.data ? res.data : [];
childrenData.value.records = res.data ? res.data : [];
}
});
}
function showChildrenModel(operateType: NaiveUI.TableOperateType, row: Api.Sys.Core.DictionaryItemVO | null) {
childrenModelOperateType.value = operateType;
childrenModelTitle.value = operateType === 'edit' ? $t('common.edit') : $t('common.add');
childrenModelVisible.value = true;
childrenModel.value = createChildrenModel();
if (row) {
Object.assign(childrenModel.value, jsonClone(row));
}
}
function handleChildrenSubmit() {
const apiParams: Api.Sys.Core.DictionaryItemOp = {
dictionaryId: props.rowData?.id || '',
...childrenOperateModel.value
};
const apiParams = childrenModel.value;
if (childrenModelOperateType.value === 'edit') {
// 编辑
fetchDictionaryItemEdit(apiParams).then(() => {
fetchDictionaryItemUpdate(apiParams).then(() => {
window.$message?.success($t('common.updateSuccess'));
childrenModelVisible.value = false;
handleInitChildrenModel();
handleInitChildrenData();
});
} else {
// 新增
fetchDictionaryItemAdd(apiParams).then(() => {
fetchDictionaryItemInsert(apiParams).then(() => {
window.$message?.success($t('common.updateSuccess'));
childrenModelVisible.value = false;
handleInitChildrenModel();
handleInitChildrenData();
});
}
}
function handleChildrenDelete(row: DictionaryItem, index: number) {
function handleChildrenDelete(row: Api.Sys.Core.DictionaryItemVO, index: number) {
if (row.id) {
// 执行删除
fetchDictionaryItemDelete(row.id).then(() => {
window.$message?.success($t('common.deleteSuccess'));
handleInitChildrenModel();
handleInitChildrenData();
});
} else {
model.value.children = model.value.children.splice(index);
} else if (childrenData.value.records) {
childrenData.value.records = childrenData.value.records.splice(index);
}
}
function closeDrawer() {
visible.value = false;
}
async function handleSubmit() {
await validate();
const isEdit = props.operateType === 'edit';
const opFunc = isEdit ? fetchDictionaryEdit : fetchDictionaryAdd;
const opData: Api.Sys.Core.DictionaryOp = {
id: props.rowData?.id || null,
...model.value
};
opFunc(opData).then(() => {
window.$message?.success($t('common.updateSuccess'));
closeDrawer();
emit('submitted');
});
}
watch(visible, () => {
if (visible.value) {
handleInitModel();
handleInitChildrenData();
restoreValidation();
handleInitChildrenModel();
}
});
</script>
@ -286,43 +279,43 @@ watch(visible, () => {
<NCard v-if="props.operateType === 'edit'" :title="$t('page.sys.core.dictionary.item.title')">
<template #header-extra>
<NSpace>
<NButton type="primary" @click="showChildrenModel('add')">
<NButton type="primary" @click="showChildrenModel('add', null)">
{{ $t('common.add') }}
</NButton>
</NSpace>
</template>
<NDataTable :data="model.children" :columns="childrenColumns" :bordered="true" />
<NDataTable :data="childrenData.records" :columns="childrenColumns" :bordered="true" />
<NModal
v-model:show="childrenModelVisible"
preset="dialog"
:title="childrenTitle"
:title="childrenModelTitle"
:positive-text="$t('common.confirm')"
:negative-text="$t('common.cancel')"
@positive-click="handleChildrenSubmit"
@negative-click="childrenModelVisible = false"
>
<NForm :model="childrenOperateModel">
<NForm :model="childrenModel">
<NFormItem :label="$t('page.sys.core.dictionary.item.fields.name')" path="name">
<NInput
v-model:value="childrenOperateModel.name"
v-model:value="childrenModel.name"
:placeholder="$t('page.sys.core.dictionary.item.fields.name')"
/>
</NFormItem>
<NFormItem :label="$t('page.sys.core.dictionary.item.fields.code')" path="code">
<NInput
v-model:value="childrenOperateModel.code"
v-model:value="childrenModel.code"
:placeholder="$t('page.sys.core.dictionary.item.fields.code')"
/>
</NFormItem>
<NFormItem :label="$t('page.sys.core.dictionary.item.fields.sort')" path="sort">
<NInputNumber
v-model:value="childrenOperateModel.sort"
v-model:value="childrenModel.sort"
:placeholder="$t('page.sys.core.dictionary.item.fields.sort')"
/>
</NFormItem>
<NFormItem :label="$t('page.sys.core.dictionary.item.fields.description')" path="description">
<NInput
v-model:value="childrenOperateModel.description"
v-model:value="childrenModel.description"
:placeholder="$t('page.sys.core.dictionary.item.fields.description')"
type="textarea"
/>
@ -333,7 +326,7 @@ watch(visible, () => {
</NScrollbar>
<template #footer>
<NSpace :size="16">
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
<NButton @click="visible = false">{{ $t('common.cancel') }}</NButton>
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
</NSpace>
</template>

View File

@ -5,20 +5,24 @@ import { dictionaryTypeOptions } from '@/constants/sys/core/dictionary';
import { translateOptions } from '@/utils/common';
import { $t } from '@/locales';
// ******************** 数据定义 ********************
// 定义组件
defineOptions({
name: 'DictionarySearch'
});
// 定义触发
interface Emits {
(e: 'search'): void;
}
const emit = defineEmits<Emits>();
const model = defineModel<Api.Sys.Core.DictionaryQueryPageRequest>('model', { required: true });
// 定义数据
const model = defineModel<Api.Common.PageRequest<Api.Sys.Core.DictionaryDTO>>('model', { required: true });
const defaultModel = jsonClone(toRaw(model.value));
// ******************** 触发事件 ********************
function resetModel() {
Object.assign(model.value, defaultModel);
}