import { CreateElement, VNode } from "vue"; import moment from "moment"; import { getToken } from "@/utils/auth"; import { deepCopy, formatFileSize, formatTime, debounce } from "@/utils/index"; import { uploadSize } from "@/settings"; import axios from "axios"; import { flowList } from "@/api/flow"; import MobilePicker from '@/components/MobilePicker/index.vue'; import MobileMultipleSelect from "@/components/MobileMultipleSelect/index.vue"; import { Message } from 'element-ui' function isJSON(str) { if (typeof str !== 'string') return false; try { const result = JSON.parse(str); const type = Object.prototype.toString.call(result); return type === '[object Object]' || type === '[object Array]'; } catch (e) { return false; } } /** * @param {String} device 'desktop' | 'mobile' * @param {Object} info field参数 * @param {CreateElement} h * @param {Object} row 子表单的row * @param {Boolean} pWrite 主表单中子表单字段是否可写 * @param {Boolean} pReadable * @return {VNode} 主表单包含el-form-item 子表单表单组件 **/ export default function formBuilder( device, info, h, row, pWrite = false, pReadable = false, pname ) { let target = row ? row : this.form; let formItem; //下拉选项 let options = []; if (info?.selection_model) { options = info.selection_model_items || []; } else if (info?.stub) { options = info?.stub?.split(/\r\n/) || []; } if (device === "desktop") { // 可写并且不为查看和子表单下 if ( info._writeable || (info.type === "relation" && info._readable) || pWrite ) { switch (info.type) { case "text": formItem = h("el-input", { props: { value: target[info.name], clearable: true, placeholder: info.help_text, }, attrs: { placeholder: info.help_text, }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }); break; case "textarea": formItem = h("el-input", { props: { type: "textarea", autosize: { minRows: 2, }, value: target[info.name], clearable: true, placeholder: info.help_text, }, attrs: { placeholder: info.help_text, }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }); break; case "date": formItem = h("el-date-picker", { props: { type: "date", "value-format": "yyyy-MM-dd", format: "yyyy年MM月dd日", value: target[info.name], clearable: true, placeholder: info.help_text, "picker-options": { shortcuts: this.shortcuts, }, }, attrs: { placeholder: info.help_text, }, style: { width: "100%", }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }); break; case "datetime": formItem = h("el-date-picker", { props: { type: "datetime", "value-format": "yyyy-MM-dd HH:mm:ss", format: "yyyy-MM-dd HH:mm", value: target[info.name], clearable: true, placeholder: info.help_text, "picker-options": { shortcuts: this.shortcuts, }, }, style: { width: "100%", }, attrs: { placeholder: info.help_text, }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }); break; case "choice": case "select": const getSelectValue = () => { if (!!info.multiple) { return target[info.name] ? target[info.name] .toString() ?.split(/,|\|/) .map((i) => { return ((isNaN(Number(i)) || !i) ? i : Number(i)) }) : []; } else { return (isNaN(Number(target[info.name])) || !target[info.name]) ? target[info.name] : Number(target[info.name]); } }; formItem = h( "el-select", { props: { value: getSelectValue(), clearable: true, placeholder: info.help_text, multiple: !!info.multiple, // "multiple-limit": info.multiple, filterable: true, "value-key": "id", "reserve-keyword": true, "allow-create": !!info.is_select2_tag, "default-first-option": true, }, style: { width: "100%", }, attrs: { placeholder: info.help_text, }, on: { input: (e) => { this.$set(target, info.name, e.toString()); }, }, }, options.map((option) => h("el-option", { key: typeof option === "object" ? option.id : option, props: { label: typeof option === "object" ? option.name : option, value: typeof option === "object" ? option.id : option, }, }) ) ); break; case "radio": formItem = h( "el-radio-group", { props: { value: target[info.name], }, attrs: { placeholder: info.help_text, }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }, options.map((option) => h( "el-radio", { props: { label: typeof option === "object" ? option.id : option, }, }, typeof option === "object" ? option.name : option ) ) ); break; case "file": formItem = row ? h("vxe-upload", { props: { value: row[info.name], "progress-text": "{percent}%", "more-config": { maxCount: 1, layout: "horizontal" }, "show-button-text": false, "limit-size": uploadSize / 1024 / 1024, // vxeupload 单位Mb "limit-count": info.multiple ? 20 : 1, multiple: !!info.multiple, "name-field": "original_name", readonly: pReadable, "upload-method": ({ file }) => { const formData = new FormData(); formData.append("file", file); window.$_uploading = true; return axios .post(process.env.VUE_APP_UPLOAD_API, formData, { headers: { Authorization: `Bearer ${getToken()}`, }, }) .then((response) => { window.$_uploading = false; if (response.status === 200 && !response.data.code) { if (!(row[info.name] instanceof Array)) { row[info.name] = []; } row[info.name].push({ response: response.data.data, name: response.data.data.original_name, url: response.data.data.url, original_name: response.data.data.original_name, }); if ( row[info.name].length > (info.multiple ? 20 : 1) ) { row[info.name].shift(); } } else { this.$message.error("上传失败"); } }) .catch((err) => { window.$_uploading = false; }); }, "remove-method": (_) => { row[info.name] = []; }, }, }) : h( "el-upload", { props: { action: process.env.VUE_APP_UPLOAD_API, headers: { Authorization: `Bearer ${getToken()}`, }, accept: "application/msword,image/jpeg,application/pdf,image/png,application/vnd.ms-powerpoint,text/plain,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document", multiple: !!info.multiple, limit: info.multiple ? 20 : 1, fileList: this.form[info.name] instanceof Array ? this.form[info.name]?.map((i) => { if (i.hasOwnProperty("original_name")) { i.name = i.original_name; } return i; }) : [], beforeUpload: (file) => { if (file.size > uploadSize) { this.$message({ type: "warning", message: `上传图片大小超过${formatFileSize( uploadSize )}!`, }); return false; } window.$_uploading = true; }, onSuccess: (response, file, fileList) => { window.$_uploading = false; fileList.forEach((file) => { if (file.response?.data && !file.response?.code) { file.response = file.response?.data; file.url = file.response?.url; } }); this.form[info.name] = fileList; }, onRemove: (file, fileList) => { this.form[info.name] = fileList; }, onError: (err, file, fileList) => { window.$_uploading = false; this.form[info.name] = fileList; this.$message({ type: "warning", message: err, }); }, }, scopedSlots: { file: (scope) => { let { file } = scope; return [ h("div", {}, [ h("i", { class: { "el-icon-circle-check": file.status === "success", "el-icon-loading": file.status === "uploading", }, style: { color: file.status === "success" ? "green" : "", }, }), h( "a", { class: { "uploaded-a": file.status === "success", }, style: { padding: "0 4px", }, on: { click: (_) => { this.$bus.$emit("online-file", file.url); }, }, }, file.original_name || file.name ), ]), h("i", { class: "el-icon-close", on: { ["click"]: () => { if (file.status === "uploading") return; this.form[info.name].splice( this.form[info.name].indexOf(file), 1 ); }, }, }), ]; }, }, }, [ h( "el-button", { slot: "trigger", props: { size: "small", type: "primary", }, }, "选取文件" ), h( "div", { class: "el-upload__tip", slot: "tip", }, `文件不超过${formatFileSize(uploadSize)}` ), ] ); break; case "label": formItem = h( "div", { props: { type: "primary", }, }, info.label ); break; case "static": formItem = h( "el-link", { props: { type: "primary", }, attrs: { href: target[info.name], target: "_blank", }, }, info.label ); break; case "hr": formItem = h("el-divider", {}, info.label); break; case "relation-flow": if (!this.flows[info.name]) { let extraParam = {} if (isJSON(info.stub)) { extraParam = JSON.parse(info.stub) } flowList("all", { page: 1, page_size: 9999, is_simple: 1, custom_model_id: isJSON(info.stub) ? '' : info.stub, is_auth: 1, ids:target[info.name]?target[info.name]:'', ...extraParam }).then((res) => { this.$set(this.flows, info.name, res.data.data); }); } formItem = h( "el-select", { ref: `relation-flow-${info.name}`, props: { value: target[info.name] ? target[info.name] .toString() ?.split(",") .map((i) => Number(i)) : [], clearable: true, placeholder: info.help_text || '输入标题或编号搜索流程..', multiple: true, filterable: true, "reserve-keyword": true, "filter-method": debounce((query) => { this.tempFlowList = this.flows[info.name].filter(flow => new RegExp(query, 'i').test(flow.title + flow.no)) console.log(query) if (this.tempFlowList.length === 0) { Message.warning("未搜索到匹配流程") } }, 500).bind(this) }, attrs: { placeholder: info.help_text, }, style: { width: "100%", }, on: { input: (e) => { this.$set(target, info.name, e.toString()); this.tempFlowList.length = 0; }, }, }, (this.tempFlowList.length > 0 ? this.tempFlowList : this.flows[info.name])?.map((option) => h("el-option", { props: { label: option.title, value: option.id, }, }, [ h("div", { }, [ h("span", {},option.title), h("el-button", { style: { float: 'right' }, props: { type: 'primary', size: 'mini', icon: 'el-icon-search' }, on: { click: e => { e.stopPropagation() let target = this.$router.resolve({ path: "/flow/detail", query: { module_id: option.custom_model_id, flow_id: option.id, isSinglePage: 1, }, }); this.modalRender = (h) => h("iframe", { attrs: { src: target.href, }, style: { border: "none", width: "100%", height: "100%", }, }); this.isShowModal = true; this.$refs[`relation-flow-${info.name}`]?.blur() } } }, '查看') ]) ]) ) ); break; case "relation": formItem = h( "vxe-table", { ref: `subForm-${info.name}`, style: { "margin-top": "10px", }, props: { "min-height": "200px", border: true, stripe: true, data: this.form[info.name] && typeof this.form[info.name] !== "string" ? this.form[info.name] : [], "keep-source": true, "column-config": { resizable: true }, "show-overflow": true, "edit-rules": info._writeable ? this.subRules[`${info.name}_rules`] : {}, "edit-config": info._writeable ? { trigger: "click", mode: "row", showStatus: false, isHover: true, autoClear: false, } : {}, }, on: { "edit-closed": ({ row, column }) => { const $table = this.$refs[`subForm-${info.name}`]; if ($table) { this.$set( this.form, info.name, this.$refs[`subForm-${info.name}`].tableData ); } }, }, }, [ info._writeable ? h( "vxe-column", { props: { width: 56, align: "center", }, scopedSlots: { default: ({ row }) => { return h("el-button", { slot: "default", style: { padding: "9px", }, props: { type: "danger", size: "small", icon: "el-icon-minus", }, on: { click: async (_) => { const $table = this.$refs[`subForm-${info.name}`]; if ($table) { await $table.remove(row); this.form[info.name] = $table.getTableData()?.tableData; } }, }, }); }, }, }, [ h("el-button", { slot: "header", style: { padding: "9px", }, props: { type: "primary", size: "small", icon: "el-icon-plus", }, on: { click: async (_) => { const $table = this.$refs[`subForm-${info.name}`]; if ($table) { const record = {}; this.form[info.name].unshift(record); // 临时数据不好验证长度 // const { row: newRow } = await $table.insert( // record // ); await this.$nextTick(); await $table.setEditRow(record); } }, }, }), ] ) : "", ...this.subForm .get(info.sub_custom_model_id) ?.customModel?.fields?.map((subField, subIndex) => h("vxe-column", { props: { field: subField.name, title: subField.label, align: "center", "min-width": "180", "edit-render": {}, }, scopedSlots: { edit: ({ row: myrow }) => { return formBuilder.bind(this)( device, subField, h, myrow, info._writeable, false ); }, [["file", "choices", "choice", "select", "radio"].indexOf( subField.type ) !== -1 ? "default" : false]: ({ row: myrow }) => { return formBuilder.bind(this)( device, subField, h, myrow, false, true ); }, }, }) ), ] ); break; } } else if (info._readable || pReadable) { switch (info.type) { case "date": formItem = h( "span", { style: { color: "#333", }, }, target[info.name] ? moment(target[info.name]).format("YYYY年MM月DD日") : "" ); break; case "datetime": formItem = h( "span", { style: { color: "#333", }, }, target[info.name] ? moment(target[info.name]).format("YYYY年MM月DD日 HH时mm分") : "" ); break; case "choice": case "select": const getDetailSelectValue = () => { let res = ""; if (!!info.multiple) { res = target[info.name] ? target[info.name] .toString() ?.split(/,|\|/) .map((i) => ((isNaN(Number(i)) || !i) ? i : Number(i))) : []; } else { res = (isNaN(Number(target[info.name])) || !target[info.name]) ? target[info.name] : Number(target[info.name]); } if (res instanceof Array) { if (typeof options[0] === "object") { return options ?.filter((i) => res.indexOf(i.id) !== -1) ?.map((i) => i.name) ?.toString(); } else { return res; } } else { if (typeof options[0] === "object") { return options ?.filter((i) => res === i.id) ?.map((i) => i.name) ?.toString(); } else { return res; } } }; formItem = h( "span", { style: { color: "#333", }, }, getDetailSelectValue() ); break; case "relation-flow": console.log("info",info,target) if (!this.flows[info.name]) { let extraParam = {} if (isJSON(info.stub)) { extraParam = JSON.parse(info.stub) } flowList("all", { page: 1, page_size: 9999, is_simple: 1, custom_model_id: isJSON(info.stub) ? '' : info.stub, is_auth: 1, ids:target[info.name]?target[info.name]:'', ...extraParam }).then((res) => { this.$set(this.flows, info.name, res.data.data); }); } formItem = h( "span", { style: { color: "#333", }, }, target[info.name] ?.toString() ?.split(",") ?.map((j) => { let flow = this.flows[info.name]?.find((i) => i.id == j); return flow ? h( "el-link", { props: { type: "primary", }, style: { "line-height": "1.5", }, on: { click: (_) => { let target = this.$router.resolve({ path: "/flow/detail", query: { module_id: flow.custom_model_id, flow_id: flow.id, isSinglePage: 1, }, }); this.modalRender = (h) => h("iframe", { attrs: { src: target.href, }, style: { border: "none", width: "100%", height: "100%", }, }); this.isShowModal = true; }, }, }, flow.title ) : ""; }) ); break; case "file": formItem = row ? h("vxe-upload", { props: { value: row[info.name], "name-field": "original_name", "progress-text": "{percent}%", "more-config": { maxCount: 1, layout: "horizontal" }, "show-button-text": false, "limit-size": uploadSize / 1024 / 1024, //vxe upload单位为Mb "limit-count": info.multiple ? 20 : 1, readonly: true, }, }) : h( "el-upload", { props: { action: process.env.VUE_APP_UPLOAD_API, headers: { Authorization: `Bearer ${getToken()}`, }, disabled: true, accept: "application/msword,image/jpeg,application/pdf,image/png,application/vnd.ms-powerpoint,text/plain,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document", multiple: true, fileList: this.form[info.name] instanceof Array ? this.form[info.name]?.map((i) => { if (i.hasOwnProperty("original_name")) { i.name = i.original_name; } return i; }) : [], }, scopedSlots: { file: (scope) => { let { file } = scope; return [ h("div", {}, [ h("i", { class: "el-icon-circle-check", style: { color: "green", }, }), h( "a", { class: { "uploaded-a": file.status === "success", }, style: { padding: "0 4px", }, on: { click: (_) => { this.$bus.$emit("online-file", file.url); }, }, }, file.name ), ]), ]; }, }, }, [ h( "span", { slot: "trigger", }, `数量:${ this.form[info.name] instanceof Array ? this.form[info.name]?.length : 0 }` ), ] ); break; default: formItem = h( "span", { style: { color: "#333", }, }, target[info.name] ); } } if (formItem) { let jointlySignContent = []; let isJointly = false; this.jointlySignLog.forEach((log) => { const data = JSON.parse(log.data); Object.entries(data)?.forEach(([key, value]) => { if ( value.hasOwnProperty("custom_field_id") && value["custom_field_id"] === info.id ) { isJointly = !!log.is_jointly_sign; if (log.status) { jointlySignContent.push( h("div", [ h("span", value.value), h("br"), info.is_sign ? log.user.sign_file && log.user.sign_file.url ? h("el-image", { style: { "max-height": "80px", "max-width": "120px", }, props: { src: log.user?.sign_file?.url, fit: "contain", alt: log.user?.name, }, attrs: { src: log.user?.sign_file?.url, alt: log.user?.name, }, }) : h("span", log.user?.name) : "", info.is_sign ? h("br") : "", h( "span", log.updated_at ? this.$moment(log.updated_at).format("YYYY年MM月DD日") : "" ), ]) ); } } }); }); return row ? formItem : h( "el-form-item", { attrs: { 'data-field-id': info.id }, props: { prop: info.name, label: info.label_show ? info.label : "", "label-width": !info.label_show ? "0" : "", }, style: { // +1为了工作标题往下顺延 "grid-column-start": info.gs_x + 1, "grid-column-end": info.gs_x + 1 + info.gs_width, "grid-row-start": info.gs_y + 1 + (info.name === "flow_title" ? 0 : 1), "grid-row-end": info.gs_y + 1 + (info.name === "flow_title" ? 0 : 1) + info.gs_height, }, }, isJointly ? [info._writeable ? formItem : "", jointlySignContent] : [ (() => { if (info.name === "flow_title") { return formItem; } if (info._writeable) { return formItem; } else { let log = this.logs.find( (log) => log.node?.fields?.findIndex( (field) => field?.field_id === info.id && field.type === "write" ) !== -1 && target[info.name] ); if ((log && log.status) || log?.user?.id === this.$store.state.user.adminId || this.logs.length === 0) { return formItem; } } })(), (() => { if (info.is_sign) { let log = this.logs.find( (log) => log.node?.fields?.findIndex( (field) => field?.field_id === info.id && field.type === "write" ) !== -1 && target[info.name] ); if (log && log.status && log.user) { return h("div", [ log.user.sign_file && log.user.sign_file.url ? h("el-image", { style: { "max-height": "80px", "max-width": "120px", }, props: { src: log.user?.sign_file?.url, fit: "contain", alt: log.user?.name, }, attrs: { src: log.user?.sign_file?.url, alt: log.user?.name, }, }) : h("span", log.user?.name), h( "div", this.$moment(log.updated_at).format( "YYYY年MM月DD日" ) ), ]); } } })(), ] ); } } if (device === "mobile") { if (info._writeable || pWrite) { switch (info.type) { case "text": formItem = h("van-field", { props: { name: info.name, value: target[info.name], clearable: true, placeholder: info.help_text || info.label, }, attrs: { placeholder: info.help_text, }, on: { input: (e) => this.$set(target, info.name, e), }, }); break; case "textarea": formItem = h("van-field", { props: { name: info.name, rows: 2, type: "textarea", value: target[info.name], clearable: true, placeholder: info.help_text || info.label, }, attrs: { placeholder: info.help_text, }, on: { input: (e) => this.$set(target, info.name, e), }, }); break; case "radio": formItem = h( "van-radio-group", { props: { value: target[info.name], }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }, options.map((option) => h( "van-radio", { props: { name: typeof option === "object" ? option.id : option, "checked-color": "var(--theme-color)", }, }, typeof option === "object" ? option.name : option ) ) ); break; case "date": formItem = h("el-date-picker", { props: { type: "date", "value-format": "yyyy-MM-dd", format: "yyyy年MM月dd日", value: target[info.name], clearable: true, placeholder: info.help_text || info.label, "picker-options": { shortcuts: this.shortcuts, }, }, attrs: { placeholder: info.help_text || info.label, }, style: { width: "100%", }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }); break; case "datetime": formItem = h("el-date-picker", { props: { type: "datetime", "value-format": "yyyy-MM-dd HH:mm:ss", format: "yyyy-MM-dd HH:mm", value: target[info.name], clearable: true, placeholder: info.help_text || info.label, "picker-options": { shortcuts: this.shortcuts, }, }, style: { width: "100%", }, attrs: { placeholder: info.help_text || info.label, }, on: { input: (e) => { this.$set(target, info.name, e); }, }, }); break; case "choice": case "select": const getDetailMobileSelectValue = () => { let res = ""; if (!!info.multiple) { res = target[info.name] ? target[info.name] .toString() ?.split(/,|\|/) .map((i) => ((isNaN(Number(i)) || !i) ? i : Number(i))) : []; } else { res = (isNaN(Number(target[info.name])) || !target[info.name]) ? target[info.name] : Number(target[info.name]); } if (res instanceof Array) { if (typeof options[0] === "object") { return options ?.filter((i) => res.indexOf(i.id) !== -1) ?.map((i) => i.name) ?.toString(); } else { return res; } } else { if (typeof options[0] === "object") { return options ?.filter((i) => res === i.id) ?.map((i) => i.name) ?.toString(); } else { return res; } } }; formItem = h('div', [ h('van-field', { props: { value: getDetailMobileSelectValue(), clickable: true, readonly: true, 'label-width': 0, border: false }, on: { click: _ => { this.$refs[`popup-${info.name}-${row ? 'c' : 'b'}`].show() } } }), !!info.multiple ? h(MobileMultipleSelect, { ref: `popup-${info.name}-${row ? 'c' : 'b'}`, props: { outputType: 'string', selectDataOpts: options, options: { label: 'name', value: 'id' } }, on: { confirm: e => { this.$set(target, info.name, e) this.$refs[`popup-${info.name}-${row ? 'c' : 'b'}`].hide() } } }) : h(MobilePicker, { ref: `popup-${info.name}-${row ? 'c' : 'b'}`, props: { columns: options, }, on: { confirm: e => { this.$set(target, info.name, typeof e === "object" ? e.id : e) this.$refs[`popup-${info.name}-${row ? 'c' : 'b'}`].hide() } } }) ]) break; case "file": formItem = h( "el-upload", { props: { action: process.env.VUE_APP_UPLOAD_API, headers: { Authorization: `Bearer ${getToken()}`, }, accept: "application/msword,image/jpeg,application/pdf,image/png,application/vnd.ms-powerpoint,text/plain,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document", multiple: !!info.multiple, limit: info.multiple ? 20 : 1, fileList: this.form[info.name] instanceof Array ? this.form[info.name]?.map((i) => { if (i.hasOwnProperty("original_name")) { i.name = i.original_name; } return i; }) : [], beforeUpload: (file) => { if (file.size > uploadSize) { this.$message({ type: "warning", message: `上传图片大小超过${formatFileSize( uploadSize )}!`, }); return false; } window.$_uploading = true; }, onSuccess: (response, file, fileList) => { window.$_uploading = false; fileList.forEach((file) => { if (file.response?.data && !file.response?.code) { file.response = file.response?.data; file.url = file.response?.url; } }); target[info.name] = fileList; }, onRemove: (file, fileList) => { target[info.name] = fileList; }, onError: (err, file, fileList) => { window.$_uploading = false; target[info.name] = fileList; this.$message({ type: "warning", message: err, }); }, }, scopedSlots: { file: (scope) => { let { file } = scope; return [ h("div", {}, [ h("i", { class: { "el-icon-circle-check": file.status === "success", "el-icon-loading": file.status === "uploading", }, style: { color: file.status === "success" ? "green" : "", }, }), h( "a", { class: { "uploaded-a": file.status === "success", }, style: { padding: "0 4px", }, on: { click: (_) => { this.$bus.$emit("online-file", file.url); }, }, }, file.original_name || file.name ), ]), h("i", { class: "el-icon-close", on: { ["click"]: () => { if (file.status === "uploading") return; target[info.name].splice( target[info.name].indexOf(file), 1 ); }, }, }), ]; }, }, }, [ h( "el-button", { slot: "trigger", props: { size: "mini", type: "primary", }, }, "选取文件" ), h( "div", { class: "el-upload__tip", slot: "tip", }, `文件不超过${formatFileSize(uploadSize)}` ), ] ); break; case "relation-flow": if (!this.flows[info.name]) { let extraParam = {} if (isJSON(info.stub)) { extraParam = JSON.parse(info.stub) } flowList("all", { page: 1, page_size: 9999, is_simple: 1, custom_model_id: isJSON(info.stub) ? '' : info.stub, is_auth: 1, ids:target[info.name]?target[info.name]:'', ...extraParam }).then((res) => { this.$set(this.flows, info.name, res.data.data); }); } formItem = h('div', [ h('van-field', { props: { value: target[info.name] ?.toString() ?.split(",") ?.map((j) => { let flow = this.flows[info.name]?.find((i) => i.id == j) return flow?.title })?.toString(), clickable: true, readonly: true, 'label-width': 0, border: false }, on: { click: _ => { this.$refs[`popup-${info.name}-${row ? 'c' : 'b'}`].show() } } }), h(MobileMultipleSelect, { ref: `popup-${info.name}-${row ? 'c' : 'b'}`, props: { outputType: 'string', selectDataOpts: this.flows[info.name], options: { label: 'title', value: 'id' } }, on: { confirm: e => { this.$set(target, info.name, e) this.$refs[`popup-${info.name}-${row ? 'c' : 'b'}`].hide() } } }) ]) break; case "relation": let copySubForm = deepCopy(this.form[info.name][0]); formItem = h("div", [ h( "van-cell", { props: { title: info.label_show ? info.label : '', "arrow-direction": "down", } }, [ h( "van-button", { props: { color: "var(--theme-color)", icon: "plus", size: "small", 'native-type': 'button' }, on: { click: (_) => { this.form[info.name].push(copySubForm); }, }, }, "新增" ), ] ), h( "div", this.form[info.name] instanceof Array ? this.form[info.name]?.map((sForm, sIndex) => h( "van-cell", { props: { inset: false, }, }, [ h( "van-cell", { props: { title: info.label + "-" + (sIndex + 1), }, }, [ h( "van-button", { props: { size: "mini", type: "danger", icon: "minus", 'native-type': 'button' }, on: { click: (_) => { this.form[info.name].splice(sIndex, 1); }, }, }, "删除" ), ] ), h( "el-form", { ref: "elSubForm-" + info.name + sIndex, props: { size: "mini", model: sForm, "label-position": "right", rules: this.subRules[`${info.name}_rules`], "inline-message": true, }, style: { margin: "0 10px", }, attrs: { ref: "elSubForm-" + info.name } }, this.subForm.get(info.sub_custom_model_id)?.customModel?.fields?.map((subField) => formBuilder.bind(this)( device, subField, h, sForm, info._writeable, null, info.name ) ) ), ] ) ) : "" ), ]); break; } } else if (info._readable || pReadable) { switch (info.type) { case "date": formItem = h("van-field", { props: { readonly: true, value: target[info.name] ? moment(target[info.name]).format("YYYY年MM月DD日") : "", }, }); break; case "datetime": formItem = h("van-field", { props: { readonly: true, value: target[info.name] ? moment(target[info.name]).format( "YYYY年MM月DD日 HH时mm分ss秒" ) : "", }, }); break; case "select": case "choice": const getDetailMobileSelectValue = () => { let res = ""; if (!!info.multiple) { res = target[info.name] ? target[info.name] .toString() ?.split(/,|\|/) .map((i) => (isNaN(Number(i)) || !i ? i : Number(i))) : []; } else { res = isNaN(Number(target[info.name])) || !target[info.name] ? target[info.name] : Number(target[info.name]); } if (res instanceof Array) { if (typeof options[0] === "object") { return options ?.filter((i) => res.indexOf(i.id) !== -1) ?.map((i) => i.name) ?.toString(); } else { return res; } } else { if (typeof options[0] === "object") { return options ?.filter((i) => res === i.id) ?.map((i) => i.name) ?.toString(); } else { return res; } } }; formItem = h("van-field", { props: { readonly: true, value: getDetailMobileSelectValue(), }, }); break; case "file": let files = target[info.name]; formItem = h( "div", {}, (files && files !== "null" && files !== "undefined" ? files : [] )?.map((file) => h("div", {}, [ h( "a", { class: { "uploaded-a": file.status === "success", }, style: { padding: "0 4px", }, on: { click: (_) => { this.$bus.$emit("online-file", file.url); }, }, }, file.original_name || file.name ), ]) ) ); break; case "relation": formItem = h("div", [ h("van-cell", { props: { title: info.label_show ? info.label : '', }, }), h( "div", this.form[info.name] instanceof Array ? this.form[info.name]?.map((sForm, sIndex) => h( "van-cell", { props: { inset: false, }, }, [ h("van-cell", { props: { title: info.label + "-" + (sIndex + 1), }, }), h( "van-form", { ref: "elSubForm-"+sIndex, props: { }, style: { margin: "0 10px", }, }, Array.from(this.subForm) .map((i) => i[1]?.customModel?.fields) ?.flat() .map((subField) => formBuilder.bind(this)( device, subField, h, sForm, info._writeable, info._readable ) ) ), ] ) ) : "" ), ]); break; case "relation-flow": if (!this.flows[info.name]) { let extraParam = {} if (isJSON(info.stub)) { extraParam = JSON.parse(info.stub) } flowList("all", { page: 1, page_size: 9999, is_simple: 1, custom_model_id: isJSON(info.stub) ? '' : info.stub, is_auth: 1, ids:target[info.name]?target[info.name]:'', ...extraParam }).then((res) => { this.$set(this.flows, info.name, res.data.data); }); } formItem = h( "van-cell", { style: { width: '100%', }, props: { }, }, target[info.name] ?.toString() ?.split(",") ?.map((j) => { let flow = this.flows[info.name]?.find((i) => i.id == j); return flow ? h( "el-link", { props: { type: "primary", }, style: { "line-height": "1.5", }, on: { click: (_) => { let target = this.$router.resolve({ path: "/flow/detail", query: { module_id: flow.custom_model_id, flow_id: flow.id, isSinglePage: 1, }, }); this.modalRender = (h) => h("iframe", { attrs: { src: target.href, }, style: { border: "none", width: "100%", height: "100%", }, }); this.isShowModal = true; }, }, }, flow.title ) : ""; }) ); break; default: formItem = h("van-field", { props: { value: target[info.name], readonly: true }, }) } } if (formItem) { let jointlySignContent = []; let isJointly = false; this.jointlySignLog.forEach((log) => { const data = JSON.parse(log.data); Object.entries(data)?.forEach(([key, value]) => { if ( value.hasOwnProperty("custom_field_id") && value["custom_field_id"] === info.id ) { isJointly = !!log.is_jointly_sign; if (log.status) { jointlySignContent.push( h("div", [ h("span", value.value), h("br"), info.is_sign ? log.user.sign_file && log.user.sign_file.url ? h("el-image", { style: { "max-height": "40px", "max-width": "60px", }, props: { src: log.user?.sign_file?.url, fit: "contain", alt: log.user?.name, }, attrs: { src: log.user?.sign_file?.url, alt: log.user?.name, }, }) : h("span", log.user?.name) : "", info.is_sign ? h("br") : "", h( "span", log.updated_at ? this.$moment(log.updated_at).format("YYYY年MM月DD日") : "" ), ]) ); } } }); }); return row ? h("el-form-item", { ref: info.name, props: { prop: info.name, label: (!info.label_show || info.type === 'relation') ? "" : info.label, "label-width": (!info.label_show || info.type === 'relation') ? "0" : "", } }, [formItem]) : h( "el-form-item", { props: { prop: info.name, label: (!info.label_show || info.type === 'relation') ? "" : info.label, "label-width": (!info.label_show || info.type === 'relation') ? "0" : "", }, }, isJointly ? [info._writeable ? formItem : "", jointlySignContent] : [ (() => { if (info.name === "flow_title") { return formItem; } if (info._writeable) { return formItem; } else { let log = this.logs.find( (log) => log.node?.fields?.findIndex( (field) => field?.field_id === info.id && field.type === "write" ) !== -1 && target[info.name] ); if ((log && log.status) || log?.user?.id === this.$store.state.user.adminId || this.logs.length === 0) { return formItem; } } })(), (() => { if (info.is_sign) { let log = this.logs.find( (log) => log.node?.fields?.findIndex( (field) => field?.field_id === info.id && field.type === "write" ) !== -1 && target[info.name] ); if (log && log.status && log.user) { return h("div", [ log.user.sign_file && log.user.sign_file.url ? h("el-image", { style: { "max-height": "40px", "max-width": "60px", }, props: { src: log.user?.sign_file?.url, fit: "contain", alt: log.user?.name, }, attrs: { src: log.user?.sign_file?.url, alt: log.user?.name, }, }) : h("span", log.user?.name), h( "div", this.$moment(log.updated_at).format( "YYYY年MM月DD日" ) ), ]); } } })(), ] ); } } }