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.
522 lines
16 KiB
522 lines
16 KiB
<!--
|
|
@ 作者: 秦东
|
|
@ 时间: 2025-06-11 08:11:22
|
|
@ 备注: 表单组件循环(新版)
|
|
-->
|
|
<script lang='ts' setup>
|
|
import { Md5 } from 'ts-md5'
|
|
import { debounce } from '@/utils/lowCode/item/index'
|
|
import { uploadUrl } from '@/api/lowCode/form/fieldUnit'
|
|
import {
|
|
constFormProps,
|
|
constControlChange,
|
|
constGetControlByName,
|
|
constSetFormOptions
|
|
} from '@/api/lowCode/utils';
|
|
import validate from "@/api/lowCode/form/validate"
|
|
import { AnalysisCss,AnalysisInputCss } from '@/api/common/cssInfo' //样式解析
|
|
import { useAttrs,computed, onMounted, nextTick,ref,watch,onBeforeMount} from 'vue'
|
|
//辅助控件
|
|
import InputPage from '@/components/lowCode/assistant/inputPage.vue'
|
|
import DigitpagePage from '@/components/lowCode/assistant/digitpage.vue'
|
|
import TextareaPage from '@/components/lowCode/assistant/textareaPage.vue'
|
|
import RadioPage from '@/components/lowCode/assistant/radioPage.vue'
|
|
import CheckboxPage from '@/components/lowCode/assistant/checkboxPage.vue'
|
|
import SelectPage from '@/components/lowCode/assistant/selectPage.vue'
|
|
import CascaderPage from '@/components/lowCode/assistant/cascader.vue'
|
|
import DatePickerPage from '@/components/lowCode/assistant/datePicker.vue'
|
|
import TimePickerPage from '@/components/lowCode/assistant/timePickerPage.vue'
|
|
import OrgCitys from '@/components/lowCode/assistant/orgCitys.vue'
|
|
import SwitchPage from '@/components/lowCode/assistant/switchPage.vue'
|
|
import InputNumberPage from '@/components/lowCode/assistant/inputNumberPage.vue'
|
|
import LowcodeImagePage from '@/components/lowCode/assistant/lowcodeImage.vue'
|
|
import VideoUpAndPlay from '@/components/lowCode/assistant/videoUpAndPlay.vue'
|
|
import UploadPage from '@/components/lowCode/assistant/uploadPage.vue'
|
|
import UrlLinkPage from '@/components/lowCode/assistant/urlLink.vue'
|
|
import BaiDuMapPage from '@/components/lowCode/assistant/baiDuMap.vue'
|
|
import QuillEditor from '@/components/lowCode/assistant/quillEditor.vue'
|
|
import LowcodeCarsusel from '@/components/lowCode/assistant/lowcodeCarsusel.vue'
|
|
import SignatureMap from '@/components/lowCode/assistant/signatureMap.vue'
|
|
import LowcodeTransfer from '@/components/lowCode/assistant/lowcodeTransfer.vue'
|
|
import ColorPickerPage from '@/components/lowCode/assistant/colorPickerPage.vue'
|
|
import TreeSelectPage from '@/components/lowCode/assistant/treeSelectPage.vue'
|
|
import AssociatedForms from '@/components/lowCode/assistant/associatedForms.vue'
|
|
import SerialNumber from '@/components/lowCode/assistant/serialNumber.vue'
|
|
import ExpandUser from '@/components/lowCode/assistant/rangedUserTree.vue'
|
|
import OrgCentent from '@/components/lowCode/assistant/org.vue'
|
|
import FounderForm from '@/components/lowCode/assistant/founder.vue'
|
|
import FounderTime from '@/components/lowCode/assistant/founderTime.vue'
|
|
import EditTime from '@/components/lowCode/assistant/editTime.vue'
|
|
import OwnerPage from '@/components/lowCode/assistant/ownerPage.vue'
|
|
import DepartmentOrg from '@/components/lowCode/assistant/departmentOrg.vue'
|
|
import PickRole from '@/components/lowCode/assistant/pickrole.vue'
|
|
import PickPost from '@/components/lowCode/assistant/pickpost.vue'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
data: FormList
|
|
modelValue?: any // 子表和弹性布局时时有传
|
|
tProp?: string // 子表时的form-item的prop值,用于子表校验用
|
|
nodeKey?:string
|
|
purview?:any[]
|
|
optionsValue3Get1?:any
|
|
tablekey?:any
|
|
numrun?:any
|
|
rowIndex?:any
|
|
tableinfo?:any
|
|
orgAndManTree?: any;
|
|
}>(),
|
|
{}
|
|
)
|
|
const emits = defineEmits<{
|
|
(e: 'update:modelValue', val: any): void
|
|
(e: 'optionsValue3Get1', val: any,fieldName: string): void
|
|
(e: 'asfValueChanged', val: any): void
|
|
}>()
|
|
const formProps = inject(constFormProps, {}) as any
|
|
const imgUploadApiUrl = import.meta.env.VITE_APP_BASE_API+"/api/upordown" //默认图片
|
|
//执行类型
|
|
const type = computed(() => {
|
|
return formProps.value.type
|
|
})
|
|
//配置
|
|
const config = computed(() => {
|
|
return props.data.config || {}
|
|
})
|
|
//组件css部分
|
|
const configStyle = computed(() => {
|
|
return props.data.styles || {}
|
|
})
|
|
const control = computed(() => {
|
|
if(props.data.type == "upload"){
|
|
props.data.control.action = uploadUrl
|
|
}
|
|
return props.data.control
|
|
})
|
|
const options = ref(props.data.options) //附属属性值
|
|
const changeEvent = inject(constControlChange, '') as any
|
|
//获取值
|
|
const value = computed({
|
|
get() {
|
|
|
|
// console.log("formProps.value.model",formProps.value.model)
|
|
// console.log("props.data.name",props.data.name)
|
|
|
|
if (props.tProp) {
|
|
// 表格和弹性布局
|
|
return props.modelValue
|
|
} else {
|
|
if(props.data.type == "checkbox"){
|
|
if (formProps.value.model[props.data.name] == null || formProps.value.model[props.data.name] == ""){
|
|
// formProps.value.model[props.data.name] = []
|
|
// return formProps.value.model[props.data.name]
|
|
return []
|
|
}else{
|
|
return formProps.value.model[props.data.name]
|
|
}
|
|
}else{
|
|
return formProps.value.model[props.data.name]
|
|
}
|
|
|
|
}
|
|
},
|
|
set(newVal: any) {
|
|
if (props.tProp) {
|
|
emits('update:modelValue', newVal)
|
|
}
|
|
updateModel(newVal)
|
|
}
|
|
})
|
|
const getControlByName = inject(constGetControlByName) as any
|
|
// 对单选多选select设置options
|
|
const formOptions = inject(constSetFormOptions, {}) as any
|
|
//更新数值
|
|
const updateModel = (val: any) => {
|
|
let controlAttribute = ""
|
|
if(props.data.control){
|
|
if(props.data.control.type){
|
|
controlAttribute = props.data.control.type
|
|
}
|
|
}
|
|
changeEvent &&
|
|
changeEvent({
|
|
key: props.data.name,
|
|
value: val,
|
|
data: props.data,
|
|
tProp: props.tProp,
|
|
type: props.data.type,
|
|
attribute: controlAttribute
|
|
})
|
|
}
|
|
// 返回当前item项的校验规则
|
|
const itemRules = computed(() => {
|
|
let temp
|
|
const itemR: any = props.data.item?.rules || []
|
|
const customR = formatCustomRules()
|
|
// 如果三个都没有设置,则返回undefined
|
|
if (itemR?.length || customR?.length) {
|
|
temp = [...customR, ...itemR]
|
|
}
|
|
return temp
|
|
})
|
|
// 处理自定义校验规则,将customRules转换后追加到rules里
|
|
const formatCustomRules = () => {
|
|
const rulesReg: any = {}
|
|
validate &&
|
|
validate.forEach(item => {
|
|
rulesReg[item.type] = item.regExp
|
|
})
|
|
|
|
// 获取校验方法 父级使用provide方法注入
|
|
const temp: any = []
|
|
props.data.customRules?.forEach((item: any) => {
|
|
if (!item.message && item.type !== 'methods') {
|
|
return // 方法时允许提示信息为空
|
|
}
|
|
let obj = {}
|
|
if (item.type === 'required') {
|
|
obj = { required: true }
|
|
} else if (item.type === 'rules') {
|
|
// 自定义表达式
|
|
obj = { pattern: item.rules }
|
|
} else if (item.type === 'methods') {
|
|
// 方法时
|
|
const methods: any = item.methods
|
|
if (methods) {
|
|
obj = { validator: inject(methods, {}) }
|
|
}
|
|
} else if (item.type) {
|
|
obj = { pattern: rulesReg[item.type as string] }
|
|
}
|
|
// 这里判断下防某些条件下重复push的可能或存重复校验类型
|
|
let message: any = { message: item.message }
|
|
if (!item.message) {
|
|
// 当使用validator校验时,如果存在message字段则不能使用 callback(new Error('x'));的提示
|
|
message = {}
|
|
}
|
|
temp.push(
|
|
Object.assign(
|
|
{
|
|
trigger: item.trigger || 'blur'
|
|
},
|
|
obj,
|
|
message
|
|
)
|
|
)
|
|
})
|
|
return temp
|
|
}
|
|
/**
|
|
@ 作者: 秦东
|
|
@ 时间: 2024-07-27 15:11:42
|
|
@ 功能: 判断是否禁用
|
|
*/
|
|
const judgeIsDisabled = (key:string) => {
|
|
return false
|
|
if (type.value === 3) {
|
|
return true // 查看模式,为不可编辑状态
|
|
}
|
|
if (type.value === 1 && config.value.addDisabled) {
|
|
return true
|
|
}
|
|
if (type.value === 2 && config.value.editDisabled) {
|
|
return true // 编辑模式
|
|
}
|
|
if(props.nodeKey != undefined && props.purview != undefined && props.purview != null && props.purview != null && props.purview != "" && props.purview != "") {
|
|
if(props.purview.length < 1){
|
|
return false;
|
|
}else{
|
|
let isShow = true;
|
|
props.purview.forEach((item)=>{
|
|
if(item.nodeKey == props.nodeKey){
|
|
|
|
if(item.powerAry && item.powerAry.length > 0){
|
|
item.powerAry.forEach((itm)=>{
|
|
if(itm.id == key){
|
|
console.log("判断此组件是否禁用",itm,itm.id == key,"--------->",itm.isLook)
|
|
isShow = !itm.isEdit
|
|
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
})
|
|
return isShow
|
|
}
|
|
}else{
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
@ 作者: 秦东
|
|
@ 时间: 2024-11-13 14:36:08
|
|
@ 功能: 解析css
|
|
*/
|
|
const getFormItemLableStyle = (ele: any) => {
|
|
if(ele?.labelStyle){
|
|
// console.log("返回栅格宽度3",AnalysisCss(ele))
|
|
return AnalysisCss(ele?.labelStyle)
|
|
}
|
|
}
|
|
const getFormItemInputStyle = (ele: any,sty:number) => {
|
|
if(ele?.inputStyle){
|
|
// console.log("返回栅格宽度4",AnalysisInputCss(ele?.inputStyle,sty))
|
|
return AnalysisInputCss(ele?.inputStyle,sty)
|
|
}
|
|
}
|
|
//获取标签
|
|
const getLabel = (ele: FormItem) => {
|
|
const showColon = formProps.value.showColon ? ':' : ''
|
|
if (ele) {
|
|
return ele.showLabel ? '' : ele.label + showColon
|
|
} else {
|
|
return ''
|
|
}
|
|
}
|
|
function asfValueChanged(val:any){
|
|
emits("asfValueChanged",val)
|
|
}
|
|
|
|
const updateContentVideo = (val: any) => {
|
|
console.log("更新数据-------->",val)
|
|
//alert(1)
|
|
value.value = val;
|
|
/* props.data.control.videoMsg[0].url = val;
|
|
console.log("更新数据-------->", val);
|
|
console.log("更新数据----1---->", value.value);
|
|
console.log("更新数据----2---->", props.data.control.videoMsg[0].url); */
|
|
};
|
|
/**
|
|
@ 作者: 秦东
|
|
@ 时间: 2024-11-13 16:18:59
|
|
@ 功能: 自定义组件
|
|
*/
|
|
const currentComponent = computed(() => {
|
|
switch(props.data.type){
|
|
case "component":
|
|
// 自定义组件
|
|
return config.value.componentName;
|
|
break;
|
|
case "input":
|
|
case "password":
|
|
return markRaw(InputPage);
|
|
break;
|
|
case "digitpage":
|
|
return markRaw(DigitpagePage);
|
|
break;
|
|
case "textarea":
|
|
case "description":
|
|
return markRaw(TextareaPage);
|
|
break;
|
|
case "radio":
|
|
return markRaw(RadioPage);
|
|
break;
|
|
case "checkbox":
|
|
return markRaw(CheckboxPage);
|
|
break;
|
|
case "select":
|
|
return markRaw(SelectPage);
|
|
break;
|
|
case "cascader":
|
|
return markRaw(CascaderPage);
|
|
break;
|
|
case "datePicker":
|
|
props.data.control.valueFormat = "x";
|
|
return markRaw(DatePickerPage)
|
|
break;
|
|
case "timePicker":
|
|
props.data.control.valueFormat = "x";
|
|
return markRaw(TimePickerPage)
|
|
break;
|
|
case "organization":
|
|
return markRaw(OrgCitys)
|
|
break;
|
|
case "switch":
|
|
return markRaw(SwitchPage)
|
|
break;
|
|
case "inputNumber":
|
|
return markRaw(InputNumberPage)
|
|
break;
|
|
case "lowcodeImage":
|
|
return markRaw(LowcodeImagePage)
|
|
break;
|
|
case "videoUpAndPlay":
|
|
return markRaw(VideoUpAndPlay);
|
|
break
|
|
case "upload":
|
|
return markRaw(UploadPage);
|
|
break
|
|
case "urllink":
|
|
return markRaw(UrlLinkPage);
|
|
break
|
|
case "baidumap":
|
|
return markRaw(BaiDuMapPage);
|
|
break;
|
|
case "tinymce":
|
|
return markRaw(QuillEditor);
|
|
break;
|
|
case "lowcodeCarsusel":
|
|
return markRaw(LowcodeCarsusel);
|
|
break;
|
|
case "signaturemap":
|
|
return markRaw(SignatureMap);
|
|
break;
|
|
case "lowcodeTransfer":
|
|
return markRaw(LowcodeTransfer);
|
|
break;
|
|
case "colorPicker":
|
|
return markRaw(ColorPickerPage);
|
|
break;
|
|
case "treeSelect":
|
|
return markRaw(TreeSelectPage);
|
|
break;
|
|
case "associatedForms":
|
|
return markRaw(AssociatedForms);
|
|
break;
|
|
case "serialNumber":
|
|
return markRaw(SerialNumber);
|
|
break;
|
|
case "expand-user":
|
|
return markRaw(ExpandUser);
|
|
break;
|
|
case "orgCentent":
|
|
return markRaw(OrgCentent);
|
|
break;
|
|
case "founder":
|
|
return markRaw(FounderForm);
|
|
break;
|
|
case "founderTime":
|
|
return markRaw(FounderTime);
|
|
break;
|
|
case "editTime":
|
|
return markRaw(EditTime);
|
|
break;
|
|
case "owner":
|
|
return markRaw(OwnerPage);
|
|
break;
|
|
case "deptOrg":
|
|
return markRaw(DepartmentOrg);
|
|
break;
|
|
case "pickpost":
|
|
return markRaw(PickPost);
|
|
break;
|
|
case "pickrole":
|
|
return markRaw(PickRole);
|
|
break;
|
|
default:
|
|
return `el-${props.data.type}`
|
|
}
|
|
})
|
|
|
|
const testPage = (val:any) =>{
|
|
console.log("刷新数据-------->", val);
|
|
}
|
|
|
|
const labelMaxWidth = computed(()=>{
|
|
//if(props.data.type=='radio'){
|
|
if(props.tableinfo&&props.tableinfo.labelPosition&&props.tableinfo.labelPosition=='top'){
|
|
return "100%"
|
|
}else{
|
|
return "150px"
|
|
}
|
|
/* }else{
|
|
return "150px"
|
|
} */
|
|
})
|
|
|
|
|
|
</script>
|
|
<template>
|
|
<el-form-item
|
|
v-bind="data.item"
|
|
:prop="tProp || data.name"
|
|
:class="config.className"
|
|
:label="getLabel(data.item as FormItem)"
|
|
:rules="itemRules"
|
|
class="rlabel"
|
|
>
|
|
<template #label v-if="config.help">
|
|
<span :style="getFormItemLableStyle(configStyle)">{{ getLabel(data.item) }}</span>
|
|
<Tooltips :content="config.help" />
|
|
</template>
|
|
<template #label v-else>
|
|
<span :style="getFormItemLableStyle(configStyle)" >{{ getLabel(data.item) }}</span>
|
|
</template>
|
|
<!-- {{ data.type }} -->
|
|
<!--关联表单-->
|
|
<component
|
|
v-if="['associatedForms'].includes(data.type)"
|
|
:is="currentComponent"
|
|
:data="data"
|
|
:formProps = "formProps"
|
|
v-bind="control"
|
|
:control="control"
|
|
:config="config"
|
|
:name="control.file || 'file'"
|
|
:disabled="judgeIsDisabled(data.name)"
|
|
:options="options"
|
|
:row-index = "rowIndex"
|
|
v-model="value"
|
|
@asf-value-changed="asfValueChanged"
|
|
/>
|
|
<!--视频-->
|
|
<component
|
|
v-if="['videoUpAndPlay'].includes(data.type)"
|
|
:types="type"
|
|
:is="currentComponent"
|
|
:data="data"
|
|
v-bind="control"
|
|
:control="control"
|
|
:config="config"
|
|
:name="control.file || 'file'"
|
|
:disabled="judgeIsDisabled(data.name)"
|
|
:options="options"
|
|
v-model="value"
|
|
:val-info="value"
|
|
@updateVideoUrl="updateContentVideo"
|
|
@testPage = "testPage"
|
|
/>
|
|
<!--单行文本及密码组件-->
|
|
|
|
<component
|
|
v-else
|
|
:types="type"
|
|
:is="currentComponent"
|
|
:data="data"
|
|
v-bind="control"
|
|
:control="control"
|
|
:config="config"
|
|
:name="control.file || 'file'"
|
|
:disabled="judgeIsDisabled(data.name)"
|
|
:options="options"
|
|
v-model="value"
|
|
:tableinfo="tableinfo" :org-and-man-tree="orgAndManTree"
|
|
/>
|
|
</el-form-item>
|
|
</template>
|
|
<style lang='scss' scoped>
|
|
.rlabel{
|
|
label{
|
|
height: 100%;
|
|
}
|
|
:deep .el-form-item__label{
|
|
height: 100%;
|
|
max-width: v-bind(labelMaxWidth);
|
|
}
|
|
}
|
|
|
|
:deep .el-checkbox {
|
|
|
|
--el-checkbox-disabled-checked-input-fill: #eaf2ff;
|
|
--el-checkbox-disabled-checked-input-border-color: #1e5eff;
|
|
--el-checkbox-disabled-checked-icon-color: #1e5eff;
|
|
|
|
}
|
|
|
|
:deep .el-checkbox__input.is-disabled+span.el-checkbox__label {
|
|
color: black;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
</style>
|
|
|