|
|
import formBuilderMap from "./formBuilderMap";
|
|
|
import { CreateElement, VNode } from "vue";
|
|
|
import moment from "moment";
|
|
|
import { getToken } from "@/utils/auth";
|
|
|
import { deepCopy } from "@/utils/index";
|
|
|
/**
|
|
|
* @param {String} device 'desktop' or '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) {
|
|
|
let formItem;
|
|
|
//下拉选项
|
|
|
if (info?.selection_model) {
|
|
|
options = info.selection_model_items;
|
|
|
} else if (info?.stub) {
|
|
|
options = info?.stub?.split(/\n/) || [];
|
|
|
}
|
|
|
let options;
|
|
|
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",
|
|
|
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());
|
|
|
},
|
|
|
},
|
|
|
],
|
|
|
},
|
|
|
},
|
|
|
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,
|
|
|
},
|
|
|
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 = 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: true,
|
|
|
fileList: this.file[info.name],
|
|
|
beforeUpload: (file) => {
|
|
|
if (file.size / 1024 / 1024 > 20) {
|
|
|
this.$message({
|
|
|
type: "warning",
|
|
|
message: "上传图片大小超过20Mb!",
|
|
|
});
|
|
|
return false;
|
|
|
}
|
|
|
},
|
|
|
onSuccess: (response, file, fileList) => {
|
|
|
fileList.forEach((file) => {
|
|
|
if (file.response?.data && !file.response?.code) {
|
|
|
file.response = file.response.data;
|
|
|
}
|
|
|
});
|
|
|
this.file[info.name] = fileList;
|
|
|
},
|
|
|
onRemove: (file, fileList) => {
|
|
|
this.file[info.name] = fileList;
|
|
|
},
|
|
|
onError: (err, file, fileList) => {
|
|
|
this.file[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",
|
|
|
{
|
|
|
attrs: {
|
|
|
href: file.url,
|
|
|
download: file.name,
|
|
|
},
|
|
|
class: {
|
|
|
"uploaded-a": file.status === "success",
|
|
|
},
|
|
|
style: {
|
|
|
padding: "0 4px",
|
|
|
},
|
|
|
},
|
|
|
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: "small",
|
|
|
type: "primary",
|
|
|
},
|
|
|
},
|
|
|
"选取文件"
|
|
|
),
|
|
|
h(
|
|
|
"div",
|
|
|
{
|
|
|
class: "el-upload__tip",
|
|
|
slot: "tip",
|
|
|
},
|
|
|
"文件不超过20Mb"
|
|
|
),
|
|
|
]
|
|
|
);
|
|
|
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,
|
|
|
},
|
|
|
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,
|
|
|
},
|
|
|
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":
|
|
|
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],
|
|
|
"keep-source": true,
|
|
|
"column-config": { resizable: true },
|
|
|
"show-overflow": true,
|
|
|
"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);
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
[
|
|
|
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 = {};
|
|
|
const { row: newRow } = await $table.insert(
|
|
|
record
|
|
|
);
|
|
|
await this.$nextTick();
|
|
|
await $table.setEditRow(newRow);
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
}),
|
|
|
]
|
|
|
)
|
|
|
: "",
|
|
|
...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",
|
|
|
"edit-render": {},
|
|
|
},
|
|
|
scopedSlots: {
|
|
|
edit: ({ row }) => {
|
|
|
return formBuilder.bind(this)(
|
|
|
device,
|
|
|
subField,
|
|
|
h,
|
|
|
row,
|
|
|
info._writeable,
|
|
|
info._readable,
|
|
|
);
|
|
|
},
|
|
|
},
|
|
|
})
|
|
|
),
|
|
|
]
|
|
|
);
|
|
|
break;
|
|
|
}
|
|
|
} else if (info._readable) {
|
|
|
switch (info.type) {
|
|
|
case "date":
|
|
|
formItem = h(
|
|
|
"span",
|
|
|
{
|
|
|
style: {
|
|
|
color: "#333",
|
|
|
},
|
|
|
},
|
|
|
moment(this.form[info.name]).format("YYYY年MM月DD日")
|
|
|
);
|
|
|
break;
|
|
|
case "datetime":
|
|
|
formItem = h(
|
|
|
"span",
|
|
|
{
|
|
|
style: {
|
|
|
color: "#333",
|
|
|
},
|
|
|
},
|
|
|
moment(this.form[info.name]).format("YYYY年MM月DD日 HH时mm分ss秒")
|
|
|
);
|
|
|
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",
|
|
|
},
|
|
|
},
|
|
|
typeof findValue === "object" ? findValue.name : findValue
|
|
|
);
|
|
|
break;
|
|
|
case "file":
|
|
|
formItem = 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.file[info.name],
|
|
|
},
|
|
|
scopedSlots: {
|
|
|
file: (scope) => {
|
|
|
let { file } = scope;
|
|
|
return [
|
|
|
h("div", {}, [
|
|
|
h("i", {
|
|
|
class: "el-icon-circle-check",
|
|
|
style: {
|
|
|
color: "green",
|
|
|
},
|
|
|
}),
|
|
|
h(
|
|
|
"a",
|
|
|
{
|
|
|
attrs: {
|
|
|
href: file.url,
|
|
|
download: file.name,
|
|
|
},
|
|
|
class: {
|
|
|
"uploaded-a": file.status === "success",
|
|
|
},
|
|
|
style: {
|
|
|
padding: "0 4px",
|
|
|
},
|
|
|
},
|
|
|
file.name
|
|
|
),
|
|
|
]),
|
|
|
];
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
[
|
|
|
h(
|
|
|
"span",
|
|
|
{
|
|
|
slot: "trigger",
|
|
|
},
|
|
|
`数量:${this.file[info.name].length}`
|
|
|
),
|
|
|
]
|
|
|
);
|
|
|
break;
|
|
|
default:
|
|
|
formItem = h(
|
|
|
"span",
|
|
|
{
|
|
|
style: {
|
|
|
color: "#333",
|
|
|
},
|
|
|
},
|
|
|
this.form[info.name]
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (formItem) {
|
|
|
return row
|
|
|
? formItem
|
|
|
: h(
|
|
|
"el-form-item",
|
|
|
{
|
|
|
props: {
|
|
|
prop: info.name,
|
|
|
label: info.label,
|
|
|
},
|
|
|
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,
|
|
|
"grid-row-end": info.gs_y + 1 + info.gs_height,
|
|
|
},
|
|
|
},
|
|
|
[formItem]
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
if (device === "mobile") {
|
|
|
if (info._writeable || pWrite) {
|
|
|
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,
|
|
|
},
|
|
|
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: {
|
|
|
name: info.name,
|
|
|
label: info.label,
|
|
|
type: "textarea",
|
|
|
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("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,
|
|
|
},
|
|
|
attrs: {
|
|
|
placeholder: info.help_text,
|
|
|
},
|
|
|
on: {
|
|
|
click: (_) => {
|
|
|
this.vanCalendarOption.forFormName = info.name;
|
|
|
this.vanCalendarOption.originalObj = row;
|
|
|
this.$set(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,
|
|
|
},
|
|
|
on: {
|
|
|
click: (_) => {
|
|
|
this.vanTimePickerOption.forFormName = info.name;
|
|
|
this.vanTimePickerOption.originalObj = row;
|
|
|
this.$set(this.vanTimePickerOption, "isShow", true);
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
break;
|
|
|
case "select":
|
|
|
let findValue = 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 findValue === "object" ? findValue.name : findValue,
|
|
|
clearable: true,
|
|
|
placeholder: info.help_text,
|
|
|
},
|
|
|
on: {
|
|
|
click: (_) => {
|
|
|
this.vanPopupOption.forFormName = info.name;
|
|
|
this.vanPopupOption.originalObj = row;
|
|
|
this.$set(this.vanPopupOption, "columns", options);
|
|
|
this.$set(this.vanPopupOption, "isShow", true);
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
break;
|
|
|
case "file":
|
|
|
formItem = h('van-cell',{
|
|
|
props: {
|
|
|
title: info.label,
|
|
|
}
|
|
|
},[
|
|
|
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: true,
|
|
|
fileList: this.file[info.name],
|
|
|
beforeUpload: (file) => {
|
|
|
if (file.size / 1024 / 1024 > 20) {
|
|
|
this.$message({
|
|
|
type: "warning",
|
|
|
message: "上传图片大小超过20Mb!",
|
|
|
});
|
|
|
return false;
|
|
|
}
|
|
|
},
|
|
|
onSuccess: (response, file, fileList) => {
|
|
|
fileList.forEach((file) => {
|
|
|
if (file.response?.data && !file.response?.code) {
|
|
|
file.response = file.response.data;
|
|
|
}
|
|
|
});
|
|
|
this.file[info.name] = fileList;
|
|
|
},
|
|
|
onRemove: (file, fileList) => {
|
|
|
this.file[info.name] = fileList;
|
|
|
},
|
|
|
onError: (err, file, fileList) => {
|
|
|
this.file[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",
|
|
|
{
|
|
|
attrs: {
|
|
|
href: file.url,
|
|
|
download: file.name,
|
|
|
},
|
|
|
class: {
|
|
|
"uploaded-a": file.status === "success",
|
|
|
},
|
|
|
style: {
|
|
|
padding: "0 4px",
|
|
|
},
|
|
|
},
|
|
|
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",
|
|
|
},
|
|
|
"文件不超过20Mb"
|
|
|
),
|
|
|
]
|
|
|
)
|
|
|
])
|
|
|
break;
|
|
|
case "relation":
|
|
|
let copySubForm = deepCopy(this.form[info.name][0])
|
|
|
formItem = h("div", [
|
|
|
h("van-cell", {
|
|
|
props: {
|
|
|
"arrow-direction": "down",
|
|
|
title: info.label,
|
|
|
},
|
|
|
},[
|
|
|
h('van-button',{
|
|
|
props: {
|
|
|
type: 'info',
|
|
|
icon: 'plus',
|
|
|
size: 'small'
|
|
|
},
|
|
|
on: {
|
|
|
'click':_ => {
|
|
|
this.form[info.name].push(copySubForm)
|
|
|
}
|
|
|
}
|
|
|
},'新增')
|
|
|
]),
|
|
|
h(
|
|
|
"div",
|
|
|
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",
|
|
|
{
|
|
|
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,
|
|
|
)
|
|
|
)
|
|
|
),
|
|
|
]
|
|
|
)
|
|
|
)
|
|
|
),
|
|
|
]);
|
|
|
break;
|
|
|
}
|
|
|
} else if(info._readable || pReadable) {
|
|
|
switch (info.type) {
|
|
|
case "date":
|
|
|
formItem = h(
|
|
|
"van-cell",
|
|
|
{
|
|
|
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",
|
|
|
{
|
|
|
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 findValue = options.find((i) =>
|
|
|
typeof i === "object"
|
|
|
? i.id === this.form[info.name]
|
|
|
: i === this.form[info.name]
|
|
|
);
|
|
|
formItem = h(
|
|
|
"van-cell",
|
|
|
{
|
|
|
props: {
|
|
|
title: info.label,
|
|
|
value: typeof findValue === "object" ? findValue.name : findValue
|
|
|
}
|
|
|
},
|
|
|
);
|
|
|
break;
|
|
|
case 'file':
|
|
|
formItem = h(
|
|
|
"van-cell",
|
|
|
{
|
|
|
props: {
|
|
|
title: info.label,
|
|
|
}
|
|
|
},
|
|
|
this.file[info.name].map(file => h("div", {}, [
|
|
|
h(
|
|
|
"a",
|
|
|
{
|
|
|
attrs: {
|
|
|
href: file.url,
|
|
|
download: file.name,
|
|
|
},
|
|
|
class: {
|
|
|
"uploaded-a": file.status === "success",
|
|
|
},
|
|
|
style: {
|
|
|
padding: "0 4px",
|
|
|
},
|
|
|
},
|
|
|
file.name
|
|
|
),
|
|
|
]))
|
|
|
);
|
|
|
break
|
|
|
case 'relation':
|
|
|
formItem = h("div", [
|
|
|
h("van-cell", {
|
|
|
props: {
|
|
|
"arrow-direction": "down",
|
|
|
title: info.label,
|
|
|
},
|
|
|
}),
|
|
|
h(
|
|
|
"div",
|
|
|
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",
|
|
|
{
|
|
|
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;
|
|
|
default:
|
|
|
formItem = h('van-cell',{
|
|
|
props: {
|
|
|
title: info.label,
|
|
|
value: row ? row[info.name] : this.form[info.name]
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
return formItem;
|
|
|
}
|
|
|
}
|