From 76e925b2147f81fe4176dac59bb1701a54ca8da9 Mon Sep 17 00:00:00 2001 From: zhang zhuo Date: Thu, 27 Nov 2025 16:25:03 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A8=E5=8D=95=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/piDraggable/index.vue | 1 + src/pi.ts | 2 - src/views/tools/form/center.vue | 73 ++++++--- src/views/tools/form/config.ts | 226 +++++++++++++++++++++++++++ src/views/tools/form/index.vue | 9 +- src/views/tools/form/left.vue | 171 ++++++++++---------- src/views/tools/form/right.vue | 123 ++++++++------- 7 files changed, 433 insertions(+), 172 deletions(-) create mode 100644 src/views/tools/form/config.ts diff --git a/src/components/piDraggable/index.vue b/src/components/piDraggable/index.vue index 56bcd64..32fb6b8 100644 --- a/src/components/piDraggable/index.vue +++ b/src/components/piDraggable/index.vue @@ -93,5 +93,6 @@ function add() { .add { padding: 0 10px 10px 20px; + text-align: center; } diff --git a/src/pi.ts b/src/pi.ts index 05171d4..a3bb32e 100644 --- a/src/pi.ts +++ b/src/pi.ts @@ -11,14 +11,12 @@ import errorHandler from "@/utils/errorHandler"; import piDialog from "@/components/piDialog" import piTable from "@/components/piTable" -import piUpload from "@/components/piUpload" export default { install(app: App) { // 注册全局组件 app.component('piDialog', piDialog) app.component('piTable', piTable) - app.component('piUpload', piUpload) //注册全局指令 app.directive('auth', auth) diff --git a/src/views/tools/form/center.vue b/src/views/tools/form/center.vue index 4018678..30b6b47 100644 --- a/src/views/tools/form/center.vue +++ b/src/views/tools/form/center.vue @@ -11,22 +11,47 @@
- - - - + :required="fields[index].required"> + + + + + + + +
- +
@@ -43,6 +68,11 @@ import draggable from 'vuedraggable' import {nextTick, ref} from "vue"; import tools from "@/utils/tools" +import {getComponent} from "./config" +import piIcon from "@/components/piIcon" +import PiAsset from "@/components/piAsset" + +defineExpose({clickAddComp}) const props = defineProps({ fields: {type: Array, default: []}, @@ -68,6 +98,14 @@ function addComp(e) { emit('change', curComp.value) } +// 添加项时 +function clickAddComp(e) { + props.fields.push(e) + curIndex.value = props.fields.length-1 + curComp.value = e + emit('change', curComp.value) +} + // 选中项 function clickComp(element, index) { if (curIndex.value === index) { @@ -155,17 +193,16 @@ function copyComp(index) { .item { padding: 12px 10px; - background: #f6f7ff; - border: 1px dashed #f6f7ff; + border: 1px; border-radius: 3px; position: relative; } .tools-box { position: absolute; - right: -20px; - top: 0; - display: inline-grid; + right: 10px; + top: -16px; + display: inline-block; padding: 5px; border-radius: 4px; @@ -181,8 +218,8 @@ function copyComp(index) { color: var(--el-color-primary); } - .mt5 { - margin-top: 5px; + .ml5 { + margin-left: 5px; } .disabled { diff --git a/src/views/tools/form/config.ts b/src/views/tools/form/config.ts new file mode 100644 index 0000000..9002ec8 --- /dev/null +++ b/src/views/tools/form/config.ts @@ -0,0 +1,226 @@ +/** + * 根据 fForm.name 决定要显示哪些设置项 + */ +export const fieldEditors = { + text: [ + {key: 'width', label: '组件宽度', type: 'input'}, + {key: 'props.placeholder', label: '占位提示', type: 'input'}, + {key: 'props.prefixIcon', label: '前图标', type: 'icon'}, + {key: 'props.suffixIcon', label: '后图标', type: 'icon'}, + {key: 'props.minlength', label: '最少输入', type: 'number'}, + {key: 'props.maxlength', label: '最多输入', type: 'number'}, + {key: 'props.showWordLimit', label: '显示字数', type: 'switch'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + textarea: [ + {key: 'width', label: '组件宽度', type: 'input'}, + {key: 'props.placeholder', label: '占位提示', type: 'input'}, + {key: 'props.rows', label: '默认行数', type: 'number'}, + {key: 'props.minlength', label: '最少输入', type: 'number'}, + {key: 'props.maxlength', label: '最多输入', type: 'number'}, + {key: 'props.showWordLimit', label: '显示字数', type: 'switch'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + password: [ + {key: 'width', label: '组件宽度', type: 'input'}, + {key: 'props.placeholder', label: '占位提示', type: 'input'}, + {key: 'props.prefixIcon', label: '前图标', type: 'icon'}, + {key: 'props.suffixIcon', label: '后图标', type: 'icon'}, + {key: 'props.minlength', label: '最少输入', type: 'number'}, + {key: 'props.maxlength', label: '最多输入', type: 'number'}, + {key: 'props.showWordLimit', label: '显示字数', type: 'switch'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + number: [ + {key: 'width', label: '组件宽度', type: 'input'}, + {key: 'props.placeholder', label: '占位提示', type: 'input'}, + {key: 'props.precision', label: '精度', type: 'number'}, + {key: 'props.step', label: '步长', type: 'number'}, + {key: 'props.stepStrictly', label: '严格步数', type: 'switch'}, + { + key: 'props.controlsPosition', label: '按钮位置', type: 'radio', options: [ + {label: '默认', value: ''}, + {label: '右侧', value: 'right'}, + ] + }, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + select: [ + {key: 'width', label: '组件宽度', type: 'input'}, + {key: 'props.placeholder', label: '占位提示', type: 'input'}, + {key: 'props.multiple', label: '是否多选', type: 'switch'}, + {key: 'props.filterable', label: '能否筛选', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + cascader: [ + {key: 'width', label: '组件宽度', type: 'input'}, + {key: 'props.placeholder', label: '占位提示', type: 'input'}, + {key: 'props.separator', label: '分隔符', type: 'input'}, + {key: 'props.showAllLevels', label: '展示全路径', type: 'switch'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.props.multiple', label: '是否多选', type: 'switch'}, + {key: 'props.filterable', label: '能否筛选', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + radio: [ + { + key: 'style', label: '选项样式', type: 'radio', options: [ + {label: '默认', value: ''}, + {label: '按钮', value: 'button'}, + ] + }, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + checkbox: [ + {key: 'props.min', label: '最少应选', type: 'number'}, + {key: 'props.max', label: '最多可选', type: 'number'}, + { + key: 'style', label: '选项样式', type: 'radio', options: [ + {label: '默认', value: ''}, + {label: '按钮', value: 'button'}, + ] + }, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + switch: [ + {key: 'props.activeText', label: '打开提示', type: 'input'}, + {key: 'props.inactiveText', label: '关闭提示', type: 'input'}, + {key: 'props.activeValue', label: '打开值', type: 'input'}, + {key: 'props.inactiveValue', label: '关闭值', type: 'input'}, + {key: 'props.activeActionIcon', label: '打开图标', type: 'icon'}, + {key: 'props.inactiveActionIcon', label: '关闭图标', type: 'icon'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + slider: [ + {key: 'width', label: '组件宽度', type: 'input'}, + {key: 'props.min', label: '最大值', type: 'number'}, + {key: 'props.max', label: '最小值', type: 'number'}, + {key: 'props.step', label: '步长', type: 'number'}, + {key: 'props.showStops', label: '显示间隔点', type: 'switch'}, + {key: 'props.range', label: '范围选择', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + rate: [ + {key: 'props.max', label: '最大值', type: 'number'}, + {key: 'props.allowHalf', label: '是否半选', type: 'switch'}, + {key: 'props.showScore', label: '显示分数', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + color: [ + { + key: 'props.colorFormat', label: '颜色格式', type: 'select', options: [ + {label: 'hsl', value: 'hsl'}, + {label: 'hsv', value: 'hsv'}, + {label: 'hex(when show-alpha is false)', value: 'hex'}, + {label: 'rgb(when show-alpha is true)', value: 'rgb'}, + ] + }, + {key: 'props.showAlpha', label: '透明度', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + upload: [ + {key: 'props.name', label: '文件字段名', type: 'input'}, + {key: 'btnText', label: '按钮文字', type: 'input'}, + {key: 'props.accept', label: '文件类型', type: 'input'}, + { + key: 'props.listType', label: '列表类型', type: 'radio', options: [ + {label: 'text', value: 'text'}, + {label: 'picture', value: 'picture'}, + {label: 'picture-card', value: 'picture-card'} + ] + }, + {key: 'tip', label: '提示信息', type: 'input'}, + {key: 'props.multiple', label: '是否多选', type: 'switch'}, + {key: 'props.autoUpload', label: '自动上传', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + date: [ + {key: 'width', label: '组件宽度', type: 'input'}, + { + key: 'props.type', label: '时间类型', type: 'select', options: [ + {label: '日', value: 'date'}, + {label: '周', value: 'week'}, + {label: '月', value: 'month'}, + {label: '年', value: 'year'}, + {label: '日期时间', value: 'datetime'}, + ] + }, + {key: 'props.format', label: '显示格式', type: 'input'}, + {key: 'props.valueFormat', label: '日期格式', type: 'input'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + daterange: [ + { + key: 'props.type', label: '时间类型', type: 'select', options: [ + {label: '日期范围', value: 'daterange'}, + {label: '月范围', value: 'monthrange'}, + {label: '日期时间范围', value: 'datetimerange'}, + ] + }, + {key: 'props.rangeSeparator', label: '分隔符', type: 'input'}, + {key: 'props.format', label: '显示格式', type: 'input'}, + {key: 'props.valueFormat', label: '日期格式', type: 'input'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + time: [ + {key: 'props.editable', label: '可输入', type: 'switch'}, + {key: 'props.rangeSeparator', label: '分隔符', type: 'input'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ], + timerange: [ + {key: 'props.editable', label: '可输入', type: 'switch'}, + {key: 'props.rangeSeparator', label: '分隔符', type: 'input'}, + {key: 'props.clearable', label: '能否清空', type: 'switch'}, + {key: 'props.readonly', label: '是否只读', type: 'switch'}, + {key: 'props.disabled', label: '是否禁用', type: 'switch'}, + ] +} +// 'year' | 'years' |'month' | 'months' | 'date' | 'dates' | 'datetime' | 'week' | 'datetimerange' | 'daterange' | 'monthrange' | 'yearrange' +export const getComponent = (type) => { + const map = { + text: 'el-input', + textarea: 'el-input', + password: 'el-input', + number: 'el-input-number', + select: 'el-select', + cascader: 'el-cascader', + radio: 'el-radio-group', + checkbox: 'el-checkbox-group', + switch: 'el-switch', + slider: 'el-slider', + rate: 'el-rate', + color: 'el-color-picker', + upload: 'el-upload', + date: 'el-date-picker', + daterange: 'el-date-picker', + time: 'el-time-picker', + timerange: 'el-time-picker', + icon: 'pi-icon', + asset: 'pi-asset' + } + return map[type] || 'div' +} + +export function getByPath(obj, path) { + return path.split('.').reduce((o, k) => o?.[k], obj) +} + +export function setByPath(obj, path, value) { + const keys = path.split('.') + let o = obj + keys.slice(0, -1).forEach(k => o = o[k]) + o[keys[keys.length - 1]] = value +} diff --git a/src/views/tools/form/index.vue b/src/views/tools/form/index.vue index b10e148..6f4e1dd 100644 --- a/src/views/tools/form/index.vue +++ b/src/views/tools/form/index.vue @@ -1,9 +1,9 @@