fix: stabilize workflow action buttons

This commit is contained in:
caoqianming 2026-07-27 13:31:30 +08:00
parent 5b007a536d
commit 3dc25fef2a
3 changed files with 108 additions and 38 deletions

View File

@ -188,6 +188,12 @@ export default {
return await http.get( `${config.API_URL}/wf/ticket/${id}/transitions/`); return await http.get( `${config.API_URL}/wf/ticket/${id}/transitions/`);
} }
}, },
ticketAvailableActions: {
name: "获取当前用户可执行的工单操作",
req: async function(id){
return await http.get(`${config.API_URL}/wf/ticket/${id}/available_actions/`);
}
},
dutyAgg: { dutyAgg: {
url: `${config.API_URL}/wf/ticket/duty_agg/`, url: `${config.API_URL}/wf/ticket/duty_agg/`,
name: "待办审批聚合", name: "待办审批聚合",

View File

@ -1,4 +1,12 @@
<template> <template>
<el-button
v-if="needAccept"
type="success"
:loading="isAccepting"
:disabled="isAccepting"
@click="acceptTicket"
style="margin-right: 2px"
>接单</el-button>
<span v-if="actionShow"><el-button <span v-if="actionShow"><el-button
v-for="item in transitions" v-for="item in transitions"
:key="item.id" :key="item.id"
@ -17,10 +25,9 @@
</el-dialog> </el-dialog>
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, defineEmits,watch } from 'vue' import { ref, defineEmits, watch } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import API from '@/api'; import API from '@/api';
import TOOL from "@/utils/tool.js";
const props = defineProps({ const props = defineProps({
@ -34,44 +41,64 @@ const props = defineProps({
const workflow = ref(null); const workflow = ref(null);
const transitions = ref([]); const transitions = ref([]);
let lastInitTicketId = null; let lastInitKey = null;
const tryInit = () => { let requestVersion = 0;
// ticket_ ticket_.id const getInitKey = () => {
if (props.ticket_ && props.ticket_.id) { if (props.ticket_ && props.ticket_.id) {
if (lastInitTicketId !== props.ticket_.id) { return [
lastInitTicketId = props.ticket_.id; 'ticket',
init(); props.ticket_.id,
} props.ticket_.state,
return; JSON.stringify(props.ticket_.participant),
props.ticket_.update_time,
].join(':');
} }
// ticket_退 workflow_key
if (props.workflow_key) { if (props.workflow_key) {
if (lastInitTicketId !== '__wf_key__:' + props.workflow_key) { return `workflow:${props.workflow_key}`;
lastInitTicketId = '__wf_key__:' + props.workflow_key; }
init(); return null;
} };
const tryInit = () => {
const initKey = getInitKey();
if (initKey && lastInitKey !== initKey) {
lastInitKey = initKey;
init();
} }
}; };
onMounted(() => { tryInit(); }); watch(
watch(() => props.ticket_, () => { tryInit(); }, { deep: true }); () => [
watch(() => props.workflow_key, () => { tryInit(); }); props.ticket_?.id,
props.ticket_?.state,
props.ticket_?.participant,
props.ticket_?.update_time,
props.workflow_key,
],
tryInit,
{ deep: true, immediate: true },
);
const ticketId = ref(null); const ticketId = ref(null);
const actionShow = ref(false); const actionShow = ref(false);
const needAccept = ref(false);
const init = async () => { const init = async () => {
const currentRequestVersion = ++requestVersion;
actionShow.value = false; actionShow.value = false;
needAccept.value = false;
transitions.value = []; transitions.value = [];
if (props.ticket_ && props.ticket_.id) { if (props.ticket_ && props.ticket_.id) {
ticketId.value = props.ticket_.id; ticketId.value = props.ticket_.id;
const isParticipant = const actionInfo = await API.wf.ticket.ticketAvailableActions.req(ticketId.value);
(props.ticket_.participant_type === 1 && props.ticket_.participant === currentUser.value) || if (currentRequestVersion !== requestVersion) {
(props.ticket_.participant_type === 2 && props.ticket_.participant.includes(currentUser.value)) return;
if (isParticipant) {
actionShow.value = true;
transitions.value = await API.wf.ticket.ticketTransitions.req(ticketId.value);
} }
needAccept.value = actionInfo.need_accept;
actionShow.value = actionInfo.permission;
transitions.value = actionInfo.transitions;
}else if (props.workflow_key !=null && props.workflow_key != undefined) { }else if (props.workflow_key !=null && props.workflow_key != undefined) {
let res = await API.wf.workflow.initkey.req(props.workflow_key); let res = await API.wf.workflow.initkey.req(props.workflow_key);
if (currentRequestVersion !== requestVersion) {
return;
}
actionShow.value = true actionShow.value = true
transitions.value = res.transitions; transitions.value = res.transitions;
workflow.value = res.workflow workflow.value = res.workflow
@ -79,11 +106,21 @@ const init = async () => {
ElMessage.error("缺少workflow_key或ticketId"); ElMessage.error("缺少workflow_key或ticketId");
} }
} }
const currentUser = ref(TOOL.data.get("USER_INFO").id)
const isSaveing = ref(false); const isSaveing = ref(false);
const isAccepting = ref(false);
const emit = defineEmits(["success"]); const emit = defineEmits(["success"]);
const acceptTicket = async () => {
isAccepting.value = true;
try {
await API.wf.ticket.ticketAccept.req(ticketId.value, {});
ElMessage.success("接单成功");
lastInitKey = null;
await init();
} finally {
isAccepting.value = false;
}
};
const handleTransition = (item) => { const handleTransition = (item) => {
currentTransitionId.value = item.id; currentTransitionId.value = item.id;
if (item.attribute_type != 1) { if (item.attribute_type != 1) {
@ -160,4 +197,4 @@ const submit = async (transition_id) => {
const dialogVisible = ref(false); const dialogVisible = ref(false);
const dialogTitle = ref("处理意见"); const dialogTitle = ref("处理意见");
const suggestion = ref(""); const suggestion = ref("");
</script> </script>

View File

@ -316,6 +316,14 @@
</div> </div>
<div style="display: flex; justify-content: space-between"> <div style="display: flex; justify-content: space-between">
<div> <div>
<el-button
v-if="needAccept"
type="success"
:loading="acceptLoading"
:disabled="acceptLoading"
@click="handleAccept"
>接单</el-button
>
<el-button <el-button
type="primary" type="primary"
@click="addNode" @click="addNode"
@ -628,6 +636,8 @@ export default {
dosOption: [], dosOption: [],
handoverItem:{}, handoverItem:{},
submitLoading: false, submitLoading: false,
acceptLoading: false,
needAccept: false,
userId: this.$TOOL.data.get("USER_INFO").id, userId: this.$TOOL.data.get("USER_INFO").id,
isOwn: false, isOwn: false,
isDuty: false, isDuty: false,
@ -760,6 +770,7 @@ export default {
getticketItem() { getticketItem() {
let that = this; let that = this;
that.mainLoading = true; that.mainLoading = true;
that.isDuty = false;
that.$API.wf.ticket.ticketItem.req(that.ticketId).then((res) => { that.$API.wf.ticket.ticketItem.req(that.ticketId).then((res) => {
that.mainLoading = false; that.mainLoading = false;
that.ticketDetail = res; that.ticketDetail = res;
@ -791,11 +802,11 @@ export default {
if (this.ticketDetail.create_by == this.userId) { if (this.ticketDetail.create_by == this.userId) {
this.isOwn = true; this.isOwn = true;
} }
let participant = this.ticketDetail.participant; const participant = this.ticketDetail.participant;
if ( const participants = Array.isArray(participant)
participant == this.userId || ? participant
participant.indexOf(this.userId) > -1 : [participant];
) { if (participants.map(String).includes(String(this.userId))) {
this.isDuty = true; this.isDuty = true;
} }
}).catch((e) => { }).catch((e) => {
@ -806,21 +817,37 @@ export default {
getBtns() { getBtns() {
let that = this; let that = this;
that.audit_imgs_show = false; that.audit_imgs_show = false;
that.$API.wf.ticket.ticketTransitions.req(that.ticketId).then((res) => { that.audit_work_show = false;
that.operationBtn = res; that.needAccept = false;
that.$API.wf.ticket.ticketAvailableActions.req(that.ticketId).then((res) => {
that.operationBtn = res.transitions;
that.needAccept = res.need_accept;
if (res.permission || res.need_accept) {
that.isDuty = true;
}
console.log("operationBtn", that.operationBtn); console.log("operationBtn", that.operationBtn);
if(res.length>0){ if(that.operationBtn.length>0){
for (let i = 0; i < res.length; i++) { for (let i = 0; i < that.operationBtn.length; i++) {
if(res[i].on_submit_func=="apps.opm.services.check_opl_audit_imgs"){ if(that.operationBtn[i].on_submit_func=="apps.opm.services.check_opl_audit_imgs"){
that.audit_imgs_show = true; that.audit_imgs_show = true;
} }
if(res[i].on_submit_func=="apps.opm.services.check_opl_work_imgs"){ if(that.operationBtn[i].on_submit_func=="apps.opm.services.check_opl_work_imgs"){
that.audit_work_show = true; that.audit_work_show = true;
} }
} }
} }
}); });
}, },
handleAccept() {
this.acceptLoading = true;
this.$API.wf.ticket.ticketAccept.req(this.ticketId, {}).then(() => {
this.$message.success("接单成功");
this.getticketItem();
this.getBtns();
}).finally(() => {
this.acceptLoading = false;
});
},
//访 //访
getVisit() { getVisit() {
this.$API.vm.visit.read.req(this.projectId).then((res) => { this.$API.vm.visit.read.req(this.projectId).then((res) => {