feat-wip(components): 行政区划相关页面代码提交

This commit is contained in:
2025-12-05 13:36:39 +08:00
parent d6a78427d1
commit 38213534d0
12 changed files with 280 additions and 14 deletions

View File

@ -2,6 +2,6 @@
VITE_SERVICE_BASE_URL=https://mock.apifox.cn/m1/3109515-0-default VITE_SERVICE_BASE_URL=https://mock.apifox.cn/m1/3109515-0-default
# other backend service base url, prod environment # other backend service base url, prod environment
VITE_OTHER_SERVICE_BASE_URL= `{ VITE_OTHER_SERVICE_BASE_URL=`{
"demo": "http://localhost:9529" "demo": "http://localhost:9529"
}` }`

View File

@ -344,7 +344,12 @@ const local: App.I18n.Schema = {
}, },
rbac: { rbac: {
region: { region: {
title: 'Region' title: 'Region',
fields: {
name: 'Name',
code: 'Code',
sort: 'Sort'
}
} }
} }
} }

View File

@ -340,7 +340,12 @@ const local: App.I18n.Schema = {
}, },
rbac: { rbac: {
region: { region: {
title: '行政区划' title: '行政区划',
fields: {
name: '名称',
code: '代码',
sort: '排序'
}
} }
} }
} }

View File

@ -1,3 +1,4 @@
export * from './auth'; export * from './auth';
export * from './route'; export * from './route';
export * from './sys/core/dictionary'; export * from './sys/core/dictionary';
export * from './sys/rbac/region';

View File

@ -0,0 +1,45 @@
import { request } from '../../../request';
export function fetchRegionPaginate(pageRequest: Api.Common.PageRequest<Api.Sys.Rbac.RegionDTO>) {
return request<Api.Common.PageResponse<Api.Sys.Rbac.RegionVO>>({
url: '/region/paginate',
method: 'post',
data: pageRequest
});
}
export function fetchRegionInsert(regionDTO: Api.Sys.Rbac.RegionDTO) {
return request<boolean>({
url: '/region/insert',
method: 'post',
data: regionDTO
});
}
export function fetchRegionUpdate(regionDTO: Api.Sys.Rbac.RegionDTO) {
return request<boolean>({
url: '/region/update',
method: 'post',
data: regionDTO
});
}
export function fetchRegionDelete(id: string) {
return request<boolean>({
url: '/region/delete',
method: 'post',
data: {
id
}
});
}
export function fetchRegionDeleteBatch(ids: string[]) {
return request<number>({
url: '/region/deleteBatch',
method: 'post',
data: {
ids
}
});
}

View File

@ -5,14 +5,10 @@
*/ */
declare namespace Api { declare namespace Api {
namespace Common { namespace Common {
/** 分页请求 */ /** 带查询参数的分页请求 */
interface PageRequest { interface PageRequest<T> {
pageIndex: number; pageIndex: number;
pageSize: number; pageSize: number;
}
/** 带查询参数的分页请求 */
interface QueryPageRequest<T> extends PageRequest {
query: T; query: T;
} }

View File

@ -17,7 +17,7 @@ declare namespace Api {
code: string | null; code: string | null;
type: string | null; type: string | null;
} }
type DictionaryQueryPageRequest = Api.Common.QueryPageRequest<DictionaryQuery>; type DictionaryQueryPageRequest = Api.Common.PageRequest<DictionaryQuery>;
interface DictionaryOp { interface DictionaryOp {
id: string | null; id: string | null;
name: string; name: string;

34
src/typings/api/sys/rbac.d.ts vendored Normal file
View File

@ -0,0 +1,34 @@
declare namespace Api {
namespace Sys {
namespace Rbac {
// ******************** sys_rbac_region ********************
interface RegionVO {
id: string;
parentId: string | null;
parentCode: string | null;
rootId: string | null;
rootCode: string | null;
name: string;
code: string;
extCode: string;
sort: number;
description: string;
createTime: string;
updateTime: string;
children: RegionVO[];
}
interface RegionDTO {
id: string | null;
parentId: string | null;
parentCode: string | null;
rootId: string | null;
rootCode: string | null;
name: string | null;
code: string | null;
extCode: string | null;
sort: number | null;
description: string | null;
}
}
}
}

View File

@ -587,6 +587,11 @@ declare namespace App {
rbac: { rbac: {
region: { region: {
title: string; title: string;
fields: {
name: string;
code: string;
sort: string;
};
}; };
}; };
}; };

View File

@ -63,7 +63,6 @@ declare module 'vue' {
NFormItemGi: typeof import('naive-ui')['NFormItemGi'] NFormItemGi: typeof import('naive-ui')['NFormItemGi']
NGi: typeof import('naive-ui')['NGi'] NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid'] NGrid: typeof import('naive-ui')['NGrid']
NHr: typeof import('naive-ui')['NHr']
NInput: typeof import('naive-ui')['NInput'] NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup'] NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputNumber: typeof import('naive-ui')['NInputNumber'] NInputNumber: typeof import('naive-ui')['NInputNumber']
@ -155,7 +154,6 @@ declare global {
const NFormItemGi: typeof import('naive-ui')['NFormItemGi'] const NFormItemGi: typeof import('naive-ui')['NFormItemGi']
const NGi: typeof import('naive-ui')['NGi'] const NGi: typeof import('naive-ui')['NGi']
const NGrid: typeof import('naive-ui')['NGrid'] const NGrid: typeof import('naive-ui')['NGrid']
const NHr: typeof import('naive-ui')['NHr']
const NInput: typeof import('naive-ui')['NInput'] const NInput: typeof import('naive-ui')['NInput']
const NInputGroup: typeof import('naive-ui')['NInputGroup'] const NInputGroup: typeof import('naive-ui')['NInputGroup']
const NInputNumber: typeof import('naive-ui')['NInputNumber'] const NInputNumber: typeof import('naive-ui')['NInputNumber']

View File

@ -1,15 +1,127 @@
<script setup lang="ts"> <script setup lang="tsx">
import { reactive } from 'vue';
import { fetchRegionPaginate } from '@/service/api';
import { useAppStore } from '@/store/modules/app';
import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales'; import { $t } from '@/locales';
import RegionSearch from '@/views/sys/rbac/region/modules/region-search.vue';
// ******************** 数据定义 ********************
const appStore = useAppStore();
// 表格分页请求
const pageRequest: Api.Common.PageRequest<Api.Sys.Rbac.RegionDTO> = reactive({
pageIndex: 1,
pageSize: 10,
query: {
id: null,
parentId: null,
parentCode: null,
rootId: null,
rootCode: null,
name: null,
code: null,
extCode: null,
sort: null,
description: null
}
});
// 表格数据
const { columns, columnChecks, data, loading, getData, getDataByPage, pagination } = useNaivePaginatedTable({
api: () => fetchRegionPaginate(pageRequest),
transform: response => defaultTransform(response),
onPaginationParamsChange: params => {
pageRequest.pageIndex = params.page || 1;
pageRequest.pageSize = params.pageSize || 10;
},
columns: () => [
{
type: 'selection',
align: 'center'
},
{
key: 'index',
title: $t('common.index'),
width: 50,
align: 'center',
render: (_, index) => index + 1
},
{
key: 'name',
title: $t('page.sys.core.dictionary.fields.name'),
align: 'center',
resizable: true
},
{
key: 'code',
title: $t('page.sys.core.dictionary.fields.code'),
align: 'center',
resizable: true
},
{
key: 'sort',
title: $t('page.sys.rbac.region.fields.sort'),
align: 'center',
resizable: true
},
{
key: 'createTime',
title: $t('page.sys.core.dictionary.fields.createTime'),
align: 'center',
resizable: true
},
{
key: 'updateTime',
title: $t('page.sys.core.dictionary.fields.updateTime'),
align: 'center',
resizable: true
}
]
});
// 表格操作
const { checkedRowKeys, handleAdd } = useTableOperate(data, 'id', getData);
// ******************** 触发事件 ********************
async function handleBatchDelete() {}
</script> </script>
<template> <template>
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto"> <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<RegionSearch v-model:model="pageRequest" @search="getDataByPage" />
<NCard <NCard
:title="$t('page.sys.rbac.region.title')" :title="$t('page.sys.rbac.region.title')"
:bordered="false" :bordered="false"
size="small" size="small"
class="card-wrapper sm:flex-1-hidden" class="card-wrapper sm:flex-1-hidden"
></NCard> >
<template #header-extra>
<TableHeaderOperation
v-model:columns="columnChecks"
:disabled-delete="checkedRowKeys.length === 0"
:loading="loading"
@add="handleAdd"
@delete="handleBatchDelete"
@refresh="getData"
/>
</template>
<NDataTable
v-model:checked-row-keys="checkedRowKeys"
:columns="columns"
:data="data"
size="small"
:flex-height="!appStore.isMobile"
:scroll-x="702"
:bordered="true"
:loading="loading"
remote
:row-key="row => row.id"
:pagination="pagination"
class="sm:h-full"
/>
</NCard>
</div> </div>
</template> </template>

View File

@ -0,0 +1,65 @@
<script setup lang="ts">
import { toRaw } from 'vue';
import { jsonClone } from '@sa/utils';
import { $t } from '@/locales';
// ******************** 数据定义 ********************
// 定义组件
defineOptions({
name: 'RegionSearch'
});
// 定义触发
interface SearchEmits {
(e: 'search'): void;
}
const emit = defineEmits<SearchEmits>();
// 定义数据
const model = defineModel<Api.Common.PageRequest<Api.Sys.Rbac.RegionDTO>>('model', { required: true });
const defaultModel = jsonClone(toRaw(model.value));
// ******************** 触发事件 ********************
// 事件
function handleResetModel() {
Object.assign(model.value, jsonClone(toRaw(defaultModel)));
}
function handleSearch() {
emit('search');
}
</script>
<template>
<NCard :bordered="false" size="small" class="card-wrapper">
<NCollapse :default-expanded-names="['region-search']">
<NForm :model="model" label-placement="left" :label-width="80">
<NGrid responsive="screen" item-responsive>
<NFormItemGi span="24 s:12 m:6" :label="$t('page.sys.rbac.region.fields.name')" path="name" class="pr-24px">
<NInput v-model:value="model.query.name" :placeholder="$t('page.sys.rbac.region.fields.name')" clearable />
</NFormItemGi>
<NFormItemGi span="24 s:12 m:6" :label="$t('page.sys.rbac.region.fields.code')" path="code" class="pr-24px">
<NInput v-model:value="model.query.code" :placeholder="$t('page.sys.rbac.region.fields.code')" clearable />
</NFormItemGi>
<NFormItemGi span="24 s:12 m:6">
<NSpace class="w-full" justify="end">
<NButton @click="handleResetModel">
<template #icon>
<icon-ic-round-refresh class="text-icon" />
</template>
{{ $t('common.reset') }}
</NButton>
<NButton type="primary" ghost @click="handleSearch">
<template #icon>
<icon-ic-round-search class="text-icon" />
</template>
{{ $t('common.search') }}
</NButton>
</NSpace>
</NFormItemGi>
</NGrid>
</NForm>
</NCollapse>
</NCard>
</template>
<style scoped></style>