From 3ca29b6aa1ae94a1096646b54c4ef54bc3f0b0cc Mon Sep 17 00:00:00 2001 From: xy <271556543@qq.com> Date: Thu, 19 Sep 2024 18:01:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=81=E8=BD=AC=EF=BC=8C=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/flow/index.js | 55 +- src/icons/svg/fav.svg | 1 + src/icons/svg/flow-through-me.svg | 1 + src/icons/svg/todo.svg | 1 + src/router/index.js | 25 +- src/utils/formBuilder.js | 1188 +++++++++++++++----------- src/views/flow/DesktopForm.vue | 12 +- src/views/flow/MobileForm.vue | 3 +- src/views/flow/components/assign.vue | 71 +- src/views/flow/create.vue | 338 ++++++-- src/views/flow/list.vue | 212 ++++- src/views/login/index.vue | 10 +- 12 files changed, 1309 insertions(+), 608 deletions(-) create mode 100644 src/icons/svg/fav.svg create mode 100644 src/icons/svg/flow-through-me.svg create mode 100644 src/icons/svg/todo.svg diff --git a/src/api/flow/index.js b/src/api/flow/index.js index a360dfc..86dc43f 100644 --- a/src/api/flow/index.js +++ b/src/api/flow/index.js @@ -1,4 +1,5 @@ import request from '@/utils/request' +import { MessageBox } from 'element-ui' import qs from 'qs' export function flow(isLoading=false) { return request({ @@ -24,7 +25,7 @@ export function fieldConfig(custom_model_id,isLoading=false) { }) } -export function create(data,custom_model_id) { +export function create(custom_model_id, data) { return request({ method: 'post', url: `/api/oa/flow/create/${custom_model_id}`, @@ -45,7 +46,7 @@ export function preDeal(flow_id,params,isLoading=false) { }) } -export function deal(data,flow_id) { +export function deal(flow_id,data) { return request({ method: 'post', url: `/api/oa/flow/deal/${flow_id}`, @@ -76,6 +77,7 @@ export function flowList(type,params,isLoading = false) { return request({ method: 'get', url: `/api/oa/flow/list/${type}`, + params, isLoading }) } @@ -88,3 +90,52 @@ export function assign(flow_id, data) { data }) } + +//详情 +export function view(flow_id) { + return request({ + method: 'get', + url: `/api/oa/flow/view/${flow_id}`, + }) +} + +export function preShare(flow_id, params,isLoading = true) { + return request({ + method: 'get', + url: `/api/oa/flow/share-pre/${flow_id}`, + params, + isLoading + }) +} + +//收藏 +export function toggleFav(data,isLoading=true) { + return request({ + method: 'post', + url: '/api/oa/flow/toggle-fav', + data, + isLoading + }) +} + +//撤回 +export async function recall(data,isLoading=true) { + await MessageBox.confirm("确认撤回?","提示") + return request({ + method: 'post', + url: '/api/oa/flow/recall', + data, + isLoading + }) +} + +//删除 +export async function destroy(data,isLoading=true) { + await MessageBox.confirm("确认删除?","提示") + return request({ + method: 'post', + url: '/api/oa/flow/delete', + data, + isLoading + }) +} diff --git a/src/icons/svg/fav.svg b/src/icons/svg/fav.svg new file mode 100644 index 0000000..69007aa --- /dev/null +++ b/src/icons/svg/fav.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/flow-through-me.svg b/src/icons/svg/flow-through-me.svg new file mode 100644 index 0000000..a7290f9 --- /dev/null +++ b/src/icons/svg/flow-through-me.svg @@ -0,0 +1 @@ + diff --git a/src/icons/svg/todo.svg b/src/icons/svg/todo.svg new file mode 100644 index 0000000..bf0136f --- /dev/null +++ b/src/icons/svg/todo.svg @@ -0,0 +1 @@ + diff --git a/src/router/index.js b/src/router/index.js index 60c2a92..f15b501 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -66,15 +66,36 @@ export const constantRoutes = [ component: () => import('@/views/flow/index.vue'), meta: { title: '流程创建', icon: 'tree' } },{ - path: '/list', + path: 'list/:type', name: 'flowList', + hidden: true, component: () => import('@/views/flow/list.vue'), - meta: { title: '流程监管', icon: 'table', type: 'created-by-me' } + },{ + path: 'list/created-by-me', + name: 'flowList', + meta: { title: '流程监管', icon: 'table' } + },{ + path: 'list/fav', + name: 'flowList', + meta: { title: '我收藏的', icon: 'fav' } + },{ + path: 'list/todo', + name: 'flowList', + meta: { title: '待办流程', icon: 'todo' } + },{ + path: 'list/handled', + name: 'flowList', + meta: { title: '办理过的', icon: 'flow-through-me' } },{ path: 'create', name: 'create', component: () => import('@/views/flow/create'), hidden: true + },{ + path: 'detail', + name: 'detail', + component: () => import('@/views/flow/create'), + hidden: true }] } diff --git a/src/utils/formBuilder.js b/src/utils/formBuilder.js index 0a046b4..755d89b 100644 --- a/src/utils/formBuilder.js +++ b/src/utils/formBuilder.js @@ -1,6 +1,6 @@ -import formBuilderMap from './formBuilderMap' -import { CreateElement, VNode } from 'vue' -import moment from 'moment' +import formBuilderMap from "./formBuilderMap"; +import { CreateElement, VNode } from "vue"; +import moment from "moment"; import { getToken } from "@/utils/auth"; import { deepCopy } from "@/utils/index"; /** @@ -10,594 +10,797 @@ import { deepCopy } from "@/utils/index"; * @param {Object} row 子表单的row * @param {Boolean} pWrite 主表单中子表单字段是否可写 * @return {VNode} 主表单包含el-form-item 子表单表单组件 -**/ -export default function formBuilder (device, info, h, row, pWrite=false) { + **/ +export default function formBuilder(device, info, h, row, pWrite = false) { let formItem; //下拉选项 - if(info?.stub) { - options = info?.stub?.split('|') || [] + if (info?.stub) { + options = info?.stub?.split("|") || []; } else if (info?.selection_model) { - options = info.selection_model_items + options = info.selection_model_items; } let options; - if (device === 'desktop') { - if(info._writeable || (info.type === 'relation' && info._readable) || pWrite) { + if (device === "desktop") { + // 可写并且不为查看和子表单下 + if ( + info._writeable || + (info.type === "relation" && info._readable) || + pWrite + ) { switch (info.type) { - case 'text': - formItem = h(formBuilderMap(device).get(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 + placeholder: info.help_text, }, attrs: { - placeholder: info.help_text + placeholder: info.help_text, }, on: { - input: e => { - row ? this.$set(row,info.name,e) : this.$set(this.form,info.name,e) - } - } - }) + 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),{ + case "textarea": + formItem = h(formBuilderMap(device).get(info.type), { props: { - type: 'textarea', + type: "textarea", autosize: { - minRows: 2 + minRows: 2, }, value: row ? row[info.name] : this.form[info.name], clearable: true, - placeholder: info.help_text + placeholder: info.help_text, }, attrs: { - placeholder: info.help_text + placeholder: info.help_text, }, on: { - input: e => { - row ? this.$set(row,info.name,e) : this.$set(this.form,info.name,e) - } - } - }) + 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),{ + case "date": + formItem = h(formBuilderMap(device).get(info.type), { props: { - type: 'date', - 'value-format': 'yyyy-MM-dd', - format: 'yyyy年MM月dd日', + 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': { + "picker-options": { shortcuts: [ { - text: '一年前', + text: "一年前", onClick(picker) { - picker.$emit('pick', moment().subtract(1,'years').toDate()); - } + picker.$emit( + "pick", + moment().subtract(1, "years").toDate() + ); + }, }, { - text: '一月前', + text: "一月前", onClick(picker) { - picker.$emit('pick', moment().subtract(1,'months').toDate()); - } + picker.$emit( + "pick", + moment().subtract(1, "months").toDate() + ); + }, }, { - text: '一周前', + text: "一周前", onClick(picker) { - picker.$emit('pick', moment().subtract(1,'weeks').toDate()); - - } + picker.$emit( + "pick", + moment().subtract(1, "weeks").toDate() + ); + }, }, { - text: '今天', + text: "今天", onClick(picker) { - picker.$emit('pick', new Date()); - } + picker.$emit("pick", new Date()); + }, }, { - text: '一周后', + text: "一周后", onClick(picker) { - picker.$emit('pick', moment().add(1,'weeks').toDate()); - } + picker.$emit("pick", moment().add(1, "weeks").toDate()); + }, }, { - text: '一月后', + text: "一月后", onClick(picker) { - picker.$emit('pick', moment().add(1,'months').toDate()); - } + picker.$emit("pick", moment().add(1, "months").toDate()); + }, }, { - text: '一年后', + text: "一年后", onClick(picker) { - picker.$emit('pick', moment().add(1,'years').toDate()); - } + picker.$emit("pick", moment().add(1, "years").toDate()); + }, }, - ] - } + ], + }, }, attrs: { - placeholder: info.help_text + placeholder: info.help_text, }, style: { - width: '100%' + width: "100%", }, on: { - input: e => { - row ? this.$set(row,info.name,e) : this.$set(this.form,info.name,e) - } - } - }) + 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),{ + case "datetime": + formItem = h(formBuilderMap(device).get(info.type), { props: { - type: 'datetime', - 'value-format': 'yyyy-MM-dd', - format: 'yyyy年MM月dd日', + 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': { + "picker-options": { shortcuts: [ { - text: '一年前', + text: "一年前", onClick(picker) { - picker.$emit('pick', moment().subtract(1,'years').toDate()); - } + picker.$emit( + "pick", + moment().subtract(1, "years").toDate() + ); + }, }, { - text: '一月前', + text: "一月前", onClick(picker) { - picker.$emit('pick', moment().subtract(1,'months').toDate()); - } + picker.$emit( + "pick", + moment().subtract(1, "months").toDate() + ); + }, }, { - text: '一周前', + text: "一周前", onClick(picker) { - picker.$emit('pick', moment().subtract(1,'weeks').toDate()); - - } + picker.$emit( + "pick", + moment().subtract(1, "weeks").toDate() + ); + }, }, { - text: '今天', + text: "今天", onClick(picker) { - picker.$emit('pick', new Date()); - } + picker.$emit("pick", new Date()); + }, }, { - text: '一周后', + text: "一周后", onClick(picker) { - picker.$emit('pick', moment().add(1,'weeks').toDate()); - } + picker.$emit("pick", moment().add(1, "weeks").toDate()); + }, }, { - text: '一月后', + text: "一月后", onClick(picker) { - picker.$emit('pick', moment().add(1,'months').toDate()); - } + picker.$emit("pick", moment().add(1, "months").toDate()); + }, }, { - text: '一年后', + text: "一年后", onClick(picker) { - picker.$emit('pick', moment().add(1,'years').toDate()); - } + picker.$emit("pick", moment().add(1, "years").toDate()); + }, }, - ] - } + ], + }, }, style: { - width: '100%' + width: "100%", }, attrs: { - placeholder: info.help_text + 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 - }, - style: { - width: '100%' - }, - attrs: { - placeholder: info.help_text + input: (e) => { + row + ? this.$set(row, info.name, e) + : this.$set(this.form, info.name, e); + }, }, - 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 + 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, + }, + 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); + }, + }, }, - on: { - input: e => { - row ? this.$set(row,info.name,e) : this.$set(this.form,info.name,e) - } - } - },options.map(option => ( - h('el-radio',{ + 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: { - label: typeof option === 'object' ? option.id : option - } - },typeof option === 'object' ? option.name : option) - ))) + 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)) { + 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: "上传图片大小超过20Mb!", + message: err, }); - 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, - }, + scopedSlots: { + file: (scope) => { + let { file } = scope; + return [ + h("div", {}, [ + h("i", { class: { - "uploaded-a": - file.status === - "success", + "el-icon-circle-check": file.status === "success", + "el-icon-loading": file.status === "uploading", }, style: { - padding: "0 4px", + 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 + ) + ); }, }, - 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" - ) - ]) + }, + [ + 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) + 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' + case "static": + formItem = h( + formBuilderMap(device).get(info.type), + { + props: { + type: "primary", + }, + attrs: { + href: row ? row[info.name] : this.form[info.name], + target: "_blank", + }, }, - attrs: { - href: row ? row[info.name] : this.form[info.name], - target: "_blank" - } - },info.label) + info.label + ); break; - case 'hr': - formItem = h(formBuilderMap(device).get(info.type),{ - },info.label) + 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 - }, - 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',{ + case "choice": + formItem = h( + formBuilderMap(device).get(info.type), + { props: { - label: option, - value: 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 + 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); + }, + }, }, - 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 - } - }) - ))) + 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) - } - } - } - },[ - h('vxe-column',{ + case "choices": + formItem = h( + formBuilderMap(device).get(info.type), + { props: { - width: 56, - align: 'center' + value: row ? row[info.name] : this.form[info.name], + clearable: true, + placeholder: info.help_text, + multiple: true, }, - 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' + 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: { - type: 'primary', - size: 'small', - icon: "el-icon-plus" + label: option, + value: option, }, - 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) + }) + ) + ); + 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 + ); } - } - }), - ]), - ...this.subForm.get(info.sub_custom_model_id)?.customModel?.fields?.map((subField,subIndex) => h('vxe-column',{ + }, + }, + }, + [ + 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 + ); + }, + }, + }) + ), + ] + ); + 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: { - field: subField.name, - title: subField.label, - align: 'center', - 'edit-render': {} + 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: { - edit:({ row }) => { - return formBuilder.bind(this)(device, subField, h, row, info._writeable) - } - } - })) - ]) + 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] + ); } - } else if (info._readable) { - 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]) + 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) { + if (device === "mobile") { + if (info._writeable || pWrite) { switch (info.type) { - case 'text': - formItem = h(formBuilderMap(device).get(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 + placeholder: info.help_text, }, attrs: { - placeholder: info.help_text + placeholder: info.help_text, }, on: { - input: e => { - this.$set(this.form,info.name,e) - } - } - }) + input: (e) => { + this.$set(this.form, info.name, e); + }, + }, + }); break; - case 'textarea': - formItem = h(formBuilderMap(device).get(info.type),{ + case "textarea": + formItem = h(formBuilderMap(device).get(info.type), { props: { name: info.name, label: info.label, - type: 'textarea', + type: "textarea", value: row ? row[info.name] : this.form[info.name], clearable: true, - placeholder: info.help_text + placeholder: info.help_text, }, attrs: { - placeholder: info.help_text + placeholder: info.help_text, }, on: { - input: e => { - this.$set(this.form,info.name,e) - } - } - }) + input: (e) => { + this.$set(this.form, info.name, e); + }, + }, + }); break; - case 'date': - formItem = h('van-field',{ + case "date": + formItem = h("van-field", { props: { readonly: true, clickable: true, @@ -608,18 +811,18 @@ export default function formBuilder (device, info, h, row, pWrite=false) { placeholder: info.help_text, }, attrs: { - placeholder: info.help_text + placeholder: info.help_text, }, on: { - click: _ => { + click: (_) => { this.vanCalendarOption.forFormName = info.name; - this.$set(this.vanCalendarOption,'isShow',true); - } - } - }) + this.$set(this.vanCalendarOption, "isShow", true); + }, + }, + }); break; - case 'datetime': - formItem = h('van-field',{ + case "datetime": + formItem = h("van-field", { props: { readonly: true, clickable: true, @@ -630,15 +833,15 @@ export default function formBuilder (device, info, h, row, pWrite=false) { placeholder: info.help_text, }, on: { - click:_ => { + click: (_) => { this.vanTimePickerOption.forFormName = info.name; - this.$set(this.vanTimePickerOption,'isShow',true); - } - } - }) + this.$set(this.vanTimePickerOption, "isShow", true); + }, + }, + }); break; - case 'select': - formItem = h('van-field',{ + case "select": + formItem = h("van-field", { props: { readonly: true, clickable: true, @@ -649,32 +852,65 @@ export default function formBuilder (device, info, h, row, pWrite=false) { placeholder: info.help_text, }, on: { - click:_ => { + click: (_) => { this.vanPopupOption.forFormName = info.name; - this.$set(this.vanPopupOption,'columns',options); - this.$set(this.vanPopupOption,'isShow',true); - } - } - }) + this.$set(this.vanPopupOption, "columns", options); + this.$set(this.vanPopupOption, "isShow", true); + }, + }, + }); break; - case 'relation': - formItem = h('div',this.form[info.name].map((sForm,sIndex) => ( - h('van-cell',{ + case "relation": + formItem = h("div", [ + h("van-cell", { props: { - 'arrow-direction': 'down', - title: info.label - } - },[ - h('van-form',{ - props: { - 'scroll-to-error': true - } - },Array.from(this.subForm).map(i => i[1]?.customModel?.fields)?.flat().map(subField => formBuilder.bind(this)(device, subField, h, sForm, info._writeable))) - ]) - ))) + "arrow-direction": "down", + title: info.label, + }, + }), + h( + "div", + this.form[info.name].map((sForm, sIndex) => + h( + "van-cell", + { + props: { + "arrow-direction": "down", + title: info.label + "-" + (sIndex + 1), + "title-style": { + "margin-left": "10px", + }, + }, + }, + [ + h( + "van-form", + { + props: { + "scroll-to-error": true, + }, + }, + Array.from(this.subForm) + .map((i) => i[1]?.customModel?.fields) + ?.flat() + .map((subField) => + formBuilder.bind(this)( + device, + subField, + h, + sForm, + info._writeable + ) + ) + ), + ] + ) + ) + ), + ]); break; } - return formItem + return formItem; } } } diff --git a/src/views/flow/DesktopForm.vue b/src/views/flow/DesktopForm.vue index 08b992f..28db422 100644 --- a/src/views/flow/DesktopForm.vue +++ b/src/views/flow/DesktopForm.vue @@ -60,8 +60,12 @@ export default { originalForm(newVal) { this.form = deepCopy(newVal) }, - fileList(newVal) { - this.file = deepCopy(newVal) + fileList: { + handler:function(newVal) { + this.file = deepCopy(newVal) + }, + immediate: true, + deep: true }, scriptContent(newVal) { if(newVal) { @@ -77,7 +81,7 @@ export default { const authFields = this.fields.map(field => ({ ...field, _readable: this.readable.indexOf(field.id) !== -1, - _writeable: this.writeable.indexOf(field.id) !== -1 + _writeable: this.writeable.indexOf(field.id) !== -1, })) return h('el-form', { class: 'form', @@ -86,6 +90,8 @@ export default { 'label-position': 'top' } },authFields.map(field => formBuilder.bind(this)(this.device, field, h))) + }, + created() { } } diff --git a/src/views/flow/MobileForm.vue b/src/views/flow/MobileForm.vue index e9dbbf8..19bc7fd 100644 --- a/src/views/flow/MobileForm.vue +++ b/src/views/flow/MobileForm.vue @@ -164,10 +164,11 @@ export default { props: { 'show-toolbar': true, columns: this.vanPopupOption.columns, + 'value-key': typeof this.vanPopupOption.columns[0] === 'object' ? 'name' : 'yext' }, on: { confirm: value => { - this.$set(this.form,this.vanPopupOption.forFormName,value) + this.$set(this.form,this.vanPopupOption.forFormName,typeof value === 'object' ? value['id'] : value) this.$set(this.vanPopupOption,'isShow',false) }, cancel: _ => { diff --git a/src/views/flow/components/assign.vue b/src/views/flow/components/assign.vue index 74ef2a4..2f28373 100644 --- a/src/views/flow/components/assign.vue +++ b/src/views/flow/components/assign.vue @@ -1,6 +1,7 @@ + - + @@ -72,7 +160,7 @@ import DesktopForm from "./DesktopForm.vue"; import MobileForm from "./MobileForm.vue"; import assign from "./components/assign.vue"; -import {create, fieldConfig, preConfig,} from "@/api/flow"; +import { create, deal, fieldConfig, preConfig, preDeal, view } from "@/api/flow"; import { deepCopy } from "@/utils"; export default { @@ -118,76 +206,183 @@ export default { spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.8)", }); - try { - const res = await preConfig(this.$route.query.module_id); - const { fields } = res?.customModel; - let subFormRequest = []; - const getSubForm = (id) => { - subFormRequest.push(fieldConfig(id)); - }; - fields.forEach((field) => { - if (field.sub_custom_model_id) { - getSubForm(field.sub_custom_model_id); + //路由为detail为详情 + if(/\/detail/.test(this.$route.path) && this.$route.query.flow_id) { + try { + const res = await view(this.$route.query.flow_id); + console.log('view',res) + const { fields } = res?.customModel; + let subFormRequest = []; + const getSubForm = (id) => { + subFormRequest.push(fieldConfig(id)); + }; + fields.forEach((field) => { + if (field.sub_custom_model_id) { + getSubForm(field.sub_custom_model_id); + } + }); + const subConfigs = await Promise.all(subFormRequest); + subConfigs.forEach((sub) => { + if (sub.customModel?.id) { + this.subConfig.set(sub.customModel?.id, sub); + } + }); + this.config = res; + this.generateForm(this.form, fields); + this.form = Object.assign({}, this.form); + const { data } = res?.flow; + for (let key in data) { + try { + let jsonObj = JSON.parse(data[key]); + if (this.form.hasOwnProperty(key)) { + this.form[key] = jsonObj; + } + if (this.fileList.hasOwnProperty(key)) { + this.fileList[key] = jsonObj.map((i) => ({ + name: i.name, + url: i.url, + response: i, + })); + } + } catch (err) { + if (this.form.hasOwnProperty(key)) { + this.form[key] = data[key]; + } + } } - }); - const subConfigs = await Promise.all(subFormRequest); - subConfigs.forEach((sub) => { - if (sub.customModel?.id) { - this.subConfig.set(sub.customModel?.id, sub); + this.fileList = Object.assign({}, this.fileList); + loading.close(); + } catch (err) { + console.error(err); + this.$message.error("配置失败"); + loading.close(); + } + } else if (!this.$route.query.flow_id) { + try { + const res = await preConfig(this.$route.query.module_id); + const { fields } = res?.customModel; + let subFormRequest = []; + const getSubForm = (id) => { + subFormRequest.push(fieldConfig(id)); + }; + fields.forEach((field) => { + if (field.sub_custom_model_id) { + getSubForm(field.sub_custom_model_id); + } + }); + const subConfigs = await Promise.all(subFormRequest); + subConfigs.forEach((sub) => { + if (sub.customModel?.id) { + this.subConfig.set(sub.customModel?.id, sub); + } + }); + this.config = res; + this.generateForm(this.form, fields); + this.form = Object.assign({}, this.form); + loading.close(); + } catch (err) { + console.error(err); + this.$message.error("配置失败"); + loading.close(); + } + } else { + try { + const res = await preDeal(this.$route.query.flow_id); + const { fields } = res?.customModel; + let subFormRequest = []; + const getSubForm = (id) => { + subFormRequest.push(fieldConfig(id)); + }; + fields.forEach((field) => { + if (field.sub_custom_model_id) { + getSubForm(field.sub_custom_model_id); + } + }); + const subConfigs = await Promise.all(subFormRequest); + subConfigs.forEach((sub) => { + if (sub.customModel?.id) { + this.subConfig.set(sub.customModel?.id, sub); + } + }); + this.config = res; + this.generateForm(this.form, fields); + this.form = Object.assign({}, this.form); + const { data } = res?.flow; + for (let key in data) { + try { + let jsonObj = JSON.parse(data[key]); + if (this.form.hasOwnProperty(key)) { + this.form[key] = jsonObj; + } + if (this.fileList.hasOwnProperty(key)) { + this.fileList[key] = jsonObj.map((i) => ({ + name: i.name, + url: i.url, + response: i, + })); + } + } catch (err) { + if (this.form.hasOwnProperty(key)) { + this.form[key] = data[key]; + } + } } - }); - this.config = res; - this.generateForm(this.form, fields); - this.form = Object.assign({}, this.form); - loading.close(); - } catch (err) { - console.error(err); - this.$message.error("配置失败"); - loading.close(); + this.fileList = Object.assign({}, this.fileList); + loading.close(); + } catch (err) { + console.error(err); + this.$message.error("配置失败"); + loading.close(); + } } }, async submit(type) { + let copyForm,copyFile; if (this.device === "desktop") { - console.log(this.$refs["desktopForm"].form); - let copyForm = deepCopy(this.$refs["desktopForm"].form); - let copyFile = deepCopy(this.$refs["desktopForm"].file); - for (let [key, value] of Object.entries(copyFile)) { - if (copyForm.hasOwnProperty(key)) { - copyForm[key] = value.map((i) => i.response?.id)?.toString(); - } + copyForm = deepCopy(this.$refs["desktopForm"].form); + copyFile = deepCopy(this.$refs["desktopForm"].file); + } else { + copyForm = deepCopy(this.$refs["mobileForm"].form); + copyFile = deepCopy(this.$refs["mobileForm"].file); + } + console.log(copyForm,copyFile) + for (let [key, value] of Object.entries(copyFile)) { + if (copyForm.hasOwnProperty(key)) { + copyForm[key] = value.map((i) => i.response?.id)?.toString(); } - // for (let key in copyForm) { - // if(copyForm[key] instanceof Array && copyForm[key][0]) { - // let formatObj = {} - // let subKeys = Object.keys(copyForm[key][0]) - // subKeys.forEach(key => { - // formatObj[key] = [] - // }) - // copyForm[key].forEach(item => { - // subKeys.forEach(subKey => { - // formatObj[subKey].push(item[subKey]) - // }) - // }) - // delete formatObj['_X_ROW_KEY'] - // copyForm[key] = formatObj - // - // } - // } + } + copyForm["current_node_id"] = this.config.currentNode.id; - try { - this.result = await create(copyForm, this.$route.query.module_id); - switch (type) { - case "only-submit": - this.$router.push("/flow/list"); - break; - case "assign": - this.isShowAssign = true; - break; - } - } catch (err) { - console.error(err); + try { + let callback; + switch (type) { + case "only-submit": + if (this.$route.query.flow_id) { + copyForm["temporary_save"] = 1; + } + callback = () => this.$router.push("/flow/list/todo"); + break; + case "assign": + if (this.$route.query.flow_id) { + copyForm["temporary_save"] = 0; + } + callback = () => (this.isShowAssign = true); + break; + } + if (this.$route.query.flow_id) { + copyForm.id = this.$route.query.flow_id; + const { flow, is_last_handled_log } = await deal( + this.$route.query.flow_id, + copyForm + ); + this.result = flow; + } else { + this.result = await create(this.$route.query.module_id, copyForm); } + callback(); + } catch (err) { + console.error(err); } }, }, @@ -199,7 +394,7 @@ export default { return this.config?.customModel?.fields || []; }, readableFields() { - return this.config?.currentNode?.readable || []; + return /\/detail/.test(this.$route.path) ? this.fields?.map(i => i.id) : (this.config?.currentNode?.readable || []); }, writeableFields() { return this.config?.currentNode?.writeable || []; @@ -208,7 +403,9 @@ export default { return this.config?.currentNode || {}; }, scriptContent() { - if (this.config?.customModel?.js) { + if (this.config?.customModel?.view_js && this.$route.query.flow_id) { + return this.config?.customModel?.view_js; + } else if (this.config?.customModel?.js && !this.$route.query.flow_id) { return this.config?.customModel?.js; } }, @@ -230,9 +427,12 @@ export default { position: relative; } .btns { + display: flex; + justify-content: center; margin-top: 10px; position: sticky; bottom: 20px; + flex-wrap: wrap; } } .form-container { diff --git a/src/views/flow/list.vue b/src/views/flow/list.vue index e01680a..b467700 100644 --- a/src/views/flow/list.vue +++ b/src/views/flow/list.vue @@ -3,7 +3,7 @@