feat: base 增加wf ticketd组件可在业务组件里加载
This commit is contained in:
parent
94516f4b47
commit
8dab72dbcd
|
@ -22,6 +22,11 @@
|
||||||
--el-color-primary-dark-9: #060f19;
|
--el-color-primary-dark-9: #060f19;
|
||||||
--el-border-radius-base: 2px;
|
--el-border-radius-base: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-collapse-item__content {
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-tag {
|
.el-tag {
|
||||||
--el-tag-border-radius: 2px;
|
--el-tag-border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,6 +224,20 @@ export const actStateEnum = new EnumFactory({
|
||||||
5: { text: '已关闭', type: 'info' },
|
5: { text: '已关闭', type: 'info' },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const interveneTypeEnum = new EnumFactory({
|
||||||
|
0: { text: '正常', type: 'primary' },
|
||||||
|
1: { text: '转交', type: 'primary' },
|
||||||
|
2: { text: '加签', type: 'info' },
|
||||||
|
3: { text: '加签处理完成', type: 'primary' },
|
||||||
|
4: { text: '接单', type: 'success' },
|
||||||
|
5: { text: '评论', type: 'info' },
|
||||||
|
6: { text: '删除', type: 'danger' },
|
||||||
|
7: { text: '强制关闭', type: 'danger' },
|
||||||
|
8: { text: '强制修改状态', type: 'danger' },
|
||||||
|
10: { text: '撤回', type: 'danger' },
|
||||||
|
11: { text: '抄送', type: 'info' },
|
||||||
|
})
|
||||||
|
|
||||||
export const mCateEnum = new EnumFactory({
|
export const mCateEnum = new EnumFactory({
|
||||||
'list': ['主要辅材','办公辅料','设备维护辅料','包装辅材','标识辅材','防护辅材','其他辅材','常规辅材','医护辅材','检测辅材','倒角辅材','减薄辅材','磨抛辅材','多线切辅材','精雕辅材','扫边辅材','黑化辅材']
|
'list': ['主要辅材','办公辅料','设备维护辅料','包装辅材','标识辅材','防护辅材','其他辅材','常规辅材','医护辅材','检测辅材','倒角辅材','减薄辅材','磨抛辅材','多线切辅材','精雕辅材','扫边辅材','黑化辅材']
|
||||||
})
|
})
|
|
@ -72,43 +72,28 @@
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="工单标题"
|
label="工单标题"
|
||||||
prop="title"
|
prop="title"
|
||||||
width="180"
|
min-width="180"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
></el-table-column>
|
></el-table-column>
|
||||||
|
|
||||||
<el-table-column label="工作流" prop="title">
|
<el-table-column label="工作流" prop="title" width="160">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.workflow_.name }}
|
{{ scope.row.workflow_.name }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="所在节点">
|
<el-table-column label="所在节点" width="160">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.state_.name }}
|
{{ scope.row.state_.name }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="进行状态" prop="sort">
|
<el-table-column label="进行状态" prop="sort" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag
|
<el-tag :type="actStateEnum[scope.row.act_state]?.type">
|
||||||
:type="
|
{{ actStateEnum[scope.row.act_state]?.text }}
|
||||||
scope.row.act_state === 0
|
</el-tag>
|
||||||
? ''
|
|
||||||
: scope.row.act_state === 1
|
|
||||||
? ''
|
|
||||||
: scope.row.act_state === 2
|
|
||||||
? 'danger'
|
|
||||||
: scope.row.act_state === 3
|
|
||||||
? 'danger'
|
|
||||||
: scope.row.act_state === 5
|
|
||||||
? 'danger'
|
|
||||||
: scope.row.act_state === 4
|
|
||||||
? 'success'
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
>{{ act_states[scope.row.act_state] }}</el-tag
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="可处理人" :show-overflow-tooltip="true">
|
<el-table-column label="可处理人" :show-overflow-tooltip="true" min-width="160">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span
|
<span
|
||||||
v-if="
|
v-if="
|
||||||
|
@ -134,7 +119,6 @@
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
link
|
|
||||||
size="small"
|
size="small"
|
||||||
@click="reStart(scope.row)"
|
@click="reStart(scope.row)"
|
||||||
v-if="scope.row.script_run_last_result == false"
|
v-if="scope.row.script_run_last_result == false"
|
||||||
|
@ -144,18 +128,24 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</scTable>
|
</scTable>
|
||||||
</el-main>
|
</el-main>
|
||||||
<el-drawer title="工单详情" v-model="drawer" size="80%" destroy-on-close>
|
<el-drawer v-model="drawer" size="90%" :show-close="false">
|
||||||
<component :is="currentComponent" :ticketId="ticketId"></component>
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<h4 :id="titleId" :class="titleClass">工单详情</h4>
|
||||||
|
<el-button type="danger" @click="close">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
<component :is="currentComponent" :ticketId="ticketId" :modelId="modelId"></component>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineAsyncComponent } from 'vue'; // 异步组件加载
|
import { defineAsyncComponent, markRaw } from 'vue'; // 异步组件加载
|
||||||
|
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
|
||||||
export default {
|
export default {
|
||||||
name: "myticket",
|
name: "myticket",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
actStateEnum, interveneTypeEnum,
|
||||||
drawer: false,
|
drawer: false,
|
||||||
tvalue: "待办",
|
tvalue: "待办",
|
||||||
toptions: {
|
toptions: {
|
||||||
|
@ -189,6 +179,7 @@ export default {
|
||||||
wfOptions: [],
|
wfOptions: [],
|
||||||
currentComponent: null,
|
currentComponent: null,
|
||||||
ticketId: null,
|
ticketId: null,
|
||||||
|
modelId: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -213,7 +204,7 @@ export default {
|
||||||
reStart(row) {
|
reStart(row) {
|
||||||
this.$API.wf.ticket.retryScript.req(row.id).then((res) => {
|
this.$API.wf.ticket.retryScript.req(row.id).then((res) => {
|
||||||
this.$message.success("任务执行下发成功");
|
this.$message.success("任务执行下发成功");
|
||||||
// this.$refs.table.refresh();
|
row.script_run_last_result = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
|
@ -229,11 +220,12 @@ export default {
|
||||||
handleShow(row) {
|
handleShow(row) {
|
||||||
this.drawer = true;
|
this.drawer = true;
|
||||||
this.ticketId = row.id;
|
this.ticketId = row.id;
|
||||||
|
this.modelId = row.ticket_data.t_id;
|
||||||
const viewPath = row.workflow_.view_path;
|
const viewPath = row.workflow_.view_path;
|
||||||
// 动态 import
|
// 动态 import
|
||||||
this.currentComponent = defineAsyncComponent(() =>
|
this.currentComponent = markRaw(
|
||||||
import(`@/views${viewPath}.vue`)
|
defineAsyncComponent(() => import(`@/views${viewPath}.vue`))
|
||||||
)
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,177 @@
|
||||||
<template>
|
<template>
|
||||||
<el-container>
|
<el-collapse v-model="activeNames">
|
||||||
xxx
|
<el-collapse-item title="基本信息" name="1">
|
||||||
</el-container>
|
<el-descriptions :column="1">
|
||||||
|
<el-descriptions-item>
|
||||||
|
<span style="color:darkblue;margin-right: 4px;">({{ ticketDetail.sn }})</span>{{ ticketDetail.title
|
||||||
|
}}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="当前:">
|
||||||
|
<el-tag type="info" effect="plain">{{ ticketDetail.state_.name }}</el-tag>
|
||||||
|
<el-tag :type="actStateEnum[ticketDetail.act_state]?.type" effect="plain">
|
||||||
|
{{ actStateEnum[ticketDetail.act_state]?.text }}
|
||||||
|
</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item title="操作" name="2" v-if="actionShow">
|
||||||
|
<el-input type="textarea" :rows="2" v-model="handleForm.suggestion" placeholder="处理意见" />
|
||||||
|
<el-row>
|
||||||
|
<el-col :xs="24" :md="12" style="padding: 1px">
|
||||||
|
<el-button :loading="submitLoading" :disabled="submitLoading" v-for="item in transitions"
|
||||||
|
:key="item.id" size="small" :type="item.attribute_type === 2 ? 'danger' : 'primary'
|
||||||
|
" @click="handleTransition(item.id)">
|
||||||
|
{{ item.name }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :md="12" style="text-align: right;padding: 1px">
|
||||||
|
<el-button v-if="ticketDetail.state_.enable_retreat && isOwn" type="danger" size="small"
|
||||||
|
@click="handleRetreat">撤回</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item title="审批历史" name="3">
|
||||||
|
<div style="padding:1px"><el-timeline>
|
||||||
|
<el-timeline-item v-for="item in ticketLog" :key="item.id" :timestamp="item.create_time"
|
||||||
|
:color="getColor(item)">
|
||||||
|
<div>
|
||||||
|
<strong>{{ item.state_?.name || "未知状态" }}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span v-if="item.intervene_type != 0"><el-tag
|
||||||
|
:type="interveneTypeEnum[item.intervene_type]?.type" effect="plain">
|
||||||
|
{{ interveneTypeEnum[item.intervene_type]?.text }}
|
||||||
|
</el-tag></span>
|
||||||
|
<span v-if="item.transition_"
|
||||||
|
:style="{ color: item.transition_.attribute_type === 1 ? '#67C23A' : '#F56C6C' }">
|
||||||
|
{{ item.transition_.name }}
|
||||||
|
</span>
|
||||||
|
<span v-if="item.participant_">-{{ item.participant_.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="item.suggestion">
|
||||||
|
<el-tooltip v-if="item.suggestion.length > 20" class="box-item" effect="dark"
|
||||||
|
:content="item.suggestion" placement="top">
|
||||||
|
<span>{{ item.suggestion.slice(0, 20) + "..." }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
<span v-else>
|
||||||
|
{{ item.suggestion }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-timeline-item>
|
||||||
|
</el-timeline></div>
|
||||||
|
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref, defineProps, onMounted } from "vue";
|
||||||
|
import { actStateEnum, interveneTypeEnum } from "@/utils/enum.js";
|
||||||
|
import API from '@/api';
|
||||||
|
import TOOL from "@/utils/tool.js";
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
const props = defineProps({
|
||||||
|
ticketId: { type: String, required: true, default: null },
|
||||||
|
ticket_data: { type: Object, default: null },
|
||||||
|
});
|
||||||
|
const currentUser = ref(TOOL.data.get("USER_INFO").id)
|
||||||
|
const actionShow = ref(false);
|
||||||
|
const isOwn = ref(false);
|
||||||
|
const activeNames = ref(['1', '3']);
|
||||||
|
const ticketDetail = ref({
|
||||||
|
state_: {}
|
||||||
|
});
|
||||||
|
const ticketLog = ref([]);
|
||||||
|
const handleForm = ref({
|
||||||
|
suggestion: ""
|
||||||
|
})
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('props.ticketId', props.ticketId)
|
||||||
|
if (props.ticketId) {
|
||||||
|
getTicketDetail();
|
||||||
|
getTicketLog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const refreshTicket = async () => {
|
||||||
|
actionShow.value = false
|
||||||
|
isOwn.value = false
|
||||||
|
transitions.value = []
|
||||||
|
handleForm.value.suggestion = ''
|
||||||
|
ticketLog.value = []
|
||||||
|
activeNames.value = ['1', '3'] // 根据需要恢复初始展开项
|
||||||
|
getTicketDetail()
|
||||||
|
getTicketLog()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTicketDetail = () => {
|
||||||
|
API.wf.ticket.ticketItem.req(props.ticketId).then(res => {
|
||||||
|
ticketDetail.value = res;
|
||||||
|
if (res.create_by === currentUser.value) {
|
||||||
|
isOwn.value = true;
|
||||||
|
actionShow.value = true;
|
||||||
|
if (!activeNames.value.includes('2')) activeNames.value.push('2')
|
||||||
|
}
|
||||||
|
if (res.participant_type == 1 && res.participant === currentUser.value) {
|
||||||
|
actionShow.value = true;
|
||||||
|
if (!activeNames.value.includes('2')) activeNames.value.push('2')
|
||||||
|
getTransitions();
|
||||||
|
}
|
||||||
|
if (res.participant_type == 2 && res.participant.includes(currentUser.value)) {
|
||||||
|
actionShow.value = true;
|
||||||
|
if (!activeNames.value.includes('2')) activeNames.value.push('2')
|
||||||
|
getTransitions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTransitions = () => {
|
||||||
|
API.wf.ticket.ticketTransitions.req(props.ticketId).then(res => {
|
||||||
|
transitions.value = res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTicketLog = () => {
|
||||||
|
API.wf.ticket.ticketFlowlogs.req(props.ticketId).then(res => {
|
||||||
|
ticketLog.value = res;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColor(item) {
|
||||||
|
if (item.transition_?.attribute_type === 1) return "#67C23A"; // 同意 绿色
|
||||||
|
if (item.transition_?.attribute_type === 2) return "#F56C6C"; // 拒绝 红色
|
||||||
|
return "#909399"; // 默认灰色
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRetreat = () => {
|
||||||
|
ElMessageBox.confirm("确认撤回吗?", "温馨提示", {
|
||||||
|
confirmButtonText: "确认",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}).then(() => {
|
||||||
|
API.wf.ticket.ticketRetreat
|
||||||
|
.req(props.ticketId, handleForm.value)
|
||||||
|
.then((res) => {
|
||||||
|
refreshTicket();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitLoading = ref(false);
|
||||||
|
const transitions = ref([]);
|
||||||
|
const handleTransition = (transitionId) => {
|
||||||
|
let params = new Object();
|
||||||
|
params.transition = transitionId;
|
||||||
|
if (props.ticket_data) {
|
||||||
|
params.ticket_data = props.ticket_data;
|
||||||
|
}else{
|
||||||
|
params.ticket_data = {};
|
||||||
|
}
|
||||||
|
params.suggestion = handleForm.value.suggestion;
|
||||||
|
submitLoading.value = true;
|
||||||
|
API.wf.ticket.ticketHandle.req(props.ticketId, params).then((res) => {
|
||||||
|
submitLoading.value = false;
|
||||||
|
refreshTicket();
|
||||||
|
}).catch((e) => {
|
||||||
|
submitLoading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
|
@ -0,0 +1,95 @@
|
||||||
|
<template>
|
||||||
|
<el-button
|
||||||
|
v-for="item in transitions"
|
||||||
|
:key="item.id"
|
||||||
|
type="primary"
|
||||||
|
:loading="isSaveing"
|
||||||
|
:disabled="isSaveing"
|
||||||
|
@click="submit(item.id)"
|
||||||
|
style="margin-right: 2px"
|
||||||
|
>{{ item.name }}</el-button>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted, defineEmits } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import API from '@/api';
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
workflow_key: {type: String, default: null, required: false},
|
||||||
|
ticketId: {type: String, default: null, required: false},
|
||||||
|
t_id: {type: String, default: null, required: true},
|
||||||
|
title: {type: String, default: null, required: false},
|
||||||
|
submit_b_func: {type: Function, default: null, required: false},
|
||||||
|
ticket_data: {type: Object, default: null, required: false},
|
||||||
|
})
|
||||||
|
|
||||||
|
const workflow = ref(null);
|
||||||
|
const transitions = ref([]);
|
||||||
|
onMounted(async () => {
|
||||||
|
if (props.ticketId) {
|
||||||
|
API.wf.ticket.ticketTransitions.req(props.ticketId).then(res => {
|
||||||
|
transitions.value = res;
|
||||||
|
});
|
||||||
|
}else if (props.workflow_key) {
|
||||||
|
let res = await API.wf.workflow.initkey.req(props.workflow_key);
|
||||||
|
transitions.value = res.transitions;
|
||||||
|
workflow.value = res.workflow
|
||||||
|
}else{
|
||||||
|
ElMessage.error("缺少workflow_key或ticketId");
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
const isSaveing = ref(false);
|
||||||
|
|
||||||
|
const emit = defineEmits(["success"]);
|
||||||
|
const submit = async (transition_id) => {
|
||||||
|
isSaveing.value = true;
|
||||||
|
if (props.submit_b_func) {
|
||||||
|
await props.submit_b_func();
|
||||||
|
}
|
||||||
|
if (props.ticketId != null) {
|
||||||
|
let params = new Object();
|
||||||
|
params.transition = transition_id;
|
||||||
|
if (props.ticket_data) {
|
||||||
|
params.ticket_data = props.ticket_data;
|
||||||
|
}else{
|
||||||
|
params.ticket_data = {};
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
let res = await API.wf.ticket.ticketHandle.req(props.ticketId, params);
|
||||||
|
isSaveing.value = false;
|
||||||
|
ElMessage.success("提交成功");
|
||||||
|
emit("success", props.ticketId)
|
||||||
|
} catch (e) {
|
||||||
|
isSaveing.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let ticket = {};
|
||||||
|
ticket.title = props.title;
|
||||||
|
ticket.workflow = workflow.value;
|
||||||
|
if (props.t_id != null && props.t_id != undefined) {
|
||||||
|
ticket.ticket_data = {
|
||||||
|
t_id: props.t_id,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ElMessage.error("缺少t_id");
|
||||||
|
isSaveing.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket.transition = transition_id;
|
||||||
|
try {
|
||||||
|
let res = await API.wf.ticket.create.req(ticket);
|
||||||
|
isSaveing.value = false;
|
||||||
|
ElMessage.success("提交成功");
|
||||||
|
emit("success", res.id)
|
||||||
|
} catch (e) {
|
||||||
|
isSaveing.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
|
||||||
|
</el-main>
|
||||||
|
<el-aside width="30%">
|
||||||
|
<ticketd :ticketId="props.ticketId"></ticketd>
|
||||||
|
</el-aside>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, defineProps, onMounted} from "vue";
|
||||||
|
import ticketd from './ticketd.vue'
|
||||||
|
import API from '@/api'
|
||||||
|
const props = defineProps({
|
||||||
|
ticketId: { type: String, required: false, default: null }
|
||||||
|
});
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
Loading…
Reference in New Issue