数通智联化工云平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

469 lines
13 KiB

<!--
@ 作者: 秦东
@ 时间: 2023-09-20 13:00:49
@ 备注: 自定义表单组件渲染
-->
<script lang='ts' setup>
import { computed, watch, inject, onUnmounted } from 'vue'
import Draggable from 'vuedraggable-es'
import FormItem from './formItem.vue'
import ChildTable from './childTable.vue'
import Tooltips from '@/components/DesignForm/tooltip.vue'
import FlexBox from './flexBox.vue'
import { useDesignFormStore } from '@/store/DesignForm/designForm'
import { FormList,formTableInfo } from '@/api/DesignForm/types'
import {
constFormBtnEvent,
constFormProps
} from '@/api/DesignForm/utils'
import { Md5 } from 'ts-md5';
import { jsonParseStringify } from '@/utils/DesignForm'
const props = withDefaults(
defineProps<{
data: FormList[]
tableinfo:formTableInfo
numrun?:number
}>(),
{
data: () => {
return []
}
}
)
const store = useDesignFormStore() as any //自定义表单存储器
const formProps = inject(constFormProps, {}) as any
const type = computed(() => { //动态计算属性
return formProps.value.type
})
const state = reactive({
clone: true, // 允许clone
gridAdd: false
})
const dataList = ref<any>(props.data)
watch(
() => props.data,
(v: FormList[]) => {
dataList.value = v
2 years ago
// console.log("监听表单变化++++++++++>",v)
}
)
const activeKey = computed(() => {
return store.activeKey
})
// 禁止容器嵌套
const notNested = (type: string) => {
// const controlType = ['grid', 'table', 'tabs', 'div', 'flex', 'card']
const controlType = ['grid', 'tabs', 'div', 'card']
// let kjkdh = controlType.includes(type)
// console.log("禁止容器嵌套",kjkdh,controlType)
return controlType.includes(type)
// return false
}
const notNestedTableFlex = (type: string) => {
const controlType = ['grid', 'table', 'tabs', 'div', 'flex', 'card']
// let kjkdh = controlType.includes(type)
// console.log("禁止容器嵌套",kjkdh,controlType)
return controlType.includes(type)
// return false
}
// 删除或复制
const click = (action: string, index: number, item?: any) => {
if (type.value !== 5) {
return // 非设计模式
}
if (action === 'clone') {
const key = item.type + new Date().getTime().toString()
const newItem = jsonParseStringify(item)
dataList.value.splice(index, 0, Object.assign(newItem, { name: key }))
} else if (action === 'del') {
dataList.value.splice(index, 1)
// 清空右侧栏信息
store.setActiveKey('')
store.setControlAttr({})
} else if (action === 'gridAdd') {
item.columns.push({
list: [],
attr: { span: 12 }
})
} else if (action === 'delGridChild') {
item.splice(index, 1)
}
}
const draggableAdd = (evt: any) => {
if (type.value !== 5) {
return // 非设计模式
}
const newIndex = evt.newIndex
const key = new Date().getTime().toString()
const obj: any = dataList.value[newIndex]
const isNested = evt.target && evt.target.getAttribute('data-type') // 不能嵌套
// console.log("不能嵌套",obj,isNested)
if ((isNested === 'not-nested' && notNested(obj.type)) || ((isNested === 'not-table' || isNested === 'not-flex') && notNestedTableFlex(obj.type))) {
dataList.value.splice(newIndex, 1)
return
}
if (!obj) {
return
}
const label = obj.label || obj.item.label
delete obj.label
delete obj.icon
let objectItem = {}
// 不需要添加item的项
const notNeedItem = [
'txt',
'title',
'button',
'table',
'grid',
'tabs',
'flex',
'div'
]
// console.log("非设计模式-->",obj.type)
if (!notNeedItem.includes(obj.type)) {
objectItem = {
item: {
label: label
}
}
}
// 不需要name的组件
let nameObj = {}
const notNeedName = [
'txt',
'title',
'button',
'grid',
'tabs',
'divider',
'div',
'card'
]
if (!notNeedName.includes(obj.type) && !obj.name) {
nameObj = {
name: obj.type + key
}
}
Object.assign(obj, nameObj, objectItem)
groupClick(obj)
}
const getGroupName = (item: any) => {
if (item.name) {
return item.name
} else {
let md5Object:any = new Md5()
md5Object.appendAsciiStr(JSON.stringify(item))
let md5Str = md5Object.end()
return md5Str
}
}
// 点击激活当前
const groupClick = (item: any, ele?: string) => {
// 设计模式下才执行
if (type.value !== 5) {
return
}
if (ele) {
item.type = ele
}
store.setActiveKey(getGroupName(item))
store.setControlAttr(item)
// grid时显示添加列按钮
state.gridAdd = item.type === 'grid'
// state.clone = !notNested(item.type)
state.clone = !notNestedTableFlex(item.type)
}
// 返回栅格宽度
const getFormItemStyle = (ele: FormList) => {
if (ele.config?.span === 0) {
return { width: 'auto', margin: '0 5px' }
}
if (ele.config && ele.config.span) {
return { width: (ele.config.span / 24) * 100 + '%' }
}
}
// 根据关联条件显示隐藏当前项
const linksShow = (el: FormList, index: number) => {
// 当前项设置了关联条件,当关联主体的值等于当前组件设定的值时
if (!el.config) {
return true
}
const key = el.config.linkKey
const value = el.config.linkValue
const linkResult = el.config.linkResult
if (key && value && type.value !== 5) {
const Fn = new Function('$', `return (${value})`)
const pass = Fn(formProps.value.model)
if (linkResult === 'disabled') {
// 设置为disabled后返回显示状态
dataList.value[index].control.disabled = pass
return true
} else {
return pass
}
}
return true
}
// 根据表单设置不显示指定字段
const linksIf = (obj: FormList) => {
const { type } = formProps.value
const { config: { disabledAdd, disabledEdit, disabledDetail } = {} } = obj
if (type === 1) {
if (disabledAdd) {
// 编辑页 || 新增页
return false // 不显示
}
} else if (type === 2) {
// 编辑
if (disabledEdit) {
return false
}
} else if (type === 4 || type === 3) {
// 查看
if (disabledDetail) {
return false
}
}
// 如果当前字段的name值存在于表单数据的vIf中,则不显示
const vIf: string | string[] = formProps.value.hideField
if (vIf?.length > 0 && obj.name) {
return vIf.indexOf(obj.name) === -1 // 存在时返回false隐藏
}
return true
}
//按钮点击事件
const injectBtnEvent:any = inject(constFormBtnEvent)
const clickBtn = (control: any) => {
// 0: '提交表单',
// 1: '重置表单',
// 2: '取消返回',
// 3: '无动作(自定义)'
if (type.value !== 5) {
// 非设计模式才触发事件
injectBtnEvent && injectBtnEvent(control)
}
}
onUnmounted(() => {
// console.log('formGroup onUnmounted')
dataList.value = {}
store.setActiveKey('')
store.setControlAttr({})
})
onMounted(()=>{
console.log('formGroup onMounted',dataList,props.tableinfo)
})
</script>
<template>
<draggable
itemKey="id"
:list="dataList"
name="fade"
class="drag"
v-bind="{
group: 'form',
ghostClass: 'ghost',
animation: 200,
handle: '.drag-move',
disabled: type !== 5
}"
@add="draggableAdd"
>
<template #item="{ element, index }">
<div
class="group"
:class="{
['group-' + element.type]: true,
active: activeKey === getGroupName(element)
}"
:style="getFormItemStyle(element)"
@click.stop="groupClick(element)"
v-show="linksShow(element, index)"
v-if="linksIf(element)"
>
<!--选项卡组件-->
<template v-if="element.type === 'tabs'">
<div class="form-tabs">
<el-tabs
v-bind="element.control"
:class="[element.config?.className]"
>
<el-tab-pane
v-for="(item, tIndex) in element.columns"
:label="item.label"
:key="tIndex"
>
<form-group :data="item.list" data-type="not-nested" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<!--标题组件-->
<template v-else-if="element.type === 'title'">
<div
class="title"
:class="[element.config.className]"
v-bind="element.control"
>
<span v-html="element.control.modelValue"></span>
<Tooltips
:content="element.config.help"
v-if="element.config.help"
/>
</div>
</template>
<!--文字组件-->
<template v-else-if="element.type === 'txt'">
<div
v-bind="element.control"
:class="[element.config.className]"
v-html="element.control.modelValue"
>
</div>
</template>
<!--表格组件-->
<template v-else-if="element.type === 'table'">
<div class="form-table" v-if="type === 5">
<!-- <form-group :data="element.list" data-type="not-nested" /> -->
<form-group :data="element.list" data-type="not-table" />
</div>
<child-table v-else :data="element" />
</template>
<!--格栅布局-->
<template v-else-if="element.type === 'grid'">
<el-row class="form-row" :class="[element.className]">
<el-col
class="form-col"
:class="{
'active-col': activeKey === getGroupName(col),
[col.className]: col.className
}"
v-bind="col.attr"
v-for="(col, i) in element.columns"
:key="i"
@click.stop="groupClick(col, 'gridChild')"
>
<form-group :data="col.list" data-type="not-nested" />
<div class="drag-control" v-if="type === 5">
<div class="item-control">
<i
class="icon-del"
@click.stop="click('delGridChild', i as number, element.columns)"
>
</i>
</div>
</div>
</el-col>
</el-row>
</template>
<!--卡片布局-->
<template v-else-if="element.type === 'card'">
<el-collapse model-value="1">
<el-collapse-item :title="element.item.label" name="1">
<template #title v-if="element.help">
{{ element.item.label }}
<Tooltips :content="element.help" />
</template>
<form-group :data="element.list" data-type="not-nested" />
</el-collapse-item>
</el-collapse>
</template>
<!--分割线-->
<template v-else-if="element.type === 'divider'">
<el-divider v-bind="element.control">{{ element.item && element.item.label }}</el-divider>
</template>
<!--div容器-->
<template v-else-if="element.type === 'div'">
<div
class="div-layout"
v-bind="element.control"
:class="{
[element.className]: element.className,
inline: element.config?.inline,
[element.config?.textAlign]: element.config?.textAlign
}"
>
<form-group :data="element.list" data-type="not-nested" />
</div>
</template>
<!--弹性布局-->
<template v-else-if="element.type === 'flex'">
<!-- <form-group
:data="element.list"
data-type="not-nested"
v-if="type === 5"
/> -->
<form-group
:data="element.list"
data-type="not-flex"
v-if="type === 5"
/>
<flex-box :data="element" v-else />
<el-button
style="position: relative; top: -28px; left: 10px"
v-if="element.config.addBtnText && type === 5"
size="small"
>
{{ element.config.addBtnText }}
</el-button>
</template>
<!--按钮-->
<template v-else-if="element.type === 'button'">
<div
:class="[element.config?.className]"
:style="{ 'text-align': element.config?.textAlign }"
>
<el-button
v-bind="element.control"
@click="clickBtn(element.control)"
>
{{ element.control?.label }}
</el-button>
</div>
</template>
2 years ago
<SignatureMap v-else-if="element.type === 'signaturemap'" :data="element" />
<OrgCentent v-else-if="element.type === 'orgCentent'" :data="element" />
<BaiduMap v-else-if="element.type === 'baidumap'" :data="element" />
<OrgCitys v-else-if="element.type === 'organization'" :data="element" />
<UrlLink v-else-if="element.type === 'urllink'" :data="element" />
<SerialNumber v-else-if="element.type === 'serialNumber'" :data="element" :tablekey="props.tableinfo.name" :numrun="props.numrun" />
<!--其他组件-->
<FormItem v-else :data="element" />
2 years ago
<!--组件设计外功能框架-->
<template v-if="type === 5">
<div class="drag-control">
<div class="item-control">
<i
class="icon-plus"
@click.stop="click('gridAdd', index, element)"
v-if="state.gridAdd"
title="添加列"
></i>
<i
class="icon-clone"
@click.stop="click('clone', index, element)"
v-if="state.clone"
title="克隆"
></i>
<i class="icon-del" @click.stop="click('del', index)"></i>
</div>
<div class="drag-move icon-move"></div>
</div>
<div class="tooltip" style="display: none;">{{ element.name }}</div>
</template>
</div>
</template>
</draggable>
</template>
<style lang='scss' scoped>
</style>