processcontrol.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. <template>
  2. <div>
  3. <DarkLayout :query-form="queryForm">
  4. <!-- 查询表单插槽 -->
  5. <template #query-form>
  6. <el-form-item label="推演任务名称">
  7. <el-input
  8. v-model="queryForm.simulationName"
  9. placeholder="请输入推演任务名称"
  10. clearable
  11. />
  12. </el-form-item>
  13. </template>
  14. <!-- Header右侧操作按钮 -->
  15. <template #header-actions>
  16. <el-button icon="el-icon-search" type="primary" @click="handleQuery">
  17. 查询
  18. </el-button>
  19. <!--<el-button-->
  20. <!-- @click="openAddDialog"-->
  21. <!-- icon="el-icon-plus"-->
  22. <!-- class="blue-btn"-->
  23. <!--&gt;-->
  24. <!-- 添加-->
  25. <!--</el-button>-->
  26. </template>
  27. <!-- 主要内容 -->
  28. <template #main>
  29. <ScenarioeditingCard
  30. v-if="planList.length > 0"
  31. v-for="plan in planList"
  32. :key="plan.id + '-' + plan.createTime"
  33. :plan="plan"
  34. @edit="openExpectedEditDialog(plan)"
  35. @view-detail="viewDetails(plan)"
  36. />
  37. <el-empty v-else description="暂无方案数据" />
  38. </template>
  39. <!-- 底部右侧分页 -->
  40. <template #footer-actions>
  41. <el-pagination
  42. @size-change="handleSizeChange"
  43. @current-change="handleCurrentChange"
  44. :current-page="queryForm.pageNo"
  45. :page-sizes="[10, 20, 50, 100]"
  46. :page-size="queryForm.pageSize"
  47. layout="total, sizes, prev, pager, next, jumper"
  48. :total="total"
  49. />
  50. </template>
  51. </DarkLayout>
  52. <!-- 任务详情弹窗 -->
  53. <DarkDrawer
  54. title="任务详情"
  55. :visible.sync="dialogVisible"
  56. width="40%"
  57. :before-close="handleClose"
  58. >
  59. <el-row :gutter="20">
  60. <el-col :span="24" v-for="(task, index) in taskList" :key="index">
  61. <h3 class="section-title">
  62. <i class="el-icon-document mr-2"></i> 总体任务
  63. </h3>
  64. <div
  65. class="task-card"
  66. >
  67. <div class="flex justify-between items-center mb-3">
  68. <h4 class="task-title">{{ task.taskName }}</h4>
  69. </div>
  70. <div class="task-info">
  71. <li>任务代号: {{ task.taskCode || "-" }}</li>
  72. <li>任务类型: {{ $getDictNameByValue('task_type',task.taskType+'') || "-" }}</li>
  73. <li>任务时间: {{ task.testTime || "-" }}</li>
  74. <li>创建时间: {{ task.createTime || "-" }}</li>
  75. </div>
  76. </div>
  77. </el-col>
  78. <el-col :span="24" v-for="(task, index) in subTaskList" :key="index">
  79. <h3 class="section-title mt-4">
  80. <i class="el-icon-document mr-2"></i> 子任务
  81. </h3>
  82. <div
  83. class="task-card"
  84. >
  85. <div class="flex justify-between items-center mb-3">
  86. <h4 class="task-title">{{ task.subTaskName || "-" }}</h4>
  87. </div>
  88. <div class="task-info">
  89. <li>任务代号: {{ task.subTaskCode || "-" }}</li>
  90. <li>任务类型: {{ $getDictNameByValue('task_type',task.subTaskType+'') || "-" }}</li>
  91. <li>任务时间: {{ task.subTestTime || "-" }}</li>
  92. <li>打击维度: {{ task.fightAway || "对陆" }}</li>
  93. <li>创建时间: {{ task.createTime || "-" }}</li>
  94. </div>
  95. </div>
  96. </el-col>
  97. </el-row>
  98. </DarkDrawer>
  99. <!-- 新建/编辑 推演任务设定(单选总体方案) -->
  100. <DarkDrawer :title="editDialogTitle" :visible.sync="editVisible" size="55%">
  101. <el-form
  102. ref="editFormRef"
  103. :model="editForm"
  104. :rules="baseRules"
  105. label-width="120px"
  106. class="edit-form-dark"
  107. >
  108. <div class="form-grid">
  109. <!-- 基础信息 -->
  110. <el-form-item label="推演任务名称" prop="simulationName">
  111. <el-input v-model="editForm.simulationName" clearable />
  112. </el-form-item>
  113. <!-- 选择总体任务 -->
  114. <div class="task-select-section span-2">
  115. <h3 class="section-title">
  116. <i class="el-icon-document mr-2"></i> 选择总体任务
  117. </h3>
  118. <p class="section-desc">请选择要关联的总体任务,系统将根据总体任务推荐对应的子任务</p>
  119. <el-row :gutter="20">
  120. <el-col :span="8" v-for="(task, index) in taskList" :key="index">
  121. <div
  122. class="task-card"
  123. :class="{ 'task-card--active': selectedTask && selectedTask.id === task.id }"
  124. @click="handleTaskSelect(task)"
  125. >
  126. <div class="flex justify-between items-center mb-3">
  127. <h4 class="task-title">{{ task.taskName }}</h4>
  128. </div>
  129. <div class="task-info">
  130. <li>任务代号: {{ task.taskCode || "-" }}</li>
  131. <li>任务类型: {{ $getDictNameByValue('task_type',task.taskType+'') || "-" }}</li>
  132. <li>任务时间: {{ task.testTime || "-" }}</li>
  133. <li>创建时间: {{ task.createTime || "-" }}</li>
  134. </div>
  135. <el-button class="task-btn" type="primary">选择此任务</el-button>
  136. </div>
  137. </el-col>
  138. </el-row>
  139. </div>
  140. <!-- 选择子任务 -->
  141. <div v-if="selectedTask" class="task-select-section span-2">
  142. <h3 class="section-title">
  143. <i class="el-icon-document mr-2"></i> 选择子任务
  144. </h3>
  145. <el-row :gutter="20">
  146. <el-col :span="8" v-for="(task, index) in subTaskList" :key="index">
  147. <div
  148. class="task-card"
  149. :class="{ 'task-card--active': selectedSubTask && selectedSubTask.id === task.id }"
  150. @click="handleSubTaskSelect(task)"
  151. >
  152. <div class="flex justify-between items-center mb-3">
  153. <h4 class="task-title">{{ task.subTaskName || "-" }}</h4>
  154. </div>
  155. <div class="task-info">
  156. <li>任务代号: {{ task.subTaskCode || "-" }}</li>
  157. <li>任务类型: {{ $getDictNameByValue('task_type',task.subTaskType+'') || "-" }}</li>
  158. <li>任务时间: {{ task.subTestTime || "-" }}</li>
  159. <li>打击维度: {{ task.fightAway || "对陆" }}</li>
  160. <li>创建时间: {{ task.createTime || "-" }}</li>
  161. </div>
  162. <el-button class="task-btn" type="primary">选择此任务</el-button>
  163. </div>
  164. </el-col>
  165. </el-row>
  166. </div>
  167. <div v-if="selectedSubTask" class="task-select-section span-2">
  168. <h3 class="section-title">
  169. <i class="el-icon-document mr-2"></i> 选择方案
  170. </h3>
  171. <el-row :gutter="20">
  172. <!-- 树形表格实现 -->
  173. <el-table
  174. ref="treeTable"
  175. :data="schemeTable"
  176. style="width: 100%"
  177. row-key="id"
  178. border
  179. :tree-props="{ children: 'verList'}"
  180. @select="handleTreeSelect"
  181. @select-all="handleTreeSelectAll"
  182. >
  183. <!-- 单选列:不显示表头的选择框 -->
  184. <el-table-column
  185. type="selection"
  186. width="50"
  187. align="center"
  188. :selectable="canSelect"
  189. :show-header="false"
  190. />
  191. <!-- 树形表格字段 -->
  192. <el-table-column
  193. prop="schemeVersion"
  194. label="版本号"
  195. width="120"
  196. align="center"
  197. ></el-table-column>
  198. <el-table-column
  199. prop="batchId"
  200. label="批次ID"
  201. width=""
  202. align="center"
  203. ></el-table-column>
  204. <el-table-column
  205. prop="measurementSchemeStatus"
  206. label="测量方案"
  207. width="120"
  208. align="center"
  209. >
  210. <template slot-scope="scope">
  211. <el-tag size="mini" :type="getStatusTagType(scope.row.measurementSchemeStatus)">
  212. {{ scope.row.measurementSchemeStatus }}
  213. </el-tag>
  214. </template>
  215. </el-table-column>
  216. <!-- 干扰方案 -->
  217. <el-table-column
  218. label="干扰方案"
  219. width="120"
  220. align="center"
  221. >
  222. <template slot-scope="scope">
  223. <el-tag
  224. size="mini"
  225. :type="getStatusTagType(scope.row.interferenceSchemeStatus)"
  226. style="cursor: pointer;"
  227. @click="handleDocxClick(scope.row, '干扰')"
  228. >
  229. {{ scope.row.interferenceSchemeStatus }}
  230. </el-tag>
  231. </template>
  232. </el-table-column>
  233. <!-- 靶标方案 -->
  234. <el-table-column
  235. label="靶标方案"
  236. width="120"
  237. align="center"
  238. >
  239. <template slot-scope="scope">
  240. <el-tag
  241. size="mini"
  242. :type="getStatusTagType(scope.row.targetSchemeStatus)"
  243. style="cursor: pointer;"
  244. @click="handleDocxClick(scope.row, '靶标')"
  245. >
  246. {{ scope.row.targetSchemeStatus }}
  247. </el-tag>
  248. </template>
  249. </el-table-column>
  250. </el-table>
  251. </el-row>
  252. </div>
  253. </div>
  254. </el-form>
  255. <span class="pt-4 w-full flex justify-center">
  256. <el-button @click="editVisible = false">取 消</el-button>
  257. <el-button type="primary" @click="onEditSave">保 存</el-button>
  258. </span>
  259. </DarkDrawer>
  260. </div>
  261. </template>
  262. <script>
  263. import DarkLayout from '@/components/GlobalComponents/DarkLayout.vue'
  264. import TaskUserCard from '@/components/Components/TaskUserCard.vue'
  265. import DarkDialog from "@/components/Components/DarkDialog.vue";
  266. import ScenarioeditingCard from "@/components/GlobalComponents/ScenarioeditingCard.vue";
  267. import {getList, insertDeductionTask, updateDeductionTask} from "@/api/deductionTask";
  268. import {findPageTask, findSubTaskPage} from "@/api/taskMage/taskMage";
  269. import {getListVer} from "@/api/planningScheme";
  270. export default {
  271. components: {
  272. ScenarioeditingCard,
  273. DarkDialog,
  274. DarkLayout,
  275. TaskUserCard
  276. },
  277. data() {
  278. return {
  279. /* 可选试验任务 */
  280. taskList: [],
  281. subTaskList:[],
  282. /* 当前选择状态(单选) */
  283. editVisible: false,
  284. editMode: 'edit', // 'add' | 'edit'
  285. selectedTask: null,
  286. selectedSubTask: null,
  287. schemeTable: [],
  288. selectedTreeNode: null, // 记录当前选中的树形节点
  289. /* 表单数据 */
  290. editForm: {
  291. id: '',
  292. simulationName: '',
  293. intendedEditing:1,
  294. simType:0,
  295. taskId:'',
  296. subTaskId:'',
  297. schemeId:'',
  298. versionId: '' // 记录选中的版本ID
  299. },
  300. baseRules: {
  301. simulationName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
  302. },
  303. /* 其他弹窗与数据 */
  304. selectedPlan: {},
  305. tableData: [
  306. { date: '2023-06-01', name: '张三', address: '北京市海淀区' },
  307. { date: '2023-06-02', name: '李四', address: '上海市浦东新区' }
  308. ],
  309. dialogVisible: false,
  310. currentPlan: {},
  311. /* 列表和分页 */
  312. queryForm: { simulationName: '',intendedEditing:1,simType:0,pageNo: 1,pageSize: 10 },
  313. planList: [],
  314. total: 0,
  315. }
  316. },
  317. computed: {
  318. isAddMode() {
  319. return this.editMode === 'add'
  320. },
  321. editDialogTitle() {
  322. return this.editMode === 'add' ? '新建推演任务设定' : '编辑推演任务设定'
  323. },
  324. secretChipClass() {
  325. const map = { '绝密': 'danger', '机密': 'warning', '秘密': 'primary' }
  326. return map[this.selectedPlan?.secretLevel] || 'neutral'
  327. },
  328. selectedOverallPlanNames() {
  329. const p = this.currentOverallPlans.find(p => p.id === this.selectedOverallPlanId)
  330. return p ? [p.planName] : []
  331. }
  332. },
  333. mounted() {
  334. this.fetchData()
  335. },
  336. methods: {
  337. getStatusTagType(status) {
  338. if (!status) return 'info';
  339. switch (status) {
  340. case '已编制':
  341. case '已导入':
  342. return 'success';
  343. case '未导入':
  344. case '未编制':
  345. return 'info';
  346. case '进行中':
  347. return 'warning';
  348. default:
  349. return 'info';
  350. }
  351. },
  352. // 控制哪些行可被选择(全部可选)
  353. canSelect(row) {
  354. return true; // 可根据条件禁用某些行的选择
  355. },
  356. // 处理树形表格选择事件
  357. handleTreeSelect(selection, row) {
  358. // 如果已选中,则取消
  359. if (this.selectedTreeNode === row) {
  360. this.$refs.treeTable.clearSelection();
  361. this.selectedTreeNode = null;
  362. } else {
  363. // 清除之前的选择,只选中当前行
  364. this.$refs.treeTable.clearSelection();
  365. this.$nextTick(() => {
  366. this.$refs.treeTable.toggleRowSelection(row, true);
  367. });
  368. this.selectedTreeNode = row;
  369. }
  370. },
  371. // 禁用树形表格全选功能
  372. handleTreeSelectAll(selection) {
  373. if (selection.length > 1) {
  374. // 强制只保留最后一项
  375. const lastSelected = selection[selection.length - 1];
  376. this.$refs.treeTable.clearSelection();
  377. this.$refs.treeTable.toggleRowSelection(lastSelected, true);
  378. this.selectedTreeNode = lastSelected;
  379. }
  380. },
  381. /* 任务选择:加载其总体方案并清空已选 */
  382. async handleTaskSelect(task) {
  383. this.selectedTask = task;
  384. this.selectedSubTask = null;
  385. const params = {
  386. taskId_EQ: task.id,
  387. pageNo: 1,
  388. pageSize: 9999
  389. };
  390. const res = await findSubTaskPage(params);
  391. this.subTaskList = res.data.rows;
  392. },
  393. /* 单选工具 */
  394. isPlanSelected(plan) {
  395. return this.selectedOverallPlanId === plan.id;
  396. },
  397. togglePlan(plan) {
  398. this.selectedOverallPlanId = (this.selectedOverallPlanId === plan.id) ? '' : plan.id;
  399. },
  400. async getTaskList() {
  401. const params = {
  402. taskName_LIKE: '',
  403. taskType_EQ: '',
  404. pageNo: 1,
  405. pageSize: 9999
  406. };
  407. const res = await findPageTask(params);
  408. this.taskList = res.data.rows;
  409. },
  410. async getSubTaskList(taskId) {
  411. const params = {
  412. taskId_EQ: taskId,
  413. pageNo: 1,
  414. pageSize: 9999
  415. };
  416. const res = await findSubTaskPage(params);
  417. this.subTaskList = res.data.rows;
  418. },
  419. /* 添加:打开空白同一套表单 */
  420. async openAddDialog() {
  421. await this.getTaskList();
  422. this.editMode = 'add';
  423. this.selectedTask = null;
  424. this.selectedSubTask = null;
  425. this.editForm = {
  426. id: '',
  427. simulationName: '',
  428. intendedEditing: 1,
  429. simType: 0,
  430. taskId: '',
  431. subTaskId: '',
  432. schemeId: '',
  433. versionId: ''
  434. };
  435. this.editVisible = true;
  436. this.$nextTick(() => this.$refs.editFormRef && this.$refs.editFormRef.clearValidate());
  437. },
  438. /* 编辑:回填同一套表单 + 自动选中任务与总体方案(单选) */
  439. async openEditDialog(plan) {
  440. this.editMode = 'edit';
  441. this.editForm = JSON.parse(JSON.stringify(plan));
  442. // 重置选择状态
  443. this.selectedTreeNode = null;
  444. if (this.$refs.treeTable) {
  445. this.$refs.treeTable.clearSelection();
  446. }
  447. await this.getTaskList();
  448. const task = this.taskList.find(item => item.id === plan.taskId);
  449. if (task) {
  450. await this.handleTaskSelect(task);
  451. const subTask = this.subTaskList.find(item => item.id === plan.subTaskId);
  452. if (subTask) {
  453. // 等待子任务选择完成和数据加载
  454. await new Promise(resolve => {
  455. this.handleSubTaskSelect(subTask);
  456. // 给数据加载一点时间
  457. setTimeout(resolve, 500);
  458. });
  459. // 使用双重nextTick确保表格已渲染
  460. this.$nextTick(() => {
  461. this.$nextTick(() => {
  462. if (!this.$refs.treeTable) return;
  463. // 递归查找节点
  464. const findNode = (nodes, targetId) => {
  465. for (const node of nodes) {
  466. if (node.id === targetId) {
  467. return node;
  468. }
  469. if (node.verList && node.verList.length) {
  470. const found = findNode(node.verList, targetId);
  471. if (found) return found;
  472. }
  473. }
  474. return null;
  475. };
  476. const targetNode = findNode(this.schemeTable, plan.schemeId);
  477. if (targetNode) {
  478. // 先清除所有选择
  479. this.$refs.treeTable.clearSelection();
  480. // 选中目标节点
  481. this.$refs.treeTable.toggleRowSelection(targetNode, true);
  482. this.selectedTreeNode = targetNode;
  483. // 展开父节点
  484. this.expandParentNodes(this.schemeTable, targetNode.id);
  485. }
  486. });
  487. });
  488. }
  489. }
  490. this.editVisible = true;
  491. this.$nextTick(() => this.$refs.editFormRef && this.$refs.editFormRef.clearValidate());
  492. },
  493. // 优化展开父节点方法
  494. expandParentNodes(nodes, targetId) {
  495. const expandNodes = [];
  496. // 先收集需要展开的节点
  497. const findAndCollectParents = (nodes, targetId) => {
  498. for (const node of nodes) {
  499. if (node.id === targetId) {
  500. return true;
  501. }
  502. if (node.verList && node.verList.length) {
  503. const found = findAndCollectParents(node.verList, targetId);
  504. if (found) {
  505. expandNodes.push(node);
  506. return true;
  507. }
  508. }
  509. }
  510. return false;
  511. };
  512. findAndCollectParents(nodes, targetId);
  513. // 延迟展开,确保表格已准备好
  514. setTimeout(() => {
  515. expandNodes.forEach(node => {
  516. this.$refs.treeTable.toggleRowExpansion(node, true);
  517. });
  518. }, 300);
  519. },
  520. // 同时修改handleSubTaskSelect方法,确保数据加载完成
  521. handleSubTaskSelect(task) {
  522. return new Promise((resolve) => {
  523. this.selectedSubTask = task;
  524. this.selectedTreeNode = null;
  525. getListVer({subTaskId:task.id}).then((res) => {
  526. this.schemeTable = res.data;
  527. // 确保表格数据更新后重新渲染
  528. this.$nextTick(() => {
  529. if (this.$refs.treeTable) {
  530. this.$refs.treeTable.doLayout();
  531. }
  532. resolve();
  533. });
  534. console.log(this.schemeTable)
  535. });
  536. });
  537. },
  538. openExpectedEditDialog(plan) {
  539. this.$router.push({
  540. path: '/Deduction/taskSettingssss',
  541. query: {
  542. plan: JSON.stringify(plan)
  543. }
  544. });
  545. },
  546. /* 保存:处理树形表格选择 */
  547. onEditSave() {
  548. this.$refs.editFormRef.validate((valid) => {
  549. if (!valid) return;
  550. if (!this.selectedTask) {
  551. this.$message.error('请先选择一个总体任务');
  552. return;
  553. }
  554. if (!this.selectedSubTask) {
  555. this.$message.error('请选择一个子任务');
  556. return;
  557. }
  558. // 检查是否选择了节点
  559. if (!this.selectedTreeNode) {
  560. this.$message.error('请选择一个方案或版本');
  561. return;
  562. }
  563. // 写入所选方案和版本
  564. this.editForm.taskId = this.selectedTask.id;
  565. this.editForm.subTaskId = this.selectedSubTask.id;
  566. this.editForm.schemeId = this.selectedTreeNode.id;
  567. this.editForm.simulationType = 0;
  568. if(this.editMode==='add'){
  569. insertDeductionTask(this.editForm).then((res) => {
  570. if (res.code === 0) {
  571. this.$message.success('新建成功');
  572. this.taskList = [];
  573. this.selectedTask = null;
  574. this.subTaskList = [];
  575. this.selectedSubTask = null;
  576. this.selectedTreeNode = null;
  577. this.editVisible = false;
  578. this.handleQuery()
  579. } else {
  580. this.$message.error('新建失败');
  581. }
  582. });
  583. }else{
  584. updateDeductionTask(this.editForm).then((res)=>{
  585. if (res.code === 0) {
  586. this.$message.success('修改成功');
  587. this.taskList = [];
  588. this.selectedTask = null;
  589. this.subTaskList = [];
  590. this.selectedSubTask = null;
  591. this.selectedTreeNode = null;
  592. this.editVisible = false;
  593. this.handleQuery()
  594. } else {
  595. this.$message.error('修改失败');
  596. }
  597. })
  598. }
  599. });
  600. },
  601. /* 其它原有方法 */
  602. statusClass(s) {
  603. const map = { '已确认': 'success', '未确认': 'warning', '已失效': 'danger', '草稿': 'info' };
  604. return map[s] || 'info';
  605. },
  606. statusTagType(status) {
  607. const map = { '有效': 'warning', '待审核': 'warning', '草稿': 'info', '已失效': 'danger' };
  608. return map[status] || 'info';
  609. },
  610. handleClose(done) { done(); },
  611. async viewDetails(plan) {
  612. await this.getTaskList()
  613. this.taskList = this.taskList.filter(item=>item.id===plan.taskId)
  614. await this.getSubTaskList(plan.taskId)
  615. this.subTaskList = this.subTaskList.filter(item=>item.id===plan.subTaskId)
  616. this.dialogVisible = true;
  617. },
  618. /* 列表&分页占位 */
  619. handleQuery() {
  620. getList(this.queryForm).then((res) => {
  621. this.planList = res.data.records;
  622. this.total = res.data.total;
  623. });
  624. },
  625. resetQuery() {
  626. this.queryForm = { simulationName: '',intendedEditing:1,pageNo: 1,pageSize: 10 };
  627. this.handleQuery();
  628. },
  629. handleSizeChange(val) {
  630. this.queryForm.pageSize = val;
  631. this.handleQuery();
  632. },
  633. handleCurrentChange(val) {
  634. this.queryForm.pageNo = val;
  635. this.handleQuery();
  636. },
  637. fetchData() {
  638. this.queryForm.pageNo = 1;
  639. this.handleQuery();
  640. }
  641. }
  642. }
  643. </script>
  644. <style scoped>
  645. /* 弹窗体在 DarkDialog 里已经是深色,这里只美化表单 */
  646. .edit-form-dark {
  647. background: rgba(12, 33, 66, 0.6);
  648. border: 1px solid #2c3f59;
  649. border-radius: 8px;
  650. padding: 14px 16px;
  651. }
  652. .form-grid {
  653. display: grid;
  654. grid-template-columns: 1fr 1fr;
  655. column-gap: 18px;
  656. row-gap: 10px;
  657. }
  658. .form-grid .span-2 { grid-column: 1 / span 2; }
  659. ::v-deep .el-form-item__label { color: #9db2c9; }
  660. ::v-deep .el-input__inner,
  661. ::v-deep .el-textarea__inner,
  662. ::v-deep .el-select .el-input__inner,
  663. ::v-deep .el-date-editor .el-input__inner {
  664. background: rgba(0,0,0,0.18);
  665. border-color: rgba(255,255,255,0.12);
  666. color: #e6efff;
  667. }
  668. ::v-deep .el-input__inner::placeholder { color: #94a3b8; }
  669. ::v-deep .el-select-dropdown,
  670. ::v-deep .el-picker-panel {
  671. background: #1b2d4c;
  672. border-color: #2c3f59;
  673. color: #e6efff;
  674. }
  675. @media (max-width: 860px) {
  676. .form-grid { grid-template-columns: 1fr; }
  677. .form-grid .span-2 { grid-column: auto; }
  678. }
  679. .blue-btn:hover{
  680. background: #004466;
  681. border: 2px solid #1e3a5f;
  682. border-color: #4085ac;
  683. color: #fff;
  684. }
  685. /* Dialog 外观更暗、更清晰的分层 */
  686. ::v-deep .el-dialog__header {
  687. background: linear-gradient(180deg, #153b73, #0e2a53);
  688. border-bottom: 1px solid #364a64;
  689. }
  690. ::v-deep .el-dialog__title { color: #e6eefc; font-weight: 600; }
  691. ::v-deep .el-dialog__body { background: #0b254a; padding: 18px 22px; }
  692. ::v-deep .el-dialog__footer{
  693. background: #0b254a; border-top: 1px solid #364a64;
  694. }
  695. /* 内容容器 */
  696. .basic-info {
  697. border: 1px solid #2c3f59;
  698. border-radius: 8px;
  699. background: rgba(12, 33, 66, 0.6);
  700. box-shadow: inset 0 0 0 1px rgba(255,255,255,0.02);
  701. }
  702. /* 顶部条:密级与状态 */
  703. .top-line{
  704. display:flex; gap:10px; align-items:center;
  705. padding:12px 14px; border-bottom:1px dashed #2c3f59;
  706. }
  707. .chip{
  708. display:inline-block; padding:4px 10px; border-radius:999px;
  709. color:#fff; font-size:12px; letter-spacing:0.5px;
  710. }
  711. .chip.primary{ background:#3475b5; } /* 秘密 */
  712. .chip.warning{ background:#b88230; } /* 机密 */
  713. .chip.danger{ background:#c45656; } /* 绝密 */
  714. .chip.neutral{ background:#6b7280; }
  715. .chip.soft{ opacity:.9; }
  716. .chip.success{ background:#1f9d55; }
  717. .chip.info{ background:#4b5563; }
  718. /* 分组标题与栅格 */
  719. .section { padding: 10px 14px 14px; }
  720. .section + .section { border-top: 1px dashed #2c3f59; }
  721. .section-title{
  722. font-size:13px; color:#9db2c9; margin-bottom:8px;
  723. position:relative; padding-left:10px;
  724. }
  725. .section-title::before{
  726. content:''; position:absolute; left:0; top:4px; bottom:4px; width:3px;
  727. background: linear-gradient(180deg, #66a3ff, #3a7bd5);
  728. border-radius:2px;
  729. }
  730. /* 双栏对齐的键值栅格 */
  731. .info-grid{
  732. display:grid;
  733. grid-template-columns: 1fr 1fr;
  734. gap: 10px 18px;
  735. }
  736. .kv{ display:grid; grid-template-columns: 120px 1fr; align-items:center; }
  737. .kv.span-2{ grid-column: 1 / span 2; }
  738. .kv-label{ color:#8aa0bb; font-size:13px; justify-self:start; }
  739. .kv-value{
  740. color:#e7eef8; font-size:13px; line-height:1.6;
  741. background: rgba(0,0,0,0.12);
  742. border: 1px solid rgba(255,255,255,0.06);
  743. padding: 6px 10px; border-radius: 6px;
  744. }
  745. /* 任务卡片 */
  746. .task-select-section { margin-top: 20px; }
  747. .section-desc { font-size: 13px; color: #94a3b8; margin-bottom: 14px; }
  748. .task-card {
  749. background: #1e293b;
  750. border: 1px solid #334155;
  751. border-radius: 8px;
  752. padding: 16px;
  753. color: #e2e8f0;
  754. transition: all 0.25s ease;
  755. display: flex; flex-direction: column; justify-content: space-between;
  756. height: 100%;
  757. }
  758. .task-card:hover {
  759. border-color: #3b82f6;
  760. box-shadow: 0 4px 12px rgba(0,0,0,0.5);
  761. transform: translateY(-2px);
  762. cursor: pointer;
  763. }
  764. .task-card--active {
  765. border: 2px solid #3b82f6;
  766. box-shadow: 0 0 10px rgba(59,130,246,0.7);
  767. }
  768. .task-title { font-size: 15px; font-weight: 600; color: #fff; }
  769. .task-info { font-size: 13px; line-height: 1.6; margin-bottom: 12px; }
  770. .task-btn { width: 100%; font-weight: 600; border-radius: 6px; }
  771. /* 总体方案卡片(单选) */
  772. .plan-select-section { margin-top: 10px; }
  773. .plan-select-header {
  774. display:flex; align-items:center; justify-content: space-between; margin-bottom: 6px;
  775. }
  776. .plan-tools { display:flex; align-items:center; gap:10px; }
  777. .tool-label { color:#9db2c9; font-size:12px; margin-right:4px; }
  778. .plan-card {
  779. background: #0f1f38;
  780. border: 1px solid #2b3b55;
  781. border-radius: 8px;
  782. padding: 14px;
  783. color: #e2e8f0;
  784. transition: all .2s ease;
  785. height: 100%;
  786. }
  787. .plan-card:hover { border-color:#3b82f6; transform: translateY(-2px); cursor: pointer; }
  788. .plan-card--selected { border: 2px solid #3b82f6; box-shadow: 0 0 10px rgba(59,130,246,.5); }
  789. .plan-card__header { display:flex; align-items:center; justify-content: space-between; margin-bottom: 8px; }
  790. .plan-card__title { font-weight: 600; }
  791. .plan-card__check { font-size: 16px; }
  792. .plan-card__meta { display:flex; gap:12px; font-size:12px; color:#9db2c9; margin-bottom:8px; }
  793. .plan-card__desc { font-size: 12px; color:#cbd5e1; margin-bottom:10px; line-height: 1.7; }
  794. .plan-card__footer { display:flex; gap:8px; align-items:center; flex-wrap: wrap; }
  795. .selected-summary { margin-top: 10px; }
  796. </style>