feat: 新增字典管理

This commit is contained in:
2024-04-11 20:33:38 +08:00
parent 4d34979973
commit cc69aaecaf
7 changed files with 593 additions and 0 deletions

54
src/apis/system/dict.ts Normal file
View File

@@ -0,0 +1,54 @@
import http from '@/utils/http'
import type * as System from './type'
const BASE_URL = '/system/dict'
/** @desc 查询字典列表 */
export function listDict(query: System.DictQuery) {
return http.get<PageRes<System.DictResp[]>>(`${BASE_URL}`, query)
}
/** @desc 查询字典详情 */
export function getDict(id: string) {
return http.get<System.DictResp>(`${BASE_URL}/${id}`)
}
/** @desc 新增字典 */
export function addDict(data: any) {
return http.post(`${BASE_URL}`, data)
}
/** @desc 修改字典 */
export function updateDict(data: any, id: string) {
return http.put(`${BASE_URL}/${id}`, data)
}
/** @desc 删除字典 */
export function deleteDict(id: string) {
return http.del(`${BASE_URL}/${id}`)
}
/** @desc 查询字典项列表 */
export function listDictItem(query: System.DictItemQuery) {
return http.get<PageRes<System.DictItemResp[]>>(`${BASE_URL}/item`, query)
}
/** @desc 查询字典项详情 */
export function getDictItem(id: string) {
return http.get<System.DictItemResp>(`${BASE_URL}/item/${id}`)
}
/** @desc 新增字典项 */
export function addDictItem(data: any) {
return http.post(`${BASE_URL}/item`, data)
}
/** @desc 修改字典项 */
export function updateDictItem(data: any, id: string) {
return http.put(`${BASE_URL}/item/${id}`, data)
}
/** @desc 删除字典项 */
export function deleteDictItem(id: string) {
return http.del(`${BASE_URL}/item/${id}`)
}

View File

@@ -1,3 +1,4 @@
export * from './dept' export * from './dept'
export * from './log' export * from './log'
export * from './dict'
export * from './storage' export * from './storage'

View File

@@ -56,6 +56,41 @@ export interface LogQuery{
status?: number status?: number
} }
/** 系统字典类型 */
export interface DictResp {
id: string
name: string
code: string
isSystem: boolean
description: string
createUserString: string
createTime: string
updateUserString: string
updateTime: string
}
export interface DictQuery extends PageQuery {
description?: string
}
export type DictItemResp = {
id: string
label: string
value: string
color: string
sort: number
description: string
status: 1 | 2
dictId: number
createUserString: string
createTime: string
updateUserString: string
updateTime: string
}
export interface DictItemQuery extends PageQuery {
description?: string
status?: number
dictId: string
}
/** 系统存储类型 */ /** 系统存储类型 */
export type StorageResp = { export type StorageResp = {
id: string id: string

View File

@@ -0,0 +1,99 @@
<template>
<a-modal
v-model:visible="visible"
:title="title"
:mask-closable="false"
:esc-to-close="false"
:modal-style="{ maxWidth: '520px' }"
width="90%"
@before-ok="save"
@close="reset"
>
<GiForm ref="formRef" v-model="form" :options="options" :columns="columns" />
</a-modal>
</template>
<script setup lang="ts">
import { getDict, addDict, updateDict } from '@/apis'
import { Message } from '@arco-design/web-vue'
import { GiForm, type Columns } from '@/components/GiForm'
import { useForm } from '@/hooks'
const dataId = ref('')
const isUpdate = computed(() => !!dataId.value)
const title = computed(() => (isUpdate.value ? '修改字典' : '新增字典'))
const formRef = ref<InstanceType<typeof GiForm>>()
const options: Options = {
form: {},
col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 },
btns: { hide: true }
}
const columns: Columns = [
{ label: '名称', field: 'name', type: 'input', rules: [{ required: true, message: '请输入名称' }] },
{ label: '编码', field: 'code', type: 'input', rules: [{ required: true, message: '请输入编码' }] },
{
label: '描述',
field: 'description',
type: 'textarea',
props: {
maxLength: 200,
autoSize: { minRows: 3, maxRows: 5 }
}
}
]
const { form, resetForm } = useForm({
name: '',
code: ''
})
// 重置
const reset = () => {
formRef.value?.formRef?.resetFields()
resetForm()
}
const visible = ref(false)
// 新增
const onAdd = () => {
reset()
dataId.value = ''
visible.value = true
}
// 修改
const onUpdate = async (id: string) => {
reset()
dataId.value = id
const res = await getDict(id)
Object.assign(form, res.data)
visible.value = true
}
// 保存
const save = async () => {
try {
const isInvalid = await formRef.value?.formRef?.validate()
if (isInvalid) return false
if (isUpdate.value) {
await updateDict(form, dataId.value)
Message.success('修改成功')
} else {
await addDict(form)
Message.success('新增成功')
}
emit('save-success')
return true
} catch (error) {
return false
}
}
const emit = defineEmits<{
(e: 'save-success'): void
}>()
defineExpose({ onAdd, onUpdate })
</script>

View File

@@ -0,0 +1,127 @@
<template>
<div class="gi_page">
<a-card title="字典管理" class="general-card">
<GiTable
ref="tableRef"
row-key="id"
:data="dataList"
:columns="columns"
:loading="loading"
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
:pagination="pagination"
:disabledColumnKeys="['name']"
@refresh="search"
>
<template #custom-left>
<a-button type="primary" @click="onAdd">
<template #icon><icon-plus /></template>
<span>新增</span>
</a-button>
</template>
<template #custom-right>
<a-input v-model="queryForm.description" placeholder="请输入关键词" allow-clear @change="search">
<template #prefix><icon-search /></template>
</a-input>
<a-button @click="reset">重置</a-button>
</template>
<template #isSystem="{ record }">
<a-tag v-if="record.isSystem" color="red"></a-tag>
<a-tag v-else color="arcoblue"></a-tag>
</template>
<template #action="{ record }">
<a-space>
<template #split>
<a-divider direction="vertical" :margin="0" />
</template>
<a-link @click="onViewDictItem(record)">管理</a-link>
<a-link @click="onUpdate(record)">修改</a-link>
<a-link
status="danger"
:title="record.isSystem ? '系统内置数据不能删除' : '删除'"
:disabled="record.disabled"
@click="onDelete(record)"
>
删除
</a-link>
</a-space>
</template>
</GiTable>
</a-card>
<AddDictModal ref="AddDictModalRef" @save-success="search" />
<DictItemModal ref="DictItemModalRef" />
</div>
</template>
<script setup lang="ts">
import { listDict, deleteDict, type DictResp } from '@/apis'
import type { TableInstance } from '@arco-design/web-vue'
import AddDictModal from './AddDictModal.vue'
import DictItemModal from '@/views/system/dict/item/index.vue'
import { useTable } from '@/hooks'
import { isMobile } from '@/utils'
defineOptions({ name: 'Dict' })
const columns: TableInstance['columns'] = [
{
title: '序号',
width: 66,
align: 'center',
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize)
},
{ title: '名称', dataIndex: 'name', ellipsis: true, tooltip: true },
{ title: '编码', dataIndex: 'code', width: 170, ellipsis: true, tooltip: true },
{ title: '系统内置', slotName: 'isSystem', align: 'center', show: false },
{ title: '描述', dataIndex: 'description', ellipsis: true, tooltip: true },
{ title: '创建人', dataIndex: 'createUserString', show: false, ellipsis: true, tooltip: true },
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
{ title: '修改人', dataIndex: 'updateUserString', show: false, ellipsis: true, tooltip: true },
{ title: '修改时间', dataIndex: 'updateTime', width: 180, show: false },
{ title: '操作', slotName: 'action', width: 200, align: 'center', fixed: !isMobile() ? 'right' : undefined }
]
const queryForm = reactive({
description: undefined,
sort: ['createTime,desc']
})
const {
tableData: dataList,
loading,
pagination,
search,
handleDelete
} = useTable((p) => listDict({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
// 重置
const reset = () => {
queryForm.description = undefined
queryForm.status = undefined
search()
}
// 删除
const onDelete = (item: DictResp) => {
return handleDelete(() => deleteDict(item.id), { content: `是否确定删除字典 [${item.name}]`, showModal: true })
}
const AddDictModalRef = ref<InstanceType<typeof AddDictModal>>()
// 新增
const onAdd = () => {
AddDictModalRef.value?.onAdd()
}
// 修改
const onUpdate = (item: DictResp) => {
AddDictModalRef.value?.onUpdate(item.id)
}
const DictItemModalRef = ref<InstanceType<typeof DictItemModal>>()
// 查看字典项
const onViewDictItem = (item: DictResp) => {
DictItemModalRef.value?.open(item.id, item.code)
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,134 @@
<template>
<a-modal
v-model:visible="visible"
:title="title"
:mask-closable="false"
:esc-to-close="false"
:modal-style="{ maxWidth: '520px' }"
width="90%"
@before-ok="save"
@close="reset"
>
<GiForm ref="formRef" v-model="form" :options="options" :columns="columns">
<template #color>
<a-input v-model="form.color" placeholder="请选择或输入标签颜色" allow-clear>
<template #suffix>
<a-color-picker v-model="form.color" />
</template>
</a-input>
</template>
</GiForm>
</a-modal>
</template>
<script setup lang="ts">
import { getDictItem, addDictItem, updateDictItem } from '@/apis'
import { Message } from '@arco-design/web-vue'
import { GiForm, type Columns } from '@/components/GiForm'
import { useForm } from '@/hooks'
const dictId = ref('')
const dataId = ref('')
const isUpdate = computed(() => !!dataId.value)
const title = computed(() => (isUpdate.value ? '修改字典项' : '新增字典项'))
const formRef = ref<InstanceType<typeof GiForm>>()
const options: Options = {
form: {},
col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 },
btns: { hide: true }
}
const columns: Columns = [
{ label: '标签', field: 'label', type: 'input', rules: [{ required: true, message: '请输入标签' }] },
{ label: '值', field: 'value', type: 'input', rules: [{ required: true, message: '请输入值' }] },
{ label: '标签颜色', field: 'color', type: 'input' },
{
label: '排序',
field: 'sort',
type: 'input-number',
props: {
min: 1,
mode: 'button'
}
},
{
label: '描述',
field: 'description',
type: 'textarea',
props: {
maxLength: 200,
autoSize: { minRows: 3, maxRows: 5 }
}
},
{
label: '状态',
field: 'status',
type: 'switch',
props: {
type: 'round',
checkedValue: 1,
uncheckedValue: 2,
checkedText: '启用',
uncheckedText: '禁用'
}
}
]
const { form, resetForm } = useForm({
label: '',
value: '',
color: '',
sort: 999,
status: 1
})
// 重置
const reset = () => {
formRef.value?.formRef?.resetFields()
resetForm()
}
const visible = ref(false)
// 新增
const onAdd = (id: string) => {
reset()
dictId.value = id
dataId.value = ''
visible.value = true
}
// 修改
const onUpdate = async (id: string) => {
reset()
dataId.value = id
const res = await getDictItem(id)
Object.assign(form, res.data)
visible.value = true
}
// 保存
const save = async () => {
try {
const isInvalid = await formRef.value?.formRef?.validate()
if (isInvalid) return false
if (isUpdate.value) {
await updateDictItem(form, dataId.value)
Message.success('修改成功')
} else {
await addDictItem({ ...form, dictId: dictId.value })
Message.success('新增成功')
}
emit('save-success')
return true
} catch (error) {
return false
}
}
const emit = defineEmits<{
(e: 'save-success'): void
}>()
defineExpose({ onAdd, onUpdate })
</script>

View File

@@ -0,0 +1,143 @@
<template>
<a-modal
v-model:visible="visible"
:title="'字典项管理(' + dictCode + ')'"
title-align="start"
:mask-closable="false"
:esc-to-close="false"
:modal-style="{ maxWidth: '780px' }"
width="90%"
ok-text="关闭"
hide-cancel
>
<GiTable
ref="tableRef"
row-key="id"
:data="dataList"
:columns="columns"
:loading="loading"
:scroll="{ x: '100%', y: '100%', minWidth: 780 }"
:pagination="pagination"
:disabledColumnKeys="['label']"
@refresh="search"
>
<template #custom-left>
<a-button type="primary" @click="onAdd">
<template #icon><icon-plus /></template>
<span>新增</span>
</a-button>
</template>
<template #custom-right>
<a-input v-model="queryForm.description" placeholder="请输入关键词" allow-clear @change="search">
<template #prefix><icon-search /></template>
</a-input>
<a-button @click="reset">重置</a-button>
</template>
<template #label="{ record }">
<a-tag :color="record.color">{{ record.label }}</a-tag>
</template>
<template #status="{ record }">
<GiCellStatus :status="record.status" />
</template>
<template #action="{ record }">
<a-space>
<template #split>
<a-divider direction="vertical" :margin="0" />
</template>
<a-link @click="onUpdate(record)">修改</a-link>
<a-popconfirm
type="warning"
content="是否确定删除该条数据?"
:ok-button-props="{ status: 'danger' }"
@ok="onDelete(record)"
>
<a-link status="danger">删除</a-link>
</a-popconfirm>
</a-space>
</template>
</GiTable>
<AddDictItemModal ref="AddDictItemModalRef" @save-success="search" />
</a-modal>
</template>
<script lang="ts" setup>
import { listDictItem, deleteDictItem, type DictItemResp } from '@/apis'
import type { TableInstance } from '@arco-design/web-vue'
import AddDictItemModal from './AddDictItemModal.vue'
import { useTable } from '@/hooks'
import { isMobile } from '@/utils'
const columns: TableInstance['columns'] = [
{
title: '序号',
width: 66,
align: 'center',
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize)
},
{ title: '标签', dataIndex: 'label', slotName: 'label' },
{ title: '值', dataIndex: 'value', ellipsis: true, tooltip: true },
{ title: '状态', slotName: 'status', align: 'center' },
{ title: '排序', dataIndex: 'sort', show: false },
{ title: '描述', dataIndex: 'description', ellipsis: true, tooltip: true },
{ title: '创建人', dataIndex: 'createUserString', show: false, ellipsis: true, tooltip: true },
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
{ title: '修改人', dataIndex: 'updateUserString', show: false, ellipsis: true, tooltip: true },
{ title: '修改时间', dataIndex: 'updateTime', width: 180, show: false },
{ title: '操作', slotName: 'action', width: 130, align: 'center', fixed: !isMobile() ? 'right' : undefined }
]
const queryForm = reactive({
description: undefined,
status: undefined,
sort: ['createTime,desc']
})
const dictId = ref('')
const dictCode = ref('')
const visible = ref(false)
// 打开
const open = (id: string, code: string) => {
dataList.value = []
dictId.value = id
dictCode.value = code
visible.value = true
search()
}
defineExpose({ open })
const {
tableData: dataList,
loading,
pagination,
search,
handleDelete
} = useTable((p) => listDictItem({ ...queryForm, dictId: dictId.value, page: p.page, size: p.size }), {
immediate: true
})
// 重置
const reset = () => {
queryForm.description = undefined
queryForm.status = undefined
search()
}
// 删除
const onDelete = (item: DictItemResp) => {
return handleDelete(() => deleteDictItem(item.id), { content: `是否确定删除 [${item.label}]`, showModal: false })
}
const AddDictItemModalRef = ref<InstanceType<typeof AddDictItemModal>>()
// 新增
const onAdd = () => {
AddDictItemModalRef.value?.onAdd(dictId.value)
}
// 修改
const onUpdate = (item: DictItemResp) => {
AddDictItemModalRef.value?.onUpdate(item.id)
}
</script>
<style lang="scss" scoped></style>