浏览代码

feat: 选择字典 自定义表单支持

lanceJiang 10 月之前
父节点
当前提交
6329c08af2

+ 19 - 0
src/components/packages/formEditor/components/FormTypes/SelectDict/mobile.vue

@@ -0,0 +1,19 @@
+<script>
+import hooks from '@ER/hooks'
+export default {
+	name: 'ErSelectDict',
+	inheritAttrs: false,
+	customOptions: {}
+}
+</script>
+<script setup>
+const props = defineProps(['data', 'params'])
+const ns = hooks.useNamespace('FormTypesSelectDict_mobile')
+</script>
+<template>
+	<el-select v-model="data.options.defaultValue" :class="[ns.b()]" v-bind="params">
+		<el-option v-for="item in params.options" :key="item.value" :label="item.label" :value="item.value" />
+	</el-select>
+</template>
+
+<style scoped></style>

+ 52 - 0
src/components/packages/formEditor/components/FormTypes/SelectDict/pc.vue

@@ -0,0 +1,52 @@
+<script>
+import hooks from '@ER/hooks'
+export default {
+	name: 'ErSelectDict',
+	inheritAttrs: false,
+	customOptions: {}
+}
+</script>
+<script setup>
+import { watch, ref } from 'vue'
+import dict from '@/api/system/dict'
+const props = defineProps(['data', 'params'])
+const ns = hooks.useNamespace('FormTypesSelectDict_pc')
+// type Option = { title: string; content: string }
+const optionKey = { label: 'title', value: 'content' }
+const loadOptions = ref({ list: [], loading: false })
+const queryDictOptions = dictCode => {
+	// {title, content}[]
+	if (!dictCode) {
+		loadOptions.value = {
+			loading: false,
+			list: []
+		}
+		return
+	}
+	loadOptions.value.loading = true
+	dict.dictListSelectOptionApi(dictCode).then(list => {
+		loadOptions.value = {
+			loading: false,
+			list
+		}
+	})
+}
+
+watch(
+	() => props.params?.dictCode,
+	dictCode => {
+		queryDictOptions(dictCode)
+		// console.error(dictCode, 'SelectDict params')
+	},
+	{
+		immediate: true
+	}
+)
+</script>
+<template>
+	<el-select v-model="data.options.defaultValue" :loading="loadOptions.loading" :class="[ns.b()]" v-bind="params">
+		<el-option v-for="item in loadOptions.list" :key="item[optionKey.value]" :label="item[optionKey.label]" :value="item[optionKey.value]" />
+	</el-select>
+</template>
+
+<style scoped></style>

+ 9 - 8
src/components/packages/formEditor/components/Panels/Config/components/PropsPanel.vue

@@ -496,7 +496,7 @@ onMounted(() => {
 			<template v-else-if="checkTypeBySelected(['subform'], 'defaultValue')">
 				<PanelsConfigComponentsSubformDefaultValue />
 			</template>
-			<template v-else-if="checkTypeBySelected(['select'], 'defaultValue') && [2, 3, 4].indexOf(target.options.renderType) > -1">
+			<template v-else-if="checkTypeBySelected(['select', 'selectDict'], 'defaultValue') && [2, 3, 4].indexOf(target.options.renderType) > -1">
 				<el-select v-model="target.options.defaultValue" :class="[utils.addTestId('configPanel-defaultValue', 'id')]" v-bind="typeProps">
 					<el-option v-for="item in typeProps.options" :key="item.value" :label="item.label" :value="item.value" />
 				</el-select>
@@ -522,12 +522,12 @@ onMounted(() => {
 		</PanelsConfigComponentsTypeComponent>
 		<!-- placeholder -->
 		<PanelsConfigComponentsTypeComponent
-			v-if="checkTypeBySelected(['input', 'textarea', 'select', 'cascader', 'time', 'date', 'html', 'region'], 'placeholder')"
+			v-if="checkTypeBySelected(['input', 'textarea', 'select', 'selectDict', 'cascader', 'time', 'date', 'html', 'region'], 'placeholder')"
 			:layout-type="0"
 			:label="t('er.config.propsPanel.placeholder')"
 		>
 			<el-input
-				v-if="checkTypeBySelected(['input', 'select', 'cascader', 'time', 'date', 'html', 'region'], 'placeholder')"
+				v-if="checkTypeBySelected(['input', 'select', 'selectDict', 'cascader', 'time', 'date', 'html', 'region'], 'placeholder')"
 				v-model="target.options.placeholder"
 				clearable
 				v-bind="utils.addTestId('configPanel:placeholder')"
@@ -540,11 +540,12 @@ onMounted(() => {
 				v-bind="utils.addTestId('configPanel:placeholder')"
 			/>
 		</PanelsConfigComponentsTypeComponent>
-		<!-- select dict类型(renderType === 4) 选择字典类型 -->
+		<!-- selectDict类型 选择字典类型 -->
 		<PanelsConfigComponentsTypeComponent
-			v-if="checkTypeBySelected(['select'], 'dictCode') && target.options.renderType === 4"
+			v-if="checkTypeBySelected(['selectDict'], 'dictCode')"
 			:layout-type="0"
 			:label="t('er.config.propsPanel.dictCode')"
+			prop="dictCode"
 		>
 			<el-select v-model="target.options.dictCode" style="width: 100%" v-bind="utils.addTestId('configPanel:dictCode')">
 				<el-option v-for="item in ER.dictParentList.value" :label="item.label" :value="item.value" />
@@ -907,7 +908,7 @@ onMounted(() => {
 			>
 			</PanelsConfigComponentsCheckboxComponent>
 			<PanelsConfigComponentsCheckboxComponent
-				v-if="checkTypeBySelected(['select', 'cascader', 'uploadfile'], 'multiple')"
+				v-if="checkTypeBySelected(['select', 'selectDict', 'cascader', 'uploadfile'], 'multiple')"
 				:label="t('er.config.propsPanel.multiple')"
 				field="multiple"
 				v-bind="utils.addTestId('configPanel:multiple')"
@@ -915,7 +916,7 @@ onMounted(() => {
 			>
 			</PanelsConfigComponentsCheckboxComponent>
 			<PanelsConfigComponentsCheckboxComponent
-				v-if="checkTypeBySelected(['select', 'cascader', 'transfer', 'region'], 'filterable')"
+				v-if="checkTypeBySelected(['select', 'selectDict', 'cascader', 'transfer', 'region'], 'filterable')"
 				:label="t('er.config.propsPanel.filterable')"
 				field="filterable"
 				v-bind="utils.addTestId('configPanel:filterable')"
@@ -957,7 +958,7 @@ onMounted(() => {
 				@change="checkLogicData"
 			/>
 			<PanelsConfigComponentsCheckboxComponent
-				v-if="checkTypeBySelected(['input', 'select', 'time', 'date', 'cascader', 'region'], 'clearable')"
+				v-if="checkTypeBySelected(['input', 'select', 'selectDict', 'time', 'date', 'cascader', 'region'], 'clearable')"
 				:label="t('er.config.propsPanel.clearable')"
 				field="clearable"
 				v-bind="utils.addTestId('configPanel:clearable')"

+ 5 - 2
src/components/packages/formEditor/components/Panels/Config/components/TypeComponent.vue

@@ -38,7 +38,10 @@ const props = defineProps({
   layoutType: {
     type: Number,
     default: 1
-  }
+  },
+	prop: {
+		type: String
+	}
 })
 const fireEvent = (property, item) => {
   emit('listener', {
@@ -49,7 +52,7 @@ const fireEvent = (property, item) => {
 </script>
 <template>
   <div :class="ns.b()">
-    <el-form-item>
+    <el-form-item :prop="prop">
       <template v-if="label" v-slot:label>
         <div :class="ns.e('label')">
           <div>

+ 3 - 3
src/components/packages/formEditor/componentsConfig.js

@@ -157,7 +157,7 @@ export const fieldsConfig = [
 			},
 			{
 				// 渲染组件类型
-				type: 'select',
+				type: 'selectDict',
 				label: '字典',
 				// icon 名称
 				icon: 'dict',
@@ -177,8 +177,8 @@ export const fieldsConfig = [
 					disabled: false,
 					clearable: true,
 					// 额外渲染类型标记(label转义 render 配置等)
-					renderType: 4,
-					props: { value: 'id', label: 'name' },
+					// renderType: 4,
+					// props: { value: 'id', label: 'name' },
 					dictCode: '' // 字典编码
 				}
 			},

+ 5 - 2
src/components/packages/formEditor/index.vue

@@ -183,13 +183,16 @@ const getDictParentList = async () => {
 				value: v.code,
 				// 下拉数据
 				options: []
+				value: v.code
+				// // 下拉数据
+				// options: []
 			}
 		})
-		await Promise.all(options.map(v => dict.dictListSelectOptionApi(v.code))).then(codesOptions => {
+		/*await Promise.all(options.map(v => dict.dictListSelectOptionApi(v.code))).then(codesOptions => {
 			options.map((v, i) => {
 				v.options = (codesOptions[i] || []).map(({ title, content }) => ({ label: title, value: content }))
 			})
-		})
+		})*/
 		return options
 	})
 	dictParentList.value = data

+ 1 - 0
src/components/packages/formEditor/locale/en.js

@@ -12,6 +12,7 @@ export default {
 			select: ['Select', 'Employee', 'Role', 'Dict'], //, 'Department'
 			selectUser: 'Employee',
 			selectRole: 'Role',
+			selectDict: 'Dict',
 			time: 'Time',
 			date: 'Date',
 			rate: 'Rate',

+ 1 - 0
src/components/packages/formEditor/locale/zh-cn.js

@@ -11,6 +11,7 @@ export default {
 			checkbox: '复选框',
 			select: ['下拉框', '人员', '角色', '字典'], //, '部门'
 			selectUser: '员工',
+			selectDict: '字典',
 			selectRole: '角色',
 			time: '时间',
 			date: '日期',

+ 9 - 4
src/components/packages/hooks/use-props/index.js

@@ -300,21 +300,26 @@ export const useProps = (state, data, isPc = true, isRoot = false, specialHandli
 				result.min = options.min
 				result.max = options.max
 				break
+			case 'selectDict': // 字典
+				result.dictCode = options.dictCode
+				result.multiple = options.multiple
+				result.filterable = options.filterable
+				break
 			case 'select':
 				// 当前选中的值,如果是人员就获取人员的api,部门就获取部门的api
 				if ([2, 3].indexOf(renderType) > -1) {
 					result.options = options?.options
-				} else if (renderType === 4) {
+				} /*else if (renderType === 4) {
 					// 字典类型
 					const _dictOption = (options?.options || []).find(v => v.code === options.dictCode)
 					// console.error(options?.options, 'options?.options  _dictOption', _dictOption)
-					/*if (_dictOption) {
+					/!*if (_dictOption) {
 						if (!_dictOption.options.length) {
 							_dictOption.options = dict.dictListSelectOptionApi(options.dictCode).then(({ title, content }) => ({ label: title, value: content }))
 						}
-					}*/
+					}*!/
 					result.options = _dictOption?.options
-				} else if (renderType === 1) {
+				}*/ else if (renderType === 1) {
 					result.options = _.get(state, `data[${options.dataKey}].list`, [])
 				}
 				result.multiple = options.multiple

+ 7 - 0
src/components/packages/theme/formEditor/FormTypes/Select.scss

@@ -12,3 +12,10 @@
 @include b(FormTypesSelect_pc) {
   width: 100%;
 }
+
+@include b(FormTypesSelectDict_pc) {
+  width: 100%;
+}
+@include b(FormTypesSelectDict_mobile) {
+  width: 100%;
+}

+ 1 - 1
src/components/packages/utils/field.js

@@ -2,7 +2,7 @@ import _ from 'lodash-es'
 import { nanoid } from './nanoid'
 // 正则匹配type(itemType 类型)
 const fieldsRe =
-	/^(input|textarea|number|radio|checkbox|select|selectUser|selectRole|time|date|rate|switch|slider|html|cascader|uploadfile|signature|region|subform|iframe)$/
+	/^(input|textarea|number|radio|checkbox|select|selectUser|selectRole|selectDict|time|date|rate|switch|slider|html|cascader|uploadfile|signature|region|subform|iframe)$/
 const deepTraversal = (node, fn) => {
 	fn(node)
 	const nodes = node.type === 'subform' ? node.list[0] : node.list || node.rows || node.columns || node.children || []