feat: 数据字典

This commit is contained in:
leiqiaochu 2023-09-04 19:15:23 +08:00
parent d72e88d725
commit dfc1d1556c
5 changed files with 372 additions and 66 deletions

View File

@ -5,6 +5,10 @@ import server, { request } from '@/utils/request';
*/
export const getDicList = (data:any) => request.post('/dictionary/_query/no-paging',data)
/**
*
*/
export const getDic_page = (data:any) => request.post('/dictionary/_query',data)
/**
* ID是否重复
*/
@ -28,4 +32,19 @@ export const queryDicItem = (data:any)=>request.post('/dictionary-item/_query',d
/**
*
*/
export const saveDicItem = (data:any) => request.patch('/dictionary-item',data)
export const saveDicItem = (data:any) => request.patch('/dictionary-item',data)
/**
*
*/
export const deleteDicItem = (id:string) => request.delete(`/dictionary-item/${id}`)
/**
* value唯一
*/
export const verifyValue = (data:any) => request.post('/dictionary-item/_exists',data)
/**
*
*/
export const downDic = (data:any) => request.post('/dictionary/detail/_query',data)

View File

@ -0,0 +1,97 @@
<template>
<j-modal visible title="下载" @cancel="close" @ok="downLoad" :maskClosable="false"
:confirmLoading="loading" :width="900">
<JProTable
:columns="columns"
model="CARD"
:request="getDic_page"
:gridColumn="2"
>
<template #headerTitle>
请选择需要下载的字典
</template>
<template #card="slotProps">
<CardBox :value="slotProps" :showStatus="false" :active="_selectedRowKeys.includes(slotProps.id)" @click="onSelectChange">
<template #content>
<j-row>
<j-col :span="12">
<Ellipsis style="width: 100%">
<div>字典名称{{ slotProps.name }}</div>
</Ellipsis>
</j-col>
<j-col :span="12">
<Ellipsis style="width: 100%">
字典ID{{ slotProps.id }}
</Ellipsis>
</j-col>
</j-row>
</template>
</CardBox>
</template>
</JProTable>
</j-modal>
</template>
<script lang="ts" setup>
import { getDic_page , downDic} from '@/api/system/dictionary';
import { onlyMessage } from '@/utils/comm';
import { downloadFileByUrl } from '@/utils/utils';
import dayjs from 'dayjs';
const emit = defineEmits(['closeDown'])
const loading = ref(false)
const columns = [ {
title:'name',
dataIndex:'name',
key:'name',
ellipsis: true,
},
{
title: 'name',
dataIndex: 'name',
key: 'name',
ellipsis: true,
}]
const _selectedRowKeys:any = ref([])
const onSelectChange = (dt: any) => {
if (_selectedRowKeys.value.includes(dt.id)) {
const _index = _selectedRowKeys.value.findIndex((i:any) => i === dt.id);
_selectedRowKeys.value.splice(_index, 1);
} else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
}
};
const close = () =>{
emit('closeDown')
}
const downLoad = async() =>{
if(_selectedRowKeys.value.length){
const res:any = await downDic({
terms:[
{
terms:[
{
value:_selectedRowKeys.value,
termType:'in',
column:'id'
}
]
}
]
})
if(res.status === 200 && res.result){
const json = JSON.stringify(res.result)
if (json) {
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
downloadFileByUrl(url, `数据字典${dayjs().format('YYYY-MM-DD HH:mm:ss')}`, 'json');
emit('closeDown');
}
emit('closeDown')
}
}else{
onlyMessage('至少选择一条数据!')
}
}
</script>
<style lang="less" scoped>
</style>

View File

@ -6,9 +6,30 @@
</template>
</j-input>
<div class="controls">
<j-button type="primary" @click="showSave" style="width: 60%;">新增字典</j-button>
<j-button type="text">下载</j-button>
<j-button type="text">导入</j-button>
<PermissionButton
type="primary"
:hasPermission="true"
@click="showSave"
style="width: 60%"
>
新增字典
</PermissionButton>
<!-- <j-button type="primary" @click="showSave" style="width: 60%;">新增字典</j-button> -->
<PermissionButton
type="text"
:hasPermission="true"
@click="downVisible=true"
>
下载
</PermissionButton>
<!-- <j-button type="text" @click="downVisible=true">下载</j-button> -->
<j-upload
:before-upload="beforeUpload"
accept=".json"
:show-upload-list="false"
>
<j-button type="text">导入</j-button>
</j-upload>
</div>
<div>
@ -16,14 +37,31 @@
<template #title="item">
<div class="treeItem" @click="()=>selectDic(item.data)">
<div class="itemText">{{ item.name }}</div>
<div>
<div @click="(e) => e.stopPropagation()">
<j-popconfirm :title="item.data.status === 1 ? '确定禁用?' : '确定启用?'" @confirm="()=>updateDic(item.data)">
<j-switch v-model:checked="item.status" :checkedValue="1" :unCheckedValue="0"></j-switch>
</j-popconfirm>
<j-popconfirm title="确认删除?" @confirm="()=>deleteDic(item.id)">
<PermissionButton
type="text"
:hasPermission="true"
:popConfirm="{
title: `确定要删除?`,
onConfirm: () => deleteDic(item.id),
}"
>
删除
</PermissionButton>
<!-- <j-popconfirm title="确认删除?" @confirm="()=>deleteDic(item.id)">
<j-button type="text">删除</j-button>
</j-popconfirm>
<j-button type="text" @click="()=>showEdit(item.data)">编辑</j-button>
</j-popconfirm> -->
<PermissionButton
type="text"
:hasPermission="true"
@click="showEdit(item.data)"
>
编辑
</PermissionButton>
<!-- <j-button type="text" @click="()=>showEdit(item.data)">编辑</j-button> -->
</div>
</div>
</template>
@ -31,12 +69,15 @@
</div>
</div>
<Save v-if="saveShow" :type="addType" @close-save="saveShow = false" @success="saveSuccess" :data="editData"/>
<Export v-if="downVisible" @closeDown="closeDown"/>
<Import/>
</template>
<script lang="ts" setup>
import { getDicList ,deleteDictionary,addDictionary} from '@/api/system/dictionary';
import Save from './save/index.vue'
import { onlyMessage } from '@/utils/comm';
import { onlyMessage} from '@/utils/comm';
import Export from './Export/index.vue'
const emit = defineEmits(['selectData'])
const saveShow = ref(false)
const addType = ref('add')
@ -47,6 +88,7 @@ const showSave = () =>{
saveShow.value = true
addType.value = 'add'
}
const downVisible = ref(false)
const queryData = (first?:Boolean) =>{
getDicList({sorts: [{ name: 'createTime', order: 'desc' }]}).then((res:any)=>{
if(res.status === 200){
@ -81,7 +123,7 @@ const deleteDic = (id:string) =>{
deleteDictionary(id).then((res:any)=>{
if(res.status === 200){
onlyMessage('操作成功!')
reload()
queryData(true)
}else{
onlyMessage('操作失败!','error')
}
@ -108,6 +150,33 @@ const selectDic = (selectKeys:any)=>{
selectedKeys.value = [selectKeys.id]
emit('selectData',selectKeys)
}
/**
* 导入字典
*/
const beforeUpload = (file:any) => {
if(file.type === 'application/json') {
const reader = new FileReader();
reader.readAsText(file);
reader.onload = async(json) => {
if(json.target?.result){
const data = JSON.parse(json.target?.result);
const res =await addDictionary(data)
if(res.status === 200){
reload()
onlyMessage('操作成功!')
}
} else {
onlyMessage('文件内容不能为空', 'error')
}
};
} else {
onlyMessage('请上传json格式的文件', 'error')
}
};
const closeDown = () =>{
downVisible.value = false
}
onMounted(()=>{
queryData(true)
})

View File

@ -1,53 +1,59 @@
<template>
<j-modal visible :title="type ==='add' ? '新增':'编辑'" @cancel="close" @ok="submitData" :maskClosable="false" :confirmLoading="loading">
<j-form :model="form" layout="vertical" :rules="rules" ref="formRef">
<j-form-item label="name" name="name">
<j-input placeholder="con_type" v-model:value="form.name"></j-input>
</j-form-item>
<j-form-item label="value" name="value">
<j-input placeholder="con_type" v-model:value="form.value"></j-input>
</j-form-item>
<j-form-item label="text" name="text">
<j-input placeholder="连接失败" v-model:value="form.text"></j-input>
</j-form-item>
</j-form>
</j-modal>
<j-modal visible :title="type === 'add' ? '新增' : '编辑'" @cancel="close" @ok="submitData" :maskClosable="false"
:confirmLoading="loading">
<j-form :model="form" layout="vertical" :rules="rules" ref="formRef">
<j-form-item label="name" name="name">
<j-input placeholder="con_type" v-model:value="form.name"></j-input>
</j-form-item>
<j-form-item label="value" name="value">
<j-input placeholder="con_type" v-model:value="form.value"></j-input>
</j-form-item>
<j-form-item label="text" name="text">
<j-input placeholder="连接失败" v-model:value="form.text"></j-input>
</j-form-item>
</j-form>
</j-modal>
</template>
<script lang="ts" setup>
import { isInput } from '@/utils/regular';
import type { Rule } from 'ant-design-vue/es/form';
import { saveDicItem } from '@/api/system/dictionary';
import { saveDicItem, verifyValue } from '@/api/system/dictionary';
import { onlyMessage } from '@/utils/comm';
import { validateValueType } from '@/views/device/components/Metadata/Base/Edit/validator';
const props = defineProps({
type:{
type:String,
default:'add'
type: {
type: String,
default: 'add'
},
dicId:{
type:String,
default:''
dicId: {
type: String,
default: ''
},
sort:{
type:Number,
default:1
sort: {
type: Number,
default: 1
},
data: {
type: Object,
default: {}
}
})
const emit = defineEmits(['closeModal','refresh'])
const form = ref({
dictId:'',
name:'',
value:'',
text:'',
ordinal:0
const emit = defineEmits(['closeModal', 'refresh'])
const form: any = ref({
dictId: '',
name: '',
value: '',
text: '',
ordinal: 0
})
const loading = ref(false)
const formRef = ref()
/*
* 校验id
* 校验name
*/
const validateInput = async (_rule: Rule, value: string) => {
const validateInput = async (_rule: Rule, value: string) => {
if (value) {
if (!isInput(value)) {
return Promise.reject('请输入英文或者数字或者-或者_');
@ -56,49 +62,78 @@ const formRef = ref()
return Promise.resolve();
}
};
/**
* 校验value唯一
*/
const validateValue = async (_rule: Rule, value: string) => {
if (value) {
const res:any = await verifyValue({
terms: [
{
terms: [
{
value: value,
termType: "eq",
column: "value"
},
{
value: form.value.dictId,
termType: "eq",
column: "dictId"
}
]
}
]
})
if (res.status === 200 && res.result) {
return Promise.reject('value重复');
} else {
return Promise.resolve();
}
} else {
return Promise.resolve();
}
}
const rules = {
name: [
{ required:true,message:'请输入name'},
{ validator: validateInput, trigger: 'blur' },
{ required: true, message: '请输入name' },
{ validator: validateInput, trigger: 'change' },
{ max: 64, message: '最多可输入64位字符', trigger: 'change' },
],
value: [
{ required: true, message: '请输入value', trigger: 'blur' },
{ max: 64, message: '最多可输入64位字符', trigger: 'change' },
{ validator: validateValue, trigger: 'blur' }
],
text: [
{ required: true, message: '请输入text', trigger: 'blur' },
{ max: 64, message: '最多可输入64位字符', trigger: 'change' },
]
}
const submitData = () =>{
formRef.value.validate().then(async()=>{
const submitData = () => {
formRef.value.validate().then(async () => {
loading.value = true
const res = await saveDicItem(form.value)
if(res.status ===200){
if (res.status === 200) {
onlyMessage('操作成功!')
emit('refresh')
}else{
onlyMessage('操作失败!','error')
} else {
onlyMessage('操作失败!', 'error')
}
loading.value = false
})
}
const close = () =>{
const close = () => {
emit('closeModal')
}
watch(()=>props.dicId,()=>{
form.value.dictId = props.dicId
},{
immediate:true
})
watch(()=>props.sort,()=>{
form.value.ordinal = props.sort
},{
immediate:true
onMounted(() => {
if (props.type === 'add') {
form.value.dictId = props.dicId
form.value.ordinal = props.sort
} else {
form.value = props.data
}
})
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

View File

@ -24,25 +24,58 @@
新增
</PermissionButton>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="
true
"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</div>
</div>
<Save v-if="saveVisible" :dicId='data.id' :sort=sort @closeModal="closeModal" @refresh="refresh"/>
<Save v-if="saveVisible" :dicId='data.id' :type="modalType" :data="current" :sort=sort @closeModal="closeModal" @refresh="refresh"/>
</template>
<script lang="ts" setup>
import { queryDicItem } from '@/api/system/dictionary'
import { queryDicItem ,deleteDicItem } from '@/api/system/dictionary'
import Save from './Save/index.vue'
import type { ActionsType } from './typings';
import { onlyMessage } from '@/utils/comm';
import { cloneDeep } from 'lodash-es';
import { table } from 'console';
const props = defineProps({
data:{
type:Object,
default:{}
}
},
})
const params = ref()
const tableRef = ref()
const saveVisible = ref(false)
const sort = ref(0)
const modalType = ref('add')
const current = ref()
const columns = [
{
title:'序号',
@ -86,7 +119,53 @@ const columns = [
}
];
const getActions = (
data: Partial<Record<string, any>>,
type: 'card' | 'table',
): ActionsType[] => {
if (!data) return [];
const actions = [
{
key: 'update',
text: '编辑',
tooltip: {
title: '编辑',
},
icon: 'EditOutlined',
onClick: () => {
saveVisible.value = true;
modalType.value = 'edit';
current.value = data
},
},
{
key: 'delete',
text: '删除',
tooltip: {
title:'删除',
},
popConfirm: {
title: '确认删除?',
onConfirm: async () => {
const res = await deleteDicItem(data.id)
if(res.status ===200){
onlyMessage('操作成功!')
tableRef.value.reload()
}else{
onlyMessage('操作失败!','error')
}
},
},
icon: 'DeleteOutlined',
},
];
if (type === 'card')
return actions.filter((i: ActionsType) => i.key !== 'view');
return actions;
};
const add = () =>{
modalType.value = 'add'
current.value = {}
saveVisible.value = true
}
@ -115,8 +194,12 @@ const queryItem =async(_params:any)=>{
],
};
const resp: any = await queryDicItem(params);
sort.value = resp?.result?.total + 1
if(resp.status===200){
const arr = cloneDeep(resp.result.data)
arr?.sort((a:any,b:any)=>{
return b.ordinal - a.ordinal
})
sort.value =arr.length ? arr[0].ordinal + 1 : 1
return {
code: resp.status,
result: resp.result,
@ -137,6 +220,9 @@ const queryItem =async(_params:any)=>{
};
}
}
watch(()=>props?.data?.id,()=>{
tableRef.value.reload()
})
</script>
<style lang="less" scoped>
.des_head{