Compare commits

...

2 Commits

6 changed files with 331 additions and 34 deletions

View File

@ -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;
} }

View File

@ -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': ['主要辅材','办公辅料','设备维护辅料','包装辅材','标识辅材','防护辅材','其他辅材','常规辅材','医护辅材','检测辅材','倒角辅材','减薄辅材','磨抛辅材','多线切辅材','精雕辅材','扫边辅材','黑化辅材']
}) })

View File

@ -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`))
) );
}, },
}, },
}; };

View File

@ -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>

View File

@ -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>

View File

@ -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>