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.

1946 lines
66 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 { 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日"
)
),
]);
}
}
})(),
]
);
}
}
}