feat: 字典
This commit is contained in:
parent
454ca3d2e6
commit
3e750a0943
@ -1 +1,2 @@
|
||||
export { tagSelectOptions, tagTypes } from './src/data';
|
||||
export { default as DictTag } from './src/index.vue';
|
||||
|
71
apps/web-antd/src/views/system/dict/data/data.ts
Normal file
71
apps/web-antd/src/views/system/dict/data/data.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import type { FormSchemaGetter } from '#/adapter';
|
||||
|
||||
export const drawerSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
fieldName: 'dictCode',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
fieldName: 'dictType',
|
||||
label: '字典类型',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'listClass',
|
||||
label: '标签样式',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'dictLabel',
|
||||
label: '数据标签',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'dictValue',
|
||||
label: '数据键值',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
componentProps: {
|
||||
placeholder: '可使用tailwind类名 如bg-blue w-full h-full等',
|
||||
},
|
||||
fieldName: 'cssClass',
|
||||
formItemClass: 'items-baseline',
|
||||
help: '标签的css样式, 可添加已经编译的css类名',
|
||||
label: 'css类名',
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'dictSort',
|
||||
label: '显示排序',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'remark',
|
||||
formItemClass: 'items-baseline',
|
||||
label: '备注',
|
||||
},
|
||||
];
|
125
apps/web-antd/src/views/system/dict/data/dict-data-drawer.vue
Normal file
125
apps/web-antd/src/views/system/dict/data/dict-data-drawer.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { useVbenForm } from '#/adapter';
|
||||
import { clientAdd, clientUpdate } from '#/api/system/client';
|
||||
import { dictDetailInfo } from '#/api/system/dict/dict-data';
|
||||
import { tagTypes } from '#/components/dict';
|
||||
|
||||
import { drawerSchema } from './data';
|
||||
import TagStylePicker from './tag-style-picker.vue';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
interface DrawerProps {
|
||||
dictCode?: number | string;
|
||||
dictType: string;
|
||||
}
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
formItemClass: 'col-span-2',
|
||||
labelWidth: 80,
|
||||
},
|
||||
schema: drawerSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
/**
|
||||
* 标签样式选择器
|
||||
* default: 预设标签样式
|
||||
* custom: 自定义标签样式
|
||||
*/
|
||||
const selectType = ref('default');
|
||||
/**
|
||||
* 根据标签样式判断是自定义还是默认
|
||||
* @param listClass 标签样式
|
||||
*/
|
||||
function setupSelectType(listClass: string) {
|
||||
// 判断是自定义还是预设
|
||||
const isDefault = Reflect.has(tagTypes, listClass);
|
||||
selectType.value = isDefault ? 'default' : 'custom';
|
||||
}
|
||||
|
||||
const [BasicDrawer, drawerApi] = useVbenDrawer({
|
||||
onCancel: handleCancel,
|
||||
onConfirm: handleConfirm,
|
||||
async onOpenChange(isOpen) {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
drawerApi.drawerLoading(true);
|
||||
|
||||
const { dictCode, dictType } = drawerApi.getData() as DrawerProps;
|
||||
isUpdate.value = !!dictCode;
|
||||
formApi.setFieldValue('dictType', dictType);
|
||||
|
||||
if (dictCode && isUpdate.value) {
|
||||
const record = await dictDetailInfo(dictCode);
|
||||
setupSelectType(record.listClass);
|
||||
for (const key in record) {
|
||||
await formApi.setFieldValue(key, record[key as keyof typeof record]);
|
||||
}
|
||||
}
|
||||
|
||||
drawerApi.drawerLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
drawerApi.drawerLoading(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
const data = await formApi.getValues();
|
||||
await (isUpdate.value ? clientUpdate(data) : clientAdd(data));
|
||||
emit('reload');
|
||||
await handleCancel();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
drawerApi.drawerLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCancel() {
|
||||
drawerApi.close();
|
||||
await formApi.resetForm();
|
||||
selectType.value = 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消标签选中 必须设置为undefined才行
|
||||
*/
|
||||
async function handleDeSelect() {
|
||||
await formApi.setFieldValue('listClass', undefined);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
|
||||
<BasicForm>
|
||||
<template #listClass="slotProps">
|
||||
<TagStylePicker
|
||||
v-bind="slotProps"
|
||||
v-model:select-type="selectType"
|
||||
@deselect="handleDeSelect"
|
||||
/>
|
||||
</template>
|
||||
</BasicForm>
|
||||
</BasicDrawer>
|
||||
</template>
|
@ -1,5 +1,24 @@
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import dictDataDrawer from './dict-data-drawer.vue';
|
||||
|
||||
const [DictDataDrawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: dictDataDrawer,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
drawerApi.setData({ dictType: 'aa_bb_cc' });
|
||||
drawerApi.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div></div>
|
||||
<div>
|
||||
<a-button type="primary" @click="handleAdd">
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
<DictDataDrawer />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -0,0 +1,75 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, type PropType } from 'vue';
|
||||
|
||||
import {
|
||||
Input,
|
||||
type RadioChangeEvent,
|
||||
RadioGroup,
|
||||
Select,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { tagSelectOptions } from '#/components/dict';
|
||||
|
||||
defineEmits<{ deselect: [] }>();
|
||||
|
||||
const options = [
|
||||
{ label: '默认颜色', value: 'default' },
|
||||
{ label: '自定义颜色', value: 'custom' },
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* 主要是加了const报错
|
||||
*/
|
||||
const computedOptions = computed(
|
||||
() => options as unknown as { label: string; value: string }[],
|
||||
);
|
||||
|
||||
type SelectType = (typeof options)[number]['value'];
|
||||
|
||||
const selectType = defineModel('selectType', {
|
||||
default: 'default',
|
||||
type: String as PropType<SelectType>,
|
||||
});
|
||||
|
||||
const color = defineModel('value', {
|
||||
default: '',
|
||||
type: String,
|
||||
});
|
||||
|
||||
function handleSelectTypeChange(e: RadioChangeEvent) {
|
||||
// 必须给默认hex颜色 不能为空字符串
|
||||
if (e.target.value === 'custom') {
|
||||
color.value = '#FFFFFF';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center gap-[6px]">
|
||||
<RadioGroup
|
||||
v-model:value="selectType"
|
||||
:options="computedOptions"
|
||||
button-style="solid"
|
||||
option-type="button"
|
||||
@change="handleSelectTypeChange"
|
||||
/>
|
||||
<Select
|
||||
v-if="selectType === 'default'"
|
||||
:allow-clear="true"
|
||||
:options="tagSelectOptions()"
|
||||
class="flex-1"
|
||||
placeholder="请选择标签样式"
|
||||
@deselect="$emit('deselect')"
|
||||
/>
|
||||
<Input
|
||||
v-if="selectType === 'custom'"
|
||||
v-model:value="color"
|
||||
class="flex-1"
|
||||
disabled
|
||||
>
|
||||
<template #addonAfter>
|
||||
<input v-model="color" class="rounded-lg" type="color" />
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
</template>
|
@ -3,6 +3,7 @@ import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Card } from 'ant-design-vue';
|
||||
|
||||
import DictDataPanel from './data/index.vue';
|
||||
import DictTypePanel from './type/index.vue';
|
||||
</script>
|
||||
|
||||
@ -11,6 +12,8 @@ import DictTypePanel from './type/index.vue';
|
||||
<Card class="w-full">
|
||||
<DictTypePanel />
|
||||
</Card>
|
||||
<Card class="w-full">b</Card>
|
||||
<Card class="w-full">
|
||||
<DictDataPanel />
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user