Explorar o código

迁移新页面 , 噪声数据可视化 , 所有无人机轨迹

Rmengdi hai 1 semana
pai
achega
4c1d47f4f3
Modificáronse 2 ficheiros con 1815 adicións e 171 borrados
  1. 1462 69
      uavps-web/src/views/system/task/index.vue
  2. 353 102
      uavps-web/src/views/uavps/parameter/index.vue

+ 1462 - 69
uavps-web/src/views/system/task/index.vue

@@ -198,6 +198,14 @@
             @click="handleRun(scope.row)"
             >运行</el-button
           >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handlePlayback(scope.row)"
+            v-hasPermi="['uavps:parameter:run']"
+            >回放</el-button
+          >
           <el-button
             size="mini"
             type="text"
@@ -226,107 +234,473 @@
       @pagination="getList"
     />
 
-    <!-- 添加或修改任务数据对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="任务名称" prop="bizName">
-          <el-input v-model="form.bizName" placeholder="请输入任务名称" />
+    <!-- 添加或修改算法任务对话框 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="open"
+      width="75%"
+      :close-on-click-modal="false"
+      append-to-body
+      :before-close="cancel"
+    >
+      <el-form
+        ref="form"
+        :inline="true"
+        :model="form"
+        :rules="rules"
+        label-width="120px"
+      >
+        <el-row>
+          <el-form-item label="任务名称" prop="bizName">
+            <el-input v-model="form.bizName" placeholder="请输入任务名称" />
+          </el-form-item>
+          <el-form-item label="编队类型">
+            <el-select
+              v-model="form.multiTarget"
+              @change="typeChange"
+              placeholder="请选择"
+              :disabled="form.multiTarget == '1'"
+            >
+              <el-option
+                v-for="item in formationTypeList"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </el-row>
+        <el-row>
+          <el-form-item label="噪声类型">
+            <el-select v-model="form.noiseType" placeholder="请选择">
+              <el-option
+                v-for="item in noiseTypeList"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="噪声方差" prop="noiseVariance">
+            <el-input
+              v-model="form.noiseVariance"
+              placeholder="请输入噪声方差"
+            />
+          </el-form-item>
+          <el-form-item label="噪声均值" prop="noiseMean">
+            <el-input v-model="form.noiseMean" placeholder="请输入噪声均值" />
+          </el-form-item>
+        </el-row>
+
+        <el-divider content-position="left">平台无人机</el-divider>
+        <el-form-item label="经度" prop="platformUav.longitude">
+          <el-input
+            v-model="form.platformUav.longitude"
+            placeholder="请输入经度"
+          />
         </el-form-item>
-        <el-form-item label="多目标类型" prop="multiTarget">
-          <el-select v-model="form.multiTarget" placeholder="请选择多目标类型">
-            <el-option
-              v-for="dict in dict.type.uavps_target_formation_type"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            ></el-option>
-          </el-select>
+        <el-form-item label="纬度" prop="platformUav.latitude">
+          <el-input
+            v-model="form.platformUav.latitude"
+            placeholder="请输入纬度"
+          />
         </el-form-item>
-        <el-form-item label="噪声类型" prop="noiseType">
-          <el-select v-model="form.noiseType" placeholder="请选择噪声类型">
-            <el-option
-              v-for="dict in dict.type.uavps_task_nose_type"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            ></el-option>
-          </el-select>
+        <el-form-item label="海拔" prop="platformUav.altitude">
+          <el-input
+            v-model="form.platformUav.altitude"
+            placeholder="请输入海拔"
+          />
         </el-form-item>
-        <el-form-item label="噪声方差" prop="noiseVariance">
-          <el-input v-model="form.noiseVariance" placeholder="请输入噪声方差" />
+        <el-form-item label="东向速度" prop="platformUav.eastSpeed">
+          <el-input
+            v-model="form.platformUav.eastSpeed"
+            placeholder="请输入东向速度"
+          />
         </el-form-item>
-        <el-form-item label="噪声均值" prop="noiseMean">
-          <el-input v-model="form.noiseMean" placeholder="请输入噪声均值" />
+        <el-form-item label="北向速度" prop="platformUav.northSpeed">
+          <el-input
+            v-model="form.platformUav.northSpeed"
+            placeholder="请输入北向速度"
+          />
         </el-form-item>
+        <el-form-item label="天向速度" prop="platformUav.skySpeed">
+          <el-input
+            v-model="form.platformUav.skySpeed"
+            placeholder="请输入天向速度"
+          />
+        </el-form-item>
+
+        <div v-if="form.multiTarget == '1'">
+          <el-divider content-position="left">固定编队无人机</el-divider>
+          <el-form-item
+            label="飞机数量"
+            prop="fixedMultiTargetFormation.targetTotal"
+          >
+            <el-input-number
+              v-model="form.fixedMultiTargetFormation.targetTotal"
+              :min="1"
+              :max="50"
+              label="请输入飞机数量"
+            ></el-input-number>
+          </el-form-item>
+          <el-form-item label="经度" prop="fixedMultiTargetFormation.longitude">
+            <el-input
+              v-model="form.fixedMultiTargetFormation.longitude"
+              placeholder="请输入经度"
+            />
+          </el-form-item>
+          <el-form-item label="纬度" prop="fixedMultiTargetFormation.latitude">
+            <el-input
+              v-model="form.fixedMultiTargetFormation.latitude"
+              placeholder="请输入纬度"
+            />
+          </el-form-item>
+          <el-form-item label="海拔" prop="fixedMultiTargetFormation.altitude">
+            <el-input
+              v-model="form.fixedMultiTargetFormation.altitude"
+              placeholder="请输入海拔"
+            />
+          </el-form-item>
+          <el-form-item
+            label="东向速度"
+            prop="fixedMultiTargetFormation.eastSpeed"
+          >
+            <el-input
+              v-model="form.fixedMultiTargetFormation.eastSpeed"
+              placeholder="请输入东向速度"
+            />
+          </el-form-item>
+          <el-form-item
+            label="北向速度"
+            prop="fixedMultiTargetFormation.northSpeed"
+          >
+            <el-input
+              v-model="form.fixedMultiTargetFormation.northSpeed"
+              placeholder="请输入北向速度"
+            />
+          </el-form-item>
+          <el-form-item
+            label="天向速度"
+            prop="fixedMultiTargetFormation.skySpeed"
+          >
+            <el-input
+              v-model="form.fixedMultiTargetFormation.skySpeed"
+              placeholder="请输入天向速度"
+            />
+          </el-form-item>
+        </div>
+        <div v-show="form.multiTarget == '2'" style="width: 100%">
+          <el-divider content-position="left">自定义编队无人机</el-divider>
+          <div style="width: 100%">
+            <el-form
+              ref="canvasInfoFormRef"
+              :inline="true"
+              :model="canvasInfo"
+              :rules="infoRules"
+              class="demo-form-inline"
+              :disabled="submitInfoFlag"
+              v-show="this.title == '修改任务数据' ? false : true"
+            >
+              <el-form-item label="中心点-经度" prop="centerLongitude">
+                <el-input
+                  v-model="canvasInfo.centerLongitude"
+                  placeholder="中心点-经度"
+                ></el-input>
+              </el-form-item>
+              <el-form-item label="中心点-纬度" prop="centerLatitude">
+                <el-input
+                  v-model="canvasInfo.centerLatitude"
+                  placeholder="中心点-纬度"
+                ></el-input>
+              </el-form-item>
+              <el-form-item label="边长距离" prop="lengthKm">
+                <el-input v-model="canvasInfo.lengthKm" placeholder="边长距离">
+                  <template slot="append">km</template>
+                </el-input>
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="canvasInfoSubmit"
+                  >确 定</el-button
+                >
+              </el-form-item>
+            </el-form>
+          </div>
+          <div
+            style="
+              width: 100%;
+              height: 800px;
+              display: flex;
+              justify-content: space-evenly;
+            "
+          >
+            <div
+              ref="pixiCanvas"
+              class="left"
+              style="width: 800px; position: relative; height: 800px"
+            >
+              <div style="position: absolute; top: 5px; left: 5px">
+                <span>经度:{{ nowlongitude }}</span
+                ><br />
+                <span>经度:{{ nowlatitude }}</span>
+              </div>
+            </div>
+            <div class="right" style="width: 25%; height: 800px">
+              <el-divider content-position="left">编队信息</el-divider>
+              <div style="overflow-y: scroll; width: 100%; height: 750px">
+                <li v-for="(item, index) in formationInfoList" :key="index">
+                  <div style="cursor: pointer">
+                    <div>
+                      <span>编号:&nbsp;&nbsp;</span
+                      ><label>{{ item.number }}</label>
+                    </div>
+                    <div>
+                      <span>经度:&nbsp;&nbsp;</span
+                      ><label>{{ item.longitude }}</label>
+                    </div>
+                    <div>
+                      <span>纬度:&nbsp;&nbsp;</span
+                      ><label>{{ item.latitude }}</label>
+                    </div>
+                    <div>
+                      <span>海拔&nbsp;&nbsp;</span
+                      ><label>{{ item.altitude }}</label>
+                    </div>
+                    <div>
+                      <span>东向速度:&nbsp;&nbsp;</span
+                      ><label>{{ item.eastSpeed }}(m/s)</label>
+                    </div>
+                    <div>
+                      <span>北向速度:&nbsp;&nbsp;</span
+                      ><label>{{ item.northSpeed }}(m/s)</label>
+                    </div>
+                    <div>
+                      <span>天向速度:&nbsp;&nbsp;</span
+                      ><label>{{ item.skySpeed }}(m/s)</label>
+                    </div>
+                    <div>
+                      <span>航线类型:&nbsp;&nbsp;</span
+                      ><label>{{ item.flightPathType }}(m/s)</label>
+                    </div>
+                    <div>
+                      <span>噪音:&nbsp;&nbsp;</span
+                      ><label>{{ item.positionNoise }}(m/s)</label>
+                    </div>
+                  </div>
+                </li>
+              </div>
+            </div>
+          </div>
+        </div>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
         <el-button @click="cancel">取 消</el-button>
       </div>
     </el-dialog>
+
+    <el-drawer
+      title="设置参数"
+      size="20%"
+      :visible.sync="drawerOpen"
+      direction="rtl"
+      :show-close="false"
+      :wrapperClosable="false"
+    >
+      <div class="demo-drawer__content" style="width: 80%; margin-left: 20px">
+        <el-form
+          label-width="80px"
+          ref="formationInfoRef"
+          :rules="formationInfoRules"
+          :model="formationInfoForm"
+        >
+          <el-form-item label="编号" prop="number">
+            <el-input
+              v-model="formationInfoForm.number"
+              placeholder="请输入编号"
+            />
+          </el-form-item>
+          <el-form-item label="经度" prop="longitude">
+            <el-input
+              v-model="formationInfoForm.longitude"
+              placeholder="请输入经度"
+            />
+          </el-form-item>
+          <el-form-item label="纬度" prop="latitude">
+            <el-input
+              v-model="formationInfoForm.latitude"
+              placeholder="请输入纬度"
+            />
+          </el-form-item>
+          <el-form-item label="海拔" prop="altitude">
+            <el-input
+              v-model="formationInfoForm.altitude"
+              placeholder="请输入海拔"
+            />
+          </el-form-item>
+          <el-form-item label="东向速度" prop="eastSpeed">
+            <el-input
+              v-model="formationInfoForm.eastSpeed"
+              placeholder="请输入东向速度"
+            >
+              <template slot="append">m/s</template>
+            </el-input>
+          </el-form-item>
+          <el-form-item label="北向速度" prop="northSpeed">
+            <el-input
+              v-model="formationInfoForm.northSpeed"
+              placeholder="请输入北向速度"
+            >
+              <template slot="append">m/s</template>
+            </el-input>
+          </el-form-item>
+          <el-form-item label="天向速度" prop="skySpeed">
+            <el-input
+              v-model="formationInfoForm.skySpeed"
+              placeholder="请输入天向速度"
+            >
+              <template slot="append">m/s</template>
+            </el-input>
+          </el-form-item>
+          <el-form-item label="航线类型" prop="flightPathType">
+            <el-select
+              v-model="formationInfoForm.flightPathType"
+              placeholder="航线类型"
+            >
+              <el-option label="直线" value="直线"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="噪声" prop="positionNoise">
+            <el-input
+              v-model="formationInfoForm.positionNoise"
+              placeholder="请输入噪声"
+            />
+          </el-form-item>
+        </el-form>
+        <div class="demo-drawer__footer">
+          <el-button type="primary" @click="handleDrawerSubmit"
+            >确 定</el-button
+          >
+        </div>
+      </div>
+    </el-drawer>
+
+    <!-- 飞行轨迹展示对话框 -->
     <el-dialog
       :title="title"
       :visible.sync="showTrajectory"
       @opened="initTrajectory"
-      :before-close="destroyTrajectory"
+      :before-close="closeDialog"
       :fullscreen="true"
       append-to-body
       destroy-on-close
+      :close-on-click-modal="false"
     >
       <div class="container">
         <div>
           <el-row type="flex" align="middle" style="height: 40px">
-            <el-col :span="7">
-              <el-button @click="transFormation" type="danger"
+            <el-col :span="20">
+              <el-button
+                v-if="!isUpdateView"
+                @click="transFormation"
+                type="danger"
                 >转换队形</el-button
               >
-              <el-button @click="" type="success">回放</el-button>
-            </el-col>
-            <el-col :span="17">
-              <!--              <el-progress v-show="isShow" :percentage="percentage"></el-progress>-->
+              <el-progress
+                style="margin: 0 auto"
+                :text-inside="true"
+                :stroke-width="26"
+                v-if="isUpdateView"
+                :percentage="percentage"
+              ></el-progress>
+              <!-- <el-button @click="handlePlayback" type="success">回放</el-button> -->
             </el-col>
           </el-row>
           <el-row>
             <div ref="pixiContainer" class="pixi-container"></div>
           </el-row>
         </div>
-        <!-- <div class="right-board">
+        <div class="right-board">
           <div style="float: right">
             <el-link type="primary" @click="showConfig">显示配置</el-link>
           </div>
+          <div>
+            <el-divider content-position="left">隐藏列表</el-divider>
+            <div style="margin-left: 10px" v-if="hideList.length !== 0">
+              <el-tag
+                v-for="item in hideList"
+                @click="showSprite(item)"
+                style="cursor: pointer; margin-left: 5px"
+                >{{ item }}</el-tag
+              >
+            </div>
+            <div style="margin-left: 10px" v-else>暂无</div>
+          </div>
           <el-divider content-position="left">目标无人机群</el-divider>
           <li v-for="(item, index) in targetLblAry" :key="index">
-            <div @click="showSprite(item.id)" style="cursor: pointer">
-              <span>编号:&nbsp;&nbsp;</span><label>{{ item.showNo }}</label>
-              <span style="margin-left: 10px" v-if="hideList.includes(item.id)"
+            <div
+              v-if="!hideList.includes(item.id)"
+              @click="showSprite(item.id)"
+              style="cursor: pointer"
+            >
+              <div>
+                <span>编号:&nbsp;&nbsp;</span><label>{{ item.showNo }}</label>
+                <!-- <span style="margin-left: 10px" v-if="hideList.includes(item.id)"
                 >( 隐 藏 )</span
-              >
-            </div>
-            <div v-if="configList.includes('经度')">
-              <span>经度:&nbsp;&nbsp;</span><label>{{ item.longitude }}</label>
-            </div>
-            <div v-if="configList.includes('纬度')">
-              <span>纬度:&nbsp;&nbsp;</span><label>{{ item.latitude }}</label>
-            </div>
-            <div v-if="configList.includes('海拔')">
-              <span>海拔:&nbsp;&nbsp;</span><label>{{ item.altitude }}</label>
-            </div>
-            <div v-if="configList.includes('东向速度')">
-              <span>东向速度:&nbsp;&nbsp;</span
-              ><label>{{ item.eastSpeed }}</label>
-            </div>
-            <div v-if="configList.includes('北向速度')">
-              <span>北向速度:&nbsp;&nbsp;</span
-              ><label>{{ item.northSpeed }}</label>
-            </div>
-            <div v-if="configList.includes('天向速度')">
-              <span>天向速度:&nbsp;&nbsp;</span
-              ><label>{{ item.skySpeed }}</label>
+              > -->
+              </div>
+              <div v-if="configList.includes('经度')">
+                <span>经度:&nbsp;&nbsp;</span
+                ><label>{{ item.longitude }}</label>
+              </div>
+              <div v-if="configList.includes('纬度')">
+                <span>纬度:&nbsp;&nbsp;</span
+                ><label>{{ item.latitude }}</label>
+              </div>
+              <div v-if="configList.includes('海拔')">
+                <span>海拔:&nbsp;&nbsp;</span
+                ><label>{{ item.altitude }}</label>
+              </div>
+              <div v-if="configList.includes('东向速度')">
+                <span>东向速度:&nbsp;&nbsp;</span
+                ><label>{{ item.eastSpeed }}</label>
+              </div>
+              <div v-if="configList.includes('北向速度')">
+                <span>北向速度:&nbsp;&nbsp;</span
+                ><label>{{ item.northSpeed }}</label>
+              </div>
+              <div v-if="configList.includes('天向速度')">
+                <span>天向速度:&nbsp;&nbsp;</span
+                ><label>{{ item.skySpeed }}</label>
+              </div>
             </div>
           </li>
-        </div> -->
+        </div>
       </div>
     </el-dialog>
+
+    <!-- 显示配置对话框 -->
+    <el-dialog
+      title="显示配置"
+      :close-on-click-modal="false"
+      :visible.sync="showConfigVisible"
+      width="30%"
+    >
+      <el-checkbox-group
+        v-model="showConfigList"
+        style="display: flex; flex-direction: column"
+      >
+        <el-checkbox
+          v-for="item in configData"
+          :label="item.label"
+        ></el-checkbox>
+      </el-checkbox-group>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="showConfigVisible = false">取 消</el-button>
+        <el-button type="primary" @click="selectConfigSubmit">确 定</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 
@@ -338,6 +712,7 @@ import {
   addTask,
   updateTask,
 } from "@/api/system/task";
+import * as PIXI from "pixi.js";
 
 export default {
   name: "Task",
@@ -379,12 +754,255 @@ export default {
         createTime: null,
       },
       // 表单参数
-      form: {},
+      form: {
+        platformUav: {},
+        fixedMultiTargetFormation: {},
+      },
       // 表单校验
-      rules: {},
+      rules: {
+        bizName: [
+          { required: true, message: "任务名称不能为空", trigger: "blur" },
+        ],
+        multiTarget: [
+          {
+            required: true,
+            message: "编队类型不能为空",
+            trigger: "change",
+          },
+        ],
+        noiseType: [
+          {
+            required: true,
+            message: "噪声类型不能为空",
+            trigger: "change",
+          },
+        ],
+        noiseVariance: [
+          { required: true, message: "噪声方差不能为空", trigger: "blur" },
+        ],
+        noiseMean: [
+          { required: true, message: "噪声均值不能为空", trigger: "blur" },
+        ],
+        "platformUav.longitude": [
+          {
+            required: true,
+            message: "平台无人机经度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "platformUav.latitude": [
+          {
+            required: true,
+            message: "平台无人机纬度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "platformUav.altitude": [
+          {
+            required: true,
+            message: "平台无人机海拔不能为空",
+            trigger: "blur",
+          },
+        ],
+        "platformUav.eastSpeed": [
+          {
+            required: true,
+            message: "平台无人机东向速度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "platformUav.northSpeed": [
+          {
+            required: true,
+            message: "平台无人机北向速度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "platformUav.skySpeed": [
+          {
+            required: true,
+            message: "平台无人机天向速度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "fixedMultiTargetFormation.targetTotal": [
+          {
+            required: true,
+            message: "固定编队无人机飞机数量不能为空",
+            trigger: "blur",
+          },
+        ],
+        "fixedMultiTargetFormation.longitude": [
+          {
+            required: true,
+            message: "固定编队无人机经度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "fixedMultiTargetFormation.latitude": [
+          {
+            required: true,
+            message: "固定编队无人机纬度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "fixedMultiTargetFormation.altitude": [
+          {
+            required: true,
+            message: "固定编队无人机海拔不能为空",
+            trigger: "blur",
+          },
+        ],
+        "fixedMultiTargetFormation.eastSpeed": [
+          {
+            required: true,
+            message: "固定编队无人机东向速度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "fixedMultiTargetFormation.northSpeed": [
+          {
+            required: true,
+            message: "固定编队无人机北向速度不能为空",
+            trigger: "blur",
+          },
+        ],
+        "fixedMultiTargetFormation.skySpeed": [
+          {
+            required: true,
+            message: "固定编队无人机天向速度不能为空",
+            trigger: "blur",
+          },
+        ],
+      },
+      infoRules: {
+        centerLongitude: [
+          { required: true, message: "经度不能为空", trigger: "blur" },
+        ],
+        centerLatitude: [
+          { required: true, message: "纬度不能为空", trigger: "blur" },
+        ],
+        lengthKm: [
+          { required: true, message: "边长距离不能为空", trigger: "blur" },
+        ],
+      },
+      formationInfoRules: {
+        number: [{ required: true, message: "编号不能为空", trigger: "blur" }],
+        longitude: [
+          { required: true, message: "经度不能为空", trigger: "blur" },
+        ],
+        latitude: [
+          { required: true, message: "纬度不能为空", trigger: "blur" },
+        ],
+        altitude: [
+          { required: true, message: "海拔不能为空", trigger: "blur" },
+        ],
+        eastSpeed: [
+          { required: true, message: "东向速度不能为空", trigger: "blur" },
+        ],
+        northSpeed: [
+          { required: true, message: "北向速度不能为空", trigger: "blur" },
+        ],
+        skySpeed: [
+          { required: true, message: "天向速度不能为空", trigger: "blur" },
+        ],
+        flightPathType: [
+          { required: true, message: "航线类型不能为空", trigger: "change" },
+        ],
+        positionNoise: [
+          { required: true, message: "噪音不能为空", trigger: "blur" },
+        ],
+      },
       parameterId: 0,
+      // 是否显示轨迹
       showTrajectory: false,
+      pixiApp: null,
+      container: null,
       webSocket: null,
+      curLongitude: null,
+      curLatitude: null,
+      curAltitude: null,
+      targetTotal: null,
+      formationTypeList: [
+        {
+          value: "1",
+          label: "固定编队",
+        },
+        {
+          value: "2",
+          label: "自由编队",
+        },
+      ],
+      noiseTypeList: [
+        {
+          value: "1",
+          label: "高斯",
+        },
+        {
+          value: "2",
+          label: "瑞利",
+        },
+      ],
+      // 自定义编队信息
+      formationInfoList: [],
+      formationInfoForm: {
+        number: null,
+        longitude: 100.0,
+        latitude: 100.0,
+        altitude: 100.0,
+        eastSpeed: 100.0,
+        northSpeed: 100.0,
+        skySpeed: 100.0,
+        flightPathType: "直线",
+        positionNoise: 18.2,
+      },
+      // 编辑编队信息的
+      formationAirPiXiApp: null,
+      // 设定的画布信息
+      canvasInfo: {
+        centerLongitude: null,
+        centerLatitude: null,
+        lengthKm: null,
+      },
+      // 编辑编队信息的画布
+      pixiCanvas: null,
+      // 是否提交了编队信息
+      submitInfoFlag: false,
+      // 鼠标当前的经纬度
+      nowlongitude: null,
+      nowlatitude: null,
+      targetDataR: [],
+      targetDataN: [],
+      // 真实路径的集合
+      pathGraphicsList: [],
+      pathGraphicsPointList: [],
+      isUpdateView: false, // 是否开启实现追踪,在回放时开启
+      percentage: 50,
+      // 多久更新一次轨迹
+      updatePathFlag: 125,
+      cycleCount: 0, // 循环计数
+      showConfigVisible: false, //显示配置dialog
+      showConfigList: [], // 选择要显示的值
+      configList: ["经度", "纬度", "海拔", "东向速度", "北向速度", "天向速度"], // 显示的值
+      configData: [
+        // 可选择的值
+        { key: "longitude", label: "经度" },
+        { key: "latitude", label: "纬度" },
+        { key: "altitude", label: "海拔" },
+        { key: "eastSpeed", label: "东向速度" },
+        { key: "northSpeed", label: "北向速度" },
+        { key: "skySpeed", label: "天向速度" },
+      ],
+      hideList: [], // 当下隐藏的飞机数组
+      allId: [], // 所有飞机的id
+      changeShowNoList: [], // 需要改变的飞机编号,放有id和应该显示的编号
+      targetLblAry: [],
+      targetUavAry: [],
+      targetUavCircle: [],
+      targetUavCircleN: [],
+      targetUavCircleNum: [],
+      targetUavCircleNumN: [],
+      drawerOpen: false,
     };
   },
   created() {
@@ -410,6 +1028,7 @@ export default {
     cancel() {
       this.open = false;
       this.reset();
+      this.closeUpdataDialog();
     },
     // 表单重置
     reset() {
@@ -421,9 +1040,9 @@ export default {
         noiseType: null,
         noiseVariance: null,
         noiseMean: null,
-        platformUavStr: null,
-        fixedMultiTargetFormationStr: null,
-        customizedMultiTargetFormationStr: null,
+        platformUav: {},
+        fixedMultiTargetFormation: {},
+        customizedMultiTargetFormation: null,
         status: null,
         startTime: null,
         endTime: null,
@@ -464,14 +1083,76 @@ export default {
       const bizId = row.bizId || this.ids;
       getTask(bizId).then((response) => {
         this.form = response.data;
-        this.open = true;
+        if (this.form.multiTarget == "2") {
+          const info = this.form.customizedMultiTargetFormation[0];
+          this.formationInfoList = this.form.customizedMultiTargetFormation;
+          //自由编队
+          this.$nextTick(() => {
+            this.initFormationApp();
+            this.canvasInfo = {
+              centerLongitude: info.longitude,
+              centerLatitude: info.latitude,
+              lengthKm: 5,
+            };
+            this.airPosShow(
+              this.form.customizedMultiTargetFormation,
+              "fixedWing"
+            );
+          });
+        }
         this.title = "修改任务数据";
+        this.open = true;
       });
     },
+    // 根据后端返回的自定义编队信息,显示飞机位置
+    airPosShow(info, type) {
+      let texture;
+      if (type == "fixedWing") {
+        texture = new PIXI.Texture.from("../../textures/uav-tar.png");
+      } else {
+        // 旋翼机型 需要改
+        texture = new PIXI.Texture.from("../../textures/uav-tar.png");
+      }
+      info.forEach((item) => {
+        const { x, y } = this.calculateXY(item.longitude, item.latitude);
+
+        const sprite = new PIXI.Sprite(texture); // 示例飞机图标
+        sprite.anchor.set(0.5, 0.5);
+        sprite.scale.set(0.04);
+        sprite.x = x;
+        sprite.y = y;
+
+        this.formationAirPiXiApp.stage.addChild(sprite);
+      });
+    },
+    calculateXY(longitude, latitude) {
+      // 计算每像素对应的实际距离
+      const kmPerPixel = this.canvasInfo.lengthKm / this.pixiCanvas.clientWidth;
+
+      // 经纬度差值转实际距离
+      const deltaY = (latitude - this.canvasInfo.centerLatitude) * 111;
+      const deltaX =
+        (longitude - this.canvasInfo.centerLongitude) *
+        111 *
+        Math.cos((this.canvasInfo.centerLatitude * Math.PI) / 180);
+
+      // 实际距离转像素偏移量
+      const offsetX = deltaX / kmPerPixel;
+      const offsetY = deltaY / kmPerPixel;
+
+      // 像素坐标
+      const x = this.pixiCanvas.clientWidth / 2 + offsetX;
+      const y = this.pixiCanvas.clientHeight / 2 - offsetY;
+
+      return { x, y };
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate((valid) => {
         if (valid) {
+          if (this.form.multiTarget == "2") {
+            this.form.customizedMultiTargetFormation = this.formationInfoList;
+          }
           if (this.form.bizId != null) {
             updateTask(this.form).then((response) => {
               this.$modal.msgSuccess("修改成功");
@@ -512,11 +1193,34 @@ export default {
         `task_${new Date().getTime()}.xlsx`
       );
     },
+    showConfig() {
+      this.showConfigList = this.configList;
+      this.showConfigVisible = true;
+    },
+    selectConfigSubmit() {
+      this.configList = this.showConfigList;
+      this.showConfigVisible = false;
+    },
+    // 选择编队类型
+    typeChange(val) {
+      if (val == "2") {
+        this.$nextTick(() => {
+          this.$message.warning(`请先输入画布信息!`);
+          this.initFormationApp();
+        });
+      }
+    },
     handleRun(row) {
       this.parameterId = row.bizId || this.ids;
       this.showTrajectory = true;
       this.title = "飞行轨迹";
     },
+    handlePlayback(row) {
+      this.parameterId = row.id || this.ids;
+      this.showTrajectory = true;
+      this.isUpdateView = true;
+      this.title = "回放";
+    },
     initWebSocket() {
       const wsUri = "ws://127.0.0.1:8080/websocket/message";
       this.webSocket = new WebSocket(wsUri);
@@ -560,11 +1264,700 @@ export default {
       this.showTrajectory = false;
     },
     initTrajectory() {
+      this.clearAllAry();
+      this.initPixi();
       this.initWebSocket();
     },
-    processMessage(json) {
-      console.info(json);
+    // 处理WebSocket消息
+    processMessage(data) {
+      // console.log(data);
+      // type:1平台无人机、2真实目标、3噪声目标
+      switch (data.type) {
+        case "1": //平台无人机
+          break;
+        case "2": //真实目标  R真实数据
+          this.showTargetRAircraft(data, "R");
+          break;
+        case "3": //噪声目标  N噪声数据
+          this.showTargetNAircraft(data, "N");
+          break;
+
+        default:
+          break;
+      }
+    },
+    initPixi() {
+      this.container = this.$refs.pixiContainer;
+      if (!this.container) return;
+
+      // 创建Pixi应用
+      this.pixiApp = new PIXI.Application({
+        width: this.container.clientWidth,
+        height: this.container.clientHeight,
+        antialias: true,
+        transparent: false,
+        resolution: 1,
+        backgroundAlpha: 0,
+      });
+      this.pixiApp.renderer.backgroundColor = 0x66ccff;
+      this.container.appendChild(this.pixiApp.view);
+
+      //this.createPlane();
+
+      // 初始化路径绘制对象
+      // this.pathGraphics = new PIXI.Graphics();
+      // this.pathGraphics.stroke({ pixelLine: true });
+      // this.pixiApp.stage.addChild(this.pathGraphics);
+
+      // 添加视窗控制
+      this.enableViewControl();
+    },
+
+    // 无人机集群 真实数据
+    showTargetRAircraft(data) {
+      const targetData = data.targetAircraft[0];
+      this.targetTotal = targetData.aircrafts.length;
+      // 还没有真实数据时,先初始化数据。
+      if (this.targetDataR.length === 0) {
+        const targetTexture = new PIXI.Texture.from(
+          "../../textures/uav-tar.png"
+        );
+        for (let i = 0; i < this.targetTotal; i++) {
+          this.allId.push(targetData.aircrafts[i].aircraftNumber);
+          const group = new PIXI.Container();
+          group.id = targetData.aircrafts[i].aircraftNumber;
+          group.buttonMode = true; // 鼠标悬停时显示手型
+          group.interactive = true;
+          // 创建无人机
+          const dude = new PIXI.Sprite(targetTexture);
+          dude.anchor.set(0.5, 0.5);
+          dude.scale.set(0.04);
+
+          dude.x = targetData.aircrafts[i].coordinateX;
+          dude.y = targetData.aircrafts[i].coordinateY;
+
+          dude.id = targetData.aircrafts[i].aircraftNumber; // 分配唯一编号
+          this.targetDataR.push(dude);
+          group.addChild(dude);
+
+          // 创建圆圈  圆圈相对于飞机的位置
+          const cx = dude.x - 25;
+          const cy = dude.y - 17;
+
+          //编号-圆圈
+          const circle = new PIXI.Graphics();
+          circle.beginFill(0xff0000); // 红色
+          circle.drawCircle(0, 0, 8);
+          circle.endFill();
+          circle.x = cx;
+          circle.y = cy;
+          this.targetUavCircle.push(circle);
+          group.addChild(circle);
+
+          //编号-数字
+          const text = new PIXI.Text(targetData.aircrafts[i].aircraftNumber, {
+            fontFamily: "Arial",
+            fontSize: 12,
+            fill: 0xffffff,
+            align: "center",
+          });
+          text.anchor.set(0.5);
+          // 计算文字位置以便在圆形内居中
+          text.x = cx;
+          text.y = cy;
+          this.targetUavCircleNum.push(text);
+          group.addChild(text);
+          // 绑定鼠标事件,飞机隐藏
+          group.on("pointerdown", () => {
+            this.hideSprite(group.id);
+          });
+          this.pixiApp.stage.addChild(group);
+
+          // 创建路径
+          const pathGraphics = new PIXI.Graphics();
+          pathGraphics.lineStyle(1, 0xeeee00, 1);
+          const point = { x: dude.x, y: dude.y };
+          pathGraphics.id = targetData.aircrafts[i].aircraftNumber;
+          this.pathGraphicsPointList.push(point);
+          // pathGraphics.moveTo(dude.x, dude.y);
+          // pathGraphics.lineTo(dude.x, dude.y);
+
+          this.pathGraphicsList.push(pathGraphics);
+          this.pixiApp.stage.addChild(pathGraphics);
+
+          if (targetData.aircrafts[i].piloted) {
+            // const point = { x: dude.x, y: dude.y };
+            // this.targetUavPath.push(point);
+            // 领航飞机的位置,在转换队形时有用到
+            this.curLongitude = targetData.aircrafts[i].longitude;
+            this.curLatitude = targetData.aircrafts[i].latitude;
+            this.curAltitude = targetData.aircrafts[i].altitude;
+          }
+        }
+      } else {
+        // 每次更新
+        for (let i = 0; i < this.targetDataR.length; i++) {
+          const targetUav = this.targetDataR[i];
+
+          targetUav.x = data.targetAircraft[0].aircrafts[i].coordinateX;
+          targetUav.y = data.targetAircraft[0].aircrafts[i].coordinateY;
+          const eastSpeed = data.targetAircraft[0].aircrafts[i].eastSpeed;
+          const northSpeed = data.targetAircraft[0].aircrafts[i].northSpeed;
+          targetUav.rotation = Math.atan2(northSpeed, eastSpeed);
+
+          const cx = targetUav.x - 25;
+          const cy = targetUav.y - 17;
+
+          const circle = this.targetUavCircle[i];
+          circle.x = cx;
+          circle.y = cy;
+
+          const text = this.targetUavCircleNum[i];
+          text.x = cx;
+          text.y = cy;
+
+          if (this.cycleCount % this.updatePathFlag == 0) {
+            // 更新路径绘制
+            this.updatePath(i, targetUav.x, targetUav.y);
+          }
+
+          if (data.targetAircraft[0].aircrafts[i].piloted) {
+            const viewSprite = this.pixiApp.stage.children.find((item) => {
+              return (
+                item.id == data.targetAircraft[0].aircrafts[i].aircraftNumber
+              );
+            });
+            if (this.isUpdateView) {
+              // 获取精灵的边界
+              const spriteBounds = viewSprite.getBounds();
+              // 检测是否移出画布
+              if (spriteBounds.left < 0) {
+                // 触碰到了左边界
+                this.pixiApp.stage.x += this.container.clientWidth / 2;
+              } else if (spriteBounds.right > this.container.clientWidth) {
+                // 触碰到了右边
+                this.pixiApp.stage.x -= this.container.clientWidth / 2;
+              } else if (spriteBounds.top < 0) {
+                // 触碰到了上边
+                this.pixiApp.stage.y += this.container.clientHeight / 2;
+              } else if (spriteBounds.bottom > this.container.clientHeight) {
+                // 触碰到了下边
+                this.pixiApp.stage.y -= this.container.clientHeight / 2;
+              }
+            }
+          }
+        }
+        this.cycleCount++;
+      }
+      if (data.targetAircraft != null) {
+        for (let i = 0; i < this.targetTotal; i++) {
+          const id = targetData.aircrafts[i].aircraftNumber;
+          let findItem = this.changeShowNoList.find((item) => item.id == id);
+          // 多目标集群信息显示
+          const lbl = {
+            id: id,
+            showNo: findItem
+              ? findItem.showNo
+              : targetData.aircrafts[i].aircraftNumber,
+            longitude: targetData.aircrafts[i].longitude.toFixed(7),
+            latitude: targetData.aircrafts[i].latitude.toFixed(7),
+            altitude: targetData.aircrafts[i].altitude + " m",
+            eastSpeed: targetData.aircrafts[i].eastSpeed.toFixed(1) + " m/s",
+            northSpeed: targetData.aircrafts[i].northSpeed.toFixed(1) + " m/s",
+            skySpeed: targetData.aircrafts[i].skySpeed.toFixed(1) + " m/s",
+          };
+          if (this.targetLblAry.length === 0) {
+            this.targetLblAry.push(lbl);
+          } else {
+            this.targetLblAry.splice(i, 1, lbl);
+          }
+        }
+      }
+    },
+
+    // 无人机集群 噪音数据
+    showTargetNAircraft(data) {
+      const targetData = data.targetAircraft[0];
+      this.targetTotal = targetData.aircrafts.length;
+      // 还没有数据时,先初始化数据。
+      if (this.targetDataN.length === 0) {
+        const targetTexture = new PIXI.Texture.from("../../textures/bunny.png");
+        for (let i = 0; i < this.targetTotal; i++) {
+          const group = new PIXI.Container();
+          group.id = targetData.aircrafts[i].aircraftNumber;
+          group.interactive = true;
+          // 创建无人机
+          const dude = new PIXI.Sprite(targetTexture);
+          dude.anchor.set(0.5, 0.5);
+          // dude.scale.set(0.04);
+
+          dude.x = targetData.aircrafts[i].coordinateX;
+          dude.y = targetData.aircrafts[i].coordinateY;
+
+          dude.id = targetData.aircrafts[i].aircraftNumber; // 分配唯一编号
+          this.targetDataN.push(dude);
+          group.addChild(dude);
+
+          // 创建圆圈  圆圈相对于飞机的位置
+          const cx = dude.x - 25;
+          const cy = dude.y - 17;
+
+          //编号-圆圈
+          const circle = new PIXI.Graphics();
+          circle.beginFill(0xff0000); // 红色
+          circle.drawCircle(0, 0, 8);
+          circle.endFill();
+          circle.x = cx;
+          circle.y = cy;
+          this.targetUavCircleN.push(circle);
+          group.addChild(circle);
+
+          //编号-数字
+          const text = new PIXI.Text(targetData.aircrafts[i].aircraftNumber, {
+            fontFamily: "Arial",
+            fontSize: 12,
+            fill: 0xffffff,
+            align: "center",
+          });
+          text.anchor.set(0.5);
+          // 计算文字位置以便在圆形内居中
+          text.x = cx;
+          text.y = cy;
+          this.targetUavCircleNumN.push(text);
+          group.addChild(text);
+          this.pixiApp.stage.addChild(group);
+        }
+      } else {
+        // 每次更新
+        for (let i = 0; i < this.targetDataN.length; i++) {
+          const targetUav = this.targetDataN[i];
+
+          targetUav.x = data.targetAircraft[0].aircrafts[i].coordinateX;
+          targetUav.y = data.targetAircraft[0].aircrafts[i].coordinateY;
+          const eastSpeed = data.targetAircraft[0].aircrafts[i].eastSpeed;
+          const northSpeed = data.targetAircraft[0].aircrafts[i].northSpeed;
+          targetUav.rotation = Math.atan2(northSpeed, eastSpeed);
+
+          const cx = targetUav.x - 25;
+          const cy = targetUav.y - 17;
+
+          const circle = this.targetUavCircleN[i];
+          circle.x = cx;
+          circle.y = cy;
+
+          const text = this.targetUavCircleNumN[i];
+          text.x = cx;
+          text.y = cy;
+        }
+      }
+    },
+
+    // 飞机的显示与隐藏
+    hideSprite(id) {
+      let group = [];
+      this.pixiApp.stage.children.forEach((child) => {
+        // 检查 child 是否是 Container 类型
+        if (child instanceof PIXI.Container) {
+          if (child.id == id) {
+            group.push(child);
+          }
+        }
+      });
+      group.forEach((item) => {
+        item.visible = false;
+      });
+      this.hideList.push(id);
+      this.changeShowNoList.push({ id: id, showNo: id });
+    },
+
+    showSprite(id) {
+      let group = [];
+      this.pixiApp.stage.children.forEach((child) => {
+        // 检查 child 是否是 Container 类型
+        if (child instanceof PIXI.Container) {
+          if (child.id == id) {
+            group.push(child);
+          }
+        }
+      });
+      if (this.hideList.includes(id)) {
+        const maxNum = Math.max(...this.allId) + 1;
+        group.forEach((item) => {
+          item.children.forEach((item) => {
+            if (item instanceof PIXI.Text) {
+              item.text = maxNum;
+            }
+          });
+          for (let i = 0; i < this.changeShowNoList.length; i++) {
+            if (this.changeShowNoList[i].id == id) {
+              this.$set(this.changeShowNoList[i], "showNo", maxNum);
+              break;
+            }
+          }
+          // 已经隐藏了,要显示
+          item.visible = true;
+          let index = this.hideList.indexOf(id);
+          if (index > -1) {
+            this.hideList.splice(index, 1);
+          }
+          this.allId.push(maxNum);
+        });
+
+        // 更改画布飞机的编号
+        // group.children.forEach((item) => {
+        //   if (item instanceof PIXI.Text) {
+        //     item.text = maxNum + 1;
+        //   }
+        // });
+        // 更改右侧信息展示编号
+        // for (let i = 0; i < this.changeShowNoList.length; i++) {
+        //   if (this.changeShowNoList[i].id == id) {
+        //     this.$set(this.changeShowNoList[i], "showNo", maxNum + 1);
+        //     break;
+        //   }
+        // }
+        // 已经隐藏了,要显示
+        // group.visible = true;
+        // let index = this.hideList.indexOf(id);
+        // if (index > -1) {
+        //   this.hideList.splice(index, 1);
+        // }
+        // this.allId.push(maxNum + 1);
+      } else {
+        // 隐藏
+        group.forEach((item) => {
+          item.visible = false;
+        });
+        this.hideList.push(id);
+        this.changeShowNoList.push({ id: id, showNo: id });
+      }
+    },
+    // 添加视窗控制
+    enableViewControl() {
+      this.pixiApp.stage.interactive = true;
+      // 拖曳状态变量
+      let dragging = false;
+
+      let lastPosition = null; // 上一次鼠标的位置
+      // 鼠标按下事件
+      this.pixiApp.view.addEventListener("mousedown", (event) => {
+        dragging = true;
+        lastPosition = { x: event.clientX, y: event.clientY };
+      });
+      // 鼠标移出画布时停止拖动
+      this.pixiApp.view.addEventListener("mouseleave", () => {
+        dragging = false;
+      });
+
+      // 鼠标移动事件
+      this.pixiApp.view.addEventListener("mousemove", (event) => {
+        if (dragging) {
+          const currentPosition = { x: event.clientX, y: event.clientY };
+
+          // 计算鼠标移动的距离
+          const dx = currentPosition.x - lastPosition.x;
+          const dy = currentPosition.y - lastPosition.y;
+
+          // 更新舞台的位置
+          this.pixiApp.stage.x += dx;
+          this.pixiApp.stage.y += dy;
+
+          // 更新上一次鼠标的位置
+          lastPosition = currentPosition;
+        }
+      });
+
+      // 鼠标松开事件
+      this.pixiApp.view.addEventListener("mouseup", () => {
+        dragging = false;
+      });
+
+      // 鼠标滚轮缩放
+      this.pixiApp.renderer.view.addEventListener("wheel", (e) => {
+        e.preventDefault();
+        const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
+        this.pixiApp.stage.scale.x *= zoomFactor;
+        this.pixiApp.stage.scale.y *= zoomFactor;
+      });
+    },
+    // 更新飞行路径
+    updatePath(index, x, y) {
+      const lastPointX = this.pathGraphicsPointList[index].x;
+      const lastPointY = this.pathGraphicsPointList[index].y;
+      this.pathGraphicsList[index].moveTo(lastPointX, lastPointY);
+      this.pathGraphicsList[index].lineTo(x, y);
+      this.pathGraphicsPointList[index].x = x;
+      this.pathGraphicsPointList[index].y = y;
+      // this.pathGraphics.lineStyle(1, 0xeeee00, 1);
+      // if (this.targetUavPath.length <= 1) {
+      //   const firstData = this.targetUavPath[this.targetUavPath.length - 1];
+      //   this.lastPosition = firstData;
+      //   this.pathGraphics.moveTo(firstData.x, firstData.y);
+      // } else {
+      //   this.pathGraphics.moveTo(this.lastPosition.x, this.lastPosition.y);
+      //   const nextPos = this.targetUavPath[this.targetUavPath.length - 1];
+      //   this.pathGraphics.lineTo(nextPos.x, nextPos.y);
+      //   this.lastPosition = nextPos;
+      // }
+    },
+
+    // 确定编队信息
+    canvasInfoSubmit() {
+      this.$refs["canvasInfoFormRef"].validate((valid) => {
+        if (valid) {
+          this.submitInfoFlag = true;
+          this.addAirSprite();
+        }
+      });
+    },
+    // 初始化编队的画布
+    initFormationApp() {
+      this.pixiCanvas = this.$refs.pixiCanvas;
+      if (!this.pixiCanvas) return;
+      // 创建Pixi应用
+      this.formationAirPiXiApp = new PIXI.Application({
+        width: this.pixiCanvas.clientWidth,
+        height: this.pixiCanvas.clientHeight,
+        antialias: true,
+        transparent: false,
+        resolution: 1,
+        backgroundAlpha: 0,
+      });
+      this.formationAirPiXiApp.renderer.backgroundColor = 0x1099bb;
+      this.pixiCanvas.appendChild(this.formationAirPiXiApp.view);
+      // 绘制中心点
+      const graphics = new PIXI.Graphics();
+      graphics.beginFill(0xe53f32);
+
+      // 绘制一个圆形,半径为 5 像素
+      const centerX = this.pixiCanvas.clientWidth / 2;
+      const centerY = this.pixiCanvas.clientHeight / 2;
+      graphics.drawCircle(centerX, centerY, 3);
+      graphics.endFill();
+      this.formationAirPiXiApp.stage.addChild(graphics);
+    },
+    // 增加飞机编队
+    addAirSprite() {
+      // 判断是哪个机型
+      let texture;
+      if (this.form && this.form.multiTarget == "1") {
+        texture = new PIXI.Texture.from("../../textures/uav-tar.png");
+      } else if (this.form && this.form.multiTarget == "2") {
+        // 旋翼机型 需要改
+        texture = new PIXI.Texture.from("../../textures/uav-tar.png");
+      }
+      // 创建飞机
+      const airSprite = new PIXI.Sprite(texture);
+      airSprite.anchor.set(0.5, 0.5);
+      airSprite.scale.set(0.04);
+      airSprite.position.set(
+        this.formationAirPiXiApp.screen.width / 2,
+        this.formationAirPiXiApp.screen.height / 2
+      );
+      this.formationAirPiXiApp.stage.addChild(airSprite);
+      this.formationAirPiXiApp.stage.eventMode = "static";
+      this.formationAirPiXiApp.stage.hitArea = this.formationAirPiXiApp.screen;
+      this.formationAirPiXiApp.view.addEventListener("pointermove", (e) => {
+        airSprite.x = e.offsetX;
+        airSprite.y = e.offsetY;
+        const { clientX, clientY } = e;
+        const rect = this.formationAirPiXiApp.view.getBoundingClientRect();
+        const mouseX = clientX - rect.left;
+        const mouseY = clientY - rect.top;
+
+        // 计算对应经纬度
+        const { lat, lng } = this.calculateLatLng(mouseX, mouseY);
+        this.nowlongitude = lng;
+        this.nowlatitude = lat;
+      });
+      this.formationAirPiXiApp.view.addEventListener("dblclick", (e) => {
+        // 创建新精灵
+        const newSprite = new PIXI.Sprite(texture);
+        newSprite.anchor.set(0.5, 0.5);
+        newSprite.scale.set(0.04);
+        newSprite.x = e.offsetX;
+        newSprite.y = e.offsetY;
+        const { clientX, clientY } = e;
+        const rect = this.formationAirPiXiApp.view.getBoundingClientRect();
+        const mouseX = clientX - rect.left;
+        const mouseY = clientY - rect.top;
+
+        // 计算对应经纬度
+        const { lat, lng } = this.calculateLatLng(mouseX, mouseY);
+        this.formationInfoForm.longitude = lng;
+        this.formationInfoForm.latitude = lat;
+        this.drawerOpen = true;
+        // this.
+        this.formationAirPiXiApp.stage.addChild(newSprite);
+      });
+    },
+
+    calculateLatLng(x, y) {
+      // 计算鼠标相对于画布中心的偏移量(单位:像素)
+      const offsetX = x - this.pixiCanvas.clientWidth / 2;
+      const offsetY = y - this.pixiCanvas.clientHeight / 2;
+
+      // 将像素偏移量转换为实际距离(单位:公里)
+      const kmPerPixel = this.canvasInfo.lengthKm / this.pixiCanvas.clientWidth;
+      const deltaX = offsetX * kmPerPixel;
+      const deltaY = -offsetY * kmPerPixel; // 注意 y 轴方向相反
+
+      // 将实际距离转换为经纬度差值
+      const deltaLat = deltaY / 111; // 每纬度约 111 公里
+      const deltaLng =
+        deltaX /
+        (111 * Math.cos((this.canvasInfo.centerLatitude * Math.PI) / 180)); // 每经度约 111 * cos(lat) 公里
+
+      // 计算最终经纬度
+      const lat = Number(this.canvasInfo.centerLatitude) + Number(deltaLat);
+      const lng = Number(this.canvasInfo.centerLongitude) + Number(deltaLng);
+
+      return { lat, lng };
+    },
+
+    handleDrawerSubmit() {
+      this.$refs["formationInfoRef"].validate((valid) => {
+        if (valid) {
+          let index = this.formationInfoList.findIndex(
+            (item) => item.number == this.formationInfoForm.number
+          );
+          if (index !== -1) {
+            this.$message.warning("该编号已存在,请重新输入");
+            return;
+          } else {
+            this.drawerOpen = false;
+            this.formationInfoList.push(this.formationInfoForm);
+            this.formationInfoForm = {
+              number: null,
+              longitude: 100.0,
+              latitude: 100.0,
+              altitude: 100.0,
+              eastSpeed: 100.0,
+              northSpeed: 100.0,
+              skySpeed: 100.0,
+              flightPathType: "直线",
+              positionNoise: 18.2,
+            };
+          }
+        }
+      });
+    },
+
+    closeDialog() {
+      this.destroyTrajectory();
+      this.showTrajectory = false;
+      this.isUpdateView = false;
+    },
+
+    closeUpdataDialog() {
+      this.destroyTormationInfo();
+      this.canvasInfo = {
+        centerLongitude: null,
+        centerLatitude: null,
+        lengthKm: null,
+      };
+      this.submitInfoFlag = false;
+      this.formationAirPiXiApp = null;
+      this.pixiCanvas = null;
+      this.nowlongitude = null;
+      this.nowlatitude = null;
+      this.formationInfoList = [];
+      this.reset();
+    },
+
+    destroyTormationInfo() {
+      if (this.formationAirPiXiApp) {
+        const removedChildren = this.formationAirPiXiApp.stage.removeChildren(
+          0,
+          this.formationAirPiXiApp.stage.children.length
+        );
+        removedChildren.forEach((child) => {
+          child.destroy({
+            children: true,
+            texture: false,
+            baseTexture: false,
+          });
+        });
+        this.formationAirPiXiApp.stage.removeChildren();
+        this.formationAirPiXiApp.renderer.clear();
+        this.formationAirPiXiApp.destroy(true);
+        this.formationAirPiXiApp = null;
+      }
+    },
+
+    clearAllAry() {
+      this.targetLblAry = [];
+      this.targetLblAry = [];
+      this.targetUavAry = [];
+      this.targetUavCircle = [];
+      this.targetUavCircleN = [];
+      this.targetUavCircleNum = [];
+      this.targetUavCircleNumN = [];
+      this.configList = [
+        "经度",
+        "纬度",
+        "海拔",
+        "东向速度",
+        "北向速度",
+        "天向速度",
+      ];
+      this.lastPosition = {
+        x: null,
+        y: null,
+      };
+      this.hideList = [];
+      this.allId = [];
+      this.changeShowNoList = [];
+      this.curLongitude = null;
+      this.curLatitude = null;
+      this.curAltitude = null;
+      this.pathGraphics = null;
+      this.cycleCount = 0;
+      this.isUpdateView = false;
+      this.pathGraphicsList = [];
+      this.pathGraphicsPointList = [];
+      this.targetDataR = [];
+      this.targetDataN = [];
+      this.nowlongitude = null;
+      this.nowlatitude = null;
+      this.submitInfoFlag = false;
+      this.pixiCanvas = null;
+      this.canvasInfo = {
+        centerLongitude: null,
+        centerLatitude: null,
+        lengthKm: null,
+        heightKm: null,
+      };
     },
   },
 };
 </script>
+
+<style>
+.el-dialog__body {
+  /* padding: 0 !important; */
+  padding-top: 10px !important;
+}
+.pixi-container {
+  width: 100%;
+  /* height: 750px; */
+  height: calc(100vh - 140px);
+  position: relative;
+}
+
+.pixi-container canvas {
+  width: 100%;
+  height: 100%;
+}
+
+.container {
+  display: grid;
+  grid-template-columns: 85% 15%; /* 两栏按比例分 */
+}
+.right-board {
+  padding: 2px;
+  margin: 2px;
+  height: 750px;
+  overflow: auto; /* 当内容超出元素边界时显示滚动条 */
+}
+</style>

+ 353 - 102
uavps-web/src/views/uavps/parameter/index.vue

@@ -764,7 +764,9 @@ export default {
       targetLblAry: [],
       targetUavAry: [],
       targetUavCircle: [],
+      targetUavCircleN: [],
       targetUavCircleNum: [],
+      targetUavCircleNumN: [],
       targetUavPath: [],
       showConfigList: [], // 选择要显示的值
       configList: ["经度", "纬度", "海拔", "东向速度", "北向速度", "天向速度"], // 显示的值
@@ -830,6 +832,11 @@ export default {
       // 鼠标当前的经纬度
       nowlongitude: null,
       nowlatitude: null,
+      targetDataR: [],
+      targetDataN: [],
+      // 真实路径的集合
+      pathGraphicsList: [],
+      pathGraphicsPointList: [],
     };
   },
   created() {
@@ -901,6 +908,10 @@ export default {
       const id = row.id || this.ids;
       getParameter(id).then((response) => {
         this.form = response.data;
+        // 不设定为{},会报错
+        if (!this.form.fixedMultiTargetFormation) {
+          this.form.fixedMultiTargetFormation = {};
+        }
         this.open = true;
         this.title = "修改算法参数信息";
       });
@@ -1154,9 +1165,9 @@ export default {
       //this.createPlane();
 
       // 初始化路径绘制对象
-      this.pathGraphics = new PIXI.Graphics();
+      // this.pathGraphics = new PIXI.Graphics();
       // this.pathGraphics.stroke({ pixelLine: true });
-      this.pixiApp.stage.addChild(this.pathGraphics);
+      // this.pixiApp.stage.addChild(this.pathGraphics);
 
       // 添加视窗控制
       this.enableViewControl();
@@ -1192,42 +1203,222 @@ export default {
     },
     // 处理WebSocket消息
     processMessage(data) {
-      // 集群无人机总数
-      // this.targetTotal = 2;
-      this.targetTotal = data.targetAircraft[0].aircrafts.length;
-      // 创建无人机,红色圆圈编号
-      if (this.targetUavAry.length === 0) {
-        this.targetTexture = new PIXI.Texture.from(
+      // console.log("data", data);
+      // 无人机集群
+      if (data.targetAircraft.length !== 0) {
+        // R真实数据,N噪声数据
+        if (data.targetAircraft[0].aircrafts[0].type == "R") {
+          this.showTargetRAircraft(data, "R");
+        } else {
+          this.showTargetNAircraft(data, "N");
+        }
+      }
+      // 平台机
+      // if()
+
+      // this.targetTotal = data.targetAircraft[0].aircrafts.length;
+      // // 创建无人机,红色圆圈编号
+      // if (this.targetUavAry.length === 0) {
+      //   this.targetTexture = new PIXI.Texture.from(
+      //     "../../textures/uav-tar.png"
+      //   );
+      //   for (let i = 0; i < this.targetTotal; i++) {
+      //     this.allId.push(data.targetAircraft[0].aircrafts[i].aircraftNumber);
+      //     const group = new PIXI.Container();
+      //     group.id = data.targetAircraft[0].aircrafts[i].aircraftNumber;
+      //     group.buttonMode = true; // 鼠标悬停时显示手型
+      //     group.interactive = true;
+      //     // 创建无人机
+      //     const dude = new PIXI.Sprite(this.targetTexture);
+      //     dude.anchor.set(0.5, 0.5);
+      //     dude.scale.set(0.04);
+
+      //     dude.x = data.targetAircraft[0].aircrafts[i].coordinateX;
+      //     dude.y = data.targetAircraft[0].aircrafts[i].coordinateY;
+      //     const eastSpeed = data.targetAircraft[0].aircrafts[i].eastSpeed;
+      //     const northSpeed = data.targetAircraft[0].aircrafts[i].northSpeed;
+      //     dude.rotation = Math.atan2(northSpeed, eastSpeed);
+
+      //     dude.id = data.targetAircraft[0].aircrafts[i].aircraftNumber; // 分配唯一编号
+      //     this.targetUavAry.push(dude);
+
+      //     // 创建模糊滤镜
+      //     const blurFilter = new PIXI.filters.BlurFilter();
+      //     blurFilter.blur = 20;
+      //     dude.filters = [blurFilter];
+      //     group.addChild(dude);
+
+      //     // 创建圆圈
+      //     // 圆圈相对于飞机的位置
+      //     const cx = dude.x - 25;
+      //     const cy = dude.y - 17;
+
+      //     //编号-圆圈
+      //     const circle = new PIXI.Graphics();
+      //     circle.beginFill(0xff0000); // 红色
+      //     circle.drawCircle(0, 0, 8);
+      //     circle.endFill();
+      //     circle.x = cx;
+      //     circle.y = cy;
+      //     this.targetUavCircle.push(circle);
+      //     group.addChild(circle);
+      //     // this.pixiApp.stage.addChild(circle);
+
+      //     //编号-数字
+      //     const text = new PIXI.Text(
+      //       data.targetAircraft[0].aircrafts[i].aircraftNumber,
+      //       {
+      //         fontFamily: "Arial",
+      //         fontSize: 12,
+      //         fill: 0xffffff,
+      //         align: "center",
+      //       }
+      //     );
+      //     text.anchor.set(0.5);
+      //     // 计算文字位置以便在圆形内居中
+      //     text.x = cx;
+      //     text.y = cy;
+      //     this.targetUavCircleNum.push(text);
+      //     group.addChild(text);
+      //     // 绑定鼠标事件,飞机隐藏
+      //     group.on("pointerdown", () => {
+      //       this.hideSprite(group);
+      //     });
+      //     this.pixiApp.stage.addChild(group);
+
+      //     // 创建路径
+      //     const pathGraphics = new PIXI.Graphics();
+      //     const point = { x: dude.x, y: dude.y };
+      //     pathGraphics.id = data.targetAircraft[0].aircrafts[i].aircraftNumber;
+
+      //     if (data.targetAircraft[0].aircrafts[i].piloted) {
+      //       // const point = { x: dude.x, y: dude.y };
+      //       // this.targetUavPath.push(point);
+      //       // 领航飞机的位置,在转换队形时有用到
+      //       this.curLongitude = data.targetAircraft[0].aircrafts[i].longitude;
+      //       this.curLatitude = data.targetAircraft[0].aircrafts[i].latitude;
+      //       this.curAltitude = data.targetAircraft[0].aircrafts[i].altitude;
+      //     }
+      //   }
+      // } else {
+      //   for (let i = 0; i < this.targetUavAry.length; i++) {
+      //     const targetUav = this.targetUavAry[i];
+
+      //     targetUav.x = data.targetAircraft[0].aircrafts[i].coordinateX;
+      //     targetUav.y = data.targetAircraft[0].aircrafts[i].coordinateY;
+      //     const eastSpeed = data.targetAircraft[0].aircrafts[i].eastSpeed;
+      //     const northSpeed = data.targetAircraft[0].aircrafts[i].northSpeed;
+      //     // targetUav.rotation = Math.atan2(northSpeed, eastSpeed) + Math.PI / 2;
+      //     targetUav.rotation = Math.atan2(northSpeed, eastSpeed);
+      //     // const rotation = Math.atan2(eastSpeed, northSpeed);
+      //     // targetUav.rotation = (-rotation + 2 * Math.PI) % (2 * Math.PI);
+
+      //     const cx = targetUav.x - 25;
+      //     const cy = targetUav.y - 17;
+
+      //     const circle = this.targetUavCircle[i];
+      //     circle.x = cx;
+      //     circle.y = cy;
+
+      //     const text = this.targetUavCircleNum[i];
+      //     text.x = cx;
+      //     text.y = cy;
+
+      //     if (data.targetAircraft[0].aircrafts[i].piloted) {
+      //       // const point = { x: targetUav.x, y: targetUav.y };
+      //       // this.targetUavPath.push(point);
+      //       // this.curLongitude = data.targetAircraft[0].aircrafts[i].longitude;
+      //       // this.curLatitude = data.targetAircraft[0].aircrafts[i].latitude;
+      //       // this.curAltitude = data.targetAircraft[0].aircrafts[i].altitude;
+
+      //       const viewSprite = this.pixiApp.stage.children.find((item) => {
+      //         return (
+      //           item.id == data.targetAircraft[0].aircrafts[i].aircraftNumber
+      //         );
+      //       });
+      //       if (this.isUpdateView) {
+      //         // 获取精灵的边界
+      //         const spriteBounds = viewSprite.getBounds();
+      //         // 检测是否移出画布
+      //         if (spriteBounds.left < 0) {
+      //           // 触碰到了左边界
+      //           this.pixiApp.stage.x += this.container.clientWidth / 2;
+      //         } else if (spriteBounds.right > this.container.clientWidth) {
+      //           // 触碰到了右边
+      //           this.pixiApp.stage.x -= this.container.clientWidth / 2;
+      //         } else if (spriteBounds.top < 0) {
+      //           // 触碰到了上边
+      //           this.pixiApp.stage.y += this.container.clientHeight / 2;
+      //         } else if (spriteBounds.bottom > this.container.clientHeight) {
+      //           // 触碰到了下边
+      //           this.pixiApp.stage.y -= this.container.clientHeight / 2;
+      //         }
+      //       }
+      //     }
+      //   }
+      // }
+      // if (data.targetAircraft != null) {
+      //   for (let i = 0; i < this.targetTotal; i++) {
+      //     const id = data.targetAircraft[0].aircrafts[i].aircraftNumber;
+      //     let findItem = this.changeShowNoList.find((item) => item.id == id);
+      //     // 多目标集群信息显示
+      //     const lbl = {
+      //       id: id,
+      //       showNo: findItem
+      //         ? findItem.showNo
+      //         : data.targetAircraft[0].aircrafts[i].aircraftNumber,
+      //       longitude: data.targetAircraft[0].aircrafts[i].longitude.toFixed(7),
+      //       latitude: data.targetAircraft[0].aircrafts[i].latitude.toFixed(7),
+      //       altitude: data.targetAircraft[0].aircrafts[i].altitude + " m",
+      //       eastSpeed:
+      //         data.targetAircraft[0].aircrafts[i].eastSpeed.toFixed(1) + " m/s",
+      //       northSpeed:
+      //         data.targetAircraft[0].aircrafts[i].northSpeed.toFixed(1) +
+      //         " m/s",
+      //       skySpeed:
+      //         data.targetAircraft[0].aircrafts[i].skySpeed.toFixed(1) + " m/s",
+      //     };
+      //     if (this.targetLblAry.length === 0) {
+      //       this.targetLblAry.push(lbl);
+      //     } else {
+      //       this.targetLblAry.splice(i, 1, lbl);
+      //     }
+      //   }
+      // }
+      // if (this.cycleCount % this.updatePathFlag == 0) {
+      //   // 更新路径绘制
+      //   this.updatePath();
+      // }
+      // this.cycleCount++;
+    },
+    // 无人机集群 真实数据
+    showTargetRAircraft(data) {
+      const targetData = data.targetAircraft[0];
+      this.targetTotal = targetData.aircrafts.length;
+      // 还没有真实数据时,先初始化数据。
+      if (this.targetDataR.length === 0) {
+        const targetTexture = new PIXI.Texture.from(
           "../../textures/uav-tar.png"
         );
         for (let i = 0; i < this.targetTotal; i++) {
-          this.allId.push(data.targetAircraft[0].aircrafts[i].aircraftNumber);
+          this.allId.push(targetData.aircrafts[i].aircraftNumber);
           const group = new PIXI.Container();
-          group.id = data.targetAircraft[0].aircrafts[i].aircraftNumber;
+          group.id = targetData.aircrafts[i].aircraftNumber;
           group.buttonMode = true; // 鼠标悬停时显示手型
           group.interactive = true;
           // 创建无人机
-          const dude = new PIXI.Sprite(this.targetTexture);
+          const dude = new PIXI.Sprite(targetTexture);
           dude.anchor.set(0.5, 0.5);
           dude.scale.set(0.04);
 
-          dude.x = data.targetAircraft[0].aircrafts[i].coordinateX;
-          dude.y = data.targetAircraft[0].aircrafts[i].coordinateY;
-          const eastSpeed = data.targetAircraft[0].aircrafts[i].eastSpeed;
-          const northSpeed = data.targetAircraft[0].aircrafts[i].northSpeed;
-          dude.rotation = Math.atan2(northSpeed, eastSpeed);
+          dude.x = targetData.aircrafts[i].coordinateX;
+          dude.y = targetData.aircrafts[i].coordinateY;
 
-          dude.id = data.targetAircraft[0].aircrafts[i].aircraftNumber; // 分配唯一编号
-          this.targetUavAry.push(dude);
-
-          // 创建模糊滤镜
-          const blurFilter = new PIXI.filters.BlurFilter();
-          blurFilter.blur = 20;
-          dude.filters = [blurFilter];
+          dude.id = targetData.aircrafts[i].aircraftNumber; // 分配唯一编号
+          this.targetDataR.push(dude);
           group.addChild(dude);
 
-          // 创建圆圈
-          // 圆圈相对于飞机的位置
+          // 创建圆圈  圆圈相对于飞机的位置
           const cx = dude.x - 25;
           const cy = dude.y - 17;
 
@@ -1240,18 +1431,14 @@ export default {
           circle.y = cy;
           this.targetUavCircle.push(circle);
           group.addChild(circle);
-          // this.pixiApp.stage.addChild(circle);
 
           //编号-数字
-          const text = new PIXI.Text(
-            data.targetAircraft[0].aircrafts[i].aircraftNumber,
-            {
-              fontFamily: "Arial",
-              fontSize: 12,
-              fill: 0xffffff,
-              align: "center",
-            }
-          );
+          const text = new PIXI.Text(targetData.aircrafts[i].aircraftNumber, {
+            fontFamily: "Arial",
+            fontSize: 12,
+            fill: 0xffffff,
+            align: "center",
+          });
           text.anchor.set(0.5);
           // 计算文字位置以便在圆形内居中
           text.x = cx;
@@ -1263,26 +1450,38 @@ export default {
             this.hideSprite(group);
           });
           this.pixiApp.stage.addChild(group);
-          if (data.targetAircraft[0].aircrafts[i].piloted) {
-            const point = { x: dude.x, y: dude.y };
-            this.targetUavPath.push(point);
-            this.curLongitude = data.targetAircraft[0].aircrafts[i].longitude;
-            this.curLatitude = data.targetAircraft[0].aircrafts[i].latitude;
-            this.curAltitude = data.targetAircraft[0].aircrafts[i].altitude;
+
+          // 创建路径
+          const pathGraphics = new PIXI.Graphics();
+          pathGraphics.lineStyle(1, 0xeeee00, 1);
+          const point = { x: dude.x, y: dude.y };
+          pathGraphics.id = targetData.aircrafts[i].aircraftNumber;
+          this.pathGraphicsPointList.push(point);
+          // pathGraphics.moveTo(dude.x, dude.y);
+          // pathGraphics.lineTo(dude.x, dude.y);
+
+          this.pathGraphicsList.push(pathGraphics);
+          this.pixiApp.stage.addChild(pathGraphics);
+
+          if (targetData.aircrafts[i].piloted) {
+            // const point = { x: dude.x, y: dude.y };
+            // this.targetUavPath.push(point);
+            // 领航飞机的位置,在转换队形时有用到
+            this.curLongitude = targetData.aircrafts[i].longitude;
+            this.curLatitude = targetData.aircrafts[i].latitude;
+            this.curAltitude = targetData.aircrafts[i].altitude;
           }
         }
       } else {
-        for (let i = 0; i < this.targetUavAry.length; i++) {
-          const targetUav = this.targetUavAry[i];
+        // 每次更新
+        for (let i = 0; i < this.targetDataR.length; i++) {
+          const targetUav = this.targetDataR[i];
 
           targetUav.x = data.targetAircraft[0].aircrafts[i].coordinateX;
           targetUav.y = data.targetAircraft[0].aircrafts[i].coordinateY;
           const eastSpeed = data.targetAircraft[0].aircrafts[i].eastSpeed;
           const northSpeed = data.targetAircraft[0].aircrafts[i].northSpeed;
-          // targetUav.rotation = Math.atan2(northSpeed, eastSpeed) + Math.PI / 2;
           targetUav.rotation = Math.atan2(northSpeed, eastSpeed);
-          // const rotation = Math.atan2(eastSpeed, northSpeed);
-          // targetUav.rotation = (-rotation + 2 * Math.PI) % (2 * Math.PI);
 
           const cx = targetUav.x - 25;
           const cy = targetUav.y - 17;
@@ -1295,13 +1494,12 @@ export default {
           text.x = cx;
           text.y = cy;
 
-          if (data.targetAircraft[0].aircrafts[i].piloted) {
-            const point = { x: targetUav.x, y: targetUav.y };
-            this.targetUavPath.push(point);
-            this.curLongitude = data.targetAircraft[0].aircrafts[i].longitude;
-            this.curLatitude = data.targetAircraft[0].aircrafts[i].latitude;
-            this.curAltitude = data.targetAircraft[0].aircrafts[i].altitude;
+          if (this.cycleCount % this.updatePathFlag == 0) {
+            // 更新路径绘制
+            this.updatePath(i, targetUav.x, targetUav.y);
+          }
 
+          if (data.targetAircraft[0].aircrafts[i].piloted) {
             const viewSprite = this.pixiApp.stage.children.find((item) => {
               return (
                 item.id == data.targetAircraft[0].aircrafts[i].aircraftNumber
@@ -1327,27 +1525,24 @@ export default {
             }
           }
         }
+        this.cycleCount++;
       }
       if (data.targetAircraft != null) {
         for (let i = 0; i < this.targetTotal; i++) {
-          const id = data.targetAircraft[0].aircrafts[i].aircraftNumber;
+          const id = targetData.aircrafts[i].aircraftNumber;
           let findItem = this.changeShowNoList.find((item) => item.id == id);
           // 多目标集群信息显示
           const lbl = {
             id: id,
             showNo: findItem
               ? findItem.showNo
-              : data.targetAircraft[0].aircrafts[i].aircraftNumber,
-            longitude: data.targetAircraft[0].aircrafts[i].longitude.toFixed(7),
-            latitude: data.targetAircraft[0].aircrafts[i].latitude.toFixed(7),
-            altitude: data.targetAircraft[0].aircrafts[i].altitude + " m",
-            eastSpeed:
-              data.targetAircraft[0].aircrafts[i].eastSpeed.toFixed(1) + " m/s",
-            northSpeed:
-              data.targetAircraft[0].aircrafts[i].northSpeed.toFixed(1) +
-              " m/s",
-            skySpeed:
-              data.targetAircraft[0].aircrafts[i].skySpeed.toFixed(1) + " m/s",
+              : targetData.aircrafts[i].aircraftNumber,
+            longitude: targetData.aircrafts[i].longitude.toFixed(7),
+            latitude: targetData.aircrafts[i].latitude.toFixed(7),
+            altitude: targetData.aircrafts[i].altitude + " m",
+            eastSpeed: targetData.aircrafts[i].eastSpeed.toFixed(1) + " m/s",
+            northSpeed: targetData.aircrafts[i].northSpeed.toFixed(1) + " m/s",
+            skySpeed: targetData.aircrafts[i].skySpeed.toFixed(1) + " m/s",
           };
           if (this.targetLblAry.length === 0) {
             this.targetLblAry.push(lbl);
@@ -1356,14 +1551,85 @@ export default {
           }
         }
       }
-      if (this.cycleCount % this.updatePathFlag == 0) {
-        // 更新路径绘制
-        this.updatePath();
+    },
+
+    // 无人机集群 噪音数据
+    showTargetNAircraft(data) {
+      const targetData = data.targetAircraft[0];
+      this.targetTotal = targetData.aircrafts.length;
+      // 还没有真实数据时,先初始化数据。
+      if (this.targetDataN.length === 0) {
+        const targetTexture = new PIXI.Texture.from("../../textures/bunny.png");
+        for (let i = 0; i < this.targetTotal; i++) {
+          const group = new PIXI.Container();
+          group.id = targetData.aircrafts[i].aircraftNumber;
+          group.interactive = true;
+          // 创建无人机
+          const dude = new PIXI.Sprite(targetTexture);
+          dude.anchor.set(0.5, 0.5);
+          dude.scale.set(0.04);
+
+          dude.x = targetData.aircrafts[i].coordinateX;
+          dude.y = targetData.aircrafts[i].coordinateY;
+
+          dude.id = targetData.aircrafts[i].aircraftNumber; // 分配唯一编号
+          this.targetDataN.push(dude);
+          group.addChild(dude);
+
+          // 创建圆圈  圆圈相对于飞机的位置
+          const cx = dude.x - 25;
+          const cy = dude.y - 17;
+
+          //编号-圆圈
+          const circle = new PIXI.Graphics();
+          circle.beginFill(0xff0000); // 红色
+          circle.drawCircle(0, 0, 8);
+          circle.endFill();
+          circle.x = cx;
+          circle.y = cy;
+          this.targetUavCircleN.push(circle);
+          group.addChild(circle);
+
+          //编号-数字
+          const text = new PIXI.Text(targetData.aircrafts[i].aircraftNumber, {
+            fontFamily: "Arial",
+            fontSize: 12,
+            fill: 0xffffff,
+            align: "center",
+          });
+          text.anchor.set(0.5);
+          // 计算文字位置以便在圆形内居中
+          text.x = cx;
+          text.y = cy;
+          this.targetUavCircleNumN.push(text);
+          group.addChild(text);
+          this.pixiApp.stage.addChild(group);
+        }
+      } else {
+        // 每次更新
+        for (let i = 0; i < this.targetDataN.length; i++) {
+          const targetUav = this.targetDataN[i];
+
+          targetUav.x = data.targetAircraft[0].aircrafts[i].coordinateX;
+          targetUav.y = data.targetAircraft[0].aircrafts[i].coordinateY;
+          const eastSpeed = data.targetAircraft[0].aircrafts[i].eastSpeed;
+          const northSpeed = data.targetAircraft[0].aircrafts[i].northSpeed;
+          targetUav.rotation = Math.atan2(northSpeed, eastSpeed);
+
+          const cx = targetUav.x - 25;
+          const cy = targetUav.y - 17;
+
+          const circle = this.targetUavCircleN[i];
+          circle.x = cx;
+          circle.y = cy;
+
+          const text = this.targetUavCircleNumN[i];
+          text.x = cx;
+          text.y = cy;
+        }
       }
-      this.cycleCount++;
-      // 更新位置
-      //this.updatePosition();
     },
+
     // 飞机的显示与隐藏
     hideSprite(group) {
       this.hideList.push(group.id);
@@ -1419,38 +1685,23 @@ export default {
       this.pixiApp.stage.addChild(this.planeSprite);
     },
     // 更新飞行路径
-    updatePath() {
-      this.pathGraphics.lineStyle(1, 0xeeee00, 1);
-      if (this.targetUavPath.length <= 1) {
-        const firstData = this.targetUavPath[this.targetUavPath.length - 1];
-        this.lastPosition = firstData;
-        this.pathGraphics.moveTo(firstData.x, firstData.y);
-      } else {
-        this.pathGraphics.moveTo(this.lastPosition.x, this.lastPosition.y);
-        const nextPos = this.targetUavPath[this.targetUavPath.length - 1];
-        this.pathGraphics.lineTo(nextPos.x, nextPos.y);
-        this.lastPosition = nextPos;
-      }
-
-      // 之前的
-      // if (this.targetUavPath.length > 1) {
-      //   this.pathGraphics.moveTo(
-      //     this.targetUavPath[0].x,
-      //     this.targetUavPath[0].y
-      //   );
-
-      //   // 使用曲线平滑路径
-      //   this.targetUavPath.forEach((point, index) => {
-      //     if (index > 0) {
-      //       const prev = this.targetUavPath[index - 1];
-      //       this.pathGraphics.quadraticCurveTo(
-      //         prev.x,
-      //         prev.y,
-      //         (prev.x + point.x) / 2,
-      //         (prev.y + point.y) / 2
-      //       );
-      //     }
-      //   });
+    updatePath(index, x, y) {
+      const lastPointX = this.pathGraphicsPointList[index].x;
+      const lastPointY = this.pathGraphicsPointList[index].y;
+      this.pathGraphicsList[index].moveTo(lastPointX, lastPointY);
+      this.pathGraphicsList[index].lineTo(x, y);
+      this.pathGraphicsPointList[index].x = x;
+      this.pathGraphicsPointList[index].y = y;
+      // this.pathGraphics.lineStyle(1, 0xeeee00, 1);
+      // if (this.targetUavPath.length <= 1) {
+      //   const firstData = this.targetUavPath[this.targetUavPath.length - 1];
+      //   this.lastPosition = firstData;
+      //   this.pathGraphics.moveTo(firstData.x, firstData.y);
+      // } else {
+      //   this.pathGraphics.moveTo(this.lastPosition.x, this.lastPosition.y);
+      //   const nextPos = this.targetUavPath[this.targetUavPath.length - 1];
+      //   this.pathGraphics.lineTo(nextPos.x, nextPos.y);
+      //   this.lastPosition = nextPos;
       // }
     },