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.

1812 lines
61 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import formBuilderMap from "./formBuilderMap";
import { CreateElement, VNode } from "vue";
import moment from "moment";
import { getToken } from "@/utils/auth";
import {deepCopy, formatFileSize, formatTime} from "@/utils/index";
import { uploadSize } from "@/settings";
import axios from 'axios';
import { flowList } from "@/api/flow";
/**
* @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 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(formBuilderMap(device).get(info.type), {
props: {
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
},
attrs: {
placeholder: info.help_text,
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
break;
case "textarea":
formItem = h(formBuilderMap(device).get(info.type), {
props: {
type: "textarea",
autosize: {
minRows: 2,
},
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
},
attrs: {
placeholder: info.help_text,
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
break;
case "date":
formItem = h(formBuilderMap(device).get(info.type), {
props: {
type: "date",
"value-format": "yyyy-MM-dd",
format: "yyyy年MM月dd日",
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
"picker-options": {
shortcuts: [
{
text: "一年前",
onClick(picker) {
picker.$emit(
"pick",
moment().subtract(1, "years").toDate()
);
},
},
{
text: "一月前",
onClick(picker) {
picker.$emit(
"pick",
moment().subtract(1, "months").toDate()
);
},
},
{
text: "一周前",
onClick(picker) {
picker.$emit(
"pick",
moment().subtract(1, "weeks").toDate()
);
},
},
{
text: "今天",
onClick(picker) {
picker.$emit("pick", new Date());
},
},
{
text: "一周后",
onClick(picker) {
picker.$emit("pick", moment().add(1, "weeks").toDate());
},
},
{
text: "一月后",
onClick(picker) {
picker.$emit("pick", moment().add(1, "months").toDate());
},
},
{
text: "一年后",
onClick(picker) {
picker.$emit("pick", moment().add(1, "years").toDate());
},
},
],
},
},
attrs: {
placeholder: info.help_text,
},
style: {
width: "100%",
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
break;
case "datetime":
formItem = h(formBuilderMap(device).get(info.type), {
props: {
type: "datetime",
"value-format": "yyyy-MM-dd HH:mm:ss",
format: this.datetimeFormat,
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
"picker-options": {
shortcuts: this.shortcuts
},
},
style: {
width: "100%",
},
attrs: {
placeholder: info.help_text,
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
break;
case "select":
formItem = h(
formBuilderMap(device).get(info.type),
{
props: {
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
multiple: !!info.multiple,
'multiple-limit': info.multiple,
filterable: true,
'allow-create': !!info.is_select2_tag
},
style: {
width: "100%",
},
attrs: {
placeholder: info.help_text,
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
},
options.map((option) =>
h("el-option", {
props: {
label: typeof option === "object" ? option.name : option,
value: typeof option === "object" ? option.id : option,
},
})
)
);
break;
case "radio":
formItem = h(
formBuilderMap(device).get(info.type),
{
props: {
value: row ? row[info.name] : this.form[info.name],
},
attrs: {
placeholder: info.help_text,
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, 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,
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
})
} else {
this.$message.error("上传失败")
}
}).catch(err => {
window.$_uploading = false
})
}
}
}
) :
h(
formBuilderMap(device).get(info.type),
{
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]?.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;
}
});
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(
formBuilderMap(device).get(info.type),
{
props: {
type: "primary",
},
},
info.label
);
break;
case "static":
formItem = h(
formBuilderMap(device).get(info.type),
{
props: {
type: "primary",
},
attrs: {
href: row ? row[info.name] : this.form[info.name],
target: "_blank",
},
},
info.label
);
break;
case "hr":
formItem = h(formBuilderMap(device).get(info.type), {}, info.label);
break;
case "choice":
formItem = h(
formBuilderMap(device).get(info.type),
{
props: {
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
multiple: !!info.multiple,
'multiple-limit': info.multiple,
filterable: true
},
attrs: {
placeholder: info.help_text,
},
style: {
width: "100%",
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
},
options.map((option) =>
h("el-option", {
props: {
label: typeof option === "object" ? option.name : option,
value: typeof option === "object" ? option.id : option,
},
})
)
);
break;
case "choices":
formItem = h(
formBuilderMap(device).get(info.type),
{
props: {
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
multiple: true,
filterable: true
},
attrs: {
placeholder: info.help_text,
},
style: {
width: '100%'
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
},
options.map((option) =>
h("el-option", {
props: {
label: option,
value: option,
},
})
)
);
break;
case "relation-flow":
if (!this.flows[info.name]) {
flowList('all', {
page: 1,
page_size: 9999,
is_simple: 1,
custom_model_id: info.stub
}).then(res => {
this.$set(this.flows, info.name, res.data.data)
})
}
formItem = h(
formBuilderMap(device).get(info.type),
{
props: {
value: row ? (row[info.name] ? row[info.name].toString()?.split(',').map(i => Number(i)) : []) : (this.form[info.name] ? this.form[info.name].toString()?.split(',').map(i => Number(i)) : []),
clearable: true,
placeholder: info.help_text,
multiple: true,
filterable: true,
'reserve-keyword': true,
loading: this.flowSelectLoading
},
attrs: {
placeholder: info.help_text,
},
style: {
width: '100%'
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e.toString())
: this.$set(this.form, info.name, e.toString());
}
},
},
this.flows[info.name]?.map((option) =>
h("el-option", {
props: {
label: option.title,
value: option.id,
},
})
)
);
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,
);
},
[subField.type === 'file' ? 'default' : false]: ({ row: myrow }) => {
return formBuilder.bind(this)(
device,
subField,
h,
myrow,
info._writeable,
true,
);
}
},
})
),
]
);
break;
}
} else if (info._readable || pReadable) {
switch (info.type) {
case "date":
formItem = h(
"span",
{
style: {
color: "#333",
},
},
this.form[info.name] ? moment(this.form[info.name]).format("YYYY年MM月DD日") : ''
);
break;
case "datetime":
formItem = h(
"span",
{
style: {
color: "#333",
},
},
this.form[info.name] ? moment(this.form[info.name]).format("YYYY年MM月DD日 HH时mm分") : ''
);
break;
case "select":
let findValue = options.find((i) =>
typeof i === "object"
? i.id == this.form[info.name]
: i === this.form[info.name]
);
formItem = h(
"span",
{
style: {
color: "#333",
},
},
info.multiple ? this.form[info.name]?.toString()?.split('|')?.map(j => {
return options.find((i) =>
typeof i === "object"
? i.id == j
: i === j
)?.name;
})?.toString() : typeof findValue === "object" ? findValue.name : findValue
);
break;
case "choice":
formItem = h(
"span",
{
style: {
color: "#333",
},
},
this.form[info.name]?.toString()?.split('|').map(j => {
return options.find((i) => i.id == j)?.name;
})?.toString()
);
break;
case "choices":
let findChoicesValue = options.find((i) =>
typeof i === "object"
? i.id == this.form[info.name]
: i === this.form[info.name]
);
formItem = h(
"span",
{
style: {
color: "#333",
},
},
info.multiple ? this.form[info.name]?.toString()?.split('|').map(j => {
return options.find((i) =>
typeof i === "object"
? i.id == j
: i === j
)?.name;
})?.toString() : typeof findChoicesValue === "object" ? findChoicesValue.name : findChoicesValue
);
break;
case "relation-flow":
if (!this.flows[info.name]) {
flowList('all', {
page: 1,
page_size: 9999,
is_simple: 1,
custom_model_id: info.stub
}).then(res => {
this.$set(this.flows, info.name, res.data.data)
})
}
formItem = h(
"span",
{
style: {
color: "#333",
},
},
this.form[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(
formBuilderMap(device).get(info.type),
{
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",
},
},
this.form[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
jointlySignContent.push(h('div',[
h('span', value.value),
h('br'),
info.is_sign ? 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
}
}) : '',
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",
{
props: {
prop: info.name,
label: info.label_show ? info.label : '',
'label-width': !info.label_show ? '0': '',
},
style: {
"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 ? [(/\/detail/.test(this.$route.path) && this.$route.query.flow_id && jointlySignContent.length > 0) ? '' : formItem,(() => {
if (info.is_sign && !(/\/detail/.test(this.$route.path && this.$route.query.flow_id && jointlySignContent.length > 0))) {
let log = this.logs.find(log => log.node?.fields?.findIndex(field => field?.field?.name === info.name) !== -1) && (row ? row[info.name] : this.form[info.name])
if (log && log.user) {
return h('div',[
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('div', this.$moment(log.updated_at).format('YYYY年MM月DD日 HH时mm分'))
])
}
}
})(),jointlySignContent] : [formItem,(() => {
if (info.is_sign) {
let log = this.logs.find(log => log.node?.fields?.findIndex(field => field?.field?.name === info.name) !== -1 && (row ? row[info.name] : this.form[info.name]))
if (log && log.user) {
return h('div',[
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('div', this.$moment(log.updated_at).format('YYYY年MM月DD日 HH时mm分'))
])
}
}
})()]
);
}
}
if (device === "mobile") {
if (info._writeable || pWrite) {
let myRules = []
if (row && this.subRules && this.subRules[`${pname}_rules`] && this.subRules[`${pname}_rules`][info.name]) {
myRules = this.subRules[`${pname}_rules`][info.name]
} else {
myRules = this.rules[info.name]
}
switch (info.type) {
case "text":
formItem = h(formBuilderMap(device).get(info.type), {
props: {
name: info.name,
label: info.label,
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
rules: myRules.map(rule => {
if (rule.hasOwnProperty('required')) {
return rule
} else if (rule.hasOwnProperty('pattern')) {
return {
pattern: rule.pattern,
message: rule.message
}
} else {
return rule
}
}),
required: !!myRules?.find(j => j.required)
},
attrs: {
placeholder: info.help_text,
for: info.name
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
break;
case "textarea":
formItem = h(formBuilderMap(device).get(info.type), {
props: {
name: info.name,
label: info.label,
type: "textarea",
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
rules: this.rules[info.name],
required: !!myRules?.find(j => j.required)
},
attrs: {
placeholder: info.help_text,
for: info.name
},
on: {
input: (e) => {
row
? this.$set(row, info.name, e)
: this.$set(this.form, info.name, e);
},
},
});
break;
case "date":
formItem = h("van-field", {
props: {
readonly: true,
clickable: true,
name: info.name,
label: info.label,
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
rules: this.rules[info.name],
required: !!myRules?.find(j => j.required)
},
attrs: {
placeholder: info.help_text,
for: info.name
},
on: {
click: (_) => {
this.vanCalendarOption.forFormName = info.name;
this.vanCalendarOption.originalObj = row;
this.vanCalendarOption.isShow = true;
},
},
});
break;
case "datetime":
formItem = h("van-field", {
props: {
readonly: true,
clickable: true,
name: info.name,
label: info.label,
value: row ? row[info.name] : this.form[info.name],
clearable: true,
placeholder: info.help_text,
rules: this.rules[info.name],
required: !!myRules?.find(j => j.required)
},
attrs: {
for: info.name
},
on: {
click: (_) => {
this.vanTimePickerOption.forFormName = info.name;
this.vanTimePickerOption.originalObj = row;
this.vanTimePickerOption.isShow = true
},
},
});
break;
case "select":
let findSelect = options?.find((i) =>
typeof i === "object"
? i.id === (row ? row[info.name] : this.form[info.name])
: i === (row ? row[info.name] : this.form[info.name])
);
formItem = h("van-field", {
props: {
readonly: true,
clickable: true,
name: info.name,
label: info.label,
value: typeof findSelect === "object" ? findSelect.name : findSelect,
clearable: true,
placeholder: info.help_text,
rules: this.rules[info.name],
required: !!myRules?.find(j => j.required)
},
attrs: {
for: info.name
},
on: {
click: (_) => {
this.vanPopupOption.forFormName = info.name;
this.vanPopupOption.originalObj = row;
this.$set(this.vanPopupOption, "columns", options);
this.vanPopupOption.isShow = true;
},
},
});
break;
case "choice":
let findChoice = info.multiple ? options?.filter((i) =>
typeof i === "object"
? (row ? row[info.name].indexOf(i.id) !== -1 : this.form[info.name].indexOf(i.id) !== -1)
: i === (row ? row[info.name] : this.form[info.name])
) : options?.find((i) =>
typeof i === "object"
? i.id === (row ? row[info.name] : this.form[info.name])
: i === (row ? row[info.name] : this.form[info.name])
);
formItem = h("van-field", {
props: {
readonly: true,
clickable: true,
name: info.name,
label: info.label,
value: (findChoice instanceof Array) ? (findChoice.map(i => typeof i === "object" ? i.name : i).toString()) : (typeof findChoice === "object" ? findChoice.name : findChoice),
clearable: true,
placeholder: info.help_text,
rules: this.rules[info.name],
required: !!myRules?.find(j => j.required)
},
attrs: {
for: info.name
},
on: {
click: (_) => {
this.multipleSelectOption.forFormName = info.name;
this.multipleSelectOption.originalObj = row;
this.multipleSelectOption.outputType = 'array';
this.$set(this.multipleSelectOption, "columns", options);
this.$set(this.multipleSelectOption, "options", {
label: 'name',
value: 'id'
});
this.$set(this.multipleSelectOption, "multipleLimit", info.multiple);
this.multipleSelectOption.isShow = true;
},
},
});
break;
case "file":
formItem = h('van-cell',{
props: {
title: info.label,
rules: this.rules[info.name],
required: !!myRules?.find(j => j.required)
},
attrs: {
for: info.name
},
},[
h(
formBuilderMap(device).get(info.type),
{
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,
fileList: row ? row[info.name]?.map(i => {
if (i.hasOwnProperty('original_name')) {
i.name = i.original_name
}
return i
}) : 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;
}
});
row ? row[info.name] = fileList : this.form[info.name] = fileList;
},
onRemove: (file, fileList) => {
row ? row[info.name] = fileList : this.form[info.name] = fileList;
},
onError: (err, file, fileList) => {
window.$_uploading = false
row ? row[info.name] = fileList : 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.name
),
]),
h("i", {
class: "el-icon-close",
on: {
["click"]: () => {
this.$set(
this.file,
info.field,
this.file[info.field].filter(
(item) => item !== file
)
);
},
},
}),
];
},
},
},
[
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]) {
flowList('all', {
page: 1,
page_size: 9999,
is_simple: 1,
custom_model_id: info.stub
}).then(res => {
this.$set(this.flows, info.name, res.data.data)
})
}
formItem = h("van-field", {
props: {
readonly: true,
clickable: true,
name: info.name,
label: info.label,
value: row ? row[info.name]?.toString()?.split(',').map(j => {
return this.flows[info.name]?.find((i) =>
i.id == j
)?.title;
})?.toString() : this.form[info.name]?.toString()?.split(',').map(j => {
return this.flows[info.name]?.find((i) =>
i.id == j
)?.title;
})?.toString(),
clearable: true,
placeholder: info.help_text,
rules: this.rules[info.name],
required: !!myRules?.find(j => j.required)
},
attrs: {
for: info.name
},
on: {
click: (_) => {
this.multipleSelectOption.forFormName = info.name;
this.multipleSelectOption.originalObj = row;
this.multipleSelectOption.outputType = 'string';
this.$set(this.multipleSelectOption, "columns", this.flows[info.name]);
this.$set(this.multipleSelectOption, "options", {
label: 'title',
value: 'id'
});
this.$set(this.multipleSelectOption, "multipleLimit", info.multiple);
this.multipleSelectOption.isShow = true
},
},
});
break;
case "relation":
let copySubForm = deepCopy(this.form[info.name][0])
formItem = h("div", [
h("van-cell", {
props: {
"arrow-direction": "down",
title: info.label,
},
attrs: {
for: info.name
}
},[
h('van-button',{
props: {
color: 'var(--theme-color)',
icon: 'plus',
size: 'small'
},
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-group",
{
props: {
inset: false
}
},
[
h("van-cell", {
props: {
title: info.label + "-" + (sIndex + 1)
}
},[
h('van-button',{
props: {
size: 'mini',
type: 'danger',
icon: 'minus'
},
on: {
click: _ => {
this.form[info.name].splice(sIndex, 1)
}
}
},'删除')
]),
h(
"van-form",
{
ref: "subVanForm-"+sIndex,
props: {
"scroll-to-error": true,
},
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,
null,
info.name
)
)
),
]
)
) : ''
),
]);
break;
}
} else if(info._readable || pReadable) {
switch (info.type) {
case "date":
formItem = h(
"van-cell",
{
attrs: {
for: info.name
},
props: {
title: info.label,
value: this.form[info.name] ? moment(this.form[info.name]).format("YYYY年MM月DD日") : ''
}
}
);
break;
case "datetime":
formItem = h(
"van-cell",
{
attrs: {
for: info.name
},
props: {
title: info.label,
value: this.form[info.name] ? moment(this.form[info.name]).format("YYYY年MM月DD日 HH时mm分ss秒") : ''
}
},
);
break;
case "select":
let findSelect = options.find((i) =>
typeof i === "object"
? i.id === this.form[info.name]
: i === this.form[info.name]
);
formItem = h(
"van-cell",
{
attrs: {
for: info.name
},
props: {
title: info.label,
value: typeof findSelect === "object" ? findSelect.name : findSelect
}
},
);
break;
case 'choice':
let findChoice = options.find((i) =>
typeof i === "object"
? i.id === this.form[info.name]
: i === this.form[info.name]
);
formItem = h(
"van-cell",
{
attrs: {
for: info.name
},
props: {
title: info.label,
value: typeof findChoice === "object" ? findChoice.name : findChoice
}
},
);
break;
case 'file':
let files = (row ? row[info.name] : this.form[info.name])
formItem = h(
"van-cell",
{
attrs: {
for: info.name
},
props: {
title: info.label,
}
},
((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: {
"arrow-direction": "down",
title: info.label,
},
}),
h(
"div",
this.form[info.name] instanceof Array ? this.form[info.name]?.map((sForm, sIndex) =>
h(
"van-cell-group",
{
props: {
inset: false
}
},
[
h("van-cell", {
props: {
title: info.label + "-" + (sIndex + 1)
}
}),
h(
"van-form",
{
ref: "subVanForm",
props: {
"scroll-to-error": true,
},
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]) {
flowList('all', {
page: 1,
page_size: 9999,
is_simple: 1,
custom_model_id: info.stub
}).then(res => {
this.$set(this.flows, info.name, res.data.data)
})
}
formItem = h(
"van-cell",
{
attrs: {
for: info.name
},
props: {
title: info.label
}
},
this.form[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-cell',{
attrs: {
for: info.name
},
props: {
title: info.label,
value: row ? row[info.name] : this.form[info.name]
}
})
}
}
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
jointlySignContent.push(h('div',[
h('span', value.value),
h('br'),
info.is_sign ? 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
}
}) : '',
info.is_sign ? h('br') : '',
h('span', log.updated_at ? this.$moment(log.updated_at).format('YYYY年MM月DD') : '')
]))
}
})
})
return isJointly ? [(/\/detail/.test(this.$route.path) && this.$route.query.flow_id && jointlySignContent.length > 0) ? '' : formItem,(() => {
if (info.is_sign && !(/\/detail/.test(this.$route.path && this.$route.query.flow_id && jointlySignContent.length > 0))) {
let log = this.logs.find(log => log.node?.fields?.findIndex(field => field?.field?.name === info.name) !== -1) && (row ? row[info.name] : this.form[info.name])
if (log && log.user) {
return h('van-cell',[
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('div', this.$moment(log.updated_at).format('YYYY年MM月DD日 HH时mm分'))
])
}
}
})(),jointlySignContent] : [formItem,(() => {
if (info.is_sign) {
let log = this.logs.find(log => log.node?.fields?.findIndex(field => field?.field?.name === info.name) !== -1 && (row ? row[info.name] : this.form[info.name]))
if (log && log.user) {
return h('van-cell',[
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('div', this.$moment(log.updated_at).format('YYYY年MM月DD日 HH时mm分'))
])
}
}
})()]
}
}