任务加上需求附件查看按钮,项目列表加上导出功能,流程列表加上审批详情查看,流程连接线改为曲线,预览流程加上详情预览

This commit is contained in:
weibl
2025-11-27 16:26:51 +08:00
parent 9fe11ed556
commit ab57d20ef4
12 changed files with 203 additions and 38 deletions

View File

@@ -1,4 +1,4 @@
import { get, post } from '@/api/request';
import { download, get, post } from '@/api/request';
const env = import.meta.env;
const PREFIX = env.VITE_API_PREFIX_PROJECT;
@@ -99,3 +99,7 @@ export const addTaskForDataApi = (params: any) => {
export const addNodeForDataApi = (params: any) => {
return post(`${PREFIX}node/addNodeForData`, params);
};
export const exportProjectApi = (params: any, filename:string) => {
return download(`${PREFIX}node/exportProject`, params, filename);
};

View File

@@ -6,7 +6,7 @@
show-footer
>
<div class="monaco-editor-box">
<MonacoEditor ref="monacoRef" @saveHandle="saveEdit" :fileId="fileId" :idIndex="idIndex"></MonacoEditor>
<MonacoEditor :readonly="readonly" ref="monacoRef" @saveHandle="saveEdit" :fileId="fileId" :idIndex="idIndex"></MonacoEditor>
</div>
<!-- <template #footer>
<div>
@@ -27,11 +27,13 @@ const props = withDefaults(
idIndex: string;
fileId:string;
showDialog: boolean;
readonly: boolean;
}>(),
{
fileId: '',
showDialog: false,
idIndex: '',
readonly: false,
}
);
const emits = defineEmits(['update:showDialog', 'closeHandle', 'saveHandle']);

View File

@@ -87,7 +87,7 @@ const saveFile = async () => {
form.append('scriptFileId ', props.fileId);
form.append('fileName ', fileTitle.value);
form.append('updateFile ', new Blob([currentValue], { type: 'text/txt' }));
const res = await upload(`${PREFIX}data/updateScriptFile`, form);
const res:any = await upload(`${PREFIX}data/updateScriptFile`, form);
// const res = await fragmentUpload(
// false,
@@ -95,7 +95,7 @@ const saveFile = async () => {
// fileParentPath.value,
// fileTitle.value
// );
if (!res) {
if (res.code === 200) {
ElMessage.success('修改成功!');
text.value = toRaw(editor.value).getValue();
isChange.value = false;

View File

@@ -0,0 +1,93 @@
<template>
<el-drawer
v-model="drawerVisible"
direction="rtl"
resizable
:modal="true"
:modal-penetrable="true"
:with-header="false"
size="640"
append-to-body
>
<el-tabs v-model="activeName" class="flow-view-tabs" @tab-click="handleClick">
<el-tab-pane label="属性配置" name="attributeConfig">
<AttributeConfig readonly :nodeAttribute="nodeAttribute" ></AttributeConfig>
</el-tab-pane>
<el-tab-pane label="界面配置" name="pageConfig">
<!-- <PageConfig :nodeAttribute="nodeAttribute" ref="pageConfigRef"></PageConfig> -->
</el-tab-pane>
</el-tabs>
<template #footer>
<el-button @click="closeFun">关闭</el-button>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue';
import AttributeConfig from '@/views/simulation/creation/components/attributeConfig.vue';
const props = defineProps({
drawerVisible: {
type: Boolean,
default: false,
},
nodeAttribute: {
type: Object,
default: () => {
return {};
},
},
});
const emits = defineEmits(['update:drawerVisible', 'update:nodeAttribute']);
const drawerVisible = computed({
get() {
return props.drawerVisible;
},
set(value) {
emits('update:drawerVisible', value);
},
});
const closeFun = () => {
emits('update:drawerVisible', false);
};
const activeName = ref('attributeConfig');
const handleClick = () => {
};
onMounted(() => {
});
</script>
<style lang="scss">
.flow-view-tabs {
.el-drawer {
box-shadow: none;
}
.el-drawer__body {
padding: 0 0;
}
.el-tabs__header {
margin-bottom: 0;
}
.el-tabs__nav-scroll {
display: flex;
justify-content: center;
}
.el-tabs__item {
// width: 200px;
padding: 0 60px;
font-weight: 600;
}
}
</style>
<style lang="scss" scoped>
</style>

View File

@@ -27,10 +27,11 @@
</div>
</div>
<TeleportContainer />
<FlowConfig v-model="drawerVisible" :nodeAttribute="nodeAttribute"></FlowConfig>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref } from 'vue';
import { onMounted, ref } from 'vue';
import { getTeleport } from '@antv/x6-vue-shape';
import { queryFlowTemplateDetailApi, queryFlowTemplateVersionApi } from '@/api/capability/flow';
import { ElMessage } from 'element-plus';
@@ -38,6 +39,7 @@ import { FLOW_APPROVE_MAP } from '@/utils/enum/flow';
import { Graph } from '@antv/x6';
import { createNode, getNodeList } from '@/views/simulation/creation/components/stencil';
import { registerCustomNode } from '@/views/simulation/creation/components/registerNode';
import FlowConfig from './flowConfig.vue';
const props = defineProps({
flowUuid: {
@@ -68,6 +70,10 @@ const TeleportContainer = getTeleport();
const graph = ref<any>();
const nodeAttribute = ref();
const drawerVisible = ref(false);
const getFlowVersionOptions = async() => {
const params:any = {};
if (props.flowUuid) {
@@ -148,7 +154,8 @@ const initGraph = async() => {
graph.value.on('node:click', ({ node }:any) => {
console.log('click node', node);
if (node.data.isApp) {
nodeAttribute.value = node.data;
drawerVisible.value = true;
}
});
};

View File

@@ -26,7 +26,7 @@
</el-tooltip>
</span>
</div>
<el-radio-group v-model="nodeCondition">
<el-radio-group :disabled="readonly" v-model="nodeCondition">
<el-radio value="and"></el-radio>
<el-radio value="or"></el-radio>
</el-radio-group>
@@ -45,7 +45,7 @@
</el-tooltip>
</span>
</div>
<el-radio-group v-model="exeMethod">
<el-radio-group :disabled="readonly" v-model="exeMethod">
<el-radio value="serviceTask">自动</el-radio>
<el-radio value="userTask">手动</el-radio>
</el-radio-group>
@@ -54,6 +54,7 @@
<div class="title">
<span>节点前脚本</span>
<el-upload
v-if="!readonly"
class="upload-btn"
:multiple="true"
:auto-upload="false"
@@ -80,7 +81,7 @@
<div class="code-box" v-if="item.isPreview">
<div class="code-header">
<span class="s-name">脚本代码</span>
<div class="edit-code" @click="openCodeDialogFun(item.fileId)">在IDE中编辑</div>
<div class="edit-code" @click="openCodeDialogFun(item.fileId)">在IDE中{{ readonly?'查看':'编辑' }}</div>
</div>
<div class="code-text">
<MonacoEditor :idIndex="item.fileId + item.name" readonly :file-id="item.fileId"></MonacoEditor>
@@ -93,6 +94,7 @@
<div class="title">
<span>节点后脚本</span>
<el-upload
v-if="!readonly"
class="upload-btn"
:multiple="true"
:auto-upload="false"
@@ -106,7 +108,7 @@
<div class="s-name">脚本名称</div>
<div class="operation">
<el-input v-model="item.name" class="el-input"></el-input>
<span class="code-view-btn">
<span class="code-view-btn" v-if="!readonly">
<img src="@/assets/imgs/dragFlow/open-code.svg" v-if="!item.isPreview" @click="changeReviewFun('post',index)" alt="">
<img class="select-ing" src="@/assets/imgs/dragFlow/close-code.png" v-else @click="changeReviewFun('post',index)" alt="">
</span>
@@ -119,7 +121,7 @@
<div class="code-box" v-if="item.isPreview">
<div class="code-header">
<span class="s-name">脚本代码</span>
<div class="edit-code" @click="openCodeDialogFun(item.fileId)">在IDE中编辑</div>
<div class="edit-code" @click="openCodeDialogFun(item.fileId)">在IDE中{{ readonly?'查看':'编辑' }}</div>
</div>
<div class="code-text">
<MonacoEditor :idIndex="item.fileId + item.name" readonly :file-id="item.fileId"></MonacoEditor>
@@ -129,22 +131,27 @@
</div>
</div>
<div class="item-box">
<div class="title">执行命令</div>
<el-input v-model="exeCommand" placeholder="请输入执行命令" class="select-version">
<div class="title">前脚本执行命令</div>
<el-input :disabled="readonly" v-model="preExeCommand" placeholder="请输入执行命令" class="select-version">
</el-input>
</div>
<div class="item-box">
<div class="title">后脚本执行命令</div>
<el-input :disabled="readonly" v-model="postExeCommand" placeholder="请输入执行命令" class="select-version">
</el-input>
</div>
<div class="item-box">
<div class="title">输入文件格式</div>
<el-input v-model="inputFormat" placeholder="请输入正则表达式" class="select-version">
<el-input :disabled="readonly" v-model="inputFormat" placeholder="请输入正则表达式" class="select-version">
</el-input>
</div>
<div class="item-box">
<div class="title">输出文件格式</div>
<el-input v-model="outputFormat" placeholder="请输入正则表达式" class="select-version">
<el-input :disabled="readonly" v-model="outputFormat" placeholder="请输入正则表达式" class="select-version">
</el-input>
</div>
</div>
<FleEdit v-model:showDialog="showCodeEdit" :file-id="editFileId" :idIndex="editFileId+'dialog'"></FleEdit>
<FleEdit :readonly="readonly" v-model:showDialog="showCodeEdit" :file-id="editFileId" :idIndex="editFileId+'dialog'"></FleEdit>
</template>
<script setup lang="ts">
@@ -160,6 +167,10 @@ const props = defineProps({
type: Object,
default: () => ({}),
},
readonly: {
type: Boolean,
default: false,
},
});
const env = import.meta.env;
@@ -176,7 +187,7 @@ const PREFIX = env.VITE_API_PREFIX_DATA;
const inputFormat = computed({
get() {
return props.nodeAttribute.inputFormat;
return props.nodeAttribute.inputFormat || '';
},
set(val) {
updateNodeAttribute({ inputFormat: val });
@@ -185,25 +196,34 @@ const inputFormat = computed({
const outputFormat = computed({
get() {
return props.nodeAttribute.outputFormat;
return props.nodeAttribute.outputFormat || '';
},
set(val) {
updateNodeAttribute({ outputFormat: val });
},
});
const exeCommand = computed({
const preExeCommand = computed({
get() {
return props.nodeAttribute.exeCommand;
return props.nodeAttribute.preExeCommand || '';
},
set(val) {
updateNodeAttribute({ exeCommand: val });
updateNodeAttribute({ preExeCommand: val });
},
});
const postExeCommand = computed({
get() {
return props.nodeAttribute.postExeCommand || '';
},
set(val) {
updateNodeAttribute({ postExeCommand: val });
},
});
const nodeCondition = computed({
get() {
return props.nodeAttribute.nodeCondition;
return props.nodeAttribute.nodeCondition || 'and';
},
set(val) {
updateNodeAttribute({ nodeCondition: val });
@@ -212,7 +232,7 @@ const nodeCondition = computed({
const exeMethod = computed({
get() {
return props.nodeAttribute.exeMethod;
return props.nodeAttribute.exeMethod || 'serviceTask';
},
set(val) {
updateNodeAttribute({ exeMethod: val });

View File

@@ -31,6 +31,8 @@ export const initGraph = async () => {
// vertexMovable: true,
// },
connecting: {
connector: { name: 'smooth' },
connectionPoint: 'anchor',
router: 'normal',
// connector: {
// name: 'curveConnector',

View File

@@ -50,7 +50,7 @@ export const initNodeEvents = (graph: any) => {
if (node.data.isApp) {
drawerVisible.value = true;
updateNodeAttribute(node.data);
// selectNode = node;
selectNode = node;
// for (const key in node.data) {
// nodeAttribute[key] = node.data[key];
// }
@@ -116,7 +116,8 @@ export const nodeAttribute = reactive<any>({
iconUrl: '',
preScripts: [],
postScripts: [],
exeCommand: '', // 执行命令
postExeCommand: '', // 执行命令
preExeCommand: '', // 执行命令
nodeCondition: 'and', // 节点条件
exeMethod: 'serviceTask', // 执行方式
inputFormat: '', // 输入文件格式

View File

@@ -114,6 +114,12 @@ export const createNode = (nodeListObj:any, graph:any, stencil?:any) => {
preScripts: [],
postScripts: [],
pageConfigList: [],
postExeCommand: '', // 执行命令
preExeCommand: '', // 执行命令
nodeCondition: 'and', // 节点条件
exeMethod: 'serviceTask', // 执行方式
inputFormat: '', // 输入文件格式
outputFormat: '', // 输出文件格式
},
})
);

View File

@@ -75,7 +75,7 @@
</div>
</template>
<template #leftOptions>
<el-button v-if="flowType === FLOW_TEMPLATE_PUBLIC_STATUS.PRIVATE" icon="plus" @click="openDiaFun('create')" type="primary">
<el-button v-if="flowType !== FLOW_TEMPLATE_PUBLIC_STATUS.PUBLIC" icon="plus" @click="openDiaFun('create')" type="primary">
{{ $t('项目列表.新增') }}
</el-button>
</template>
@@ -90,10 +90,14 @@
:class="row.approveType === FLOW_APPROVE_STATUS_ENUM.NOT_APPROVED?
'dot dot-in-precess':
row.approveType === FLOW_APPROVE_STATUS_ENUM.APPROVING?
'dot dot-approving':
'dot dot-approving approving':
row.approveType === FLOW_APPROVE_STATUS_ENUM.APPROVED?
'dot dot-success':'dot-refuse'"
>.</span>{{ FLOW_APPROVE_STATUS.O[row.approveType] }}
>.</span>
<span
:class="row.approveType !== FLOW_APPROVE_STATUS_ENUM.NOT_APPROVED?'approving-span':''"
@click="seeApproveDetailFun(row)"
>{{ FLOW_APPROVE_STATUS.O[row.approveType] }}</span>
</template>
<!-- <template #tableActions="{ row }">
<div class="gl-table-actions">
@@ -138,6 +142,7 @@
v-model:showDialog="showFlowViewVisible"
:flowUuid="flowUuid"
></flowViewDialog>
<ApprovalProcess v-model="approveDetailVisible" :flowId="approveId" />
</template>
<script setup lang="ts">
@@ -150,6 +155,7 @@ import { deleteFlowTemplateDraftApi, queryFlowTemplateApi, updateFlowTemplateUse
import { ElMessage, ElMessageBox } from 'element-plus';
import { FLOW_APPROVE_STATUS_ENUM, FLOW_TEMPLATE_PUBLIC_STATUS, FLOW_USE_STATUS } from '@/utils/enum/flow';
import flowViewDialog from '@/components/common/flow/flowViewDialog.vue';
import ApprovalProcess from '@/components/common/approvalProcess/index.vue';
defineProps({
apiParams: {
@@ -160,6 +166,10 @@ defineProps({
const showFlowDetailVisible = ref(false);
const showFlowViewVisible = ref(false);
const approveDetailVisible = ref(false);
const approveId = ref('');
const { FLOW_APPROVE_STATUS, FLOW_USE_TYPE } = useDict('FLOW_APPROVE_STATUS', 'FLOW_USE_TYPE');
const showDialog = ref(false);
@@ -262,6 +272,13 @@ const openDiaFun = (tag: string, row?: any) => {
};
const seeApproveDetailFun = (row:any) => {
if (row.approveType !== FLOW_APPROVE_STATUS_ENUM.NOT_APPROVED) {
approveDetailVisible.value = true;
approveId.value = row.approveFlowId;
}
};
const addOrEditFun = ({ type, uuid }:any) => {
tableRef.value.resetFun();
flowUuid.value = uuid;
@@ -396,6 +413,9 @@ const searchFun = () => {
.display-mode {
text-align: right;
}
.approving-span {
cursor: pointer;
}
.flow-car-list {
width: 100%;
@@ -624,19 +644,19 @@ const searchFun = () => {
color: #64748b;
}
.no-approve {
background-color: #0366FF;
color: #0366FF;
}
.approving {
background-color: #ED7B2F;
color: #ED7B2F;
}
.approve-success {
background-color: #00A870;
color: #00A870;
}
.approve-refuse {
background-color: #E34D59;
color: #E34D59 ;
}
</style>

View File

@@ -10,6 +10,12 @@
:api="nodeListApi"
:searchLimitNum="3"
:actionList="actionList"
:exportApi="exportProjectApi"
exportFileName="项目列表"
:exportDict="{
nodeSubType: 'PROJECT_TYPE',
exeStatus:'PROJECT_EXE_STATUS'
}"
>
<template #cardTemplate="{tableData}">
<div class="project-card-box" >
@@ -83,7 +89,7 @@ import { reactive, ref } from 'vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import projectInfoDialog from '@/components/project/projectInfoDialog.vue';
// import { useRouter } from 'vue-router';
import { deleteNodeApi, queryNodeListApi } from '@/api/project/node';
import { deleteNodeApi, exportProjectApi, queryNodeListApi } from '@/api/project/node';
import { ElMessage } from 'element-plus';
import { NODE_TYPE } from '@/utils/enum/node';
import { disposeMemberList } from '../projectDetail/components/project';

View File

@@ -13,7 +13,7 @@
v-bind="$attrs"
:exportApi="exportTaskApi"
:exportFileName="exportFileName"
:exportParams="{...params,idMap:tagIdMap,...filterTaskParams,sortOrder:1}"
:exportParams="{...params,idMap:tagIdMap,...filterTaskParams,sortOrder:1,tagMap: getTagMapList()}"
:exportDict="{
achieveStatus: 'RESULT_ACHIEVE_STATUS',
exeStatus:'TASK_EXE_STATUS'
@@ -83,8 +83,11 @@
<template #approvalStatus="{ row }">
{{ row.approvalStatus || '未审批' }}
</template>
<template #attachments="{ row }">
<el-link type="primary" @click="seeAttachments(row.id)">查看附件</el-link>
<template #demandAttachments="{ row }">
<el-link v-if="row.demandId" type="primary" @click="seeAttachments(row.demandId)">查看附件</el-link>
</template>
<template #taskAttachments="{ row }">
<el-link type="primary" @click="seeAttachments(row.demandId)">查看附件</el-link>
</template>
<!-- <template #demandType="{row}">
{{ DEMAND_TYPE.O[row.demandType] }}
@@ -122,6 +125,7 @@ import { TASK_PROCESS_STATUS_OBJ, TASK_CALCULATE_STATUS_OBJ, TASK_PROCESS_STATUS
import { disposeTagName, setTaskSearchOptions } from '../taskPage';
import { getIdMap } from '../../projectDetail/components/project';
import { exportTaskApi, getTaskCountApi } from '@/api/project/task';
import { getTagMapList } from '@/utils/task';
const props = defineProps({
params: {
@@ -169,7 +173,7 @@ const tableRef = ref();
const tableFormRef = ref();
const demandInfo = reactive({
id: 0,
id: '',
uuid: '',
});
@@ -239,7 +243,7 @@ const getPhaseList = async (nodeType:string, projectUuid: string) => {
return optionList;
};
const seeAttachments = (demandId:number) => {
const seeAttachments = (demandId:string) => {
attachmentsVisible.value = true;
console.log('demandId', demandId);
demandInfo.id = demandId;