使用项目组件对 form-create-designer 进行增强

This commit is contained in:
puhui999 2024-03-30 18:53:05 +08:00
parent 87d1047fa9
commit bc004b3b27
15 changed files with 371 additions and 75 deletions

View File

@ -1,3 +1,4 @@
import MyFormCreate from './src/MyFormCreate.vue' import MyFormCreateDesigner from './src/MyFormCreateDesigner.vue'
import { useFormCreateDesigner } from './src/useFormCreateDesigner'
export { MyFormCreate } export { MyFormCreateDesigner, useFormCreateDesigner }

View File

@ -1,54 +0,0 @@
<template>
<form-create v-bind="attrs">
<!-- 保障 form-create 的原始插槽 -->
<template v-for="(_, name) in slots" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}"></slot>
</template>
<!-- 使用项目重新封装的文件上传组件实现文件上载 -->
<template #type-upload="scope">
<!-- {{ logC(scope) }}-->
<template v-if="scope.prop.props.uploadType === 'file'">
<!-- TODO puhui999: 考虑是否使用属性透传直接把整个 scope.prop.props 传递给组件 -->
<UploadFile
:disabled="scope.prop.props.disabled"
:limit="scope.prop.props.limit"
:modelValue="scope.model.value || scope.prop.value"
@update:modelValue="(val) => setValue(scope, val)"
/>
</template>
<template v-if="scope.prop.props.uploadType === 'image' && scope.prop.props.limit === 1">
<UploadImg
:disabled="scope.prop.props.disabled"
:modelValue="scope.model.value || scope.prop.value"
@update:modelValue="(val) => setValue(scope, val)"
/>
</template>
<template v-if="scope.prop.props.uploadType === 'image' && scope.prop.props.limit > 1">
<UploadImgs
:disabled="scope.prop.props.disabled"
:limit="scope.prop.props.limit"
:modelValue="scope.model.value || scope.prop.value"
@update:modelValue="(val) => setValue(scope, val)"
/>
</template>
</template>
</form-create>
</template>
<script lang="ts" setup>
defineOptions({ name: 'MyFormCreate' })
const attrs = useAttrs()
const slots = useSlots()
// 使 scope
// const logC = (s) => {
// console.log(s)
// }
//
const setValue = (scope: any, value: any) => {
const obj = {}
obj[scope.prop.field] = value
scope.api.setValue(obj)
}
</script>

View File

@ -0,0 +1,33 @@
<!-- TODO puhui999: 没啥问题的话准备移除 -->
<template>
<FcDesigner ref="designer" height="780px" />
</template>
<script lang="ts" setup>
import { useUploadFileRule, useUploadImgRule, useUploadImgsRule } from './config'
defineOptions({ name: 'MyFormCreateDesigner' })
const designer = ref() //
const uploadFileRule = useUploadFileRule()
const uploadImgRule = useUploadImgRule()
const uploadImgsRule = useUploadImgsRule()
onMounted(() => {
//
designer.value?.removeMenuItem('upload')
const components = [uploadFileRule, uploadImgRule, uploadImgsRule]
components.forEach((component) => {
//
designer.value?.addComponent(component)
//`main`
designer.value?.appendMenuItem('main', {
icon: component.icon,
name: component.name,
label: component.label
})
})
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,5 @@
import { useUploadFileRule } from './useUploadFileRule'
import { useUploadImgRule } from './useUploadImgRule'
import { useUploadImgsRule } from './useUploadImgsRule'
export { useUploadFileRule, useUploadImgRule, useUploadImgsRule }

View File

@ -0,0 +1,80 @@
import { generateUUID } from '@/utils'
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
export const useUploadFileRule = () => {
const label = '文件上传'
const name = 'UploadFile'
return {
icon: 'icon-upload',
label,
name,
rule() {
return {
type: name,
field: generateUUID(),
title: label,
info: '',
$required: false
}
},
props(_, { t }) {
return localeProps(t, name + '.props', [
makeRequiredRule(),
{
type: 'select',
field: 'fileType',
title: '文件类型',
value: ['doc', 'xls', 'ppt', 'txt', 'pdf'],
options: [
{ label: 'doc', value: 'doc' },
{ label: 'xls', value: 'xls' },
{ label: 'ppt', value: 'ppt' },
{ label: 'txt', value: 'txt' },
{ label: 'pdf', value: 'pdf' }
],
props: {
multiple: true
}
},
{
type: 'switch',
field: 'autoUpload',
title: '是否在选取文件后立即进行上传',
value: true
},
{
type: 'switch',
field: 'drag',
title: '拖拽上传',
value: false
},
{
type: 'switch',
field: 'isShowTip',
title: '是否显示提示',
value: true
},
{
type: 'inputNumber',
field: 'fileSize',
title: '大小限制(MB)',
value: 5,
props: { min: 0 }
},
{
type: 'inputNumber',
field: 'limit',
title: '数量限制',
value: 5,
props: { min: 0 }
},
{
type: 'switch',
field: 'disabled',
title: '是否禁用',
value: false
}
])
}
}
}

View File

@ -0,0 +1,89 @@
import { generateUUID } from '@/utils'
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
export const useUploadImgRule = () => {
const label = '单图上传'
const name = 'UploadImg'
return {
icon: 'icon-upload',
label,
name,
rule() {
return {
type: name,
field: generateUUID(),
title: label,
info: '',
$required: false
}
},
props(_, { t }) {
return localeProps(t, name + '.props', [
makeRequiredRule(),
{
type: 'switch',
field: 'drag',
title: '拖拽上传',
value: false
},
{
type: 'select',
field: 'fileType',
title: '图片类型限制',
value: ['image/jpeg', 'image/png', 'image/gif'],
options: [
{ label: 'image/apng', value: 'image/apng' },
{ label: 'image/bmp', value: 'image/bmp' },
{ label: 'image/gif', value: 'image/gif' },
{ label: 'image/jpeg', value: 'image/jpeg' },
{ label: 'image/pjpeg', value: 'image/pjpeg' },
{ label: 'image/svg+xml', value: 'image/svg+xml' },
{ label: 'image/tiff', value: 'image/tiff' },
{ label: 'image/webp', value: 'image/webp' },
{ label: 'image/x-icon', value: 'image/x-icon' }
],
props: {
multiple: true
}
},
{
type: 'inputNumber',
field: 'fileSize',
title: '大小限制(MB)',
value: 5,
props: { min: 0 }
},
{
type: 'input',
field: 'height',
title: '组件高度',
value: '150px'
},
{
type: 'input',
field: 'width',
title: '组件宽度',
value: '150px'
},
{
type: 'input',
field: 'borderradius',
title: '组件边框圆角',
value: '8px'
},
{
type: 'switch',
field: 'disabled',
title: '是否显示删除按钮',
value: true
},
{
type: 'switch',
field: 'showBtnText',
title: '是否显示按钮文字',
value: true
}
])
}
}
}

View File

@ -0,0 +1,84 @@
import { generateUUID } from '@/utils'
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
export const useUploadImgsRule = () => {
const label = '多图上传'
const name = 'UploadImgs'
return {
icon: 'icon-upload',
label,
name,
rule() {
return {
type: name,
field: generateUUID(),
title: label,
info: '',
$required: false
}
},
props(_, { t }) {
return localeProps(t, name + '.props', [
makeRequiredRule(),
{
type: 'switch',
field: 'drag',
title: '拖拽上传',
value: false
},
{
type: 'select',
field: 'fileType',
title: '图片类型限制',
value: ['image/jpeg', 'image/png', 'image/gif'],
options: [
{ label: 'image/apng', value: 'image/apng' },
{ label: 'image/bmp', value: 'image/bmp' },
{ label: 'image/gif', value: 'image/gif' },
{ label: 'image/jpeg', value: 'image/jpeg' },
{ label: 'image/pjpeg', value: 'image/pjpeg' },
{ label: 'image/svg+xml', value: 'image/svg+xml' },
{ label: 'image/tiff', value: 'image/tiff' },
{ label: 'image/webp', value: 'image/webp' },
{ label: 'image/x-icon', value: 'image/x-icon' }
],
props: {
multiple: true
}
},
{
type: 'inputNumber',
field: 'fileSize',
title: '大小限制(MB)',
value: 5,
props: { min: 0 }
},
{
type: 'inputNumber',
field: 'limit',
title: '数量限制',
value: 5,
props: { min: 0 }
},
{
type: 'input',
field: 'height',
title: '组件高度',
value: '150px'
},
{
type: 'input',
field: 'width',
title: '组件宽度',
value: '150px'
},
{
type: 'input',
field: 'borderradius',
title: '组件边框圆角',
value: '8px'
}
])
}
}
}

View File

@ -0,0 +1,31 @@
import { useUploadFileRule, useUploadImgRule, useUploadImgsRule } from './config'
import { Ref } from 'vue'
/**
* hook
*
* -
* -
* -
*/
export const useFormCreateDesigner = (designer: Ref) => {
const uploadFileRule = useUploadFileRule()
const uploadImgRule = useUploadImgRule()
const uploadImgsRule = useUploadImgsRule()
onMounted(() => {
// 移除自带的上传组件规则
designer.value?.removeMenuItem('upload')
const components = [uploadFileRule, uploadImgRule, uploadImgsRule]
components.forEach((component) => {
//插入组件规则
designer.value?.addComponent(component)
//插入拖拽按钮到`main`分类下
designer.value?.appendMenuItem('main', {
icon: component.icon,
name: component.name,
label: component.label
})
})
})
}

View File

@ -0,0 +1,19 @@
// TODO puhui999: 借鉴一下 form-create-designer utils 方法 🤣 (导入不了只能先 copy 过来用下)
export function makeRequiredRule() {
return {
type: 'Required',
field: 'formCreate$required',
title: '是否必填'
}
}
export const localeProps = (t, prefix, rules) => {
return rules.map((rule) => {
if (rule.field === 'formCreate$required') {
rule.title = t('props.required') || rule.title
} else if (rule.field && rule.field !== '_optionType') {
rule.title = t('components.' + prefix + '.' + rule.field) || rule.title
}
return rule
})
}

View File

@ -49,7 +49,6 @@ const emit = defineEmits(['update:modelValue'])
const props = defineProps({ const props = defineProps({
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired, modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
title: propTypes.string.def('文件上传'),
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // , ['png', 'jpg', 'jpeg'] fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // , ['png', 'jpg', 'jpeg']
fileSize: propTypes.number.def(5), // (MB) fileSize: propTypes.number.def(5), // (MB)
limit: propTypes.number.def(5), // limit: propTypes.number.def(5), //

View File

@ -1,22 +1,24 @@
import type { App } from 'vue' import type { App } from 'vue'
// 👇使用 form-create 需额外全局引入 element plus 组件 // 👇使用 form-create 需额外全局引入 element plus 组件
import { import {
ElAlert,
ElAside, ElAside,
ElPopconfirm,
ElHeader,
ElMain,
ElContainer, ElContainer,
ElDivider, ElDivider,
ElTransfer, ElHeader,
ElAlert, ElMain,
ElTabs, ElPopconfirm,
ElTable, ElTable,
ElTableColumn, ElTableColumn,
ElTabPane ElTabPane,
ElTabs,
ElTransfer
} from 'element-plus' } from 'element-plus'
import FcDesigner from '@form-create/designer'
import formCreate from '@form-create/element-ui' import formCreate from '@form-create/element-ui'
import install from '@form-create/element-ui/auto-import' import install from '@form-create/element-ui/auto-import'
//======================= 自定义组件 =======================
import { UploadFile, UploadImg, UploadImgs } from '@/components/UploadFile'
const components = [ const components = [
ElAside, ElAside,
@ -30,7 +32,10 @@ const components = [
ElTabs, ElTabs,
ElTable, ElTable,
ElTableColumn, ElTableColumn,
ElTabPane ElTabPane,
UploadImg,
UploadImgs,
UploadFile
] ]
// 参考 http://www.form-create.com/v3/element-ui/auto-import.html 文档 // 参考 http://www.form-create.com/v3/element-ui/auto-import.html 文档
@ -40,4 +45,5 @@ export const setupFormCreate = (app: App<Element>) => {
}) })
formCreate.use(install) formCreate.use(install)
app.use(formCreate) app.use(formCreate)
app.use(FcDesigner)
} }

View File

@ -45,6 +45,7 @@ import * as FormApi from '@/api/bpm/form'
import FcDesigner from '@form-create/designer' import FcDesigner from '@form-create/designer'
import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate' import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate'
import { useTagsViewStore } from '@/store/modules/tagsView' import { useTagsViewStore } from '@/store/modules/tagsView'
import { useFormCreateDesigner } from '@/components/FormCreate'
defineOptions({ name: 'BpmFormEditor' }) defineOptions({ name: 'BpmFormEditor' })
@ -55,6 +56,7 @@ const { query } = useRoute() // 路由信息
const { delView } = useTagsViewStore() // const { delView } = useTagsViewStore() //
const designer = ref() // const designer = ref() //
useFormCreateDesigner(designer) //
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const formLoading = ref(false) // const formLoading = ref(false) //
const formData = ref({ const formData = ref({

View File

@ -88,7 +88,7 @@
<!-- 表单详情的弹窗 --> <!-- 表单详情的弹窗 -->
<Dialog v-model="detailVisible" title="表单详情" width="800"> <Dialog v-model="detailVisible" title="表单详情" width="800">
<my-form-create :option="detailData.option" :rule="detailData.rule" /> <form-create :option="detailData.option" :rule="detailData.rule" />
</Dialog> </Dialog>
</template> </template>

View File

@ -24,15 +24,15 @@
{{ processInstance?.startUser.nickname }} {{ processInstance?.startUser.nickname }}
<el-tag size="small" type="info">{{ processInstance?.startUser.deptName }}</el-tag> <el-tag size="small" type="info">{{ processInstance?.startUser.deptName }}</el-tag>
</el-form-item> </el-form-item>
<el-card class="mb-15px !-mt-10px" v-if="runningTasks[index].formId > 0"> <el-card v-if="runningTasks[index].formId > 0" class="mb-15px !-mt-10px">
<template #header> <template #header>
<span class="el-icon-picture-outline"> <span class="el-icon-picture-outline">
填写表单{{ runningTasks[index]?.formName }} 填写表单{{ runningTasks[index]?.formName }}
</span> </span>
</template> </template>
<form-create <form-create
v-model:api="approveFormFApis[index]"
v-model="approveForms[index].value" v-model="approveForms[index].value"
v-model:api="approveFormFApis[index]"
:option="approveForms[index].option" :option="approveForms[index].option"
:rule="approveForms[index].rule" :rule="approveForms[index].rule"
/> />
@ -91,7 +91,7 @@
</template> </template>
<!-- 情况一流程表单 --> <!-- 情况一流程表单 -->
<el-col v-if="processInstance?.processDefinition?.formType === 10" :offset="6" :span="16"> <el-col v-if="processInstance?.processDefinition?.formType === 10" :offset="6" :span="16">
<my-form-create <form-create
v-model="detailForm.value" v-model="detailForm.value"
v-model:api="fApi" v-model:api="fApi"
:option="detailForm.option" :option="detailForm.option"

View File

@ -30,8 +30,7 @@
</Dialog> </Dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
defineOptions({ name: 'InfraBuild' }) import { useFormCreateDesigner } from '@/components/FormCreate'
import FcDesigner from '@form-create/designer'
import { useClipboard } from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import { isString } from '@/utils/is' import { isString } from '@/utils/is'
@ -41,6 +40,8 @@ import xml from 'highlight.js/lib/languages/java'
import json from 'highlight.js/lib/languages/json' import json from 'highlight.js/lib/languages/json'
import formCreate from '@form-create/element-ui' import formCreate from '@form-create/element-ui'
defineOptions({ name: 'InfraBuild' })
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
@ -49,7 +50,7 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // const dialogTitle = ref('') //
const formType = ref(-1) // 0 - JSON1 - Options2 - const formType = ref(-1) // 0 - JSON1 - Options2 -
const formData = ref('') // const formData = ref('') //
useFormCreateDesigner(designer) //
/** 打开弹窗 */ /** 打开弹窗 */
const openModel = (title: string) => { const openModel = (title: string) => {
dialogVisible.value = true dialogVisible.value = true
@ -81,12 +82,12 @@ const makeTemplate = () => {
const rule = designer.value.getRule() const rule = designer.value.getRule()
const opt = designer.value.getOption() const opt = designer.value.getOption()
return `<template> return `<template>
<my-form-create <form-create
v-model:api="fApi" v-model:api="fApi"
:rule="rule" :rule="rule"
:option="option" :option="option"
@submit="onSubmit" @submit="onSubmit"
></my-form-create> ></form-create>
</template> </template>
<script setup lang=ts> <script setup lang=ts>
const faps = ref(null) const faps = ref(null)