Scenarioediting.vue 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  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.name"
  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. >
  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="handleEdit(plan)"
  35. @view-detail="openEditDialog(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="pagination.currentPage"
  45. :page-sizes="[10, 20, 50, 100]"
  46. :page-size="pagination.pageSize"
  47. layout="total, sizes, prev, pager, next, jumper"
  48. :total="pagination.total"
  49. />
  50. </template>
  51. </DarkLayout>
  52. <!-- 任务详情弹窗 -->
  53. <DarkDialog
  54. title="任务详情"
  55. :visible.sync="dialogVisible"
  56. width="50%"
  57. :before-close="handleClose"
  58. >
  59. <el-descriptions :column="2" border>
  60. <el-descriptions-item label="方案名称">{{ currentPlan.planName }}</el-descriptions-item>
  61. <el-descriptions-item label="任务名称">{{ currentPlan.taskName }}</el-descriptions-item>
  62. <el-descriptions-item label="任务代号">{{ currentPlan.taskCode }}</el-descriptions-item>
  63. <el-descriptions-item label="开始时间">{{ currentPlan.startTime }}</el-descriptions-item>
  64. <el-descriptions-item label="结束时间">{{ currentPlan.endTime }}</el-descriptions-item>
  65. <el-descriptions-item label="编制状态">{{ currentPlan.compileStatus }}</el-descriptions-item>
  66. <el-descriptions-item label="密级">{{ currentPlan.secretLevel }}</el-descriptions-item>
  67. <el-descriptions-item label="保密期限">{{ currentPlan.secretYears }}</el-descriptions-item>
  68. <el-descriptions-item label="状态">{{ currentPlan.status }}</el-descriptions-item>
  69. </el-descriptions>
  70. <span slot="footer" class="dialog-footer">
  71. <el-button @click="dialogVisible = false">关闭</el-button>
  72. </span>
  73. </DarkDialog>
  74. <!-- 基本信息弹窗 -->
  75. <DarkDialog title="基本信息" :visible.sync="basicInfoVisible" width="760px">
  76. <div class="basic-info">
  77. <div class="top-line">
  78. <span class="chip" :class="secretChipClass">{{ selectedPlan.secretLevel }}</span>
  79. <span class="chip soft" :class="statusClass(selectedPlan.status)">
  80. {{ selectedPlan.status }}
  81. </span>
  82. </div>
  83. <div class="section">
  84. <div class="section-title">任务信息</div>
  85. <div class="info-grid">
  86. <div class="kv"><div class="kv-label">任务代号</div><div class="kv-value">{{ selectedPlan.taskCode }}</div></div>
  87. <div class="kv"><div class="kv-label">任务名称</div><div class="kv-value">{{ selectedPlan.taskName }}</div></div>
  88. <div class="kv"><div class="kv-label">任务开始时间</div><div class="kv-value">{{ selectedPlan.taskStartTime }}</div></div>
  89. <div class="kv"><div class="kv-label">任务结束时间</div><div class="kv-value">{{ selectedPlan.taskEndTime }}</div></div>
  90. <div class="kv"><div class="kv-label">任务状态</div><div class="kv-value">{{ selectedPlan.taskStatus }}</div></div>
  91. <div class="kv"><div class="kv-label">保密期限</div><div class="kv-value">{{ selectedPlan.confidentialLevelYears }}</div></div>
  92. </div>
  93. </div>
  94. <div class="section">
  95. <div class="section-title">创建信息</div>
  96. <div class="info-grid">
  97. <div class="kv"><div class="kv-label">创建人</div><div class="kv-value">{{ selectedPlan.username }}</div></div>
  98. <div class="kv"><div class="kv-label">创建时间</div><div class="kv-value">{{ selectedPlan.createTime }}</div></div>
  99. </div>
  100. </div>
  101. </div>
  102. <span slot="footer" class="dialog-footer">
  103. <el-button @click="basicInfoVisible = false">关闭</el-button>
  104. </span>
  105. </DarkDialog>
  106. <!-- 新建/编辑 推演任务设定(单选总体方案) -->
  107. <DarkDialog :title="editDialogTitle" :visible.sync="editVisible" width="75%">
  108. <el-form
  109. ref="editFormRef"
  110. :model="editForm"
  111. :rules="baseRules"
  112. label-width="120px"
  113. class="edit-form-dark"
  114. >
  115. <div class="form-grid">
  116. <!-- 基础信息 -->
  117. <el-form-item label="推演任务名称" prop="simulationTaskName">
  118. <el-input v-model="editForm.simulationTaskName" clearable />
  119. </el-form-item>
  120. <el-form-item label="开始时间" prop="simulationStartTime" class="span-2">
  121. <el-date-picker
  122. v-model="editForm.simulationStartTime"
  123. type="datetime"
  124. value-format="yyyy-MM-dd HH:mm:ss"
  125. placeholder="选择开始时间"
  126. style="width: 100%;"
  127. />
  128. </el-form-item>
  129. <!-- 选择试验任务 -->
  130. <div class="task-select-section span-2">
  131. <h3 class="section-title">
  132. <i class="el-icon-document mr-2"></i> 选择试验任务
  133. </h3>
  134. <p class="section-desc">请选择要关联的试验任务,系统将根据任务推荐对应的总体方案</p>
  135. <el-row :gutter="20">
  136. <el-col :span="8" v-for="(task, index) in taskList" :key="index">
  137. <div
  138. class="task-card"
  139. :class="{ 'task-card--active': selectedTask && selectedTask.code === task.code }"
  140. @click="handleTaskSelect(task)"
  141. >
  142. <div class="flex justify-between items-center mb-3">
  143. <h4 class="task-title">{{ task.name }}</h4>
  144. <el-tag :type="getTagType(task.status)" size="mini">
  145. {{ task.statusText }}
  146. </el-tag>
  147. </div>
  148. <div class="task-info">
  149. <p>任务代号:{{ task.code }}</p>
  150. <p>开始时间:{{ task.startTime }}</p>
  151. <p>结束时间:{{ task.endTime }}</p>
  152. <p>任务类型:{{ task.type }}</p>
  153. </div>
  154. <el-button class="task-btn" type="primary">选择此任务</el-button>
  155. </div>
  156. </el-col>
  157. </el-row>
  158. </div>
  159. <!--选择综合布设方案(单选) -->
  160. <div v-if="currentOverallPlans.length" class="plan-select-section span-2">
  161. <div class="plan-select-header">
  162. <h3 class="section-title">
  163. <i class="el-icon-collection mr-2"></i>选择综合布设方案
  164. </h3>
  165. <el-button type="text" @click="clearPlanSelection">清空</el-button>
  166. </div>
  167. <p class="section-desc">
  168. 已为任务「{{ selectedTask && selectedTask.name }}」加载 {{ currentOverallPlans.length }} 个可用总体方案。
  169. </p>
  170. <el-row :gutter="20">
  171. <el-col :span="8" v-for="plan in currentOverallPlans" :key="plan.id">
  172. <div
  173. class="plan-card"
  174. :class="{ 'plan-card--selected': isPlanSelected(plan) }"
  175. @click="togglePlan(plan)"
  176. >
  177. <div class="plan-card__header">
  178. <span class="plan-card__title" :title="plan.planName">{{ plan.planName }}</span>
  179. <i v-if="isPlanSelected(plan)" class="el-icon-check plan-card__check"></i>
  180. </div>
  181. <div class="plan-card__meta">
  182. <span>任务:{{ plan.taskName }}</span>
  183. <span>版本:{{ plan.version }}</span>
  184. </div>
  185. <div class="plan-card__desc">
  186. <p>任务代号:{{ plan.taskCode }}</p>
  187. <p>开始时间:{{ plan.startTime }}</p>
  188. <p>结束时间:{{ plan.endTime }}</p>
  189. <p>保密等级:{{ plan.secretLevel }}</p>
  190. <p>保密期限:{{ plan.secretYears }}</p>
  191. </div>
  192. <div class="plan-card__footer">
  193. <!-- <el-tag size="mini" :type="statusTagType(plan.status)">{{ plan.status }}</el-tag>-->
  194. <el-tag size="mini" :type="plan.interferenceSchemeStatus === '已编制' ? 'success' : (plan.interferenceSchemeStatus === '编制中' ? 'warning' : 'info')">
  195. 干扰方案:{{ plan.interferenceSchemeStatus }}
  196. </el-tag>
  197. <el-tag size="mini" :type="plan.measurementSchemeStatus === '已编制' ? 'success' : (plan.measurementSchemeStatus === '编制中' ? 'warning' : 'info')">
  198. 测量方案:{{ plan.measurementSchemeStatus }}
  199. </el-tag>
  200. <el-tag size="mini" :type="plan.targetSchemeStatus === '已编制' ? 'success' : (plan.targetSchemeStatus === '编制中' ? 'warning' : 'info')">
  201. 目标方案:{{ plan.targetSchemeStatus }}
  202. </el-tag>
  203. </div>
  204. </div>
  205. </el-col>
  206. </el-row>
  207. <div class="selected-summary" v-if="selectedOverallPlanNames.length">
  208. <el-alert
  209. :title="`已选择:` + selectedOverallPlanNames.join('、')"
  210. type="success"
  211. :closable="false"
  212. show-icon
  213. />
  214. </div>
  215. </div>
  216. </div>
  217. </el-form>
  218. <span slot="footer" class="dialog-footer">
  219. <el-button @click="editVisible = false">取 消</el-button>
  220. <el-button type="primary" @click="onEditSave">保 存</el-button>
  221. </span>
  222. </DarkDialog>
  223. </div>
  224. </template>
  225. <script>
  226. import DarkLayout from '@/components/GlobalComponents/DarkLayout.vue'
  227. import TaskUserCard from '@/components/Components/TaskUserCard.vue'
  228. import DarkDialog from "@/components/Components/DarkDialog.vue";
  229. import ScenarioeditingCard from "@/components/GlobalComponents/ScenarioeditingCard.vue";
  230. export default {
  231. components: {
  232. ScenarioeditingCard,
  233. DarkDialog,
  234. DarkLayout,
  235. TaskUserCard
  236. },
  237. data() {
  238. return {
  239. /* 可选试验任务 */
  240. taskList: [
  241. {
  242. name: '新型导弹打击试验',
  243. status: 'creatable',
  244. statusText: '可创建',
  245. code: 'TASK-2023-001',
  246. startTime: '2023-01-01',
  247. endTime: '2023-12-31',
  248. type: '导弹试验'
  249. },
  250. {
  251. name: '电子对抗演练',
  252. status: 'creatable',
  253. statusText: '可创建',
  254. code: 'TASK-2023-002',
  255. startTime: '2023-02-01',
  256. endTime: '2023-11-30',
  257. type: '电子对抗'
  258. },
  259. {
  260. name: '综合试验验证',
  261. status: 'inProgress',
  262. statusText: '进行中',
  263. code: 'TASK-2023-003',
  264. startTime: '2023-03-01',
  265. endTime: '2023-10-31',
  266. type: '综合验证'
  267. }
  268. ],
  269. /* 任务 -> 总体方案(按任务分类,使用你的新数据结构) */
  270. overallPlanDict: {
  271. 'TASK-2023-001': [
  272. {
  273. id: '1',
  274. planName: '新型导弹打击试验-综合布设方案',
  275. taskName: '新型导弹打击试验',
  276. taskCode: 'TASK-2023-001',
  277. startTime: '2023-01-01',
  278. endTime: '2023-12-31',
  279. secretLevel: '秘密',
  280. secretYears: '10年',
  281. status: '有效',
  282. interferenceSchemeStatus: '已编制',
  283. measurementSchemeStatus: '已编制',
  284. targetSchemeStatus: '已编制',
  285. version: 'V1.0.0'
  286. },
  287. {
  288. id: '5',
  289. planName: '电子对抗演练-综合布设方案',
  290. taskName: '电子对抗演练',
  291. taskCode: 'TASK-2023-001',
  292. startTime: '2023-01-01',
  293. endTime: '2023-12-31',
  294. secretLevel: '秘密',
  295. secretYears: '10年',
  296. status: '有效',
  297. interferenceSchemeStatus: '已编制',
  298. measurementSchemeStatus: '已编制',
  299. targetSchemeStatus: '已编制',
  300. version: 'V1.0.0'
  301. }
  302. ],
  303. 'TASK-2023-002': [
  304. {
  305. id: '2',
  306. planName: '电子对抗演练-综合布设方案',
  307. taskName: '电子对抗演练',
  308. taskCode: 'TASK-2023-002',
  309. startTime: '2023-02-01',
  310. endTime: '2023-11-30',
  311. secretLevel: '机密',
  312. secretYears: '15年',
  313. status: '有效',
  314. interferenceSchemeStatus: '已编制',
  315. measurementSchemeStatus: '已编制',
  316. targetSchemeStatus: '已编制',
  317. version: 'V1.1.0'
  318. }
  319. ],
  320. 'TASK-2023-003': [
  321. {
  322. id: '3',
  323. planName: '电子对抗演练-综合布设方案',
  324. taskName: '电子对抗演练',
  325. taskCode: 'TASK-2023-003',
  326. startTime: '2023-03-01',
  327. endTime: '2023-10-31',
  328. secretLevel: '绝密',
  329. secretYears: '20年',
  330. status: '有效',
  331. interferenceSchemeStatus: '已编制',
  332. measurementSchemeStatus: '已编制',
  333. targetSchemeStatus: '已编制',
  334. version: 'V0.9.0'
  335. },
  336. {
  337. id: '4',
  338. planName: '新型导弹打击试验-综合布设方案',
  339. taskName: '新型导弹打击试验',
  340. taskCode: 'TASK-2023-003',
  341. startTime: '2023-03-01',
  342. endTime: '2023-10-31',
  343. secretLevel: '绝密',
  344. secretYears: '20年',
  345. status: '有效',
  346. interferenceSchemeStatus: '已编制',
  347. measurementSchemeStatus: '已编制',
  348. targetSchemeStatus: '已编制',
  349. version: 'V0.9.0'
  350. }
  351. ]
  352. },
  353. /* 当前选择状态(单选) */
  354. editVisible: false,
  355. editMode: 'edit', // 'add' | 'edit'
  356. selectedTask: null,
  357. currentOverallPlans: [],
  358. selectedOverallPlanId: '',
  359. /* 表单数据 */
  360. editForm: {
  361. timeRange: [],
  362. id: '',
  363. planName: '',
  364. simulationTaskName: '',
  365. simulationStartTime: '',
  366. simulationEndTime: '',
  367. simulationCount: '',
  368. simulationParticipantTasks: '',
  369. secretLevel: '秘密',
  370. status: '草稿',
  371. username: '',
  372. createTime: '',
  373. isScenarioEdited: false,
  374. selectedOverallPlans: [],
  375. selectedOverallPlanIds: []
  376. },
  377. baseRules: {
  378. simulationTaskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
  379. simulationStartTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
  380. simulationEndTime: [
  381. { required: true, message: '请选择结束时间', trigger: 'change' },
  382. { validator: (rule, value, cb) => this.validateTimeRange(rule, value, cb), trigger: 'change' }
  383. ],
  384. secretLevel: [{ required: true, message: '请选择密级', trigger: 'change' }]
  385. },
  386. /* 其他弹窗与数据 */
  387. basicInfoVisible: false,
  388. selectedPlan: {},
  389. tableData: [
  390. { date: '2023-06-01', name: '张三', address: '北京市海淀区' },
  391. { date: '2023-06-02', name: '李四', address: '上海市浦东新区' }
  392. ],
  393. dialogVisible: false,
  394. currentPlan: {},
  395. /* 列表和分页 */
  396. queryForm: { name: '', taskCode: '' },
  397. planList: [
  398. {
  399. id: 'sim-002',
  400. planName: '仿真试验任务',
  401. simulationTaskName: '多舰协同防空反导仿真',
  402. simulationStartTime: '2023-06-01 09:00:00',
  403. simulationEndTime: '2023-06-03 17:00:00',
  404. simulationCount: '3次',
  405. simulationParticipantTasks: '新型导弹打击试验',
  406. secretLevel: '秘密',
  407. status: '未确认',
  408. username: '李舰长',
  409. createTime: '2023-05-20 10:15:33'
  410. },
  411. {
  412. id: 'sim-003',
  413. planName: '仿真试验任务',
  414. simulationTaskName: '复杂电磁环境下电子对抗仿真',
  415. simulationStartTime: '2023-07-05 08:30:00',
  416. simulationEndTime: '2023-07-10 16:00:00',
  417. simulationCount: '8次',
  418. simulationParticipantTasks: '电子对抗演练',
  419. secretLevel: '绝密',
  420. status: '草稿',
  421. username: '王工程师',
  422. createTime: '2023-06-28 16:45:12'
  423. },
  424. {
  425. id: 'sim-004',
  426. planName: '仿真试验任务',
  427. simulationTaskName: '多军种联合指挥系统仿真推演',
  428. simulationStartTime: '2023-08-15 08:00:00',
  429. simulationEndTime: '2023-08-20 18:00:00',
  430. simulationCount: '6次',
  431. simulationParticipantTasks: '新型导弹打击试验',
  432. secretLevel: '机密',
  433. status: '草稿',
  434. username: '赵指挥官',
  435. createTime: '2023-07-30 09:20:45'
  436. },
  437. {
  438. id: 'sim-005',
  439. planName: '仿真试验任务',
  440. simulationTaskName: '复杂电磁环境下电子对抗仿真',
  441. simulationStartTime: '2023-07-05 08:30:00',
  442. simulationEndTime: '2023-07-10 16:00:00',
  443. simulationCount: '8次',
  444. simulationParticipantTasks: '电子对抗演练',
  445. secretLevel: '绝密',
  446. status: '草稿',
  447. username: '王工程师',
  448. createTime: '2023-06-28 16:45:12'
  449. },
  450. {
  451. id: 'sim-006',
  452. planName: '仿真试验任务',
  453. simulationTaskName: '多军种联合指挥系统仿真推演',
  454. simulationStartTime: '2023-08-15 08:00:00',
  455. simulationEndTime: '2023-08-20 18:00:00',
  456. simulationCount: '6次',
  457. simulationParticipantTasks: '新型导弹打击试验',
  458. secretLevel: '机密',
  459. status: '草稿',
  460. username: '赵指挥官',
  461. createTime: '2023-07-30 09:20:45'
  462. },
  463. {
  464. id: 'sim-007',
  465. planName: '仿真试验任务',
  466. simulationTaskName: '复杂电磁环境下电子对抗仿真',
  467. simulationStartTime: '2023-07-05 08:30:00',
  468. simulationEndTime: '2023-07-10 16:00:00',
  469. simulationCount: '8次',
  470. simulationParticipantTasks: '电子对抗演练',
  471. secretLevel: '绝密',
  472. status: '草稿',
  473. username: '王工程师',
  474. createTime: '2023-06-28 16:45:12'
  475. },
  476. ],
  477. pagination: { currentPage: 1, pageSize: 10, total: 0 }
  478. }
  479. },
  480. computed: {
  481. isAddMode() {
  482. return this.editMode === 'add'
  483. },
  484. editDialogTitle() {
  485. return this.editMode === 'add' ? '新建推演任务设定' : '编辑推演任务设定'
  486. },
  487. secretChipClass() {
  488. const map = { '绝密': 'danger', '机密': 'warning', '秘密': 'primary' }
  489. return map[this.selectedPlan?.secretLevel] || 'neutral'
  490. },
  491. selectedOverallPlanNames() {
  492. const p = this.currentOverallPlans.find(p => p.id === this.selectedOverallPlanId)
  493. return p ? [p.planName] : []
  494. }
  495. },
  496. methods: {
  497. /* 任务选择:加载其总体方案并清空已选 */
  498. handleTaskSelect(task) {
  499. this.selectedTask = task
  500. this.currentOverallPlans = this.overallPlanDict[task.code] || []
  501. this.clearPlanSelection()
  502. this.$message.success(`已选择任务:${task.name}`)
  503. },
  504. /* 单选工具 */
  505. isPlanSelected(plan) {
  506. return this.selectedOverallPlanId === plan.id
  507. },
  508. togglePlan(plan) {
  509. this.selectedOverallPlanId = (this.selectedOverallPlanId === plan.id) ? '' : plan.id
  510. },
  511. clearPlanSelection() {
  512. this.selectedOverallPlanId = ''
  513. },
  514. getTagType(status) {
  515. if (status === 'creatable') return 'success'
  516. else if (status === 'inProgress') return 'warning'
  517. return 'info'
  518. },
  519. /* 添加:打开空白同一套表单 */
  520. openAddDialog() {
  521. this.editMode = 'add'
  522. this.selectedTask = null
  523. this.currentOverallPlans = []
  524. this.clearPlanSelection()
  525. this.editForm = {
  526. id: '',
  527. planName: '',
  528. simulationTaskName: '',
  529. simulationStartTime: '',
  530. simulationEndTime: '',
  531. simulationCount: '',
  532. simulationParticipantTasks: '',
  533. secretLevel: '秘密',
  534. status: '草稿',
  535. username: '',
  536. createTime: '',
  537. isScenarioEdited: false,
  538. selectedOverallPlans: [],
  539. selectedOverallPlanIds: []
  540. }
  541. this.editVisible = true
  542. this.$nextTick(() => this.$refs.editFormRef && this.$refs.editFormRef.clearValidate())
  543. },
  544. openEditDialog(plan) {
  545. this.$router.push({
  546. path: '/Deduction/taskSettingssss',
  547. query: {
  548. plan: encodeURIComponent(JSON.stringify(plan))
  549. }
  550. })
  551. },
  552. /* 供卡片 @edit 使用的入口:弹出「基本信息」预览 */
  553. handleEdit() {
  554. this.basicInfoVisible = true
  555. this.selectedPlan = {
  556. status: '已确认',
  557. taskCode: 'plan-001',
  558. taskName: '新型导弹打击试验',
  559. taskStartTime: '2023-06-15',
  560. taskEndTime: '2023-06-20',
  561. taskStatus: '已编制',
  562. secretLevel: '秘密',
  563. confidentialLevelYears: '10年',
  564. username: '张三',
  565. createTime: '2023-01-01'
  566. }
  567. },
  568. /* 保存:单选版本 */
  569. onEditSave() {
  570. this.$refs.editFormRef.validate((valid) => {
  571. if (!valid) return
  572. if (!this.selectedTask) {
  573. this.$message.error('请先选择一个试验任务')
  574. return
  575. }
  576. if (!this.selectedOverallPlanId) {
  577. this.$message.error('请选择一个总体方案')
  578. return
  579. }
  580. const plan = this.currentOverallPlans.find(p => p.id === this.selectedOverallPlanId)
  581. if (!plan) return
  582. // 写入所选方案(保持后端兼容:IDs 与 名称串)
  583. this.editForm.selectedOverallPlans = [{ id: plan.id, name: plan.planName }]
  584. this.editForm.selectedOverallPlanIds = [plan.id]
  585. this.editForm.simulationParticipantTasks = plan.planName
  586. this.editForm.taskCode = this.selectedTask.code
  587. // 本地更新演示(替换为实际后端接口)
  588. const idx = this.planList.findIndex(p => p.id === this.editForm.id)
  589. if (idx !== -1) {
  590. this.$set(this.planList, idx, { ...this.planList[idx], ...this.editForm })
  591. } else {
  592. const newId = 'sim-' + Math.random().toString(36).slice(2, 6)
  593. const newItem = {
  594. id: newId,
  595. planName: '仿真试验任务',
  596. simulationTaskName: this.editForm.simulationTaskName,
  597. simulationStartTime: this.editForm.simulationStartTime,
  598. simulationEndTime: this.editForm.simulationEndTime,
  599. simulationCount: '1次',
  600. simulationParticipantTasks: this.editForm.simulationParticipantTasks,
  601. secretLevel: this.editForm.secretLevel,
  602. status: '草稿',
  603. username: this.editForm.username || '系统',
  604. createTime: this.editForm.createTime || new Date().toISOString().slice(0, 19).replace('T', ' ')
  605. }
  606. this.planList.unshift(newItem)
  607. }
  608. this.$message.success('已保存')
  609. this.editVisible = false
  610. })
  611. },
  612. /* 其它原有方法 */
  613. statusClass(s) {
  614. const map = { '已确认': 'success', '未确认': 'warning', '已失效': 'danger', '草稿': 'info' }
  615. return map[s] || 'info'
  616. },
  617. statusTagType(status) {
  618. const map = { '有效': 'warning', '待审核': 'warning', '草稿': 'info', '已失效': 'danger' }
  619. return map[status] || 'info'
  620. },
  621. handleViewDetail(plan) {
  622. this.$router.push({ path: '/Deduction/stratDeduction' })
  623. },
  624. handleClose(done) { done() },
  625. handleSelect(plan) {},
  626. viewDetails(plan) {
  627. this.currentPlan = plan
  628. this.dialogVisible = true
  629. },
  630. /* 时间范围校验:结束必须≥开始 */
  631. validateTimeRange(rule, value, callback) {
  632. const start = this.editForm.simulationStartTime
  633. const end = this.editForm.simulationEndTime
  634. if (start && end && new Date(end).getTime() < new Date(start).getTime()) {
  635. callback(new Error('结束时间不能早于开始时间'))
  636. } else {
  637. callback()
  638. }
  639. },
  640. /* 列表&分页占位 */
  641. handleQuery() {},
  642. resetQuery() {
  643. this.queryForm = { name: '', taskCode: '' }
  644. this.handleQuery()
  645. },
  646. handleSizeChange(val) {
  647. this.pagination.pageSize = val
  648. this.fetchData()
  649. },
  650. handleCurrentChange(val) {
  651. this.pagination.currentPage = val
  652. this.fetchData()
  653. },
  654. fetchData() {}
  655. }
  656. }
  657. </script>
  658. <style scoped>
  659. /* 弹窗体在 DarkDialog 里已经是深色,这里只美化表单 */
  660. .edit-form-dark {
  661. background: rgba(12, 33, 66, 0.6);
  662. border: 1px solid #2c3f59;
  663. border-radius: 8px;
  664. padding: 14px 16px;
  665. }
  666. .form-grid {
  667. display: grid;
  668. grid-template-columns: 1fr 1fr;
  669. column-gap: 18px;
  670. row-gap: 10px;
  671. }
  672. .form-grid .span-2 { grid-column: 1 / span 2; }
  673. ::v-deep .el-form-item__label { color: #9db2c9; }
  674. ::v-deep .el-input__inner,
  675. ::v-deep .el-textarea__inner,
  676. ::v-deep .el-select .el-input__inner,
  677. ::v-deep .el-date-editor .el-input__inner {
  678. background: rgba(0,0,0,0.18);
  679. border-color: rgba(255,255,255,0.12);
  680. color: #e6efff;
  681. }
  682. ::v-deep .el-input__inner::placeholder { color: #94a3b8; }
  683. ::v-deep .el-select-dropdown,
  684. ::v-deep .el-picker-panel {
  685. background: #1b2d4c;
  686. border-color: #2c3f59;
  687. color: #e6efff;
  688. }
  689. @media (max-width: 860px) {
  690. .form-grid { grid-template-columns: 1fr; }
  691. .form-grid .span-2 { grid-column: auto; }
  692. }
  693. .blue-btn:hover{
  694. background: #004466;
  695. border: 2px solid #1e3a5f;
  696. border-color: #4085ac;
  697. color: #fff;
  698. }
  699. /* Dialog 外观更暗、更清晰的分层 */
  700. ::v-deep .el-dialog__header {
  701. background: linear-gradient(180deg, #153b73, #0e2a53);
  702. border-bottom: 1px solid #364a64;
  703. }
  704. ::v-deep .el-dialog__title { color: #e6eefc; font-weight: 600; }
  705. ::v-deep .el-dialog__body { background: #0b254a; padding: 18px 22px; }
  706. ::v-deep .el-dialog__footer{
  707. background: #0b254a; border-top: 1px solid #364a64;
  708. }
  709. /* 内容容器 */
  710. .basic-info {
  711. border: 1px solid #2c3f59;
  712. border-radius: 8px;
  713. background: rgba(12, 33, 66, 0.6);
  714. box-shadow: inset 0 0 0 1px rgba(255,255,255,0.02);
  715. }
  716. /* 顶部条:密级与状态 */
  717. .top-line{
  718. display:flex; gap:10px; align-items:center;
  719. padding:12px 14px; border-bottom:1px dashed #2c3f59;
  720. }
  721. .chip{
  722. display:inline-block; padding:4px 10px; border-radius:999px;
  723. color:#fff; font-size:12px; letter-spacing:0.5px;
  724. }
  725. .chip.primary{ background:#3475b5; } /* 秘密 */
  726. .chip.warning{ background:#b88230; } /* 机密 */
  727. .chip.danger{ background:#c45656; } /* 绝密 */
  728. .chip.neutral{ background:#6b7280; }
  729. .chip.soft{ opacity:.9; }
  730. .chip.success{ background:#1f9d55; }
  731. .chip.info{ background:#4b5563; }
  732. /* 分组标题与栅格 */
  733. .section { padding: 10px 14px 14px; }
  734. .section + .section { border-top: 1px dashed #2c3f59; }
  735. .section-title{
  736. font-size:13px; color:#9db2c9; margin-bottom:8px;
  737. position:relative; padding-left:10px;
  738. }
  739. .section-title::before{
  740. content:''; position:absolute; left:0; top:4px; bottom:4px; width:3px;
  741. background: linear-gradient(180deg, #66a3ff, #3a7bd5);
  742. border-radius:2px;
  743. }
  744. /* 双栏对齐的键值栅格 */
  745. .info-grid{
  746. display:grid;
  747. grid-template-columns: 1fr 1fr;
  748. gap: 10px 18px;
  749. }
  750. .kv{ display:grid; grid-template-columns: 120px 1fr; align-items:center; }
  751. .kv.span-2{ grid-column: 1 / span 2; }
  752. .kv-label{ color:#8aa0bb; font-size:13px; justify-self:start; }
  753. .kv-value{
  754. color:#e7eef8; font-size:13px; line-height:1.6;
  755. background: rgba(0,0,0,0.12);
  756. border: 1px solid rgba(255,255,255,0.06);
  757. padding: 6px 10px; border-radius: 6px;
  758. }
  759. /* 任务卡片 */
  760. .task-select-section { margin-top: 20px; }
  761. .section-desc { font-size: 13px; color: #94a3b8; margin-bottom: 14px; }
  762. .task-card {
  763. background: #1e293b;
  764. border: 1px solid #334155;
  765. border-radius: 8px;
  766. padding: 16px;
  767. color: #e2e8f0;
  768. transition: all 0.25s ease;
  769. display: flex; flex-direction: column; justify-content: space-between;
  770. height: 100%;
  771. }
  772. .task-card:hover {
  773. border-color: #3b82f6;
  774. box-shadow: 0 4px 12px rgba(0,0,0,0.5);
  775. transform: translateY(-2px);
  776. cursor: pointer;
  777. }
  778. .task-card--active {
  779. border: 2px solid #3b82f6;
  780. box-shadow: 0 0 10px rgba(59,130,246,0.7);
  781. }
  782. .task-title { font-size: 15px; font-weight: 600; color: #fff; }
  783. .task-info { font-size: 13px; line-height: 1.6; margin-bottom: 12px; }
  784. .task-btn { width: 100%; font-weight: 600; border-radius: 6px; }
  785. /* 总体方案卡片(单选) */
  786. .plan-select-section { margin-top: 10px; }
  787. .plan-select-header {
  788. display:flex; align-items:center; justify-content: space-between; margin-bottom: 6px;
  789. }
  790. .plan-tools { display:flex; align-items:center; gap:10px; }
  791. .tool-label { color:#9db2c9; font-size:12px; margin-right:4px; }
  792. .plan-card {
  793. background: #0f1f38;
  794. border: 1px solid #2b3b55;
  795. border-radius: 8px;
  796. padding: 14px;
  797. color: #e2e8f0;
  798. transition: all .2s ease;
  799. height: 100%;
  800. }
  801. .plan-card:hover { border-color:#3b82f6; transform: translateY(-2px); cursor: pointer; }
  802. .plan-card--selected { border: 2px solid #3b82f6; box-shadow: 0 0 10px rgba(59,130,246,.5); }
  803. .plan-card__header { display:flex; align-items:center; justify-content: space-between; margin-bottom: 8px; }
  804. .plan-card__title { font-weight: 600; }
  805. .plan-card__check { font-size: 16px; }
  806. .plan-card__meta { display:flex; gap:12px; font-size:12px; color:#9db2c9; margin-bottom:8px; }
  807. .plan-card__desc { font-size: 12px; color:#cbd5e1; margin-bottom:10px; line-height: 1.7; }
  808. .plan-card__footer { display:flex; gap:8px; align-items:center; flex-wrap: wrap; }
  809. .selected-summary { margin-top: 10px; }
  810. </style>