|
|
@@ -1,26 +1,26 @@
|
|
|
<template>
|
|
|
<el-card class="ui-card fill-card" shadow="hover">
|
|
|
- <div slot="header" class="card-header">
|
|
|
- <div class="title-left">
|
|
|
- <i class="fa fa-crosshairs icon-primary"></i><span>试验任务规划(导弹打击目标与弹道)</span>
|
|
|
- </div>
|
|
|
- <div class="title-right">
|
|
|
- <el-form inline size="small">
|
|
|
- <el-form-item label="方案名称">
|
|
|
- <el-input v-model="scenarioNameLocal" disabled style="width:220px;"/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="导弹数量">
|
|
|
- <el-input-number v-model="missileCountLocal" :max="20" :min="1" :step="1" disabled/>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="想定版本">
|
|
|
- <el-input v-model="scenarioVersionLocal" style="width:120px;"/>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <!--<div slot="header" class="card-header">-->
|
|
|
+ <!-- <div class="title-left">-->
|
|
|
+ <!-- <i class="fa fa-crosshairs icon-primary"></i><span>试验任务规划(导弹打击目标与弹道)</span>-->
|
|
|
+ <!-- </div>-->
|
|
|
+ <!-- <div class="title-right">-->
|
|
|
+ <!-- <el-form inline size="small">-->
|
|
|
+ <!-- <el-form-item label="方案名称">-->
|
|
|
+ <!-- <el-input v-model="scenarioNameLocal" disabled style="width:220px;"/>-->
|
|
|
+ <!-- </el-form-item>-->
|
|
|
+ <!-- <el-form-item label="导弹数量">-->
|
|
|
+ <!-- <el-input-number v-model="missileCountLocal" :max="20" :min="1" :step="1" disabled/>-->
|
|
|
+ <!-- </el-form-item>-->
|
|
|
+ <!-- <el-form-item label="想定版本">-->
|
|
|
+ <!-- <el-input v-model="scenarioVersionLocal" style="width:120px;"/>-->
|
|
|
+ <!-- </el-form-item>-->
|
|
|
+ <!-- </el-form>-->
|
|
|
+ <!-- </div>-->
|
|
|
+ <!--</div>-->
|
|
|
|
|
|
<div class="fill-scroll">
|
|
|
- <el-alert :closable="false" class="mb-16" show-icon title="依次配置每枚导弹的打击目标与弹道参数" type="info"/>
|
|
|
+ <el-alert :closable="false" class="mb-16" show-icon title="每枚导弹的打击目标与弹道参数" type="info"/>
|
|
|
<el-collapse v-model="openPanels">
|
|
|
<el-collapse-item
|
|
|
v-for="(m,idx) in missilesLocal"
|
|
|
@@ -29,7 +29,7 @@
|
|
|
:title="`导弹 #${idx+1}`"
|
|
|
>
|
|
|
<MissileMissionCard
|
|
|
- :missile.sync="missilesLocal[idx]"
|
|
|
+ :missile="missilesLocal[idx]"
|
|
|
@import-trajectory="$emit('import-trajectory', $event)"
|
|
|
@preview-trajectory="$emit('preview-trajectory', $event)"
|
|
|
/>
|
|
|
@@ -52,8 +52,14 @@
|
|
|
style="width: 220px;"
|
|
|
/>
|
|
|
<div style="flex:1"></div>
|
|
|
- <el-button type="text" class="gc-op" @click="clearAllFaults">
|
|
|
- <i class="el-icon-circle-close"></i> 清空模拟
|
|
|
+ <!--<el-button type="text" class="gc-op" @click="clearAllFaults">-->
|
|
|
+ <!-- <i class="el-icon-circle-close"></i> 清空模拟-->
|
|
|
+ <!--</el-button>-->
|
|
|
+ <el-button
|
|
|
+ class="blue_btn"
|
|
|
+ style="margin-right: 4px"
|
|
|
+ @click="addFault(row)"
|
|
|
+ >新增
|
|
|
</el-button>
|
|
|
</div>
|
|
|
|
|
|
@@ -68,63 +74,125 @@
|
|
|
row-key="id"
|
|
|
>
|
|
|
<el-table-column type="index" label="#" width="48" align="center"/>
|
|
|
- <el-table-column prop="name" label="故障名称" min-width="160" show-overflow-tooltip/>
|
|
|
- <el-table-column prop="targetName" label="目标设备" min-width="160" show-overflow-tooltip/>
|
|
|
- <!-- <el-table-column prop="severity" label="级别" width="80" align="center">-->
|
|
|
- <!-- <template slot-scope="{ row }">-->
|
|
|
- <!-- <span class="fault-badge" :class="'sev-'+row.severity">{{ row.severity }}</span>-->
|
|
|
- <!-- </template>-->
|
|
|
- <!-- </el-table-column>-->
|
|
|
- <el-table-column label="操作" width="160" align="center" fixed="right">
|
|
|
+ <el-table-column prop="faultName" label="故障名称" min-width="160" show-overflow-tooltip/>
|
|
|
+ <el-table-column prop="zbName" label="目标设备" min-width="160" show-overflow-tooltip/>
|
|
|
+ <el-table-column prop="executeTheScript" label="执行脚本" min-width="160" show-overflow-tooltip>
|
|
|
+
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="250" align="center" fixed="right">
|
|
|
<template slot-scope="{ row }">
|
|
|
<el-button
|
|
|
size="mini"
|
|
|
type="primary"
|
|
|
- style="padding: 2px 6px; margin-right: 4px"
|
|
|
- :disabled="activeFaultIds.has(row.id)"
|
|
|
- @click="triggerFault(row)"
|
|
|
- >触发
|
|
|
+ style="margin-right: 4px"
|
|
|
+ @click="jsonEdit(row)"
|
|
|
+ >JSON编辑器
|
|
|
</el-button>
|
|
|
<el-button
|
|
|
- size="mini"
|
|
|
- :disabled="!activeFaultIds.has(row.id)"
|
|
|
- style="padding: 2px 6px"
|
|
|
- @click="restoreFault(row.id)"
|
|
|
- >恢复
|
|
|
+ size="mini"
|
|
|
+ type="danger"
|
|
|
+ style="margin-right: 4px"
|
|
|
+ @click="deleteFault(row)"
|
|
|
+ >删除
|
|
|
</el-button>
|
|
|
+ <!--<el-button-->
|
|
|
+ <!-- size="mini"-->
|
|
|
+ <!-- type="primary"-->
|
|
|
+ <!-- style="padding: 2px 6px; margin-right: 4px"-->
|
|
|
+ <!-- :disabled="activeFaultIds.has(row.id)"-->
|
|
|
+ <!-- @click="triggerFault(row)"-->
|
|
|
+ <!-->触发-->
|
|
|
+ <!--</el-button>-->
|
|
|
+ <!--<el-button-->
|
|
|
+ <!-- size="mini"-->
|
|
|
+ <!-- :disabled="!activeFaultIds.has(row.id)"-->
|
|
|
+ <!-- style="padding: 2px 6px"-->
|
|
|
+ <!-- @click="restoreFault(row.id)"-->
|
|
|
+ <!-->恢复-->
|
|
|
+ <!--</el-button>-->
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
<!-- 快速添加 -->
|
|
|
- <div class="fault-quick-add"
|
|
|
- style="margin-top:10px; display:grid; grid-template-columns:1.2fr 1.4fr .9fr auto; gap:8px;">
|
|
|
- <el-input v-model="quickFault.name" size="mini" placeholder="自定义故障名,如:相机离线"/>
|
|
|
- <el-select v-model="quickFault.targetUnitId" size="mini" placeholder="选择目标设备">
|
|
|
- <el-option
|
|
|
- v-for="u in units"
|
|
|
- :key="'opt-'+u.id"
|
|
|
- :label="u.name"
|
|
|
- :value="u.id"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- <!-- <el-select v-model="quickFault.severity" size="mini" placeholder="级别">-->
|
|
|
- <!-- <el-option label="warning" value="warning" />-->
|
|
|
- <!-- <el-option label="critical" value="critical" />-->
|
|
|
- <!-- </el-select>-->
|
|
|
- <el-button size="mini" type="success" @click="addQuickFault">添加并触发</el-button>
|
|
|
- </div>
|
|
|
+ <!--<div class="fault-quick-add"-->
|
|
|
+ <!-- style="margin-top:10px; display:grid; grid-template-columns:1.2fr 1.4fr .9fr auto; gap:8px;">-->
|
|
|
+ <!-- <el-input v-model="quickFault.name" size="mini" placeholder="自定义故障名,如:相机离线"/>-->
|
|
|
+ <!-- <el-select v-model="quickFault.targetUnitId" size="mini" placeholder="选择目标设备">-->
|
|
|
+ <!-- <el-option-->
|
|
|
+ <!-- v-for="u in units"-->
|
|
|
+ <!-- :key="'opt-'+u.id"-->
|
|
|
+ <!-- :label="u.name"-->
|
|
|
+ <!-- :value="u.id"-->
|
|
|
+ <!-- />-->
|
|
|
+ <!-- </el-select>-->
|
|
|
+ <!-- <!– <el-select v-model="quickFault.severity" size="mini" placeholder="级别">–>-->
|
|
|
+ <!-- <!– <el-option label="warning" value="warning" />–>-->
|
|
|
+ <!-- <!– <el-option label="critical" value="critical" />–>-->
|
|
|
+ <!-- <!– </el-select>–>-->
|
|
|
+ <!-- <el-button size="mini" type="success" @click="addQuickFault">添加并触发</el-button>-->
|
|
|
+ <!--</div>-->
|
|
|
</el-card>
|
|
|
+ <el-dialog :title="dialogTitle" :visible.sync="showFaultEdit" width="40%">
|
|
|
+ <el-form ref="faultForm"
|
|
|
+ :rule="rules" :model="faultForm" label-width="120px">
|
|
|
+ <!-- 故障名称 -->
|
|
|
+ <el-form-item label="故障名称">
|
|
|
+ <el-input v-model="faultForm.faultName" placeholder="请输入故障名称" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="目标设备">
|
|
|
+ <el-cascader
|
|
|
+ v-model="faultForm.schemeEquId"
|
|
|
+ :options="cascaderOptions"
|
|
|
+ :props="{ emitPath: false, checkStrictly: true, expandTrigger: 'hover' }"
|
|
|
+ placeholder="请选择设备"
|
|
|
+ clearable
|
|
|
+ style="width: 300px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 执行脚本(JSON 格式) -->
|
|
|
+ <el-form-item label="执行脚本">
|
|
|
+ <!--<JsonEditor :value="faultForm.executeTheScript"></JsonEditor>-->
|
|
|
+ <el-input
|
|
|
+ v-model="faultForm.executeTheScript"
|
|
|
+ type="textarea"
|
|
|
+ :rows="6"
|
|
|
+ placeholder='请输入 JSON 格式脚本,例如:{"cmd": "reboot", "timeout": 30}'
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="submitForm">提交</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <el-dialog title="JSON编辑器" :visible.sync="showJsonEditor" width="40%">
|
|
|
+ <JsonEditor ref="JsonEditor" :value="scriptJson"></JsonEditor>
|
|
|
+ <el-button type="primary" @click="updeteJson">提交</el-button>
|
|
|
+ </el-dialog>
|
|
|
</el-card>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import MissileMissionCard from './MissileMissionCard.vue';
|
|
|
+import {missileList} from "@/api/taskMage/taskMage";
|
|
|
+import JsonEditor from "@/components/JsonEditor/index.vue";
|
|
|
+import {
|
|
|
+ battlefieldEnvironmentInsert,
|
|
|
+ faultsimulationDelete,
|
|
|
+ faultsimulationInsert, faultsimulationUpdate,
|
|
|
+ findPageWrapper, getEquTree
|
|
|
+} from "@/api/faultSimulation";
|
|
|
|
|
|
export default {
|
|
|
name: 'MissileMissionPanel',
|
|
|
- components: {MissileMissionCard},
|
|
|
+ components: {MissileMissionCard,JsonEditor},
|
|
|
props: {
|
|
|
+ planId:{type: String, default: ''},
|
|
|
+ taskId:{type: String, default: ''},
|
|
|
+ subTaskId:{type: String, default: ''},
|
|
|
missiles: {type: Array, required: true},
|
|
|
openMissilePanels: {type: Array, default: () => []},
|
|
|
scenarioName: {type: String, default: ''},
|
|
|
@@ -133,7 +201,7 @@ export default {
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
- missilesLocal: this.clone(this.missiles),
|
|
|
+ missilesLocal: [],
|
|
|
openPanels: [...this.openMissilePanels],
|
|
|
scenarioNameLocal: this.scenarioName,
|
|
|
scenarioVersionLocal: this.scenarioVersion,
|
|
|
@@ -332,20 +400,34 @@ export default {
|
|
|
],
|
|
|
/* ===== 故障模拟:新增字段 ===== */
|
|
|
faultQuery: '',
|
|
|
- faultScenarios: [
|
|
|
- {
|
|
|
- id: 'F001', name: '热像仪过载', targetUnitId: 'unit1', targetName: '中波红外热像仪-01', severity: 'critical',
|
|
|
- effect: {statusClass: 'inactive', overlay: 'ripple', blink: true, note: '温度异常,自动降载'}
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'F002', name: '可见光相机离线', targetUnitId: 'unit2', targetName: '可见光相机-03', severity: 'warning',
|
|
|
- effect: {statusClass: 'standby', overlay: 'beacon', blink: true, note: '网络抖动,断连重试中'}
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'F003', name: '指挥中心通信异常', targetUnitId: 'unit5', targetName: '指挥中心', severity: 'critical',
|
|
|
- effect: {statusClass: 'inactive', overlay: 'cross', blink: false, note: '主链路中断,切备链'}
|
|
|
- },
|
|
|
- ],
|
|
|
+ dialogTitle:'新增故障模拟',
|
|
|
+ showFaultEdit:false,
|
|
|
+ faultForm: {
|
|
|
+ faultName: '',
|
|
|
+ executeTheScript: '', // 前端保存为字符串
|
|
|
+ equipmentId:'1',
|
|
|
+ schemeEquId:'1',
|
|
|
+ },
|
|
|
+ equTree:[],
|
|
|
+ rules: {
|
|
|
+ faultName: [
|
|
|
+ { required: true, message: '请输入故障名称', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ schemeEquId: [
|
|
|
+ { required: true, message: '请选中设备', trigger: 'change' }
|
|
|
+ ],
|
|
|
+ executeTheScript: [
|
|
|
+ { required: true, message: '请输入执行脚本', trigger: 'blur' },
|
|
|
+ {
|
|
|
+ validator: this.validateJson,
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ showJsonEditor:false,
|
|
|
+ selectRow:null,
|
|
|
+ scriptJson:{},
|
|
|
+ faultScenarios: [],
|
|
|
activeFaultIds: new Set(),
|
|
|
_unitBackups: {},
|
|
|
faultOverlays: [],
|
|
|
@@ -359,15 +441,6 @@ export default {
|
|
|
this.missilesLocal = this.clone(v);
|
|
|
}
|
|
|
},
|
|
|
- missilesLocal: {
|
|
|
- deep: true,
|
|
|
- handler(v) {
|
|
|
- this.$emit('update:missiles', this.clone(v));
|
|
|
- }
|
|
|
- },
|
|
|
- openMissilePanels(v) {
|
|
|
- this.$emit('update:openMissilePanels', v);
|
|
|
- },
|
|
|
openMissilePanels: {
|
|
|
immediate: true,
|
|
|
handler(v) {
|
|
|
@@ -382,17 +455,59 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
computed:{
|
|
|
+ cascaderOptions() {
|
|
|
+ return this.equTree.map(group => ({
|
|
|
+ value: group.name,
|
|
|
+ label: group.name,
|
|
|
+ disabled: true,
|
|
|
+ children: group.equList?.map(item => ({
|
|
|
+ value: item.id,
|
|
|
+ label: item.name,
|
|
|
+ disabled: false
|
|
|
+ })) || []
|
|
|
+ }));
|
|
|
+ },
|
|
|
// 故障列表过滤
|
|
|
filteredFaults() {
|
|
|
const q = (this.faultQuery || '').trim().toLowerCase()
|
|
|
if (!q) return this.faultScenarios
|
|
|
return this.faultScenarios.filter(f =>
|
|
|
- String(f.name).toLowerCase().includes(q) ||
|
|
|
- String(f.targetName).toLowerCase().includes(q)
|
|
|
+ String(f.faultName).toLowerCase().includes(q) ||
|
|
|
+ String(f.schemeEquId).toLowerCase().includes(q)
|
|
|
)
|
|
|
}
|
|
|
},
|
|
|
+ mounted() {
|
|
|
+ this.fetchData()
|
|
|
+ },
|
|
|
methods: {
|
|
|
+ validateJson(rule, value, callback) {
|
|
|
+ if (!value) {
|
|
|
+ callback(); // 空值由 required 控制
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ JSON.parse(value);
|
|
|
+ callback(); // 合法 JSON
|
|
|
+ } catch (e) {
|
|
|
+ callback(new Error('执行脚本必须是有效的 JSON 格式'));
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fetchData(){
|
|
|
+ // 导弹列表
|
|
|
+ missileList({taskId:this.taskId,subTaskId:this.subTaskId}).then((res)=>{
|
|
|
+ this.missilesLocal = res.data
|
|
|
+ })
|
|
|
+ // 故障列表
|
|
|
+ findPageWrapper({simulationId:this.planId,pageNo:1,pageSize:9999}).then((res)=>{
|
|
|
+ this.faultScenarios = res.data.records
|
|
|
+ })
|
|
|
+ // 获取设备信息
|
|
|
+ getEquTree({subTaskId:this.subTaskId}).then((res)=>{
|
|
|
+ this.equTree = res.data
|
|
|
+ })
|
|
|
+ },
|
|
|
clone(o) {
|
|
|
return JSON.parse(JSON.stringify(o || {}));
|
|
|
},
|
|
|
@@ -402,6 +517,73 @@ export default {
|
|
|
this.$message.success('已清空所有故障模拟')
|
|
|
},
|
|
|
/* ===== 故障模拟:核心方法 ===== */
|
|
|
+ addFault(){
|
|
|
+
|
|
|
+ this.dialogTitle='新增故障模拟'
|
|
|
+ this.showFaultEdit = true
|
|
|
+ },
|
|
|
+ deleteFault(row){
|
|
|
+ this.$confirm(`确定要删除故障【${row.faultName}】吗?`, '删除确认', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ // 用户点击“确定”
|
|
|
+ faultsimulationDelete({id:row.id}).then(() => {
|
|
|
+ this.$message.success('删除成功');
|
|
|
+ findPageWrapper({simulationId:this.planId,pageNo:1,pageSize:9999}).then((res)=>{
|
|
|
+ this.faultScenarios = res.data.records
|
|
|
+ })
|
|
|
+ }).catch(() => {
|
|
|
+ this.$message.error('删除失败');
|
|
|
+ });
|
|
|
+ }).catch(() => {
|
|
|
+ // 用户点击“取消”或关闭弹窗
|
|
|
+ this.$message.info('已取消删除');
|
|
|
+ });
|
|
|
+ },
|
|
|
+ submitForm(){
|
|
|
+ this.$refs.faultForm.validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ // 提交到后端
|
|
|
+ faultsimulationInsert({simulationId:this.planId,...this.faultForm}).then(res => {
|
|
|
+ this.$message.success('提交成功');
|
|
|
+ findPageWrapper({simulationId:this.planId,pageNo:1,pageSize:9999}).then((res)=>{
|
|
|
+ this.faultScenarios = res.data.records
|
|
|
+ })
|
|
|
+ this.showFaultEdit = false
|
|
|
+ }).catch(err => {
|
|
|
+ this.$message.error('提交失败');
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.$message.warning('请完善表单信息');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ jsonEdit(row){
|
|
|
+ this.selectRow = row
|
|
|
+ this.scriptJson = JSON.parse(row.executeTheScript)
|
|
|
+ this.showJsonEditor = true
|
|
|
+ },
|
|
|
+ updeteJson(){
|
|
|
+ if(!this.$refs.JsonEditor.isJsonString(this.$refs.JsonEditor.getValue())){
|
|
|
+ this.$message.warning("JSON格式出错!")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ faultsimulationUpdate({id:this.selectRow.id,executeTheScript:this.$refs.JsonEditor.getValue()}).then((res)=>{
|
|
|
+ if(res.code === 0){
|
|
|
+ this.$message.success("修改成功")
|
|
|
+ findPageWrapper({simulationId:this.planId,pageNo:1,pageSize:9999}).then((res)=>{
|
|
|
+ this.faultScenarios = res.data.records
|
|
|
+ })
|
|
|
+ this.showJsonEditor = false
|
|
|
+ }else{
|
|
|
+ // this.$message.success("修改成功")
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
triggerFault(fault) {
|
|
|
const unit = this.units.find(u => u.id === fault.targetUnitId)
|
|
|
if (!unit) {
|
|
|
@@ -527,7 +709,9 @@ export default {
|
|
|
|
|
|
::v-deep .el-collapse-item__wrap {
|
|
|
background: transparent;
|
|
|
- border: none;
|
|
|
+ border: 1px solid rgba(255,255,255,.10);
|
|
|
+ border-top: none;
|
|
|
+ border-radius: 0px 0px 12px 12px;
|
|
|
margin-top: -1px;
|
|
|
}
|
|
|
|