This commit is contained in:
2025-11-07 18:42:52 +08:00
15 changed files with 213 additions and 180 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -108,7 +108,7 @@ const addOrEditProject = async () => {
if (await tableFormRef.value.validateFun()) {
if (hasSameValue()) return;
loadingInterface.value = true;
if (props?.projectId) {
if (!props?.projectId) {
await createProject();
} else {
// console.log('编辑项目', projectForm);

View File

@@ -66,6 +66,8 @@ interface RuleForm {
remarks: string | null
userId: string | null
userList: Array<any> | null
templateName?: string | null
templateId?: string | null
}
const form = ref<RuleForm>({
file: null,
@@ -78,6 +80,8 @@ const form = ref<RuleForm>({
remarks: null,
userId: null,
userList: null,
templateName: null,
templateId: null,
});
const onShowFun = () => {
@@ -102,8 +106,11 @@ const getDisciplineNodeTypeFun = async () => {
const poolCategoryTypeList: any = await commonStore.getDictData('POOL_CATEGORY_TYPE');
disciplineNodeType.value = poolCategoryTypeList.A.find((item: any) => item.label === '学科').value ;
};
const onFormChangeFun = () => {
const onFormChangeFun = (data:any) => {
form.value = tableFormRef.value?.getFormDataFun();
if (data.key === 'templateId') {
form.value.templateName = data?.val?.label;
}
};
const tableFormRef = ref<any>();
const onConfirmFun = async () => {

View File

@@ -60,11 +60,7 @@
<el-link type="primary" @click="previewFileFun(row)">{{ $t('知识库.预览') }}</el-link>
<UploadFile v-model="row.id" :name="$t('知识库.下载')" />
<el-link type="primary" @click="editFileFun(row)">{{ $t('知识库.编辑') }}</el-link>
<el-popconfirm :title="$t('知识库.确认删除')" @confirm="delFileFun(row)">
<template #reference>
<el-link type="danger">{{ $t('工况库.删除') }}</el-link>
</template>
</el-popconfirm>
<el-link type="danger" @click="delFileFun(row)">{{ $t('工况库.删除') }}</el-link>
</div>
</template>
</BaseTable>
@@ -82,20 +78,21 @@
</template>
<script lang="ts" setup>
import { ref, watchEffect, type Ref } from 'vue';
import { h, ref, watchEffect, type Ref } from 'vue';
import { DArrowLeft, Plus } from '@element-plus/icons-vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import FileTree from '@/components/common/fileTree/index.vue';
import knowledgeDetailModal from './components/knowledgeDetailModal.vue';
import folderModal from './components/folderDetailModal.vue';
import { dataCreateDirApi, dataListDirApi, dataRenameDirApi, dataUploadFilesApi, dataDelDirApi, dataQueryDirApi, dataFileSearchApi, dataDelFileApi, dataUpdateFileApi } from '@/api/data/data';
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import type { RenderContentContext } from 'element-plus';
import { formatFileSize } from '@/utils/file';
import UploadFile from '@/components/common/uploadFile/index.vue';
import TableSearch from '@/components/common/table/tableSearch.vue';
import { cloneDeep } from 'lodash-es';
import { DIR_TYPE } from '@/utils/enum/data.ts';
import ApproveList from '@/components/common/approveList/index.vue';
type Data = RenderContentContext['data']
const fileTreeRef = ref<any>();
@@ -226,6 +223,8 @@ const openModalFun = () => {
const onOkFun = async (formData:any) => {
const req = {
...currentRow.value,
templateId: formData.templateId,
templateName: formData.templateName,
file: formData.file.raw,
fileName: formData.file.name,
size: formData.file.size,
@@ -261,17 +260,42 @@ const editFileFun = (row:any ) => {
currentRow.value = row;
visible.value = true;
};
const delFileFun = async (row:any ) => {
const req = {
delFileId: row.id,
};
const res:any = await dataDelFileApi(req);
if (res.code === 200) {
refreshTableFun();
ElMessage.success(res.message);
} else {
ElMessage.error(res.message);
}
const delFileFun = async (row: any) => {
const templateId = ref('');
const templateName = ref('');
ElMessageBox({
title: '审核模版',
showCancelButton: true,
showConfirmButton: true,
confirmButtonText: '确认',
cancelButtonText: '取消',
message: () =>
h(ApproveList, {
modelValue: templateId.value,
'onChange': (val: any) => {
templateName.value = val.label;
templateId.value = val.value;
},
}),
}).then(async () => {
if (!templateId.value) {
ElMessage.error('请选择审核模版');
return;
}
const req = {
templateId: templateId.value,
templateName: templateName.value,
delFileId: row.id,
};
const res:any = await dataDelFileApi(req);
if (res.code === 200) {
refreshTableFun();
ElMessage.success(res.message);
} else {
ElMessage.error(res.message);
}
});
};
const onCellDblclickFun = (e:any) => {
if (e.row.dataType === 1) {

View File

@@ -312,6 +312,7 @@ import Dialog from '@/components/common/dialog/index.vue';
import { handleLoadDataApi, getHandleLoadDataResultApi, setTrainingDataInputOutputColumnApi, getTrainingDataInputOutputColumnApi, submitTrainingApi, getAlgorithmParamApi, getTrainingResultApi, stopTrainingApi, getModelDetailApi, getModelTrainingWebSocketUrl } from '@/api/data/dataForecast';
import paramSetting from './components/paramSetting.vue';
import { initEcharts } from '@/components/common/echartCard/echartsOptions';
import { getUserId } from '@/utils/user.ts';
const emit = defineEmits(['back', 'syncModelInfo']);
@@ -321,7 +322,7 @@ const props = defineProps({
default: null,
},
});
const currentUserId = localStorage.getItem('userId') || '1029001';
const currentUserId = getUserId();
const trainDataTableRef = ref();
const dataSetDialogVisible = ref(false);
@@ -533,6 +534,7 @@ const paramSettingRef: any = ref(null);
const beginTrainingFun = async () => {
const formData = await paramSettingRef.value?.getFormDataFun();
const req = {
userId: currentUserId,
modelId: props.modelForm.id,
...formData,
};

View File

@@ -1,5 +1,6 @@
import { reactive, ref } from 'vue';
import { ref } from 'vue';
// 控制连接桩显示/隐藏
const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
for (let i = 0, len = ports.length; i < len; i += 1) {
ports[i].style.visibility = show ? 'visible' : 'hidden';
@@ -22,7 +23,7 @@ export const initNodeEvents = (graph: any) => {
showPorts(ports, false);
});
graph.on('node:selected', ({ node }:any) => {
console.log('node', node);
console.log('selected node', node);
node.addTools({
name: 'boundary',
args: {
@@ -36,7 +37,7 @@ export const initNodeEvents = (graph: any) => {
});
});
graph.on('node:unselected', ({ node }:any) => {
console.log('node', node);
console.log('unselected node', node);
node.removeTools();
const container = document.getElementById('container')!;
const ports = container.querySelectorAll(
@@ -44,6 +45,19 @@ export const initNodeEvents = (graph: any) => {
) as NodeListOf<SVGElement>;
showPorts(ports, false);
});
graph.on('node:click', ({ node }:any) => {
console.log('click node', node);
});
};
const showPropertyConfigDialog = ref(false);
export const useNode = () => {
return {
showPropertyConfigDialog,
};
};
export const nodeAttributeRef:any = ref({

View File

@@ -0,0 +1,40 @@
import { Graph, Path } from '@antv/x6';
export const registerCustomConnector = () => {
// 注册连线
Graph.registerConnector(
'curveConnector',
(sourcePoint, targetPoint) => {
const hgap = Math.abs(targetPoint.x - sourcePoint.x);
const path = new Path();
path.appendSegment(
Path.createSegment('M', sourcePoint.x - 4, sourcePoint.y)
);
path.appendSegment(
Path.createSegment('L', sourcePoint.x + 12, sourcePoint.y)
);
// 水平三阶贝塞尔曲线
path.appendSegment(
Path.createSegment(
'C',
sourcePoint.x < targetPoint.x
? sourcePoint.x + hgap / 2
: sourcePoint.x - hgap / 2,
sourcePoint.y,
sourcePoint.x < targetPoint.x
? targetPoint.x - hgap / 2
: targetPoint.x + hgap / 2,
targetPoint.y,
targetPoint.x - 6,
targetPoint.y
)
);
path.appendSegment(
Path.createSegment('L', targetPoint.x + 2, targetPoint.y)
);
return path.serialize();
},
true
);
};

View File

@@ -5,18 +5,18 @@
<div class="app-name">{{ appProperty.name }}</div>
<div class="app-tag">{{ appProperty.type }}</div>
</div>
<div>
<!-- <div>
<span @click="attributeFun">属性</span>
<span @click="paramFun">参数</span>
</div>
</div> -->
</div>
</template>
<script lang="ts" setup>
import { inject, onMounted, reactive } from 'vue';
import { setNodeAttribute } from './nodeEvents';
// import { setNodeAttribute } from './nodeEvents';
const emits = defineEmits(['attribute', 'param']);
// const emits = defineEmits(['attribute', 'param']);
const appProperty = reactive({
name: '',
@@ -26,19 +26,14 @@ const appProperty = reactive({
const getNode:any = inject('getNode');
const attributeFun = () => {
console.log('click attributeFun');
setNodeAttribute(appProperty);
// const store = CommonStore();
// console.log('store', nodeRef, store);
// console.log('attributeFun');
// emits('attribute', appProperty);
};
// const attributeFun = () => {
// console.log('click attributeFun');
// setNodeAttribute(appProperty);
// };
const paramFun = () => {
console.log('paramFun');
emits('param', appProperty);
};
// const paramFun = () => {
// emits('param', appProperty);
// };
onMounted(() => {
if (getNode) {

View File

@@ -2,6 +2,9 @@
<div class="gl-page-content">
<!-- <el-button @click="exportJson">导出json</el-button>
<el-button @click="importJson">导入json</el-button> -->
<div class="header-box">
</div>
<div id="container">
<div id="stencil"></div>
</div>
@@ -10,7 +13,7 @@
</template>
<script setup lang="ts">
import { Graph, Shape, Path } from '@antv/x6';
import { Graph, Shape } from '@antv/x6';
import { Selection } from '@antv/x6-plugin-selection';
import { Snapline } from '@antv/x6-plugin-snapline';
import { Keyboard } from '@antv/x6-plugin-keyboard';
@@ -21,43 +24,11 @@ import { getTeleport } from '@antv/x6-vue-shape';
import { keyboardEvents } from './components/keyboard';
import { stencilRegister } from './components/stencil';
import { initNodeEvents, nodeAttributeRef } from './components/nodeEvents';
import { registerCustomConnector } from './components/registerConnector';
// 注册连线
Graph.registerConnector(
'curveConnector',
(sourcePoint, targetPoint) => {
const hgap = Math.abs(targetPoint.x - sourcePoint.x);
const path = new Path();
path.appendSegment(
Path.createSegment('M', sourcePoint.x - 4, sourcePoint.y)
);
path.appendSegment(
Path.createSegment('L', sourcePoint.x + 12, sourcePoint.y)
);
// 水平三阶贝塞尔曲线
path.appendSegment(
Path.createSegment(
'C',
sourcePoint.x < targetPoint.x
? sourcePoint.x + hgap / 2
: sourcePoint.x - hgap / 2,
sourcePoint.y,
sourcePoint.x < targetPoint.x
? targetPoint.x - hgap / 2
: targetPoint.x + hgap / 2,
targetPoint.y,
targetPoint.x - 6,
targetPoint.y
)
);
path.appendSegment(
Path.createSegment('L', targetPoint.x + 2, targetPoint.y)
);
registerCustomConnector();
return path.serialize();
},
true
);
const TeleportContainer = getTeleport();
let graph:any = null;
const initGraph = () => {
@@ -140,44 +111,6 @@ const initGraph = () => {
// },
// });
// 注册连线
Graph.registerConnector(
'curveConnector',
(sourcePoint, targetPoint) => {
const hgap = Math.abs(targetPoint.x - sourcePoint.x);
const path = new Path();
path.appendSegment(
Path.createSegment('M', sourcePoint.x - 4, sourcePoint.y)
);
path.appendSegment(
Path.createSegment('L', sourcePoint.x + 12, sourcePoint.y)
);
// 水平三阶贝塞尔曲线
path.appendSegment(
Path.createSegment(
'C',
sourcePoint.x < targetPoint.x
? sourcePoint.x + hgap / 2
: sourcePoint.x - hgap / 2,
sourcePoint.y,
sourcePoint.x < targetPoint.x
? targetPoint.x - hgap / 2
: targetPoint.x + hgap / 2,
targetPoint.y,
targetPoint.x - 6,
targetPoint.y
)
);
path.appendSegment(
Path.createSegment('L', targetPoint.x + 2, targetPoint.y)
);
return path.serialize();
},
true
);
// 控制连接桩显示/隐藏
initNodeEvents(graph);
graph.use(
@@ -222,46 +155,6 @@ const initGraph = () => {
);
keyboardEvents(graph);
// const flag = true;
// graph.on('node:added', ({ node }) => {
// const { x, y } = node.position();
// console.log('node', x, y );
// if (flag) {
// flag = false;
// graph.addNode({
// shape: 'custom-vue-node',
// x: x,
// y: y,
// // customConfig: {
// // type: 'save',
// // },
// });
// setTimeout(() => {
// graph.removeNode( node.id );
// flag = true;
// }, 10);
// }
// });
// #endregion
// console.log('Dnd', Dnd, graph, JSON.stringify(Dnd));
// const dnd = new Dnd({
// target: graph,
// scaled: false,
// getDropNode: (node:any) => {
// console.log('node1', node);
// // 返回一个新的节点作为实际放置到画布上的节点
// return node;
// },
// getDragNode: (node:any) => {
// console.log('node2', node);
// // 返回一个新的节点作为实际放置到画布上的节点
// return node;
// },
// });
// console.log('dnd', dnd);
};
// const exportJson = () => {
// console.log('graph', graph);

View File

@@ -545,6 +545,7 @@ const updateTreeDataApi = async (insertList: any[], deleteList: any[], updateLis
addNodeList: insertList,
editNodeList: updateList,
deleteNodeList,
ownRootNodeUuid: props.nodeLevel1Uuid,
tagMap: getTagMapList(),
});
if (res.code === 200) {

View File

@@ -22,8 +22,14 @@
<template #cardTemplate="{tableData}">
<div class="project-card-box" >
<div class="projects-grid">
<div v-for="project in tableData" :key="project.id" class="project-card">
<div class="card-header">
<div v-for="(project,index) in tableData" :key="project.id" @click="goProjectDetailFun(project.uuid,project.nodeName)" class="project-card">
<img v-if="index%2!==0" src="@/assets/imgs/projectList/project-blue.png" alt="">
<img v-else src="@/assets/imgs/projectList/project-green.png" alt="">
<div class="bottom-box">
<span class="title">{{ project.nodeName }}</span>
<span class="status">{{ PROJECT_EXE_STATUS.O[project.exeStatus ] }}</span>
</div>
<!-- <div class="card-header">
<img class="project-icon" src="@/assets/imgs/projectTree/project-icon.png" alt="">
<div class="title-section">
<div class="project-title">{{ project.nodeName }}</div>
@@ -56,7 +62,7 @@
<div class="progress-bar">
<div class="progress-fill" :style="{ width: project.progress + '%' }"></div>
</div>
</div>
</div> -->
</div>
</div>
</div>
@@ -105,12 +111,12 @@
@nextPageFun="nextPageFun"
@completeFun="completeFun"
/>
<projectDetail
<ProjectDetail
v-if="showProjectDetailVisible"
:projectName="currentProject.nodeName"
:projectUuid="currentProject.nodeId"
@goBack="showProjectDetailVisible = false"
></projectDetail>
></ProjectDetail>
</template>
<script setup lang="ts">
@@ -125,7 +131,7 @@ import { disposeMemberList } from '../projectDetail/components/project';
import { useDict } from '@/utils/useDict';
import { tableActionsLength } from '@/utils/common';
import dayjs from 'dayjs';
import projectDetail from '../projectDetail/index.vue';
import ProjectDetail from '../projectDetail/index.vue';
export interface IUserInfo {
id: number;
@@ -189,7 +195,7 @@ const currentProjectBaseInfo = reactive<any>({
memberList: [],
});
const viewType = ref('list');
const viewType = ref('card');
const currentRow = ref();
@@ -396,19 +402,52 @@ const deleteNodeFun = async(row:IProjectInfo) => {
}
}
}
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.project-card {
height: 160px;
background: white;
border-radius: 12px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
padding: 18px;
// padding: 18px;
transition: all 0.3s ease;
border: 1px solid #e2e8f0;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 100%;
}
.bottom-box {
position: absolute;
left: 0;
bottom: 0;
height: 40px;
width: 100%;
border-radius: 8px;
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
.status {
background-color: #F4F4F5;
border: 1px solid #E0E0E0;
font-size: 12px;
padding: 2px 10px;
border-radius: 4px;
width: 60px;
height: 25px;
text-align: center;
}
}
}
.project-card:hover {

View File

@@ -141,6 +141,7 @@ import { getTaskTreeFun } from '@/views/task/projectDetail/components/projectApi
import { filterTask, getIdMap } from '@/views/task/projectDetail/components/project';
import { tagSortList } from '@/utils/enum/node';
import { getMemberListStr } from '@/utils/task';
import { issuedTaskApi } from '@/api/project/demand';
const props = defineProps({
diaVisible: {
@@ -204,6 +205,7 @@ const confirmFun = async() => {
tagProperty[item] = parentNodeInfo[item] ? parentNodeInfo[item].split(',') : [];
});
const idMap = getIdMap(demandItem.projectId, demandItem.phaseId);
const pMemberListStr = getMemberListStr(demandItem.pMemberList);
if (demandItem.insertMode === 'lib') {
const addTaskList = demandItem.chooseTaskList.map((task:any) => {
return {
@@ -212,6 +214,7 @@ const confirmFun = async() => {
beginTime: demandItem.beginTime,
endTime: demandItem.endTime,
eMemberList: demandItem.eMemberList,
pMemberList: pMemberListStr,
};
});
params.push({
@@ -221,26 +224,28 @@ const confirmFun = async() => {
});
} else {
params.push({
addNodeList: {
taskName: demandItem.taskName,
addNodeList: [{
nodeName: demandItem.taskName,
...tagProperty,
beginTime: demandItem.beginTime,
endTime: demandItem.endTime,
eMemberList: demandItem.eMemberList,
},
pMemberList: pMemberListStr,
nodeId: parentNodeInfo.uuid,
}],
demandId: demandItem.uuid,
idMap: idMap,
});
}
}
console.log('params', params);
// const res:any = await issuedTaskApi(params);
// if (res.code === 200) {
// ElMessage.success('任务分发成功!');
// closeFun();
// } else {
// ElMessage.error('任务分发失败!');
// }
const res:any = await issuedTaskApi({ reqList: params });
if (res.code === 200) {
ElMessage.success('批量任务分发成功!');
closeFun();
} else {
ElMessage.error('批量任务分发失败!');
}
loadingInterface.value = false;
};

View File

@@ -389,7 +389,7 @@ const sendTaskConfirmFun = () => {
idMap: getIdMap(sendForm.projectId, sendForm.phaseId),
};
}
const res:any = await issuedTaskApi(params);
const res:any = await issuedTaskApi({ reqList: [params] });
if (res.code === 200) {
ElMessage.success('任务分发成功!');
closeSendFun();
@@ -424,9 +424,12 @@ const sendTaskFun = async(row:any) => {
const tableRef = ref();
const checkedList = ref();
const batchSendFun = () => {
checkedList.value = tableRef.value.tableRef.tableRef.getCheckboxRecords();
if (checkedList.value.length === 0) {
return ElMessage.warning('请勾选需要分发的需求!');
}
bachSendVisible.value = true;
console.log('tableRef.value.tableRef.getCheckboxRecords()', tableRef.value.tableRef.tableRef.getCheckboxRecords());
checkedList.value = tableRef.value.tableRef.tableRef.getCheckboxRecords();
};
</script>

View File

@@ -63,11 +63,12 @@ import { queryTaskListApi, updateTaskStatusApi } from '@/api/project/task';
import { TASK_CALCULATE_STATUS, TASK_CALCULATE_STATUS_OPTIONS, TASK_PROCESS_STATUS, TASK_PROCESS_STATUS_OPTIONS } from '@/utils/enum/task';
import { ElMessage } from 'element-plus';
import taskTable from '../components/taskTable.vue';
import { nextTick, onMounted, ref } from 'vue';
import { onMounted, ref } from 'vue';
import Dialog from '@/components/common/dialog/index.vue';
import TableForm from '@/components/common/table/tableForm.vue';
import { tableActionsLength } from '@/utils/common';
import dayjs from 'dayjs';
import { getMemberListStr } from '@/utils/task';
const exeTableRef = ref();
@@ -97,9 +98,15 @@ const editRow = ref();
const editTaskFun = (row: any) => {
formVisible.value = true;
editRow.value = row;
nextTick(() => {
tableFormRef.value.setFormDataFun({ ...row, achieveStatus: row.achieveStatus + '', eMemberList: row.eMemberList ? row.eMemberList.map((item: any) => item.id).join(',') : '' });
});
console.log('formLoad', tableFormRef.value);
// nextTick(() => {
setFormData(editRow.value);
// });
};
const setFormData = (row: any) => {
if (tableFormRef.value) {
tableFormRef.value.setFormDataFun({ ...row, achieveStatus: row.achieveStatus + '', eMemberList: getMemberListStr(row.eMemberList) });
}
};
const deleteTaskFun = (uuid:string) => {
@@ -124,6 +131,7 @@ const formLoad = () => {
});
tableFormRef.value.setOptionsFun('exeStatus', exeStatusList);
tableFormRef.value.setOptionsFun('achieveStatus', achieveStatusList);
setFormData(editRow.value);
// });
};
const disposeDisabledExeStatus = (status: string, option: { value: TASK_PROCESS_STATUS; }) => {
@@ -162,12 +170,14 @@ const confirmFun = async() => {
const fromData:any = tableFormRef.value.getFormDataFun();
// console.log('tableFormRef.value.getFormDataFun()', fromData);
const params:any = {
...fromData,
taskIds: [fromData.uuid],
req: {
...fromData,
exeStatus: fromData.exeStatus,
achieveStatus: fromData.achieveStatus,
process: fromData.progress,
pMemberList: getMemberListStr(fromData.pMemberList),
nodeName: fromData.taskName,
},
};
if (fromData.exeStatus === TASK_PROCESS_STATUS.COMPLETED) {