|
|
@@ -0,0 +1,331 @@
|
|
|
+<!--
|
|
|
+ * @Author: tengmingxue 1473375109@qq.com
|
|
|
+ * @Date: 2023-08-30 17:25:03
|
|
|
+ * @LastEditors: tengmingxue 1473375109@qq.com
|
|
|
+ * @LastEditTime: 2023-09-25 16:25:12
|
|
|
+ * @FilePath: \xld-gis-admin\src\views\dataAdmin\dataAdmin\flowStep\index.vue
|
|
|
+ * @Description: 流程图表
|
|
|
+-->
|
|
|
+<template>
|
|
|
+ <div class="flow-chart">
|
|
|
+ <div class="flow-title">{{ flowTitle }}流程信息</div>
|
|
|
+ <div class="flow-code">
|
|
|
+ <span>流程编号:</span>
|
|
|
+ <span>{{ flowCode }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend">
|
|
|
+ <template v-for="legend in legends" :key="legend.key">
|
|
|
+ <div class="item-list">
|
|
|
+ <span class="item-span-legend" :style="`background-color:${legend.color};`"></span>
|
|
|
+ <span class="item-span">{{ legend.name }}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <div class="flow">
|
|
|
+ <a-steps>
|
|
|
+ <template v-for="(step, index) in steps" :key="step.xh">
|
|
|
+ <!-- status 1:已完成,2:进行中,3:驳回,0:未开始 -->
|
|
|
+ <a-step :status="status[step.status]">
|
|
|
+ <template #title>
|
|
|
+ <div class="step-title">{{ step.stepName }}</div>
|
|
|
+ </template>
|
|
|
+ <template #icon>
|
|
|
+ <div class="cicle-out">
|
|
|
+ <div
|
|
|
+ class="cicle"
|
|
|
+ :style="`border: 2px solid ${colors[step.status]};color:${colors[step.status]};`"
|
|
|
+ >{{ index + 1 }}</div
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #description>
|
|
|
+ <!-- <div class="desc-step-name">{{ step.stepName }}</div> -->
|
|
|
+ <div class="desc-handler">
|
|
|
+ <template v-for="user in step.handlers" :key="user.id">
|
|
|
+ <span class="handler-name" :style="`background-color:${colors[user.status]};`" :title="user.handler">{{
|
|
|
+ user.handler
|
|
|
+ }}</span>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </a-step>
|
|
|
+ </template>
|
|
|
+ </a-steps>
|
|
|
+ </div>
|
|
|
+ <div class="log-table">
|
|
|
+ <handle-log :flowStatus="flowStatus"></handle-log>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import { defineComponent, ref, watch, reactive, onMounted, nextTick, toRefs } from 'vue';
|
|
|
+// 引入封装的table
|
|
|
+import { BasicTable, TableAction, useTable } from '/@/components/Table';
|
|
|
+// 引入封装的权限识别
|
|
|
+import { Authority } from '/@/components/Authority';
|
|
|
+// 引入搜索框和表格表头
|
|
|
+import { columns, searchFormSchema } from './flowData';
|
|
|
+// 引入删除
|
|
|
+import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
|
|
|
+import { message, Popconfirm } from 'ant-design-vue';
|
|
|
+import { useMessage } from '/@/hooks/web/useMessage';
|
|
|
+import HandleLog from './handleLog.vue';
|
|
|
+import { session } from '/@/utils/Memory.js';
|
|
|
+import { getFlowConfigByBusinessName } from '/@/api/resource/examine';
|
|
|
+import { getAccountList } from '/@/api/system/system';
|
|
|
+const props = {
|
|
|
+ flowTitle: { type: String, require: true },
|
|
|
+ flowCode: { type: String, default: '' },
|
|
|
+ flowStatus: { type: String, default: '1' }, //流程状态 1,新增 2 审核
|
|
|
+};
|
|
|
+export default defineComponent({
|
|
|
+ components: { BasicTable, Authority, Popconfirm, TableAction, HandleLog },
|
|
|
+ props,
|
|
|
+ setup(props, { emit }) {
|
|
|
+ const data = reactive({
|
|
|
+ flowTitle: ref(props.flowTitle),
|
|
|
+ flowCode: ref(props.flowCode),
|
|
|
+ flowName: props.flowTitle,
|
|
|
+ flowStatus: props.flowStatus, //流程状态 1,新增 2 审核
|
|
|
+ sysUserInfo: {},
|
|
|
+ legends: [
|
|
|
+ { key: 1, name: '已完成', color: '#67C23A' },
|
|
|
+ { key: 2, name: '进行中', color: '#2D74E7' },
|
|
|
+ { key: 3, name: '驳回', color: '#E6A23C' },
|
|
|
+ { key: 4, name: '未开始', color: '#989898' },
|
|
|
+ ],
|
|
|
+ colors: ['#989898', '#67C23A', '#2D74E7', '#E6A23C'],
|
|
|
+ status: ['wait', 'finish', 'process', 'back'],
|
|
|
+ steps: [
|
|
|
+ //status 1:已完成,2:进行中,3:驳回,0:未开始
|
|
|
+ // {
|
|
|
+ // xh: 1,
|
|
|
+ // stepName: '地图资源上传',
|
|
|
+ // handlers: [{ handler: '张三', id: '1', status: '1' }],
|
|
|
+ // status: '1',
|
|
|
+ // },
|
|
|
+ // { xh: 6, stepName: '完成', handlers: [], status: '0' },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+ const { createMessage } = useMessage();
|
|
|
+ /**
|
|
|
+ * 获取系统人员信息,并存为字典
|
|
|
+ */
|
|
|
+ const queryAllUserInfos = async () => {
|
|
|
+ const res = await getAccountList({ page: 1, pageSize: 999 });
|
|
|
+ if (res) {
|
|
|
+ res.items.map((item) => {
|
|
|
+ data.sysUserInfo[item['EMPLOYEE_ID']] = item['NAME'];
|
|
|
+ });
|
|
|
+ }
|
|
|
+ console.log('人员信息',data.sysUserInfo)
|
|
|
+ };
|
|
|
+ const queryData = async () => {
|
|
|
+ const res = await getFlowConfigByBusinessName(data.flowName);
|
|
|
+ console.log('地图资源上传配置信息', res);
|
|
|
+ if (res) {
|
|
|
+ setFlowNodes(res);
|
|
|
+ } else {
|
|
|
+ createMessage.error(`获取流程【${data.flowName}】配置信息异常!请联系管理员检查!`);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const setFlowNodes = async (flow) => {
|
|
|
+ if (!flow?.flowInfo || !flow?.flowNode || !flow?.flowNodePerson) {
|
|
|
+ createMessage.error(`获取流程【${data.flowName}】配置信息异常!请联系管理员检查!`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (flow?.flowNode.length === 0) {
|
|
|
+ createMessage.error(`流程【${data.flowName}】未配置审核步骤!请联系管理员配置!`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const user = session.getItem('userInfo');
|
|
|
+ data.steps = [
|
|
|
+ {
|
|
|
+ xh: 0,
|
|
|
+ stepName: flow.flowInfo['FLOWNAME'],
|
|
|
+ handlers: [
|
|
|
+ { handler: user['EMPLOYEE']['NAME'], id: user['EMPLOYEE']['EMPLOYEE_ID'], status: '1' },
|
|
|
+ ],
|
|
|
+ status: '1', //status 1:已完成,2:进行中,3:驳回,0:未开始
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ const step = getFlowNodes(flow.flowNode, flow.flowNodePerson);
|
|
|
+ console.log('步骤',step)
|
|
|
+ if(step) data.steps.push(...step)
|
|
|
+ const length = step.length
|
|
|
+ //最后一步默认完成
|
|
|
+ data.steps.push({ xh: length+2, stepName: '完成', handlers: [], status: '0' })
|
|
|
+ };
|
|
|
+
|
|
|
+ const getFlowNodes = (flowNode, flowNodePerson) => {
|
|
|
+ let index = 1;
|
|
|
+ let steps = [];
|
|
|
+ function getNextNode(nodes, id) {
|
|
|
+ const node = flowNode.find((item) => item['PRENODEID'] === id);
|
|
|
+ if (node) {
|
|
|
+ const eximPersons = flowNodePerson.filter((item) => item['FLOWNODEID'] === node['ID']);
|
|
|
+ let handlers = [];
|
|
|
+ eximPersons.map((item) => {
|
|
|
+ handlers.push({
|
|
|
+ handler: data.sysUserInfo[item['USERID']],
|
|
|
+ id: item['USERID'],
|
|
|
+ status: '0',
|
|
|
+ });
|
|
|
+ });
|
|
|
+ steps.push({
|
|
|
+ xh: (index = index + 1),
|
|
|
+ stepName: node['NODENAME'],
|
|
|
+ handlers: handlers,
|
|
|
+ status: '0',
|
|
|
+ });
|
|
|
+ getNextNode(nodes, node['ID']); //递归
|
|
|
+ }
|
|
|
+ else return false;
|
|
|
+ }
|
|
|
+ getNextNode(flowNode,'')
|
|
|
+ return steps
|
|
|
+ };
|
|
|
+
|
|
|
+ // 生命周期函数
|
|
|
+ onMounted(() => {
|
|
|
+ queryAllUserInfos();
|
|
|
+ queryData();
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...toRefs(data),
|
|
|
+ createMessage,
|
|
|
+ queryData,
|
|
|
+ setFlowNodes,
|
|
|
+ getFlowNodes,
|
|
|
+ };
|
|
|
+ },
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+ <style lang="scss" scoped>
|
|
|
+.flow-chart {
|
|
|
+ height: 100%;
|
|
|
+ .flow-title {
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ line-height: 40px;
|
|
|
+ text-align: center;
|
|
|
+ font-family: Source Han Sans CN;
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 300;
|
|
|
+ letter-spacing: 0px;
|
|
|
+ color: #2d74e7;
|
|
|
+ }
|
|
|
+ .flow-code {
|
|
|
+ height: 20px;
|
|
|
+ text-align: center;
|
|
|
+ font-family: Source Han Sans CN;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 300;
|
|
|
+ letter-spacing: 0px;
|
|
|
+ color: rgba(0, 0, 0, 0.6);
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .legend {
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ top: 53px;
|
|
|
+ height: 100px;
|
|
|
+ width: 72px;
|
|
|
+ .item-list {
|
|
|
+ margin: 4px 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ .item-span-legend {
|
|
|
+ display: flex;
|
|
|
+ height: 10px;
|
|
|
+ width: 10px;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+ .item-span {
|
|
|
+ font-family: Source Han Sans CN;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 300;
|
|
|
+ line-height: normal;
|
|
|
+ letter-spacing: 0px;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow {
|
|
|
+ height: 140px;
|
|
|
+ width: 100%;
|
|
|
+ padding: 0 20px;
|
|
|
+
|
|
|
+ :deep(.ant-steps) {
|
|
|
+ height: 100%;
|
|
|
+ .ant-steps-item {
|
|
|
+ margin-right: 0px !important;
|
|
|
+ height: 100%;
|
|
|
+ .ant-steps-item-container {
|
|
|
+ margin-top: 20px;
|
|
|
+ height: 100%;
|
|
|
+ .ant-steps-item-content {
|
|
|
+ position: absolute;
|
|
|
+ height: 100%;
|
|
|
+ width: 100%;
|
|
|
+ margin-top: 20px;
|
|
|
+ left: 16px;
|
|
|
+ .ant-steps-item-title {
|
|
|
+ .step-title {
|
|
|
+ position: absolute;
|
|
|
+ top: -33px;
|
|
|
+ left: -16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .ant-steps-item-description {
|
|
|
+ margin-left: -16px;
|
|
|
+ .desc-step-name {
|
|
|
+ margin-top: 4px;
|
|
|
+ }
|
|
|
+ .desc-handler {
|
|
|
+ margin-top: 38px;
|
|
|
+ .handler-name {
|
|
|
+ display: flex;
|
|
|
+ float: left;
|
|
|
+ height: 36px;
|
|
|
+ line-height: 36px;
|
|
|
+ width: 44px;
|
|
|
+ margin-right: 3px;
|
|
|
+ justify-content: center;
|
|
|
+ color: #fff;
|
|
|
+ background-color: #2d74e7;
|
|
|
+ border-radius: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .ant-steps-item-icon {
|
|
|
+ margin-top: 20px;
|
|
|
+ margin-right: 0px;
|
|
|
+ .cicle-out {
|
|
|
+ height: 40px;
|
|
|
+ width: 40px;
|
|
|
+ .cicle {
|
|
|
+ height: 30px;
|
|
|
+ width: 30px;
|
|
|
+ line-height: 24px;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .log-table {
|
|
|
+ height: calc(100% - 374px);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|