feat: 字典

This commit is contained in:
dap 2024-09-23 15:04:23 +08:00
parent 454ca3d2e6
commit 3e750a0943
6 changed files with 297 additions and 3 deletions

View File

@ -1 +1,2 @@
export { tagSelectOptions, tagTypes } from './src/data';
export { default as DictTag } from './src/index.vue';

View 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: '备注',
},
];

View 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>

View File

@ -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>

View File

@ -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>

View File

@ -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>