教代会意见一个单位可以设置多个管理员,审核时只需要一个管理员审核即可完成节点

This commit is contained in:
2026-09-08 19:27:34 +08:00
parent c18579fe40
commit f2b02f8b49
28 changed files with 1233 additions and 325 deletions
@@ -40,6 +40,7 @@
'assigneeMode',
'buttonConfig',
'enableNextOperator',
'countersignGroupBy',
'h5form'
]"
>
@@ -83,6 +84,19 @@
</template>
<template v-slot="{model,field}">
<el-form-item label="会签办理维度" v-if="['ALL', 'COUNTERSIGN', 'countersign', 1].includes(model.performType)">
<el-select :value="model.countersignGroupBy || 'PERSON'"
@input="handleCountersignGroupChange(model, $event)" style="width: 100%">
<el-option label="按人员(每人分别办理)" value="PERSON"></el-option>
<el-option label="按所属单位(同单位任一人办理)" value="UNIT"></el-option>
<el-option label="按工会(同工会任一人办理)" value="UNION"></el-option>
<el-option label="按承办单位(同承办单位任一人办理)" value="UNDERTAKE"></el-option>
</el-select>
<div style="color: #909399; line-height: 20px; margin-top: 6px;">
分组后,同组任一人办理即完成本组;会签数量和比例按组计算。
意见答复请选择“按承办单位”。配置在新生成的任务中生效,已有待办保持原规则。
</div>
</el-form-item>
<el-form-item label="指定下一步处理人">
<el-checkbox v-model="model['enableNextOperator']">指定下一步处理人</el-checkbox>
</el-form-item>
@@ -114,6 +128,7 @@
id: "${id!}",
designerData: {},
flowData: {},
formLoading: false,
assignmentHandlerClassOptions: [],
candidateHandlerClassOptions: []
}
@@ -135,7 +150,16 @@
}
},
methods: {
// model 为当前节点的插槽表单,value 为所选办理维度;在实例方法内响应式赋值,避免插槽 this 指向错误。
handleCountersignGroupChange(model, value) {
this.$set(model, 'countersignGroupBy', value)
},
handleSave(val) {
// 避免连点重复保存;请求结束后统一恢复保存状态。
if (this.formLoading) {
return
}
this.formLoading = true
const design = {
...this.designerData,
content: val.json
@@ -146,6 +170,8 @@
} else {
window.parent.postMessage("error")
}
}).always(() => {
this.formLoading = false
})
},
getDetail() {
@@ -18,7 +18,7 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
<table-tool label="人员列表">
<el-button @click="openAdd" type="primary" size="small">新增</el-button>
</table-tool>
<el-table :data="tableData" size="mini">
<el-table :data="tableData" v-loading="tableLoading" size="mini">
<el-table-column label="序号" type="index" width="60">
<template v-slot="scope">{{scope.$index + (pageForm.pageNumber - 1) * pageForm.pageSize + 1}}</template>
</el-table-column>
@@ -36,13 +36,16 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
<el-dialog title="添加" :visible.sync="dialogFormVisible" width="600px" :close-on-click-modal="false">
<el-form :model="formData" ref="form" size="small" label-width="60px">
<el-form-item prop="roleCode" label="角色">
<dict-select placeholder="请选择角色" v-model="formData.roleCode" code="UNIT_ROLES"></dict-select>
<el-select placeholder="请选择角色" :value="formData.roleCode" @change="(value) => this.$set(this.formData, 'roleCode', value)" style="width: 100%">
<el-option v-for="item in roleOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="userId" label="人员">
<user-select
placeholder="请选择人员"
style="width: 100%"
v-model="formData.userId"
:value="formData.userId"
@change="(value) => this.$set(this.formData, 'userId', value)"
api="/platform/sys/unit/listUserSelect"
:api_params="{ unitId: currentData?.id }"
:option_label_func="
@@ -54,10 +57,11 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
<el-button @click="this.$set(this, 'dialogFormVisible', false)" :disabled="formLoading">取 消</el-button>
<el-button type="primary" :loading="formLoading" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
<slot></slot>
</div>
`,
props: {
@@ -70,6 +74,9 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
return {
dialogFormVisible: false,
formData: {},
roleOptions: [],
tableLoading: false,
formLoading: false,
pageForm: {
unitName: "",
searchName: "username",
@@ -87,20 +94,26 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
computed: {},
methods: {
doDelete({ userId, roleCode }) {
this.$confirm("您确定要删除吗?", "提示", {
// 删除提案领导会同步取消提案配置中的负责人,操作前明确提示。
const message = roleCode === "PROPOSAL_UNIT_LEADER" ? "删除后将同时取消提案承办单位配置中的该负责人,确定删除吗?" : "您确定要删除吗?"
const unitId = this.currentData.id
this.$confirm(message, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then((res) => {
this.tableLoading = true
$.post("/platform/sys/unit/deleteUnitUserRole", {
userId,
roleCode,
unitId: this.currentData.id
unitId
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
}).always(() => {
this.tableLoading = false
})
})
},
@@ -111,6 +124,13 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
})
},
doSubmit() {
// 单位、角色和人员必须完整,提交期间阻止重复点击。
if (this.formLoading) return
if (!this.currentData?.id || !this.formData.roleCode || !this.formData.userId) {
this.$message.warning("请选择单位、角色和人员")
return
}
this.formLoading = true
$.post("/platform/sys/unit/insertUnitUserRole", {
...this.formData,
unitId: this.currentData.id
@@ -120,6 +140,8 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
this.$message.success(res.msg)
this.doSearch()
}
}).always(() => {
this.formLoading = false
})
},
doSearch() {
@@ -134,17 +156,28 @@ const UNIT_LEADER_MANAGE_TEMPLATE = {
this.pageForm.pageSize = val
this.pageData()
},
// 角色选项由当前业务接口提供,保留字典角色并补充提案领导。
loadRoleOptions() {
this.$axios.post("/platform/sys/unit/unitRoleOptions").then((res) => {
if (res.code === 0) this.roleOptions = res.data
})
},
pageData() {
if (!this.currentData?.id) return
this.tableLoading = true
this.pageForm.unitId = this.currentData.id
this.$axios.post(loc() + "/leaderPageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
}).finally(() => {
this.tableLoading = false
})
}
},
created() {
this.loadRoleOptions()
this.pageData()
}
}
@@ -81,7 +81,7 @@ const OPINION_INFO = {
<template v-if="['schoolAudit', 'office'].includes(task.taskName)">
<el-descriptions-item label="主办单位" :span="3">
{{task.ext.tf_masterUnitName}}
{{task.ext.tf_masterUnitNameStr || task.ext.tf_masterUnitName}}
</el-descriptions-item>
<el-descriptions-item label="协办单位" :span="3">
{{task.ext.tf_slaveUnitNameStr}}
@@ -91,10 +91,10 @@ layout("/layouts/platform.html"){
<el-form-item
label="主办单位"
v-if="isSchoolPass()"
:rules="[{required:true, message:'必填',trigger:['change','blur']}]"
prop="tf_masterUnitId"
:rules="[{type:'array',required:true,min:1,message:'请选择主办单位',trigger:['change','blur']}]"
prop="tf_masterUnitIds"
>
<el-select v-model="formData.tf_masterUnitId" filterable clearable style="width: 100%" placeholder="请选择主办单位">
<el-select v-model="formData.tf_masterUnitIds" multiple filterable clearable style="width: 100%" placeholder="请选择主办单位">
<el-option
v-for="item in underTakeOptions"
:label="item.name"
@@ -112,7 +112,7 @@ layout("/layouts/platform.html"){
:label="item.name"
:value="item.id"
:key="item.id"
:disabled="item.id===formData.tf_masterUnitId"
:disabled="formData.tf_masterUnitIds.includes(item.id)"
></el-option>
</el-select>
</el-form-item>
@@ -123,7 +123,7 @@ layout("/layouts/platform.html"){
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction" size="small" type="primary">提交</el-button>
<el-button @click="handleTaskAction" :loading="formLoading" size="small" type="primary">提交</el-button>
</el-row>
</div>
</opinion-info>
@@ -182,7 +182,7 @@ layout("/layouts/platform.html"){
approval: false
},
formData: {
tf_masterUnitId: null,
tf_masterUnitIds: [],
tf_slaveUnitIds: []
},
showApprovalForm: false,
@@ -212,7 +212,7 @@ layout("/layouts/platform.html"){
return
}
this.$nextTick(() => {
this.$refs.formRef && this.$refs.formRef.clearValidate(["typeId", "tf_masterUnitId", "tf_slaveUnitIds"])
this.$refs.formRef && this.$refs.formRef.clearValidate(["typeId", "tf_masterUnitIds", "tf_slaveUnitIds"])
})
},
openView(row) {
@@ -229,7 +229,7 @@ layout("/layouts/platform.html"){
processTaskId: row.taskId,
taskName: row.curTaskName,
typeId: row.typeId,
tf_masterUnitId: null,
tf_masterUnitIds: [],
tf_slaveUnitIds: [],
tf_schoolResult: 'YES',
roleCode: 'OFFICE_MANAGER',
@@ -239,6 +239,9 @@ layout("/layouts/platform.html"){
},
handleTaskAction() {
if (this.formLoading) {
return
}
this.schoolResultChange()
this.$nextTick(() => {
this.$refs.formRef.validate((valid) => {
@@ -248,6 +251,7 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formLoading = true
const loading = createLoading('提交中')
const submitType = this.formData.tf_schoolResult === 'ROLLBACK' ? 6 : 1
const executeTask = () => {
@@ -259,11 +263,13 @@ layout("/layouts/platform.html"){
tf_opinion: this.formData.tf_opinion,
} : {
...this.formData,
tf_masterUnitName: this.formData.tf_masterUnitId ? this.underTakeOptions.find(v => v.id === this.formData.tf_masterUnitId)?.name : null,
// ID 数组供任务分配使用,名称数组和拼接文本供审批历史展示。
tf_masterUnitNames: this.formData.tf_masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_masterUnitNameStr: this.formData.tf_masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(','),
tf_slaveUnitNames: this.formData.tf_slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_slaveUnitNameStr: this.formData.tf_slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(','),
}
this.$axios.post("/flow/common/executeTask", {
return this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...taskData,
submitType: submitType,
@@ -274,27 +280,26 @@ layout("/layouts/platform.html"){
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
loading.close()
})
}
if (submitType === 6 || !this.isSchoolPass()) {
executeTask()
return
return executeTask().finally(() => {
this.formLoading = false
loading.close()
})
}
// 通过审核时校工会可调整意见类别,需要先保存 typeId,再按流程表 YES 分支继续流转
this.$axios.post("/platform/opinion/schoolAudit/edit", {
// 通过审核先保存类别,返回流程提交 Promise,让失败和成功都统一释放 loading
return this.$axios.post("/platform/opinion/schoolAudit/edit", {
info: JSON.stringify({
id: this.formData.id,
typeId: this.formData.typeId
})
}).then((editRes) => {
if (editRes.code === 0) {
executeTask()
return
return executeTask()
}
loading.close()
}).catch(() => {
}).finally(() => {
this.formLoading = false
loading.close()
})
})