feat: 数据字典
This commit is contained in:
parent
d72e88d725
commit
dfc1d1556c
|
@ -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)
|
|
@ -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>
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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>
|
|
@ -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{
|
||||
|
|
Loading…
Reference in New Issue