Bladeren bron

方案筹划部分开发

zhaoen 4 maanden geleden
bovenliggende
commit
1fc7975e17

+ 138 - 83
src/api/planningScheme/index.js

@@ -1,129 +1,184 @@
 import request from "@/utils/request";
 
 export function planningSchemePage(params) {
-    return request({
-        url: "/api/v1/planning-scheme/page",
-        method: "get",
-        params,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/page",
+    method: "get",
+    params,
+  });
 }
 
 export function getListVer(data) {
-    return request({
-        url: "/api/v1/planning-scheme/getListVer",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/getListVer",
+    method: "post",
+    data,
+  });
 }
 
 export function synergismSchemePage(params) {
-    return request({
-        url: "/api/v1/planning-scheme/user-roles-page",
-        method: "post",
-        params: params,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/user-roles-page",
+    method: "post",
+    params: params,
+  });
 }
 
 export function getSynergismScheme(params) {
-    return request({
-        url: "/api/v1/planning-scheme/get",
-        method: "get",
-        params,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/get",
+    method: "get",
+    params,
+  });
 }
 
 export function planningSchemeUpdateMeasurement(data) {
-    return request({
-        url: "/api/v1/planning-scheme/update-measurement",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/update-measurement",
+    method: "post",
+    data,
+  });
 }
 
 export function planningSchemeUpdate(data) {
-    return request({
-        url: "/api/v1/planning-scheme/update",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/update",
+    method: "post",
+    data,
+  });
 }
 
 export function planningSchemeUpdateInte(data) {
-    return request({
-        url: "/api/v1/planning-scheme/update-interference",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/update-interference",
+    method: "post",
+    data,
+  });
 }
 
 export function planningSchemeUpdateTarget(data) {
-    return request({
-        url: "/api/v1/planning-scheme/update-target",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/update-target",
+    method: "post",
+    data,
+  });
 }
 
 export function planningSchemeUpdateUserRole(data) {
-    return request({
-        url: "/api/v1/planning-scheme/update-user-role",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/planning-scheme/update-user-role",
+    method: "post",
+    data,
+  });
 }
 
 export function schemeChapterInsert(data) {
-    return request({
-        url: "/api/v1/schemechapter/insert",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/schemechapter/insert",
+    method: "post",
+    data,
+  });
 }
 
 export function schemeChapterInsertPlan(data) {
-    return request({
-        url: "/api/v1/schemechapter/insert-plan",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/schemechapter/insert-plan",
+    method: "post",
+    data,
+  });
 }
 
 export function schemeChapterTree(params) {
-    return request({
-        url: "/api/v1/schemechapter/tree",
-        method: "get",
-        params,
-    });
+  return request({
+    url: "/api/v1/schemechapter/tree",
+    method: "get",
+    params,
+  });
 }
 
 export function schemeChapterUpdateList(data) {
-    return request({
-        url: "/api/v1/schemechapter/updateList",
-        method: "post",
-        data,
-    });
+  return request({
+    url: "/api/v1/schemechapter/updateList",
+    method: "post",
+    data,
+  });
 }
 
+export function flattenTree(tree, childrenKey = "children") {
+  const result = [];
+
+  function traverse(node) {
+    if (Array.isArray(node)) {
+      node.forEach(traverse);
+    } else {
+      // 将当前节点加入结果(可选择是否保留 children 字段)
+      const { [childrenKey]: _, ...rest } = node;
+      result.push(rest);
+
+      // 递归处理子节点
+      if (node[childrenKey] && node[childrenKey].length > 0) {
+        traverse(node[childrenKey]);
+      }
+    }
+  }
 
+  traverse(tree);
+  return result;
+}
 
-export function flattenTree(tree, childrenKey = 'children') {
-    const result = [];
-
-    function traverse(node) {
-        if (Array.isArray(node)) {
-            node.forEach(traverse);
-        } else {
-            // 将当前节点加入结果(可选择是否保留 children 字段)
-            const { [childrenKey]: _, ...rest } = node;
-            result.push(rest);
+// 查询文件
+export function viewFile(param) {
+  return request({
+    url: `/api/v1/planning-scheme/getFileByType`,
+    method: "get",
+    params: param,
+  });
+}
 
-            // 递归处理子节点
-            if (node[childrenKey] && node[childrenKey].length > 0) {
-                traverse(node[childrenKey]);
-            }
-        }
-    }
+// 查询历史版本
+export function queryHistory(param) {
+  return request({
+    url: `/api/v1/planning-scheme/page-version`,
+    method: "get",
+    params: param,
+  });
+}
 
-    traverse(tree);
-    return result;
+//装备详情
+export function zbGet(id) {
+  return request({
+    url: `/api/v1/subplanzb/get/${id}`,
+    method: "get",
+  });
+}
+// 装备新增
+export function zbAdd(data) {
+  return request({
+    url: `/api/v1/subplanzb/insert`,
+    method: "post",
+    data,
+  });
+}
+// 装备查询
+export function zbPage(param) {
+  return request({
+    url: `/api/v1/subplanzb/findPage`,
+    method: "get",
+    params: param,
+  });
+}
+// 装备修改
+export function zbUpdate(data) {
+  return request({
+    url: `/api/v1/subplanzb/update`,
+    method: "post",
+    data,
+  });
+}
+// 装备删除
+export function zbDel(id) {
+  return request({
+    url: `/api/v1/subplanzb/delete/${id}`,
+    method: "get",
+  });
 }

+ 10 - 4
src/components/Components/TaskUserCard.vue

@@ -107,10 +107,16 @@
       <el-button icon="el-icon-view" class="blue-btn" @click="viewDetail">
         详情
       </el-button>
-      <el-button icon="el-icon-tickets" class="blue-btn" @click="viewChildsDetail">
+      <el-button
+        icon="el-icon-tickets"
+        class="blue-btn"
+        @click="viewChildsDetail"
+      >
         子任务
       </el-button>
-      <el-button icon="el-icon-edit" class="blue-btn" @click="editPlan">编辑</el-button>
+      <el-button icon="el-icon-edit" class="blue-btn" @click="editPlan">
+        编辑
+      </el-button>
     </div>
   </el-card>
 </template>
@@ -180,8 +186,8 @@
       },
       compileStatusTagType() {
         const statusMap = {
-          定稿: "success",
-          暂存: "warning",
+          2: "success",
+          1: "warning",
         };
         return statusMap[this.plan.taskStatus] || "info";
       },

+ 26 - 6
src/components/GlobalComponents/OverallCard.vue

@@ -121,18 +121,26 @@
     </div>
 
     <div class="plan-actions">
-      <el-button type="warning" icon="el-icon-download" @click="exportPlan">
-        导出
-      </el-button>
-
       <el-button
         v-if="isAllImported"
-        icon="el-icon-edit"
-        class="blue-btn"
+        type="warning"
+        icon="el-icon-download"
         @click="viewDetail"
       >
         编制靶标保障方案
       </el-button>
+
+      <!--<el-button-->
+      <!--  v-if="isAllImported"-->
+      <!--  icon="el-icon-edit"-->
+      <!--  class="blue-btn"-->
+      <!--  @click="viewDetail"-->
+      <!--&gt;-->
+      <!--  编制靶标保障方案-->
+      <!--</el-button>-->
+      <el-button v-if="isDef" icon="el-icon-time" @click="viewHistory(plan)">
+        历史记录
+      </el-button>
     </div>
   </el-card>
 </template>
@@ -159,6 +167,10 @@
           version: "",
         }),
       },
+      isDef: {
+        type: Boolean,
+        default: true,
+      },
     },
     data() {
       return {
@@ -196,6 +208,13 @@
       this.checkOverflows();
     },
     methods: {
+      // 查看历史记录
+      viewHistory(plan) {
+        this.$router.push({
+          path: "/GlobalComponents/viewHistory",
+          query: { batchId: plan.batchId },
+        });
+      },
       getSchemeStatusType(status) {
         const statusMap = {
           已编制: "success",
@@ -287,6 +306,7 @@
   ::v-deep .el-card__header {
     background-color: #123e7f;
   }
+
   .target-plan-card {
     margin-bottom: 15px;
     transition: all 0.3s ease;

+ 773 - 0
src/components/GlobalComponents/viewHistory.vue

@@ -0,0 +1,773 @@
+<template>
+  <div>
+    <DarkLayout :query-form="queryForm">
+      <!-- 查询表单插槽 -->
+      <template #query-form>
+        <el-form-item label="任务名称">
+          <el-input
+            v-model="queryForm.taskName"
+            placeholder="请输入任务名称"
+            clearable
+          />
+        </el-form-item>
+        <el-form-item label="任务代号">
+          <el-input
+            v-model="queryForm.taskCode"
+            placeholder="请输入任务代号"
+            clearable
+          />
+        </el-form-item>
+      </template>
+
+      <!-- Header右侧操作按钮 -->
+      <template #header-actions>
+        <el-button type="primary" @click="handleQuery">查询</el-button>
+        <el-button class="blue-btn" @click="resetQuery">重置</el-button>
+        <el-button class="blue-btn" @click="handleAdd">新增</el-button>
+      </template>
+
+      <!-- 主要内容 -->
+      <template #main>
+        <OverallCard
+          v-for="plan in plans"
+          :key="plan.id"
+          :plan="plan"
+          :is-def="isDef"
+          @view-detail="handleViewDetail"
+          @export-plan="handleExportPlan"
+          @link-to="(val) => linkTo(val, plan)"
+        />
+        <!--<el-empty v-else description="暂无方案数据"/>-->
+      </template>
+
+      <!-- 底部右侧分页 -->
+      <template #footer-actions>
+        <el-pagination
+          :current-page="pagination.currentPage"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="pagination.pageSize"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="pagination.total"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </template>
+    </DarkLayout>
+
+    <!-- 干扰方案上传弹窗 -->
+    <el-dialog :visible.sync="showInteUpload" :title="inteHasFile" width="50%">
+      <div v-if="inteHasFile === '上传干扰方案'">
+        <el-upload
+          ref="inteUpload"
+          class="upload-demo"
+          action="#"
+          :file-list="inteFileList"
+          accept=".doc,.docx"
+          :auto-upload="false"
+          :on-change="handleInteFileChange"
+          :before-upload="beforeUploadHandle"
+          :limit="1"
+        >
+          <!-- ,.pdf,.xlsx,.xls -->
+          <el-button slot="trigger" size="small" type="primary">
+            选取文件
+          </el-button>
+          <el-button
+            style="margin-left: 10px"
+            size="small"
+            type="success"
+            @click="submitInteUpload"
+          >
+            上传到服务器
+          </el-button>
+          <div slot="tip" class="el-upload__tip">
+            只能上传doc、docx格式的文件
+          </div>
+        </el-upload>
+      </div>
+
+      <div v-else>
+        <VueOfficeDocx :src="inteFileView" class="preview-container" />
+        <!--<el-table :data="grFileList" border>-->
+        <!--  <el-table-column label="文件名称" prop="fileName"></el-table-column>-->
+        <!--  <el-table-column label="文件类型" prop="fileType"></el-table-column>-->
+        <!--  <el-table-column label="操作" width="120px" align="center">-->
+        <!--    <template slot-scope="{row}">-->
+        <!--      <el-button @click="downFile(row)">下载</el-button>-->
+        <!--    </template>-->
+        <!--  </el-table-column>-->
+        <!--</el-table>-->
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="showInteUpload = false">取消</el-button>
+      </span>
+    </el-dialog>
+
+    <!-- 靶标方案上传弹窗 -->
+    <el-dialog :visible.sync="showTargetUpload" :title="bbHasFile" width="50%">
+      <div v-if="bbHasFile === '上传靶标方案'">
+        <el-upload
+          ref="targetUpload"
+          class="upload-demo"
+          action="#"
+          :file-list="targetFileList"
+          accept=".docx"
+          :auto-upload="false"
+          :on-change="handleTargetFileChange"
+          :before-upload="beforeUploadHandle"
+          :limit="1"
+        >
+          <el-button slot="trigger" size="small" type="primary">
+            选取文件
+          </el-button>
+          <el-button
+            style="margin-left: 10px"
+            size="small"
+            type="success"
+            @click="submitTargetUpload"
+          >
+            上传到服务器
+          </el-button>
+          <div slot="tip" class="el-upload__tip">只能上传docx格式的文件</div>
+        </el-upload>
+      </div>
+      <div v-else>
+        <VueOfficeDocx :src="bbFileView" class="preview-container" />
+        <!--<el-table :data="bbFileList" border>-->
+        <!--  <el-table-column label="文件名称" prop="fileName"></el-table-column>-->
+        <!--  <el-table-column label="文件类型" prop="fileType"></el-table-column>-->
+        <!--  <el-table-column label="操作" width="120px" align="center">-->
+        <!--    <template slot-scope="{row}">-->
+        <!--      <el-button @click="downFile(row)">下载</el-button>-->
+        <!--    </template>-->
+        <!--  </el-table-column>-->
+        <!--</el-table>-->
+      </div>
+
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="showTargetUpload = false">取消</el-button>
+      </span>
+    </el-dialog>
+
+    <!-- 任务详情弹窗 -->
+    <el-dialog
+      title="任务详情"
+      :visible.sync="dialogVisible"
+      width="50%"
+      :before-close="handleClose"
+    >
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="方案名称">
+          {{ currentPlan.planName }}
+        </el-descriptions-item>
+        <el-descriptions-item label="任务名称">
+          {{ currentPlan.taskName }}
+        </el-descriptions-item>
+        <el-descriptions-item label="任务代号">
+          {{ currentPlan.taskCode }}
+        </el-descriptions-item>
+        <el-descriptions-item label="开始时间">
+          {{ currentPlan.startTime }}
+        </el-descriptions-item>
+        <el-descriptions-item label="结束时间">
+          {{ currentPlan.endTime }}
+        </el-descriptions-item>
+        <el-descriptions-item label="编制状态">
+          {{ currentPlan.compileStatus }}
+        </el-descriptions-item>
+        <el-descriptions-item label="状态">
+          {{ currentPlan.status }}
+        </el-descriptions-item>
+      </el-descriptions>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false">关闭</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+  import DarkLayout from "@/components/GlobalComponents/DarkLayout.vue";
+  // import InterferenceCard from '@/components/Components/InterferenceCard.vue'
+  // import DarkDialog from "@/components/Components/DarkDialog.vue";
+  import {
+    planningSchemePage,
+    planningSchemeUpdate,
+    planningSchemeUpdateInte,
+    planningSchemeUpdateTarget,
+    planningSchemeUploadTarget,
+    viewFile,
+    queryHistory,
+  } from "@/api/planningScheme";
+  import { exportSolutionToWord } from "@/views/planningSchem/comprehensive/wordExporter";
+  import { baseURL, contentType, tokenName } from "@/config";
+  import store from "@/store";
+  import { doUpload } from "@/api/tool/ossTool";
+  // import VueOfficeDocx from '@vue-office/docx'
+  // import '@vue-office/docx/lib/index.css'
+
+  export default {
+    name: "Historybb",
+    components: {
+      // DarkDialog,
+      DarkLayout,
+      // InterferenceCard,
+      // VueOfficeDocx
+    },
+    data() {
+      return {
+        isDef: false,
+        bbHasFile: "上传靶标方案",
+        inteHasFile: "上传干扰方案",
+        bbFileView: "",
+        inteFileView: "",
+        tableData: [
+          {
+            date: "2023-06-01",
+            name: "张三",
+            address: "北京市海淀区",
+          },
+          {
+            date: "2023-06-02",
+            name: "李四",
+            address: "上海市浦东新区",
+          },
+        ],
+        dialogVisible: false,
+        currentPlan: {}, // 当前选中的任务数据
+        queryForm: {
+          taskName: "",
+          taskCode: "",
+        },
+        plans: [],
+        planss: [
+          {
+            id: "1",
+            fightAway: "对陆",
+            planName: "新型导弹打击试验",
+            taskName: "新型导弹打击试验",
+            taskCode: "TASK-2023-001",
+            startTime: "2023-01-01",
+            endTime: "2023-12-31",
+            status: "有效",
+            interferenceSchemeStatus: "已导入",
+            measurementSchemeStatus: "已编制",
+            targetSchemeStatus: "已导入",
+            version: "V1.0.0",
+          },
+          {
+            id: "2",
+            fightAway: "对陆",
+            planName: "电子对抗演练",
+            taskName: "电子对抗演练",
+            taskCode: "TASK-2023-002",
+            startTime: "2023-02-01",
+            endTime: "2023-11-30",
+            status: "待审核",
+            interferenceSchemeStatus: "已导入",
+            measurementSchemeStatus: "已编制",
+            targetSchemeStatus: "未导入",
+            version: "V1.1.0",
+          },
+          {
+            id: "4",
+            fightAway: "对陆",
+            planName: "电子对抗演练",
+            taskName: "电子对抗演练",
+            taskCode: "TASK-2023-003",
+            startTime: "2023-03-01",
+            endTime: "2023-10-31",
+            status: "草稿",
+            interferenceSchemeStatus: "未导入",
+            measurementSchemeStatus: "未编制",
+            targetSchemeStatus: "未导入",
+            version: "V0.9.0",
+          },
+
+          {
+            id: "3",
+            fightAway: "对陆",
+            planName: "新型导弹打击试验",
+            taskName: "新型导弹打击试验",
+            taskCode: "TASK-2023-003",
+            startTime: "2023-03-01",
+            endTime: "2023-10-31",
+            status: "草稿",
+            interferenceSchemeStatus: "已导入",
+            measurementSchemeStatus: "未编制",
+            targetSchemeStatus: "未导入",
+            version: "V0.9.0",
+          },
+          {
+            id: "9",
+            fightAway: "对陆",
+            planName: "电子对抗演练",
+            taskName: "电子对抗演练",
+            taskCode: "TASK-2023-001",
+            startTime: "2023-01-01",
+            endTime: "2023-12-31",
+            status: "有效",
+            interferenceSchemeStatus: "已导入",
+            measurementSchemeStatus: "已编制",
+            targetSchemeStatus: "未导入",
+            version: "V1.0.0",
+          },
+        ],
+        pagination: {
+          currentPage: 1,
+          pageSize: 10,
+          total: 0,
+        },
+        selectPlan: null,
+        showAdvancedSearch: false,
+        showInteUpload: false, // 干扰方案上传弹窗
+        showTargetUpload: false, // 靶标方案上传弹窗
+        inteFileList: [], // 干扰方案文件列表
+        targetFileList: [], // 靶标方案文件列表
+      };
+    },
+    mounted() {
+      this.handleQuery();
+    },
+    methods: {
+      // 下载文件
+      downFile(data) {
+        const fileUrl = data.fileHttp;
+        if (!fileUrl) {
+          this.$message.error("文件链接不存在,无法下载");
+          return;
+        }
+        const a = document.createElement("a");
+        a.href = fileUrl;
+        a.download = data.fileName; // 可根据需求从 data 中取文件名,如 data.fileName
+        document.body.appendChild(a);
+        a.click();
+        document.body.removeChild(a);
+      },
+
+      // 页面导航方法
+      navigateTo(type, isOk) {
+        if (type === "inte") {
+          console.log("跳转至干扰方案", { isOk });
+          this.$router.push({ path: "/childPlan/intePlan", query: { isOk } });
+        } else if (type === "target") {
+          this.$router.push({ path: "/childPlan/targetPlan", query: { isOk } });
+        }
+      },
+
+      // 上传之前
+      beforeUploadHandle(file) {
+        let Xls = file.name.split(".")[file.name.split(".").length - 1];
+        const isLt4M = file.size / 1024 / 1024 < 4;
+        if (
+          // Xls === "xls" ||
+          Xls === "docx"
+          // Xls === "doc" ||
+          // Xls === "xlsx" ||
+          // Xls === "txt" ||
+          // Xls === "png" ||
+          // Xls === "jpg" ||
+          // Xls === "gif" ||
+          // Xls === "pdf" ||
+          // Xls === "ppt" ||
+          // Xls === "pptx"
+          // Xls != 'exe' &&
+          // Xls != 'bat' &&
+          // Xls != 'sh'
+        ) {
+          if (!isLt4M) {
+            this.$message({
+              message: "上传文件大小不能超过4MB!",
+              type: "warning",
+            });
+            return false;
+          } else {
+            return file;
+          }
+        } else {
+          this.$message.error("上传文件格式不正确!");
+          return false;
+        }
+      },
+
+      // 干扰方案上传成功处理
+      async handleInteUploadSuccess(response, file, fileList) {
+        if (response.code !== 200) {
+          this.$message.success("干扰方案上传失败");
+          return;
+        }
+        this.$message.success("干扰方案上传成功");
+
+        const fileJson = JSON.stringify(
+          fileList
+            .map((item) => ({
+              fileName: item.name,
+              fileHttp: item.response?.data?.url || "",
+              fileType: item.response?.data?.type || "",
+              type: 1,
+            }))
+            .filter((item) => item.fileHttp)
+        );
+
+        try {
+          await planningSchemeUpdate({
+            id: this.selectPlan.id,
+            interferenceSchemeStatus: "已导入",
+            schemeSubPlan: fileJson,
+          });
+
+          this.showInteUpload = false;
+          this.inteFileList = [];
+          this.handleQuery();
+        } catch (err) {
+          console.error("更新方案失败:", err);
+          this.$message.error("方案更新失败");
+        }
+      },
+
+      // 靶标方案上传成功处理
+      async handleTargetUploadSuccess(response, file, fileList) {
+        if (response.code !== 200) {
+          this.$message.success("靶标方案上传失败");
+          return;
+        }
+        this.$message.success("靶标方案上传成功");
+
+        // 1. 将 fileList 转为 JSON(和干扰方案保持一致)
+        const fileJson = JSON.stringify(
+          fileList
+            .map((item) => ({
+              fileName: item.name,
+              fileHttp: item.response?.data?.url || "",
+              fileType: item.response?.data?.type || "",
+              type: 2,
+            }))
+            .filter((item) => item.fileHttp) // 过滤掉上传失败的文件
+        );
+
+        try {
+          // 2. 调用 API 更新靶标方案
+          await planningSchemeUpdate({
+            id: this.selectPlan.id,
+            schemeSubPlan: fileJson,
+          });
+
+          // 3. 更新 UI 状态
+          this.showTargetUpload = false;
+          this.targetFileList = [];
+
+          // 4. 刷新数据
+          this.handleQuery();
+        } catch (err) {
+          console.error("靶标方案更新失败:", err);
+          this.$message.error("靶标方案保存失败,请重试");
+        }
+      },
+
+      // 同步干扰方案文件列表
+      handleInteFileChange(file, fileList) {
+        this.inteFileList = fileList; // ✅ 手动同步
+      },
+
+      // 同步靶标方案文件列表
+      handleTargetFileChange(file, fileList) {
+        this.targetFileList = fileList; // ✅ 手动同步
+      },
+
+      // 上传失败处理
+      handleUploadError(err, file, fileList) {
+        this.$message.error("文件上传失败,请重试");
+      },
+
+      /**
+       * 合并 schemeSubPlan
+       * @param {Array} existingList - 已有的文件列表(解析后的)
+       * @param {Object} newFile - 新上传的文件信息 { fileName, fileHttp, fileType, type }
+       * @returns {Array} 合并后的列表
+       */
+      mergeSchemeSubPlan(existingList, newFile) {
+        // 1. 先过滤掉同 type 的旧文件(保证每个 type 只有一个)
+        const filtered = existingList.filter(
+          (item) => item.type !== newFile.type
+        );
+
+        // 2. 添加新文件
+        return [...filtered, newFile];
+      },
+
+      /**
+       * 解析 schemeSubPlan 字符串为数组
+       * @returns {Array} 解析后的文件列表
+       */
+      parseSchemeSubPlan() {
+        try {
+          console.log(this.selectPlan.schemeSubPlan);
+          const str = this.selectPlan.schemeSubPlan;
+          return str ? JSON.parse(str) : [];
+        } catch (error) {
+          console.error("解析 schemeSubPlan 失败:", error);
+          return [];
+        }
+      },
+
+      // 提交干扰方案上传
+      async submitInteUpload() {
+        if (this.inteFileList.length === 0) {
+          this.$message.warning("请先选择文件");
+          return;
+        }
+
+        const formData = new FormData();
+        this.inteFileList.forEach((file) => {
+          if (file.raw) {
+            formData.append("files", file.raw);
+          }
+        });
+
+        try {
+          const response = await doUpload(formData);
+          if (response.code !== 0) {
+            this.$message.error(`上传失败: ${response.msg || "未知错误"}`);
+            return;
+          }
+
+          // ✅ 1. 构造新文件对象
+          const newFile = {
+            fileName: this.inteFileList[0].name,
+            fileHttp: response.data.fileStoragePath,
+            fileType: response.data.suffix,
+            type: 1, // 干扰方案
+          };
+
+          // ✅ 2. 解析已有数据
+          const existingList = this.parseSchemeSubPlan();
+
+          // ✅ 3. 合并
+          const mergedList = this.mergeSchemeSubPlan(existingList, newFile);
+
+          // ✅ 4. 转为 JSON 字符串
+          const fileJson = JSON.stringify(mergedList);
+
+          // ✅ 5. 更新干扰方案
+          await planningSchemeUpdateInte({
+            id: this.selectPlan.id,
+            schemeSubPlan: fileJson,
+          });
+
+          // ✅ 6. 成功后清空
+          this.showInteUpload = false;
+          this.inteFileList = [];
+          this.$refs.inteUpload?.clearFiles(); // 注意:是 inteUpload,不是 targetUpload
+
+          // ✅ 7. 刷新
+          this.handleQuery();
+          this.$message.success("干扰方案上传并更新成功");
+        } catch (error) {
+          console.error("上传或更新失败:", error);
+          this.$message.error("操作失败:" + (error.message || "请重试"));
+        }
+      },
+
+      // 提交靶标方案上传
+      async submitTargetUpload() {
+        if (this.targetFileList.length === 0) {
+          this.$message.warning("请先选择文件");
+          return;
+        }
+
+        const formData = new FormData();
+        this.targetFileList.forEach((file) => {
+          if (file.raw) {
+            formData.append("files", file.raw);
+          }
+        });
+
+        try {
+          const response = await doUpload(formData);
+          if (response.code !== 0) {
+            this.$message.error(`上传失败: ${response.msg || "未知错误"}`);
+            return;
+          }
+
+          // ✅ 1. 构造新文件对象
+          const newFile = {
+            fileName: this.targetFileList[0].name,
+            fileHttp: response.data.fileStoragePath,
+            fileType: response.data.suffix,
+            type: 2, // 靶标方案
+          };
+
+          // ✅ 2. 解析已有数据
+          const existingList = this.parseSchemeSubPlan();
+
+          // ✅ 3. 合并
+          const mergedList = this.mergeSchemeSubPlan(existingList, newFile);
+
+          // ✅ 4. 转为 JSON 字符串
+          const fileJson = JSON.stringify(mergedList);
+
+          // ✅ 5. 更新靶标方案
+          await planningSchemeUpdateTarget({
+            id: this.selectPlan.id,
+            schemeSubPlan: fileJson,
+          });
+
+          // ✅ 6. 成功后清空
+          this.showTargetUpload = false;
+          this.targetFileList = [];
+          this.$refs.targetUpload?.clearFiles();
+
+          // ✅ 7. 刷新
+          this.handleQuery();
+          this.$message.success("靶标方案上传并更新成功");
+        } catch (error) {
+          console.error("上传或更新失败:", error);
+          this.$message.error("操作失败:" + (error.message || "请重试"));
+        }
+      },
+
+      handleClose(done) {
+        done();
+      },
+
+      handleViewDetail(plan) {
+        this.$router.push({
+          path: "/planningSchem/overallPlanDesign",
+          query: { batchId: plan.batchId, isDef: this.isDef },
+        });
+      },
+      //导出
+      async handleExportPlan(plan) {
+        try {
+          await exportSolutionToWord(plan.batchId);
+          this.$message.success("导出Word成功");
+        } catch (error) {
+          this.$message.error(error.message || "导出Word失败");
+        }
+        // this.$message.success("导出成功!")
+      },
+      // 子方案跳转,增加plan参数用于获取方案状态
+      linkTo(val, plan) {
+        console.log("linkTo参数:", val, "方案状态:", plan);
+        // 根据不同类型和状态判断显示上传还是跳转
+        if (val.type === "inte" && plan.interferenceSchemeStatus === "未导入") {
+          console.log("干扰方案未导入,显示上传组件");
+          this.inteHasFile = "上传干扰方案";
+          this.selectPlan = plan;
+          this.showInteUpload = true;
+        } else if (
+          val.type === "target" &&
+          plan.targetSchemeStatus === "未导入"
+        ) {
+          console.log("靶标方案未导入,显示上传组件");
+          this.bbHasFile = "上传靶标方案";
+          this.selectPlan = plan;
+          this.showTargetUpload = true;
+        } else if (
+          val.type === "meas" &&
+          plan.measurementSchemeStatus === "未编制"
+        ) {
+          this.$router.push({
+            path: "/childPlan/measPlan",
+            query: { plan: JSON.stringify(plan) },
+          });
+        } else if (
+          val.type === "meas" &&
+          plan.measurementSchemeStatus === "已编制"
+        ) {
+          this.$router.push({
+            path: "/home/collaborativeCreate_Cl",
+            query: { plan: JSON.stringify(plan), isEdit: "false" },
+          });
+        } else if (
+          val.type === "inte" &&
+          plan.interferenceSchemeStatus === "已导入"
+        ) {
+          // this.grFileList = JSON.parse(plan.schemeSubPlan)
+          this.getViewFile(plan.id, 3, "inteFileView");
+        } else if (
+          val.type === "target" &&
+          plan.targetSchemeStatus === "已导入"
+        ) {
+          // this.bbFileList = JSON.parse(plan.schemeSubPlan)
+          this.getViewFile(plan.id, 1, "bbFileView");
+        } else {
+          // 已导入/已编制状态正常跳转
+          this.navigateTo(val.type, val.isOk);
+        }
+      },
+
+      getViewFile(id, type, file) {
+        let param = {
+          id: id,
+          type: type,
+          isDef: this.isDef,
+        };
+        viewFile(param).then((res) => {
+          if (res.code !== 0) {
+            return;
+          }
+          let data = JSON.parse(res.data.schemeSubPlan);
+          this[file] = data[0].fileHttp;
+          if (type === 1) {
+            this.bbHasFile = "查看靶标方案";
+            this.showTargetUpload = true;
+          } else {
+            this.inteHasFile = "查看干扰方案";
+            this.showInteUpload = true;
+          }
+        });
+      },
+
+      async handleQuery() {
+        // 查询逻辑
+        const res = await queryHistory({
+          ...this.queryForm,
+          batchId: this.$route.query.batchId,
+          pageNo: this.pagination.currentPage,
+          pageSize: this.pagination.pageSize,
+        });
+        this.plans = res.data.records;
+        this.pagination.total = res.data.total;
+      },
+      resetQuery() {
+        this.queryForm = {
+          taskName: "",
+          taskCode: "",
+        };
+        this.handleQuery();
+      },
+      handleAdd() {
+        this.$router.push({ path: "/childPlans/associationTask" });
+      },
+      handleSizeChange(val) {
+        this.pagination.pageSize = val;
+        this.fetchData();
+      },
+      handleCurrentChange(val) {
+        this.pagination.currentPage = val;
+        this.fetchData();
+      },
+      fetchData() {
+        // 获取数据逻辑
+      },
+    },
+  };
+</script>
+
+<style scoped>
+  .preview-container {
+    width: 100%;
+    min-height: 300px;
+    max-height: 500px;
+    border: 1px solid #eee;
+  }
+
+  ::v-deep .el-dialog__body {
+    max-height: calc(100vh - 150px);
+    overflow: auto;
+    padding: 20px;
+  }
+</style>
+
+<style scoped></style>

+ 2 - 0
src/main.js

@@ -15,6 +15,8 @@ import VueOfficePdf from "@vue-office/pdf";
 import "@vue-office/docx/lib/index.css";
 import "@vue-office/excel/lib/index.css";
 
+// 引入全局dialog样式
+import "@/styles/dialogOwnStyle.scss";
 //导入全局组件
 import "@/components";
 //引入全局时间组件

+ 7 - 0
src/router/index.js

@@ -225,6 +225,13 @@ export const constantRoutes = [
     component: () => import("@/views/planningSchem/childsPlan/measPlan.vue"),
     hidden: false,
   },
+  /*历史版本展示页面*/
+  {
+    path: "/GlobalComponents/viewHistory",
+    name: "historybb",
+    component: () => import("@/components/GlobalComponents/viewHistory.vue"),
+    hidden: false,
+  },
   /*测量方案预览跳转页*/
   {
     path: "/childPlans/measPlanDetail",

+ 76 - 0
src/styles/dialogOwnStyle.scss

@@ -0,0 +1,76 @@
+.dark-dialog {
+  .el-dialog {
+    background: #11285e;
+    border: 1px solid #425163;
+    border-radius: 4px;
+
+    &__header {
+      border-bottom: 1px solid #425163;
+      padding: 15px 20px;
+
+      .el-dialog__title,
+      .dark-dialog-title {
+        color: #e0e6ed !important;
+        font-size: 16px !important;
+        font-weight: bold !important;
+      }
+
+      .el-dialog__headerbtn {
+        .el-dialog__close {
+          color: #8796ad;
+
+          &:hover {
+            color: #e0e6ed;
+          }
+        }
+      }
+    }
+
+    &__body {
+      color: #e0e6ed;
+      padding: 20px;
+
+      .el-descriptions {
+        &__header {
+          .el-descriptions__title {
+            color: #e0e6ed;
+          }
+        }
+
+        &__body {
+          background: transparent;
+
+          .el-descriptions-item__label {
+            color: #8796ad;
+            background: #1e2733;
+          }
+
+          .el-descriptions-item__content {
+            color: #e0e6ed;
+            background: #1e2733;
+          }
+        }
+      }
+    }
+
+    &__footer {
+      border-top: 1px solid #425163;
+      padding: 10px 20px;
+      text-align: right;
+
+      .el-button {
+        &.dark-button {
+          background-color: #425163;
+          border-color: #5a6b7d;
+          color: #e0e6ed;
+
+          &:hover {
+            background-color: #5a6b7d;
+            border-color: #677a8c;
+            color: #ffffff;
+          }
+        }
+      }
+    }
+  }
+}

+ 13 - 34
src/views/dataManagement/threeModelTypeManagement/index.vue

@@ -18,7 +18,8 @@
           filterable
           style="width: 180px"
         >
-          <el-option v-for="(item, index) in $getDictList('sys_type_category')" :key="index" :label="item.dictName" :value="item.dictName"/>
+          <el-option v-for="(item, index) in $getDictList('sys_type_category')" :key="index" :label="item.dictName"
+                     :value="item.dictName"/>
         </el-select>
       </el-form-item>
       <!--<el-form-item label="创建时间">-->
@@ -60,28 +61,26 @@
       >
         <el-table-column type="selection" width="55"/>
         <el-table-column type="index" label="序号" width="60"/>
-        <!--<el-table-column prop="id" label="编号" width="100" sortable align="center"/>-->
+        <!--<el-table-column prop="id" label="编号" width="100" sortable />-->
         <el-table-column
           prop="typeName"
           label="类型名称"
-          align="center"
           show-overflow-tooltip
         />
         <el-table-column
           prop="typeCategory"
           label="类型分类"
-          align="center"
         />
-        <el-table-column prop="description" label="模型描述" align="center"/>
-        <el-table-column prop="status" label="是否启用" width="120" align="center">
+        <el-table-column prop="description" label="模型描述"/>
+        <el-table-column prop="status" label="是否启用" width="120">
           <template slot-scope="{ row }">
             <el-tag type="success" v-if="row.status === 1">是</el-tag>
             <el-tag type="danger" v-else>否</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="createBy" label="创建人" width="160" align="center"/>
-        <el-table-column prop="createTime" label="创建时间" width="220" align="center" sortable/>
-        <el-table-column label="操作" fixed="right" align="center" width="220">
+        <el-table-column prop="createBy" label="创建人" width="160"/>
+        <el-table-column prop="createTime" label="创建时间" width="220" sortable/>
+        <el-table-column label="操作" fixed="right" width="220">
           <template slot-scope="{ row }">
             <div class="action-bar">
               <!--<el-link type="primary" :underline="false" @click="handleView(row)">查看</el-link>-->
@@ -151,7 +150,8 @@
         </el-form-item>
         <el-form-item label="类型分类" prop="typeCategory">
           <el-select v-model="addForm.typeCategory" placeholder="请选择类型分类" style="width: 220px">
-            <el-option v-for="(item, index) in $getDictList('sys_type_category')" :key="index" :label="item.dictName" :value="item.dictName"/>
+            <el-option v-for="(item, index) in $getDictList('sys_type_category')" :key="index" :label="item.dictName"
+                       :value="item.dictName"/>
           </el-select>
         </el-form-item>
         <el-form-item label="类型描述" prop="description">
@@ -279,29 +279,6 @@ export default {
         this.pagination.total = res.data.total
         this.tableData = res.data.records || []
       })
-      // 过滤
-      // let list = this.allData.slice()
-      //
-      // if (this.queryForm.name) {
-      //   const kw = this.queryForm.name.trim()
-      //   list = list.filter(r => r.name.includes(kw))
-      // }
-      // if (this.queryForm.code) {
-      //   list = list.filter(r => r.code === this.queryForm.code)
-      // }
-      // if (this.queryForm.dateRange && this.queryForm.dateRange.length === 2) {
-      //   const [start, end] = this.queryForm.dateRange
-      //   const s = new Date(start).getTime()
-      //   const e = new Date(end).getTime()
-      //   list = list.filter(r => {
-      //     const t = new Date(r.createTime).getTime()
-      //     return t >= s && t <= e
-      //   })
-      // }
-      // this.pagination.total = list.length
-      // // 分页
-      // const startIdx = (this.pagination.currentPage - 1) * this.pagination.pageSize
-      // this.tableData = list.slice(startIdx, startIdx + this.pagination.pageSize)
     },
     resetQuery() {
       this.queryForm = {
@@ -448,11 +425,13 @@ export default {
 .el-form-item__label {
   color: #fff !important;
 }
+
 .el-dialog__title {
   color: #e0e6ed !important;
   font-size: 16px !important;
   font-weight: bold !important;
 }
+
 .dark-dialog {
   .el-dialog {
     background: #11285e;
@@ -547,7 +526,7 @@ export default {
 
 .three-model-container .el-table td {
   color: #ffffff !important;
-  background:  rgba(1, 25, 97) !important;
+  background: rgba(1, 25, 97) !important;
 }
 
 .three-model-container .el-table th {

+ 5 - 5
src/views/equipment/equipment.vue

@@ -44,11 +44,11 @@
         <el-table-column prop="ipAddress" label="IP地址" width="120" align="center"/>
         <el-table-column prop="port" label="端口" width="100" align="center"/>
         <el-table-column prop="communicationType" label="通讯方式" width="100" align="center">
-          <template slot-scope="{ row }">
-            <span v-if="row.communicationType === '0'">PDXP</span>
-            <span v-else-if="row.communicationType === '1'">UDP</span>
-            <span v-else>TCP</span>
-          </template>
+          <!--<template slot-scope="{ row }">-->
+          <!--  <span v-if="row.communicationType === '0'">PDXP</span>-->
+          <!--  <span v-else-if="row.communicationType === '1'">UDP</span>-->
+          <!--  <span v-else>TCP</span>-->
+          <!--</template>-->
         </el-table-column>
         <el-table-column prop="connectionStatus" label="连通状态" width="100" align="center">
           <template slot-scope="{ row }">

+ 3 - 3
src/views/planAndDeduction/childsTask/components/childTaskCard.vue

@@ -86,7 +86,7 @@
         <div class="info-row">
           <span class="info-label dark-label">处理状态:</span>
           <el-tag :type="compileStatusTagType" effect="dark" class="info-value">
-            {{ $getDictNameByValue("sys_childTask_status", plan.applyStatus) }}
+            {{ $getDictNameByValue("sys_childTask_status", plan.subTaskStatus) }}
           </el-tag>
         </div>
 
@@ -181,8 +181,8 @@ export default {
     },
     compileStatusTagType() {
       const statusMap = {
-        定稿: "success",
-        暂存: "warning",
+        "2": "success",
+        "1": "warning",
       };
       return statusMap[this.plan.subTaskStatus] || "info";
     },

+ 25 - 5
src/views/planningSchem/childsPlan/measPlan.vue

@@ -67,12 +67,12 @@
         <div v-if="currentStep === 0" class="animate-fadeIn space-y-6">
           <!-- 自动筹划页面 -->
           <div v-if="planningType === 'auto'">
-            <auto-plan-create></auto-plan-create>
+            <auto-plan-create :planInfo="planInfo" :dataJson="planJson"></auto-plan-create>
           </div>
 
           <!-- 半自动筹划页面 -->
           <div v-if="planningType === 'semi'">
-            <semi-plan-create :planInfo="planInfo" :dataJson="planJson" @save-plan="savePlanJson"></semi-plan-create>
+            <semi-plan-create ref="semiPlanCreate" :planInfo="planInfo" :dataJson="planJson" @save-plan="savePlanJson"></semi-plan-create>
           </div>
         </div>
 
@@ -448,11 +448,15 @@ export default {
       }
     },
     // 下一步
-    nextStep() {
-
+   async nextStep() {
       // 检查是否可以进入下一步
       if (!this.canProceedToNextStep) return;
 
+      if (this.currentStep === 0) {
+        this.planJson = await this.$refs['semiPlanCreate'].getAllData()
+        console.log(this.planJson)
+      }
+
       // 如果是最后一步,提交表单
       if (this.currentStep === 1) {
         this.submitForm();
@@ -478,7 +482,23 @@ export default {
     submitForm() {
       const planId = JSON.parse(this.$route.query.plan).id
       const userIds = this.selectedUsers.map(user => user.id);
-      planningSchemeUpdateMeasurement({id:planId,schemeContent:this.planJson,userIds:userIds})
+      console.log(JSON.parse(this.planJson))
+      let data = JSON.parse(this.planJson)
+      let schemeContent = JSON.stringify(data.textJson)
+      let schemeSubPlan = JSON.stringify({
+        algorithmJson: data.algorithmJson,
+        xml: data.xml,
+      })
+      planningSchemeUpdateMeasurement({
+        id:planId,
+        // schemeContent:this.planJson,
+        schemeContent: schemeContent,
+        schemeSubPlan: schemeSubPlan,
+        userIds:userIds,
+      })
+
+      console.log(JSON.parse(schemeContent))
+      console.log(JSON.parse(schemeSubPlan))
 
       // 这里可以添加表单验证和提交逻辑
       this.$message.success('筹划方案创建成功!');

+ 1 - 0
src/views/planningSchem/comprehensive/components/autoPlanCreate.vue

@@ -98,6 +98,7 @@
           <WangEditor
               v-model="content"
               :height="400"
+              style="max-width: 1350px"
               :disabled="false"
               @change="handleContentChange"
           />

+ 266 - 100
src/views/planningSchem/comprehensive/components/semiPlanCreate.vue

@@ -35,7 +35,7 @@
                 <span class="text-blue-300 font-blod">任务类型</span>
               </div>
               <div class="flex text-sm mt-2">
-                <span>{{ $getDictNameByValue('task_type',planInfo.taskType+'') || "-" }}</span>
+                <span>{{ $getDictNameByValue('task_type', planInfo.taskType + '') || "-" }}</span>
               </div>
             </el-card>
             <el-card shadow="hover" class="p-3 mb-2 text-white bg-gray-100 bg-opacity-20 border-l-8 border-blue-400">
@@ -63,43 +63,43 @@
           <!-- 搜索栏 -->
           <div class="mb-4">
             <el-input
-                v-model="templateSearch"
-                placeholder="搜索模板..."
-                prefix-icon="el-icon-search"
-                size="small"
-                class="bg-gray-800 bg-opacity-50 border-gray-600 text-white"
+              v-model="templateSearch"
+              placeholder="搜索模板..."
+              prefix-icon="el-icon-search"
+              size="small"
+              class="bg-gray-800 bg-opacity-50 border-gray-600 text-white"
             ></el-input>
           </div>
 
           <!-- 模板表格 -->
           <el-table
-              :data="filteredTemplates"
-              border
-              size="small"
-              highlight-current-row
-              @row-click=""
-              class="mb-4 bg-gray-800 bg-opacity-30 border-gray-600"
+            :data="filteredTemplates"
+            border
+            size="small"
+            highlight-current-row
+            @row-click=""
+            class="mb-4 bg-gray-800 bg-opacity-30 border-gray-600"
           >
             <el-table-column
-                prop="name"
-                label="模板名称"
-                width="140"
-                show-overflow-tooltip
+              prop="name"
+              label="模板名称"
+              width="140"
+              show-overflow-tooltip
             >
             </el-table-column>
             <el-table-column
-                prop="description"
-                show-overflow-tooltip
-                label="描述">
+              prop="description"
+              show-overflow-tooltip
+              label="描述">
             </el-table-column>
 
             <el-table-column label="操作" width="80" align="center">
               <template #default="scope">
                 <!-- 使用按钮 -->
                 <el-button
-                    type="success"
-                    size="small"
-                    @click="handleUse(scope.row)"
+                  type="success"
+                  size="small"
+                  @click="handleUse(scope.row)"
                 >
                   应用
                 </el-button>
@@ -151,11 +151,11 @@
                     </el-select>
                   </el-form-item>
                   <el-form-item label="网格间距(m)">
-                    <el-input v-model.number="algorithmParams.minSpacing2" ></el-input>
+                    <el-input v-model.number="algorithmParams.minSpacing2"></el-input>
                   </el-form-item>
                   <div style="border-top: 1px solid #737877;margin-bottom: 10px"></div>
                   <el-form-item label="装备数量">
-                    <el-input v-model.number="algorithmParams.eqNumber2" ></el-input>
+                    <el-input v-model.number="algorithmParams.eqNumber2"></el-input>
                   </el-form-item>
                   <el-form-item label="装备类型">
                     <el-input v-model="algorithmParams.eqType2"></el-input>
@@ -172,14 +172,14 @@
                     <el-input v-model="algorithmParams.randomCenter" placeholder="请输入聚类中心"></el-input>
                   </el-form-item>
                   <el-form-item label="聚类半径(m)">
-                    <el-input v-model.number="algorithmParams.minSpacing3" ></el-input>
+                    <el-input v-model.number="algorithmParams.minSpacing3"></el-input>
                   </el-form-item>
                   <div style="border-top: 1px solid #737877;margin-bottom: 10px"></div>
                   <el-form-item label="装备数量">
-                    <el-input v-model.number="algorithmParams.eqNumber3" ></el-input>
+                    <el-input v-model.number="algorithmParams.eqNumber3"></el-input>
                   </el-form-item>
                   <el-form-item label="装备类型">
-                    <el-input v-model="algorithmParams.eqType3" ></el-input>
+                    <el-input v-model="algorithmParams.eqType3"></el-input>
                   </el-form-item>
                 </el-form>
               </div>
@@ -187,24 +187,24 @@
           </el-tabs>
 
           <!-- BB装备配置 -->
-<!--          <el-card class="bg-gray-400 bg-opacity-30 border-none">
-            <div class="text-lg font-bold mb-2">装备配置</div>
-            <el-form label-position="top" size="small" label-width="60px">
-              <el-form-item label="装备数量">
-                <el-input value="12"></el-input>
-              </el-form-item>
-              <el-form-item label="装备类型">
-                <el-select placeholder="请选择" style="width: 100%">
-                  <el-option
-                      v-for="type in equipmentTypes"
-                      :key="type"
-                      :label="type"
-                      :value="type"
-                  ></el-option>
-                </el-select>
-              </el-form-item>
-            </el-form>
-          </el-card>-->
+          <!--          <el-card class="bg-gray-400 bg-opacity-30 border-none">
+                      <div class="text-lg font-bold mb-2">装备配置</div>
+                      <el-form label-position="top" size="small" label-width="60px">
+                        <el-form-item label="装备数量">
+                          <el-input value="12"></el-input>
+                        </el-form-item>
+                        <el-form-item label="装备类型">
+                          <el-select placeholder="请选择" style="width: 100%">
+                            <el-option
+                                v-for="type in equipmentTypes"
+                                :key="type"
+                                :label="type"
+                                :value="type"
+                            ></el-option>
+                          </el-select>
+                        </el-form-item>
+                      </el-form>
+                    </el-card>-->
 
           <!-- 操作控制 -->
           <div class="space-y-2 mt-4">
@@ -217,17 +217,17 @@
         <!-- 右侧主内容区 -->
         <div class="flex-1 space-y-4 p-6 bg-gray-400 bg-opacity-20 backdrop-blur-lg border-gray-50 rounded-xl">
           <!-- 布设状态 -->
-        <!--<div class="flex items-center mb-4">
-            <h3 class="text-lg font-bold" style="color: #4fc2f7">布设状态</h3>
-          </div>
-          <div class="flex flex-col p-4 bg-black bg-opacity-20 mb-2">
-            <div class="">
-              <p>已布设BB数量: <span class="text-blue-300">0</span></p>
-              <p>当前算法: <span class="text-blue-300">随机布设</span></p>
-              <p>布设密度: <span class="text-blue-300">中等</span></p>
-              <p>覆盖面积: <span class="text-blue-300">0%</span></p>
+          <!--<div class="flex items-center mb-4">
+              <h3 class="text-lg font-bold" style="color: #4fc2f7">布设状态</h3>
             </div>
-          </div>-->
+            <div class="flex flex-col p-4 bg-black bg-opacity-20 mb-2">
+              <div class="">
+                <p>已布设BB数量: <span class="text-blue-300">0</span></p>
+                <p>当前算法: <span class="text-blue-300">随机布设</span></p>
+                <p>布设密度: <span class="text-blue-300">中等</span></p>
+                <p>覆盖面积: <span class="text-blue-300">0%</span></p>
+              </div>
+            </div>-->
 
           <div class="flex items-center mb-4">
             <h3 class="text-lg font-bold" style="color: #4fc2f7">方案信息</h3>
@@ -247,48 +247,144 @@
             <span>判别线</span>
           </div>
           <!-- 网格画布(模拟) -->
-          <div class="w-full bg-black bg-opacity-20 bg-blue-850 border border-blue-700 flex items-center justify-center" style="min-height: 400px">
+          <div class="w-full bg-black bg-opacity-20 bg-blue-850 border border-blue-700 flex items-center justify-center"
+               style="min-height: 400px">
             <!--<span class="text-blue-400">网格画布区域(可结合Canvas等实现交互)</span>-->
             <!--<img src="@/assets/plan_images/靶标.jpg" class="w-full h-full" />-->
-            <DrawioEmbed ref="drawioRef" />
+            <DrawioEmbed ref="drawioRef"/>
           </div>
           <div class="text-sm bg-blue-400 bg-opacity-20 rounded-md p-4 mt-2">
             操作提示: 点击BB区位可选中,拖拽可调整位置,双击可查看详情,使用右侧配置区设置参数后点击"生成方案"按钮。
           </div>
 
           <!-- 方案信息 -->
-          <WangEditor
+          <div class="editor-container">
+            <WangEditor
               v-model="content"
               :height="400"
+              style="max-width: 1350px"
               :disabled="false"
               @change="handleContentChange"
+            />
+          </div>
+
+          <!-- 装备信息 -->
+          <el-row>
+            <el-col :span="24">
+              <el-button icon="el-icon-plus" @click="openAdd">添加</el-button>
+            </el-col>
+          </el-row>
+          <el-table
+            :data="zbInfoList"
+            style="width: 100%"
+            border
+            :header-cell-style="{ 'text-align': 'center' }"
+            :cell-style="{ 'text-align': 'center' }"
+          >
+            <el-table-column label="序号" prop="89"></el-table-column>
+            <el-table-column label="装备" prop="89"></el-table-column>
+            <el-table-column label="位置" prop="89"></el-table-column>
+            <el-table-column label="任务" prop="89"></el-table-column>
+            <el-table-column label="操作">
+              <template slot-scope="{ row }">
+                <el-button type="danger" @click="delZbInfo(row)">删除</el-button>
+                <el-button @click="openAdd(row)">编辑</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+          <el-pagination
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+            :current-page="zbQueryForm.pageNo"
+            :page-sizes="[10, 20, 50, 100]"
+            :page-size="zbQueryForm.pageSize"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="zbQueryForm.total"
           />
         </div>
       </div>
     </div>
 
+    <!-- 添加装备弹窗 -->
+    <el-dialog
+      :title="addOrUpdateTitle"
+      :visible.sync="addOrUpdateTVisible"
+      class="dark-dialog"
+      width="60%"
+      :close-on-click-modal="false"
+    >
+      <el-form ref="addFormRef" :model="addForm" :rules="rules" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="装备名称" prop="zbName">
+              <el-input v-model="addForm.zbName" placeholder="请输入任务名称"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="是否精确位置" prop="isExactLocation">
+              <el-radio-group v-model="addForm.isExactLocation" @change="locationChange">
+                <el-radio-button :label="0">非精确位置</el-radio-button>
+                <el-radio-button :label="1">精确位置</el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20" v-if="addForm.isExactLocation === 1">
+          <el-col :span="12">
+            <el-form-item label="X坐标" prop="equipPositionX">
+              <el-input v-model="addForm.equipPositionX" placeholder="请输入X坐标"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="Y坐标" prop="equipPositionY">
+              <el-input v-model="addForm.equipPositionY" placeholder="请输入Y坐标"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="位置描述" prop="positionDescription">
+              <el-input type="textarea" :rows="4" v-model="addForm.positionDescription" placeholder="请输入位置描述"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="任务描述" prop="taskRemark">
+              <el-input type="textarea" :rows="4" v-model="addForm.taskRemark" placeholder="请输入任务描述"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="addOrUpdateTVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleAddSubmit">确 定</el-button>
+      </div>
+    </el-dialog>
+
     <!-- 可拖动悬浮球 -->
     <div
-        class="floating-button"
-        :style="{ top: floatTop + 'px', left: floatLeft + 'px' }"
-        @mousedown="startDrag"
-        @click="toggleDrawer"
+      class="floating-button"
+      :style="{ top: floatTop + 'px', left: floatLeft + 'px' }"
+      @mousedown="startDrag"
+      @click="toggleDrawer"
     >
       <i class="el-icon-s-opportunity text-2xl"></i>
     </div>
 
     <!-- 抽屉组件 -->
     <el-drawer
-        title="AI助手"
-        :with-header="false"
-        :z-index="9999999"
-        :visible.sync="drawerVisible"
-        :direction="drawerDirection"
-        style="z-index: 100;color:white;font-size: 16px"
-        size="40%"
+      title="AI助手"
+      :with-header="false"
+      :z-index="9999999"
+      :visible.sync="drawerVisible"
+      :direction="drawerDirection"
+      style="z-index: 100;color:white;font-size: 16px"
+      size="40%"
     >
       <div class="h-full w-full">
-        <QAChat :messages="qaMessages" @question="handleQuestion" />
+        <QAChat :messages="qaMessages" @question="handleQuestion"/>
       </div>
     </el-drawer>
   </div>
@@ -299,30 +395,55 @@
 import WangEditor from "@/components/Components/WangEditor.vue";
 import QAChat from "@/components/Components/QAChat.vue"
 import DrawioEmbed from "@/components/DrawioEmbed/index.vue";
-import {getSynergismScheme} from "@/api/planningScheme";
+import {getSynergismScheme, zbAdd, zbPage, zbGet, zbUpdate, zbDel} from "@/api/planningScheme";
 
 export default {
-  props:{
-    dataJson:{
-      type:String,
+  props: {
+    dataJson: {
+      type: String,
       default: null,
     },
-    planInfo:{
-      type:Object,
-      default: ()=>{
+    planInfo: {
+      type: Object,
+      default: () => {
         return {}
       }
     }
   },
-  components:{
+  components: {
     WangEditor,
     QAChat,
     DrawioEmbed
   },
   data() {
     return {
+      // 表格编辑相关
+      zbInfoList: [],
+      addOrUpdateTitle: '新增装备信息',
+      addOrUpdateTVisible: false,
+      addForm: {
+        zbName: '',
+        isExactLocation: 0,
+        equipPositionX: '',
+        equipPositionY: '',
+        positionDescription: '',
+        taskRemark: '',
+      },
+      zbQueryForm: {
+        pageNo: 1,
+        pageSize: 10,
+        total: 0,
+      },
+      rules: {
+        zbName: [{required: true, message: '装备名称不能为空', trigger: 'blur'}],
+        isExactLocation: [{required: true, message: '请选择是否精确位置', trigger: 'change'}],
+        equipPositionX: [{required: true, message: 'X坐标不能为空', trigger: 'blur'}],
+        equipPositionY: [{required: true, message: 'Y坐标不能为空', trigger: 'blur'}],
+        positionDescription: [{required: true, message: '位置描述不能为空', trigger: 'blur'}],
+        taskRemark: [{required: true, message: '任务描述不能为空', trigger: 'blur'}],
+      },
 
-      content:'',
+      content: '',
       selectedTemplate: null,
 
       templateSearch: '',
@@ -374,12 +495,12 @@ export default {
         minSpacing1: 50,
         minSpacing2: 50,
         minSpacing3: 50,
-        eqNumber1:5,
-        eqNumber2:5,
-        eqNumber3:5,
-        eqType1:'',
-        eqType2:'',
-        eqType3:'',
+        eqNumber1: 5,
+        eqNumber2: 5,
+        eqNumber3: 5,
+        eqType1: '',
+        eqType2: '',
+        eqType3: '',
       },
       // 悬浮球相关
       floatTop: 200,
@@ -392,11 +513,11 @@ export default {
       drawerDirection: 'rtl', // 从右侧滑出
       // 历史记录数据
       historyData: [
-        { time: '2025-08-20 11:05', operation: '创建方案', user: '张三' },
-        { time: '2025-08-20 11:10', operation: '修改随机参数', user: '张三' },
-        { time: '2025-08-20 11:15', operation: '保存草稿', user: '张三' }
+        {time: '2025-08-20 11:05', operation: '创建方案', user: '张三'},
+        {time: '2025-08-20 11:10', operation: '修改随机参数', user: '张三'},
+        {time: '2025-08-20 11:15', operation: '保存草稿', user: '张三'}
       ],
-      schemeInfo:{}
+      schemeInfo: {}
     };
   },
   computed: {
@@ -407,13 +528,44 @@ export default {
       }
       const searchStr = this.templateSearch.toLowerCase();
       return this.templates.filter(template =>
-          template.name.toLowerCase().includes(searchStr) ||
-          template.description.toLowerCase().includes(searchStr) ||
-          template.applicableScenario.toLowerCase().includes(searchStr)
+        template.name.toLowerCase().includes(searchStr) ||
+        template.description.toLowerCase().includes(searchStr) ||
+        template.applicableScenario.toLowerCase().includes(searchStr)
       );
     }
   },
   methods: {
+    handleSizeChange(val) {
+      this.zbQueryForm.pageSize = val
+      this.pageList()
+    },
+    handleCurrentChange(val) {
+      this.zbQueryForm.pageNo = val
+      this.pageList()
+    },
+    // 分页获取数据
+    pageList() {
+
+    },
+    locationChange(data) {
+      this.addForm.positionDescription = ''
+      this.addForm.equipPositionX = ''
+      this.addForm.equipPositionY = ''
+      // } else {
+      // }
+      // if (data) {
+    },
+    // 添加装备
+    openAdd(row) {
+      this.addOrUpdateTVisible = true
+    },
+    // 添加装备确认按钮
+    handleAddSubmit() {
+
+    },
+    // 删除装备信息
+    delZbInfo(row) {
+    },
     async loadDefaultData(xml) {
       try {
         await this.$refs.drawioRef.setData(xml)
@@ -431,15 +583,25 @@ export default {
         console.error('获取失败:', err)
       }
     },
-    async save(){
+    async save() {
       const xml = await this.getXmlData()
+      console.log(xml)
       const planJson = JSON.stringify({
-        algorithmJson:this.algorithmParams,   // 布设算法
+        algorithmJson: this.algorithmParams,   // 布设算法
         textJson: this.content,   // 富文本
         xml: xml
       })
 
-      this.$emit("save-plan", { planJson: planJson });
+      this.$emit("save-plan", {planJson: planJson});
+    },
+    async getAllData() {
+      const xml = await this.getXmlData()
+      console.log(xml)
+      return JSON.stringify({
+        algorithmJson: this.algorithmParams,   // 布设算法
+        textJson: this.content,   // 富文本
+        xml: xml
+      })
     },
     handleUse(plan) {
       // 执行“使用”逻辑
@@ -455,9 +617,9 @@ export default {
       console.log('编辑器内容变化:', html)
       // 可以在这里处理内容,如实时保存等
     },
-    back(){
+    back() {
       this.$message.success('操作成功')
-      this.$router.push({ path: '/scheme/collaborative' })
+      this.$router.push({path: '/scheme/collaborative'})
     },
     // 悬浮球拖动相关方法
     startDrag(e) {
@@ -508,10 +670,10 @@ export default {
   },
   // 监听窗口大小变化,调整悬浮球位置
   mounted() {
-    getSynergismScheme({id:this.planInfo.id}).then((res)=>{
+    getSynergismScheme({id: this.planInfo.id}).then((res) => {
       this.schemeInfo = res.data;
     })
-    if(this.dataJson){
+    if (this.dataJson) {
       const data = JSON.parse(this.dataJson)
       console.log(data)
       this.algorithmParams = data.algorithmJson;
@@ -531,6 +693,10 @@ export default {
 </script>
 
 <style scoped>
+.editor-container {
+  width: 100% !important;
+}
+
 .bb-layout-page {
   font-size: 16px;
   background-color: #030d1e;
@@ -582,7 +748,7 @@ export default {
   border-bottom: 1px solid rgba(79, 194, 247, 0.3);
 }
 
-::v-deep .el-tabs__nav-wrap{
+::v-deep .el-tabs__nav-wrap {
   background: #09264c;
 }
 </style>

+ 44 - 22
src/views/planningSchem/comprehensive/index.vue

@@ -33,6 +33,7 @@
           v-for="plan in plans"
           :key="plan.id"
           :plan="plan"
+          :isDef="isDef"
           @view-detail="handleViewDetail"
           @export-plan="handleExportPlan"
           @link-to="(val) => linkTo(val, plan)"
@@ -85,7 +86,7 @@
 
       <div v-else>
         <VueOfficeDocx
-          :src="grFileList[0].fileHttp"
+          :src="inteFileView"
           class="preview-container"
         />
         <!--<el-table :data="grFileList" border>-->
@@ -131,7 +132,7 @@
       </div>
       <div v-else>
         <VueOfficeDocx
-          :src="bbFileList[0].fileHttp"
+          :src="bbFileView"
           class="preview-container"
         />
         <!--<el-table :data="bbFileList" border>-->
@@ -155,15 +156,15 @@
                 :visible.sync="dialogVisible"
                 width="50%"
                 :before-close="handleClose">
-      <el-descriptions :column="2" border>
-        <el-descriptions-item label="方案名称">{{ currentPlan.planName }}</el-descriptions-item>
-        <el-descriptions-item label="任务名称">{{ currentPlan.taskName }}</el-descriptions-item>
-        <el-descriptions-item label="任务代号">{{ currentPlan.taskCode }}</el-descriptions-item>
-        <el-descriptions-item label="开始时间">{{ currentPlan.startTime }}</el-descriptions-item>
-        <el-descriptions-item label="结束时间">{{ currentPlan.endTime }}</el-descriptions-item>
-        <el-descriptions-item label="编制状态">{{ currentPlan.compileStatus }}</el-descriptions-item>
-        <el-descriptions-item label="状态">{{ currentPlan.status }}</el-descriptions-item>
-      </el-descriptions>
+      <!--<el-descriptions :column="2" border>-->
+      <!--  <el-descriptions-item label="方案名称">{{ currentPlan.planName }}</el-descriptions-item>-->
+      <!--  <el-descriptions-item label="任务名称">{{ currentPlan.taskName }}</el-descriptions-item>-->
+      <!--  <el-descriptions-item label="任务代号">{{ currentPlan.taskCode }}</el-descriptions-item>-->
+      <!--  <el-descriptions-item label="开始时间">{{ currentPlan.startTime }}</el-descriptions-item>-->
+      <!--  <el-descriptions-item label="结束时间">{{ currentPlan.endTime }}</el-descriptions-item>-->
+      <!--  <el-descriptions-item label="编制状态">{{ currentPlan.compileStatus }}</el-descriptions-item>-->
+      <!--  <el-descriptions-item label="状态">{{ currentPlan.status }}</el-descriptions-item>-->
+      <!--</el-descriptions>-->
       <span slot="footer" class="dialog-footer">
         <el-button @click="dialogVisible = false">关闭</el-button>
       </span>
@@ -180,7 +181,8 @@ import {
   planningSchemePage,
   planningSchemeUpdate, planningSchemeUpdateInte,
   planningSchemeUpdateTarget,
-  planningSchemeUploadTarget
+  planningSchemeUploadTarget,
+  viewFile
 } from "@/api/planningScheme";
 import {exportSolutionToWord} from "@/views/planningSchem/comprehensive/wordExporter";
 import {baseURL, contentType, tokenName} from "@/config";
@@ -200,8 +202,9 @@ export default {
     return {
       bbHasFile: '上传靶标方案',
       inteHasFile: '上传干扰方案',
-      bbFileList: [],
-      grFileList: [],
+      bbFileView: '',
+      inteFileView: '',
+      isDef: true,
       tableData: [
         {
           date: '2023-06-01',
@@ -215,7 +218,7 @@ export default {
         }
       ],
       dialogVisible: false,
-      currentPlan: {}, // 当前选中的任务数据
+      // currentPlan: {}, // 当前选中的任务数据
       queryForm: {
         taskName: '',
         taskCode: ''
@@ -609,7 +612,7 @@ export default {
     },
 
     handleViewDetail(plan) {
-      this.$router.push({path: '/planningSchem/overallPlanDesign', query: {batchId: plan.batchId}})
+      this.$router.push({path: '/planningSchem/overallPlanDesign', query: {batchId: plan.batchId, isDef: this.isDef}})
     },
     //导出
     async handleExportPlan(plan) {
@@ -640,19 +643,38 @@ export default {
       } else if (val.type === 'meas' && plan.measurementSchemeStatus === '已编制') {
         this.$router.push({path: '/home/collaborativeCreate_Cl', query: {plan: JSON.stringify(plan), isEdit: 'false'}});
       } else if (val.type === "inte" && plan.interferenceSchemeStatus === '已导入') {
-        this.grFileList = JSON.parse(plan.schemeSubPlan)
-        this.inteHasFile = '查看干扰方案'
-        this.showInteUpload = true;
+        // this.grFileList = JSON.parse(plan.schemeSubPlan)
+        this.getViewFile(plan.id, 3, 'inteFileView')
       } else if (val.type === "target" && plan.targetSchemeStatus === '已导入') {
-        this.bbFileList = JSON.parse(plan.schemeSubPlan)
-        this.bbHasFile = '查看靶标方案'
-        this.showTargetUpload = true;
+        // this.bbFileList = JSON.parse(plan.schemeSubPlan)
+        this.getViewFile(plan.id, 1, 'bbFileView')
       } else {
         // 已导入/已编制状态正常跳转
         this.navigateTo(val.type, val.isOk);
       }
     },
 
+    getViewFile(id, type, file) {
+      let param = {
+        id: id,
+        type: type,
+      }
+      viewFile(param).then(res => {
+        if (res.code !== 0) {
+          return
+        }
+        let data = JSON.parse(res.data.schemeSubPlan)
+        this[file] = data[0].fileHttp
+        if (type === 1) {
+          this.bbHasFile = '查看靶标方案'
+          this.showTargetUpload = true;
+        } else {
+          this.inteHasFile = '查看干扰方案'
+          this.showInteUpload = true;
+        }
+      })
+    },
+
     async handleQuery() {
       // 查询逻辑
       const res = await planningSchemePage({

+ 5 - 5
src/views/planningSchem/comprehensive/overallPlanDesign.vue

@@ -4,12 +4,12 @@
       <!-- 主页面内容 -->
       <template #header-controls>
         <div class="header-actions">
-          <el-button type="primary" @click="saveSolution">保存方案</el-button>
-          <el-button class="blue-btn" @click="exportAsWord">导出为Word</el-button>
+          <el-button v-if="$route.query.isDef === 'true'" type="success" @click="saveSolution">保存方案</el-button>
+          <el-button type="primary" @click="exportAsWord">导出为Word</el-button>
           <el-button class="blue-btn">查看试验任务详情</el-button>
           <!-- 查看子方案下拉菜单 -->
           <el-dropdown trigger="click" @command="handleCommand">
-            <el-button class="blue-btn" icon="el-icon-folder-opened">
+            <el-button type="info" icon="el-icon-folder-opened">
               查看子方案<i class="el-icon-arrow-down el-icon--right"></i>
             </el-button>
             <el-dropdown-menu slot="dropdown">
@@ -28,8 +28,8 @@
             <div slot="header" class="tree-header dark-header">
               <span>方案目录</span>
               <div>
-                <el-button icon="el-icon-plus" size="mini" @click="openAddChapterDialog"></el-button>
-                <el-button icon="el-icon-delete" size="mini" @click="deleteSection"></el-button>
+                <el-button v-if="$route.query.isDef === 'true'" icon="el-icon-plus" size="mini" @click="openAddChapterDialog"></el-button>
+                <el-button v-if="$route.query.isDef === 'true'" icon="el-icon-delete" size="mini" @click="deleteSection"></el-button>
               </div>
             </div>
             <!-- 横向滚动容器 -->

+ 27 - 4
src/views/programPlanning/collaborativePlanning/collaborativeCreate_CL.vue

@@ -338,6 +338,7 @@
           <WangEditor
               v-model="content"
               :height="400"
+              style="max-width: 1350px"
               :disabled="!isEdit"
               @change="handleContentChange"
           />
@@ -487,15 +488,37 @@ export default {
 
     },
     async fetchData(){
-      await getSynergismScheme({id:this.planInfo.id}).then((res)=>{
-        this.schemeInfo = res.data;
+      let res = await getSynergismScheme({id:this.planInfo.id})
         if(res.data.schemeContent){
           const data = JSON.parse(res.data.schemeContent)
+          console.log(data)
+          this.$nextTick(()=>{
+            this.content = data;
+          })
+        }
+        if (res.data.schemeSubPlan) {
+          const data = JSON.parse(res.data.schemeSubPlan)
+          console.log(data)
           this.algorithmParams = data.algorithmJson;
-          this.content = data.textJson;
           this.loadDefaultData(data.xml.xmlData);
         }
-      })
+      // await getSynergismScheme({id:this.planInfo.id}).then((res)=>{
+      //   this.schemeInfo = res.data;
+      //   console.log(res.data, '============')
+      //   if(res.data.schemeContent){
+      //     const data = JSON.parse(res.data.schemeContent)
+      //     console.log(data)
+      //     this.$nextTick(()=>{
+      //       this.content = data;
+      //     })
+      //   }
+      //   if (res.data.schemeSubPlan) {
+      //     const data = JSON.parse(res.data.schemeSubPlan)
+      //     console.log(data)
+      //     this.algorithmParams = data.schemeSubPlan;
+      //     this.loadDefaultData(data.xml.xmlData);
+      //   }
+      // })
     },
     async loadDefaultData(xml) {
       try {