|
@@ -0,0 +1,419 @@
|
|
|
|
|
+<!-- ProjectListDialog.vue -->
|
|
|
|
|
+<template>
|
|
|
|
|
+ <el-dialog
|
|
|
|
|
+ v-model="dialogVisible"
|
|
|
|
|
+ align-center
|
|
|
|
|
+ :append-to-body="true"
|
|
|
|
|
+ width="800"
|
|
|
|
|
+ class="dialog_class"
|
|
|
|
|
+ draggable
|
|
|
|
|
+ @close="handleClose"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #header="{ titleId, titleClass }">
|
|
|
|
|
+ <div class="my-header">
|
|
|
|
|
+ <h4 :id="titleId" :class="titleClass">
|
|
|
|
|
+ {{ $t("dialog.projectlist") }}
|
|
|
|
|
+ </h4>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <template #default>
|
|
|
|
|
+ <div class="project-main-content custom-table">
|
|
|
|
|
+ <el-table
|
|
|
|
|
+ :data="projectLists"
|
|
|
|
|
+ style="width: 100%; height: 540px; overflow: auto"
|
|
|
|
|
+ @row-click="handleRowClick"
|
|
|
|
|
+ :row-class-name="tableRowClassName"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ type="index"
|
|
|
|
|
+ :label="$t('project.number')"
|
|
|
|
|
+ width="100"
|
|
|
|
|
+ ></el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="name"
|
|
|
|
|
+ :label="$t('project.name')"
|
|
|
|
|
+ ></el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="dirsize"
|
|
|
|
|
+ :label="$t('project.dirsize')"
|
|
|
|
|
+ ></el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="updateTime"
|
|
|
|
|
+ :label="$t('project.updateTime')"
|
|
|
|
|
+ min-width="100"
|
|
|
|
|
+ ></el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="uname"
|
|
|
|
|
+ :label="$t('project.uname')"
|
|
|
|
|
+ ></el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="keywords"
|
|
|
|
|
+ :label="$t('project.keywords')"
|
|
|
|
|
+ ></el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="remark"
|
|
|
|
|
+ :label="$t('project.description')"
|
|
|
|
|
+ ></el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="project-main-pagination">
|
|
|
|
|
+ <div class="custom-pagination">
|
|
|
|
|
+ <el-pagination
|
|
|
|
|
+ v-model:current-page="pagination.currentPage"
|
|
|
|
|
+ v-model:page-size="pagination.pageSize"
|
|
|
|
|
+ :page-sizes="[5, 10, 20, 50]"
|
|
|
|
|
+ background
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ layout="prev, slot, sizes, pager, next"
|
|
|
|
|
+ :total="parseInt(pagination.total)"
|
|
|
|
|
+ class="mt-4"
|
|
|
|
|
+ @size-change="handleSizeChange"
|
|
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #default>
|
|
|
|
|
+ <span>{{ $t("project.total") }} {{ pagination.total }}</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-pagination>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <span class="lastbtn">
|
|
|
|
|
+ <el-button @click="handleCancel">{{ $t("dialog.cancel") }}</el-button>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ @click="confirmSelected"
|
|
|
|
|
+ :disabled="selectedRows.length === 0"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ $t("dialog.ok") }}
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, watch } from "vue"
|
|
|
|
|
+import { useI18n } from "vue-i18n"
|
|
|
|
|
+import { useRouter } from "vue-router"
|
|
|
|
|
+import { useProjectStore } from "@/store/project"
|
|
|
|
|
+import { ElMessage } from "element-plus"
|
|
|
|
|
+import { request } from "@/utils/request"
|
|
|
|
|
+import emitter from '@/utils/emitter';
|
|
|
|
|
+
|
|
|
|
|
+const { t } = useI18n()
|
|
|
|
|
+const router = useRouter()
|
|
|
|
|
+const projectStore = useProjectStore()
|
|
|
|
|
+
|
|
|
|
|
+const props = defineProps({
|
|
|
|
|
+ visible: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: false
|
|
|
|
|
+ },
|
|
|
|
|
+ identify: {
|
|
|
|
|
+ type: String,
|
|
|
|
|
+ default: "default"
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const emit = defineEmits(["update:visible", "confirm"])
|
|
|
|
|
+
|
|
|
|
|
+// 本地状态控制对话框显示
|
|
|
|
|
+const dialogVisible = ref(props.visible)
|
|
|
|
|
+
|
|
|
|
|
+// 监听 props.visible 变化
|
|
|
|
|
+watch(
|
|
|
|
|
+ () => props.visible,
|
|
|
|
|
+ (newVal) => {
|
|
|
|
|
+ dialogVisible.value = newVal
|
|
|
|
|
+ if (newVal) {
|
|
|
|
|
+ getProjectList()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+const pagination = ref({
|
|
|
|
|
+ total: 1,
|
|
|
|
|
+ currentPage: 1,
|
|
|
|
|
+ pageSize: 5,
|
|
|
|
|
+ searchtag: ""
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const projectLists = ref([])
|
|
|
|
|
+const selectedRows = ref([])
|
|
|
|
|
+
|
|
|
|
|
+// 获取项目列表
|
|
|
|
|
+const getProjectList = () => {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ transCode: "ES0001",
|
|
|
|
|
+ count: pagination.value.pageSize,
|
|
|
|
|
+ page: pagination.value.currentPage,
|
|
|
|
|
+ searchtag: pagination.value.searchtag
|
|
|
|
|
+ }
|
|
|
|
|
+ request(params)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ pagination.value.total = res.total
|
|
|
|
|
+ projectLists.value = res.rows.map((item) => ({
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ updateTime: item.updateTime.split(" +")[0]
|
|
|
|
|
+ }))
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => {
|
|
|
|
|
+ console.error(err)
|
|
|
|
|
+ ElMessage.error(err.returnMsg)
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理行点击事件
|
|
|
|
|
+const handleRowClick = (row) => {
|
|
|
|
|
+ const index = selectedRows.value.findIndex((item) => item.pid === row.pid)
|
|
|
|
|
+ if (index === -1) {
|
|
|
|
|
+ selectedRows.value = [row] // 单选模式
|
|
|
|
|
+ } else {
|
|
|
|
|
+ selectedRows.value.splice(index, 1) // 取消选中
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 为行添加类名
|
|
|
|
|
+const tableRowClassName = ({ row }) => {
|
|
|
|
|
+ return selectedRows.value.some((item) => item.pid === row.pid)
|
|
|
|
|
+ ? "selected-row"
|
|
|
|
|
+ : ""
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理分页变化
|
|
|
|
|
+const handleSizeChange = (newSize) => {
|
|
|
|
|
+ pagination.value.pageSize = newSize
|
|
|
|
|
+ pagination.value.currentPage = 1
|
|
|
|
|
+ getProjectList()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleCurrentChange = () => {
|
|
|
|
|
+ getProjectList()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 确认选中行
|
|
|
|
|
+const confirmSelected = () => {
|
|
|
|
|
+ if (selectedRows.value.length !== 1) {
|
|
|
|
|
+ ElMessage.warning(t("message.selectOneProject"))
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const selected = selectedRows.value[0]
|
|
|
|
|
+ const project = {
|
|
|
|
|
+ projectId: selected.pid,
|
|
|
|
|
+ projectName: selected.name || `Project ${projectStore.projects.length + 1}`,
|
|
|
|
|
+ keywords: selected.keywords || "",
|
|
|
|
|
+ remark: selected.remark || "",
|
|
|
|
|
+ flow: selected.flow ? selected.flow : { nodes: [], edges: [] }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 根据 identify 处理不同的确认逻辑
|
|
|
|
|
+ if (props.identify === "openProject") {
|
|
|
|
|
+ // HeaderButtonBar.vue 的逻辑:更新项目并跳转
|
|
|
|
|
+ if (projectStore.projects.some((p) => p.projectId === selected.pid)) {
|
|
|
|
|
+ projectStore.updateProjectInfo(selected.pid, project)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ projectStore.addProject(project)
|
|
|
|
|
+ }
|
|
|
|
|
+ projectStore.setActiveProject(selected.pid)
|
|
|
|
|
+ router.push({ path: "/home" })
|
|
|
|
|
+ } else if (props.identify === "importProject") {
|
|
|
|
|
+ // 获取项目编码
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ transCode: "ES0030",
|
|
|
|
|
+ pid: selected.pid,
|
|
|
|
|
+ npid: projectStore.pid
|
|
|
|
|
+ };
|
|
|
|
|
+ request(params)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ console.log("res===>:", res);
|
|
|
|
|
+
|
|
|
|
|
+ // 解析 cpjson 和 oldflow
|
|
|
|
|
+ const cpjson = JSON.parse(res.cpjson);
|
|
|
|
|
+ const oldflow = JSON.parse(res.oldflow);
|
|
|
|
|
+
|
|
|
|
|
+ // 创建映射表,便于快速查找
|
|
|
|
|
+ const idMapping = {};
|
|
|
|
|
+ cpjson.forEach(mapping => {
|
|
|
|
|
+ idMapping[mapping.oldId] = mapping.newId;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 创建节点ID映射表(旧节点ID -> 新节点ID)
|
|
|
|
|
+ const nodeIdMapping = {};
|
|
|
|
|
+
|
|
|
|
|
+ // 复制并处理节点数据
|
|
|
|
|
+ const processedNodes = oldflow.nodes.map(node => {
|
|
|
|
|
+ const newNode = { ...node };
|
|
|
|
|
+
|
|
|
|
|
+ // 处理节点的 pcId
|
|
|
|
|
+ if (newNode.data && newNode.data.pcId && idMapping[newNode.data.pcId]) {
|
|
|
|
|
+ newNode.data.pcId = idMapping[newNode.data.pcId];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 生成新的节点ID并建立映射关系
|
|
|
|
|
+ const oldNodeId = newNode.id;
|
|
|
|
|
+ const timestamp = Date.now();
|
|
|
|
|
+ const randomStr = Math.random().toString(36).substr(2, 9);
|
|
|
|
|
+
|
|
|
|
|
+ if (newNode.type === 'point-only') {
|
|
|
|
|
+ // point-only 节点保持类似的命名格式
|
|
|
|
|
+ newNode.id = `point-${timestamp}_${randomStr}`;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 其他节点保持 componentId_timestamp_random 格式
|
|
|
|
|
+ const parts = newNode.id.split('_');
|
|
|
|
|
+ if (parts.length > 0) {
|
|
|
|
|
+ newNode.id = `${parts[0]}_${timestamp}_${randomStr}`;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ newNode.id = `node_${timestamp}_${randomStr}`;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 保存节点ID映射关系
|
|
|
|
|
+ nodeIdMapping[oldNodeId] = newNode.id;
|
|
|
|
|
+
|
|
|
|
|
+ return newNode;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 复制并处理边数据
|
|
|
|
|
+ const processedEdges = oldflow.edges.map(edge => {
|
|
|
|
|
+ const newEdge = { ...edge };
|
|
|
|
|
+
|
|
|
|
|
+ // 处理边的 pcid
|
|
|
|
|
+ if (newEdge.data && newEdge.data.pcid && idMapping[newEdge.data.pcid]) {
|
|
|
|
|
+ newEdge.data.pcid = idMapping[newEdge.data.pcid];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理边的 frompcId
|
|
|
|
|
+ if (newEdge.data && newEdge.data.frompcId && idMapping[newEdge.data.frompcId]) {
|
|
|
|
|
+ newEdge.data.frompcId = idMapping[newEdge.data.frompcId];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理边的 topcId
|
|
|
|
|
+ if (newEdge.data && newEdge.data.topcId && idMapping[newEdge.data.topcId]) {
|
|
|
|
|
+ newEdge.data.topcId = idMapping[newEdge.data.topcId];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新边的源节点和目标节点ID
|
|
|
|
|
+ if (newEdge.source && nodeIdMapping[newEdge.source]) {
|
|
|
|
|
+ newEdge.source = nodeIdMapping[newEdge.source];
|
|
|
|
|
+ }
|
|
|
|
|
+ if (newEdge.target && nodeIdMapping[newEdge.target]) {
|
|
|
|
|
+ newEdge.target = nodeIdMapping[newEdge.target];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新边的ID
|
|
|
|
|
+ if (newEdge.id) {
|
|
|
|
|
+ newEdge.id = `imported_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新边的 sourceHandle 和 targetHandle(如果需要)
|
|
|
|
|
+ // 这里可以根据需要处理连接点的映射
|
|
|
|
|
+
|
|
|
|
|
+ return newEdge;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 创建处理后的 flow 数据
|
|
|
|
|
+ const processedFlow = {
|
|
|
|
|
+ nodes: processedNodes,
|
|
|
|
|
+ edges: processedEdges
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ console.log("处理后的节点和边:", processedFlow);
|
|
|
|
|
+
|
|
|
|
|
+ // 获取当前激活的项目
|
|
|
|
|
+ const currentProject = projectStore.getActiveProject();
|
|
|
|
|
+ if (currentProject) {
|
|
|
|
|
+ // 确保当前项目的 flow 数据结构正确
|
|
|
|
|
+ const currentNodes = Array.isArray(currentProject.flow?.nodes) ? currentProject.flow.nodes : [];
|
|
|
|
|
+ const currentEdges = Array.isArray(currentProject.flow?.edges) ? currentProject.flow.edges : [];
|
|
|
|
|
+
|
|
|
|
|
+ // 合并到当前项目的 flow 中
|
|
|
|
|
+ const mergedFlow = {
|
|
|
|
|
+ nodes: [...currentNodes, ...processedFlow.nodes],
|
|
|
|
|
+ edges: [...currentEdges, ...processedFlow.edges]
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ console.log("合并后的flow:", mergedFlow);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新当前项目的 flow 数据
|
|
|
|
|
+ projectStore.updateProjectInfo(currentProject.projectId, {
|
|
|
|
|
+ ...currentProject,
|
|
|
|
|
+ flow: mergedFlow
|
|
|
|
|
+ });
|
|
|
|
|
+ emitter.emit('refresh-flow', currentProject.projectId);
|
|
|
|
|
+ emit("refresh-flow", mergedFlow);
|
|
|
|
|
+
|
|
|
|
|
+ ElMessage.success(t("message.importSuccess"));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage.error("无法获取当前项目信息");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => {
|
|
|
|
|
+ console.error(err);
|
|
|
|
|
+ ElMessage.error(err.returnMsg);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 触发确认事件,传递 project 和 identify
|
|
|
|
|
+ emit("confirm", { project: selected, identify: props.identify });
|
|
|
|
|
+ dialogVisible.value = false;
|
|
|
|
|
+ emit("update:visible", false);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 取消
|
|
|
|
|
+const handleCancel = () => {
|
|
|
|
|
+ dialogVisible.value = false
|
|
|
|
|
+ emit("update:visible", false)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 关闭对话框
|
|
|
|
|
+const handleClose = () => {
|
|
|
|
|
+ selectedRows.value = []
|
|
|
|
|
+ dialogVisible.value = false
|
|
|
|
|
+ emit("update:visible", false)
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+.project-main-content.custom-table {
|
|
|
|
|
+ max-height: 540px;
|
|
|
|
|
+ overflow: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.project-main-pagination {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ margin-top: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.custom-pagination {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.lastbtn {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-table .selected-row) {
|
|
|
|
|
+ background-color: #f3f8fb !important;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-table .selected-row td:first-child) {
|
|
|
|
|
+ border-left: 4px solid #12739e !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-table .selected-row td) {
|
|
|
|
|
+ border-top: 1px solid #12739e !important;
|
|
|
|
|
+ border-bottom: 1px solid #12739e !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-table .selected-row td:last-child) {
|
|
|
|
|
+ border-right: 1px solid #12739e !important;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|