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.

494 lines
15 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.

<template>
<div>
<vxe-modal
title="批量审批"
:z-index="zIndex"
:value="isShow"
@input="e => $emit('update:isShow', e)"
:min-height="300"
resize
:width="defaultModalSize.sWidth"
:height="defaultModalSize.sHeight"
:fullscreen="$store.getters.device === 'mobile'"
show-zoom
draggable
storage
show-footer
>
<vxe-table
ref="table"
stripe
keep-source
show-overflow
:column-config="{ resizable: true }"
:print-config="{}"
:export-config="{}"
:row-config="{ keyField: 'id' }"
:custom-config="{ mode: 'popup' }"
:data="dealFlows"
>
<vxe-column
min-width="140"
header-align="center"
field="title"
title="工作名称"
></vxe-column>
<vxe-column
width="80"
align="center"
field="id"
title="流水号"
></vxe-column>
<vxe-column
header-align="center"
min-width="240"
field="_simple"
title="简要"
></vxe-column>
<vxe-column
width="80"
title="发起人"
align="center"
field="creator.name"
></vxe-column>
<vxe-column
width="80"
title="承办人员"
align="center"
field="last_log.user.name"
></vxe-column>
<vxe-column
header-align="center"
min-width="120"
field="custom_model.name"
title="流程名称"
></vxe-column>
<vxe-column
width="164"
field="no"
align="center"
title="编号"
></vxe-column>
<vxe-column
width="200"
:visible="$route.params.type === 'all'"
align="center"
field="created_at"
title="发起日期"
:formatter="
({ cellValue }) =>
$moment(cellValue).format('YYYY-MM-DD HH:mm:ss')
"
:export-method="
({ row, column, options }) =>
$moment(row['created_at']).format('YYYY-MM-DD HH:mm:ss')
"
></vxe-column>
</vxe-table>
<template v-if="device === 'desktop'">
<DesktopForm
:device="device"
ref="desktopForm"
:config="config"
:is-first-node="isFirstNode"
:need-flow-title="false"
:sub-form="subConfig"
:fields="fields"
:original-form="form"
:readable="[]"
:script-content="scriptContent"
:writeable="writeableFields"
:rules="rules"
:sub-rules="subRules"
:logs="config.logs"
></DesktopForm>
</template>
<template v-else>
<MobileForm
:device="device"
ref="mobileForm"
:config="config"
:is-first-node="isFirstNode"
:need-flow-title="false"
:sub-form="subConfig"
:fields="fields"
:original-form="form"
:readable="[]"
:script-content="scriptContent"
:writeable="writeableFields"
:rules="rules"
:sub-rules="subRules"
:logs="config.logs"
></MobileForm>
</template>
<template #footer>
<el-button
icon="el-icon-document-add"
type="info"
size="small"
@click="submit('only-submit')"
>暂存不流转</el-button
>
<el-button type="primary" size="small" @click="submit('assign')"
>保存并流转 <i class="el-icon-right"></i
></el-button>
</template>
</vxe-modal>
<assign :visible.sync="isShowAssign" :result="result" multiple :multipleIds="dealFlows.map(flow => flow.id)" @refresh="$emit('update:isShow', false),$emit('refresh')" />
</div>
</template>
<script>
import { PopupManager } from 'element-ui/lib/utils/popup'
import { defaultModalSize } from '@/settings'
import {create, deal, fieldConfig, preDeal} from '@/api/flow'
import { validation, validationName } from "@/utils/validate";
import MobileForm from "@/views/flow/MobileForm.vue";
import DesktopForm from "@/views/flow/DesktopForm.vue";
import assign from './assign.vue'
import {deepCopy} from "@/utils";
export default {
components: {
DesktopForm, MobileForm,assign
},
props: {
isShow: {
type: Boolean,
default: false
},
dealFlows: {
type: Array,
default: () => []
}
},
data() {
return {
loading: false,
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
form: {},
subConfig: new Map(),
config: {},
rules: {},
subRules: {},
flows: [],
isShowAssign: false,
result: {},
}
},
methods: {
generateForm(object, fields, relation = false, pname) {
fields.forEach((field) => {
if (field.rules && field.rules.length > 0 && this.writeableFields.find(i => i === field.id) && !relation) {
this.rules[field.name] = field.rules.map((rule) => {
switch (rule) {
case "required":
if (field.type === 'relation') {
return {
validator: (myRule, value, callback) => {
if (value instanceof Array && value.length > 0) {
callback()
} else {
callback(`请填写${field.label}`)
}
},
message: `请填写${field.label}`,
trigger: "blur",
};
} else {
return {
required: true,
message: `请填写${field.label}`,
trigger: "blur",
};
}
default:
return {
validator: (myRule, value, callback) => {
if (validation.get(rule).test(value) || value === '') {
callback();
} else {
callback(
new Error(
`${field.label}必须为${validationName.get(rule)}`
)
);
}
},
trigger: "blur",
pattern: validation.get(rule),
message: `${field.label}必须为${validationName.get(rule)}`,
};
}
});
}
if (relation) {
this.subRules[`${pname}_rules`][field.name] = field.rules.map((rule) => {
switch (rule) {
case "required":
return {
required: true,
message: `请填写${field.label}`,
};
default:
return {
validator: ({ cellValue }) => {
return new Promise((resolve, reject) => {
if (validation.get(rule).test(cellValue) || cellValue === '') {
resolve()
} else {
reject(
new Error(
`${field.label}必须为${validationName.get(rule)}`
)
);
}
})
},
trigger: "blur",
pattern: validation.get(rule),
message: `${field.label}必须为${validationName.get(rule)}`,
};
}
});
}
if (field.type === "relation") {
this.subRules[`${field.name}_rules`] = {}
object[field.name] = [{}];
this.generateForm(
object[field.name][0],
this.subConfig.get(field.sub_custom_model_id)?.customModel?.fields,
true,
field.name
);
} else {
if (/\/detail/.test(this.$route.path) && this.$route.query.flow_id) {
object[field.name] = "";
} else {
if (this.writeableFields.indexOf(field.id) !== -1 || this.readableFields.indexOf(field.id) !== -1) {
object[field.name] = (this.writeableFields.indexOf(field.id) !== -1 && field.default_value) ? field.default_value : (field.type === 'file' ? [] : "");
}
}
}
});
},
async getConfig() {
const firstFlow = this.dealFlows[0]
const loading = this.$loading({
lock: true,
text: "拼命加载中",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.8)",
});
try {
const res = await preDeal(firstFlow.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);
const { data } = res?.flow;
for (let key in data) {
try {
let jsonObj = JSON.parse(data[key]);
jsonObj.forEach(item => {
// 遍历对象中的每个键值对
for (const key in item) {
if (typeof item[key] === 'string') {
try {
// 尝试解析字符串为 JSON 对象
const parsedValue = JSON.parse(item[key]);
// 如果解析成功,替换原始字符串
item[key] = parsedValue;
} catch (e) {
// 如果解析失败,继续保持原始字符串
}
}
}
})
if (this.form.hasOwnProperty(key)) {
this.form[key] = jsonObj;
}
} catch (err) {
if (this.form.hasOwnProperty(key)) {
if (data[key] instanceof Array) {
if (data[key].length > 0) {
this.form[key] = data[key];
} else {
this.form[key] = ''
}
}
if (data[key] && data[key] !== 'null' && data[key] !== 'undefined') {
this.form[key] = data[key];
}
}
}
}
this.form = Object.assign({}, this.form);
loading.close();
} catch (err) {
console.error(err);
this.$message.error("配置失败");
loading.close();
}
},
async submit(type) {
if (window.$_uploading) {
this.$message.warning("文件正在上传中")
return
}
let copyForm;
if (this.device === "desktop") {
try {
await this.$refs['desktopForm'].validate()
} catch (err) {
console.warn(err)
this.$message.warning('数据校验失败')
return
}
copyForm = deepCopy(this.$refs["desktopForm"].form);
} else {
try {
await this.$refs['mobileForm'].validate()
} catch (err) {
console.warn(err)
this.$message.warning('数据校验失败')
return
}
copyForm = deepCopy(this.$refs["mobileForm"].form);
}
const uploadHandler = (form, fields) => {
let keys = Object.keys(form)
keys.forEach(key => {
if (form[key] instanceof Array) {
if (form[key].length > 0 && typeof form[key][0] === 'object') {
const myField = fields.find(field => field.name === key)
if (myField) {
if (myField.type === 'file') {
form[key] = form[key].map(i => i.hasOwnProperty('response') ? i.response : i)
} else {
form[key].forEach(i => {
uploadHandler(i, this.subConfig.get(myField.sub_custom_model_id)?.customModel?.fields)
})
}
}
} else {
form[key] = ''
}
} else {
if (form[key] === 'null' || form[key] === 'undefined') {
form[key] = ''
}
}
})
}
uploadHandler(copyForm, this.fields)
for (let key in copyForm) {
let myField = this.fields.find(i => i.name === key)
if (myField && this.writeableFields.indexOf(myField.id) === -1) {
delete copyForm[key]
}
}
copyForm["current_node_id"] = this.config.currentNode.id;
try {
let callback;
switch (type) {
case "only-submit":
if (this.$route.query.flow_id) {
copyForm["temporary_save"] = 1;
}
callback = () => {
this.$emit('update:isShow', false)
this.$emit('refresh')
}
break;
case "assign":
if (this.$route.query.flow_id) {
copyForm["temporary_save"] = 0;
}
callback = () => (this.isShowAssign = true);
break;
}
const resArr = await Promise.all(this.dealFlows.map(flow => deal(flow.id, copyForm)))
const { flow, is_last_handled_log } = resArr[0]
this.result = flow;
if (!is_last_handled_log) {
await this.$alert(
"办理成功其他会签办理完成后由最后办理的成员流转到下一节点",
"提示",
{
showClose: false,
}
);
callback = () => {
this.$emit('update:isShow', false)
this.$emit('refresh')
}
}
callback();
} catch (err) {
console.error(err);
}
},
},
computed: {
device() {
return this.$store.state.app.device;
},
fields() {
return this.config?.customModel?.fields || [];
},
scriptContent() {
if (this.config?.customModel?.view_js && this.$route.query.flow_id && /\/detail/.test(this.$route.path)) {
return this.config?.customModel?.view_js;
} else if (this.config?.customModel?.js && !/\/detail/.test(this.$route.path)) {
return this.config?.customModel?.js;
}
},
readableFields() {
return []
},
writeableFields() {
return this.config?.currentNode?.writeable || [];
},
isFirstNode() {
return this.config?.logs?.length === 0 || this.config?.currentNode?.category === 'start'
}
},
watch: {
isShow(newVal) {
if (newVal) {
this.zIndex = PopupManager.nextZIndex()
if (this.dealFlows instanceof Array && this.dealFlows.length > 0) {
this.getConfig()
}
}
}
}
}
</script>
<style scoped lang="scss">
</style>