吉安感知网项目-前端
shuishen
2026-02-03 89380e6260a75d1d3b94de687ebcc2f50d50659d
uniapps/work-wx/src/subPackages/flightApplication/add.vue
@@ -1,9 +1,8 @@
<template>
<view class="flightApplication-add">
    <view class="title">
        基本信息
    </view>
    <u-form labelPosition="top" :model="formParams" :rules="rules" ref="formRef">
         <view class="title form-title">基本信息</view>
        <u-form-item
                label="飞行计划"
                labelWidth="200rpx"
@@ -12,7 +11,7 @@
                ref="item1"
                required
        >
            <u-input v-model="formParams.flightPlanName" border="none" placeholder="请输入飞行计划名称"></u-input>
            <u-input v-model="formParams.flightPlanName" border="none" placeholder="请输入"></u-input>
        </u-form-item>
        <u-form-item
                label="任务类型"
@@ -27,7 +26,7 @@
                v-model="formParams.flightTaskTypeText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择任务类型"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -49,7 +48,7 @@
                v-model="formParams.flightRuleText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择飞行规则"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -71,7 +70,7 @@
                v-model="formParams.flightModeText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择飞行方式"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -102,7 +101,7 @@
        >
            <u-input v-model="formParams.flightEndTime" border="none" placeholder="请选择日期" suffixIcon="calendar"></u-input>
        </u-form-item>
        <u-form-item
                label="计划类型"
                labelWidth="200rpx"
@@ -116,7 +115,7 @@
                v-model="formParams.planTypeText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择计划类型"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -172,7 +171,13 @@
                :borderBottom="true"
                ref="item1"
        >
            <u-input v-model="formParams.tempAirspaceApprovalText" border="none" readonly placeholder="(建议文件大小100M内,仅支持pdf、jpg、jpeg、png等格式)"></u-input>
            <template #label>
                <view class="custom-label">
                    <text>临时空域批件</text>
                    <text class="label-tip">(建议文件大小100M内,仅支持pdf、jpg、jpeg、png等格式)</text>
                </view>
            </template>
            <u-input v-model="formParams.tempAirspaceApprovalText" border="none" readonly placeholder="请选择"></u-input>
            <template #right>
                <u-upload
                    @afterRead="afterRead"
@@ -204,17 +209,17 @@
        <u-form-item
                label="飞行器"
                labelWidth="230rpx"
                prop="aircraftId"
                prop="spacecraftText"
                :borderBottom="true"
                required
                ref="item2"
                @click="isShowAircraftInfo = true"
        >
            <u-input
                v-model="formParams.aircraftText"
                v-model="formParams.spacecraftText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择飞行器"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -226,7 +231,7 @@
        <u-form-item
                label="飞手"
                labelWidth="230rpx"
                prop="pilotId"
                prop="pilotText"
                :borderBottom="true"
                ref="item2"
                required
@@ -236,7 +241,7 @@
                v-model="formParams.pilotText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择飞手"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -259,7 +264,7 @@
                v-model="formParams.airspaceText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择空域"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -271,7 +276,7 @@
        <u-form-item
                label="航线"
                labelWidth="230rpx"
                prop="routeId"
                prop="selectedRouteId"
                :borderBottom="true"
                ref="item2"
                required
@@ -281,7 +286,7 @@
                v-model="formParams.routeText"
                disabled
                disabledColor="#ffffff"
                placeholder="请选择航线"
                placeholder="请选择"
                border="none"
            ></u-input>
            <template #right>
@@ -324,38 +329,106 @@
        @confirm="onPickerPlanType"
        @cancel="isShowPlanType = false"
    />
    <up-datetime-picker
    <u-datetime-picker
            :show="isShowStartTime"
            v-model="startTime"
            mode="datetime"
            :min-date="minDate"
            :formatter="formatter"
            @confirm="onConfirmStartTime"
             @cancel="isShowStartTime = false"
        ></up-datetime-picker>
        <up-datetime-picker
        ></u-datetime-picker>
        <u-datetime-picker
            :show="isShowEndTime"
            v-model="endTime"
            mode="datetime"
            :min-date="minDate"
            :formatter="formatter"
            @confirm="onConfirmEndTime"
            @cancel="isShowEndTime = false"
        ></up-datetime-picker>
        ></u-datetime-picker>
    <!-- <u-calendar :show="isShowTimeRange" mode="date" @confirm="onConfirmTimeRange" @close="isShowTimeRange = false" :close-on-click-overlay="true"></u-calendar> -->
    <!-- <u-calendar :show="isShowTimeRange" mode="range" @confirm="onConfirmTimeRange" @close="isShowTimeRange = false" :close-on-click-overlay="true" :allow-same-day="true" :show-time="true" time-format="HH:mm:ss"></u-calendar> -->
    <!-- 飞行器 -->
     <u-picker
     <!-- <u-picker
        :show="isShowAircraftInfo"
        :columns="[aircraftInfoList]"
        keyName="label"
        @confirm="onPickerAircraftInfo"
        @cancel="isShowAircraftInfo = false"
    />
    /> -->
    <u-popup
    :show="isShowAircraftInfo"
    mode="bottom"
    round="20"
    @close="isShowAircraftInfo = false"
  >
  <scroll-view scroll-y>
    <view class="select-header">
        <view>请选择飞行器</view>
        <view class="select-header-btn">
            <view class="cancel-btn" @click="isShowAircraftInfo = false">取消</view>
            <view @click="onPickerAircraftInfo">确定</view>
        </view>
    </view>
    <view class="select-content">
          <up-checkbox-group
            v-model="formParams.spacecraftId"
            placement="column"
            @change="checkboxChange"
        >
            <up-checkbox
                :customStyle="{marginBottom: '8px'}"
                v-for="(item, index) in aircraftInfoList"
                :key="item.id"
                :label="item.label"
                :name="item.value"
            >
            </up-checkbox>
        </up-checkbox-group>
    </view>
    </scroll-view>
  </u-popup>
    <!-- 飞手 -->
    <u-picker
    <!-- <u-picker
        :show="isShowPilotInfo"
        :columns="[pilotInfoList]"
        keyName="label"
        @confirm="onPickerPilotInfo"
        @cancel="isShowPilotInfo = false"
    />
    /> -->
    <u-popup
    :show="isShowPilotInfo"
    mode="bottom"
    round="20"
    @close="isShowPilotInfo = false"
  >
  <scroll-view scroll-y>
    <view class="select-header">
        <view>请选择飞手</view>
        <view class="select-header-btn">
            <view class="cancel-btn" @click="isShowPilotInfo = false">取消</view>
            <view @click="onPickerPilotInfo">确定</view>
        </view>
    </view>
    <view class="select-content">
          <up-checkbox-group
            v-model="formParams.pilotId"
            placement="column"
            @change="checkboxPilotChange"
        >
            <up-checkbox
                :customStyle="{marginBottom: '8px'}"
                v-for="(item, index) in pilotInfoList"
                :key="item.id"
                :label="item.label"
                :name="item.value"
            >
            </up-checkbox>
        </up-checkbox-group>
    </view>
    </scroll-view>
  </u-popup>
    <!-- 空域 -->
    <u-picker
        :show="isShowAirspaceInfo"
@@ -373,7 +446,7 @@
        @cancel="isShowFlightRouteInfo = false"
    />
    </u-form>
    <u-button @click="submitForm" color="#1D6FE9">飞行申请</u-button>
    <u-button :disabled="isSubmitDisabled" @click="submitForm" color="#1D6FE9">飞行申请</u-button>
    <!-- 飞任务类型 -->
    <view class="attention">
        注:新增空域/航线/飞手等前往吉安市低空经济服务一体化
@@ -381,9 +454,20 @@
</view>
</template>
<script setup>
import { flightPlanSaveApi, flightRoutePageInfoApi, aircraftInfoPageInfoOfMyApi, pilotInfoPageInfoOfMyApi, flightAirspacePageInfoApi, uploadFileApi } from '@/api/index'
import {
    flightPlanSaveApi,
    flightRoutePageInfoApi,
    aircraftInfoPageInfoOfMyApi,
    pilotInfoPageInfoOfMyApi,
    droneFlightTaskApi,
    uploadFileApi
 } from '@/api/index'
import { ref, computed, onMounted } from 'vue'
import dayjs from 'dayjs'
// 获取store中的数据 字典
import { useAppStore, useUserStore } from "@/store";
const appStore = useAppStore()
const formRef = ref(null);
const formParams = ref({
@@ -400,20 +484,20 @@
    planType: '', // 计划类型
    planTypeText: '', // 计划类型文本
    contactPerson: '', // 联系人
    contactPhon: '', // 联系人电话
    contactPhone: '', // 联系人电话
    undertaker: '', // 承办人
    undertakerPhone: '', // 承办人电话
    timeRange: '', // 时间范围
    flightStartTime: '', // 飞行活动开始时间
    flightEndTime: '', // 飞行活动结束时间
    weatherCondition: '', // 气象条件
    spacecraftId: '', // 航天器id
    spacecraftId: [], // 航天器id
    spacecraftText: '', // 航天器文本
    pilotId: '', // 飞手id
    pilotId: [], // 飞手id
    pilotText: '', // 飞手文本
    airspaceId: '', // 空域id
    airspaceText: '', // 空域文本
    routeId: '', // 航线id
    selectedRouteId: '', // 航线id
    routeText: '', // 航线文本
})
const rules = ref({
@@ -432,13 +516,37 @@
    contactPerson: [
        { required: true, message: '请输入联系人', trigger: 'blur' }
    ],
    contactPhon: [
    contactPhone: [
        // 验证手机号码
        {
            validator: (rule, value, callback) => {
                const reg = /^1[3456789]\d{9}$/
                if (!reg.test(value)) {
                    callback(new Error('请输入正确的手机号码'))
                } else {
                    callback()
                }
            },
            trigger: 'blur'
        },
        { required: true, message: '请输入联系人电话', trigger: 'blur' }
    ],
    undertaker: [
        { required: true, message: '请输入承办人', trigger: 'blur' }
    ],
    undertakerPhone: [
        // 验证手机号码
        {
            validator: (rule, value, callback) => {
                const reg = /^1[3456789]\d{9}$/
                if (!reg.test(value)) {
                    callback(new Error('请输入正确的手机号码'))
                } else {
                    callback()
                }
            },
            trigger: 'blur'
        },
        { required: true, message: '请输入承办人联系电话', trigger: 'blur' }
    ],
    startTime: [
@@ -447,47 +555,22 @@
    endTime: [
        { required: true, message: '请选择飞行活动结束时间', trigger: 'change' }
    ],
    spacecraftId: [
    spacecraftText: [
        { required: true, message: '请选择飞行器', trigger: 'change' }
    ],
    pilotId: [
    pilotText: [
        { required: true, message: '请选择飞手', trigger: 'change' }
    ],
    airspaceId: [
        { required: true, message: '请选择空域', trigger: 'change' }
    ],
    routeId: [
    selectedRouteId: [
        { required: true, message: '请选择航线', trigger: 'change' }
    ],
})
// 任务类型
const isShowFlightTaskType = ref(false)
const actionsFlightTaskType = [
    {
        label: '警务',
        value: '警务',
    },
    {
        label: '文旅',
        value: '文旅',
    },
    {
        label: '航拍',
        value: '航拍',
    },
    {
        label: '物流',
        value: '物流',
    },
    {
        label: '巡检',
        value: '巡检',
    },
    {
        label: '植保',
        value: '植保',
    },
]
const actionsFlightTaskType = ref(appStore.getTaskType)
const onPickerFlightTaskType = (e) => {
  const selected = e.value[0]
  formParams.value.flightTaskType = selected.value
@@ -497,16 +580,7 @@
// 飞行规则
const isShowFlightRule = ref(false)
const actionsFlightRule = [
    {
        label: '目视餡相飞行规则(VFR)',
        value: '目视餡相飞行规则(VFR)',
    },
    {
        label: '仪表飞行规则(IFR)',
        value: '仪表飞行规则(IFR)',
    },
]
const actionsFlightRule = ref(appStore.getFlightRules)
const onPickerFlightRule = (e) => {
  const selected = e.value[0]
  formParams.value.flightRule = selected.value
@@ -515,16 +589,7 @@
}
// 飞行方式
const isShowFlightMode = ref(false)
const actionsFlightMode = [
    {
        label: '视距内飞行 (VLOS)',
        value: '视距内飞行 (VLOS)',
    },
    {
        label: '超视距飞行(BVLOS)',
        value: '超视距飞行(BVLOS)',
    },
]
const actionsFlightMode = ref(appStore.getFlightMode)
const onPickerFlightMode = (e) => {
  const selected = e.value[0]
  formParams.value.flightMode = selected.value
@@ -533,16 +598,7 @@
}
// 计划类型
const isShowPlanType = ref(false)
const actionsPlanType = [
    {
        label: '一般',
        value: '0',
    },
    {
        label: '紧急',
        value: '1',
    }
]
const actionsPlanType = ref(appStore.getFlightPlan)
const onPickerPlanType = (e) => {
  const selected = e.value[0]
  formParams.value.planType = selected.value
@@ -553,6 +609,7 @@
const isShowStartTime = ref(false)
// 是否显示结束时间选择器
const isShowEndTime = ref(false)
const minDate = ref(Date.now()); // 设置最小日期为当前时间戳
const startTime = ref(Date.now()); // 设置默认值为当前时间戳
const endTime = ref(Date.now()); // 设置默认值为当前时间戳
@@ -581,10 +638,17 @@
        }))
    })
}
const onPickerAircraftInfo = (e) => {
  const selected = e.value[0]
  formParams.value.aircraftId = selected.value
  formParams.value.aircraftText = selected.label
// const onPickerAircraftInfo = (e) => {
//   const selected = e.value[0]
//   formParams.value.spacecraftId = selected.value
//   formParams.value.aircraftText = selected.label
//   isShowAircraftInfo.value = false
// }
function checkboxChange(val) {
    formParams.value.spacecraftId = val.join(',')
    formParams.value.spacecraftText = aircraftInfoList.value.filter(item => val.includes(item.value)).map(item => item.label).join(',')
}
const onPickerAircraftInfo = () => {
  isShowAircraftInfo.value = false
}
// 获取飞手信息
@@ -601,22 +665,26 @@
        }))
    })
}
function checkboxPilotChange(val) {
    formParams.value.pilotId = val.join(',')
    formParams.value.pilotText = pilotInfoList.value.filter(item => val.includes(item.value)).map(item => item.label).join(',')
}
const onPickerPilotInfo = (e) => {
  const selected = e.value[0]
  formParams.value.pilotId = selected.value
  formParams.value.pilotText = selected.label
//   const selected = e.value[0]
//   formParams.value.pilotId = selected.value
//   formParams.value.pilotText = selected.label
  isShowPilotInfo.value = false
}
// 获取空域信息
const isShowAirspaceInfo = ref(false)
const airspaceInfoList = ref([])
function getAirspaceInfo() {
    flightAirspacePageInfoApi({
    droneFlightTaskApi({
        current: 1,
        size: 1000,
    }).then(res => {
        airspaceInfoList.value = res.data.data.records.map(item => ({
            label: item.airspaceName || '暂无',
            label: item.taskName || '暂无',
            value: item.id,
        }))
    })
@@ -635,7 +703,6 @@
        current: 1,
        size: 1000,
    }).then(res => {
        console.log(res.data.data, '0000')
        flightRouteInfoList.value = res.data.data.records.map(item => ({
            label: item.name,
            value: item.id,
@@ -644,7 +711,7 @@
}
const onPickerFlightRouteInfo = (e) => {
  const selected = e.value[0]
  formParams.value.routeId = selected.value
  formParams.value.selectedRouteId = selected.value
  formParams.value.routeText = selected.label
  isShowFlightRouteInfo.value = false
}
@@ -654,36 +721,36 @@
    // 获取上传的文件对象
    const file = event.file;
    console.log('上传的文件:', file);
    // 显示加载提示
    uni.showLoading({
        title: '上传中...'
    });
    // 准备上传参数
    const uploadParams = {
        name: 'file', // 服务器端接收文件的字段名
        file: file, // 传入文件对象
        filePath: file.path || file.url, // 文件路径
    };
    // 调用上传文件接口
    uploadFileApi(uploadParams).then(res => {
        uni.hideLoading();
        console.log('上传成功结果:', res);
        // 根据接口返回的数据结构处理结果
        if (res.data && res.data.code === 200) {
            // 假设接口返回的数据结构是 { url, fileName } 等
            const uploadResult = res.data.data;
            // 更新表单数据,将上传结果展示在input内
            formParams.value.tempAirspaceApprovalText = uploadResult.fileName || uploadResult.url || '文件上传成功';
            // 可以将完整的上传信息保存到表单中,以便提交时使用
            formParams.value.tempAirspaceApproval = uploadResult.fileUrl || '文件上传成功';
            uni.showToast({
                title: '上传成功',
                icon: 'success'
@@ -703,12 +770,14 @@
        });
    });
};
const isSubmitDisabled = ref(false)
// 提交表单
const submitForm = async () => {
  await formRef.value.validate()
  isSubmitDisabled.value = true
  flightPlanSaveApi(formParams.value).then(res => {
    if (res.data.code === 200) {
        isSubmitDisabled.value = true
      uni.showToast({
        title: '提交成功',
        icon: 'success',
@@ -725,9 +794,26 @@
        duration: 2000
      })
    }
  }).finally(() => {
    isSubmitDisabled.value = false
  })
}
const formatter = (type, value) => {
    if (type === 'year') return `${value}年`;
    if (type === 'month') return `${value}月`;
    if (type === 'day') return `${value}日`;
    if (type === 'hour') return `${value}时`;
    if (type === 'minute') return `${value}分`;
    return value;
};
onMounted(() => {
    // getProTypeApi()
    // getTaskType()
    // getFlightMode()
    // getFlightRules()
    // getFlightPlan()
    getAircraftInfo()
    getPilotInfo()
    getAirspaceInfo()
@@ -755,20 +841,32 @@
        width: 80%;
        padding: 28rpx;
        border-radius: 8rpx 8rpx 8rpx 8rpx;
        margin-bottom: 20rpx;
        // margin-bottom: 20rpx;
    }
    :deep(.u-toolbar__wrapper__confirm) {
        color: #1D6FE9;
    }
    .custom-label {
        .label-tip {
            font-family: Source Han Sans CN, Source Han Sans CN;
            font-weight: 400;
            font-size: 18rpx;
            color: #3A3A3A;
        }
    }
    .attention {
        font-family: Source Han Sans CN, Source Han Sans CN;
        font-weight: 400;
        font-size: 12px;
        color: #1D6FE9;
        //  margin-top: 24rpx;
         margin: 40rpx 0;
        text-align: center;
    }
    .select-wrapper {
        position: relative;
        width: 100%;
        .select-icon {
            position: absolute;
            right: 20rpx;
@@ -801,7 +899,7 @@
        border-radius: 8rpx 8rpx 8rpx 8rpx;
    }
    :deep(.u-form-item) {
        margin-bottom: 40rpx;
        margin-bottom: 20rpx;
        padding: 16rpx 24rpx 18rpx 24rpx;
        border-radius: 6px 6px 6px 6px;
        background: white;
@@ -814,7 +912,7 @@
            border-radius: 8rpx;
            padding: 0 20rpx;
            background-color: #f5f5f5;
            &::placeholder {
                font-family: Source Han Sans CN, Source Han Sans CN;
                font-weight: 400;
@@ -822,12 +920,12 @@
                color: #D2D2D2;
            }
        }
        .clickable-input {
            width: 100%;
            cursor: pointer;
        }
        :deep(.u-form-item__label) {
            margin-bottom: 20rpx;
            // font-weight: bold;
@@ -837,11 +935,39 @@
            font-size: 30rpx;
            color: #222324;
        }
        :deep(.u-form-item__required) {
            color: #FF2600;
            margin-right: 8rpx;
        }
    }
    .uni-scroll-view {
       display: flex;
       flex-direction: column;
    }
    .select-header {
        display: flex;
        justify-content: space-between;
        padding: 20rpx 20rpx;
        font-size: 32rpx;
        color: #222324;
        .select-header-btn {
            display: flex;
            font-size: 28rpx;
            color: #1D6FE9;
            .cancel-btn {
                color: #86909C;
                margin-right: 20rpx;
            }
        }
    }
    .select-content {
        height: 600rpx;
        text-align: center;
        padding: 20rpx 20rpx;
    }
}
</style>