feat:新增字典管理

This commit is contained in:
5g0Wp7Zy 2025-09-09 16:22:50 +08:00
parent a906c23b8a
commit aa5a4d645a
3 changed files with 415 additions and 212 deletions

View File

@ -6,7 +6,11 @@ import {
StaffRoleFormType,
AddFromType,
AddStaffFromType,
StaffListParams
StaffListParams,
DictListParams,
AddDictFormType,
DictItemListParams,
AddDictItemFormType
} from "./types";
// 获取菜单数据
@ -251,3 +255,75 @@ export const getStaffByIdAPI = (staffId: string) => {
params: { staffId }
});
};
// 字典分页查询
export const getDictListAPI = (params: DictListParams) => {
return axios({
url: "staff/ebikeDic/page",
method: "get",
params
});
};
// 添加字典表
export const addDictAPI = (data: AddDictFormType) => {
return axios({
url: "/staff/ebikeDic/save",
method: "post",
data
});
};
// 根据主键更新字典表
export const updateDictAPI = (data: AddDictFormType) => {
return axios({
url: "/staff/ebikeDic/update",
method: "post",
data
});
};
// 根据主键删除字典表
export const delDictAPI = (dicId: string) => {
return axios({
url: `/staff/ebikeDic/remove`,
method: "get",
params: { dicId }
});
};
// 分页查询字典数据项
export const getDictItemListAPI = (params: DictItemListParams) => {
return axios({
url: "staff/ebikeDicValue/page",
method: "get",
params
});
};
// 添加字典数据项
export const addDictItemAPI = (data: AddDictItemFormType) => {
return axios({
url: "/staff/ebikeDicValue/save",
method: "post",
data
});
};
// 根据主键更新字典数据项
export const updateDictItemAPI = (data: AddDictItemFormType) => {
return axios({
url: "/staff/ebikeDicValue/update",
method: "post",
data
});
};
// 根据主键删除字典数据项
export const delDictItemAPI = (dicValueId: string) => {
return axios({
url: `/staff/ebikeDicValue/remove`,
method: "get",
params: { dicValueId }
});
};

View File

@ -1,43 +1,43 @@
type ListType = {
interface ListType {
pageNum: number;
pageSize: number;
};
}
// 运营商列表查询参数
export type OperatorListParams = ListType & {
export interface OperatorListParams extends ListType {
operatorName?: string;
};
}
//添加运营商
export type OperatorFormType = {
export interface OperatorFormType {
operatorId?: string;
operatorName: string;
contactPhone: string;
address: string;
};
}
// 员工角色表查询参数
export type StaffRoleListParams = ListType & {
export interface StaffRoleListParams extends ListType {
roleName?: string;
};
}
// 运营商员工查询参数
export type StaffListParams = ListType & {
export interface StaffListParams extends ListType {
username?: string;
contactPhone?: string;
};
}
// 添加员工角色
export type StaffRoleFormType = {
export interface StaffRoleFormType {
roleId?: string;
roleName: string;
roleCode: string;
operatorId: string;
description?: string;
};
}
// 添加系统权限表
export type AddFromType = {
export interface AddFromType {
id?: string; // ID
type: 1 | 2 | 3; // 1: 目录, 2: 菜单, 3: 按钮
parentId: string; // 父级ID
@ -50,10 +50,10 @@ export type AddFromType = {
component: string; // 组件
permissionId: string; // 权限标识
buttonCode: string; // 按钮编码
};
}
// 添加运营商员工
export type AddStaffFromType = {
export interface AddStaffFromType {
staffId?: string; // 员工ID
username: string; // 用户名
password: string; // 密码
@ -61,4 +61,30 @@ export type AddStaffFromType = {
status: 1 | 2; // 状态 1: 启用, 2: 禁用
operatorId: string; // 运营商ID
roleIds?: string[]; // 角色ID数组
};
}
// 字典查询参数
export interface DictListParams extends ListType {
dicName?: string; // 字典名称
dicCode?: string; // 字典编码
}
// 添加字典表
export interface AddDictFormType {
dicId?: string; // ID
dicName: string; // 字典名称
dicCode: string; // 字典编码
}
// 分页查询字典数据项
export interface DictItemListParams extends ListType {
dicCode: string; // 字典编码
}
// 添加字典数据项
export interface AddDictItemFormType {
dicValueId?: string; // 数据项ID
dicValueName: string; // 数据项名称
dicValue: string; // 数据项值
dicId: string; // 字典ID
}

View File

@ -4,11 +4,8 @@
<s-layout-tools>
<template #left>
<a-space wrap>
<a-input v-model="form.name" placeholder="请输入字典名称" allow-clear />
<a-input v-model="form.code" placeholder="请输入字典编码" allow-clear />
<a-select placeholder="启用状态" v-model="form.status" style="width: 120px" allow-clear>
<a-option v-for="item in openState" :key="item.value" :value="item.value">{{ item.name }}</a-option>
</a-select>
<a-input v-model="form.dicName" placeholder="请输入字典名称" allow-clear />
<a-input v-model="form.dicCode" placeholder="请输入字典码" allow-clear />
<a-button type="primary" @click="search">
<template #icon><icon-search /></template>
<span>查询</span>
@ -25,40 +22,21 @@
<template #icon><icon-plus /></template>
<span>新增</span>
</a-button>
<a-button type="primary" status="danger">
<template #icon><icon-delete /></template>
<span>删除</span>
</a-button>
</a-space>
</template>
</s-layout-tools>
<a-table
row-key="id"
:data="dictList"
row-key="dicId"
:data="roleList"
:bordered="{ cell: true }"
:loading="loading"
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
:pagination="pagination"
:row-selection="{ type: 'checkbox', showCheckedAll: true }"
:selected-keys="selectedKeys"
@select="select"
@select-all="selectAll"
>
<template #columns>
<a-table-column title="序号" :width="64">
<template #cell="cell">{{ cell.rowIndex + 1 }}</template>
</a-table-column>
<a-table-column title="字典名称" data-index="name"></a-table-column>
<a-table-column title="字典编码" data-index="code"></a-table-column>
<a-table-column title="状态" :width="100" align="center">
<template #cell="{ record }">
<a-tag bordered size="small" color="arcoblue" v-if="record.status === 1">启用</a-tag>
<a-tag bordered size="small" color="red" v-else>禁用</a-tag>
</template>
</a-table-column>
<a-table-column title="描述" data-index="description" :ellipsis="true" :tooltip="true"></a-table-column>
<a-table-column title="创建时间" data-index="createTime" :width="180"></a-table-column>
<a-table-column title="字典名称" data-index="dicName" align="center"></a-table-column>
<a-table-column title="字典码" data-index="dicCode" align="center"></a-table-column>
<a-table-column title="创建时间" data-index="createTime" align="center"></a-table-column>
<a-table-column title="操作" :width="280" align="center" :fixed="'right'">
<template #cell="{ record }">
<a-space>
@ -70,7 +48,7 @@
<template #icon><icon-edit /></template>
<span>修改</span>
</a-button>
<a-popconfirm type="warning" content="确定删除该字典吗?">
<a-popconfirm type="warning" content="确定删除该字典吗?" @ok="onDelete(record)">
<a-button type="primary" status="danger" size="mini">
<template #icon><icon-delete /></template>
<span>删除</span>
@ -83,29 +61,22 @@
</a-table>
</div>
<a-modal v-model:visible="open" @close="afterClose" @ok="handleOk" @cancel="afterClose">
<!-- 新增弹窗 -->
<a-modal width="40%" v-model:visible="open" @close="afterClose" @before-ok="handleOk" @cancel="afterClose">
<template #title> {{ title }} </template>
<div>
<a-form ref="formRef" auto-label-width :rules="rules" :model="addFrom">
<a-form-item field="name" label="字典名称" validate-trigger="blur">
<a-input v-model="addFrom.name" placeholder="请输入字典名称" allow-clear />
<a-form ref="formRef" auto-label-width :rules="rules" :model="addForm">
<a-form-item field="dicName" label="字典名称" validate-trigger="blur">
<a-input v-model="addForm.dicName" placeholder="请输入字典名称" allow-clear />
</a-form-item>
<a-form-item field="code" label="字典编码" validate-trigger="blur">
<a-input v-model="addFrom.code" placeholder="请输入字典编码" allow-clear />
</a-form-item>
<a-form-item field="description" label="描述" validate-trigger="blur">
<a-textarea v-model="addFrom.description" placeholder="请输入字典描述" allow-clear />
</a-form-item>
<a-form-item field="description" label="状态" validate-trigger="blur">
<a-switch type="round" :checked-value="1" :unchecked-value="0" v-model="addFrom.status">
<template #checked> 启用 </template>
<template #unchecked> 禁用 </template>
</a-switch>
<a-form-item field="dicCode" label="字典编码" validate-trigger="blur">
<a-input v-model="addForm.dicCode" placeholder="请输入字典编码" allow-clear />
</a-form-item>
</a-form>
</div>
</a-modal>
<!-- 字典详情 -->
<a-modal width="50%" v-model:visible="detailOpen" @ok="detailOk" ok-text="关闭" :hide-cancel="true">
<template #title> 字典详情 </template>
<div>
@ -115,37 +86,22 @@
<template #icon><icon-plus /></template>
<span>新增</span>
</a-button>
<a-button type="primary" status="danger">
<template #icon><icon-delete /></template>
<span>删除</span>
</a-button>
</a-space>
</a-row>
<a-table
row-key="id"
:data="dictDetail.list"
:bordered="{ cell: true }"
:loading="detailLoading"
:scroll="{ x: '100%', y: '100%' }"
:pagination="pagination"
:row-selection="{ type: 'checkbox', showCheckedAll: true }"
:selected-keys="selectedKeysDetail"
@select="selectDetail"
@select-all="selectAllDetail"
:pagination="dictDetailPagination"
>
<template #columns>
<a-table-column title="序号" :width="64">
<template #cell="cell">{{ cell.rowIndex + 1 }}</template>
</a-table-column>
<a-table-column title="字典名" data-index="name"></a-table-column>
<a-table-column title="字典值" data-index="value"></a-table-column>
<a-table-column title="状态" :width="100" align="center">
<template #cell="{ record }">
<a-tag bordered size="small" color="arcoblue" v-if="record.status === 1">启用</a-tag>
<a-tag bordered size="small" color="red" v-else>禁用</a-tag>
</template>
</a-table-column>
<a-table-column title="字典名" data-index="dicValueName" align="center"></a-table-column>
<a-table-column title="字典值" data-index="dicValue" align="center"></a-table-column>
<a-table-column title="操作" align="center" :fixed="'right'">
<template #cell="{ record }">
<a-space>
@ -153,7 +109,7 @@
<template #icon><icon-edit /></template>
<span>修改</span>
</a-button>
<a-popconfirm type="warning" content="确定删除该字典吗?">
<a-popconfirm type="warning" content="确定删除该字典吗?" @ok="onDetailDelete(record)">
<a-button type="primary" status="danger" size="mini">
<template #icon><icon-delete /></template>
<span>删除</span>
@ -167,21 +123,16 @@
</div>
</a-modal>
<a-modal v-model:visible="detailCaseOpen" @close="afterCloseDetail" @ok="handleOkDetail" @cancel="afterCloseDetail">
<!-- 添加字典字段 -->
<a-modal v-model:visible="detailCaseOpen" @close="afterCloseDetail" @before-ok="handleOkDetail" @cancel="afterCloseDetail">
<template #title> {{ detailTitle }} </template>
<div>
<a-form ref="detailFormRef" auto-label-width :rules="detaulRules" :model="deatilForm">
<a-form-item field="name" label="字典名称" validate-trigger="blur">
<a-input v-model="deatilForm.name" placeholder="请输入字典名称" allow-clear />
<a-form-item field="dicValueName" label="字典名称" validate-trigger="blur">
<a-input v-model="deatilForm.dicValueName" placeholder="请输入字典名称" allow-clear />
</a-form-item>
<a-form-item field="value" label="字典值" validate-trigger="blur">
<a-input v-model="deatilForm.value" placeholder="请输入字典值" allow-clear />
</a-form-item>
<a-form-item field="description" label="状态" validate-trigger="blur">
<a-switch type="round" :checked-value="1" :unchecked-value="0" v-model="deatilForm.status">
<template #checked> 启用 </template>
<template #unchecked> 禁用 </template>
</a-switch>
<a-form-item field="dicValue" label="字典值" validate-trigger="blur">
<a-input v-model="deatilForm.dicValue" placeholder="请输入字典值" allow-clear />
</a-form-item>
</a-form>
</div>
@ -190,176 +141,326 @@
</template>
<script setup lang="ts">
import { getDictAPI } from "@/api/modules/system/index";
import {
getDictListAPI,
addDictAPI,
updateDictAPI,
delDictAPI,
getDictItemListAPI,
addDictItemAPI,
updateDictItemAPI,
delDictItemAPI
} from "@/api/modules/system";
import { deepClone } from "@/utils";
const openState = ref(dictFilter("status"));
const form = ref({
name: "",
code: "",
status: null
});
const search = () => {
getDict();
};
const reset = () => {
form.value = {
name: "",
code: "",
status: null
};
getDict();
};
import { AddDictFormType, AddDictItemFormType } from "@/api/modules/system/types";
const open = ref<boolean>(false);
const title = ref<string>("");
const form = ref<{
dicName: string;
dicCode: string;
}>({
dicName: "",
dicCode: ""
});
//
const roleList = ref([]);
const loading = ref(false);
const pagination = ref({
pageNum: 1,
pageSize: 10,
showPageSize: true,
showTotal: true
});
// /
const open = ref(false);
const title = ref("");
const formRef = ref();
const rules = {
name: [
dicName: [
{
required: true,
message: "请输入字典名称"
}
],
code: [
dicCode: [
{
required: true,
message: "请输入字典编码"
}
],
status: [
{
required: true,
message: "请选择状态"
}
]
};
const addFrom = ref({
name: "",
code: "",
description: "",
status: 1
const addForm = ref<AddDictFormType>({
dicName: "",
dicCode: ""
});
const formRef = ref();
const onAdd = () => {
open.value = true;
title.value = "新增字典";
};
const handleOk = async () => {
let state = await formRef.value.validate();
if (state) return (open.value = true); //
arcoMessage("success", "模拟提交成功");
getDict();
};
//
const afterClose = () => {
formRef.value.resetFields();
addFrom.value = {
name: "",
code: "",
description: "",
status: 1
};
};
const onUpdate = (record: any) => {
title.value = "修改字典";
addFrom.value = deepClone(record);
open.value = true;
};
const loading = ref(false);
const pagination = ref({
pageSize: 10,
showPageSize: true
});
const selectedKeys = ref([]);
const select = (list: []) => {
selectedKeys.value = list;
};
const selectAll = (state: boolean) => {
selectedKeys.value = state ? (dictList.value.map((el: any) => el.id) as []) : [];
};
const dictList = ref();
//
const getDict = async () => {
loading.value = true;
let res = await getDictAPI();
dictList.value = res.data || [];
const res: any = await getDictListAPI({
dicName: form.value.dicName,
dicCode: form.value.dicCode,
pageNum: pagination.value.pageNum,
pageSize: pagination.value.pageSize
});
loading.value = false;
if (res.code !== 200) {
return;
}
const { records, pageNumber, pageSize } = res.data;
pagination.value.pageNum = pageNumber;
pagination.value.pageSize = pageSize;
roleList.value = records;
};
//
//
const search = () => {
pagination.value.pageNum = 1;
getDict();
};
//
const reset = () => {
form.value = {
dicName: "",
dicCode: ""
};
pagination.value.pageNum = 1;
getDict();
};
const onAdd = () => {
title.value = "新增字典";
open.value = true;
addForm.value = {
dicName: "",
dicCode: ""
};
};
//
const onUpdate = (record: any) => {
title.value = "修改字典";
open.value = true;
addForm.value.dicId = record.dicId;
addForm.value.dicName = record.dicName;
addForm.value.dicCode = record.dicCode;
};
//
const onDelete = async (record: any) => {
try {
let res: any = await delDictAPI(record.dicId);
if (res.code === 200) {
arcoMessage("success", "删除成功");
getDict();
}
} catch (error: any) {
console.error(error);
}
};
//
const resetForm = () => {
formRef.value.resetFields();
addForm.value = {
dicName: "",
dicCode: ""
};
};
//
const afterClose = () => {
resetForm();
};
//
const handleOk = async () => {
let state = await formRef.value.validate();
if (state) return false; //
if (addForm.value.dicId) {
try {
let res: any = await updateDictAPI(deepClone(addForm.value));
if (res.code === 200) {
arcoMessage("success", "修改成功");
resetForm();
getDict();
return true;
}
} catch (error: any) {
console.error(error);
return false;
}
} else {
try {
console.log(deepClone(addForm.value));
let res: any = await addDictAPI(deepClone(addForm.value));
if (res.code === 200) {
arcoMessage("success", "新增成功");
resetForm();
getDict();
return true;
}
} catch (error: any) {
console.error(error);
return false;
}
}
};
/**
* 字典详情
**/
const detailLoading = ref(false);
const detailOpen = ref(false);
const dictDetail = ref({
list: []
});
const recordData = ref<any>({});
const dictDetailPagination = ref({
pageNum: 1,
pageSize: 10,
showPageSize: true,
showTotal: true
});
//
const onDictData = (record: any) => {
detailLoading.value = true;
dictDetail.value = record;
detailOpen.value = true;
recordData.value = record;
getDictItemList(recordData.value);
};
//
const getDictItemList = async (record: any) => {
detailLoading.value = true;
const res: any = await getDictItemListAPI({
dicCode: record.dicCode,
pageNum: dictDetailPagination.value.pageNum,
pageSize: dictDetailPagination.value.pageSize
});
detailLoading.value = false;
if (res.code !== 200) {
return;
}
const { records, pageNumber, pageSize } = res.data;
dictDetailPagination.value.pageNum = pageNumber;
dictDetailPagination.value.pageSize = pageSize;
dictDetail.value.list = records;
};
const detailOk = () => {
detailOpen.value = false;
//
const detailOk = async () => {};
const onAddDetail = () => {
detailTitle.value = "新增字典数据";
detailCaseOpen.value = true;
deatilForm.value.dicId = recordData.value.dicId;
};
const deatilForm = ref({
name: "",
value: "",
status: 1
//
const onDetailUpdate = (record: any) => {
detailTitle.value = "修改字典数据";
detailCaseOpen.value = true;
deatilForm.value.dicValueId = record.dicValueId;
deatilForm.value.dicValueName = record.dicValueName;
deatilForm.value.dicValue = record.dicValue;
deatilForm.value.dicId = recordData.value.dicId;
};
/**
* 添加字典字段
**/
const detailFormRef = ref();
const detailTitle = ref("");
const detailCaseOpen = ref(false);
const deatilForm = ref<AddDictItemFormType>({
dicValueName: "",
dicValue: "",
dicId: ""
});
const detaulRules = ref({
name: [
dicValueName: [
{
required: true,
message: "请输入字典名称"
}
],
value: [
dicValue: [
{
required: true,
message: "请输入字典值"
}
],
status: [
{
required: true,
message: "请选择状态"
}
]
});
const detailFormRef = ref();
const detailTitle = ref("");
const detailCaseOpen = ref(false);
const onAddDetail = () => {
detailTitle.value = "新增字典数据";
detailCaseOpen.value = true;
};
//
const handleOkDetail = async () => {
let state = await detailFormRef.value.validate();
if (state) return (detailCaseOpen.value = true); //
arcoMessage("success", "模拟提交成功");
if (state) return false; //
if (deatilForm.value.dicValueId) {
try {
let res: any = await updateDictItemAPI(deepClone(deatilForm.value));
if (res.code === 200) {
arcoMessage("success", "修改成功");
resetDetailForm();
getDictItemList(recordData.value);
return true;
}
} catch (error: any) {
console.error(error);
return false;
}
} else {
try {
let res: any = await addDictItemAPI(deepClone(deatilForm.value));
if (res.code === 200) {
arcoMessage("success", "新增成功");
resetDetailForm();
getDictItemList(recordData.value);
return true;
}
} catch (error: any) {
console.error(error);
return false;
}
}
};
const onDetailUpdate = (record: any) => {
detailTitle.value = "修改字典数据";
deatilForm.value = deepClone(record);
detailCaseOpen.value = true;
};
//
const afterCloseDetail = () => {
//
const resetDetailForm = () => {
detailFormRef.value.resetFields();
deatilForm.value = {
name: "",
value: "",
status: 1
dicValueName: "",
dicValue: "",
dicId: ""
};
};
const selectedKeysDetail = ref([]);
const selectDetail = (list: []) => {
selectedKeysDetail.value = list;
};
const selectAllDetail = (state: boolean) => {
selectedKeysDetail.value = state ? (dictDetail.value.list.map((el: any) => el.id) as []) : [];
//
const afterCloseDetail = () => {
resetDetailForm();
};
getDict();
//
const onDetailDelete = async (record: any) => {
try {
let res: any = await delDictItemAPI(record.dicValueId);
if (res.code === 200) {
arcoMessage("success", "删除成功");
getDictItemList(recordData.value);
}
} catch (error: any) {
console.error(error);
}
};
onMounted(() => {
getDict();
});
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.text-right-gap {
margin-right: $margin;
}
</style>