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

11 months ago
<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' }"
11 months ago
:data="dealFlows"
11 months ago
>
<vxe-column
min-width="140"
header-align="center"
field="title"
title="工作名称"
></vxe-column>
<vxe-column
width="80"
align="center"
field="id"
title="流水号"
></vxe-column>
10 months ago
<vxe-column
header-align="center"
min-width="240"
field="_simple"
title="简要"
></vxe-column>
11 months ago
<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>
11 months ago
<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>
11 months ago
<template #footer>
11 months ago
<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>
11 months ago
</template>
</vxe-modal>
11 months ago
<assign :visible.sync="isShowAssign" :result="result" multiple :multipleIds="dealFlows.map(flow => flow.id)" @refresh="$emit('update:isShow', false),$emit('refresh')" />
11 months ago
</div>
</template>
<script>
import { PopupManager } from 'element-ui/lib/utils/popup'
11 months ago
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";
11 months ago
export default {
11 months ago
components: {
DesktopForm, MobileForm,assign
},
11 months ago
props: {
isShow: {
type: Boolean,
default: false
},
11 months ago
dealFlows: {
11 months ago
type: Array,
default: () => []
}
},
data() {
return {
loading: false,
defaultModalSize,
zIndex: PopupManager.nextZIndex(),
11 months ago
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;
}
11 months ago
callback = () => {
this.$emit('update:isShow', false)
this.$emit('refresh')
}
11 months ago
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,
}
);
11 months ago
callback = () => {
this.$emit('update:isShow', false)
this.$emit('refresh')
}
11 months ago
}
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'
11 months ago
}
},
watch: {
isShow(newVal) {
if (newVal) {
this.zIndex = PopupManager.nextZIndex()
11 months ago
if (this.dealFlows instanceof Array && this.dealFlows.length > 0) {
this.getConfig()
}
11 months ago
}
}
}
}
</script>
<style scoped lang="scss">
</style>