From 75aeb4e63339b60f9559af984c7d9f87a7cba24a Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期四, 09 五月 2024 17:40:47 +0800
Subject: [PATCH] 轨迹动画和任务管理

---
 src/utils/map/animation.js                        |   22 
 src/views/historymode/HistoryMode.vue             |   29 
 src/components/mission/MIssionCreate.vue          |   74 +++
 src/api/missionApi.js                             |    9 
 src/components.d.ts                               |    6 
 src/components/animation/TrajectoryState.vue      |   31 +
 src/components/mission/MissionManage.vue          |  148 +++++++
 src/views/HomePage.vue                            |   12 
 src/components/CardDialog.vue                     |   45 ++
 src/components/animation/HistoricalTrajectory.vue |   64 +++
 src/components/mission/MissionImport.vue          |    0 
 src/composables/formConfirm.js                    |  156 ++++++++
 src/components/map/MapToolbox.vue                 |    8 
 src/components/core/CoreMenu.vue                  |    9 
 src/stores/map-animation.js                       |   19 +
 src/utils/expand/expand.js                        |   26 +
 src/api/index.js                                  |    1 
 src/components/map/BaseMap.vue                    |   11 
 src/main.js                                       |    5 
 src/utils/map/sector.js                           |  432 +++++++++++----------
 src/components/search/OptionMission.vue           |    6 
 src/stores/mission.js                             |    9 
 src/components/core/CoreHeader.vue                |   10 
 src/model/FrameAnimation.js                       |    4 
 24 files changed, 879 insertions(+), 257 deletions(-)

diff --git a/src/api/index.js b/src/api/index.js
index 30f3296..21205a1 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -4,6 +4,7 @@
 const debug = false;
 
 let ip1 = 'http://114.215.109.124:8805/';
+// let ip1 = 'http://47.100.191.150:9029/';
 
 if (debug) {
   ip1 = 'http://192.168.0.138:8082/';
diff --git a/src/api/missionApi.js b/src/api/missionApi.js
index e07e9fe..af08c4d 100644
--- a/src/api/missionApi.js
+++ b/src/api/missionApi.js
@@ -8,5 +8,14 @@
     let params = `page=${page}&perPage=${pageSize}`;
     params += type ? `&type=${type}` : '';
     return $http.get(`air/mission/type?${params}`).then((res) => res.data);
+  },
+
+  putNewMission(mission) {
+    return $http.post(`air/mission/create`, mission).then((res) => res.data);
+  },
+
+  deleteMission(missionCode) {
+    let params = `missionCode=${missionCode}`;
+    return $http.post(`air/mission/delete?${params}`).then((res) => res.data);
   }
 };
diff --git a/src/components.d.ts b/src/components.d.ts
index 008a148..6880056 100644
--- a/src/components.d.ts
+++ b/src/components.d.ts
@@ -10,6 +10,7 @@
     BaseCard: typeof import('./components/BaseCard.vue')['default']
     BaseMap: typeof import('./components/map/BaseMap.vue')['default']
     CardButton: typeof import('./components/CardButton.vue')['default']
+    CardDialog: typeof import('./components/CardDialog.vue')['default']
     CoreHeader: typeof import('./components/core/CoreHeader.vue')['default']
     CoreMenu: typeof import('./components/core/CoreMenu.vue')['default']
     DataSummary: typeof import('./components/monitor/DataSummary.vue')['default']
@@ -20,6 +21,7 @@
     ElCol: typeof import('element-plus/es')['ElCol']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+    ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
     ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
     ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
@@ -42,6 +44,9 @@
     HistoricalTrajectory: typeof import('./components/animation/HistoricalTrajectory.vue')['default']
     LineChart: typeof import('./components/monitor/LineChart.vue')['default']
     MapToolbox: typeof import('./components/map/MapToolbox.vue')['default']
+    MIssionCreate: typeof import('./components/mission/MIssionCreate.vue')['default']
+    MissionImport: typeof import('./components/mission/MissionImport.vue')['default']
+    MissionManage: typeof import('./components/mission/MissionManage.vue')['default']
     OptionDevice: typeof import('./components/search/OptionDevice.vue')['default']
     OptionMission: typeof import('./components/search/OptionMission.vue')['default']
     OptionTime: typeof import('./components/search/OptionTime.vue')['default']
@@ -50,6 +55,7 @@
     RouterView: typeof import('vue-router')['RouterView']
     SearchBar: typeof import('./components/search/SearchBar.vue')['default']
     SliderBar: typeof import('./components/SliderBar.vue')['default']
+    TrajectoryState: typeof import('./components/animation/TrajectoryState.vue')['default']
   }
   export interface ComponentCustomProperties {
     vLoading: typeof import('element-plus/es')['ElLoadingDirective']
diff --git a/src/components/CardDialog.vue b/src/components/CardDialog.vue
new file mode 100644
index 0000000..26608bc
--- /dev/null
+++ b/src/components/CardDialog.vue
@@ -0,0 +1,45 @@
+<template>
+  <el-dialog
+    :model-value="modelValue"
+    @update-modelvalue="handleChange"
+    :show-close="false"
+    align-center
+  >
+    <template #header="{ close, titleId, titleClass }">
+      <BaseCard direction="top-left" borderless="t">
+        <template #content>
+          <el-row justify="space-between" align="middle">
+            <el-row align="middle">
+              <font-awesome-icon icon="fa fa-list" class="m-r-4" />
+              <span :id="titleId" :class="titleClass">{{ title }}</span>
+            </el-row>
+            <font-awesome-icon
+              icon="fa fa-times"
+              class="cursor-p m-r-4"
+              @click="close"
+            />
+          </el-row>
+        </template>
+      </BaseCard>
+    </template>
+    <BaseCard size="medium">
+      <template #content>
+        <slot></slot>
+      </template>
+    </BaseCard>
+  </el-dialog>
+</template>
+<script>
+export default {
+  props: {
+    title: String,
+    modelValue: Boolean
+  },
+  emits: ['update:modelValue'],
+  methods: {
+    handleChange(value) {
+      this.$emit('update:modelValue', value);
+    }
+  }
+};
+</script>
diff --git a/src/components/animation/HistoricalTrajectory.vue b/src/components/animation/HistoricalTrajectory.vue
index e2e50bf..3224b43 100644
--- a/src/components/animation/HistoricalTrajectory.vue
+++ b/src/components/animation/HistoricalTrajectory.vue
@@ -17,7 +17,7 @@
         </div>
         <div class="label-date margin-left-2">
           <span class="label-date-title">鍊嶉��</span>
-          <el-select v-model="speed" size="small" class="w-80">
+          <el-select v-model="speed" size="small" class="w-60">
             <el-option label="1.0X" :value="1" />
             <el-option label="4.0X" :value="4" />
             <el-option label="8.0X" :value="8" />
@@ -29,15 +29,37 @@
   </BaseCard>
 </template>
 <script>
+import { mapActions } from 'pinia';
+import { MapAnimation } from '@/utils/map/animation';
+import { FactorDatas } from '@/model/FactorDatas';
+import { useMapAnimationStore } from '@/stores/map-animation';
+
+const mapAnimation = new MapAnimation();
+
 export default {
-  props: {},
-  emits: ['change'],
+  props: {
+    factorDatas: FactorDatas,
+    factorType: String
+  },
+  emits: ['change', 'stop'],
   data() {
     return {
       speed: 1,
       // 鍔ㄧ敾鐘舵�侊紝0锛氬仠姝紱1锛氭挱鏀撅紱2锛氭殏鍋�
       status: 0
     };
+  },
+  watch: {
+    speed(nV, oV) {
+      if (nV != oV) {
+        this.changeSpeed(nV);
+      }
+    },
+    factorType(nV, oV) {
+      if (nV != oV) {
+        mapAnimation.setFactorType(nV);
+      }
+    }
   },
   computed: {
     btnStop() {
@@ -53,26 +75,58 @@
     }
   },
   methods: {
+    ...mapActions(useMapAnimationStore, ['start', 'pause', 'stop']),
     handleStop() {
       if (this.status != 0) {
         this.status = 0;
+        this.stopAnimation();
         this.handleChange();
       }
     },
     handlePlayOrPause() {
       if (this.status == 1) {
         this.status = 2;
+        this.pauseAnimation();
       } else {
         this.status = 1;
+        this.startAnimation();
       }
       this.handleChange();
     },
     handleChange() {
-      console.log(this.status);
       this.$emit('change', this.status);
+    },
+
+    newTimeTask() {
+      mapAnimation.setDynamicSpeed(false); //鍏抽棴鍔ㄦ�佺粯鍒堕�熷害璋冩暣
+      mapAnimation.moveAnimation(this.factorDatas, this.factorType);
+    },
+    startAnimation() {
+      this.changeSpeed(this.speed);
+      if (!mapAnimation.runStatus()) {
+        this.newTimeTask();
+      } else {
+        mapAnimation.start();
+      }
+      this.start();
+    },
+    changeSpeed(speed) {
+      mapAnimation.changeSpeed(speed);
+    },
+    pauseAnimation() {
+      mapAnimation.pause();
+      this.pause();
+    },
+    stopAnimation() {
+      mapAnimation.stop();
+      this.stop();
     }
   },
-  mounted() {}
+  mounted() {
+    mapAnimation.setOnStopCallback(() => {
+      this.$emit('stop');
+    });
+  }
 };
 </script>
 <style scoped>
diff --git a/src/components/animation/TrajectoryState.vue b/src/components/animation/TrajectoryState.vue
new file mode 100644
index 0000000..749cc09
--- /dev/null
+++ b/src/components/animation/TrajectoryState.vue
@@ -0,0 +1,31 @@
+<template>
+  <BaseCard size="middle-s" direction="down">
+    <template #content>
+      <span style="margin: 36px; font-size: large">{{ stateText }}</span>
+    </template>
+  </BaseCard>
+</template>
+<script>
+export default {
+  props: {
+    status: {
+      type: Number,
+      default: 0
+    }
+  },
+  computed: {
+    stateText() {
+      switch (this.status) {
+        case 0:
+          return '杞ㄨ抗鍔ㄧ敾宸插仠姝�';
+        case 1:
+          return '杞ㄨ抗鍔ㄧ敾鎾斁涓�...';
+        case 2:
+          return '杞ㄨ抗鍔ㄧ敾宸叉殏鍋�';
+        default:
+          return '杞ㄨ抗鍔ㄧ敾宸插仠姝�';
+      }
+    }
+  }
+};
+</script>
diff --git a/src/components/core/CoreHeader.vue b/src/components/core/CoreHeader.vue
index 381807a..f3e83a5 100644
--- a/src/components/core/CoreHeader.vue
+++ b/src/components/core/CoreHeader.vue
@@ -1,6 +1,6 @@
 <template>
-  <div class="map-title ff-title flexbox-col align-items p-events-auto">
-    <div class="map-title-content">
+  <div class="map-title ff-title flexbox-col align-items">
+    <div class="map-title-content p-events-auto">
       <div class="ff-border-bottom"></div>
       <div class="ff-border-top">
         <div class="ff-border-content flexbox-col align-items">
@@ -25,4 +25,8 @@
   methods: {}
 };
 </script>
-<style scoped></style>
+<style scoped>
+.map-title {
+  /* background-color: aliceblue; */
+}
+</style>
diff --git a/src/components/core/CoreMenu.vue b/src/components/core/CoreMenu.vue
index a88e8cc..58050a8 100644
--- a/src/components/core/CoreMenu.vue
+++ b/src/components/core/CoreMenu.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="map-mode-change p-events-auto">
+  <div v-show="status == 0" class="map-mode-change p-events-auto">
     <template v-for="(item, index) in menu" :key="item.path">
       <a :class="btnClz(item.selected)" @click="navTo(index)">
         <div>{{ item.name }}</div>
@@ -41,6 +41,9 @@
 </template>
 
 <script>
+import { mapState } from 'pinia';
+import { useMapAnimationStore } from '@/stores/map-animation';
+
 export default {
   data() {
     return {
@@ -69,7 +72,9 @@
       ]
     };
   },
-  computed: {},
+  computed: {
+    ...mapState(useMapAnimationStore, ['status'])
+  },
   methods: {
     btnClz(selected) {
       return (
diff --git a/src/components/map/BaseMap.vue b/src/components/map/BaseMap.vue
index 64f2e53..2da91ff 100644
--- a/src/components/map/BaseMap.vue
+++ b/src/components/map/BaseMap.vue
@@ -29,4 +29,15 @@
   display: none;
   opacity: 0 !important;
 }
+
+.amap-marker-label {
+  font-size: 13px;
+  text-align: center;
+  color: white;
+  background-color: transparent;
+  text-shadow: black 2px 2px 2px;
+  border-radius: 2px;
+  border: 0px;
+  padding: 4px;
+}
 </style>
diff --git a/src/components/map/MapToolbox.vue b/src/components/map/MapToolbox.vue
index 270e612..0b0db4d 100644
--- a/src/components/map/MapToolbox.vue
+++ b/src/components/map/MapToolbox.vue
@@ -1,6 +1,6 @@
 <template>
   <el-dropdown
-    class="p-events-auto dropdown-wrap"
+    class="p-events-auto"
     trigger="click"
     size="small"
     @command="handleCommand"
@@ -103,12 +103,6 @@
 </script>
 
 <style scoped>
-.dropdown-wrap {
-  position: absolute;
-  top: 10px;
-  left: 2px;
-}
-
 .el-button {
   margin: initial !important;
 }
diff --git a/src/components/mission/MIssionCreate.vue b/src/components/mission/MIssionCreate.vue
new file mode 100644
index 0000000..247fe32
--- /dev/null
+++ b/src/components/mission/MIssionCreate.vue
@@ -0,0 +1,74 @@
+<template>
+  <el-button
+    type="primary"
+    class="el-button-custom"
+    @click="dialogVisible = !dialogVisible"
+  >
+    鏂板缓浠诲姟
+  </el-button>
+  <CardDialog v-model="dialogVisible" title="鏂板缓璧拌埅浠诲姟">
+    <el-form
+      :inline="false"
+      :model="formObj"
+      ref="formRef"
+      :rules="rules"
+      label-position="right"
+      label-width="150px"
+    >
+      <slot name="form-item" :formObj="formObj"></slot>
+      <el-form-item>
+        <el-button
+          :disabled="!edit"
+          type="primary"
+          @click="onSubmit"
+          :loading="loading"
+          >鎻愪氦</el-button
+        >
+        <el-button v-if="useCancel" @click="onCancel">鍙栨秷</el-button>
+      </el-form-item>
+    </el-form>
+  </CardDialog>
+</template>
+<script setup>
+import { onActivated, onDeactivated, ref, reactive, watch } from 'vue';
+import missionApi from '@/api/missionApi';
+import { useFormConfirm } from '@/composables/formConfirm';
+import { useFetchData } from '@/composables/fetchData';
+
+const dialogVisible = ref(false);
+const { loading, fetchData } = useFetchData();
+const baseRules = reactive({
+  _usertype: [
+    {
+      required: true,
+      message: '鐢ㄦ埛绫诲瀷涓嶈兘涓虹┖',
+      trigger: 'change'
+    }
+  ],
+  _locations: [
+    {
+      required: true,
+      message: '琛屾斂鍖哄垝涓嶈兘涓虹┖',
+      trigger: 'change'
+    }
+  ],
+  _scenetype: [
+    {
+      required: true,
+      message: '鍦烘櫙绫诲瀷涓嶈兘涓虹┖',
+      trigger: 'change'
+    }
+  ]
+});
+// 鍒涘缓浠诲姟
+function createMission() {}
+const { formObj, formRef, edit, onSubmit, onCancel, onReset, clear } =
+  useFormConfirm({
+    submit: {
+      do: createMission
+    },
+    cancel: {
+      do: () => (dialogVisible.value = false)
+    }
+  });
+</script>
diff --git a/src/components/mission/MissionImport.vue b/src/components/mission/MissionImport.vue
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/components/mission/MissionImport.vue
diff --git a/src/components/mission/MissionManage.vue b/src/components/mission/MissionManage.vue
new file mode 100644
index 0000000..124400a
--- /dev/null
+++ b/src/components/mission/MissionManage.vue
@@ -0,0 +1,148 @@
+<template>
+  <el-button
+    type="primary"
+    icon="Memo"
+    class="el-button-custom p-events-auto"
+    @click="dialogVisible = !dialogVisible"
+  >
+    浠诲姟绠$悊
+  </el-button>
+  <el-dialog v-model="dialogVisible" :show-close="false" align-center>
+    <template #header="{ close, titleId, titleClass }">
+      <BaseCard direction="top-left" borderless="t">
+        <template #content>
+          <el-row justify="space-between" align="middle">
+            <el-row align="middle">
+              <font-awesome-icon icon="fa fa-list" class="m-r-4" />
+              <span :id="titleId" :class="titleClass">璧拌埅浠诲姟绠$悊</span>
+            </el-row>
+            <font-awesome-icon
+              icon="fa fa-times"
+              class="cursor-p m-r-4"
+              @click="close"
+            />
+          </el-row>
+        </template>
+      </BaseCard>
+    </template>
+    <BaseCard size="medium">
+      <template #content>
+        <el-row class="mission-table">
+          <el-col :span="20">
+            <el-table
+              :data="missionList"
+              table-layout="fixed"
+              size="small"
+              :show-overflow-tooltip="true"
+              border
+              row-class-name="t-row"
+              cell-class-name="t-cell"
+              header-row-class-name="t-header-row"
+              header-cell-class-name="t-header-cell"
+            >
+              <el-table-column
+                type="index"
+                label="搴忓彿"
+                align="center"
+                width="50"
+              />
+              <el-table-column
+                prop="missionCode"
+                label="浠诲姟缂栧彿"
+                align="center"
+              />
+              <el-table-column
+                prop="startTime"
+                label="寮�濮嬫椂闂�"
+                align="center"
+                :formatter="timeFormatter"
+              />
+              <el-table-column
+                prop="endTime"
+                label="缁撴潫鏃堕棿"
+                align="center"
+                :formatter="timeFormatter"
+              />
+              <el-table-column label="绠$悊" width="70" align="center">
+                <template #default="{ row }">
+                  <el-button
+                    type="primary"
+                    size="small"
+                    class="el-button-custom"
+                    @click="deleteMission(row)"
+                    >鍒犻櫎</el-button
+                  >
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-col>
+          <el-col :span="4" class="flex-col">
+            <div>
+              <el-button type="primary" class="el-button-custom">
+                鏂板缓浠诲姟
+              </el-button>
+            </div>
+            <div>
+              <el-button type="primary" class="el-button-custom">
+                鏁版嵁瀵煎叆
+              </el-button>
+            </div>
+            <div>
+              <el-button type="primary" class="el-button-custom">
+                涓嬭浇妯℃澘
+              </el-button>
+            </div>
+          </el-col>
+        </el-row>
+      </template>
+    </BaseCard>
+  </el-dialog>
+</template>
+<script>
+import moment from 'moment';
+import { mapState } from 'pinia';
+import { useMissionStore } from '@/stores/mission';
+
+export default {
+  props: {},
+  data() {
+    return {
+      dialogVisible: false
+    };
+  },
+  computed: {
+    ...mapState(useMissionStore, ['missionList'])
+  },
+  methods: {
+    createMission() {},
+    deleteMission(row) {},
+    timeFormatter(row, col, cellValue, index) {
+      return moment(cellValue).format('YYYY-MM-DD HH:mm:ss');
+    }
+  }
+};
+</script>
+<style>
+.el-dialog {
+  --el-dialog-bg-color: transparent !important;
+  --el-dialog-title-font-size: var(--el-font-size-medium);
+  --el-dialog-content-font-size: 14px;
+  --el-dialog-padding-primary: 0px !important;
+}
+
+.el-dialog__title {
+  color: var(--font-color);
+}
+</style>
+<style scoped>
+.flex-col {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+  align-items: flex-end;
+}
+
+.mission-table {
+  height: 60vh;
+}
+</style>
diff --git a/src/components/search/OptionMission.vue b/src/components/search/OptionMission.vue
index 8322c9d..5ac3d51 100644
--- a/src/components/search/OptionMission.vue
+++ b/src/components/search/OptionMission.vue
@@ -18,8 +18,10 @@
 </template>
 
 <script>
+import { mapStores } from 'pinia';
 import missionApi from '@/api/missionApi';
 import { useFetchData } from '@/composables/fetchData';
+import { useMissionStore } from '@/stores/mission';
 
 export default {
   setup() {
@@ -37,6 +39,9 @@
       index: undefined
     };
   },
+  computed: {
+    ...mapStores(useMissionStore)
+  },
   methods: {
     fetchMission() {
       this.fetchData((page, pageSize) => {
@@ -44,6 +49,7 @@
           .fethchMission({ type: this.type, page, pageSize })
           .then((res) => {
             this.missionList = res.data;
+            this.missionStore.missionList = res.data;
             // if (this.missionList.length > 0) {
             //   this.handleChange(0);
             // }
diff --git a/src/composables/formConfirm.js b/src/composables/formConfirm.js
new file mode 100644
index 0000000..430c790
--- /dev/null
+++ b/src/composables/formConfirm.js
@@ -0,0 +1,156 @@
+import { onActivated, onDeactivated, ref, watch } from 'vue';
+import { useCloned } from '@vueuse/core';
+// import { useMessageBoxTip, useMessageBox } from './messageBox';
+
+// 琛ㄥ崟鐨勭‘璁ゅ拰鍙栨秷
+export function useFormConfirm({
+  defaultForm = undefined,
+  submit = {
+    do: () => {}
+  },
+  cancel = {
+    do: () => {}
+  },
+  reset = {
+    do: () => {}
+  }
+}) {
+  if (!submit.title) submit.title = '鎻愪氦';
+  if (!submit.msg) submit.msg = '纭鏄惁鎻愪氦锛�';
+  if (!cancel.title) cancel.title = '鍙栨秷';
+  if (!cancel.msg) cancel.msg = '鏄惁鏀惧純宸茬紪杈戠殑鍐呭锛�';
+
+  // const formProps = defineProps({
+  //   // 鏄惁鍦ㄦ彁浜ゆ垚鍔熷悗娓呯┖琛ㄥ崟
+  //   clearAftSubmit: Boolean
+  // });
+
+  //琛ㄥ崟鍐呭
+  const formObj = ref(defaultForm ? defaultForm : {});
+  let formObjClone = useCloned(formObj, { manual: true });
+  //琛ㄥ崟缁勪欢寮曠敤
+  const formRef = ref(null);
+
+  // 琛ㄥ崟缂栬緫鐘舵��
+  const edit = ref(false);
+  let isReset = false;
+  const active = ref(true);
+
+  // 鑻ョ粍浠跺疄渚嬫槸 <KeepAlive> 缂撳瓨鏍戠殑涓�閮ㄥ垎锛屽綋缁勪欢琚彃鍏ュ埌 DOM 涓椂璋冪敤
+  onActivated(() => {
+    active.value = true;
+  });
+  // 鑻ョ粍浠跺疄渚嬫槸 <KeepAlive> 缂撳瓨鏍戠殑涓�閮ㄥ垎锛屽綋缁勪欢浠� DOM 涓绉婚櫎鏃惰皟鐢�
+  onDeactivated(() => {
+    active.value = false;
+  });
+
+  // 褰撹〃鍗曡鍙栨秷婵�娲诲悗锛屾竻绌鸿〃鍗曟暟鎹�
+  watch(active, (nValue) => {
+    if (!nValue) {
+      clear();
+    }
+  });
+
+  // 琛ㄥ崟琚慨鏀硅繃, 鏇存柊缂栬緫鐘舵��
+  watch(
+    formObj,
+    (nv, ov) => {
+      if (!isReset && nv != ov) {
+        formObjClone = useCloned(nv, { manual: true });
+      }
+      if (!isReset && nv === ov) {
+        edit.value = true;
+      }
+      isReset = false;
+    },
+    { deep: true }
+  );
+
+  // 閲嶇疆琛ㄥ崟
+  const _reset = function () {
+    formRef.value.clearValidate();
+    edit.value = false;
+    isReset = true;
+    formObj.value = useCloned(formObjClone.cloned, {
+      manual: true
+    }).cloned.value;
+  };
+
+  // 娓呯┖琛ㄥ崟
+  const clear = function () {
+    isReset = true;
+    formRef.value.resetFields();
+    edit.value = false;
+  };
+
+  // 鎻愪氦鎴愬姛鍚�
+  const submited = function () {
+    // if (formProps.clearAftSubmit) clear();
+    edit.value = false;
+    formObjClone = useCloned(formObj, { manual: true });
+  };
+
+  // 鎻愪氦琛ㄥ崟
+  const onSubmit = function (messageBox = true) {
+    formRef.value.validate(async (valid) => {
+      if (valid) {
+        if (messageBox) {
+          // useMessageBoxTip({
+          //   confirmMsg: submit.msg,
+          //   confirmTitle: submit.title,
+          //   onConfirm: async () => {
+          //     const res = await submit.do();
+          //     submited();
+          //     return res;
+          //   }
+          // });
+        } else {
+          await submit.do();
+          submited();
+        }
+      }
+    });
+  };
+
+  // 鍙栨秷鎻愪氦
+  const onCancel = function () {
+    if (edit.value) {
+      // 寮瑰嚭纭妗�
+      // useMessageBox({
+      //   confirmMsg: cancel.msg,
+      //   confirmTitle: cancel.title,
+      //   onConfirm: () => {
+      //     // clear();
+      //     return cancel.do();
+      //   }
+      // });
+    } else {
+      cancel.do();
+    }
+  };
+
+  // 閲嶇疆琛ㄥ崟
+  const onReset = function (tips) {
+    if (edit.value) {
+      if (tips) {
+        // 寮瑰嚭纭妗�
+        // useMessageBox({
+        //   confirmMsg: '鏄惁閲嶇疆琛ㄥ崟鍐呭锛�',
+        //   confirmTitle: '閲嶇疆琛ㄥ崟',
+        //   onConfirm: () => {
+        //     _reset();
+        //     return reset.do();
+        //   }
+        // });
+      } else {
+        _reset();
+        reset.do();
+      }
+    } else {
+      reset.do();
+    }
+  };
+
+  return { formObj, formRef, edit, onSubmit, onCancel, onReset, clear };
+}
diff --git a/src/main.js b/src/main.js
index d6c2bf4..06f7e7e 100644
--- a/src/main.js
+++ b/src/main.js
@@ -7,15 +7,14 @@
 import App from './App.vue';
 import router from './router';
 
+import './utils/expand/expand';
+
 /* import the fontawesome core */
 import { library } from '@fortawesome/fontawesome-svg-core';
 /* import font awesome icon component */
 import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
 /* import specific icons */
-// import { all } from '@awesome.me/kit-KIT_CODE/icons';
 import { fas } from '@fortawesome/free-solid-svg-icons';
-// import { faTwitter, faFontAwesome } from '@fortawesome/free-brands-svg-icons'
-// import { faTwitter, faFontAwesome } from '@fortawesome/free-regular-svg-icons'
 
 /* add icons to the library */
 library.add(fas);
diff --git a/src/model/FrameAnimation.js b/src/model/FrameAnimation.js
index ad4dd8c..b74d6d9 100644
--- a/src/model/FrameAnimation.js
+++ b/src/model/FrameAnimation.js
@@ -118,7 +118,9 @@
         if (this.isPause) {
           return;
         }
-        if (index >= t.count) {
+        // 缁樺埗3D鍥惧舰鏃讹紝鏈�灏戦渶瑕�2涓偣鎵嶅彲缁樺埗鍥惧舰
+        // 鍥犳姝ゅ绱㈠紩鍙埌鍊掓暟绗簩涓偣灏辩粨鏉�
+        if (index >= t.count - 1) {
           this._endTask(this.intervalFlag);
           return;
         }
diff --git a/src/stores/map-animation.js b/src/stores/map-animation.js
new file mode 100644
index 0000000..b8e906b
--- /dev/null
+++ b/src/stores/map-animation.js
@@ -0,0 +1,19 @@
+import { ref } from 'vue';
+import { defineStore } from 'pinia';
+
+export const useMapAnimationStore = defineStore('mapAnimation', () => {
+  // // 鍔ㄧ敾鐘舵�侊紝0锛氬仠姝紱1锛氭挱鏀撅紱2锛氭殏鍋�
+  const status = ref(0);
+
+  function start() {
+    status.value = 1;
+  }
+  function pause() {
+    status.value = 2;
+  }
+  function stop() {
+    status.value = 0;
+  }
+
+  return { status, start, pause, stop };
+});
diff --git a/src/stores/mission.js b/src/stores/mission.js
new file mode 100644
index 0000000..cb79aa8
--- /dev/null
+++ b/src/stores/mission.js
@@ -0,0 +1,9 @@
+import { ref } from 'vue';
+import { defineStore } from 'pinia';
+
+// 璧拌埅浠诲姟
+export const useMissionStore = defineStore('mission', () => {
+  const missionList = ref([]);
+
+  return { missionList };
+});
diff --git a/src/utils/expand/expand.js b/src/utils/expand/expand.js
new file mode 100644
index 0000000..6495211
--- /dev/null
+++ b/src/utils/expand/expand.js
@@ -0,0 +1,26 @@
+Date.prototype.format = function (fmt) {
+  var o = {
+    'M+': this.getMonth() + 1, //鏈堜唤
+    'd+': this.getDate(), //鏃�
+    'h+': this.getHours(), //灏忔椂
+    'm+': this.getMinutes(), //鍒�
+    's+': this.getSeconds(), //绉�
+    'q+': Math.floor((this.getMonth() + 3) / 3), //瀛e害
+    S: this.getMilliseconds() //姣
+  };
+  if (/(y+)/.test(fmt)) {
+    fmt = fmt.replace(
+      RegExp.$1,
+      (this.getFullYear() + '').substr(4 - RegExp.$1.length)
+    );
+  }
+  for (var k in o) {
+    if (new RegExp('(' + k + ')').test(fmt)) {
+      fmt = fmt.replace(
+        RegExp.$1,
+        RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
+      );
+    }
+  }
+  return fmt;
+};
diff --git a/src/utils/map/animation.js b/src/utils/map/animation.js
index ab13719..05c8ba7 100644
--- a/src/utils/map/animation.js
+++ b/src/utils/map/animation.js
@@ -3,7 +3,7 @@
 import Layer from '@/utils/map/3dLayer';
 import sector from '@/utils/map/sector';
 import { map } from '@/utils/map/index_old';
-import util from "@/utils/map/util";
+import util from '@/utils/map/util';
 import car_driving from '@/assets/mipmap/car_driving.png';
 import boat_driving from '@/assets/mipmap/boat_driving.png';
 
@@ -11,7 +11,7 @@
   // 闈炶繛缁潗鏍囩偣鏈�澶ц窛绂�(绫�)
   this.maxD = 500;
   // 褰撳墠缁樺埗鐨勭洃娴嬪洜瀛愮被鍨�
-  this.factorType = 0;
+  this.factorType;
   this.factorDatas;
   // 杞藉叿绫诲瀷
   this.vehicleType = 0; // 0: 杞﹁締锛�1锛氭棤浜烘満锛�2锛氭棤浜鸿埞
@@ -116,7 +116,7 @@
       var fData2 = factorDatas.getByIndex(i + 1, i + 2);
 
       // 璁$畻鍔ㄧ敾杞ㄨ抗
-      for (let i = 0; i < count - 1; i++) {
+      for (let i = 0; i < count; i++) {
         // path
         var length = d * (i + 1);
         if (isNaN(angle)) {
@@ -149,26 +149,16 @@
         animationData,
         function (data, index, count) {
           var length = data.length();
-          var start = length - count + 1;
+          var start = length - count;
           // 1.鑾峰彇鏁版嵁
           var d = data.getByIndex(0, start + index + 1);
-          var f = d.factor[that.factorType + 1 + ''];
+          var f = d.factor[that.factorType];
           // 2.缁樺埗鍥惧舰
           if (length > count || index > 0) {
             // 3d鍥惧舰
-            // var lnglat = d.lnglats_GD[d.lnglats_GD.length - 1];
             Layer.drawMesh(d, f);
-            // MapUtil.drawLine(lnglat)
-
             // 椋庡悜椋庨��
-            sector.drawSector(d, start + index);
-            // if (d.factor['17'] != undefined && d.factor['16'] != undefined) {
-            //   var windDir = d.factor['17'].datas;
-            //   windDir = windDir[windDir.length - 1].factorData;
-            //   var windSpeed = d.factor['16'].datas;
-            //   windSpeed = windSpeed[windSpeed.length - 1].factorData;
-            //   MapUtil.drawSector4(lnglat, windDir, windSpeed);
-            // }
+            sector.drawSectorAna(d, start + index);
           }
 
           var pos = d.lnglats_GD[d.lnglats_GD.length - 1];
diff --git a/src/utils/map/sector.js b/src/utils/map/sector.js
index f2aa490..0e3ced6 100644
--- a/src/utils/map/sector.js
+++ b/src/utils/map/sector.js
@@ -4,229 +4,247 @@
 
 var _defaultDeg = 30,
   _sector = undefined,
-  _sectorViews = {};
+  _sectorViews = new Map(),
+  // 鍔ㄧ敾杞ㄨ抗
+  _sectorViewsAna = new Map();
+
+const zoomStyleMapping = {
+  14: 0,
+  15: 0,
+  16: 0,
+  17: 0,
+  18: 0,
+  19: 0,
+  20: 0
+};
+
+function sectorParams(fDatas, i) {
+  const lnglat = fDatas.lnglats_GD[i];
+  let windDir = fDatas.factor[17].datas[i].factorData;
+  let windSpeed = fDatas.factor[16].datas[i].factorData;
+  if (!windDir) windDir = 0;
+  if (!windSpeed) windSpeed = 0;
+
+  // if (windSpeed > 10) {
+  //   return;
+  // }
+
+  var sDeg = windDir - _defaultDeg; //鎵囧舰璧峰瑙掑害锛堜互涓婃柟浣滀负0搴︼級
+  // sDeg = sDeg < 0 ? sDeg + 360 : sDeg
+  var eDeg = windDir + _defaultDeg; //鎵囧舰缁撴潫瑙掑害
+  // eDeg = eDeg < 0 ? eDeg + 360 : eDeg
+
+  var distance = windSpeed * 10 * 60; //鍗婂緞(椋庨��*鏃堕棿)
+  var lnglat2 = calculate.getLatLon(lnglat, distance, sDeg);
+  var lnglat3 = calculate.getLatLon(lnglat, distance, windDir);
+  var lnglat4 = calculate.getLatLon(lnglat, distance, eDeg);
+  var list = calculate.parse2LngLat([lnglat, lnglat2, lnglat3, lnglat4]);
+
+  var distance2 = windSpeed * 5 * 60; //鍗婂緞(椋庨��*鏃堕棿)
+  var lnglat2_2 = calculate.getLatLon(lnglat, distance2, sDeg);
+  var lnglat2_3 = calculate.getLatLon(lnglat, distance2, windDir);
+  var lnglat2_4 = calculate.getLatLon(lnglat, distance2, eDeg);
+  var list2 = calculate.parse2LngLat([lnglat2_2, lnglat2_3, lnglat2_4]);
+
+  distance = distance.toFixed(0);
+  distance2 = distance2.toFixed(0);
+
+  return { sDeg, eDeg, lnglat, distance, distance2, list, list2 };
+}
+
+/**
+ * 鍙缉鏀剧殑鏍囪
+ * 鏃犳硶淇敼position锛堝畼缃戞湭鎵惧埌鐩稿叧api锛�
+ */
+function elasticMarker(position, content) {
+  // eslint-disable-next-line no-undef
+  return new AMap.ElasticMarker({
+    zoom: [14, 20],
+    position: position,
+    styles: [
+      {
+        icon: {
+          img: imgLocation,
+          size: [16, 16], //鍙鍖哄煙鐨勫ぇ灏�
+          ancher: [8, 16], //閿氱偣
+          fitZoom: 18, //鏈�鍚堥�傜殑绾у埆
+          scaleFactor: 1, //鍦板浘鏀惧ぇ涓�绾х殑缂╂斁姣斾緥绯绘暟
+          maxScale: 2, //鏈�澶ф斁澶ф瘮渚�
+          minScale: 1 //鏈�灏忔斁澶ф瘮渚�
+        },
+        label: {
+          content: content,
+          offset: [-35, 0],
+          position: 'BM',
+          minZoom: 15
+        }
+      }
+    ],
+    zoomStyleMapping: zoomStyleMapping
+  });
+}
+
+/**
+ * 鏂囨湰鏍囪
+ * 鍙慨鏀筽osition
+ */
+function textMaker(position, text) {
+  // eslint-disable-next-line no-undef
+  return new AMap.Text({
+    text: text,
+    position: position,
+    style: {
+      'font-size': '13px',
+      'text-align': 'center',
+      color: 'white',
+      'background-color': 'transparent',
+      'text-shadow': 'black 2px 2px 2px',
+      'border-radius': '2px',
+      border: '0px',
+      padding: '4px'
+    }
+  });
+}
+
+function drawSectorMesh(sDeg, eDeg, lnglat, distance, distance2) {
+  // eslint-disable-next-line no-undef
+  var sector = new AMap.Object3D.Mesh();
+  sector.transparent = true;
+  sector.backOrFront = 'both';
+
+  var unit = 5;
+
+  var p0 = calculate.lngLatToGeodeticCoord([lnglat])[0];
+  var geometry = sector.geometry;
+
+  var count = distance / unit;
+  var unitDeg = (eDeg - sDeg) / count;
+
+  for (let i = 0; i < count; i++) {
+    var angle1 = sDeg + unitDeg * i;
+    var angle2 = sDeg + unitDeg * (i + 1);
+
+    var l1 = calculate.getLatLon(lnglat, distance, angle1);
+    var l2 = calculate.getLatLon(lnglat, distance, angle2);
+    var l3 = calculate.getLatLon(lnglat, distance2, angle1);
+    var l4 = calculate.getLatLon(lnglat, distance2, angle2);
+
+    var coors = calculate.lngLatToGeodeticCoord([l1, l2, l3, l4]);
+    l1 = coors[0];
+    l2 = coors[1];
+    l3 = coors[2];
+    l4 = coors[3];
+
+    // 鍐呮祴鎵囧舰
+    geometry.vertices.push(p0.x, p0.y, 0);
+    geometry.vertices.push(l3.x, l3.y, 0);
+    geometry.vertices.push(l4.x, l4.y, 0);
+    // 澶栦晶鎵囧舰
+    geometry.vertices.push(l3.x, l3.y, 0);
+    geometry.vertices.push(l4.x, l4.y, 0);
+    geometry.vertices.push(l1.x, l1.y, 0);
+    geometry.vertices.push(l2.x, l2.y, 0);
+    // console.log(l3.x + ',' + l3.y + ' | ' + l1.x + ',' + l1.y);
+
+    // 鍐呮祴鎵囧舰棰滆壊
+    geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
+    geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
+    geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
+    //澶栦晶鎵囧舰棰滆壊
+    geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
+    geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
+    geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
+    geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
+
+    var index = i * 7;
+    geometry.faces.push(index, index + 1, index + 2);
+    geometry.faces.push(index + 3, index + 4, index + 5);
+    geometry.faces.push(index + 4, index + 5, index + 6);
+  }
+  object3Dlayer.add(sector);
+  _sector = sector;
+}
+
+function drawTextMaker(list, list2, distance, distance2) {
+  //10鍒嗛挓鎵囧舰
+  const a = _sectorViews.get('text10-t');
+  if (a == undefined) {
+    const text10t = textMaker(list[2], '10鍒嗛挓');
+    _sectorViews.set('text10-t', text10t);
+    const textM10t = textMaker(list[1], distance + 'm');
+    _sectorViews.set('textM10-t', textM10t);
+    map.add([text10t, textM10t]);
+  } else {
+    _sectorViews.get('text10-t').setPosition(list[2]);
+    _sectorViews.get('textM10-t').setPosition(list[1]);
+    _sectorViews.get('textM10-t').setText(distance + 'm');
+  }
+  //5鍒嗛挓鎵囧舰
+  const b = _sectorViews.get('text5-t');
+  if (b == undefined) {
+    const text5t = textMaker(list2[1], '5鍒嗛挓');
+    _sectorViews.set('text5-t', text5t);
+    const textM5t = textMaker(list2[0], distance2 + 'm');
+    _sectorViews.set('textM5-t', textM5t);
+    map.add([text5t, textM5t]);
+  } else {
+    _sectorViews.get('text5-t').setPosition(list2[1]);
+    _sectorViews.get('textM5-t').setPosition(list2[0]);
+    _sectorViews.get('textM5-t').setText(distance2 + 'm');
+  }
+}
+
+function drawElasticMarker(list, list2, distance, distance2) {
+  //10鍒嗛挓鎵囧舰
+  const text10 = elasticMarker(list[2], '<div>10鍒嗛挓</div>');
+  _sectorViews.set('text10', text10);
+  const textM = elasticMarker(list[1], `<div>${distance}m</div>`);
+  _sectorViews.set('textM10', textM);
+  map.add([text10, textM]);
+
+  //5鍒嗛挓鎵囧舰
+  const text5 = elasticMarker(list2[1], '<div>5鍒嗛挓</div>');
+  _sectorViews.set('text5', text5);
+  const textM5 = elasticMarker(list2[0], `<div>${distance2}m</div>`);
+  _sectorViews.set('textM5', textM5);
+  map.add([text5, textM5]);
+}
 
 export default {
   clearSector() {
     var list = [];
-    for (const key in _sectorViews) {
-      list.push(_sectorViews[key]);
+    for (const iterator of _sectorViews) {
+      list.push(iterator[1]);
+    }
+    for (const iterator of _sectorViewsAna) {
+      list.push(iterator[1]);
     }
     if (list.length > 0) {
       map.remove(list);
-      _sectorViews = {};
+      _sectorViews.clear();
     }
+    this.clearSectorMesh();
+  },
+  clearSectorMesh() {
     if (_sector) {
       object3Dlayer.remove(_sector);
     }
   },
   drawSector(fDatas, i) {
-    const lnglat = fDatas.lnglats_GD[i];
-    let windDir = fDatas.factor[17].datas[i].factorData;
-    let windSpeed = fDatas.factor[16].datas[i].factorData;
-    if (!windDir) windDir = 0;
-    if (!windSpeed) windSpeed = 0;
-
-    if (windSpeed > 10) {
-      return;
-    }
     if (_sector != undefined) {
       this.clearSector();
     }
+    const { sDeg, eDeg, lnglat, distance, distance2, list, list2 } =
+      sectorParams(fDatas, i);
+    drawSectorMesh(sDeg, eDeg, lnglat, distance, distance2);
+    drawElasticMarker(list, list2, distance, distance2);
+  },
 
-    // eslint-disable-next-line no-undef
-    var sector = new AMap.Object3D.Mesh();
-    sector.transparent = true;
-    sector.backOrFront = 'both';
-
-    var unit = 5;
-
-    var sDeg = windDir - _defaultDeg; //鎵囧舰璧峰瑙掑害锛堜互涓婃柟浣滀负0搴︼級
-    // sDeg = sDeg < 0 ? sDeg + 360 : sDeg
-    var eDeg = windDir + _defaultDeg; //鎵囧舰缁撴潫瑙掑害
-    // eDeg = eDeg < 0 ? eDeg + 360 : eDeg
-
-    var distance = windSpeed * 10 * 60; //鍗婂緞(椋庨��*鏃堕棿)
-    var lnglat2 = calculate.getLatLon(lnglat, distance, sDeg);
-    var lnglat3 = calculate.getLatLon(lnglat, distance, windDir);
-    var lnglat4 = calculate.getLatLon(lnglat, distance, eDeg);
-    var list = calculate.parse2LngLat([lnglat, lnglat2, lnglat3, lnglat4]);
-
-    var distance2 = windSpeed * 5 * 60; //鍗婂緞(椋庨��*鏃堕棿)
-    var lnglat2_2 = calculate.getLatLon(lnglat, distance2, sDeg);
-    var lnglat2_3 = calculate.getLatLon(lnglat, distance2, windDir);
-    var lnglat2_4 = calculate.getLatLon(lnglat, distance2, eDeg);
-    var list2 = calculate.parse2LngLat([lnglat2_2, lnglat2_3, lnglat2_4]);
-
-    var p0 = calculate.lngLatToGeodeticCoord([lnglat])[0];
-    var geometry = sector.geometry;
-
-    var count = distance / unit;
-    var unitDeg = (eDeg - sDeg) / count;
-    for (let i = 0; i < count; i++) {
-      var angle1 = sDeg + unitDeg * i;
-      var angle2 = sDeg + unitDeg * (i + 1);
-
-      var l1 = calculate.getLatLon(lnglat, distance, angle1);
-      var l2 = calculate.getLatLon(lnglat, distance, angle2);
-      var l3 = calculate.getLatLon(lnglat, distance2, angle1);
-      var l4 = calculate.getLatLon(lnglat, distance2, angle2);
-
-      var coors = calculate.lngLatToGeodeticCoord([l1, l2, l3, l4]);
-      l1 = coors[0];
-      l2 = coors[1];
-      l3 = coors[2];
-      l4 = coors[3];
-
-      // 鍐呮祴鎵囧舰
-      geometry.vertices.push(p0.x, p0.y, 0);
-      geometry.vertices.push(l3.x, l3.y, 0);
-      geometry.vertices.push(l4.x, l4.y, 0);
-      // 澶栦晶鎵囧舰
-      geometry.vertices.push(l3.x, l3.y, 0);
-      geometry.vertices.push(l4.x, l4.y, 0);
-      geometry.vertices.push(l1.x, l1.y, 0);
-      geometry.vertices.push(l2.x, l2.y, 0);
-      // console.log(l3.x + ',' + l3.y + ' | ' + l1.x + ',' + l1.y);
-
-      // 鍐呮祴鎵囧舰棰滆壊
-      geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
-      geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
-      geometry.vertexColors.push(1, 0.11, 0.25, 0.6);
-      //澶栦晶鎵囧舰棰滆壊
-      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
-      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
-      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
-      geometry.vertexColors.push(1, 0.37, 0.07, 0.5);
-
-      var index = i * 7;
-      geometry.faces.push(index, index + 1, index + 2);
-      geometry.faces.push(index + 3, index + 4, index + 5);
-      geometry.faces.push(index + 4, index + 5, index + 6);
-    }
-    object3Dlayer.add(sector);
-    _sector = sector;
-
-    distance = distance.toFixed(0);
-    distance2 = distance2.toFixed(0);
-    const zoomStyleMapping = {
-      14: 0,
-      15: 0,
-      16: 0,
-      17: 0,
-      18: 0,
-      19: 0,
-      20: 0
-    };
-    //10鍒嗛挓鎵囧舰
-    // eslint-disable-next-line no-undef
-    var text15 = new AMap.ElasticMarker({
-      zoom: [14, 20],
-      position: list[2],
-      styles: [
-        {
-          icon: {
-            img: imgLocation,
-            size: [16, 16], //鍙鍖哄煙鐨勫ぇ灏�
-            ancher: [8, 16], //閿氱偣
-            fitZoom: 18, //鏈�鍚堥�傜殑绾у埆
-            scaleFactor: 1, //鍦板浘鏀惧ぇ涓�绾х殑缂╂斁姣斾緥绯绘暟
-            maxScale: 2, //鏈�澶ф斁澶ф瘮渚�
-            minScale: 1 //鏈�灏忔斁澶ф瘮渚�
-          },
-          label: {
-            content: '<div>10鍒嗛挓</div>',
-            offset: [-35, 0],
-            position: 'BM',
-            minZoom: 15
-          }
-        }
-      ],
-      zoomStyleMapping: zoomStyleMapping
-    });
-    _sectorViews['text10'] = text15;
-    // eslint-disable-next-line no-undef
-    var textM = new AMap.ElasticMarker({
-      zoom: [14, 20],
-      position: list[1],
-      styles: [
-        {
-          icon: {
-            img: imgLocation,
-            size: [16, 16], //鍙鍖哄煙鐨勫ぇ灏�
-            ancher: [8, 16], //閿氱偣
-            fitZoom: 18, //鏈�鍚堥�傜殑绾у埆
-            scaleFactor: 1, //鍦板浘鏀惧ぇ涓�绾х殑缂╂斁姣斾緥绯绘暟
-            maxScale: 2, //鏈�澶ф斁澶ф瘮渚�
-            minScale: 1 //鏈�灏忔斁澶ф瘮渚�
-          },
-          label: {
-            content: `<div>${distance}m</div>`,
-            offset: [-35, 0],
-            position: 'BM',
-            minZoom: 15
-          }
-        }
-      ],
-      zoomStyleMapping: zoomStyleMapping
-    });
-    _sectorViews['textM'] = textM;
-    map.add(_sectorViews['text10']);
-    map.add(_sectorViews['textM']);
-
-    //5鍒嗛挓鎵囧舰
-    let pList = list2;
-    // eslint-disable-next-line no-undef
-    var text5 = new AMap.ElasticMarker({
-      position: pList[1],
-      styles: [
-        {
-          icon: {
-            img: imgLocation,
-            size: [16, 16], //鍙鍖哄煙鐨勫ぇ灏�
-            ancher: [8, 16], //閿氱偣
-            fitZoom: 18, //鏈�鍚堥�傜殑绾у埆
-            scaleFactor: 1, //鍦板浘鏀惧ぇ涓�绾х殑缂╂斁姣斾緥绯绘暟
-            maxScale: 2, //鏈�澶ф斁澶ф瘮渚�
-            minScale: 1 //鏈�灏忔斁澶ф瘮渚�
-          },
-          label: {
-            content: `<div>5鍒嗛挓</div>`,
-            offset: [-35, 0],
-            position: 'BM',
-            minZoom: 15
-          }
-        }
-      ],
-      zoomStyleMapping: zoomStyleMapping
-    });
-    _sectorViews['text5'] = text5;
-    // eslint-disable-next-line no-undef
-    var textM5 = new AMap.ElasticMarker({
-      position: pList[0],
-      styles: [
-        {
-          icon: {
-            img: imgLocation,
-            size: [16, 16], //鍙鍖哄煙鐨勫ぇ灏�
-            ancher: [8, 16], //閿氱偣
-            fitZoom: 18, //鏈�鍚堥�傜殑绾у埆
-            scaleFactor: 1, //鍦板浘鏀惧ぇ涓�绾х殑缂╂斁姣斾緥绯绘暟
-            maxScale: 2, //鏈�澶ф斁澶ф瘮渚�
-            minScale: 1 //鏈�灏忔斁澶ф瘮渚�
-          },
-          label: {
-            content: `<div>${distance2}m</div>`,
-            offset: [-35, 0],
-            position: 'BM',
-            minZoom: 15
-          }
-        }
-      ],
-      zoomStyleMapping: zoomStyleMapping
-    });
-    _sectorViews['textM5'] = textM5;
-    map.add(_sectorViews['textM5']);
-    map.add(_sectorViews['text5']);
+  drawSectorAna(fDatas, i) {
+    this.clearSectorMesh();
+    const { sDeg, eDeg, lnglat, distance, distance2, list, list2 } =
+      sectorParams(fDatas, i);
+    drawSectorMesh(sDeg, eDeg, lnglat, distance, distance2);
+    drawTextMaker(list, list2, distance, distance2);
   }
 };
diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue
index 4d60672..afe27b3 100644
--- a/src/views/HomePage.vue
+++ b/src/views/HomePage.vue
@@ -2,7 +2,10 @@
   <BaseMap></BaseMap>
   <div class="overlay-container">
     <CoreHeader></CoreHeader>
-    <MapToolbox></MapToolbox>
+    <el-row class="dropdown-wrap">
+      <MapToolbox></MapToolbox>
+      <MissionManage></MissionManage>
+    </el-row>
     <CoreMenu></CoreMenu>
     <router-view></router-view>
   </div>
@@ -23,4 +26,11 @@
   /* padding: 4px; */
   pointer-events: none;
 }
+
+.dropdown-wrap {
+  position: absolute;
+  top: 10px;
+  left: 2px;
+  gap: 4px;
+}
 </style>
diff --git a/src/views/historymode/HistoryMode.vue b/src/views/historymode/HistoryMode.vue
index f9b89f9..b40ea8a 100644
--- a/src/views/historymode/HistoryMode.vue
+++ b/src/views/historymode/HistoryMode.vue
@@ -1,10 +1,12 @@
 <template>
   <div class="p-events-none m-t-2">
-    <el-row v-show="status == 0" justify="center">
+    <el-row justify="center" align="middle" class="top-wrap">
       <SearchBar
+        v-show="status == 0"
         :search-time="searchTime"
         @search="fetchHistroyData"
       ></SearchBar>
+      <TrajectoryState v-show="status != 0" :status="status"></TrajectoryState>
     </el-row>
     <el-row class="m-t-2">
       <FactorRadio
@@ -17,6 +19,14 @@
         class="m-t-2"
         :factor="factorDatas.factor[factorType]"
       ></FactorLegend>
+    </el-row>
+    <el-row class="historical" justify="center">
+      <HistoricalTrajectory
+        :factor-datas="factorDatas"
+        :factor-type="factorType"
+        @change="(e) => (status = e)"
+        @stop="draw"
+      ></HistoricalTrajectory>
     </el-row>
     <TrendAnalysis
       class="trend-analysis"
@@ -32,11 +42,6 @@
       :factor-datas="factorDatas"
       :device-type="deviceType"
     ></DataSheet>
-    <el-row class="historical" justify="center">
-      <HistoricalTrajectory
-        @change="(e) => (status = e)"
-      ></HistoricalTrajectory>
-    </el-row>
   </div>
 </template>
 
@@ -82,7 +87,7 @@
   },
   watch: {
     factorType(nValue, oValue) {
-      if (nValue != oValue) {
+      if (nValue != oValue && this.status == 0) {
         this.draw();
       }
     }
@@ -115,10 +120,6 @@
       marks.drawMassMarks(this.factorDatas, e, (index) => {
         // 鏌ヨ鑼冨洿鍐呯殑鐩戞祴绔欑偣
         // SceneUtil.searchByCoordinate(lnglat[0], lnglat[1], distance);
-        // 3. 瓒嬪娍鍥捐烦杞畾浣�
-        // const progress = FChart.locate(lineChart.chart, lineChart.option, i, _factor.factorName);
-        // 4. 琛ㄦ牸鏁版嵁璺宠浆瀹氫綅
-        // Table.locate(i);
         this.drawSector(index);
         this.locateIndex = index;
       });
@@ -188,6 +189,10 @@
 };
 </script>
 <style scoped>
+.top-wrap {
+  height: 40px;
+}
+
 .trend-analysis {
   position: absolute;
   left: 0;
@@ -202,7 +207,7 @@
 
 .historical {
   position: absolute;
-  bottom: 0;
+  bottom: 10px;
   left: 0;
   right: 0;
 }

--
Gitblit v1.9.3