orderEdit.vue 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959
  1. <template>
  2. <div class="task-setting-container">
  3. <!-- 背景网格装饰 -->
  4. <div class="grid-bg"></div>
  5. <!-- 头部区域:军事风格 - 庄重威严 -->
  6. <div class="header">
  7. <div class="header-logo flex items-center">
  8. <i class="el-icon-shield text-red-500 mr-2 text-xl"></i>
  9. <h1>任务想定编辑</h1>
  10. </div>
  11. <div class="header-controls">
  12. <el-button type="success" icon="el-icon-back" @click="goBack" class="btn军事">
  13. 返回
  14. </el-button>
  15. <el-button type="primary" icon="el-icon-save" @click="saveTask" class="btn军事">
  16. 保存任务
  17. </el-button>
  18. <el-button type="warning" icon="el-icon-refresh" @click="resetTask" class="btn军事">
  19. 重置
  20. </el-button>
  21. </div>
  22. </div>
  23. <!-- 主布局容器:大屏分区明确 -->
  24. <el-container class="h-[calc(100vh-60px)] flex-row overflow-hidden">
  25. <!-- 左侧栏:任务配置 -->
  26. <el-aside width="20%" class="min-w-[240px] border-right border-[#0c4a6e] relative">
  27. <div class="aside-border-decoration"></div>
  28. <div class="task-panel h-full">
  29. <div class="task-content">
  30. <!-- 基本信息:大屏简洁风格 -->
  31. <div class="section-card mb-6">
  32. <div class="section-header">
  33. <h4 class="section-title">
  34. <i class="el-icon-info"></i>
  35. 基本信息
  36. </h4>
  37. </div>
  38. <el-form :model="taskForm" label-width="100px" size="small" class="p-4">
  39. <el-form-item label="任务名称" class="mb-3">
  40. <el-input v-model="taskForm.name" placeholder="请输入任务名称" :disabled="true" />
  41. </el-form-item>
  42. <el-form-item label="任务类别" class="mb-3">
  43. <el-select v-model="taskForm.category" placeholder="请选择任务类别" :disabled="true">
  44. <el-option label="保障任务" value="support" />
  45. <el-option label="实战任务" value="combat" />
  46. </el-select>
  47. </el-form-item>
  48. <el-form-item label="任务类型" class="mb-3">
  49. <el-select v-model="taskForm.type" placeholder="请选择任务类型" :disabled="true">
  50. <el-option label="防空作战" value="air-defense" />
  51. <el-option label="对海作战" value="sea-combat" />
  52. <el-option label="对地打击" value="ground-strike" />
  53. <el-option label="电子对抗" value="electronic-warfare" />
  54. </el-select>
  55. </el-form-item>
  56. <el-form-item label="导弹类型" class="mb-3">
  57. <el-select v-model="taskForm.missileType" placeholder="请选择导弹类型" @change="updateTargetsByMissileType" :disabled="true">
  58. <el-option label="地空导弹" value="surface-to-air" />
  59. <el-option label="空地导弹" value="air-to-surface" />
  60. <el-option label="反舰导弹" value="anti-ship" />
  61. <el-option label="巡航导弹" value="cruise" />
  62. </el-select>
  63. </el-form-item>
  64. <el-form-item label="导弹数量" class="mb-3">
  65. <el-input-number v-model="taskForm.missileCount" :min="1" :max="100" size="small" @change="updateTargetsByMissileCount" :disabled="true" />
  66. </el-form-item>
  67. <el-form-item label="执行时间" class="mb-3">
  68. <el-date-picker
  69. v-model="taskForm.executeTime"
  70. type="datetime"
  71. placeholder="选择执行时间"
  72. format="yyyy-MM-dd HH:mm:ss"
  73. value-format="yyyy-MM-dd HH:mm:ss"
  74. :disabled="true"
  75. />
  76. </el-form-item>
  77. <el-form-item label="任务依据">
  78. <el-input
  79. v-model="taskForm.description"
  80. type="textarea"
  81. :rows="3"
  82. placeholder="请输入任务依据"
  83. :disabled="true"
  84. />
  85. </el-form-item>
  86. </el-form>
  87. </div>
  88. <!-- 靶标设置 -->
  89. <div class="section-card mb-6">
  90. <div class="section-header">
  91. <h4 class="section-title">
  92. <i class="el-icon-location"></i>
  93. 靶标设置
  94. </h4>
  95. <el-button type="text" icon="el-icon-plus" @click="addTarget" class="text-green-400" :disabled="!canAddMoreTargets">
  96. 添加靶标
  97. </el-button>
  98. </div>
  99. <div class="target-list p-4">
  100. <div class="target-hint text-xs text-yellow-400 mb-2" v-if="taskForm.targets.length < taskForm.missileCount">
  101. 提示:可添加 {{ taskForm.missileCount - taskForm.targets.length }} 个靶标
  102. </div>
  103. <div class="target-hint text-xs text-red-400 mb-2" v-if="taskForm.targets.length > taskForm.missileCount">
  104. 警告:靶标数量超过导弹数量 {{ taskForm.targets.length - taskForm.missileCount }} 个
  105. </div>
  106. <div
  107. class="target-item p-3 mb-3"
  108. v-for="target in taskForm.targets"
  109. :key="target.id"
  110. >
  111. <div class="target-header flex justify-between items-center mb-2">
  112. <span class="target-name font-bold truncate max-w-[150px]">{{ target.name }}</span>
  113. <div class="target-actions flex">
  114. <el-button type="text" icon="el-icon-edit" @click="editTarget(target)" class="p-1 text-blue-400" />
  115. <el-button type="text" icon="el-icon-delete" @click="removeTarget(target)" class="p-1 text-red-400" />
  116. </div>
  117. </div>
  118. <div class="target-info flex justify-between text-sm">
  119. <span class="target-type">{{ target.type }}</span>
  120. <span class="target-coord truncate max-w-[120px]">{{ target.coordinates }}</span>
  121. </div>
  122. <div class="target-threat mt-2 flex items-center text-xs">
  123. <span class="mr-2">威胁等级:</span>
  124. <div class="threat-bars flex gap-1">
  125. <div
  126. class="threat-bar"
  127. v-for="n in 5"
  128. :key="n"
  129. :class="{ 'active': n <= target.threatLevel }"
  130. ></div>
  131. </div>
  132. </div>
  133. <div class="target-equipment mt-2 text-xs text-gray-400">
  134. <span>负责装备:</span>
  135. <el-select v-model="target.equipmentId" placeholder="选择装备" size="mini" @change="updateTargetEquipment(target.id, $event)">
  136. <el-option
  137. v-for="equip in allEquipment"
  138. :key="equip.id"
  139. :label="equip.label"
  140. :value="equip.id"
  141. />
  142. </el-select>
  143. </div>
  144. </div>
  145. </div>
  146. </div>
  147. </div>
  148. </div>
  149. </el-aside>
  150. <!-- 中间主区域:装备配置(整合设备树和设备策略) -->
  151. <el-main class="p-0 h-full flex flex-col relative">
  152. <div class="main-border-decoration"></div>
  153. <!-- 装备配置内容区 -->
  154. <div class="equipment-content-box flex-1 overflow-y-auto p-4">
  155. <!-- 装备配置标题 -->
  156. <div class="section-card mb-6">
  157. <div class="section-header">
  158. <h4 class="section-title">
  159. <i class="el-icon-cpu mr-2"></i>
  160. 装备配置
  161. </h4>
  162. </div>
  163. <!-- 装备树和详情的分栏布局 -->
  164. <div class="equipment-config-container p-4 grid grid-cols-3 gap-4">
  165. <!-- 左侧:装备树形结构 -->
  166. <div class="equipment-tree-container col-span-1">
  167. <div class="section-card h-full">
  168. <div class="equipment-tree p-3">
  169. <el-tree
  170. :data="equipmentTree"
  171. :props="defaultProps"
  172. node-key="id"
  173. @node-click="handleEquipmentClick"
  174. :expand-on-click-node="false"
  175. :highlight-current="true"
  176. >
  177. <span slot-scope="{ node, data }" class="custom-tree-node">
  178. <span class="tree-node-content flex items-center">
  179. <i :class="getEquipmentIcon(data)" class="mr-2"></i>
  180. <span>{{ node.label }}</span>
  181. <span v-if="data.indicatorClass" class="ml-2 w-2 h-2 rounded-full" :class="data.indicatorClass"></span>
  182. </span>
  183. </span>
  184. </el-tree>
  185. </div>
  186. </div>
  187. </div>
  188. <!-- 右侧:装备详情和策略配置 -->
  189. <div class="equipment-details-container col-span-2">
  190. <div v-if="selectedEquipment" class="section-card h-full">
  191. <div class="section-header">
  192. <h4 class="section-title">
  193. <i :class="getEquipmentIcon(selectedEquipment)" class="mr-2"></i>
  194. {{ selectedEquipment.label }} - 配置详情
  195. </h4>
  196. </div>
  197. <div class="equipment-detail p-4">
  198. <div class="grid grid-cols-2 gap-4 mb-4">
  199. <div v-for="(item, index) in selectedEquipment.details" :key="index" class="detail-item">
  200. <div class="detail-label text-sm text-gray-400">{{ item.label }}</div>
  201. <div class="detail-value font-medium">{{ item.value }}</div>
  202. </div>
  203. </div>
  204. <div class="mt-4 pt-4 border-t border-blue-900/30">
  205. <h5 class="text-sm font-medium mb-3 text-blue-300">装备策略配置</h5>
  206. <el-form :model="selectedEquipmentStrategy" label-width="100px" size="small">
  207. <el-form-item label="工作模式">
  208. <el-select
  209. v-model="selectedEquipmentStrategy.mode"
  210. placeholder="选择工作模式"
  211. size="small"
  212. >
  213. <el-option v-for="option in selectedEquipmentStrategy.options" :key="option.value" :label="option.label" :value="option.value" />
  214. </el-select>
  215. </el-form-item>
  216. <el-form-item label="工作状态">
  217. <el-select
  218. v-model="selectedEquipment.status"
  219. placeholder="选择工作状态"
  220. size="small"
  221. @change="updateEquipmentStatus"
  222. >
  223. <el-option label="待命" value="standby" />
  224. <el-option label="就绪" value="ready" />
  225. <el-option label="维护中" value="maintenance" />
  226. </el-select>
  227. </el-form-item>
  228. <el-form-item label="部署位置">
  229. <el-select
  230. v-model="selectedEquipment.position"
  231. placeholder="选择部署位置"
  232. size="small"
  233. @change="updateEquipmentPosition"
  234. >
  235. <el-option label="左翼" value="left" />
  236. <el-option label="右翼" value="right" />
  237. <el-option label="中央" value="center" />
  238. <el-option label="前沿" value="front" />
  239. <el-option label="后方" value="rear" />
  240. </el-select>
  241. </el-form-item>
  242. <el-form-item label="优先级">
  243. <el-input-number v-model="selectedEquipmentStrategy.params.priority" :min="1" :max="10" size="mini" />
  244. </el-form-item>
  245. <el-form-item label="响应时间">
  246. <el-input-number v-model="selectedEquipmentStrategy.params.responseTime" :min="1" size="mini" />
  247. </el-form-item>
  248. <el-form-item label="备注信息">
  249. <el-input
  250. v-model="selectedEquipment.notes"
  251. type="textarea"
  252. :rows="2"
  253. placeholder="请输入备注信息"
  254. @change="updateEquipmentNotes"
  255. />
  256. </el-form-item>
  257. </el-form>
  258. </div>
  259. </div>
  260. </div>
  261. <div v-else class="section-card h-full flex items-center justify-center p-4 text-gray-400">
  262. <div class="text-center">
  263. <i class="el-icon-cpu text-3xl mb-2"></i>
  264. <p>请从左侧选择一个装备查看详情</p>
  265. </div>
  266. </div>
  267. </div>
  268. </div>
  269. </div>
  270. <!-- 装备数量概览 -->
  271. <div class="section-card mb-6">
  272. <div class="section-header">
  273. <h4 class="section-title">
  274. <i class="el-icon-dashboard mr-2"></i>
  275. 装备数量概览
  276. </h4>
  277. </div>
  278. <div class="equipment-status-grid p-4 grid grid-cols-4 gap-3">
  279. <div class="status-card p-3 border border-blue-500/30 rounded">
  280. <div class="status-title text-sm text-gray-400 mb-1">总装备数</div>
  281. <div class="status-value text-2xl font-bold">{{ totalEquipment }}</div>
  282. </div>
  283. <div class="status-card p-3 border border-green-500/30 rounded">
  284. <div class="status-title text-sm text-gray-400 mb-1">测量装备数</div>
  285. <div class="status-value text-2xl font-bold text-green-400">{{ measurementEquipmentCount }}</div>
  286. </div>
  287. <div class="status-card p-3 border border-purple-500/30 rounded">
  288. <div class="status-title text-sm text-gray-400 mb-1">干扰装备数</div>
  289. <div class="status-value text-2xl font-bold text-purple-400">{{ jammingEquipmentCount }}</div>
  290. </div>
  291. <div class="status-card p-3 border border-red-500/30 rounded">
  292. <div class="status-title text-sm text-gray-400 mb-1">靶标装备数</div>
  293. <div class="status-value text-2xl font-bold text-red-400">{{ targetEquipmentCount }}</div>
  294. </div>
  295. </div>
  296. </div>
  297. <!-- 靶标-装备分配关系 -->
  298. <div class="section-card">
  299. <div class="section-header">
  300. <h4 class="section-title">
  301. <i class="el-icon-link mr-2"></i>
  302. 靶标-装备分配关系
  303. </h4>
  304. </div>
  305. <div class="target-equipment-map p-4">
  306. <el-table
  307. :data="targetEquipmentMapData"
  308. border
  309. size="small"
  310. :header-cell-style="{background: 'rgba(30, 58, 138, 0.3)', color: '#bae6fd', borderColor: 'rgba(14, 165, 233, 0.2)'}"
  311. :row-style="{background: 'rgba(15, 23, 42, 0.5)', color: '#e0f2fe', borderColor: 'rgba(14, 165, 233, 0.1)'}"
  312. >
  313. <el-table-column prop="targetName" label="靶标名称"></el-table-column>
  314. <el-table-column prop="targetType" label="靶标类型"></el-table-column>
  315. <el-table-column prop="threatLevel" label="威胁等级">
  316. <template slot-scope="scope">
  317. <div class="threat-bars flex gap-1 justify-center">
  318. {{scope.row.threatLevel}}
  319. <div
  320. class="threat-bar"
  321. v-for="n in 5"
  322. :key="n"
  323. :class="{ 'active': n <= scope.row.threatLevel }"
  324. ></div>
  325. </div>
  326. </template>
  327. </el-table-column>
  328. <el-table-column prop="equipmentName" label="负责装备" width="180"></el-table-column>
  329. <el-table-column prop="equipmentStatus" label="装备状态" width="100">
  330. <template slot-scope="scope">
  331. <span :class="statusLabelClass(scope.row.equipmentStatus)">{{ equipmentStatusText(scope.row.equipmentStatus) }}</span>
  332. </template>
  333. </el-table-column>
  334. </el-table>
  335. </div>
  336. </div>
  337. </div>
  338. </el-main>
  339. <!-- 右侧栏:任务预览(优化布局) -->
  340. <el-aside width="20%" class="min-w-[240px] border-left border-[#0c4a6e] relative">
  341. <div class="aside-border-decoration"></div>
  342. <div class="preview-panel h-full">
  343. <div class="preview-content p-4">
  344. <!-- 任务类型信息(放在最上面) -->
  345. <div class="preview-section mb-4 p-3">
  346. <div class="task-type-title text-center text-lg font-bold text-blue-300 mb-1">{{ taskTypeName }}</div>
  347. <div class="task-category text-center text-sm text-gray-400">{{ taskCategoryName }}</div>
  348. <div class="task-missile text-center text-xs mt-2 text-gray-400">
  349. 导弹类型: {{ missileTypeName || '未选择' }}
  350. </div>
  351. </div>
  352. <!-- 任务概览:紧凑布局 -->
  353. <div class="preview-section mb-4">
  354. <h4 class="p-2 font-medium border-b m-0 text-sm">任务概览</h4>
  355. <div class="overview-stats p-3">
  356. <div class="stat-row-compact flex justify-between items-center py-1 border-b border-blue-900/10">
  357. <span class="stat-label-compact text-xs">靶标数量</span>
  358. <span class="stat-value-compact font-bold">{{ taskForm.targets.length }}</span>
  359. </div>
  360. <div class="stat-row-compact flex justify-between items-center py-1 border-b border-blue-900/10">
  361. <span class="stat-label-compact text-xs">导弹数量</span>
  362. <span class="stat-value-compact font-bold">{{ taskForm.missileCount || 0 }}</span>
  363. </div>
  364. <div class="stat-row-compact flex justify-between items-center py-1 border-b border-blue-900/10">
  365. <span class="stat-label-compact text-xs">装备总数</span>
  366. <span class="stat-value-compact font-bold">{{ totalEquipment }}</span>
  367. </div>
  368. <div class="stat-row-compact flex justify-between items-center py-1 border-b border-blue-900/10">
  369. <span class="stat-label-compact text-xs">就绪装备</span>
  370. <span class="stat-value-compact font-bold text-green-400">{{ readyEquipmentCount }}</span>
  371. </div>
  372. <div class="stat-row-compact flex justify-between items-center py-1">
  373. <span class="stat-label-compact text-xs">执行时间</span>
  374. <span class="stat-value-compact font-bold text-xs truncate">{{ taskForm.executeTime || '未指定' }}</span>
  375. </div>
  376. <div class="stat-row-compact flex justify-between items-center py-1">
  377. <span class="stat-label-compact text-xs">倒计时</span>
  378. <span class="stat-value-compact font-bold text-xs text-yellow-400">{{ formattedCountdown }}</span>
  379. </div>
  380. </div>
  381. </div>
  382. <!-- 执行时间轴:紧凑布局 -->
  383. <div class="preview-section">
  384. <h4 class="p-2 font-medium border-b m-0 text-sm">执行时间轴</h4>
  385. <div class="timeline-container p-3 relative">
  386. <div class="timeline-line absolute top-0 bottom-0 left-3 w-0.5"></div>
  387. <div
  388. class="timeline-item-compact relative mb-3 pl-8"
  389. v-for="event in events"
  390. :key="event.id"
  391. >
  392. <div class="timeline-dot absolute left-0 top-1 w-5 h-5 rounded-full flex items-center justify-center z-10" :class="dotClassMap[event.dotClass]">
  393. <div class="w-1.5 h-1.5 rounded-full bg-white"></div>
  394. </div>
  395. <div class="timeline-content-compact">
  396. <div class="flex justify-between items-start mb-0">
  397. <div class="timeline-time text-xs font-bold">{{ event.time }}</div>
  398. <!-- <div class="timeline-status text-xs px-1.5 py-0 rounded" :class="statusClassMap[event.dotClass]">{{ event.status }}</div>-->
  399. <div class="timeline-title text-xs font-bold">{{ event.title }}</div>
  400. </div>
  401. <!-- <div class="timeline-title text-xs font-bold">{{ event.title }}</div>-->
  402. </div>
  403. </div>
  404. </div>
  405. </div>
  406. </div>
  407. </div>
  408. </el-aside>
  409. </el-container>
  410. <!-- 添加靶标对话框 -->
  411. <el-dialog
  412. title="添加靶标"
  413. :visible.sync="showTargetDialog"
  414. width="30%"
  415. custom-class="target-dialog"
  416. >
  417. <el-form :model="targetForm" label-width="100px">
  418. <el-form-item label="靶标名称">
  419. <el-input v-model="targetForm.name" placeholder="请输入靶标名称"></el-input>
  420. </el-form-item>
  421. <el-form-item label="靶标类型">
  422. <el-select v-model="targetForm.type" placeholder="请选择靶标类型">
  423. <el-option label="空中靶标" value="空中靶标" :disabled="!isAirTargetAllowed"></el-option>
  424. <el-option label="海上靶标" value="海上靶标" :disabled="!isSeaTargetAllowed"></el-option>
  425. <el-option label="地面靶标" value="地面靶标" :disabled="!isGroundTargetAllowed"></el-option>
  426. </el-select>
  427. </el-form-item>
  428. <el-form-item label="坐标位置">
  429. <el-input v-model="targetForm.coordinates" placeholder="格式:东经XX°XX′,北纬XX°XX′"></el-input>
  430. </el-form-item>
  431. <el-form-item label="威胁等级">
  432. <el-slider v-model="targetForm.threatLevel" :min="1" :max="5" show-input />
  433. </el-form-item>
  434. <el-form-item label="负责装备">
  435. <el-select v-model="targetForm.equipmentId" placeholder="选择负责装备">
  436. <el-option
  437. v-for="equip in allEquipment"
  438. :key="equip.id"
  439. :label="equip.label"
  440. :value="equip.id"
  441. />
  442. </el-select>
  443. </el-form-item>
  444. </el-form>
  445. <div slot="footer" class="dialog-footer">
  446. <el-button @click="showTargetDialog = false" class="btn军事">取消</el-button>
  447. <el-button type="primary" @click="confirmAddTarget" class="btn军事">确定</el-button>
  448. </div>
  449. </el-dialog>
  450. </div>
  451. </template>
  452. <script>
  453. export default {
  454. components: {},
  455. data() {
  456. return {
  457. // 时间显示
  458. 天文时间: '',
  459. 绝对时间: '',
  460. // 任务表单数据 - 设置默认值
  461. taskForm: {
  462. name: '红旗-9B防空导弹拦截试验',
  463. category: 'combat', // 任务类别:support-保障任务,combat-实战任务
  464. type: 'air-defense',
  465. missileType: 'surface-to-air', // 导弹类型
  466. missileCount: 6, // 导弹数量
  467. executeTime: '2025-10-15 14:30:00',
  468. description: '本次试验旨在验证红旗-9B防空导弹系统对多批次、多类型空中靶标的拦截能力,测试在强电子干扰环境下的作战效能。',
  469. targets: [
  470. {
  471. id: 1,
  472. name: '高空侦察机',
  473. type: '空中靶标',
  474. coordinates: '东经121°25′,北纬30°15′',
  475. threatLevel: 5,
  476. equipmentId: 'A1'
  477. },
  478. {
  479. id: 2,
  480. name: '巡航导弹模拟靶',
  481. type: '空中靶标',
  482. coordinates: '东经121°30′,北纬30°20′',
  483. threatLevel: 4,
  484. equipmentId: 'A1'
  485. },
  486. {
  487. id: 3,
  488. name: '隐身战机模拟靶',
  489. type: '空中靶标',
  490. coordinates: '东经121°20′,北纬30°25′',
  491. threatLevel: 5,
  492. equipmentId: 'B2'
  493. }
  494. ]
  495. },
  496. // 装备树形结构数据
  497. equipmentTree: [
  498. {
  499. id: 'category1',
  500. label: '测量装备',
  501. children: [
  502. {
  503. id: 'A1',
  504. label: '高空观测装置A1',
  505. side: '',
  506. indicatorClass: 'bg-blue-500',
  507. status: 'ready',
  508. position: 'front',
  509. notes: '',
  510. details: [
  511. { label: '状态', value: '运行中' },
  512. { label: '覆盖范围', value: '3500米' },
  513. { label: '高度', value: '5000米' },
  514. { label: '观测精度', value: '92%' },
  515. { label: '功率', value: '100%' },
  516. { label: '电量', value: '86%' },
  517. { label: '发现目标', value: '3个' },
  518. { label: '数据链路', value: '稳定' }
  519. ]
  520. },
  521. {
  522. id: 'B2',
  523. label: '地面观测装置B2',
  524. side: '',
  525. indicatorClass: 'bg-blue-500',
  526. status: 'ready',
  527. position: 'center',
  528. notes: '',
  529. details: [
  530. { label: '状态', value: '运行中' },
  531. { label: '覆盖范围', value: '1200米' },
  532. { label: '高度', value: '100米' },
  533. { label: '观测精度', value: '88%' },
  534. { label: '功率', value: '90%' },
  535. { label: '电量', value: '92%' },
  536. { label: '发现目标', value: '2个' },
  537. { label: '数据链路', value: '稳定' }
  538. ]
  539. },
  540. {
  541. id: 'C3',
  542. label: '移动观测装置C3',
  543. side: '',
  544. indicatorClass: 'bg-blue-500',
  545. status: 'standby',
  546. position: 'rear',
  547. notes: '',
  548. details: [
  549. { label: '状态', value: '待命' },
  550. { label: '覆盖范围', value: '800米' },
  551. { label: '速度', value: '40km/h' },
  552. { label: '观测精度', value: '85%' },
  553. { label: '功率', value: '70%' },
  554. { label: '电量', value: '95%' },
  555. { label: '发现目标', value: '0个' },
  556. { label: '数据链路', value: '稳定' }
  557. ]
  558. }
  559. ]
  560. },
  561. {
  562. id: 'category2',
  563. label: '干扰装备',
  564. children: [
  565. {
  566. id: 'D1',
  567. label: '雷达干扰器D1',
  568. side: '',
  569. indicatorClass: 'bg-purple-500',
  570. status: 'standby',
  571. position: 'left',
  572. notes: '',
  573. details: [
  574. { label: '状态', value: '待命' },
  575. { label: '功率', value: '60%' },
  576. { label: '高度', value: '50米' },
  577. { label: '覆盖范围', value: '2000米' },
  578. { label: '电量', value: '95%' },
  579. { label: '干扰类型', value: '雷达波' },
  580. { label: '有效距离', value: '5km' },
  581. { label: '数据链路', value: '稳定' }
  582. ]
  583. },
  584. {
  585. id: 'E2',
  586. label: '光电干扰器E2',
  587. side: '',
  588. indicatorClass: 'bg-purple-500',
  589. status: 'ready',
  590. position: 'right',
  591. notes: '',
  592. details: [
  593. { label: '状态', value: '运行中' },
  594. { label: '功率', value: '80%' },
  595. { label: '干扰波段', value: '可见光-红外' },
  596. { label: '覆盖范围', value: '1500米' },
  597. { label: '电量', value: '88%' },
  598. { label: '干扰强度', value: '强' },
  599. { label: '数据链路', value: '稳定' }
  600. ]
  601. }
  602. ]
  603. },
  604. {
  605. id: 'category3',
  606. label: '靶标装备',
  607. children: [
  608. {
  609. id: 'redA',
  610. label: '空中靶标A集群',
  611. side: '',
  612. indicatorClass: 'bg-red-500',
  613. status: 'ready',
  614. position: 'front',
  615. notes: '',
  616. details: [
  617. { label: '状态', value: '就绪' },
  618. { label: '数量', value: '5' },
  619. { label: '速度', value: '350m/s' },
  620. { label: '高度', value: '2000米' },
  621. { label: '机动能力', value: '高' },
  622. { label: '雷达反射面积', value: '0.1-5㎡' },
  623. { label: '数据链路', value: '可控' }
  624. ]
  625. },
  626. {
  627. id: 'redB',
  628. label: '海上靶标B',
  629. side: '',
  630. indicatorClass: 'bg-red-500',
  631. status: 'standby',
  632. position: 'front',
  633. notes: '',
  634. details: [
  635. { label: '状态', value: '待命' },
  636. { label: '排水量', value: '500吨' },
  637. { label: '速度', value: '30节' },
  638. { label: '雷达反射面积', value: '500㎡' },
  639. { label: '机动能力', value: '中' },
  640. { label: '数据链路', value: '可控' }
  641. ]
  642. }
  643. ]
  644. }
  645. ],
  646. defaultProps: {
  647. children: 'children',
  648. label: 'label'
  649. },
  650. // 选中装备的策略配置
  651. selectedEquipmentStrategy: {
  652. mode: '',
  653. options: [],
  654. params: {
  655. priority: 5,
  656. responseTime: 30
  657. }
  658. },
  659. // 时间轴事件数据
  660. events: [
  661. {
  662. id: 1,
  663. title: '靶标装备就位',
  664. time: 'T+00:00:00',
  665. description: '所有靶标装备到达指定位置',
  666. status: '全部就位',
  667. dotClass: 'warning',
  668. position: 50
  669. },
  670. {
  671. id: 2,
  672. title: '导弹准备发射',
  673. time: 'T+00:01:45',
  674. description: '导弹系统进入发射准备阶段',
  675. status: '准备中...',
  676. dotClass: 'warning',
  677. position: 70
  678. },
  679. {
  680. id: 3,
  681. title: '干扰装备启动',
  682. time: 'T-00:02:30',
  683. description: '干扰装备D1和E2开始启动',
  684. status: '功率: 60%',
  685. dotClass: 'info',
  686. position: 30
  687. },
  688. {
  689. id: 4,
  690. title: '试验开始',
  691. time: 'T+00:03:20',
  692. description: '导弹发射,测量系统开始记录数据',
  693. status: '进行中',
  694. dotClass: 'danger',
  695. position: 90
  696. },
  697. {
  698. id: 5,
  699. title: '观测装置部署完成',
  700. time: 'T-00:05:00',
  701. description: '完成高空观测装置A1、地面观测装置B2部署',
  702. status: '覆盖率: 92%',
  703. dotClass: 'info',
  704. position: 10
  705. },
  706. ],
  707. // 其他状态
  708. showTargetDialog: false,
  709. targetForm: {
  710. name: '',
  711. type: '',
  712. coordinates: '',
  713. threatLevel: 3,
  714. equipmentId: ''
  715. },
  716. selectedEquipment: null,
  717. // 时间轴点颜色映射
  718. dotClassMap: {
  719. info: 'bg-blue-500', // 信息蓝
  720. warning: 'bg-yellow-500', // 警告黄
  721. danger: 'bg-red-500' // 危险红
  722. },
  723. // 状态标签样式映射
  724. statusClassMap: {
  725. info: 'bg-blue-900/50 text-blue-300',
  726. warning: 'bg-yellow-900/50 text-yellow-300',
  727. danger: 'bg-red-900/50 text-red-300'
  728. }
  729. }
  730. },
  731. computed: {
  732. measurementEquipmentCount() {
  733. let count = 0;
  734. this.equipmentTree.forEach(category => {
  735. if (category.id === 'category1' && category.children) {
  736. count += category.children.length;
  737. }
  738. });
  739. return count;
  740. },
  741. jammingEquipmentCount() {
  742. let count = 0;
  743. this.equipmentTree.forEach(category => {
  744. if (category.id === 'category2' && category.children) {
  745. count += category.children.length;
  746. }
  747. });
  748. return count;
  749. },
  750. targetEquipmentCount() {
  751. let count = 0;
  752. this.equipmentTree.forEach(category => {
  753. if (category.id === 'category3' && category.children) {
  754. count += category.children.length;
  755. }
  756. });
  757. return count;
  758. },
  759. totalEquipment() {
  760. // 计算所有装备的总数
  761. let count = 0;
  762. this.equipmentTree.forEach(category => {
  763. if (category.children && category.children.length) {
  764. count += category.children.length;
  765. }
  766. });
  767. return count;
  768. },
  769. readyEquipmentCount() {
  770. // 计算就绪状态的装备数量
  771. let count = 0;
  772. this.equipmentTree.forEach(category => {
  773. if (category.children && category.children.length) {
  774. category.children.forEach(equip => {
  775. if (equip.status === 'ready') count++;
  776. });
  777. }
  778. });
  779. return count;
  780. },
  781. standbyEquipmentCount() {
  782. // 计算待命状态的装备数量
  783. let count = 0;
  784. this.equipmentTree.forEach(category => {
  785. if (category.children && category.children.length) {
  786. category.children.forEach(equip => {
  787. if (equip.status === 'standby') count++;
  788. });
  789. }
  790. });
  791. return count;
  792. },
  793. maintenanceEquipmentCount() {
  794. // 计算维护中状态的装备数量
  795. let count = 0;
  796. this.equipmentTree.forEach(category => {
  797. if (category.children && category.children.length) {
  798. category.children.forEach(equip => {
  799. if (equip.status === 'maintenance') count++;
  800. });
  801. }
  802. });
  803. return count;
  804. },
  805. allEquipment() {
  806. // 提取所有装备列表
  807. let equipment = [];
  808. this.equipmentTree.forEach(category => {
  809. if (category.children && category.children.length) {
  810. equipment = [...equipment, ...category.children];
  811. }
  812. });
  813. return equipment;
  814. },
  815. /*sortedEvents() {
  816. // 按时间排序事件,从T0开始递增
  817. return [...this.events].sort((a, b) => {
  818. // 解析时间格式为秒数以便比较
  819. const getSeconds = (timeStr) => {
  820. const sign = timeStr.startsWith('T+') ? 1 : -1;
  821. const timePart = timeStr.substring(2);
  822. const [hours, minutes, seconds] = timePart.split(':').map(Number);
  823. return sign * (hours * 3600 + minutes * 60 + seconds);
  824. };
  825. return getSeconds(a.time) - getSeconds(b.time);
  826. });
  827. },*/
  828. taskTypeName() {
  829. const typeMap = {
  830. 'air-defense': '防空作战',
  831. 'sea-combat': '对海作战',
  832. 'ground-strike': '对地打击',
  833. 'electronic-warfare': '电子对抗'
  834. };
  835. return typeMap[this.taskForm.type] || '未设置';
  836. },
  837. taskCategoryName() {
  838. const categoryMap = {
  839. 'support': '保障任务',
  840. 'combat': '实战任务'
  841. };
  842. return categoryMap[this.taskForm.category] || '未设置';
  843. },
  844. missileTypeName() {
  845. const missileTypeMap = {
  846. 'surface-to-air': '地空导弹',
  847. 'air-to-surface': '空地导弹',
  848. 'anti-ship': '反舰导弹',
  849. 'cruise': '巡航导弹'
  850. };
  851. return missileTypeMap[this.taskForm.missileType] || '';
  852. },
  853. canAddMoreTargets() {
  854. // 控制是否可以添加更多靶标
  855. return this.taskForm.missileCount > 0 && this.taskForm.targets.length < this.taskForm.missileCount * 2;
  856. },
  857. // 根据导弹类型判断允许的靶标类型
  858. isAirTargetAllowed() {
  859. return ['surface-to-air', 'air-to-surface', 'cruise'].includes(this.taskForm.missileType);
  860. },
  861. isSeaTargetAllowed() {
  862. return ['anti-ship', 'cruise'].includes(this.taskForm.missileType);
  863. },
  864. isGroundTargetAllowed() {
  865. return ['air-to-surface', 'cruise'].includes(this.taskForm.missileType);
  866. },
  867. formattedCountdown() {
  868. // 计算倒计时
  869. if (!this.taskForm.executeTime) return '未设置执行时间';
  870. const executeTime = new Date(this.taskForm.executeTime).getTime();
  871. const now = new Date().getTime();
  872. const diff = executeTime - now;
  873. if (diff < 0) return '已过期';
  874. const days = Math.floor(diff / (1000 * 60 * 60 * 24));
  875. const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  876. const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
  877. return `${days}天${hours}时${minutes}分后执行`;
  878. },
  879. targetEquipmentMapData() {
  880. // 构建靶标-装备关系数据
  881. return this.taskForm.targets.map(target => {
  882. const equipment = this.allEquipment.find(equip => equip.id === target.equipmentId);
  883. return {
  884. targetName: target.name,
  885. targetType: target.type,
  886. threatLevel: target.threatLevel,
  887. equipmentName: equipment ? equipment.label : '未分配',
  888. equipmentStatus: equipment ? equipment.status : ''
  889. };
  890. });
  891. }
  892. },
  893. methods: {
  894. startShow() {
  895. this.$router.push('/Deduction/stratDeduction')
  896. },
  897. saveTask() {
  898. // 验证靶标设置不能为空
  899. if (this.taskForm.targets.length === 0) {
  900. this.$message.error('靶标设置不能为空,请添加至少一个靶标');
  901. return;
  902. }
  903. this.$message.success('任务保存成功')
  904. },
  905. goBack(){
  906. // 返回上一页逻辑
  907. this.$confirm('确定要退出吗?', '提示', {
  908. confirmButtonText: '确定',
  909. cancelButtonText: '取消',
  910. type: 'warning'
  911. }).then(() => {
  912. this.$router.go(-1)
  913. }).catch(() => {
  914. // 取消重置
  915. });
  916. },
  917. startSimulation() {
  918. this.$message.info('开始任务推演...')
  919. },
  920. resetTask() {
  921. this.$confirm('确定要重置任务配置吗?', '提示', {
  922. confirmButtonText: '确定',
  923. cancelButtonText: '取消',
  924. type: 'warning'
  925. }).then(() => {
  926. // 重置表单逻辑
  927. this.$message.success('任务配置已重置');
  928. }).catch(() => {
  929. // 取消重置
  930. });
  931. },
  932. addTarget() {
  933. this.targetForm = {
  934. name: '',
  935. type: '',
  936. coordinates: '',
  937. threatLevel: 3,
  938. equipmentId: ''
  939. };
  940. this.showTargetDialog = true;
  941. },
  942. confirmAddTarget() {
  943. if (!this.targetForm.name || !this.targetForm.type || !this.targetForm.coordinates) {
  944. this.$message.warning('请填写完整靶标信息');
  945. return;
  946. }
  947. this.taskForm.targets.push({
  948. id: Date.now(),
  949. ...this.targetForm
  950. });
  951. this.showTargetDialog = false;
  952. this.$message.success('靶标添加成功');
  953. },
  954. editTarget(target) {
  955. this.targetForm = { ...target };
  956. this.showTargetDialog = true;
  957. },
  958. removeTarget(target) {
  959. this.$confirm(`确定要删除靶标"${target.name}"吗?`, '提示', {
  960. confirmButtonText: '确定',
  961. cancelButtonText: '取消',
  962. type: 'warning'
  963. }).then(() => {
  964. this.taskForm.targets = this.taskForm.targets.filter(t => t.id !== target.id);
  965. this.$message.success('靶标已删除');
  966. }).catch(() => {
  967. // 取消删除
  968. });
  969. },
  970. // 处理装备点击事件
  971. handleEquipmentClick(data) {
  972. // 只处理叶子节点(具体装备)
  973. if (!data.children || data.children.length === 0) {
  974. this.selectedEquipment = { ...data };
  975. // 设置该装备对应的策略选项
  976. this.setEquipmentStrategyOptions(data);
  977. }
  978. },
  979. // 根据装备类型设置策略选项
  980. setEquipmentStrategyOptions(equipment) {
  981. // 根据不同类型的装备设置不同的策略选项
  982. if (equipment.id.startsWith('A') || equipment.id.startsWith('B') || equipment.id.startsWith('C')) {
  983. // 测量装备
  984. this.selectedEquipmentStrategy = {
  985. mode: 'track',
  986. options: [
  987. { label: '持续跟踪', value: 'track' },
  988. { label: '重点跟踪', value: 'focus' },
  989. { label: '扫描跟踪', value: 'scan' }
  990. ],
  991. params: {
  992. priority: 3,
  993. responseTime: 10
  994. }
  995. };
  996. } else if (equipment.id.startsWith('D') || equipment.id.startsWith('E')) {
  997. // 干扰装备
  998. this.selectedEquipmentStrategy = {
  999. mode: 'auto',
  1000. options: [
  1001. { label: '自动干扰模式', value: 'auto' },
  1002. { label: '手动干扰模式', value: 'manual' },
  1003. { label: '前置干扰模式', value: 'preemptive' }
  1004. ],
  1005. params: {
  1006. priority: 5,
  1007. responseTime: 30
  1008. }
  1009. };
  1010. } else if (equipment.id.startsWith('red')) {
  1011. // 靶标装备
  1012. this.selectedEquipmentStrategy = {
  1013. mode: 'evade',
  1014. options: [
  1015. { label: '规避模式', value: 'evade' },
  1016. { label: '突防模式', value: 'penetrate' },
  1017. { label: '佯动模式', value: 'feint' }
  1018. ],
  1019. params: {
  1020. priority: 4,
  1021. responseTime: 5
  1022. }
  1023. };
  1024. }
  1025. },
  1026. // 更新装备状态
  1027. updateEquipmentStatus() {
  1028. this.updateEquipmentData();
  1029. },
  1030. // 更新装备位置
  1031. updateEquipmentPosition() {
  1032. this.updateEquipmentData();
  1033. },
  1034. // 更新装备备注
  1035. updateEquipmentNotes() {
  1036. this.updateEquipmentData();
  1037. },
  1038. // 更新树形结构中的装备数据
  1039. updateEquipmentData() {
  1040. if (!this.selectedEquipment) return;
  1041. const updateNode = (nodes) => {
  1042. for (let i = 0; i < nodes.length; i++) {
  1043. if (nodes[i].id === this.selectedEquipment.id) {
  1044. nodes[i] = { ...this.selectedEquipment };
  1045. return true;
  1046. }
  1047. if (nodes[i].children && nodes[i].children.length) {
  1048. if (updateNode(nodes[i].children)) {
  1049. return true;
  1050. }
  1051. }
  1052. }
  1053. return false;
  1054. };
  1055. updateNode(this.equipmentTree);
  1056. },
  1057. // 更新靶标关联的装备
  1058. updateTargetEquipment(targetId, equipmentId) {
  1059. const target = this.taskForm.targets.find(t => t.id === targetId);
  1060. if (target) {
  1061. target.equipmentId = equipmentId;
  1062. }
  1063. },
  1064. // 根据导弹类型更新靶标设置
  1065. updateTargetsByMissileType() {
  1066. // 根据选择的导弹类型过滤不兼容的靶标
  1067. if (!this.taskForm.missileType) return;
  1068. const compatibleTypes = [];
  1069. if (this.isAirTargetAllowed) compatibleTypes.push('空中靶标');
  1070. if (this.isSeaTargetAllowed) compatibleTypes.push('海上靶标');
  1071. if (this.isGroundTargetAllowed) compatibleTypes.push('地面靶标');
  1072. // 过滤不兼容的靶标
  1073. this.taskForm.targets = this.taskForm.targets.filter(target =>
  1074. compatibleTypes.includes(target.type)
  1075. );
  1076. // 如果没有靶标,自动创建一个兼容的靶标
  1077. if (this.taskForm.targets.length === 0) {
  1078. this.taskForm.targets.push({
  1079. id: Date.now(),
  1080. name: `靶标${compatibleTypes[0]}`,
  1081. type: compatibleTypes[0],
  1082. coordinates: '东经120°00′,北纬30°00′',
  1083. threatLevel: 3,
  1084. equipmentId: ''
  1085. });
  1086. }
  1087. },
  1088. // 根据导弹数量更新靶标设置
  1089. updateTargetsByMissileCount() {
  1090. // 如果靶标数量超过导弹数量的2倍,删除多余的靶标
  1091. const maxTargets = this.taskForm.missileCount * 2;
  1092. if (this.taskForm.targets.length > maxTargets) {
  1093. this.taskForm.targets = this.taskForm.targets.slice(0, maxTargets);
  1094. this.$message.info(`靶标数量已调整为${maxTargets}个(不超过导弹数量的2倍)`);
  1095. }
  1096. },
  1097. // 获取装备图标
  1098. getEquipmentIcon(data) {
  1099. // 判断是否为类别节点
  1100. if (data.children && data.children.length > 0) {
  1101. return 'el-icon-folder-opened';
  1102. }
  1103. // 根据装备类型返回不同图标
  1104. if (data.id.startsWith('A') || data.id.startsWith('B') || data.id.startsWith('C')) {
  1105. return 'el-icon-eye';
  1106. } else if (data.id.startsWith('D') || data.id.startsWith('E')) {
  1107. return 'el-icon-wifi';
  1108. } else if (data.id.startsWith('red')) {
  1109. return 'el-icon-target';
  1110. }
  1111. return 'el-icon-cpu';
  1112. },
  1113. // 装备状态文本转换
  1114. equipmentStatusText(status) {
  1115. const statusMap = {
  1116. 'ready': '就绪',
  1117. 'standby': '待命',
  1118. 'maintenance': '维护中'
  1119. };
  1120. return statusMap[status] || status;
  1121. },
  1122. // 装备状态标签样式
  1123. statusLabelClass(status) {
  1124. const classMap = {
  1125. 'ready': 'text-green-400 bg-green-900/30 px-1.5 py-0 rounded text-xs',
  1126. 'standby': 'text-yellow-400 bg-yellow-900/30 px-1.5 py-0 rounded text-xs',
  1127. 'maintenance': 'text-red-400 bg-red-900/30 px-1.5 py-0 rounded text-xs'
  1128. };
  1129. return classMap[status] || '';
  1130. },
  1131. // 更新时间显示
  1132. updateTime() {
  1133. const now = new Date();
  1134. this.天文时间 = now.toLocaleString('zh-CN', {
  1135. year: 'numeric',
  1136. month: '2-digit',
  1137. day: '2-digit',
  1138. hour: '2-digit',
  1139. minute: '2-digit',
  1140. second: '2-digit',
  1141. hour12: false
  1142. }).replace(/\//g, '-');
  1143. // 模拟绝对时间
  1144. const epoch = new Date('2000-01-01T00:00:00Z');
  1145. const diff = Math.floor((now - epoch) / 1000);
  1146. this.绝对时间 = `J${diff}`;
  1147. }
  1148. },
  1149. watch: {
  1150. // 监听导弹类型变化,更新靶标设置
  1151. 'taskForm.missileType': function() {
  1152. this.updateTargetsByMissileType();
  1153. }
  1154. },
  1155. mounted() {
  1156. // 初始化时间
  1157. this.updateTime();
  1158. // 每秒更新时间
  1159. setInterval(this.updateTime, 1000);
  1160. }
  1161. }
  1162. </script>
  1163. <style lang="scss" scoped>
  1164. /* 军事风格大屏基础样式 - 深色背景,高对比度 */
  1165. .task-setting-container {
  1166. display: flex;
  1167. flex-direction: column;
  1168. height: 100vh;
  1169. background-color: #050c1a; /* 深色军事背景 */
  1170. color: #e0f2fe; /* 主文本色 - 浅蓝色 */
  1171. font-family: "Microsoft YaHei", Arial, sans-serif;
  1172. position: relative;
  1173. overflow: hidden;
  1174. }
  1175. /* 军事网格背景 */
  1176. .grid-bg {
  1177. position: absolute;
  1178. top: 0;
  1179. left: 0;
  1180. width: 100%;
  1181. height: 100%;
  1182. background-size: 40px 40px;
  1183. background-image:
  1184. linear-gradient(to right, rgba(14, 55, 107, 0.1) 1px, transparent 1px),
  1185. linear-gradient(to bottom, rgba(14, 55, 107, 0.1) 1px, transparent 1px);
  1186. pointer-events: none;
  1187. z-index: 0;
  1188. }
  1189. /* 头部样式:军事风格 - 庄重威严 */
  1190. .header {
  1191. flex: 0 0 60px;
  1192. background-color: #0f172a; /* 头部深色背景 */
  1193. background-image: linear-gradient(to right, #0f172a, #1e3a8a);
  1194. display: flex;
  1195. align-items: center;
  1196. padding: 0 20px;
  1197. justify-content: space-between;
  1198. border-bottom: 1px solid #0ea5e9;
  1199. box-shadow: 0 2px 10px rgba(14, 165, 233, 0.2);
  1200. position: relative;
  1201. z-index: 10;
  1202. .header-logo {
  1203. display: flex;
  1204. align-items: center;
  1205. h1 {
  1206. font-size: 1.5rem;
  1207. color: #bae6fd;
  1208. margin: 0;
  1209. white-space: nowrap;
  1210. text-shadow: 0 0 5px rgba(14, 165, 233, 0.5);
  1211. }
  1212. }
  1213. .header-time {
  1214. display: flex;
  1215. gap: 20px;
  1216. color: #93c5fd;
  1217. font-size: 14px;
  1218. .time-item {
  1219. padding: 5px 10px;
  1220. background-color: rgba(15, 23, 42, 0.7);
  1221. border: 1px solid rgba(14, 165, 233, 0.3);
  1222. border-radius: 3px;
  1223. }
  1224. }
  1225. .header-controls {
  1226. display: flex;
  1227. gap: 15px;
  1228. }
  1229. }
  1230. /* 军事风格按钮 */
  1231. .btn军事 {
  1232. position: relative;
  1233. overflow: hidden;
  1234. transition: all 0.3s ease;
  1235. border: 1px solid rgba(14, 165, 233, 0.5) !important;
  1236. box-shadow: 0 0 5px rgba(14, 165, 233, 0.3);
  1237. &:after {
  1238. content: '';
  1239. position: absolute;
  1240. top: 0;
  1241. left: -100%;
  1242. width: 100%;
  1243. height: 100%;
  1244. background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
  1245. transition: all 0.5s ease;
  1246. }
  1247. &:hover:after {
  1248. left: 100%;
  1249. }
  1250. }
  1251. /* 侧边栏装饰线 */
  1252. .aside-border-decoration {
  1253. position: absolute;
  1254. top: 0;
  1255. right: 0;
  1256. width: 3px;
  1257. height: 100%;
  1258. background: linear-gradient(to bottom,
  1259. rgba(14, 165, 233, 0) 0%,
  1260. rgba(14, 165, 233, 0.5) 50%,
  1261. rgba(14, 165, 233, 0) 100%);
  1262. z-index: 1;
  1263. }
  1264. /* 主区域装饰线 */
  1265. .main-border-decoration {
  1266. position: absolute;
  1267. top: 0;
  1268. left: 0;
  1269. width: 3px;
  1270. height: 100%;
  1271. background: linear-gradient(to bottom,
  1272. rgba(14, 165, 233, 0) 0%,
  1273. rgba(14, 165, 233, 0.5) 50%,
  1274. rgba(14, 165, 233, 0) 100%);
  1275. z-index: 1;
  1276. }
  1277. /* 左侧任务面板:军事风格分区明确 */
  1278. .task-panel {
  1279. width: 100%;
  1280. background-color: rgba(15, 23, 42, 0.8);
  1281. backdrop-filter: blur(5px);
  1282. display: flex;
  1283. flex-direction: column;
  1284. min-width: 0;
  1285. overflow: hidden;
  1286. border-right: 1px solid rgba(14, 165, 233, 0.2);
  1287. .panel-header {
  1288. padding: 12px 15px;
  1289. border-bottom: 1px solid rgba(14, 165, 233, 0.3);
  1290. flex-shrink: 0;
  1291. background-color: rgba(30, 58, 138, 0.6);
  1292. background-image: linear-gradient(to right, rgba(30, 58, 138, 0.8), rgba(15, 23, 42, 0.8));
  1293. h3 {
  1294. color: #bae6fd;
  1295. font-size: 1rem;
  1296. margin: 0;
  1297. font-weight: 500;
  1298. display: flex;
  1299. align-items: center;
  1300. }
  1301. }
  1302. .task-content {
  1303. flex: 1;
  1304. overflow-y: auto;
  1305. padding: 15px;
  1306. min-height: 0;
  1307. &::-webkit-scrollbar {
  1308. width: 6px;
  1309. height: 6px;
  1310. }
  1311. &::-webkit-scrollbar-track {
  1312. background: rgba(15, 23, 42, 0.5);
  1313. }
  1314. &::-webkit-scrollbar-thumb {
  1315. background-color: rgba(59, 130, 246, 0.5);
  1316. border-radius: 3px;
  1317. }
  1318. }
  1319. }
  1320. /* 中间装备配置区域 */
  1321. .equipment-content-box {
  1322. background-color: rgba(5, 12, 26, 0.9);
  1323. min-height: 0;
  1324. &::-webkit-scrollbar {
  1325. width: 6px;
  1326. height: 6px;
  1327. }
  1328. &::-webkit-scrollbar-track {
  1329. background: rgba(15, 23, 42, 0.5);
  1330. }
  1331. &::-webkit-scrollbar-thumb {
  1332. background-color: rgba(59, 130, 246, 0.5);
  1333. border-radius: 3px;
  1334. }
  1335. }
  1336. .equipment-config-container {
  1337. height: calc(100% - 40px);
  1338. }
  1339. .equipment-tree-container {
  1340. height: 100%;
  1341. }
  1342. .equipment-details-container {
  1343. height: 100%;
  1344. }
  1345. .equipment-status-grid {
  1346. display: grid;
  1347. grid-template-columns: repeat(4, 1fr);
  1348. gap: 10px;
  1349. }
  1350. .status-card {
  1351. background-color: rgba(15, 23, 42, 0.6);
  1352. border-radius: 3px;
  1353. transition: all 0.2s;
  1354. &:hover {
  1355. transform: translateY(-2px);
  1356. box-shadow: 0 3px 10px rgba(14, 165, 233, 0.1);
  1357. }
  1358. .status-title {
  1359. color: #94a3b8;
  1360. }
  1361. .status-value {
  1362. color: #60a5fa;
  1363. text-shadow: 0 0 3px rgba(59, 130, 246, 0.2);
  1364. }
  1365. }
  1366. /* 树形结构样式 */
  1367. .equipment-tree {
  1368. max-height: calc(100% - 20px);
  1369. overflow-y: auto;
  1370. &::-webkit-scrollbar {
  1371. width: 6px;
  1372. height: 6px;
  1373. }
  1374. &::-webkit-scrollbar-track {
  1375. background: rgba(15, 23, 42, 0.5);
  1376. }
  1377. &::-webkit-scrollbar-thumb {
  1378. background-color: rgba(59, 130, 246, 0.5);
  1379. border-radius: 3px;
  1380. }
  1381. }
  1382. .custom-tree-node {
  1383. width: 100%;
  1384. display: inline-block;
  1385. }
  1386. .tree-node-content {
  1387. width: 100%;
  1388. padding: 2px 0;
  1389. color: #e0f2fe;
  1390. &:hover {
  1391. color: #60a5fa;
  1392. }
  1393. }
  1394. /* 右侧预览面板:军事风格数据突出 */
  1395. .preview-panel {
  1396. width: 100%;
  1397. background-color: rgba(15, 23, 42, 0.8);
  1398. backdrop-filter: blur(5px);
  1399. display: flex;
  1400. flex-direction: column;
  1401. min-width: 0;
  1402. overflow: hidden;
  1403. border-left: 1px solid rgba(14, 165, 233, 0.2);
  1404. .panel-header {
  1405. padding: 12px 15px;
  1406. border-bottom: 1px solid rgba(14, 165, 233, 0.3);
  1407. flex-shrink: 0;
  1408. background-color: rgba(30, 58, 138, 0.6);
  1409. background-image: linear-gradient(to right, rgba(30, 58, 138, 0.8), rgba(15, 23, 42, 0.8));
  1410. }
  1411. .preview-content {
  1412. flex: 1;
  1413. overflow-y: auto;
  1414. min-height: 0;
  1415. &::-webkit-scrollbar {
  1416. width: 6px;
  1417. height: 6px;
  1418. }
  1419. &::-webkit-scrollbar-track {
  1420. background: rgba(15, 23, 42, 0.5);
  1421. }
  1422. &::-webkit-scrollbar-thumb {
  1423. background-color: rgba(59, 130, 246, 0.5);
  1424. border-radius: 3px;
  1425. }
  1426. }
  1427. }
  1428. /* 通用模块样式:军事风格简洁 */
  1429. .section-card {
  1430. background-color: rgba(15, 23, 42, 0.7);
  1431. border-radius: 4px;
  1432. overflow: hidden;
  1433. border: 1px solid rgba(14, 165, 233, 0.3);
  1434. box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
  1435. transition: all 0.3s ease;
  1436. &:hover {
  1437. box-shadow: 0 3px 15px rgba(14, 165, 233, 0.2);
  1438. border-color: rgba(14, 165, 233, 0.5);
  1439. }
  1440. }
  1441. .section-header {
  1442. background-color: rgba(30, 58, 138, 0.5);
  1443. padding: 8px 15px;
  1444. display: flex;
  1445. justify-content: space-between;
  1446. align-items: center;
  1447. border-bottom: 1px solid rgba(14, 165, 233, 0.2);
  1448. .section-title {
  1449. color: #bae6fd;
  1450. font-size: 14px;
  1451. margin: 0;
  1452. font-weight: 500;
  1453. display: flex;
  1454. align-items: center;
  1455. }
  1456. }
  1457. /* 表单样式:军事风格简洁易读 */
  1458. .el-input__inner,
  1459. .el-textarea__inner,
  1460. .el-select .el-input__inner {
  1461. background-color: rgba(15, 23, 42, 0.8);
  1462. border: 1px solid rgba(14, 165, 233, 0.3);
  1463. color: #e0f2fe;
  1464. width: 100%;
  1465. border-radius: 3px;
  1466. height: 32px;
  1467. font-size: 14px;
  1468. &:focus {
  1469. border-color: #3b82f6;
  1470. box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
  1471. }
  1472. &::placeholder {
  1473. color: #64748b;
  1474. }
  1475. &:disabled {
  1476. background-color: rgba(15, 23, 42, 0.5);
  1477. color: #94a3b8;
  1478. cursor: not-allowed;
  1479. }
  1480. }
  1481. .el-textarea__inner {
  1482. min-height: 80px !important;
  1483. height: auto;
  1484. resize: vertical;
  1485. }
  1486. /* 下拉框样式:军事风格简洁 */
  1487. ::v-deep .el-select-dropdown {
  1488. background-color: rgba(15, 23, 42, 0.95);
  1489. border: 1px solid rgba(14, 165, 233, 0.3);
  1490. border-radius: 3px;
  1491. box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
  1492. .el-select-dropdown__item {
  1493. color: #e0f2fe;
  1494. padding: 8px 16px;
  1495. font-size: 14px;
  1496. &:hover {
  1497. background-color: rgba(30, 58, 138, 0.5);
  1498. }
  1499. &.selected {
  1500. background-color: rgba(59, 130, 246, 0.5);
  1501. color: white;
  1502. }
  1503. }
  1504. }
  1505. /* 输入框数字控件样式:军事风格简洁 */
  1506. ::v-deep .el-input-number {
  1507. .el-input-number__decrease,
  1508. .el-input-number__increase {
  1509. background-color: rgba(30, 58, 138, 0.5);
  1510. border-color: rgba(14, 165, 233, 0.3);
  1511. color: #e0f2fe;
  1512. width: 30px;
  1513. height: 30px;
  1514. line-height: 30px;
  1515. &:hover {
  1516. background-color: rgba(30, 58, 138, 0.8);
  1517. color: white;
  1518. }
  1519. &:disabled {
  1520. background-color: rgba(15, 23, 42, 0.5);
  1521. color: #94a3b8;
  1522. cursor: not-allowed;
  1523. }
  1524. }
  1525. }
  1526. /* 靶标项样式:军事风格清晰 */
  1527. .target-item {
  1528. background-color: rgba(15, 23, 42, 0.6);
  1529. border: 1px solid rgba(14, 165, 233, 0.2);
  1530. border-radius: 3px;
  1531. transition: all 0.2s;
  1532. &:hover {
  1533. border-color: rgba(14, 165, 233, 0.5);
  1534. background-color: rgba(15, 23, 42, 0.8);
  1535. }
  1536. .target-name {
  1537. color: #bae6fd;
  1538. }
  1539. .target-type {
  1540. color: #60a5fa;
  1541. }
  1542. .target-coord {
  1543. color: #94a3b8;
  1544. }
  1545. .target-threat {
  1546. color: #94a3b8;
  1547. .threat-bars {
  1548. height: 6px;
  1549. }
  1550. .threat-bar {
  1551. width: 6px;
  1552. height: 100%;
  1553. background-color: rgba(100, 116, 139, 0.3);
  1554. border-radius: 1px;
  1555. &.active {
  1556. background-color: #f97316;
  1557. }
  1558. }
  1559. }
  1560. .target-equipment {
  1561. margin-top: 4px;
  1562. padding-top: 4px;
  1563. border-top: 1px dashed rgba(14, 165, 233, 0.2);
  1564. }
  1565. }
  1566. .target-hint {
  1567. padding: 4px 6px;
  1568. border-radius: 3px;
  1569. background-color: rgba(15, 23, 42, 0.5);
  1570. border: 1px solid rgba(234, 179, 8, 0.3);
  1571. }
  1572. /* 装备详情样式 */
  1573. .equipment-detail {
  1574. background-color: rgba(15, 23, 42, 0.5);
  1575. border-radius: 3px;
  1576. }
  1577. .detail-item {
  1578. margin-bottom: 12px;
  1579. .detail-label {
  1580. color: #94a3b8;
  1581. margin-bottom: 4px;
  1582. }
  1583. .detail-value {
  1584. color: #e0f2fe;
  1585. }
  1586. }
  1587. /* 靶标-装备分配关系表格样式 */
  1588. ::v-deep .el-table {
  1589. background-color: transparent;
  1590. color: #e0f2fe;
  1591. .el-table__empty-text {
  1592. color: #94a3b8;
  1593. }
  1594. .el-table__row:hover > td {
  1595. background-color: rgba(30, 58, 138, 0.2);
  1596. }
  1597. }
  1598. /* 任务概览样式:紧凑布局 */
  1599. .preview-section {
  1600. background-color: rgba(15, 23, 42, 0.7);
  1601. border: 1px solid rgba(14, 165, 233, 0.3);
  1602. border-radius: 3px;
  1603. overflow: hidden;
  1604. transition: all 0.3s;
  1605. &:hover {
  1606. box-shadow: 0 3px 15px rgba(14, 165, 233, 0.1);
  1607. }
  1608. }
  1609. .preview-section h4 {
  1610. color: #bae6fd;
  1611. border-bottom-color: rgba(14, 165, 233, 0.2);
  1612. display: flex;
  1613. align-items: center;
  1614. }
  1615. .overview-stats {
  1616. display: flex;
  1617. flex-direction: column;
  1618. gap: 5px;
  1619. }
  1620. .stat-row-compact {
  1621. display: flex;
  1622. justify-content: space-between;
  1623. align-items: center;
  1624. }
  1625. .stat-label-compact {
  1626. color: #94a3b8;
  1627. }
  1628. .stat-value-compact {
  1629. color: #60a5fa;
  1630. }
  1631. /* 时间轴样式:紧凑布局 */
  1632. .timeline-container {
  1633. padding-left: 10px;
  1634. }
  1635. .timeline-line {
  1636. background-color: rgba(14, 165, 233, 0.3);
  1637. left: 8px;
  1638. }
  1639. .timeline-item-compact {
  1640. position: relative;
  1641. transition: all 0.3s;
  1642. padding-bottom: 5px;
  1643. &:hover {
  1644. transform: translateX(3px);
  1645. }
  1646. }
  1647. .timeline-content-compact {
  1648. background-color: rgba(15, 23, 42, 0.6);
  1649. border: 1px solid rgba(14, 165, 233, 0.2);
  1650. border-radius: 3px;
  1651. padding: 3px 5px;
  1652. }
  1653. .timeline-time {
  1654. color: #60a5fa;
  1655. }
  1656. .timeline-title {
  1657. color: #bae6fd;
  1658. }
  1659. .timeline-description {
  1660. color: #94a3b8;
  1661. line-height: 1.5;
  1662. }
  1663. .timeline-dot {
  1664. box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.8);
  1665. }
  1666. /* 对话框样式:军事风格适配 */
  1667. ::v-deep .target-dialog, ::v-deep .equipment-dialog {
  1668. .el-dialog {
  1669. background-color: rgba(15, 23, 42, 0.95);
  1670. border: 1px solid rgba(14, 165, 233, 0.3);
  1671. border-radius: 4px;
  1672. box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  1673. }
  1674. .el-dialog__header {
  1675. background-color: rgba(30, 58, 138, 0.6);
  1676. border-bottom: 1px solid rgba(14, 165, 233, 0.3);
  1677. .el-dialog__title {
  1678. color: #bae6fd;
  1679. }
  1680. }
  1681. .el-dialog__body {
  1682. background-color: rgba(15, 23, 42, 0.95);
  1683. color: #e0f2fe;
  1684. }
  1685. .el-dialog__footer {
  1686. background-color: rgba(15, 23, 42, 0.95);
  1687. border-top: 1px solid rgba(14, 165, 233, 0.3);
  1688. }
  1689. }
  1690. /* 按钮样式优化:军事风格突出 */
  1691. ::v-deep .el-button {
  1692. border-radius: 3px;
  1693. border: none;
  1694. &.el-button--primary {
  1695. background-color: #1e40af;
  1696. color: white;
  1697. &:hover {
  1698. background-color: #3b82f6;
  1699. }
  1700. }
  1701. &.el-button--success {
  1702. background-color: #065f46;
  1703. color: white;
  1704. &:hover {
  1705. background-color: #16a34a;
  1706. }
  1707. }
  1708. &.el-button--warning {
  1709. background-color: #92400e;
  1710. color: white;
  1711. &:hover {
  1712. background-color: #d97706;
  1713. }
  1714. }
  1715. &.el-button--text {
  1716. color: #94a3b8;
  1717. &:hover {
  1718. color: #bae6fd;
  1719. background-color: rgba(148, 163, 184, 0.1);
  1720. }
  1721. }
  1722. }
  1723. /* 滑块样式:军事风格适配 */
  1724. ::v-deep .el-slider {
  1725. .el-slider__runway {
  1726. background-color: rgba(51, 65, 85, 0.5);
  1727. }
  1728. .el-slider__bar {
  1729. background-color: #3b82f6;
  1730. }
  1731. .el-slider__button {
  1732. border-color: #3b82f6;
  1733. }
  1734. }
  1735. /* 消息提示样式:军事风格适配 */
  1736. ::v-deep .el-message {
  1737. background-color: rgba(30, 58, 138, 0.8);
  1738. border-color: rgba(14, 165, 233, 0.3);
  1739. color: #e0f2fe;
  1740. }
  1741. /* 确认框样式:军事风格适配 */
  1742. ::v-deep .el-dialog--confirm {
  1743. .el-dialog__body {
  1744. color: #e0f2fe;
  1745. }
  1746. }
  1747. /* 全局容器背景色确认 */
  1748. ::v-deep .el-container {
  1749. background: transparent;
  1750. }
  1751. /* 树形控件样式适配 */
  1752. ::v-deep .el-tree {
  1753. background-color: transparent;
  1754. .el-tree-node__content {
  1755. color: #e0f2fe;
  1756. height: 32px;
  1757. &:hover {
  1758. background-color: rgba(30, 58, 138, 0.3);
  1759. }
  1760. }
  1761. .el-tree-node.is-current > .el-tree-node__content {
  1762. background-color: rgba(59, 130, 246, 0.2);
  1763. color: #60a5fa;
  1764. }
  1765. .el-tree-node__expand-icon {
  1766. color: #94a3b8;
  1767. &:hover {
  1768. color: #60a5fa;
  1769. }
  1770. }
  1771. }
  1772. /* 大屏响应式优化 */
  1773. @media (max-width: 1600px) {
  1774. .equipment-config-container {
  1775. grid-template-columns: 1fr 2fr;
  1776. }
  1777. }
  1778. @media (max-width: 1200px) {
  1779. .equipment-config-container {
  1780. grid-template-columns: 1fr;
  1781. }
  1782. .equipment-status-grid {
  1783. grid-template-columns: repeat(2, 1fr);
  1784. }
  1785. }
  1786. </style>