forked from drone/command-center-dashboard

罗广辉
2025-04-16 942e784e3127a2234a3a66c761d9876a01dd7dcc
Merge remote-tracking branch 'origin/master'
28 files modified
2 files renamed
14 files added
2841 ■■■■■ changed files
.env.development 2 ●●●●● patch | view | raw | blame | history
.env.production 2 ●●●●● patch | view | raw | blame | history
src/api/home/common.js 8 ●●●● patch | view | raw | blame | history
src/api/home/event.js 8 ●●●●● patch | view | raw | blame | history
src/api/home/machineNest.js 83 ●●●●● patch | view | raw | blame | history
src/assets/images/aiNowFly/photo.png patch | view | raw | blame | history
src/assets/images/aiNowFly/stop.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/close.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/expand.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/offline.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/point-active.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/point.png patch | view | raw | blame | history
src/assets/images/newEndPointicon.png patch | view | raw | blame | history
src/assets/images/newStartPoint.png patch | view | raw | blame | history
src/assets/images/newarrow-right.png patch | view | raw | blame | history
src/assets/images/task/cancel.png patch | view | raw | blame | history
src/assets/images/task/publish.png patch | view | raw | blame | history
src/components/CommonDateTime.vue 3 ●●●● patch | view | raw | blame | history
src/hooks/components/DevicePopUpBox.vue patch | view | raw | blame | history
src/hooks/components/EventPopUpBox.vue patch | view | raw | blame | history
src/hooks/useMapAggregation/useMapAggregation.js 11 ●●●●● patch | view | raw | blame | history
src/hooks/useSingleDroneMap/useSingleDroneMap.js 236 ●●●●● patch | view | raw | blame | history
src/layout/Header.vue 5 ●●●●● patch | view | raw | blame | history
src/store/modules/common.js 4 ●●●● patch | view | raw | blame | history
src/store/modules/home.js 7 ●●●●● patch | view | raw | blame | history
src/views/Home/AINowFly.vue 188 ●●●●● patch | view | raw | blame | history
src/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventOverviewDetailLeft.vue 44 ●●●● patch | view | raw | blame | history
src/views/Home/EventOverviewDetail/EventOverviewDetailRight.vue 182 ●●●● patch | view | raw | blame | history
src/views/Home/Footer.vue 7 ●●●● patch | view | raw | blame | history
src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue 15 ●●●●● patch | view | raw | blame | history
src/views/Home/HomeLeft/MachineNestList.vue 10 ●●●● patch | view | raw | blame | history
src/views/Home/HomeLeft/OverviewNext.vue 23 ●●●●● patch | view | raw | blame | history
src/views/Home/RSide.vue 6 ●●●●● patch | view | raw | blame | history
src/views/Home/SearchBox.vue 25 ●●●●● patch | view | raw | blame | history
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceEvent.vue 94 ●●●● patch | view | raw | blame | history
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJob.vue 16 ●●●●● patch | view | raw | blame | history
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue 22 ●●●● patch | view | raw | blame | history
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue 8 ●●●●● patch | view | raw | blame | history
src/views/SignMachineNest/SignMachineNest.vue 169 ●●●●● patch | view | raw | blame | history
src/views/TaskManage/TaskIntermediateContent/AddTask.vue 413 ●●●●● patch | view | raw | blame | history
src/views/TaskManage/TaskIntermediateContent/TaskMap.vue 725 ●●●● patch | view | raw | blame | history
src/views/TaskManage/TaskIntermediateContent/TaskTable.vue 337 ●●●●● patch | view | raw | blame | history
src/views/TaskManage/TaskTop/TaskTime.vue 1 ●●●● patch | view | raw | blame | history
vite.config.mjs.timestamp-1744707003737-1868137d88f2d.mjs 187 ●●●●● patch | view | raw | blame | history
.env.development
@@ -11,3 +11,5 @@
# 航线文件地址
VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/minio/cloud-bucket
#系统运维
VITE_APP_ADMIN_URL = 'https://wrj.shuixiongit.com/manage'
.env.production
@@ -5,3 +5,5 @@
VITE_BUILD_COMPRESS = gzip
# ws地址
VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws
# 管理后台地址
VITE_APP_ADMIN_URL = ' https://aisky.org.cn/manage'
src/api/home/common.js
@@ -25,18 +25,18 @@
        params,
    })
}
// 机巢搜索
// 地址搜索
export const searchByKeyword = params => {
    return request({
        url: `/drone-device-core/map/amap/searchByKeyword?keyword=${params}`,
        method: 'get',
    })
}
// 地址搜索
export const selectDeviceList = params => {
// 机巢搜索
export const selectDeviceList = data => {
    return request({
        url: `/drone-device-core/manage/api/v1/devices/selectDeviceList`,
        method: 'post',
        params,
        data: data,
    })
}
src/api/home/event.js
@@ -55,3 +55,11 @@
        data,
    })
}
// 点击图片关联的事件历史图片列表
export const findImgHistory = id => {
    return request({
        url: '/drone-device-core/jobEvent/findImgHistory?eventId='+id,
        method: 'get',
    })
}
src/api/home/machineNest.js
@@ -2,60 +2,69 @@
// 机巢统计
export const getDeviceInfoNum = params => {
    return request({
        url: '/drone-device-core/manage/api/v1/devices/getDeviceInfoNum',
        method: 'get',
        params,
    })
  return request({
    url: '/drone-device-core/manage/api/v1/devices/getDeviceInfoNum',
    method: 'get',
    params,
  })
}
// 机巢列表
export const selectDevicePage = ({ nickname, ...params }) => {
    return request({
        url: `/drone-device-core/manage/api/v1/devices/selectDevicePage?type=${params.type}&current=${params.current}&size=${params.size}`,
        method: 'post',
        data: {
            nickname,
        },
    })
  return request({
    url: `/drone-device-core/manage/api/v1/devices/selectDevicePage?type=${params.type}&current=${params.current}&size=${params.size}`,
    method: 'post',
    data: {
      nickname,
    },
  })
}
// 机巢数据
export const getFlightStatistics = dockSn => {
    return request({
        url: `/drone-device-core/manage/api/v1/devices/getFlightStatistics?dockSn=${dockSn}`,
        method: 'get',
        params: {},
    })
  return request({
    url: `/drone-device-core/manage/api/v1/devices/getFlightStatistics?dockSn=${dockSn}`,
    method: 'get',
    params: {},
  })
}
// 机巢直播/无人机直播 均可使用
export const liveStart = (deviceSn, quality) => {
    return request({
        url: `/drone-device-core/manage/api/v1/live/streams/liveStart?deviceSn=${deviceSn}&quality=${quality}`,
        method: 'post',
        data: {},
        headers: {
            areaCode: '',
        },
    })
  return request({
    url: `/drone-device-core/manage/api/v1/live/streams/liveStart?deviceSn=${deviceSn}&quality=${quality}`,
    method: 'post',
    data: {},
    headers: {
      areaCode: '',
    },
  })
}
// 单个机巢获取机巢详情
export const getDeviceDetail = deviceSn => {
    return request({
        url: `/drone-device-core/manage/api/v1/devices/getDeviceDetail?deviceSn=${deviceSn}`,
        method: 'get',
        params: {},
    })
  return request({
    url: `/drone-device-core/manage/api/v1/devices/getDeviceDetail?deviceSn=${deviceSn}`,
    method: 'get',
    params: {},
  })
}
// 设备-事件列表
export const getDeviceEventList = (data,params) => {
    return request({
        url: `/drone-device-core/jobEvent/eventPage`,
        method: 'post',
        data,
        params
    })
export const getDeviceEventList = (data, params) => {
  return request({
    url: `/drone-device-core/jobEvent/eventPage`,
    method: 'post',
    data,
    params
  })
}
// 事件列表---点位上图
export const getEventList = (data, params) => {
  return request({
    url: '/drone-device-core/jobEvent/eventList',
    method: 'post',
    data,
    params
  })
}
src/assets/images/aiNowFly/photo.png
src/assets/images/aiNowFly/stop.png
src/assets/images/home/useEventOperate/close.png
src/assets/images/home/useEventOperate/expand.png
src/assets/images/home/useEventOperate/offline.png
src/assets/images/home/useEventOperate/point-active.png
src/assets/images/home/useEventOperate/point.png
src/assets/images/newEndPointicon.png
src/assets/images/newStartPoint.png
src/assets/images/newarrow-right.png
src/assets/images/task/cancel.png
src/assets/images/task/publish.png
src/components/CommonDateTime.vue
@@ -60,9 +60,8 @@
let timeClick = (item,index) => {
  checked.value = item;
  const newDateRange = dateRanges[item];
  store.commit('setEventTimeType', [checked.value, timeListEnum[index]]);
  model.value = newDateRange;
  emit('change', newDateRange, timeListEnum[index]);
  emit('change', newDateRange, timeListEnum[index],checked.value);
};
onMounted(() => {
  // 如果父组件传入了值,就使用父组件的值 by cpz
src/hooks/components/DevicePopUpBox.vue
src/hooks/components/EventPopUpBox.vue
src/hooks/useMapAggregation/useMapAggregation.js
@@ -4,8 +4,8 @@
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
import DevicePopUpBox from '@/hooks/useMapAggregation/DevicePopUpBox.vue'
import EventPopUpBox from '@/hooks/useMapAggregation/EventPopUpBox.vue'
import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue'
import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
import { render } from 'vue'
import { useStore } from 'vuex'
@@ -137,14 +137,12 @@
      if (arr.length !== 0) {
        returnObj.childrens = arr
      }
      console.log(returnObj, '111111')
      return returnObj
    })
  }
  // 获取事件聚合
  function getMapEventCount (params) {
    console.log(5555555)
    return getMapEvents(params).then(res => {
      const resData = res?.data?.data
      if (resData?.data) {
@@ -185,7 +183,6 @@
    eventList = []
    if (!areaCode) return
    saveParams.area_code = areaCode
    console.log(type, '444')
    const list = type === 'device' ? await getDeviceCount(areaCode) : await getMapEventCount(saveParams)
    const splashedList = type === 'device'
      ? await getDeviceList(areaCode)
@@ -248,8 +245,6 @@
      return
    }
    handlerInit()
    if (newValue.eventTimeType) {
      saveParams = { area_code: newValue.selectedAreaCode, date_enum: store.state.home.eventTimeParams }
    }
@@ -260,6 +255,8 @@
    needFly = true
    if (!viewer) return
    handlerInit()
    viewer.scene.postRender.removeEventListener(determineScaling)
    initMapData(newValue.selectedAreaCode).then(() => {
src/hooks/useSingleDroneMap/useSingleDroneMap.js
New file
@@ -0,0 +1,236 @@
/*
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2025-04-15 22:41:40
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2025-04-16 18:38:00
 * @FilePath: \command-center-dashboard\src\hooks\useSingleDroneMap\useSingleDroneMap.js
 * @Description:
 *
 * Copyright (c) 2025 by shuishen, All Rights Reserved.
 */
import * as Cesium from 'cesium'
import endingImg from '@/assets/images/aiNowFly/ending.png'
import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
/**
 *
 * @param {Object} options - 配置选项
 */
export function useSingleDroneMap (options = {
  eventPositions: [],
  eventApi: null,
  eventApiParams: {}
}) {
  const { eventPositions, eventApi, eventApiParams } = options
  let viewer = null
  let handler = null
  let currentEntity = null
  // 初始化机场位置
  const initDroneEntity = (dronePosition) => {
    const { lng, lat, status } = dronePosition
    if (!lng || !lat) return
    const markerImg = status ? endingHighImg : endingImg
    const position = Cesium.Cartesian3.fromDegrees(+lng, +lat, 0)
    const droneEntity = viewer?.entities.add({
      id: `single-drone-position`,
      position: position,
      billboard: {
        image: new Cesium.ConstantProperty(markerImg),
        width: 35,
        height: 35,
      },
      ellipse: {
        semiMinorAxis: 5000,
        semiMajorAxis: 5000,
        outline: true,
        material: Cesium.Color.CORNFLOWERBLUE.withAlpha(0.3),
      },
      properties: {
        customData: {
          data: {
            type: 'single-drone-event'
          }
        }
      }
    })
    viewer?.flyTo(droneEntity, {
      offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
      duration: 0.5,
    })
  }
  // 机巢事件地图撒点
  const initDroneEventEntity = (eventPositions = eventPositions) => {
    // 遍历特征并添加实体
    eventPositions.length && eventPositions.forEach((item, index) => {
      const { longitude, latitude, status, id } = item
      const position = Cesium.Cartesian3.fromDegrees(+longitude, +latitude, 0)
      viewer?.entities.add({
        id: `single-drone-event-${index}`,
        position: position,
        billboard: {
          image: new Cesium.ConstantProperty(endingHighImg),
          width: 35,
          height: 35,
        },
        properties: {
          customData: {
            data: {
              type: 'single-drone-sign'
            }
          }
        },
      })
    })
  }
  // 调用传入api
  const initEventApiEntity = () => {
    removeEventLayer()
    eventApi(
      {
        ...eventApiParams,
      }
    ).then(res => {
      const result = res.data.data.records
      initDroneEventEntity(result)
    })
  }
  // 事件地图撒点加载方式
  const initEventLayer = () => {
    eventApi ? initEventApiEntity() : initDroneEventEntity()
  }
  const removeEventLayer = () => {
    // entities移除
    const entitiesIDs = viewer?.entities.values.map(i => i.id)
    entitiesIDs && entitiesIDs.forEach(item => {
      item.includes('single-drone-event') && viewer?.entities.removeById(item)
    })
  }
  // 移除当前地图所有entity
  const removeLayer = () => {
    // entities移除
    const entitiesIDs = viewer?.entities.values.map(i => i.id)
    entitiesIDs.forEach(item => {
      item.includes('single-drone-') && viewer?.entities.removeById(item)
    })
  }
  // 查找特定类型的实体
  const findEntityByType = (entities, type) => {
    return entities.find(entity =>
      entity?.properties?.customData?._value?.data?.type === type
    )
  }
  // 左键单机事件
  const singleMachineEvent = async click => {
    let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id)
    if (!clickedEntities.length) return
    const currentEntity = findEntityByType(clickedEntities, 'single-drone-event')
    removeLabel()
    if (currentEntity) {
      viewer?.scene.postRender.addEventListener(labelBoxRender)
    }
  }
  // 事件初始化
  const handlerInit = () => {
    if (handler) return
    handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas)
    handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }
  // 事件移除
  const removeHandler = () => {
    handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    handler?.destroy()
    handler = null
  }
  // 获取弹框box
  const getLabelDom = data => {
    const vNode = h(EventPopUpBox, { data, removeLabel })
    const tooltipContainer = document.createElement('div')
    tooltipContainer.id = 'mapPopUpBox'
    tooltipContainer.style.position = 'absolute'
    tooltipContainer.style.transform = styleTransform
    tooltipContainer.style.pointerEvents = 'none'
    document.querySelector('.page-index').append(tooltipContainer)
    render(vNode, tooltipContainer)
    return tooltipContainer
  }
  // 弹框位置刷新
  const labelBoxRender = () => {
    if (!currentEntity) return
    let dom = document.querySelector('#mapPopUpBox')
    if (!dom) {
      dom = getLabelDom(currentEntity.properties.customData._value.data)
    }
    const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentEntity?.position?._value)
    if (screenPosition) {
      dom.style.left = `${screenPosition.x}px`
      dom.style.top = `${screenPosition.y}px`
      dom.style.display = 'block'
    }
  }
  const removeDom = () => {
    const dom = document.querySelector('#mapPopUpBox')
    if (dom && dom.parentNode) {
      dom.parentNode.removeChild(dom)
    }
  }
  // 移除弹框标签
  const removeLabel = () => {
    viewer?.scene.postRender.removeEventListener(labelBoxRender)
    removeDom()
  }
  const init = () => {
    viewer = window.$viewer
    handlerInit()
  }
  const removeAll = () => {
    removeLayer()
    removeHandler()
    removeLabel()
  }
  // 自动清理
  onUnmounted(() => {
    removeAll()
  })
  return {
    init,
    removeAll,
    initEventLayer,
    initDroneEntity,
  }
}
src/layout/Header.vue
@@ -31,6 +31,7 @@
import { useRouter, useRoute } from 'vue-router';
import { Message } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { ELocalStorageKey } from '@/utils/http/enums';
const router = useRouter();
const route = useRoute();
@@ -50,6 +51,10 @@
]);
const handleClick = ({ path, name }) => {
  if (['系统运维'].includes(name)) {
    window.open(import.meta.env.VITE_APP_ADMIN_URL + '?token=' + localStorage.getItem(ELocalStorageKey.Token), '_blank');
    return;
  }
  if (!['首页', '任务管理'].includes(name)) return ElMessage.warning('正在加急开发中...');
  // 更新 leftList 的 active 状态
  leftList.value.forEach(item => {
src/store/modules/common.js
@@ -36,8 +36,12 @@
      visual: '3D',
      isDark: false,
    },
    isHideBottomIcon: true,
  },
  mutations: {
    setHideBottomIcon (state, data) {
      state.isHideBottomIcon = data
    },
    setMapSetting: (state, data) => {
      state.mapSetting = data
      loadLAYER()
src/store/modules/home.js
@@ -117,10 +117,9 @@
                dock.work_osd = info.host
            }
        },
    setEventTimeType : (state, data) => {
      console.log('33333')
      state.eventTimeType = data[0]
      state.eventTimeParams = data[1]
    setEventTimeType: (state, [timeType, timeParams]) => {
      state.eventTimeType = timeType
      state.eventTimeParams = timeParams
    },
    setEventTimeRang : (state, time) => {
      state.eventTimeRang = time
src/views/Home/AINowFly.vue
@@ -14,21 +14,46 @@
                <el-input disabled type="text" v-model="di" placeholder="地名&经纬度"/>
            </el-form-item>
            <!--            todo-->
            <el-form-item label="事件">
            <el-form-item label="飞行事件">
                <div class="event">
                    <img src="@/assets/images/aiNowFly/picture-recording.png" alt="">
                    <div class="img-close" v-show="isPhoto">
                        <img @click="isPhoto=false" class="close" src="@/assets/images/aiNowFly/close.png" alt="">
                        <img src="@/assets/images/aiNowFly/photo.png" alt="">
                    </div>
                    <div class="img-close" v-show="isStop">
                        <img @click="isStop=false" class="close" src="@/assets/images/aiNowFly/close.png" alt="">
                        <img src="@/assets/images/aiNowFly/stop.png" alt="">
                    </div>
                    <div class="add-event" @click="isShowEvent = !isShowEvent">+
                        <div class="event-select" v-show="isShowEvent">
                            <div class="photo" @click="isPhoto=true">拍照</div>
                            <div class="stop" @click="isStop=true">悬停</div>
                        </div>
                    </div>
                </div>
            </el-form-item>
        </el-form>
        <div class="title-list">可飞行机巢列表:</div>
        <el-table :data="list" height="120" @selection-change="handleSelectionChange">
            <el-table-column type="selection" />
            <!-- <el-table-column type="index" label="序号" /> -->
            <el-table-column prop="nickname" label="机巢名称" />
            <el-table-column prop="minute" label="可飞行时间" />
            <el-table-column prop="exe_distance" label="可飞行距离" />
        </el-table>
        <div class="tabledata">
            <div class="table-content">
                <div class="tabler-item">
                    <el-checkbox v-model="isCheckAll" @change="checkedAll"/>
                </div>
                <div class="table-item">机巢名称</div>
                <div class="table-item">可飞行时间</div>
                <div class="table-item">可飞行距离</div>
            </div>
            <div class="table-content" v-for="item in list">
                <div class="tabler-item">
                    <el-checkbox v-model="item.checked" @change="handleItemCheck"/>
                </div>
                <div class="table-item">{{ item.nickname }}</div>
                <div class="table-item">{{ item.minute }}</div>
                <div class="table-item">{{ item.exe_distance }}</div>
            </div>
        </div>
        <div class="btn-submit" @click="nowFly"><img src="@/assets/images/aiNowFly/fly.png" alt=""></div>
    </div>
</template>
@@ -61,9 +86,17 @@
    type: 1,
    begin_time: nowTime,
    end_time: nowTime,
    action_modes: [{action_actuator_func: 'startRecord'}],
}
const params = ref(_.cloneDeep(paramsInit))
const di = computed(() => params.value.longitude + ',' + params.value.latitude)
// 事件默认隐藏
const isShowEvent = ref(false);
// 添加事件
const isPhoto = ref(false)
const isStop = ref(false)
const rules = ref({
    name: [
@@ -89,6 +122,12 @@
    await ruleFormRef.value.validate()
    if (!params.value.dock_sns.length) return ElMessage.warning('请选择将要飞行的机巢')
    if (!params.value.longitude) return ElMessage.warning('请选择飞行的点')
    if (isPhoto.value) {
        params.value.action_modes.push({action_actuator_func:'takePhoto'})
    }
    if (isStop.value) {
        params.value.action_modes.push({action_actuator_func:'hover'})
    }
    createTask(params.value).then(res => {
        ElMessage.success('起飞成功')
        if (params.value.dock_sns.length === 1) {
@@ -205,6 +244,7 @@
  size: 10
});
const isCheckAll = ref(false);
// 获取飞机列表
const getFJList = async () => {
    let pageParams = ref({
@@ -215,10 +255,27 @@
    const res = await getFlyingNestBy(pageParams.value, pagingParams.value)
    list.value = (res.data?.data || []).map(item => ({
        ...item,
        checked: false,
        minute: _.round(item.estimated_arrival_time / 60, 0),
    }))
    if (!list.value.length) ElMessage.warning('附近暂无可用无人机')
    renderingLine()
}
// 单个选择框变化
const handleItemCheck = () => {
  const allChecked = list.value.every(item => item.checked)
  const someChecked = list.value.some(item => item.checked)
  isCheckAll.value = allChecked
  params.value.dock_sns = list.value.filter(item => item.checked).map(item => item.device_sn)
}
// 全选
const checkedAll = () => {
    list.value.forEach(item => {
        item.checked = isCheckAll.value
    })
    params.value.dock_sns = isCheckAll.value ? list.value.map(item => item.device_sn) : []
}
const initMap = () => {
@@ -240,6 +297,8 @@
    list.value = []
    eventPoint = {}
    store.commit('setFootActiveIndex', 0)
    // 显示相关的按钮
    store.commit('setHideBottomIcon', true)
}
onBeforeUnmount(() => {
@@ -304,79 +363,82 @@
      box-shadow: 0 0 0 1px #026AD6;
    }
        .event {
            display: flex;
            img {
                width: 40px;
                height: 34px;
                margin-right: 10px;
            }
            .img-close {
                position: relative;
                .close {
                    cursor: pointer;
                    width: 8px;
                    height: 8px;
                    position: absolute;
                    top: -8px;
                    right: 1px;
                }
            }
            .add-event {
                width: 38px;
                height: 38px;
                background: rgba(83,179,255,0.16);
                border-radius: 8px 8px 8px 8px;
                border: 1px dashed;
                text-align: center;
                line-height: 38px;
                color: #11C4FF;
                position: relative;
                cursor: pointer;
                // border-image: linear-gradient(180deg, rgba(17, 196, 255, 1), rgba(255, 255, 255, 1)) 1 1;
                .event-select {
                    z-index: 10;
                    position: absolute;
                    top: 40px;
                    width: 72px;
                    height: 70px;
                    background: #0F1929;
                    box-shadow: inset 0px -50px 50px 0px rgba(27,148,255,0.13);
                    border-radius: 8px 8px 8px 8px;
                    border: 1px solid #51A8FF;
                    text-align: center;
                    color: #D3E9FF;
                    .photo {
                        height: 36px;
                        border-bottom: 1px solid #51A8FF;
                    }
                }
            }
        }
    }
    .title-list {
        padding: 0 0 14px 11px;
    }
    .el-table {
        width: 300px;
    .tabledata {
        height: 120px;
        margin: 0 0 0 11px;
        overflow: hidden;
        :deep(.el-scrollbar__wrap) {
            overflow-x: hidden !important;
        border: 1px dashed #fff;
        margin: 0px 10px;
        .table-content {
            padding: 0 8px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px dashed #fff;
        }
        :deep(.el-table__body-wrapper) {
            overflow-x: hidden !important;
        }
        :deep(.el-table__header-wrapper) {
            th {
                font-size: 12px;
                color: #D3E9FF;
                background-color: #122348;
                font-weight: normal;
                border-bottom: none;
            }
        }
        :deep(.el-table__empty-block) {
            background-color: #0A1734;
            height: auto !important;  // 移除固定高度
        min-height: 60px;        // 设置最小高度
            .el-table__empty-text {
                color: #FFFFFF;
            }
        }
        :deep(.el-table__body) {
            background-color: #0A1734;
            tr {
                background-color: #0A1734 !important;
                color: #FFFFFF;
                &:hover > td {
                    background-color: #0A1734 !important;
                }
            }
        }
        :deep(.el-scrollbar) {
            background-color: #0A1734;
        .table-item {
            width: 100px;
            text-align: center;
            height: 32px;
            line-height: 32px;
        }
    }
    .btn-submit {
        cursor: pointer;
        margin-left: 88px;
        margin-top: 12px;
        img { width: 138px; height: 38px; }
    }
    :deep(.el-table__inner-wrapper) {
    border: 1px dashed #2F497D;
    &::before {
      display: none;
    }
  }
  :deep(.el-table__cell) {
    border: none;
  }
  :deep(.el-table__border) {
    display: none;
  }
}
</style>
src/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventOverviewDetailLeft.vue
@@ -1,12 +1,12 @@
<template>
    <!--时间 天气-->
    <common-weather></common-weather>
    <div class="event-overview-detail-left">
        <!--返回-->
        <div class="do-return" @click="goBack">
            <img src="@/assets/images/return.png" alt="" />
        </div>
        <common-title title="事件数据分析" />
    <!--返回-->
    <div class="do-return" :style="{left:isHideBottomIcon?pxToRem(430):pxToRem(46)}" @click="goBack">
        <img src="@/assets/images/return.png" alt="" />
    </div>
    <common-title v-show="isHideBottomIcon" :style="{left:pxToRem(14)}" title="事件数据分析" />
    <div v-show="isHideBottomIcon" class="event-overview-detail-left">
        <CommonDateTime class="dateTime" v-model="timeArr" @change="timeChange" />
        <EventDataAnalysis />
        <EventTrendAnalysis />
@@ -22,6 +22,7 @@
import { useStore } from 'vuex'
import EventTrendAnalysis from '@/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventTrendAnalysis.vue'
import EventTop5 from '@/views/Home/EventOverviewDetail/EventOverviewDetailLeft/EventTop5.vue'
import { pxToRem } from '@/utils/rem'
// 选中机巢默认日
// const today = dayjs().format('YYYY-MM-DD')
@@ -30,6 +31,8 @@
const startOfWeek = dayjs().startOf('week').add(1, 'day').format('YYYY-MM-DD')
const endOfWeek = dayjs().endOf('week').add(1, 'day').format('YYYY-MM-DD')
const timeArr = ref([startOfWeek, endOfWeek])
const isHideBottomIcon = computed(() => store.state.common.isHideBottomIcon)
const store = useStore()
@@ -41,13 +44,15 @@
provide('eventOverviewParams', params)
// 时间变化
const timeChange = (value, date_enum) => {
const timeChange = (value, date_enum, type) => {
    params.value = {
        ...params.value,
        date_enum,
    }
    store.commit('setEventTimeType', [type, date_enum]);
}
const goBack = () => {
    store.commit('setHideBottomIcon', true)
    store.commit('setIsEventOverviewDetail', false)
}
</script>
@@ -55,8 +60,8 @@
.event-overview-detail-left {
    position: absolute;
    width: 390px;
    height: 920px;
    top: 120px;
    height: 870px;
    top: 166px;
    margin-left: 29px;
    background: linear-gradient(
    270deg,
@@ -71,20 +76,19 @@
    align-items: center;
    .dateTime {
        width: 400px;
        width: 356px;
        margin: 0 0 8px 0;
    }
}
.do-return {
    position: absolute;
    top: 136px;
    left: 430px;
    cursor: pointer;
    .do-return {
        position: absolute;
        right: -50px;
        cursor: pointer;
        img {
            width: 60px;
            height: 33px;
        }
    img {
        width: 60px;
        height: 33px;
    }
}
</style>
src/views/Home/EventOverviewDetail/EventOverviewDetailRight.vue
@@ -1,9 +1,9 @@
<template>
    <div class="event-overviewdetail-right" :class="{ isMore }">
        <CommonTitle title="工单列表" />
        <CommonTitle title="事件概况" :style="{right: isMore?pxToRem(410):pxToRem(0)}" />
        <div class="content">
            <img class="leftArrow" :src="isMore ? rightArrowImg : leftArrowImg" @click="leftArrowFun" alt="" />
            <img class="leftArrow" :class="isMore?'rightArrow':''" :src="isMore ? rightArrowImg : leftArrowImg" @click="leftArrowFun" alt="" />
            <el-date-picker
                class="ztzf-date-picker"
@@ -50,12 +50,12 @@
                    <img class="statusItemImg" :src="item.img" alt="" />
                    <div class="statusItemInfo">
                        <div class="statusItemName">{{ item.name }}</div>
                        <div class="statusItemNum">{{ item.num || 0 }}</div>
                        <div class="statusItemNum" :style="{ color:item.color }">{{ item.num || 0 }}</div>
                    </div>
                </div>
            </div>
            <el-checkbox-group v-model="params.event_keys" @change="getList">
            <el-checkbox-group v-show="isMore" v-model="params.event_keys" @change="getList">
                <el-checkbox v-for="item in eventList" :value="item.status" :key="item.dictKey">
                    <template #default>
                        <span class="eventListItemCheckboxName">{{ item.name }}</span>
@@ -70,6 +70,7 @@
                        class="eventListItemImg"
                        :src="getSmallImg(item.photo_url)"
                        alt=""
                        @click="getFindImgHistory(item.id)"
                    />
                    <div class="eventListItemPosition" :title="item.address" @click="positioning(item)">
                        <img :src="positioningImg" alt="" title="点击定位" />
@@ -95,6 +96,25 @@
            </div>
        </div>
    </div>
    <div class="image-list" v-if="isShowBigImg">
        <div class="title">
            <img @click="isShowBigImg=false" src="@/assets/images/home/useEventOperate/close.png" alt="">
        </div>
        <div class="content">
            <img :src="clickImgSrc" alt="">
        </div>
        <div class="card">
            <div v-for="(item,index) in imageList">
                <div class="time-top" :class="index===selectedImgIndex?'active':''" @click="clickWeekTime(item,index)">{{ item.create_time_str }}</div>
                <div class="time-point">
                    <img v-if="index===selectedImgIndex" src="@/assets/images/home/useEventOperate/point-active.png" alt="">
                    <img v-else src="@/assets/images/home/useEventOperate/point.png" alt="">
                </div>
                <div class="time-bottom">{{ item.create_time }}</div>
            </div>
            <div class="time-line"></div>
        </div>
    </div>
</template>
<script setup>
import status0Img from '@/assets/images/home/eventOverviewDetail/status0.png'
@@ -110,7 +130,7 @@
import dayjs from 'dayjs'
import { selectDevicePage } from '@/api/home/machineNest'
import { getMultipleDictionary } from '@/api/system/dictbiz'
import { getEvenNum, getEventPage, getEventStatusNum } from '@/api/home/event'
import { getEvenNum, getEventPage, getEventStatusNum, findImgHistory } from '@/api/home/event'
import cesiumOperation from '@/utils/cesium-tsa'
import CommonTitle from '@/components/CommonTitle.vue'
import { pxToRem } from '@/utils/rem'
@@ -148,6 +168,8 @@
    isMore.value = !isMore.value
    params.value.size = isMore.value ? 16 : 8
    params.value.current = 1
    // 下半部分隐藏 右侧隐藏
    store.commit('setHideBottomIcon', !isMore.value)
    getList()
}
@@ -181,12 +203,12 @@
// 事件状态+数量
const statusList = ref([
    { name: '全部状态', img: status0Img, id: undefined,few: true },
    { name: '待审核', img: status1Img, id: 2 },
    { name: '待处理', img: status2Img, id: 0, few: true },
    { name: '处理中', img: status3Img, id: 3, few: true },
    { name: '已完成', img: status4Img, id: 4, few: true },
    { name: '待分拨', img: status5Img, id: 1 },
    { name: '全部状态', img: status0Img, id: undefined,few: true, color: '#FFD509' },
    { name: '待审核', img: status1Img, id: 2, color: '#8CFEA7' },
    { name: '待处理', img: status2Img, id: 0, few: true, color: '#FF7411' },
    { name: '处理中', img: status3Img, id: 3, few: true, color: '#FFC398' },
    { name: '已完成', img: status4Img, id: 4, few: true, color: '#AFD9FB' },
    { name: '待分拨', img: status5Img, id: 1, color: '#11C4FF' },
])
const getEventStatusNumFun = () => {
@@ -244,6 +266,24 @@
        total.value = resData.total
    })
}
const isShowBigImg = ref(false)
const imageList = ref([]);
const clickImgSrc = ref('');
const selectedImgIndex = ref(0);
// 点击图片放大 显示详细信息
const getFindImgHistory = (id) => {
    findImgHistory(id).then((res) => {
        if (res.data.code !== 0) return
        imageList.value = res.data.data
        clickImgSrc.value = res.data.data[0]?.url;
        isShowBigImg.value = true
    })
}
// 点击周期
const clickWeekTime = (item,index) => {
    clickImgSrc.value = item.url
    selectedImgIndex.value = index
}
const getDateRange = unit => {
  if (unit === 'today') {
@@ -282,25 +322,31 @@
    height: 922px;
    width: 405px;
    font-size: 18px;
    z-index: 10;
    &.isMore {
        width: 807px;
        width: 808px;
        .content {
            width: 792px;
            padding-left: 44px;
        }
    }
    .content {
        width: 390px;
        height: 877px;
        background: linear-gradient(270deg, #1f3e7a 0%, rgba(31, 62, 122, 0.35) 79%, rgba(31, 62, 122, 0) 100%);
        background: linear-gradient(
    270deg,
    rgba(31, 62, 122, 0) 0%,
    rgba(31, 62, 122, 0.35) 21%,
    #1f3e7a 100%);
        display: flex;
        justify-content: space-between;
        align-content: start;
        flex-wrap: wrap;
        padding: 7px 15px 0 11px;
        gap: 10px;
        padding: 7px 13px 0 11px;
        gap: 16px;
        .leftArrow {
            position: absolute;
@@ -310,38 +356,42 @@
            cursor: pointer;
        }
        .rightArrow {
            position: absolute;
            top: 50%;
            left: 30px;
            transform: translateY(-50%);
            cursor: pointer;
        }
        .statusList {
            width: 100%;
            display: flex;
            justify-content: space-between;
            .statusItem {
                width: 95px;
                // width: 95px;
                height: 44px;
                display: flex;
                flex: 1;
                justify-content: center;
                position: relative;
                cursor: pointer;
                // margin-right: 4px;
                &.active {
                    background: linear-gradient(
                        180deg,
                        rgba(19, 80, 141, 0) 0%,
                        rgba(22, 56, 91, 0.48) 48%,
                        #053462 91%,
                        #259dff 91%,
                        #259dff 98%
                    );
                    background: linear-gradient( 180deg, rgba(19,80,141,0) 0%, rgba(22,56,91,0.48) 48%, #053462 98%, #259DFF 98%, #259DFF 98%);
                }
                .statusItemImg {
                    width: 35px;
                    height: 35px;
                    width: 34px;
                    height: 34px;
                    margin-right: 1px;
                }
                .statusItemInfo {
                    .statusItemName {
                        width: 59px;
                        // width: 59px;
                        height: 17px;
                        font-family: Segoe UI, Segoe UI;
                        font-weight: 400;
@@ -351,6 +401,7 @@
                        text-align: left;
                        font-style: normal;
                        text-transform: none;
                        margin-bottom: 4px;
                    }
                    .statusItemNum {
@@ -401,13 +452,14 @@
            width: 100%;
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            gap: 20px 0;
            // justify-content: space-between;
            gap: 20px 10px;
            .eventListItem {
                width: 175px;
                height: 140px;
                position: relative;
                cursor: pointer;
                .eventListItemImg {
                    width: 174px;
@@ -475,4 +527,76 @@
    display: flex;
    justify-content: center;
}
.image-list {
    position: absolute;
    left: 40%;
    transform: translate(-40%);
    bottom: 218px;
    width: 524px;
    height: 382px;
    background: #0F1929;
    box-shadow: inset 0px -50px 50px 0px rgba(27,148,255,0.13);
    border-radius: 0px 0px 0px 0px;
    border: 2px solid;
    border-image: linear-gradient(180deg, rgba(81, 168, 255, 0), rgba(48, 111, 202, 1), rgba(255, 255, 255, 1), rgba(27, 148, 255, 1)) 2 2;
    .title {
        position: relative;
        text-align: right;
        right: 12px;
        top: 12px;
        img {
            width: 10px;
            height: 10px;
            cursor: pointer;
        }
    }
    .content {
        width: 475px;
        height: 231px;
        box-shadow: 1px 3px 6px 0px rgba(81,168,255,0.58);
        border-radius: 20px 20px 20px 20px;
        border-image: linear-gradient(180deg, rgba(81, 168, 255, 1), rgba(189, 228, 255, 1)) 2 2;
        margin: 28px 28px;
        img {
            width: 100%;
            height: 230px;
        }
    }
    .card {
        margin: 26px 26px;
        color: #BECBEA;
        display: flex;
        justify-content: space-between;
        position: relative;
        .time-top {
            width: 50px;
            height: 30px;
            line-height: 30px;
            text-align: center;
            color: #ffffff;
            background: linear-gradient( 180deg, rgba(13,30,70,0.72) 0%, #142E6B 100%);
            border: 1px solid #0054D3;
            cursor: pointer;
        }
        .active {
            background: linear-gradient( 180deg, rgba(13,48,131,0.72) 0%, #023DC8 100%);
            border: 1px solid;
            border-image: linear-gradient(180deg, rgba(0, 84, 211, 1), rgba(146, 186, 245, 1)) 1 1;
        }
        .time-point {
            text-align: center;
            img {
                width: 8px;
                height: 12px;
            }
        }
        .time-line {
            position: absolute;
            background: linear-gradient( 82deg, rgba(23,40,79,0) 0%, #576D9F 17%, #576D9F 86%, rgba(23,40,79,0) 100%);
            height: 2px;
            top: 38px;
            width: 100%;
        }
    }
}
</style>
src/views/Home/Footer.vue
@@ -1,5 +1,5 @@
<template>
    <div class="footer">
    <div class="footer" v-show="isHideBottomIcon">
        <img
            v-for="(item,index) in list.filter(i => !i.show)"
            :class="item.className"
@@ -37,6 +37,7 @@
const store = useStore()
const footActiveIndex = computed(() => store.state.home.footActiveIndex)
const isHideBottomIcon = computed(() => store.state.common.isHideBottomIcon)
// 机巢聚合
const { init, removeAll } = useMapAggregation('device')
@@ -76,6 +77,10 @@
    fromItem?.removeAll?.()
    nextTick(() => toItem?.init?.())
    list.value = list.value.map(item => ({ ...item, active: item.name === toItem?.name }))
    if (index === 5) {
        // 相关图标不显示
        store.commit('setHideBottomIcon', false)
    }
}
watch(
src/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue
@@ -3,7 +3,7 @@
    <el-dialog
        class="inspection-rask-details-dialog ztzf-dialog"
        v-model="isShowDetailsDialog"
        :width="pxToRem(1000)"
        :width="pxToRem(1500)"
        :close-on-click-modal="false"
        :destroy-on-close="true"
    >
@@ -64,7 +64,7 @@
            <el-table
                :data="taskDetailData"
                :row-class-name="tableRowClassName"
                :row-style="{ height: '54px', fontSize: '14px', 'text-align': 'center' }"
                :row-style="{ height: '45px', fontSize: '14px', 'text-align': 'center' }"
                :header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }"
            >
                <el-table-column label="序号" type="index" width="60">
@@ -115,7 +115,7 @@
            </el-table>
        </div>
        <!-- 分页 -->
        <div style="display: flex; justify-content: center">
        <div style="display: flex; justify-content: center;margin:15px 0;">
            <el-pagination
                class="ztzf-pagination"
                v-model:current-page="pageParams.current"
@@ -322,7 +322,7 @@
.tabledata {
    padding: 0 16px;
    overflow: hidden;
    height: 640px;
    // height: 640px;
    overflow-y: scroll !important;
}
@@ -343,9 +343,4 @@
    color: #8cfea7;
}
</style>
<style lang="scss">
.inspection-rask-details-dialog {
    width: 1270px;
    height: 856px;
}
</style>
src/views/Home/HomeLeft/MachineNestList.vue
@@ -5,13 +5,17 @@
    <div class="machine-nest-list">
        <MachineNestTotal @searchNickName="handleSearch" />
        <div class="content-wrapper">
            <div
            <!-- <div
                class="table-list"
                v-if="tableList.length > 0"
                infinite-scroll-distance="6"
                v-infinite-scroll="loadMore"
                :infinite-scroll-disabled="busy"
                infinite-scroll-immediate="true"
            > -->
            <div
                class="table-list"
                v-if="tableList.length > 0"
            >
                <div
                    :class="[index % 2 === 1 ? 'table-itemeven' : 'table-item']"
@@ -73,7 +77,7 @@
// 分页参数
const pageParams = ref({
    current: 1,
    size: 8,
    size: 99,
    total: 0,
})
@@ -90,7 +94,7 @@
        if (res.data.code !== 0) return
        if (res.data.data.records.length === 0) return (isMore.value = false)
        // pageParams.value.current += 1
        pageParams.value.size += 8
        // pageParams.value.size += 8
        tableList.value = res.data.data.records;// [...tableList.value, ...res.data.data.records]
        busy.value = false
    })
src/views/Home/HomeLeft/OverviewNext.vue
@@ -8,14 +8,17 @@
                <div class="name">机巢名称</div>
                <div class="status">机巢状态</div>
            </div>
            <div
            <!-- <div
                class="table-body"
                v-if="tableList.length > 0"
                infinite-scroll-distance="6"
                v-infinite-scroll="loadMore"
                :infinite-scroll-disabled="busy"
                infinite-scroll-immediate="true"
            >
            > -->
            <div
                class="table-body"
                v-if="tableList.length > 0">
                <div
                    class="table-item"
                    :class="[index % 2 === 1 ? '' : 'table-item-odd']"
@@ -66,7 +69,7 @@
// 分页参数
const pageParams = ref({
    current: 1,
    size: 5,
    size: 99,
    total: 0,
})
// 机巢列表
@@ -82,24 +85,24 @@
        if (res.data.code !== 0) return
        if (res.data.data.records.length === 0) return (isMore.value = false)
        // pageParams.value.current += 1
        pageParams.value.size += 5;
        // pageParams.value.size += 5;
        tableList.value = res.data.data.records;// [...tableList.value, ...res.data.data.records]
        busy.value = false
    })
}
// 加载更多数据
const loadMore = async () => {
    busy.value = true
    if (!isMore.value) return
    getTableList()
}
// const loadMore = async () => {
    // busy.value = true
    // if (!isMore.value) return
    // getTableList()
// }
// 搜索数据
const handleSearch = name => {
    searchText.value = name
    pageParams.value.current = 1
    pageParams.value.size = 5;
    // pageParams.value.size = 5;
    tableList.value = []
    isMore.value = true
    getTableList()
src/views/Home/RSide.vue
@@ -1,5 +1,5 @@
<template>
    <div class="ai-chat">
    <div class="ai-chat" v-show="isHideBottomIcon">
        <el-popover placement="bottom" :visible="visible" :width="200" trigger="click">
            <template #reference>
                <div class="chat" id="chatID" v-drag:chatID @mousedown="handleMouseDown" @mouseup="handleMouseUp" />
@@ -11,7 +11,7 @@
        </el-popover>
        <img class="chat-bottom" src="../../assets/images/chat-bottom.png" alt="" />
    </div>
    <div class="r-side">
    <div class="r-side" v-show="isHideBottomIcon">
        <img
            v-for="(item, index) in images"
            :key="index"
@@ -49,6 +49,8 @@
const store = useStore()
const currentAreaPosition = computed(() => store.state.home.currentAreaPosition)
// 事件概况 展开隐藏
const isHideBottomIcon = computed(() => store.state.common.isHideBottomIcon)
let activeIndex = ref(null)
const activeChange = value => {
src/views/Home/SearchBox.vue
@@ -21,7 +21,7 @@
        :load="load"
        :props="props"
        style="width: 240px"
        @change="treeChange"
        @node-click="handleNodeClick"
      />
    </div>
  </div>
@@ -47,9 +47,9 @@
const searchBoxRef = ref(null);
const selectDownRef = ref(null);
function treeChange(value, node) {
  areaValue.value = node.label;
  store.commit('setSelectedAreaCode', value);
function handleNodeClick(data) {
  areaValue.value = data.name;
  store.commit('setSelectedAreaCode', data.code);
}
const props = {
@@ -93,9 +93,7 @@
// 获取机巢搜索结果
const getDeviceList = async () => {
  const res = await selectDeviceList({
    keyword: searchKey.value,
  });
  const res = await selectDeviceList({nickname: searchKey.value});
  if (res.data.code !== 0) return;
  machineNestList.value = res?.data?.data || [];
  downList.value = res?.data?.data || [];
@@ -144,11 +142,12 @@
watch(searchKey, async (newVal) => {
  if (optionsValue.value === '2') {
    await getAddressList();
  } else {
    await getDeviceList();
  }
}, { immediate: false });
onMounted(() => {
  getDeviceList();
  document.addEventListener('click', handleClickOutside);
});
@@ -166,8 +165,8 @@
.select-down-list {
  position: absolute;
  top: 188px;
  left: 45%;
  transform: translateX(-45%);
  left: 44%;
  transform: translateX(-40%);
  width: 220px;
  height: 256px;
  overflow-y: auto;
@@ -175,6 +174,7 @@
  border-radius: 0px 0px 8px 8px;
  border: 1px solid;
  border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1;
  opacity: 0.8;
  &::-webkit-scrollbar {
    width: 0;
    display: none;
@@ -187,6 +187,11 @@
    line-height: 32px;
    text-align: center;
    cursor: pointer;
    &:hover {
      background: linear-gradient( 90deg, rgba(0,122,255,0) 0%, rgba(0,98,204,0.6) 50%, rgba(0,73,153,0) 100%);
      border: 1px solid;
      border-image: linear-gradient(90deg, rgba(0, 199, 190, 0), rgba(48, 176, 199, 1), rgba(0, 199, 190, 0)) 1 1;
    }
  }
}
.searchBox {
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceEvent.vue
@@ -2,45 +2,48 @@
    <div class="deviceevent-container">
        <div class="machineTableDetailsTitle">
            <p>
                相关事件<span>{{ total }}</span
                >件
                相关事件
                <span>{{ total }}</span>
                件
            </p>
        </div>
        <div class="deviceevent-table ztzf-table" >
            <el-table :data="list" :row-class-name="tableRowClassName"
            style="width: 100%;"
            :row-style="{ height: '38px', fontSize: '14px', 'text-align': 'center' }"
            :header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }">
            <el-table-column label="序号" type="index" width="60">
        <div class="deviceevent-table ztzf-table">
            <el-table
                :data="list"
                :row-class-name="tableRowClassName"
                style="width: 100%"
                :row-style="{ height: '35px', fontSize: '14px', 'text-align': 'center' }"
                :header-cell-style="{ 'text-align': 'center', height: '30px', fontSize: '14px' }"
            >
                <el-table-column label="序号" type="index" width="60">
                    <template #default="{ $index }">
                        {{ ($index + 1).toString().padStart(2, '0') }}
                    </template>
                </el-table-column>
            <el-table-column prop="id" label="事件编号" />
            <el-table-column prop="event_name" label="事件名称" />
            <el-table-column prop="create_user" label="所属单位 " />
            <el-table-column show-overflow-tooltip prop="remark" label="事件内容" />
            <el-table-column show-overflow-tooltip prop="ai_types" label="关联算法" />
            <el-table-column prop="status" label="事件状态">
                <template #default="scope">
                    <div class="pending" v-if="scope.row.status === 0">待处理</div>
                    <div class="reviewed" v-if="scope.row.status === 2">待审核</div>
                    <div class="processing" v-if="scope.row.status === 3">处理中</div>
                    <div class="done" v-if="scope.row.status === 4">已完成</div>
                    <div class="ended" v-if="scope.row.status === 5">已完结</div>
                </template>
            </el-table-column>
            <el-table-column label="操作" width="80">
                <template #default="scope">
                <div class="ztzf-view" @click="distribution(scope.row)">查看</div>
                </template>
            </el-table-column>
        </el-table>
                <el-table-column prop="id" label="事件编号" />
                <el-table-column prop="event_name" label="事件名称" />
                <el-table-column prop="create_user" label="所属单位 " />
                <el-table-column show-overflow-tooltip prop="remark" label="事件内容" />
                <el-table-column show-overflow-tooltip prop="ai_types" label="关联算法" />
                <el-table-column prop="status" label="事件状态">
                    <template #default="scope">
                        <div class="pending" v-if="scope.row.status === 0">待处理</div>
                        <div class="reviewed" v-if="scope.row.status === 2">待审核</div>
                        <div class="processing" v-if="scope.row.status === 3">处理中</div>
                        <div class="done" v-if="scope.row.status === 4">已完成</div>
                        <div class="ended" v-if="scope.row.status === 5">已完结</div>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="80">
                    <template #default="scope">
                        <div class="ztzf-view" @click="distribution(scope.row)">查看</div>
                    </template>
                </el-table-column>
            </el-table>
        </div>
        <el-pagination
        class="ztzf-pagination"
            class="ztzf-pagination"
            background
            v-model:current-page="sizeParams.current"
            v-model:page-size="sizeParams.size"
            layout="prev, pager, next, jumper"
@@ -79,11 +82,7 @@
        const resData = res?.data?.data || {}
        list.value = resData.records
        total.value = resData.total
    })
}
const pageChange = val => {
    sizeParams.value.current = val
@@ -103,11 +102,10 @@
</script>
<style scoped lang="scss">
// 标题
.machineTableDetailsTitle {
    margin: 0 24px;
    margin-bottom: 16px;
    margin-bottom: 10px;
    background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
    background-size: 100% 100%;
    p {
@@ -127,38 +125,36 @@
}
// 表格
.deviceevent-table {
padding: 0 17px;
    padding: 0 17px;
}
// 分页
:deep(.el-pagination) {
    display: flex;
    justify-content: center;
}
:deep(.el-pagination button) {
    background: center center no-repeat none !important;
    color: #8eb8ea !important;
}
// 待处理
.pending{
color: #FF7411;
.pending {
    color: #ff7411;
}
// 待审核
.reviewed{
color: #8CFEA7;
.reviewed {
    color: #8cfea7;
}
// 处理中
.processing{
color: #FFC398;
.processing {
    color: #ffc398;
}
// 已完成
.done{
color: #AFD9FB;
.done {
    color: #afd9fb;
}
// 已完结
.ended{
color: #11C4FF;
.ended {
    color: #11c4ff;
}
</style>
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJob.vue
@@ -12,8 +12,8 @@
                :data="list"
                :row-class-name="tableRowClassName"
                style="width: 100%"
                :row-style="{ height: '38px', fontSize: '14px', 'text-align': 'center' }"
                :header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }"
                :row-style="{ height: '35px', fontSize: '14px', 'text-align': 'center' }"
                :header-cell-style="{ 'text-align': 'center', height: '30px', fontSize: '14px' }"
            >
                <el-table-column label="序号" type="index" width="60">
                    <template #default="{ $index }">
@@ -100,7 +100,7 @@
// 标题
.machineTableDetailsTitle {
    margin: 0 24px;
    margin-bottom: 16px;
    margin-bottom: 10px;
    background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
    background-size: 100% 100%;
    p {
@@ -121,15 +121,9 @@
// 表格
.devicelob-table {
    padding: 0 17px;
    // height: 280px;
    // overflow: hidden;
    // overflow-y: scroll !important;
}
// :deep(::-webkit-scrollbar) {
//     width: 0;
//     display: none;
//     background: none !important;
// }
// 分页
:deep(.el-pagination) {
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue
@@ -1,4 +1,4 @@
<!-- 任务详情 -->
<!-- 历史任务详情 -->
<template>
    <el-dialog
        class="ztzf-dialog"
@@ -24,7 +24,7 @@
                    </div>
                    <div class="itemBoxRight">
                        <div class="itemTitle">关联算法:</div>
                        <div class="itemValue">{{ flystatus }}</div>
                        <div class="itemValue">{{ flystatus ? flystatus :'' }}</div>
                    </div>
                </div>
                <JobRelatedEvents v-if="isShow" />
@@ -123,7 +123,7 @@
            if (item.name === '任务时间') {
                item.value = detailsData.value.begin_time.slice(0, 10) + '-' + detailsData.value.end_time.slice(0, 10)
            } else if (item.name === '任务频次') {
                item.value = detailsData.value.rep_rule_type + ' -- ' + detailsData.value.rep_rule_val
                item.value ===undefined ? '' : detailsData.value.rep_rule_type + ' -- ' + detailsData.value.rep_rule_val
            } else {
                item.value = detailsData.value?.[item.field] || ''
            }
@@ -240,14 +240,16 @@
        }
        .imgListBox {
            display: flex;
            flex-wrap: wrap;
            // display: flex;
            // flex-wrap: wrap;
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 10px;
            .imgItem {
                width: 200px;
                height: 200px;
            }
            margin-bottom: 49px;
            // .imgItem {
            //     width: 200px;
            //     height: 200px;
            // }
        }
    }
src/views/SignMachineNest/MachineRight/MachineStatus/MachineTableDetails/MachineTableDetails.vue
@@ -70,12 +70,10 @@
<style lang="scss">
.machineTableDetails {
    width: 1270px;
    height: 856px;
    .el-pagination {
        text-align: left;
        padding: 20px 20px 0 20px;
        padding: 10px 20px 5px 10px;
    }
    .my-header {
        display: inline-block;
@@ -90,7 +88,7 @@
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 14px;
    margin-bottom: 10px;
    font-size: 14px;
    color: #ffffff;
    .itemBox {
@@ -115,7 +113,7 @@
    margin: 0 24px;
}
.machineTableDetailsTitle {
    margin-bottom: 16px;
    margin-bottom: 10px;
    background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
    background-size: 100% 100%;
    span {
src/views/SignMachineNest/SignMachineNest.vue
@@ -1,98 +1,119 @@
<template>
  <MachineLeft></MachineLeft>
  <MachineRight></MachineRight>
    <MachineLeft></MachineLeft>
    <MachineRight></MachineRight>
</template>
<script setup>
import MachineLeft from '@/views/SignMachineNest/MachineLeft/MachineLeft.vue'
import MachineRight from '@/views/SignMachineNest/MachineRight/MachineRight.vue';
import { useConnectWebSocket } from '@/utils/websocket/connect-websocket';
import { getWebsocketUrl } from '@/websocket/util/config';
import { EBizCode } from '@/utils/staticData/enums.js';
import { EModeCode } from '@/utils/staticData/device.js';
import { useStore } from 'vuex';
import { getDeviceDetail, getFlightStatistics } from '@/api/home/machineNest';
import MachineRight from '@/views/SignMachineNest/MachineRight/MachineRight.vue'
import { useConnectWebSocket } from '@/utils/websocket/connect-websocket'
import { getWebsocketUrl } from '@/websocket/util/config'
import { EBizCode } from '@/utils/staticData/enums.js'
import { EModeCode } from '@/utils/staticData/device.js'
import { useStore } from 'vuex'
import { getDeviceDetail, getFlightStatistics, getEventList } from '@/api/home/machineNest'
import { useSingleDroneMap } from '@/hooks/useSingleDroneMap/useSingleDroneMap'
const store = useStore();
let connectWs = ref(null);
const store = useStore()
let connectWs = ref(null)
// 单个机巢信息
const singleUavHome = computed(() => store.state.home.singleUavHome);
const singleUavHome = computed(() => store.state.home.singleUavHome)
const selectedAreaCode = computed(() => store.state.user.selectedAreaCode)
let osdVisible = ref({});
let osdVisible = ref({})
let workspaceId = ref('');
let workspaceId = ref('')
// 进入单个机巢开始连接ws
const createWsConntect = () => {
  let webSorketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId.value;
  // 监听ws 消息
  connectWs.value = useConnectWebSocket(messageHandler, webSorketUrl);
};
    let webSorketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId.value
    // 监听ws 消息
    connectWs.value = useConnectWebSocket(messageHandler, webSorketUrl)
}
const messageHandler = (result) => {
  let payload = JSON.parse(result) // 为了兼容聊天消息
  if (!payload) return
  switch (payload.biz_code) {
    case EBizCode.GatewayOsd: {
      store.commit('setGatewayInfo', payload.data)
      break
    }
    case EBizCode.DeviceOsd: {
      // console.log(payload, 'DeviceOsd')
      store.commit('setDeviceInfo', payload)
      store.commit('setWsMessage', payload)
      break
    }
    case EBizCode.DockOsd: {
      store.commit('setDockOnfo', payload.data)
      break
    }
    default:
          break
  }
};
const messageHandler = result => {
    let payload = JSON.parse(result) // 为了兼容聊天消息
    if (!payload) return
    switch (payload.biz_code) {
        case EBizCode.GatewayOsd: {
            store.commit('setGatewayInfo', payload.data)
            break
        }
        case EBizCode.DeviceOsd: {
            // console.log(payload, 'DeviceOsd')
            store.commit('setDeviceInfo', payload)
            store.commit('setWsMessage', payload)
            break
        }
        case EBizCode.DockOsd: {
            store.commit('setDockOnfo', payload.data)
            break
        }
        default:
            break
    }
}
// 单机巢初始化及事件撒点
const { init, initEventLayer, initDroneEntity } = useSingleDroneMap({
    eventApi: getEventList,
    eventApiParams: {
        device_sn: singleUavHome.value.device_sn,
    },
})
// 获取单个机巢信息
const getSingleDetails = () => {
  getDeviceDetail(singleUavHome.value.device_sn).then((res) => {
    if (res.data.code !== 0) return;
    const result = res.data.data;
    const child = result.children;
    // 对应store 里面数据结构
    osdVisible.value.sn = child?.device_sn || ''
    osdVisible.value.callsign = child?.nickname || '--'
    osdVisible.value.model = EModeCode.Disconnected || ''
    osdVisible.value.visible = true
    osdVisible.value.gateway_sn = result?.device_sn || ''
    osdVisible.value.is_dock = true
    osdVisible.value.gateway_callsign = result?.callsign || '--'
    osdVisible.value.payloads = child?.payloads_list || []
    osdVisible.value.device_domain = child.domain || 0
    osdVisible.value.device_sub_type = child.sub_type || 1
    osdVisible.value.device_type = child.type || 0
    // osdVisible.value.latest_wayline_job = result?.latest_wayline_job || {}
    store.commit('setOsdVisibleInfo', osdVisible.value);
    store.commit('setSelectedWorkSpaceId', result.workspace_id);
    workspaceId.value = result.workspace_id;
    createWsConntect();
  });
};
    getDeviceDetail(singleUavHome.value.device_sn).then(res => {
        if (res.data.code !== 0) return
        const result = res.data.data
        initDroneEntity({
            lng: result.longitude,
            lat: result.latitude,
            status: result.status,
        })
        const child = result.children
        // 对应store 里面数据结构
        osdVisible.value.sn = child?.device_sn || ''
        osdVisible.value.callsign = child?.nickname || '--'
        osdVisible.value.model = EModeCode.Disconnected || ''
        osdVisible.value.visible = true
        osdVisible.value.gateway_sn = result?.device_sn || ''
        osdVisible.value.is_dock = true
        osdVisible.value.gateway_callsign = result?.callsign || '--'
        osdVisible.value.payloads = child?.payloads_list || []
        osdVisible.value.device_domain = child.domain || 0
        osdVisible.value.device_sub_type = child.sub_type || 1
        osdVisible.value.device_type = child.type || 0
        // osdVisible.value.latest_wayline_job = result?.latest_wayline_job || {}
        store.commit('setOsdVisibleInfo', osdVisible.value)
        store.commit('setSelectedWorkSpaceId', result.workspace_id)
        workspaceId.value = result.workspace_id
        createWsConntect()
    })
}
// 获取机巢统计数据 提供给左右侧组件使用
const getMachineData = () => {
  getFlightStatistics(singleUavHome.value.device_sn).then(res => {
    if (res.data.code !== 0) return;
    const result = res.data.data;
    store.commit('setSingleTotal', result);
  })
};
    getFlightStatistics(singleUavHome.value.device_sn).then(res => {
        if (res.data.code !== 0) return
        const result = res.data.data
        store.commit('setSingleTotal', result)
    })
}
onMounted(() => {
  getSingleDetails();
  getMachineData();
});
    nextTick(() => {
        init()
    })
    initEventLayer()
    getSingleDetails()
    getMachineData()
})
onUnmounted(() => {
  connectWs?.value?.close();
});
    connectWs?.value?.close()
})
</script>
src/views/TaskManage/TaskIntermediateContent/AddTask.vue
@@ -1,49 +1,71 @@
<!-- 机巢列表详情 -->
<!-- 新建任务 -->
<template>
    <el-dialog
        class="ztzf-dialog"
        modal-class="add-task"
        v-model="isShowAddTask"
        title="新建任务"
        :width="pxToRem(1500)"
        :close-on-click-modal="false"
        :destroy-on-close="true">
        :destroy-on-close="true"
    >
        <!-- <el-divider content-position="left">新建任务</el-divider> -->
        <div class="task-contain">
            <div class="left">
                <div class="search">
                    <div class="item"><span class="required">*</span>任务名称:<el-input v-model="searchForm.name" placeholder="请输入任务名称"></el-input></div>
                    <div class="item"><span class="required">*</span>任务日期:
                    <div class="item">
                        <el-input class="ztzf-input" v-model="searchForm.name" placeholder="请输入任务/机巢名称"></el-input>
                    </div>
                    <div class="item">
                        <el-date-picker
                            class="ztzf-date-picker"
                            v-model="taskData"
                            format="YYYY-MM-DD"
                            type="daterange"
                            range-separator="至"
                            start-placeholder="开始日期"
                            end-placeholder="结束日期"
                            value-format="YYYY-MM-DD"
                            :disabled-date="disabledDate"
                            @change="changeselect"
                        />
                    </div>
                    <div class="item">任务时间:
                    <div class="item">
                        <div class="itemchild">任务时间:</div>
                        <el-time-picker
                            class="ztzf-date-picker tasktimer"
                            v-model="timeSlot"
                            placeholder="选择时间"
                            placeholder="请选择"
                            format="HH:mm"
                            value-format="HH:mm"/>
                            value-format="HH:mm"
                        />
                    </div>
                    <div class="item">选择航线:
                    <div class="item">
                        <div class="itemchild">选择航线:</div>
                        <el-select
                            class="ztzf-select"
                            v-model="searchForm.file_id"
                            @change="getWayLineFile"
                            placeholder="请选择航线"
                            clearable>
                            clearable
                        >
                            <el-option
                                v-for="item in routeOptions"
                                :key="item.wayline_id"
                                :label="item.name"
                                :value="item.wayline_id"/>
                            </el-select>
                        </div>
                        <div class="item">关联算法:
                            <TaskAlgorithmBusiness :showAlgorithm="true" @algorithmChange="algorithmChange"/>
                        </div>
                    <div class="item">任务描述:<el-input v-model="searchForm.remark" placeholder="请输入任务名称"></el-input></div>
                                :value="item.wayline_id"
                            />
                        </el-select>
                    </div>
                    <div class="item">
                        <div class="itemchild">关联算法:</div>
                        <TaskAlgorithmBusiness  :setWidth="200" :showAlgorithm="true" @algorithmChange="algorithmChange" />
                    </div>
                    <div class="item">
                        <div class="itemchild">任务描述:</div>
                        <el-input class="ztzf-input" v-model="searchForm.remark" placeholder="请输入任务名称"></el-input>
                    </div>
                </div>
                <div class="lines">
                    <div class="wayline-type">
@@ -52,26 +74,29 @@
                            <el-radio :value="2" label="智能规划选区"></el-radio>
                        </el-radio-group>
                    </div>
                    <TaskMap class="wayline-map"
                    <TaskMap
                        class="wayline-map"
                        :wayLineFile="wayLineFile"
                        :checkedTableData="checkedTableData"
                        :waylineTypeTest="waylineType"
                        :waylineTypeTest="waylineType"
                        @clickPosition="clickSignPosition"
                        @saveWayline="savePlanerWayline"
                    />
                </div>
            </div>
            <div class="right">
                <TaskTable ref="taskTableRef"
                    :waylineId="waylineId"
                    :waylineType="waylineType"
            <div class="right ">
                <TaskTable
                    ref="taskTableRef"
                    :waylineId="waylineId"
                    :waylineType="waylineType"
                    :singlePoint="singlePoint"
                    :planarPoints="planarPoints"
                    @update:selected="handleSelected"
                    @update:selected="handleSelected"
                />
                <div class="btn">
                    <el-button type="primary" @click="cancel">取消</el-button>
                    <el-button type="primary" @click="submitClick">发布</el-button>
                    <img @click="cancel" style="margin-right:23px" src="@/assets/images/task/cancel.png" alt="">
                    <img @click="submitClick" src="@/assets/images/task/publish.png" alt="">
                </div>
            </div>
        </div>
@@ -79,26 +104,26 @@
</template>
<script setup>
import { ElMessage } from 'element-plus';
import { pxToRem } from '@/utils/rem';
import { getWaylineList, createTask } from '@/api/home/task';
import TaskAlgorithmBusiness from '../components/TaskAlgorithmBusiness.vue';
import TaskMap from './TaskMap.vue';
import TaskTable from './TaskTable.vue';
import { ElMessage } from 'element-plus'
import { pxToRem } from '@/utils/rem'
import { getWaylineList, createTask } from '@/api/home/task'
import TaskAlgorithmBusiness from '../components/TaskAlgorithmBusiness.vue'
import TaskMap from './TaskMap.vue'
import TaskTable from './TaskTable.vue'
const emit = defineEmits(['refresh']);
const emit = defineEmits(['refresh'])
const rangDate = ref([]);
const rangDate = ref([])
// 航线ID
const waylineId = ref('');
const waylineId = ref('')
// 航线文件
const wayLineFile = ref('');
const wayLineFile = ref('')
// 航线类型
const waylineType = ref(3);
const waylineType = ref(3)
// 添加子组件引用
const taskTableRef = ref(null);
const taskData = ref('');
const timeSlot = ref('');
const taskTableRef = ref(null)
const taskData = ref('')
const timeSlot = ref('')
const searchForm = reactive({
    name: '',
    ai_types: [],
@@ -112,157 +137,157 @@
    longitude: '',
    latitude: '',
    polygon: [],
});
const isShowAddTask = defineModel('show');
})
const isShowAddTask = defineModel('show')
// 禁用当天之前的日期
const disabledDate = (time) => {
  return time.getTime() < Date.now() - 8.64e7; // 86400000 = 24 * 60 * 60 * 1000
};
const disabledDate = time => {
    return time.getTime() < Date.now() - 8.64e7 // 86400000 = 24 * 60 * 60 * 1000
}
// 获取航线列表数据
const routeOptions = ref([]);
const routeOptions = ref([])
const getRouteList = async () => {
  const res = await getWaylineList();
  if (res.data.code === 0) {
    routeOptions.value = res.data.data;
  }
};
    const res = await getWaylineList()
    if (res.data.code === 0) {
        routeOptions.value = res.data.data
    }
}
// 关联算法
const algorithmChange = (val) => {
  searchForm.ai_types = val;
};
const algorithmChange = val => {
    searchForm.ai_types = val
}
// 切换航线类型
const radioChange = (val) => {
const radioChange = val => {
    // 清空选中航线值
    searchForm.file_id = '';
    searchForm.file_id = ''
    // 航线ID也清空
    waylineId.value = '';
    wayLineFile.value = '';
  waylineType.value = val;
    searchForm.type = val;
    waylineId.value = ''
    wayLineFile.value = ''
    waylineType.value = val
    searchForm.type = val
    // 清空列表数据
    nextTick(() => {
    if (taskTableRef.value) {
      taskTableRef.value.clearTableData();
    }
  });
};
        if (taskTableRef.value) {
            taskTableRef.value.clearTableData()
        }
    })
}
// 获取航线文件
const getWayLineFile = async (val) => {
    searchForm.type = 0;
    waylineType.value = 0;
    waylineId.value = val;
    const currentRoute = routeOptions.value.find(item => item.wayline_id === val);
  wayLineFile.value = currentRoute.object_key;
};
const getWayLineFile = async val => {
    searchForm.type = 0
    waylineType.value = 0
    waylineId.value = val
    const currentRoute = routeOptions.value.find(item => item.wayline_id === val)
    wayLineFile.value = currentRoute.object_key
}
// 获取选中机场列表数据,并且发布
let checkedTableData = ref([]);
const handleSelected = (val) => {
  searchForm.dock_sns = val.map(item => item.device_sn);
    checkedTableData.value = val;
};
let checkedTableData = ref([])
const handleSelected = val => {
    searchForm.dock_sns = val.map(item => item.device_sn)
    checkedTableData.value = val
}
// 地图点击事件 表格重新刷新数据
let singlePoint = ref({});
const clickSignPosition = (val) => {
  singlePoint.value = val;
    searchForm.longitude = val.longitude;
    searchForm.latitude = val.latitude;
};
let singlePoint = ref({})
const clickSignPosition = val => {
    singlePoint.value = val
    searchForm.longitude = val.longitude
    searchForm.latitude = val.latitude
}
// 保存面状航线
let planarPoints = ref([]);
const savePlanerWayline = (val) => {
  planarPoints.value = val;
    const polygonArray = val.map(point => [point.longitude, point.latitude]);
    searchForm.polygon = polygonArray;
};
let planarPoints = ref([])
const savePlanerWayline = val => {
    planarPoints.value = val
    const polygonArray = val.map(point => [point.longitude, point.latitude])
    searchForm.polygon = polygonArray
}
// 提交
const submitClick = () => {
    if (!taskData.value) {
    ElMessage({
      message: '请选择任务日期',
      type: 'warning'
    });
    return;
  }
        ElMessage({
            message: '请选择任务日期',
            type: 'warning',
        })
        return
    }
    if (!searchForm.name) {
    ElMessage({
      message: '请输入任务名称',
      type: 'warning'
    });
    return;
  }
        ElMessage({
            message: '请输入任务名称',
            type: 'warning',
        })
        return
    }
    // 检查任务时间
  if (timeSlot.value) {
    const now = new Date();
    const today = now.toDateString();
    const selectedDate = new Date(taskData.value).toDateString();
    if (today === selectedDate) {
      const [hours, minutes] = timeSlot.value.split(':');
      const selectedTime = new Date();
      selectedTime.setHours(parseInt(hours), parseInt(minutes));
      if (selectedTime < now) {
        ElMessage({
          message: '任务时间不能小于当前时间',
          type: 'warning'
        });
        return;
      }
    }
  }
    if (timeSlot.value) {
        const now = new Date()
        const today = now.toDateString()
        const selectedDate = new Date(taskData.value).toDateString()
        if (today === selectedDate) {
            const [hours, minutes] = timeSlot.value.split(':')
            const selectedTime = new Date()
            selectedTime.setHours(parseInt(hours), parseInt(minutes))
            if (selectedTime < now) {
                ElMessage({
                    message: '任务时间不能小于当前时间',
                    type: 'warning',
                })
                return
            }
        }
    }
    if (searchForm.dock_sns.length === 0) {
        ElMessage({
            message: '请选择机场',
            type: 'warning'
        });
        return;
            type: 'warning',
        })
        return
    }
    searchForm.begin_time = `${taskData.value} 00:00:00`;
  searchForm.end_time = `${taskData.value} 23:59:59`;
    searchForm.execute_time_arr = timeSlot.value ? [timeSlot.value] : [];
    createTask(searchForm).then((res) => {
    searchForm.begin_time = `${taskData.value} 00:00:00`
    searchForm.end_time = `${taskData.value} 23:59:59`
    searchForm.execute_time_arr = timeSlot.value ? [timeSlot.value] : []
    createTask(searchForm).then(res => {
        if (res.data.code === 0) {
            ElMessage.success('任务创建成功');
            ElMessage.success('任务创建成功')
            // 关闭当前窗口,刷新任务管理列表
            isShowAddTask.value = false;
            isShowAddTask.value = false
            // 清除数据
            cancel();
            emit('refresh');
            cancel()
            emit('refresh')
        }
    });
};
    })
}
const cancel = () => {
  isShowAddTask.value = false;
    isShowAddTask.value = false
    // 清除搜索数据
    searchForm.name = '';
  searchForm.ai_types = [];
  searchForm.file_id = '';
  searchForm.begin_time = '';
  searchForm.end_time = '';
  timeSlot.value = '';
  searchForm.remark = '';
  searchForm.dock_sns = [];
  rangDate.value = [];
  waylineId.value = '';
  wayLineFile.value = '';
    taskData.value = '';
};
    searchForm.name = ''
    searchForm.ai_types = []
    searchForm.file_id = ''
    searchForm.begin_time = ''
    searchForm.end_time = ''
    timeSlot.value = ''
    searchForm.remark = ''
    searchForm.dock_sns = []
    rangDate.value = []
    waylineId.value = ''
    wayLineFile.value = ''
    taskData.value = ''
}
onMounted(() => {
  getRouteList();
    getRouteList()
})
</script>
<style lang="scss">
.add-task{
.add-task {
    .el-pagination {
        text-align: left;
        padding: 20px;
@@ -273,52 +298,72 @@
<style lang="scss" scoped>
.task-contain {
    display: flex;
    padding: 20px 32px 32px 27px;
    .left {
        width: 68%;
        margin-right: 35px;
        .search {
            display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-template-rows: repeat(2, 1fr);
      gap: 30px; // 增加间距使布局更合理
      margin-bottom: 8px; // 添加底部间距
            grid-template-columns: repeat(3, 1fr);
            grid-template-rows: repeat(2, 1fr);
            gap: 30px; // 增加间距使布局更合理
            margin-bottom: 8px; // 添加底部间距
            .item {
                position: relative;
        display: flex;
        align-items: center;
        :deep(.el-input),
        :deep(.el-select),
        :deep(.el-date-picker),
        :deep(.el-time-picker) {
          width: 240px;
          // margin-left: 10px;
        }
                :deep(.el-date-editor.el-input__wrapper) {
          width: 200px;  // 调整日期选择器宽度
        }
                .required {
                    color: #f56c6c;
                    margin-left: 4px;
                    position: absolute;
                    left: -10px;
                    top: 8px;
                display: flex;
                align-items: center;
                font-size: 16px;
                color: #ffffff;
                .itemchild {
                width: 68px;
                 white-space: nowrap;
                margin-right: 5px;
                }
      }
                :deep(.el-date-editor.el-input__wrapper) {
                    width: 200px; // 调整日期选择器宽度
                }
            }
        }
    }
    .right {
        width: 32%;
        display: flex;
    flex-direction: column;
    justify-content: space-between;
    .btn {
      margin-top: 20px;
      text-align: center;
      .el-button {
        margin: 0 10px;
      }
    }
        flex-direction: column;
        justify-content: space-between;
        .btn {
            display: flex;
            justify-content: center;
            align-items: center;
            img {
            width: 137px;
            height: 32px;
            cursor: pointer;
            }
        }
    }
    :deep(.tasktimer .el-input__wrapper) {
        background: none !important;
        color: #8ac3fd !important;
    }
    :deep(.el-input__inner) {
        color: #8ac3fd !important;
        &::placeholder {
            color: #8ac3fd !important;
        }
    }
    :deep(.el-radio__inner){
    background: none !important;
    border: 1px solid #1B5D9A !important;
    }
    :deep(.el-radio__label){
    color: #fff !important;
    }
    :deep(.el-radio__inner:after ){
    background: #65B5FF !important;
    }
}
</style>
src/views/TaskManage/TaskIntermediateContent/TaskMap.vue
@@ -7,33 +7,37 @@
import AmapMercatorTilingScheme from '@/utils/cesium/AmapMercatorTilingScheme'
import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'
import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial'
import lineImg from '@/assets/images/arrow-right-blue.png';
import Startingpointicon from '@/assets/images/Startingpointicon.png';
import EndPointicon from '@/assets/images/EndPointicon.png';
import lineImg from '@/assets/images/arrow-right-blue.png'
import Startingpointicon from '@/assets/images/Startingpointicon.png'
import EndPointicon from '@/assets/images/EndPointicon.png'
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
import { getCenterPoint } from '@/utils/cesium/mapUtil'
import { getWaylineByArea } from '@/api/home/task';
import { useStore } from 'vuex';
const store = useStore();
const userAreaPosition = computed(() => store.state.home.userAreaPosition);
import { getWaylineByArea } from '@/api/home/task'
import { useStore } from 'vuex'
import { addBlueFilter } from '@/utils/cesium/common'
// 新图片
import newStartPoint from '@/assets/images/newStartPoint.png'
import newEndPointImg from '@/assets/images/newEndPointicon.png'
import newlineImg from '@/assets/images/newarrow-right.png'
const store = useStore()
const userAreaPosition = computed(() => store.state.home.userAreaPosition)
// 声明事件
const emit = defineEmits(['clickPosition', 'saveWayline']);
const emit = defineEmits(['clickPosition', 'saveWayline'])
const props = defineProps({
    wayLineFile: {
    type: String,
    default: ''
  },
  checkedTableData: {
    type: Array,
    default: () => []
  },
        type: String,
        default: '',
    },
    checkedTableData: {
        type: Array,
        default: () => [],
    },
    waylineTypeTest: {
    type: Number,
    default: 3
  }
        type: Number,
        default: 3,
    },
})
const imageryProvider_ammapSL = new Cesium.UrlTemplateImageryProvider({
@@ -46,17 +50,16 @@
    maximumLevel: 18,
    tilingScheme: new AmapMercatorTilingScheme(),
    credit: 'amap_SL',
});
})
let viewer = null;
let currentEntity = null;
let connectLines = []; // 存储连接线实体
let polygonPoints = []; // 存储多边形的点
let polygonEntity = null; // 存储多边形实体
let existingEntity = null; // 后端返回数据生成得面状线
let viewer = null
let currentEntity = null
let connectLines = [] // 存储连接线实体
let polygonPoints = [] // 存储多边形的点
let polygonEntity = null // 存储多边形实体
let existingEntity = null // 后端返回数据生成得面状线
// 添加变量跟踪当前菜单
let currentMenu = null;
let currentMenu = null
const init = () => {
    viewer = new Viewer('taskMap', {
@@ -74,80 +77,81 @@
        fullscreenButton: false,
        // sceneMode: Cesium.SceneMode.COLUMBUS_VIEW,
    })
    viewer.imageryLayers.addImageryProvider(imageryProvider_ammapSL)
    viewer.scene.morphTo2D(0);
    const gdLayer = viewer.imageryLayers.addImageryProvider(imageryProvider_ammapSL)
    const options = {
        bInvertColor: true,
        bFilterColor: true,
        filterColor: '#4e70a6',
    }
    // 添加蓝色滤镜
    addBlueFilter(options, viewer, gdLayer)
    viewer.scene.morphTo2D(0)
    //设置默认点
    const { longitude = 115.763819, latitude = 28.787374, height = 10 } = userAreaPosition.value || {};
    const { longitude = 115.763819, latitude = 28.787374, height = 10 } = userAreaPosition.value || {}
    viewer.camera.setView({
        destination: Cartesian3.fromDegrees(longitude, latitude, height),
    });
    })
}
// 单点左键点击事件
const singlePointLeftClick = () => {
  viewer.screenSpaceEventHandler.setInputAction((click) => {
    viewer.screenSpaceEventHandler.setInputAction(click => {
        if (props.waylineTypeTest !== 1) return
    const cartesian = viewer.camera.pickEllipsoid(
      click.position,
      viewer.scene.globe.ellipsoid
    );
    if (cartesian) {
      // 清除之前的实体
      viewer.entities.removeAll();
      // 添加新点
      const point = viewer.entities.add({
        position: cartesian,
        point: {
          pixelSize: 10,
          color: Cesium.Color.WHITE
        }
      });
      // 转换坐标
      const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
      const longitude = Cesium.Math.toDegrees(cartographic.longitude);
      const latitude = Cesium.Math.toDegrees(cartographic.latitude);
      // 更新当前实体引用
      currentEntity = point;
      // 发送坐标
      emit('clickPosition', { longitude, latitude });
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
};
        const cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
        if (cartesian) {
            // 清除之前的实体
            viewer.entities.removeAll()
            // 添加新点
            const point = viewer.entities.add({
                position: cartesian,
                point: {
                    pixelSize: 10,
                    color: Cesium.Color.fromCssColorString('#1FFF69'),
                },
            })
            // 转换坐标
            const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
            const longitude = Cesium.Math.toDegrees(cartographic.longitude)
            const latitude = Cesium.Math.toDegrees(cartographic.latitude)
            // 更新当前实体引用
            currentEntity = point
            // 发送坐标
            emit('clickPosition', { longitude, latitude })
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
// 智能规划航线
const intelligentPlanning = () => {
    // 添加点击事件监听
  viewer.screenSpaceEventHandler.setInputAction((click) => {
    viewer.screenSpaceEventHandler.setInputAction(click => {
        if (props.waylineTypeTest !== 2) return
        const cartesian = viewer.camera.pickEllipsoid(
            click.position,
            viewer.scene.globe.ellipsoid
        );
        const cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
        if (cartesian) {
            // 添加新点
            const point = viewer.entities.add({
                position: cartesian,
                point: {
                    pixelSize: 10,
                    color: Cesium.Color.WHITE
                }
            });
                    color: Cesium.Color.fromCssColorString('#1FFF69'),
                },
            })
            // 存储点位
            polygonPoints.push(cartesian);
            polygonPoints.push(cartesian)
            // 当点击超过2个点时绘制多边形
            if (polygonPoints.length > 2) {
                // 移除旧的多边形
                if (polygonEntity) {
                    viewer.entities.remove(polygonEntity);
                    viewer.entities.remove(polygonEntity)
                }
                // 创建新的多边形
                polygonEntity = viewer.entities.add({
                    polygon: {
@@ -159,110 +163,109 @@
                        outlineColor: new Cesium.Color(0, 0.5, 1, 1), // 蓝
                        outlineWidth: 2,
                        height: 0, // Set explicit height
                        heightReference: Cesium.HeightReference.NONE // Disable terrain clamping
                    }
                });
                        heightReference: Cesium.HeightReference.NONE, // Disable terrain clamping
                    },
                })
            }
            // 转换坐标并发送
            const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
            const longitude = Cesium.Math.toDegrees(cartographic.longitude);
            const latitude = Cesium.Math.toDegrees(cartographic.latitude);
            const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
            const longitude = Cesium.Math.toDegrees(cartographic.longitude)
            const latitude = Cesium.Math.toDegrees(cartographic.latitude)
            // emit('clickPosition', cartographic);
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    // 修改右键点击事件,添加菜单
    viewer.screenSpaceEventHandler.setInputAction((movement) => {
    viewer.screenSpaceEventHandler.setInputAction(movement => {
        if (props.waylineTypeTest !== 2) return
        if (polygonPoints.length > 2) {
            // 清除之前的菜单
            if (currentMenu) {
                document.body.querySelectorAll('.context-menu').forEach(menu => menu.remove());
                document.body.querySelectorAll('.context-menu').forEach(menu => menu.remove())
            }
            const menuContainer = document.createElement('div');
            menuContainer.className = 'context-menu';
            const menuContainer = document.createElement('div')
            menuContainer.className = 'context-menu'
            // 获取地图容器
            const mapContainer = document.getElementById('taskMap');
            const mapContainer = document.getElementById('taskMap')
            // 使用鼠标右键点击的实际位置
            menuContainer.style.position = 'absolute';
            menuContainer.style.left = `${movement.position.x}px`;
            menuContainer.style.top = `${movement.position.y}px`;
            menuContainer.style.zIndex = '1000';
            menuContainer.style.position = 'absolute'
            menuContainer.style.left = `${movement.position.x}px`
            menuContainer.style.top = `${movement.position.y}px`
            menuContainer.style.zIndex = '1000'
            menuContainer.innerHTML = `
                <div class="menu-item" id="saveWayline">保存航线</div>
                <div class="menu-item" id="cancelDraw">取消绘制</div>
            `;
            mapContainer.appendChild(menuContainer);
            currentMenu = menuContainer;
            `
            mapContainer.appendChild(menuContainer)
            currentMenu = menuContainer
            // 添加全局点击事件监听
            const handleClickOutside = (e) => {
                if (!menuContainer) return;
                const isClickInside = menuContainer.contains(e.target);
            const handleClickOutside = e => {
                if (!menuContainer) return
                const isClickInside = menuContainer.contains(e.target)
                if (!isClickInside) {
                    menuContainer.remove();
                    document.removeEventListener('mousedown', handleClickOutside);
                    menuContainer.remove()
                    document.removeEventListener('mousedown', handleClickOutside)
                }
            };
            }
            // 延迟添加事件监听,避免右键点击立即触发
            setTimeout(() => {
                document.addEventListener('mousedown', handleClickOutside);
            }, 100);
                document.addEventListener('mousedown', handleClickOutside)
            }, 100)
            // 菜单按钮点击事件
            document.getElementById('saveWayline').onclick = () => {
                const coordinates = polygonPoints.map(point => {
                    const cartographic = Cesium.Cartographic.fromCartesian(point);
                    const cartographic = Cesium.Cartographic.fromCartesian(point)
                    return {
                        longitude: Cesium.Math.toDegrees(cartographic.longitude),
                        latitude: Cesium.Math.toDegrees(cartographic.latitude)
                    };
                });
                emit('saveWayline', coordinates);
                saveWaylineByArea(coordinates);
                mapContainer.removeChild(menuContainer);
            };
                        latitude: Cesium.Math.toDegrees(cartographic.latitude),
                    }
                })
                emit('saveWayline', coordinates)
                saveWaylineByArea(coordinates)
                mapContainer.removeChild(menuContainer)
            }
            document.getElementById('cancelDraw').onclick = () => {
                polygonPoints = [];
                viewer.entities.removeAll();
                mapContainer.removeChild(menuContainer);
            };
                polygonPoints = []
                viewer.entities.removeAll()
                mapContainer.removeChild(menuContainer)
            }
        }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
};
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
// 保存航线并且获取线
const saveWaylineByArea = (dataValue) => {
    const polygonArray = dataValue.map(point => [point.longitude, point.latitude]);
const saveWaylineByArea = dataValue => {
    const polygonArray = dataValue.map(point => [point.longitude, point.latitude])
    getWaylineByArea({ type: 2, polygon: polygonArray }).then(res => {
        if (res.data.code !== 0) retrun;
        drawResultWayline(res.data.data);
    });
        if (res.data.code !== 0) retrun
        drawResultWayline(res.data.data)
    })
}
// 绘制后端生成得面状线
const drawResultWayline = (dataValue) => {
const drawResultWayline = dataValue => {
    // 先检查并删除已存在的航线
  existingEntity = viewer.entities.getById('result_wayline');
  if (existingEntity) {
    viewer.entities.remove(existingEntity);
  }
    const cartesian3List = ref([]);
    dataValue.forEach((lnglat) => {
    existingEntity = viewer.entities.getById('result_wayline')
    if (existingEntity) {
        viewer.entities.remove(existingEntity)
    }
    const cartesian3List = ref([])
    dataValue.forEach(lnglat => {
        const cartesian3 = Cesium.Cartesian3.fromDegrees(
            Number(lnglat.x),
            Number(lnglat.y),
            Number(100), // 默认100
            Number(100) // 默认100
        )
        cartesian3List.value.push(cartesian3)
    });
    })
    const setting = {
        id: 'result_wayline',
        polyline: {
@@ -275,7 +278,7 @@
        polyline: setting.polyline,
        id: setting.id,
    })
};
}
// 选中航线时调用 渲染线和点 type = 0
const renderingLine = lineObj => {
@@ -283,83 +286,90 @@
        const [lon, lat] = item.Point.coordinates.split(',')
        return Cartesian3.fromDegrees(Number(lon), Number(lat))
    })
    viewer.entities.add({
        polyline: {
            width: 4,
            width: 5,
            positions: positions,
            material: new ImageTrailMaterial({
                color: { alpha: 1, blue: 1, green: 1, red: 1 },
                speed: 20,
                image: lineImg,
                repeat: { x: Math.floor(40), y: 1 },
            // material: new ImageTrailMaterial({
            //     color: { alpha: 1, blue: 1, green: 1, red: 1 },
            //     speed: 20,
            //     image: newlineImg,
            //     repeat: { x: Math.floor(40), y: 1 },
            // }),
            material: new Cesium.PolylineGlowMaterialProperty({
                // color: Cesium.Color.GREEN,
                image: newlineImg,
            }),
            clampToGround: false,
        },
    })
  positions.forEach((point, index) => {
    let setting = {};
    // if (index === 0) {
    //   //TODO
    // }
    positions.forEach((point, index) => {
        let setting = {}
        // if (index === 0) {
        //   //TODO
        // }
        // else if (index === 1) {
    //   setting = {
    //     position: point,
    //     id: `point_${index}`,
    //     billboard: {
    //       image: Startingpointicon,
    //       outlineWidth: 0,
    //       width: 20,
    //       height: 20,
    //       scale: 1.0,
    //     },
    //   }
    // } else
        //   setting = {
        //     position: point,
        //     id: `point_${index}`,
        //     billboard: {
        //       image: Startingpointicon,
        //       outlineWidth: 0,
        //       width: 20,
        //       height: 20,
        //       scale: 1.0,
        //     },
        //   }
        // } else
        if (index === positions.length - 1) {
      setting = {
        position: point,
        id: `point_${index}`,
        billboard: {
          image: EndPointicon,
          outlineWidth: 0,
          width: 20,
          height: 20,
          scale: 1.0,
        },
      }
    } else {
      setting = {
        position: point,
        id: `point_${index}`,
        label: {
          text: `${index+1}`,
          font: 'bold 14px serif',
          style: Cesium.LabelStyle.FILL,
          verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直居中
          horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平居中
          pixelOffset: new Cesium.Cartesian2(0, 0), // 根据需要调整偏移量
          eyeOffset: new Cesium.Cartesian3(0, 0, -10) // 使标签在点的上方
        },
            setting = {
                position: point,
                id: `point_${index}`,
                billboard: {
                    image: newEndPointImg,
                    outlineWidth: 0,
                    width: 20,
                    height: 20,
                    scale: 1.0,
                },
            }
        } else {
            setting = {
                position: point,
                id: `point_${index}`,
                label: {
                    text: `${index + 1}`,
                    font: 'bold 14px serif',
                    fillColor: Cesium.Color.WHITE,
                    //     style: Cesium.LabelStyle.FILL,
                    //     verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直居中
                    //     horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平居中
                        pixelOffset: new Cesium.Cartesian2(2, 0), // 根据需要调整偏移量
                    eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 使标签在点的上方
                },
                billboard: {
                    image: new Cesium.ConstantProperty(newStartPoint),
                    width: 70,
                    height: 70,
                },
                // point: {
                //     pixelSize: 24,
                //     color: new Cesium.Color.fromBytes(255, 186, 0, 255),
                // },
        point: {
          pixelSize: 24,
          color: new Cesium.Color.fromBytes(255, 186, 0, 255),
        },
        offset: new Cesium.Cartesian2(10, 30),
      }
    }
    viewer.entities.add(setting)
  });
                offset: new Cesium.Cartesian2(10, 30),
            }
        }
        viewer.entities.add(setting)
    })
}
// 飞到中心点
function flyToPoints(lngLatArr) {
    if (!Array.isArray(lngLatArr) || lngLatArr.length === 0) return
    const positions = lngLatArr.map(([lon, lat]) =>
        Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat))
    )
    const positions = lngLatArr.map(([lon, lat]) => Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat)))
    // 计算包围盒 BoundingSphere(所有点的外接球)
    const boundingSphere = Cesium.BoundingSphere.fromPoints(positions)
    viewer.camera.flyToBoundingSphere(boundingSphere, {
@@ -368,11 +378,10 @@
    })
}
// 异步解析kmz文件
const analysis = async url => {
    return new Promise(async resolve => {
        const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`);
        const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`)
        const templateXML = await res.fileInfoObj['wpmz/template.kml']
        const templateXMLJSON = XMLToJSON(templateXML)?.['Document']
        const templateXMLObj = removeTextKey(templateXMLJSON.Folder)
@@ -382,16 +391,16 @@
// 绘制线和飞行
const drawLine = async () => {
  let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL+ props.wayLineFile);
    const res = await analysis(prexUrl.value);
    let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL + props.wayLineFile)
    const res = await analysis(prexUrl.value)
    if (!res.Placemark.length) return
  renderingLine(res);
    renderingLine(res)
    const points = res.Placemark.map(item => item.Point.coordinates.split(','))
    flyToPoints(points)
}
// 选择航线时,根据选择机巢连线
const selectLineFile = (newVal) => {
const selectLineFile = newVal => {
    // 清除之前的实体
    // viewer.entities.removeAll();
    // 重新绘制航线
@@ -400,7 +409,7 @@
    // }
    // 添加选中点和连接线
    const positions = newVal.map(item => {
        const position = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude));
        const position = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude))
        // 添加机巢点
        viewer.entities.add({
            position: position,
@@ -409,9 +418,9 @@
                width: 24,
                height: 24,
            },
        });
        return position;
    });
        })
        return position
    })
    // 添加连接线
    if (positions.length > 1) {
@@ -421,33 +430,30 @@
                width: 2,
                material: new Cesium.PolylineDashMaterialProperty({
                    color: Cesium.Color.RED,
                    dashLength: 8.0
                })
            }
        });
                    dashLength: 8.0,
                }),
            },
        })
    }
    // 飞到中心点
    const lngLatArr = newVal.map(item => [item.longitude, item.latitude]);
    flyToPoints(lngLatArr);
};
    const lngLatArr = newVal.map(item => [item.longitude, item.latitude])
    flyToPoints(lngLatArr)
}
// 单个点生成选择多个机巢生成航线
const singlePointLines = (newVal) => {
const singlePointLines = newVal => {
    // 清除之前的连接线
    connectLines.forEach(line => viewer.entities.remove(line));
    connectLines = [];
    connectLines.forEach(line => viewer.entities.remove(line))
    connectLines = []
    if (currentEntity) {
        // 获取当前点的位置
        const currentPosition = currentEntity.position.getValue();
        const currentPosition = currentEntity.position.getValue()
        // 为每个选中的机巢创建点和连接线
        newVal.forEach(item => {
            // 创建机巢点
            const nestPosition = Cartesian3.fromDegrees(
                Number(item.longitude),
                Number(item.latitude)
            );
            const nestPosition = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude))
            viewer.entities.add({
                position: nestPosition,
                billboard: {
@@ -455,7 +461,7 @@
                    width: 24,
                    height: 24,
                },
            });
            })
            // 创建连接线
            const line = viewer.entities.add({
@@ -464,155 +470,163 @@
                    width: 2,
                    material: new Cesium.PolylineDashMaterialProperty({
                        color: Cesium.Color.RED,
                        dashLength: 8.0
                    })
                }
            });
            connectLines.push(line);
        });
                        dashLength: 8.0,
                    }),
                },
            })
            connectLines.push(line)
        })
        // 飞到所有点的中心位置
        const lngLatArr = newVal.map(item => [item.longitude, item.latitude]);
        flyToPoints(lngLatArr);
        const lngLatArr = newVal.map(item => [item.longitude, item.latitude])
        flyToPoints(lngLatArr)
    }
};
}
// 智慧规划航线-面状航线
const planarPointsLines = (newVal) => {
  // 如果存在面状航线
  if (existingEntity) {
    const waylinePositions = existingEntity.polyline.positions.getValue();
    newVal.forEach(item => {
      // 创建机巢点
      const nestPosition = Cartesian3.fromDegrees(
        Number(item.longitude),
        Number(item.latitude)
      );
      // 添加机巢图标
      viewer.entities.add({
        position: nestPosition,
        billboard: {
          image: new Cesium.ConstantProperty(uavImg),
          width: 24,
          height: 24,
        },
      });
const planarPointsLines = newVal => {
    // 如果存在面状航线
    if (existingEntity) {
        const waylinePositions = existingEntity.polyline.positions.getValue()
      // 找到最近的航线点并连线
      let minDistance = Number.MAX_VALUE;
      let closestPosition = null;
      waylinePositions.forEach(waylinePos => {
        const distance = Cartesian3.distance(nestPosition, waylinePos);
        if (distance < minDistance) {
          minDistance = distance;
          closestPosition = waylinePos;
        }
      });
        newVal.forEach(item => {
            // 创建机巢点
            const nestPosition = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude))
      // 创建连接线
      if (closestPosition) {
        const line = viewer.entities.add({
          polyline: {
            positions: [nestPosition, closestPosition],
            width: 2,
            material: new Cesium.PolylineDashMaterialProperty({
              color: Cesium.Color.CHARTREUSE,
              dashLength: 8.0
            })
          }
        });
        connectLines.push(line);
      }
    });
            // 添加机巢图标
            viewer.entities.add({
                position: nestPosition,
                billboard: {
                    image: new Cesium.ConstantProperty(uavImg),
                    width: 24,
                    height: 24,
                },
            })
    // 飞到所有点的中心位置
    const lngLatArr = newVal.map(item => [item.longitude, item.latitude]);
    flyToPoints(lngLatArr);
  }
};
            // 找到最近的航线点并连线
            let minDistance = Number.MAX_VALUE
            let closestPosition = null
            waylinePositions.forEach(waylinePos => {
                const distance = Cartesian3.distance(nestPosition, waylinePos)
                if (distance < minDistance) {
                    minDistance = distance
                    closestPosition = waylinePos
                }
            })
            // 创建连接线
            if (closestPosition) {
                const line = viewer.entities.add({
                    polyline: {
                        positions: [nestPosition, closestPosition],
                        width: 2,
                        material: new Cesium.PolylineDashMaterialProperty({
                            color: Cesium.Color.CHARTREUSE,
                            dashLength: 8.0,
                        }),
                    },
                })
                connectLines.push(line)
            }
        })
        // 飞到所有点的中心位置
        const lngLatArr = newVal.map(item => [item.longitude, item.latitude])
        flyToPoints(lngLatArr)
    }
}
// 监听选择航线文件事件
watch(() => props.wayLineFile, async (newVal, oldValue) => {
    await removeMap();
    if(newVal){
        await drawLine();
    }
}, { deep: true });
watch(
    () => props.wayLineFile,
    async (newVal, oldValue) => {
        await removeMap()
        if (newVal) {
            await drawLine()
        }
    },
    { deep: true }
)
// 监听表格选中数据变化
watch(() => props.checkedTableData, (newVal) => {
    if (newVal.length > 0 && props.waylineTypeTest === 0) {
        selectLineFile(newVal);
    } else if (newVal.length > 0 && props.waylineTypeTest === 1) {
        singlePointLines(newVal);
    } else if (newVal.length > 0 && props.waylineTypeTest === 2) {
        planarPointsLines(newVal);
    }
}, { deep: true });
watch(
    () => props.checkedTableData,
    newVal => {
        if (newVal.length > 0 && props.waylineTypeTest === 0) {
            selectLineFile(newVal)
        } else if (newVal.length > 0 && props.waylineTypeTest === 1) {
            singlePointLines(newVal)
        } else if (newVal.length > 0 && props.waylineTypeTest === 2) {
            planarPointsLines(newVal)
        }
    },
    { deep: true }
)
// 监听航线类型
watch(() => props.waylineTypeTest, async (newVal) => {
    await removeMap();
    if (newVal === 1) {
        await singlePointLeftClick();
    } else if (newVal === 2) {
        await intelligentPlanning();
    }
}, { deep: true });
watch(
    () => props.waylineTypeTest,
    async newVal => {
        await removeMap()
        if (newVal === 1) {
            await singlePointLeftClick()
        } else if (newVal === 2) {
            await intelligentPlanning()
        }
    },
    { deep: true }
)
const removeEvent = () => {
    // 清除事件监听器
    viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
    viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
};
const removeMap = () => {
  // 清除所有实体
  if (viewer) {
    // 清除连接线
    connectLines.forEach(line => viewer.entities.remove(line));
    connectLines = [];
    // 清除多边形点和实体
    polygonPoints = [];
    if (polygonEntity) {
      viewer.entities.remove(polygonEntity);
    }
    // 清除当前实体和面状航线
    if (currentEntity) {
      viewer.entities.remove(currentEntity);
    }
    if (existingEntity) {
      viewer.entities.remove(existingEntity);
    }
        viewer.entities.removeAll();
    // 重置所有变量
    currentEntity = null;
    polygonEntity = null;
    existingEntity = null;
  }
    viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
const removeMap = () => {
    // 清除所有实体
    if (viewer) {
        // 清除连接线
        connectLines.forEach(line => viewer.entities.remove(line))
        connectLines = []
        // 清除多边形点和实体
        polygonPoints = []
        if (polygonEntity) {
            viewer.entities.remove(polygonEntity)
        }
        // 清除当前实体和面状航线
        if (currentEntity) {
            viewer.entities.remove(currentEntity)
        }
        if (existingEntity) {
            viewer.entities.remove(existingEntity)
        }
        viewer.entities.removeAll()
        // 重置所有变量
        currentEntity = null
        polygonEntity = null
        existingEntity = null
    }
}
onBeforeUnmount(() => {
    removeMap();
    removeEvent();
    removeMap()
    removeEvent()
    // 移除所有实体并销毁viewer
    viewer.destroy();
    viewer = null;
    viewer.destroy()
    viewer = null
})
onMounted(() => {
    nextTick(() => {
        init()
    })
});
})
</script>
<style scoped lang="scss">
#taskMap {
@@ -644,14 +658,14 @@
            display: none;
        }
    }
:deep(.context-menu) {
    position: absolute;
    background: rgba(0, 21, 41, 0.9);;
    border-radius: 4px;
    padding: 8px 0;
    min-width: 120px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
    :deep(.context-menu) {
        position: absolute;
        background: rgba(0, 21, 41, 0.9);
        border-radius: 4px;
        padding: 8px 0;
        min-width: 120px;
        box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
        .menu-item {
            padding: 8px 16px;
@@ -659,12 +673,11 @@
            cursor: pointer;
            transition: all 0.3s;
            font-size: 14px;
            &:hover {
                background: rgba(255, 255, 255, 0.1);
            }
        }
    }
}
</style>
src/views/TaskManage/TaskIntermediateContent/TaskTable.vue
@@ -1,189 +1,230 @@
<template>
  <div class="table-container">
    <el-table :data="tableData" style="width: 100%" height="400"
      @selection-change="handleSelectionChange"
      @select="handleSelect">
      <el-table-column type="selection" width="55" :selectable="checkSelectable" />
      <el-table-column type="index" label="序号" width="60" />
      <el-table-column prop="nickname" label="机巢名称" />
      <el-table-column prop="estimated_arrival_time" label="预计到达时间" />
      <el-table-column prop="exe_distance" label="执行里程" />
    </el-table>
    <div class="pagination">
      <el-pagination
        v-model:current-page="pagingParams.page"
        v-model:page-size="pagingParams.size"
        :page-sizes="[10, 20, 30]"
        layout="total, sizes, prev, pager, next"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
    <div class="table-container ztzf-table">
        <div class="taskTableTitle"><span>可飞行机巢列表</span></div>
        <el-table
            :data="tableData"
            style="width: 100%"
            height="400"
            :row-style="{ height: '38px', fontSize: '14px', 'text-align': 'center' }"
            :header-cell-style="{ 'text-align': 'center', height: '36px', fontSize: '14px' }"
            @selection-change="handleSelectionChange"
            @select="handleSelect"
        >
            <el-table-column type="selection" width="55" :selectable="checkSelectable" />
            <el-table-column type="index" label="序号" width="60" >
                <template #default="{ $index }">
                        {{ ($index + 1).toString().padStart(2, '0') }}
                    </template>
            </el-table-column>
            <el-table-column show-overflow-tooltip prop="nickname" label="机巢名称" />
            <el-table-column show-overflow-tooltip width="120" prop="estimated_arrival_time" label="预计到达时间" />
            <el-table-column show-overflow-tooltip prop="exe_distance" label="执行里程" />
        </el-table>
        <div class="pagination">
            <el-pagination
                class="ztzf-pagination"
                v-model:current-page="pagingParams.page"
                v-model:page-size="pagingParams.size"
                :page-sizes="[10, 20, 30]"
                layout=" prev, pager, next"
                :total="total"
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
            />
        </div>
    </div>
</template>
<script setup>
import { getFlyingNestBy } from '@/api/home/task';
import { getFlyingNestBy } from '@/api/home/task'
const props = defineProps({
  waylineId: {
    type: String,
    default: ''
  },
  waylineType: {
    type: Number,
    default: 3
  },
  singlePoint: {
    type: Object,
    default: () => ({})
  },
  planarPoints: {
    type: Array,
    default: () => ([])
  }
});
    waylineId: {
        type: String,
        default: '',
    },
    waylineType: {
        type: Number,
        default: 3,
    },
    singlePoint: {
        type: Object,
        default: () => ({}),
    },
    planarPoints: {
        type: Array,
        default: () => [],
    },
})
// 选中的数据
const selectedRows = ref([]);
const selectedRows = ref([])
// 分页参数
let pageParams = ref({
  wayline_id: props.waylineId,
  type: props.waylineType,
  longitude: props.singlePoint.longitude,
  latitude: props.singlePoint.latitude,
  polygon: [],
});
    wayline_id: props.waylineId,
    type: props.waylineType,
    longitude: props.singlePoint.longitude,
    latitude: props.singlePoint.latitude,
    polygon: [],
})
let pagingParams = ref({
  current: 1,
  size: 10
});
    current: 1,
    size: 10,
})
// 获取可用机巢列表数据
const total = ref(0);
const tableData = ref([]);
const total = ref(0)
const tableData = ref([])
const getNestList = async () => {
    tableData.value = [];
  const res = await getFlyingNestBy(pageParams.value, pagingParams.value);
  if (res.data.code === 0) {
    tableData.value = res.data.data;
  }
};
    tableData.value = []
    const res = await getFlyingNestBy(pageParams.value, pagingParams.value)
    if (res.data.code === 0) {
        tableData.value = res.data.data
    }
}
// 分页大小改变
const handleSizeChange = (val) => {
  pagingParams.value.size = val;
  getNestList();
};
const handleSizeChange = val => {
    pagingParams.value.size = val
    getNestList()
}
// 页码改变
const handleCurrentChange = (val) => {
  pagingParams.value.current = val;
  getNestList();
};
const handleCurrentChange = val => {
    pagingParams.value.current = val
    getNestList()
}
// 刷新数据
const refreshData = () => {
  tableData.value = [];
  pagingParams.value.current = 1;
  getNestList();
};
    tableData.value = []
    pagingParams.value.current = 1
    getNestList()
}
const emit = defineEmits(['update:selected']);
const handleSelectionChange = (val) => {
  // 如果不是智能规划选区模式,才更新所有选中数据
  if (props.waylineType !== 2) {
    selectedRows.value = val;
    emit('update:selected', val);
  }
};
const emit = defineEmits(['update:selected'])
const handleSelectionChange = val => {
    // 如果不是智能规划选区模式,才更新所有选中数据
    if (props.waylineType !== 2) {
        selectedRows.value = val
        emit('update:selected', val)
    }
}
// 控制表格行是否可选
const checkSelectable = (row) => {
  if (props.waylineType === 2) {
    // 如果已经有选中的行,且当前行未被选中,则不允许选择
    return selectedRows.value.length === 0 || selectedRows.value.some(selected => selected.device_sn === row.device_sn);
  }
  return true;
};
const checkSelectable = row => {
    if (props.waylineType === 2) {
        // 如果已经有选中的行,且当前行未被选中,则不允许选择
        return selectedRows.value.length === 0 || selectedRows.value.some(selected => selected.device_sn === row.device_sn)
    }
    return true
}
// 处理单行选择
const handleSelect = (selection, row) => {
  if (props.waylineType === 2) {
    // 如果是智能规划选区模式,确保只能选中一行
    if (selection.length > 1) {
      // 保留最后选中的那一行
      const lastSelected = selection[selection.length - 1];
      selectedRows.value = [lastSelected];
      // 触发更新事件
      emit('update:selected', selectedRows.value);
    }
  }
};
    if (props.waylineType === 2) {
        // 如果是智能规划选区模式,确保只能选中一行
        if (selection.length > 1) {
            // 保留最后选中的那一行
            const lastSelected = selection[selection.length - 1]
            selectedRows.value = [lastSelected]
            // 触发更新事件
            emit('update:selected', selectedRows.value)
        }
    }
}
// 监听航线ID变化
watch(() => props.waylineId, (newVal) => {
  pageParams.value.type = 0;
  if (newVal) {
    pageParams.value.wayline_id = newVal;
    refreshData();
  } else {
    // 数据为空时,清除列表数据
    tableData.value = [];
  }
}, { deep: true });
watch(
    () => props.waylineId,
    newVal => {
        pageParams.value.type = 0
        if (newVal) {
            pageParams.value.wayline_id = newVal
            refreshData()
        } else {
            // 数据为空时,清除列表数据
            tableData.value = []
        }
    },
    { deep: true }
)
// 监听单点返回的数据
watch(() => props.singlePoint, (newVal) => {
  pageParams.value.wayline_id = '';
  pageParams.value.type = 1;
  if (newVal && newVal.latitude && newVal.longitude) {
    pageParams.value.latitude = newVal.latitude;
    pageParams.value.longitude = newVal.longitude;
    refreshData();
  }
}, { deep: true });
watch(
    () => props.singlePoint,
    newVal => {
        pageParams.value.wayline_id = ''
        pageParams.value.type = 1
        if (newVal && newVal.latitude && newVal.longitude) {
            pageParams.value.latitude = newVal.latitude
            pageParams.value.longitude = newVal.longitude
            refreshData()
        }
    },
    { deep: true }
)
// 监听面状航线返回的数据
watch(() => props.planarPoints, (newVal) => {
  pageParams.value.wayline_id = '';
  pageParams.value.type = 2;
  if (newVal && newVal.length > 0) {
    const polygonArray = newVal.map(point => [point.longitude, point.latitude]);
    pageParams.value.polygon = polygonArray;
    refreshData();
  }
}, { deep: true });
watch(
    () => props.planarPoints,
    newVal => {
        pageParams.value.wayline_id = ''
        pageParams.value.type = 2
        if (newVal && newVal.length > 0) {
            const polygonArray = newVal.map(point => [point.longitude, point.latitude])
            pageParams.value.polygon = polygonArray
            refreshData()
        }
    },
    { deep: true }
)
// 暴露给父组件的方法
const clearTableData = () => {
  tableData.value = [];
};
    tableData.value = []
}
defineExpose({
  clearTableData
});
onMounted(() => {});
    clearTableData,
})
// 表格隔行变色
const tableRowClassName = ({ row, rowIndex }) => {
    if (rowIndex % 2 === 1) {
        return 'warning-row'
    } else {
        return 'success-row'
    }
}
onMounted(() => {})
</script>
<style lang="scss" scoped>
.table-container {
  height: 500px;
  // display: flex;
  // flex-direction: column;
  .pagination {
    margin-top: 10px;
  }
  // :deep(.el-table) {
  //   flex: 1;
  //   background-color: transparent;
  //   --el-table-border-color: rgba(255, 255, 255, 0.1);
  //   --el-table-header-bg-color: rgba(31, 62, 122, 0.5);
  //   --el-table-header-text-color: #fff;
  //   --el-table-text-color: #fff;
  // }
    height: 500px;
    .pagination {
        margin-top: 10px;
    }
    // 分页
    :deep(.el-pagination) {
        display: flex;
        justify-content: center;
    }
    .taskTableTitle {
        margin-bottom: 16px;
        background: url('/src/assets/images/signMachineNest/machineRight/detailtitle.png') no-repeat center;
        background-size: 100% 100%;
        span {
            display: inline-block;
            margin-left: 10px;
            font-size: 16px;
            color: #ddf0ff;
            line-height: 20px;
            text-align: left;
            margin-bottom: 8px;
        }
    }
    :deep(.el-checkbox__inner){
    background:  none !important;
    border: 1px solid #3194EF !important;
    }
}
</style>
src/views/TaskManage/TaskTop/TaskTime.vue
@@ -107,7 +107,6 @@
// 添加监听
watch(() => store.state.task.taskSearchParams, (newVal) => {
  console.log(newVal, '33333');
  if (newVal) {
    getJobNumBar(newVal);
    (newVal);
vite.config.mjs.timestamp-1744707003737-1868137d88f2d.mjs
New file
@@ -0,0 +1,187 @@
// vite.config.mjs
import {
  defineConfig,
  loadEnv
} from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite/dist/node/index.js";
import { resolve } from "path";
// vite/plugins/index.js
import vue from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/@vitejs/plugin-vue/dist/index.mjs";
// vite/plugins/auto-import.js
import autoImport from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/unplugin-auto-import/dist/vite.js";
function createAutoImport() {
  return autoImport({
    imports: ["vue", "vue-router", "vuex"],
    dts: false
  });
}
// vite/plugins/compression.js
import compression from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite-plugin-compression/dist/index.mjs";
function createCompression(env) {
  const { VITE_BUILD_COMPRESS } = env;
  const plugin = [];
  if (VITE_BUILD_COMPRESS) {
    const compressList = VITE_BUILD_COMPRESS.split(",");
    if (compressList.includes("gzip")) {
      plugin.push(
        compression({
          ext: ".gz",
          deleteOriginFile: false
        })
      );
    }
    if (compressList.includes("brotli")) {
      plugin.push(
        compression({
          ext: ".br",
          algorithm: "brotliCompress",
          deleteOriginFile: false
        })
      );
    }
  }
  return plugin;
}
// vite/plugins/setup-extend.js
import setupExtend from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite-plugin-vue-setup-extend/dist/index.mjs";
function createSetupExtend() {
  return setupExtend();
}
// vite/plugins/svg-plugin.js
import { createSvgIconsPlugin } from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/vite-plugin-svg-icons/dist/index.mjs";
import path from "path";
function createSvgPlugin() {
  return createSvgIconsPlugin({
    iconDirs: [path.resolve(process.cwd(), "src/assets/svg")],
    //svg图片存放的目录
    symbolId: "icon-[name]",
    // symbol的id
    inject: "body-last",
    // 插入的位置
    customDomId: "__svg__icons__dom__"
    // svg的id
  });
}
// vite/plugins/index.js
function createVitePlugins(viteEnv, isBuild = false) {
  const vitePlugins = [vue()];
  vitePlugins.push(createAutoImport());
  vitePlugins.push(createSetupExtend());
  vitePlugins.push(createSvgPlugin());
  isBuild && vitePlugins.push(...createCompression(viteEnv));
  return vitePlugins;
}
// vite.config.mjs
import postCssPxToRem from "file:///E:/%E9%99%88%E7%91%B6/%E4%B8%AD%E5%9B%BE%E6%99%BA%E9%A3%9E/command-center-dashboard/node_modules/postcss-pxtorem/index.js";
var __vite_injected_original_dirname = "E:\\\u9648\u7476\\\u4E2D\u56FE\u667A\u98DE\\command-center-dashboard";
var vite_config_default = ({
  mode,
  command
}) => {
  const env = loadEnv(mode, process.cwd());
  const {
    VITE_APP_ENV,
    VITE_APP_BASE,
    VITE_APP_API_URL
  } = env;
  const isProd = VITE_APP_ENV === "production";
  const buildConfig = {
    target: "esnext",
    minify: isProd ? "terser" : "esbuild"
    // 根据环境选择压缩工具
  };
  if (isProd) {
    buildConfig.terserOptions = {
      compress: {
        drop_console: true,
        // 删除 console
        drop_debugger: true
        // 删除 debugger
      },
      format: {
        comments: false
        // 删除所有注释
      }
    };
    buildConfig.rollupOptions = {
      output: {
        manualChunks: {
          "element-plus": ["element-plus"],
          "@smallwei/avue": ["@smallwei/avue"]
        }
      }
    };
  }
  return defineConfig({
    base: VITE_APP_BASE,
    define: {
      __VUE_I18N_FULL_INSTALL__: true,
      __VUE_I18N_LEGACY_API__: true,
      __INTLIFY_PROD_DEVTOOLS__: false
    },
    server: {
      // port: 2888,
      proxy: {
        "/api": {
          target: VITE_APP_API_URL,
          changeOrigin: true,
          rewrite: (path2) => path2.replace(/^\/api/, "")
        }
      }
    },
    resolve: {
      alias: {
        "~": resolve(__vite_injected_original_dirname, "./"),
        "@": resolve(__vite_injected_original_dirname, "./src"),
        components: resolve(__vite_injected_original_dirname, "./src/components"),
        styles: resolve(__vite_injected_original_dirname, "./src/styles"),
        utils: resolve(__vite_injected_original_dirname, "./src/utils")
      }
    },
    css: {
      preprocessorOptions: {
        scss: {
          api: "modern-compiler",
          additionalData: `@use "@/styles/variables.scss" as *;`
        }
      },
      postcss: {
        plugins: [
          postCssPxToRem({
            rootValue: 10,
            // 指定转换基准值,通常是设计稿宽度的1/10
            propList: ["*"],
            // 可以从px转换为rem的属性,这里是所有属性
            unitPrecision: 5,
            // 允许REM单位增长到的十进制数
            selectorBlackList: [],
            // 选择器黑名单,忽略转换的选择器
            replace: true,
            // 替换包含rem的规则,而不是添加回退
            mediaQuery: false,
            // 允许在媒体查询中转换px
            minPixelValue: 0
            // 设置要替换的最小像素值
          })
        ]
      }
    },
    plugins: createVitePlugins(env, command === "build"),
    build: buildConfig,
    optimizeDeps: {
      esbuildOptions: {
        target: "esnext"
      }
    }
  });
};
export {
  vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcubWpzIiwgInZpdGUvcGx1Z2lucy9pbmRleC5qcyIsICJ2aXRlL3BsdWdpbnMvYXV0by1pbXBvcnQuanMiLCAidml0ZS9wbHVnaW5zL2NvbXByZXNzaW9uLmpzIiwgInZpdGUvcGx1Z2lucy9zZXR1cC1leHRlbmQuanMiLCAidml0ZS9wbHVnaW5zL3N2Zy1wbHVnaW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZS5jb25maWcubWpzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9FOi8lRTklOTklODglRTclOTElQjYvJUU0JUI4JUFEJUU1JTlCJUJFJUU2JTk5JUJBJUU5JUEzJTlFL2NvbW1hbmQtY2VudGVyLWRhc2hib2FyZC92aXRlLmNvbmZpZy5tanNcIjtpbXBvcnQge1xyXG4gIGRlZmluZUNvbmZpZyxcclxuICBsb2FkRW52XHJcbn0gZnJvbSAndml0ZSc7XHJcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tICdwYXRoJ1xyXG5pbXBvcnQgY3JlYXRlVml0ZVBsdWdpbnMgZnJvbSAnLi92aXRlL3BsdWdpbnMnO1xyXG5pbXBvcnQgcG9zdENzc1B4VG9SZW0gZnJvbSAncG9zdGNzcy1weHRvcmVtJ1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgKHtcclxuICBtb2RlLFxyXG4gIGNvbW1hbmRcclxufSkgPT4ge1xyXG4gIGNvbnN0IGVudiA9IGxvYWRFbnYobW9kZSwgcHJvY2Vzcy5jd2QoKSlcclxuICBjb25zdCB7XHJcbiAgICBWSVRFX0FQUF9FTlYsXHJcbiAgICBWSVRFX0FQUF9CQVNFLFxyXG4gICAgVklURV9BUFBfQVBJX1VSTFxyXG4gIH0gPSBlbnZcclxuICAvLyBcdTUyMjRcdTY1QURcdTY2MkZcdTYyNTNcdTc1MUZcdTRFQTdcdTczQUZcdTU4ODNcdTUzMDVcclxuICBjb25zdCBpc1Byb2QgPSBWSVRFX0FQUF9FTlYgPT09ICdwcm9kdWN0aW9uJ1xyXG5cclxuICAvLyBcdTY4MzlcdTYzNkVcdTY2MkZcdTU0MjZcdTc1MUZcdTRFQTdcdTczQUZcdTU4ODNcdUZGMENcdTUyQThcdTYwMDFcdThCQkVcdTdGNkVcdTUzOEJcdTdGMjlcdTkxNERcdTdGNkVcclxuICBjb25zdCBidWlsZENvbmZpZyA9IHtcclxuICAgIHRhcmdldDogJ2VzbmV4dCcsXHJcbiAgICBtaW5pZnk6IGlzUHJvZCA/ICd0ZXJzZXInIDogJ2VzYnVpbGQnLCAvLyBcdTY4MzlcdTYzNkVcdTczQUZcdTU4ODNcdTkwMDlcdTYyRTlcdTUzOEJcdTdGMjlcdTVERTVcdTUxNzdcclxuICB9O1xyXG5cclxuICAvLyBcdTU5ODJcdTY3OUNcdTY2MkZcdTc1MUZcdTRFQTdcdTczQUZcdTU4ODNcdUZGMENcdTZERkJcdTUyQTBUZXJzZXJcdTc2ODRcdTkxNERcdTdGNkVcclxuICBpZiAoaXNQcm9kKSB7XHJcbiAgICBidWlsZENvbmZpZy50ZXJzZXJPcHRpb25zID0ge1xyXG4gICAgICBjb21wcmVzczoge1xyXG4gICAgICAgIGRyb3BfY29uc29sZTogdHJ1ZSwgLy8gXHU1MjIwXHU5NjY0IGNvbnNvbGVcclxuICAgICAgICBkcm9wX2RlYnVnZ2VyOiB0cnVlLCAvLyBcdTUyMjBcdTk2NjQgZGVidWdnZXJcclxuICAgICAgfSxcclxuICAgICAgZm9ybWF0OiB7XHJcbiAgICAgICAgY29tbWVudHM6IGZhbHNlIC8vIFx1NTIyMFx1OTY2NFx1NjI0MFx1NjcwOVx1NkNFOFx1OTFDQVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG4gICAgYnVpbGRDb25maWcucm9sbHVwT3B0aW9ucyA9IHtcclxuICAgICAgb3V0cHV0OiB7XHJcbiAgICAgICAgbWFudWFsQ2h1bmtzOiB7XHJcbiAgICAgICAgICAnZWxlbWVudC1wbHVzJzogWydlbGVtZW50LXBsdXMnXSxcclxuICAgICAgICAgICdAc21hbGx3ZWkvYXZ1ZSc6IFsnQHNtYWxsd2VpL2F2dWUnXVxyXG4gICAgICAgIH0sXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIGRlZmluZUNvbmZpZyh7XHJcbiAgICBiYXNlOiBWSVRFX0FQUF9CQVNFLFxyXG4gICAgZGVmaW5lOiB7XHJcbiAgICAgIF9fVlVFX0kxOE5fRlVMTF9JTlNUQUxMX186IHRydWUsXHJcbiAgICAgIF9fVlVFX0kxOE5fTEVHQUNZX0FQSV9fOiB0cnVlLFxyXG4gICAgICBfX0lOVExJRllfUFJPRF9ERVZUT09MU19fOiBmYWxzZVxyXG4gICAgfSxcclxuICAgIHNlcnZlcjoge1xyXG4gICAgICAvLyBwb3J0OiAyODg4LFxyXG4gICAgICBwcm94eToge1xyXG4gICAgICAgICcvYXBpJzoge1xyXG4gICAgICAgICAgdGFyZ2V0OiBWSVRFX0FQUF9BUElfVVJMLFxyXG4gICAgICAgICAgY2hhbmdlT3JpZ2luOiB0cnVlLFxyXG4gICAgICAgICAgcmV3cml0ZTogcGF0aCA9PiBwYXRoLnJlcGxhY2UoL15cXC9hcGkvLCAnJyksXHJcbiAgICAgICAgfSxcclxuICAgICAgfSxcclxuICAgIH0sXHJcbiAgICByZXNvbHZlOiB7XHJcbiAgICAgIGFsaWFzOiB7XHJcbiAgICAgICAgJ34nOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vJyksXHJcbiAgICAgICAgJ0AnOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjJyksXHJcbiAgICAgICAgY29tcG9uZW50czogcmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9jb21wb25lbnRzJyksXHJcbiAgICAgICAgc3R5bGVzOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjL3N0eWxlcycpLFxyXG4gICAgICAgIHV0aWxzOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjL3V0aWxzJyksXHJcbiAgICAgIH0sXHJcbiAgICB9LFxyXG4gICAgY3NzOiB7XHJcbiAgICAgIHByZXByb2Nlc3Nvck9wdGlvbnM6IHtcclxuICAgICAgICBzY3NzOiB7XHJcbiAgICAgICAgICBhcGk6ICdtb2Rlcm4tY29tcGlsZXInLFxyXG4gICAgICAgICAgYWRkaXRpb25hbERhdGE6IGBAdXNlIFwiQC9zdHlsZXMvdmFyaWFibGVzLnNjc3NcIiBhcyAqO2AsXHJcbiAgICAgICAgfSxcclxuICAgICAgfSxcclxuICAgICAgcG9zdGNzczoge1xyXG4gICAgICAgIHBsdWdpbnM6IFtcclxuICAgICAgICAgIHBvc3RDc3NQeFRvUmVtKHtcclxuICAgICAgICAgICAgcm9vdFZhbHVlOiAxMCwgLy8gXHU2MzA3XHU1QjlBXHU4RjZDXHU2MzYyXHU1N0ZBXHU1MUM2XHU1MDNDXHVGRjBDXHU5MDFBXHU1RTM4XHU2NjJGXHU4QkJFXHU4QkExXHU3QTNGXHU1QkJEXHU1RUE2XHU3Njg0MS8xMFxyXG4gICAgICAgICAgICBwcm9wTGlzdDogWycqJ10sIC8vIFx1NTNFRlx1NEVFNVx1NEVDRXB4XHU4RjZDXHU2MzYyXHU0RTNBcmVtXHU3Njg0XHU1QzVFXHU2MDI3XHVGRjBDXHU4RkQ5XHU5MUNDXHU2NjJGXHU2MjQwXHU2NzA5XHU1QzVFXHU2MDI3XHJcbiAgICAgICAgICAgIHVuaXRQcmVjaXNpb246IDUsIC8vIFx1NTE0MVx1OEJCOFJFTVx1NTM1NVx1NEY0RFx1NTg5RVx1OTU3Rlx1NTIzMFx1NzY4NFx1NTM0MVx1OEZEQlx1NTIzNlx1NjU3MFxyXG4gICAgICAgICAgICBzZWxlY3RvckJsYWNrTGlzdDogW10sIC8vIFx1OTAwOVx1NjJFOVx1NTY2OFx1OUVEMVx1NTQwRFx1NTM1NVx1RkYwQ1x1NUZGRFx1NzU2NVx1OEY2Q1x1NjM2Mlx1NzY4NFx1OTAwOVx1NjJFOVx1NTY2OFxyXG4gICAgICAgICAgICByZXBsYWNlOiB0cnVlLCAvLyBcdTY2RkZcdTYzNjJcdTUzMDVcdTU0MkJyZW1cdTc2ODRcdTg5QzRcdTUyMTlcdUZGMENcdTgwMENcdTRFMERcdTY2MkZcdTZERkJcdTUyQTBcdTU2REVcdTkwMDBcclxuICAgICAgICAgICAgbWVkaWFRdWVyeTogZmFsc2UsIC8vIFx1NTE0MVx1OEJCOFx1NTcyOFx1NUE5Mlx1NEY1M1x1NjdFNVx1OEJFMlx1NEUyRFx1OEY2Q1x1NjM2MnB4XHJcbiAgICAgICAgICAgIG1pblBpeGVsVmFsdWU6IDAgLy8gXHU4QkJFXHU3RjZFXHU4OTgxXHU2NkZGXHU2MzYyXHU3Njg0XHU2NzAwXHU1QzBGXHU1MENGXHU3RDIwXHU1MDNDXHJcbiAgICAgICAgICB9KSxcclxuICAgICAgICBdXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwbHVnaW5zOiBjcmVhdGVWaXRlUGx1Z2lucyhlbnYsIGNvbW1hbmQgPT09ICdidWlsZCcpLFxyXG4gICAgYnVpbGQ6IGJ1aWxkQ29uZmlnLFxyXG4gICAgb3B0aW1pemVEZXBzOiB7XHJcbiAgICAgIGVzYnVpbGRPcHRpb25zOiB7XHJcbiAgICAgICAgdGFyZ2V0OiAnZXNuZXh0JyxcclxuICAgICAgfSxcclxuICAgIH0sXHJcbiAgfSk7XHJcbn07XHJcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFxcXFx2aXRlXFxcXHBsdWdpbnNcXFxcaW5kZXguanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9pbmRleC5qc1wiO2ltcG9ydCB2dWUgZnJvbSAnQHZpdGVqcy9wbHVnaW4tdnVlJztcclxuXHJcbmltcG9ydCBjcmVhdGVBdXRvSW1wb3J0IGZyb20gJy4vYXV0by1pbXBvcnQnO1xyXG5pbXBvcnQgY3JlYXRlQ29tcHJlc3Npb24gZnJvbSAnLi9jb21wcmVzc2lvbic7XHJcbmltcG9ydCBjcmVhdGVTZXR1cEV4dGVuZCBmcm9tICcuL3NldHVwLWV4dGVuZCc7XHJcbmltcG9ydCBjcmVhdGVTdmdQbHVnaW4gZnJvbSAnLi9zdmctcGx1Z2luJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGNyZWF0ZVZpdGVQbHVnaW5zKHZpdGVFbnYsIGlzQnVpbGQgPSBmYWxzZSkge1xyXG4gIGNvbnN0IHZpdGVQbHVnaW5zID0gW3Z1ZSgpXTtcclxuICB2aXRlUGx1Z2lucy5wdXNoKGNyZWF0ZUF1dG9JbXBvcnQoKSk7XHJcbiAgdml0ZVBsdWdpbnMucHVzaChjcmVhdGVTZXR1cEV4dGVuZCgpKTtcclxuICB2aXRlUGx1Z2lucy5wdXNoKGNyZWF0ZVN2Z1BsdWdpbigpKTtcclxuICBpc0J1aWxkICYmIHZpdGVQbHVnaW5zLnB1c2goLi4uY3JlYXRlQ29tcHJlc3Npb24odml0ZUVudikpO1xyXG4gIHJldHVybiB2aXRlUGx1Z2lucztcclxufVxyXG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIkU6XFxcXFx1OTY0OFx1NzQ3NlxcXFxcdTRFMkRcdTU2RkVcdTY2N0FcdTk4REVcXFxcY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkXFxcXHZpdGVcXFxccGx1Z2luc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXFxcXGF1dG8taW1wb3J0LmpzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9FOi8lRTklOTklODglRTclOTElQjYvJUU0JUI4JUFEJUU1JTlCJUJFJUU2JTk5JUJBJUU5JUEzJTlFL2NvbW1hbmQtY2VudGVyLWRhc2hib2FyZC92aXRlL3BsdWdpbnMvYXV0by1pbXBvcnQuanNcIjtpbXBvcnQgYXV0b0ltcG9ydCBmcm9tICd1bnBsdWdpbi1hdXRvLWltcG9ydC92aXRlJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGNyZWF0ZUF1dG9JbXBvcnQoKSB7XHJcbiAgcmV0dXJuIGF1dG9JbXBvcnQoe1xyXG4gICAgaW1wb3J0czogWyd2dWUnLCAndnVlLXJvdXRlcicsICd2dWV4J10sXHJcbiAgICBkdHM6IGZhbHNlLFxyXG4gIH0pO1xyXG59XHJcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFxcXFx2aXRlXFxcXHBsdWdpbnNcXFxcY29tcHJlc3Npb24uanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9jb21wcmVzc2lvbi5qc1wiO2ltcG9ydCBjb21wcmVzc2lvbiBmcm9tICd2aXRlLXBsdWdpbi1jb21wcmVzc2lvbic7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBjcmVhdGVDb21wcmVzc2lvbihlbnYpIHtcclxuICBjb25zdCB7IFZJVEVfQlVJTERfQ09NUFJFU1MgfSA9IGVudjtcclxuICBjb25zdCBwbHVnaW4gPSBbXTtcclxuICBpZiAoVklURV9CVUlMRF9DT01QUkVTUykge1xyXG4gICAgY29uc3QgY29tcHJlc3NMaXN0ID0gVklURV9CVUlMRF9DT01QUkVTUy5zcGxpdCgnLCcpO1xyXG4gICAgaWYgKGNvbXByZXNzTGlzdC5pbmNsdWRlcygnZ3ppcCcpKSB7XHJcbiAgICAgIHBsdWdpbi5wdXNoKFxyXG4gICAgICAgIGNvbXByZXNzaW9uKHtcclxuICAgICAgICAgIGV4dDogJy5neicsXHJcbiAgICAgICAgICBkZWxldGVPcmlnaW5GaWxlOiBmYWxzZSxcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgaWYgKGNvbXByZXNzTGlzdC5pbmNsdWRlcygnYnJvdGxpJykpIHtcclxuICAgICAgcGx1Z2luLnB1c2goXHJcbiAgICAgICAgY29tcHJlc3Npb24oe1xyXG4gICAgICAgICAgZXh0OiAnLmJyJyxcclxuICAgICAgICAgIGFsZ29yaXRobTogJ2Jyb3RsaUNvbXByZXNzJyxcclxuICAgICAgICAgIGRlbGV0ZU9yaWdpbkZpbGU6IGZhbHNlLFxyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBwbHVnaW47XHJcbn1cclxuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJFOlxcXFxcdTk2NDhcdTc0NzZcXFxcXHU0RTJEXHU1NkZFXHU2NjdBXHU5OERFXFxcXGNvbW1hbmQtY2VudGVyLWRhc2hib2FyZFxcXFx2aXRlXFxcXHBsdWdpbnNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkU6XFxcXFx1OTY0OFx1NzQ3NlxcXFxcdTRFMkRcdTU2RkVcdTY2N0FcdTk4REVcXFxcY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkXFxcXHZpdGVcXFxccGx1Z2luc1xcXFxzZXR1cC1leHRlbmQuanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9zZXR1cC1leHRlbmQuanNcIjtpbXBvcnQgc2V0dXBFeHRlbmQgZnJvbSAndml0ZS1wbHVnaW4tdnVlLXNldHVwLWV4dGVuZCc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBjcmVhdGVTZXR1cEV4dGVuZCgpIHtcclxuICByZXR1cm4gc2V0dXBFeHRlbmQoKTtcclxufVxyXG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIkU6XFxcXFx1OTY0OFx1NzQ3NlxcXFxcdTRFMkRcdTU2RkVcdTY2N0FcdTk4REVcXFxcY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkXFxcXHZpdGVcXFxccGx1Z2luc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRTpcXFxcXHU5NjQ4XHU3NDc2XFxcXFx1NEUyRFx1NTZGRVx1NjY3QVx1OThERVxcXFxjb21tYW5kLWNlbnRlci1kYXNoYm9hcmRcXFxcdml0ZVxcXFxwbHVnaW5zXFxcXHN2Zy1wbHVnaW4uanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0U6LyVFOSU5OSU4OCVFNyU5MSVCNi8lRTQlQjglQUQlRTUlOUIlQkUlRTYlOTklQkElRTklQTMlOUUvY29tbWFuZC1jZW50ZXItZGFzaGJvYXJkL3ZpdGUvcGx1Z2lucy9zdmctcGx1Z2luLmpzXCI7aW1wb3J0IHsgY3JlYXRlU3ZnSWNvbnNQbHVnaW4gfSBmcm9tICd2aXRlLXBsdWdpbi1zdmctaWNvbnMnXHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gY3JlYXRlU3ZnUGx1Z2luKCkge1xyXG4gIHJldHVybiAgY3JlYXRlU3ZnSWNvbnNQbHVnaW4oe1xyXG4gICAgaWNvbkRpcnM6IFtwYXRoLnJlc29sdmUocHJvY2Vzcy5jd2QoKSwgXCJzcmMvYXNzZXRzL3N2Z1wiKV0sIC8vc3ZnXHU1NkZFXHU3MjQ3XHU1QjU4XHU2NTNFXHU3Njg0XHU3NkVFXHU1RjU1XHJcbiAgICBzeW1ib2xJZDogXCJpY29uLVtuYW1lXVwiLCAvLyBzeW1ib2xcdTc2ODRpZFxyXG4gICAgaW5qZWN0OiBcImJvZHktbGFzdFwiLCAvLyBcdTYzRDJcdTUxNjVcdTc2ODRcdTRGNERcdTdGNkVcclxuICAgIGN1c3RvbURvbUlkOiBcIl9fc3ZnX19pY29uc19fZG9tX19cIiAvLyBzdmdcdTc2ODRpZFxyXG4gIH0pO1xyXG59XHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBcVY7QUFBQSxFQUNuVjtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxlQUFlOzs7QUNKMFYsT0FBTyxTQUFTOzs7QUNBSixPQUFPLGdCQUFnQjtBQUV0WSxTQUFSLG1CQUFvQztBQUN6QyxTQUFPLFdBQVc7QUFBQSxJQUNoQixTQUFTLENBQUMsT0FBTyxjQUFjLE1BQU07QUFBQSxJQUNyQyxLQUFLO0FBQUEsRUFDUCxDQUFDO0FBQ0g7OztBQ1A4WCxPQUFPLGlCQUFpQjtBQUV2WSxTQUFSLGtCQUFtQyxLQUFLO0FBQzdDLFFBQU0sRUFBRSxvQkFBb0IsSUFBSTtBQUNoQyxRQUFNLFNBQVMsQ0FBQztBQUNoQixNQUFJLHFCQUFxQjtBQUN2QixVQUFNLGVBQWUsb0JBQW9CLE1BQU0sR0FBRztBQUNsRCxRQUFJLGFBQWEsU0FBUyxNQUFNLEdBQUc7QUFDakMsYUFBTztBQUFBLFFBQ0wsWUFBWTtBQUFBLFVBQ1YsS0FBSztBQUFBLFVBQ0wsa0JBQWtCO0FBQUEsUUFDcEIsQ0FBQztBQUFBLE1BQ0g7QUFBQSxJQUNGO0FBQ0EsUUFBSSxhQUFhLFNBQVMsUUFBUSxHQUFHO0FBQ25DLGFBQU87QUFBQSxRQUNMLFlBQVk7QUFBQSxVQUNWLEtBQUs7QUFBQSxVQUNMLFdBQVc7QUFBQSxVQUNYLGtCQUFrQjtBQUFBLFFBQ3BCLENBQUM7QUFBQSxNQUNIO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFDQSxTQUFPO0FBQ1Q7OztBQzFCZ1ksT0FBTyxpQkFBaUI7QUFFelksU0FBUixvQkFBcUM7QUFDMUMsU0FBTyxZQUFZO0FBQ3JCOzs7QUNKNFgsU0FBUyw0QkFBNEI7QUFDamEsT0FBTyxVQUFVO0FBRUYsU0FBUixrQkFBbUM7QUFDeEMsU0FBUSxxQkFBcUI7QUFBQSxJQUMzQixVQUFVLENBQUMsS0FBSyxRQUFRLFFBQVEsSUFBSSxHQUFHLGdCQUFnQixDQUFDO0FBQUE7QUFBQSxJQUN4RCxVQUFVO0FBQUE7QUFBQSxJQUNWLFFBQVE7QUFBQTtBQUFBLElBQ1IsYUFBYTtBQUFBO0FBQUEsRUFDZixDQUFDO0FBQ0g7OztBSkhlLFNBQVIsa0JBQW1DLFNBQVMsVUFBVSxPQUFPO0FBQ2xFLFFBQU0sY0FBYyxDQUFDLElBQUksQ0FBQztBQUMxQixjQUFZLEtBQUssaUJBQWlCLENBQUM7QUFDbkMsY0FBWSxLQUFLLGtCQUFrQixDQUFDO0FBQ3BDLGNBQVksS0FBSyxnQkFBZ0IsQ0FBQztBQUNsQyxhQUFXLFlBQVksS0FBSyxHQUFHLGtCQUFrQixPQUFPLENBQUM7QUFDekQsU0FBTztBQUNUOzs7QURSQSxPQUFPLG9CQUFvQjtBQU4zQixJQUFNLG1DQUFtQztBQVN6QyxJQUFPLHNCQUFRLENBQUM7QUFBQSxFQUNkO0FBQUEsRUFDQTtBQUNGLE1BQU07QUFDSixRQUFNLE1BQU0sUUFBUSxNQUFNLFFBQVEsSUFBSSxDQUFDO0FBQ3ZDLFFBQU07QUFBQSxJQUNKO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxFQUNGLElBQUk7QUFFSixRQUFNLFNBQVMsaUJBQWlCO0FBR2hDLFFBQU0sY0FBYztBQUFBLElBQ2xCLFFBQVE7QUFBQSxJQUNSLFFBQVEsU0FBUyxXQUFXO0FBQUE7QUFBQSxFQUM5QjtBQUdBLE1BQUksUUFBUTtBQUNWLGdCQUFZLGdCQUFnQjtBQUFBLE1BQzFCLFVBQVU7QUFBQSxRQUNSLGNBQWM7QUFBQTtBQUFBLFFBQ2QsZUFBZTtBQUFBO0FBQUEsTUFDakI7QUFBQSxNQUNBLFFBQVE7QUFBQSxRQUNOLFVBQVU7QUFBQTtBQUFBLE1BQ1o7QUFBQSxJQUNGO0FBQ0EsZ0JBQVksZ0JBQWdCO0FBQUEsTUFDMUIsUUFBUTtBQUFBLFFBQ04sY0FBYztBQUFBLFVBQ1osZ0JBQWdCLENBQUMsY0FBYztBQUFBLFVBQy9CLGtCQUFrQixDQUFDLGdCQUFnQjtBQUFBLFFBQ3JDO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQ0EsU0FBTyxhQUFhO0FBQUEsSUFDbEIsTUFBTTtBQUFBLElBQ04sUUFBUTtBQUFBLE1BQ04sMkJBQTJCO0FBQUEsTUFDM0IseUJBQXlCO0FBQUEsTUFDekIsMkJBQTJCO0FBQUEsSUFDN0I7QUFBQSxJQUNBLFFBQVE7QUFBQTtBQUFBLE1BRU4sT0FBTztBQUFBLFFBQ0wsUUFBUTtBQUFBLFVBQ04sUUFBUTtBQUFBLFVBQ1IsY0FBYztBQUFBLFVBQ2QsU0FBUyxDQUFBQSxVQUFRQSxNQUFLLFFBQVEsVUFBVSxFQUFFO0FBQUEsUUFDNUM7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUFBLElBQ0EsU0FBUztBQUFBLE1BQ1AsT0FBTztBQUFBLFFBQ0wsS0FBSyxRQUFRLGtDQUFXLElBQUk7QUFBQSxRQUM1QixLQUFLLFFBQVEsa0NBQVcsT0FBTztBQUFBLFFBQy9CLFlBQVksUUFBUSxrQ0FBVyxrQkFBa0I7QUFBQSxRQUNqRCxRQUFRLFFBQVEsa0NBQVcsY0FBYztBQUFBLFFBQ3pDLE9BQU8sUUFBUSxrQ0FBVyxhQUFhO0FBQUEsTUFDekM7QUFBQSxJQUNGO0FBQUEsSUFDQSxLQUFLO0FBQUEsTUFDSCxxQkFBcUI7QUFBQSxRQUNuQixNQUFNO0FBQUEsVUFDSixLQUFLO0FBQUEsVUFDTCxnQkFBZ0I7QUFBQSxRQUNsQjtBQUFBLE1BQ0Y7QUFBQSxNQUNBLFNBQVM7QUFBQSxRQUNQLFNBQVM7QUFBQSxVQUNQLGVBQWU7QUFBQSxZQUNiLFdBQVc7QUFBQTtBQUFBLFlBQ1gsVUFBVSxDQUFDLEdBQUc7QUFBQTtBQUFBLFlBQ2QsZUFBZTtBQUFBO0FBQUEsWUFDZixtQkFBbUIsQ0FBQztBQUFBO0FBQUEsWUFDcEIsU0FBUztBQUFBO0FBQUEsWUFDVCxZQUFZO0FBQUE7QUFBQSxZQUNaLGVBQWU7QUFBQTtBQUFBLFVBQ2pCLENBQUM7QUFBQSxRQUNIO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxJQUNBLFNBQVMsa0JBQWtCLEtBQUssWUFBWSxPQUFPO0FBQUEsSUFDbkQsT0FBTztBQUFBLElBQ1AsY0FBYztBQUFBLE1BQ1osZ0JBQWdCO0FBQUEsUUFDZCxRQUFRO0FBQUEsTUFDVjtBQUFBLElBQ0Y7QUFBQSxFQUNGLENBQUM7QUFDSDsiLAogICJuYW1lcyI6IFsicGF0aCJdCn0K