吉安感知网项目-后端
zhongrj
2026-01-31 d9644b47ac04cd20c79ae6583f9a82b5f7535170
Merge remote-tracking branch 'origin/master'
25 files modified
5 files renamed
4 files copied
23 files added
5 files deleted
4113 ■■■■■ changed files
README.md 3 ●●●● patch | view | raw | blame | history
drone-common/src/main/java/org/sxkj/common/constant/LauncherConstant.java 4 ●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/dto/FwAreaDivideStatisticsDTO.java 9 ●●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/mapper/FwAreaDivideMapper.xml 21 ●●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/service/impl/FwAreaDivideServiceImpl.java 1 ●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/service/impl/FwDefenseSceneManageServiceImpl.java 4 ●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/vo/FwAreaDivideStatisticsVO.java 6 ●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/cockpit/controller/CockpitController.java 16 ●●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/cockpit/service/ICockpitService.java 7 ●●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/cockpit/service/impl/CockpitServiceImpl.java 13 ●●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/device/mapper/FwDeviceMapper.xml 212 ●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/record/mapper/FwDroneAlarmRecordMapper.xml 42 ●●●● patch | view | raw | blame | history
drone-service/drone-fw/src/main/java/org/sxkj/fw/record/mapper/FwDroneFlightRecordMapper.xml 20 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/controller/GdImplementListController.java 123 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/controller/GdMaterialController.java 121 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/dto/GdImplementListDTO.java 101 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/dto/GdMaterialDTO.java 69 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/dto/GdThingListMaterialRelDTO.java 13 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/entity/GdImplementListEntity.java 94 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/entity/GdMaterialEntity.java 64 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/entity/GdThingListMaterialRelEntity.java 59 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/excel/GdImplementListExcel.java 102 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/excel/GdMaterialExcel.java 80 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/excel/GdThingListMaterialRelExcel.java 75 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdImplementListMapper.java 24 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdImplementListMapper.xml 52 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdMaterialMapper.java 23 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdMaterialMapper.xml 32 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdThingListMaterialRelMapper.java 22 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdThingListMaterialRelMapper.xml 31 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/param/GdImplementListPageParam.java 39 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdImplementListService.java 24 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdMaterialService.java 23 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdThingListMaterialRelService.java 22 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/impl/GdImplementListServiceImpl.java 60 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/impl/GdMaterialServiceImpl.java 55 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/impl/GdThingListMaterialRelServiceImpl.java 54 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/vo/GdImplementListVO.java 102 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/vo/GdMaterialVO.java 69 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/vo/GdThingListMaterialRelVO.java 13 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/wrapper/GdImplementListWrapper.java 50 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/wrapper/GdMaterialWrapper.java 50 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/wrapper/GdThingListMaterialRelWrapper.java 50 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/controller/GdImplementationListController.java 151 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/entity/GdImplementationListEntity.java 84 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/mapper/GdImplementationListMapper.xml 36 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/service/impl/GdImplementationListServiceImpl.java 54 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/wrapper/GdImplementationListWrapper.java 50 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/orderdata/mapper/GdDataObjectionMapper.xml 8 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdWorkOrderFlowController.java 22 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdWorkOrderFlowEntity.java 11 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/enums/PatrolTaskStatusEnum.java 17 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/enums/WorkOrderStatusEnum.java 421 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdWorkOrderFlowService.java 9 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java 59 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdPatrolTaskServiceImpl.java 742 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdWorkOrderFlowServiceImpl.java 186 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdWorkOrderServiceImpl.java 42 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/vo/WorkOrderStageVO.java 63 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/vo/WorkOrderStatusDetailVO.java 72 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java 5 ●●●● patch | view | raw | blame | history
drone-service/drone-system/src/main/java/org/sxkj/system/service/impl/RegionServiceImpl.java 27 ●●●●● patch | view | raw | blame | history
README.md
@@ -17,4 +17,5 @@
三、服务启动说明
1. 启动集成模块
drone-auth、drone-system、drone-gateway
2. 分别启动业务相关模块(按需启动)
2. 分别启动业务相关模块(按需启动)
3. 吉安服务器使用test环境、74.78使用prod环境
drone-common/src/main/java/org/sxkj/common/constant/LauncherConstant.java
@@ -43,13 +43,13 @@
    /**
     * nacos prod 地址
     */
    String NACOS_PROD_ADDR = "172.21.81.239:8899";
    String NACOS_PROD_ADDR = "127.0.0.1:8899";
    String NACOS_LOCAL_ADDR = "192.168.1.227:8848";
    /**
     * nacos test 地址
     */
    String NACOS_TEST_ADDR = "172.19.118.191:8899";
    String NACOS_TEST_ADDR = "192.168.1.36:18848";
    /**
     * sentinel dev 地址
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/dto/FwAreaDivideStatisticsDTO.java
@@ -55,6 +55,12 @@
    private String areaType;
    /**
     * 区域类型key集合(逗号分隔)
     */
    @ApiModelProperty(value = "区域类型key集合(逗号分隔)")
    private String areaTypeKeys;
    /**
     * 场景类型
     */
    @ApiModelProperty(value = "场景类型")
@@ -108,4 +114,7 @@
    @ApiModelProperty(value = "部门集合",hidden = true)
    private List<Long> deptList;
    @ApiModelProperty(value = "区域类型key集合", hidden = true)
    private List<String> areaTypeKeyList;
}
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/mapper/FwAreaDivideMapper.xml
@@ -23,6 +23,7 @@
    <resultMap id="fwAreaDivideStatisticsResultMap" type="org.sxkj.fw.area.vo.FwAreaDivideStatisticsVO">
        <result column="id" property="id"/>
        <result column="area_name" property="areaName"/>
        <result column="area_type_keys" property="areaTypeKeys"/>
        <result column="scene_name" property="sceneName"/>
        <result column="scene_type" property="sceneType"/>
        <result column="device_count" property="deviceCount"/>
@@ -236,6 +237,7 @@
        select
            stats.id,
            stats.area_name,
            stats.area_type_keys,
            stats.scene_name,
            stats.scene_type,
            stats.device_count,
@@ -252,15 +254,18 @@
            select
            ad.id,
            ad.area_name,
            ad.area_type_keys,
            (
                select group_concat(distinct ds.scene_name)
                from ja_fw_defense_scene ds
                join ja_fw_defense_scene_manage dsm on dsm.defense_scene_id = ds.id and dsm.is_deleted = 0
                where ds.is_deleted = 0
                  and find_in_set(ad.id, ds.area_divide_ids)
            ) as scene_name,
            (
                select group_concat(distinct ds.scene_type)
                from ja_fw_defense_scene ds
                join ja_fw_defense_scene_manage dsm on dsm.defense_scene_id = ds.id and dsm.is_deleted = 0
                where ds.is_deleted = 0
                  and find_in_set(ad.id, ds.area_divide_ids)
            ) as scene_type,
@@ -302,6 +307,13 @@
            from ja_fw_area_divide ad
            <where>
                ad.is_deleted = 0
                and exists (
                    select 1
                    from ja_fw_defense_scene ds
                    join ja_fw_defense_scene_manage dsm on dsm.defense_scene_id = ds.id and dsm.is_deleted = 0
                    where ds.is_deleted = 0
                      and find_in_set(ad.id, ds.area_divide_ids)
                )
                <if test="param2.id != null and param2.id != ''">
                    and ad.id = #{param2.id}
                </if>
@@ -320,6 +332,13 @@
                <if test="param2.areaCode != null and param2.areaCode != ''">
                    and ad.area_code = #{param2.areaCode}
                </if>
                <if test="param2.areaTypeKeyList != null and param2.areaTypeKeyList.size > 0">
                    and (
                        <foreach collection="param2.areaTypeKeyList" item="key" separator=" or ">
                            find_in_set(#{key}, ad.area_type_keys)
                        </foreach>
                    )
                </if>
                <if test="param2.deptList != null and param2.deptList.size > 0">
                    and ad.create_dept in
                    <foreach collection="param2.deptList" item="deptId" open="(" separator="," close=")">
@@ -334,6 +353,7 @@
        select
        stats.id,
        stats.area_name,
        stats.area_type_keys,
        stats.scene_name,
        stats.scene_type,
        stats.device_count,
@@ -350,6 +370,7 @@
        select
        ad.id,
        ad.area_name,
        ad.area_type_keys,
        (
            select group_concat(distinct ds.scene_name)
            from ja_fw_defense_scene ds
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/service/impl/FwAreaDivideServiceImpl.java
@@ -204,6 +204,7 @@
                                                                            FwAreaDivideStatisticsDTO fwAreaDivideStatistics) {
        List<Long> deptList = SysCache.getDeptChildIds(Long.valueOf(AuthUtil.getDeptId()));
        fwAreaDivideStatistics.setDeptList(deptList);
        fwAreaDivideStatistics.setAreaTypeKeyList(parseAreaTypeKeyList(fwAreaDivideStatistics.getAreaTypeKeys()));
        return page.setRecords(baseMapper.selectFwAreaDivideStatisticsPage(page, fwAreaDivideStatistics));
    }
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/service/impl/FwDefenseSceneManageServiceImpl.java
@@ -93,6 +93,7 @@
     */
    @Override
    public boolean deleteFwDefenseSceneManage(List<Long> longList) {
        //删除场景管理
        boolean b = deleteLogic(longList);
        if (b) {
            // 1.遍历所有删除的场景管理ID
@@ -102,6 +103,9 @@
                List<Long> deviceIdList = baseMapper.selectDeviceId(sceneManageId);
                AllDeviceId.addAll(deviceIdList);
            }
            if (AllDeviceId == null || AllDeviceId.isEmpty()) {
                return true;
            }
            // 3.禁用设备
            return fwDeviceService.update(Wrappers.<FwDeviceEntity>lambdaUpdate()
                .set(FwDeviceEntity::getIsEnabled, 0)
drone-service/drone-fw/src/main/java/org/sxkj/fw/area/vo/FwAreaDivideStatisticsVO.java
@@ -47,10 +47,10 @@
    private String areaName;
    /**
     * 区域类型
     * 区域类型key集合(逗号分隔)
     */
    @ApiModelProperty(value = "区域类型")
    private String areaType;
    @ApiModelProperty(value = "区域类型key集合(逗号分隔)")
    private String areaTypeKeys;
    /**
     * 场景名称
drone-service/drone-fw/src/main/java/org/sxkj/fw/cockpit/controller/CockpitController.java
@@ -3,6 +3,8 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springblade.core.mp.support.Condition;
@@ -70,6 +72,20 @@
    }
    /**
     * 设备出库去向统计
     * @return 统计数据
     */
    @GetMapping("/statisticalDeviceOut")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "设备出库去向统计", notes = "设备出库去向统计")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "effectiveRangeKmIsNotNull", value = "有效范围是否为空:0-不处理 1-不为空 2-为空", paramType = "query", dataType = "string")
    })
    public R<List<DeviceStatisticsVO>> statisticalDeviceOut(String effectiveRangeKmIsNotNull) {
        return R.data(cockpitService.getDeviceOutStatistics(effectiveRangeKmIsNotNull));
    }
    /**
     * 告警记录统计接口
     */
    @GetMapping("/alarmStatistics")
drone-service/drone-fw/src/main/java/org/sxkj/fw/cockpit/service/ICockpitService.java
@@ -47,4 +47,11 @@
     * @return
     */
    AlarmStatisticsVO statisticsAlarmsAndDeviceRecords();
    /**
     *
     * @param effectiveRangeKmIsNotNull
     * @return
     */
    List<DeviceStatisticsVO> getDeviceOutStatistics(String effectiveRangeKmIsNotNull);
}
drone-service/drone-fw/src/main/java/org/sxkj/fw/cockpit/service/impl/CockpitServiceImpl.java
@@ -55,7 +55,8 @@
        String regionName = byCode.getName();
        fwDevice.setRegionName(regionName);
        fwDevice.setCurrentDeptId(AuthUtil.getDeptId());
        return fwDeviceService.selectCockpitDevicePage(page, fwDevice);
        IPage<CockpitFwDeviceVO> cockpitFwDeviceVOIPage = fwDeviceService.selectCockpitDevicePage(page, fwDevice);
        return cockpitFwDeviceVOIPage;
    }
    @Override
@@ -120,4 +121,14 @@
        alarmStatisticsVO.setRealTimeAlarmCount(alarmStatistics.getRealTimeAlarmCount());
        return alarmStatisticsVO;
    }
    /**
     *
     * @param effectiveRangeKmIsNotNull
     * @return
     */
    @Override
    public List<DeviceStatisticsVO> getDeviceOutStatistics(String effectiveRangeKmIsNotNull) {
        return fwDeviceService.getDeviceOutStatistics(effectiveRangeKmIsNotNull);
    }
}
drone-service/drone-fw/src/main/java/org/sxkj/fw/device/mapper/FwDeviceMapper.xml
@@ -245,29 +245,13 @@
                split_device_type
            FROM
                ja_fw_device d
            LEFT JOIN (
                SELECT
                    device_id,
                    out_target,
                    ROW_NUMBER() OVER (
                    PARTITION BY
                    device_id
                    ORDER BY
                    create_time DESC
                    ) AS rn
                FROM
                    ja_fw_device_track
                WHERE
                    out_target IS NOT NULL
                ) t ON d.id = t.device_id AND t.rn = 1
            WHERE
                d.is_deleted = 0
            AND status != 3
            AND track_status = 1
            AND effective_range_km is not null
            AND effective_range_km > 0
                AND d.is_enabled = 1
                AND status != 3
                AND track_status = 1
            <if test="regionName != null and regionName != ''">
                and (t.out_target = #{regionName}
                and (d.final_outbound_area = #{regionName}
                <!-- 或者设备是共享给当前部门的 -->
                <if test="currentDeptId != null and currentDeptId != '' ">
                    or d.id in (
@@ -292,30 +276,14 @@
                split_device_type
            FROM
                ja_fw_device d
            LEFT JOIN (
                SELECT
                    device_id,
                    out_target,
                    ROW_NUMBER() OVER (
                    PARTITION BY
                    device_id
                    ORDER BY
                    create_time DESC
                ) AS rn
            FROM
                ja_fw_device_track
            WHERE
                out_target IS NOT NULL
            ) t ON d.id = t.device_id AND t.rn = 1
            WHERE
                d.is_deleted = 0
            AND status != 3
            AND device_type = '3'
            AND track_status = 1
            AND effective_range_km is not null
            AND effective_range_km > 0
                AND is_enabled = 1
                AND status != 3
                AND device_type = '3'
                AND track_status = 1
            <if test="regionName != null and regionName != ''">
                and (t.out_target = #{regionName}
                and (d.final_outbound_area = #{regionName}
                <!-- 或者设备是共享给当前部门的 -->
                <if test="currentDeptId != null and currentDeptId != '' ">
                    or d.id in (
@@ -355,29 +323,14 @@
    <!-- 设备出库去向统计 -->
    <select id="getDeviceOutStatistics" resultType="org.sxkj.fw.cockpit.vo.DeviceStatisticsVO">
        SELECT
            t.out_target AS type,
            d.final_outbound_area AS type,
            COUNT(*) AS count
        FROM
            ja_fw_device d
                LEFT JOIN (
                SELECT
                    device_id,
                    out_target,
                    ROW_NUMBER() OVER (
                        PARTITION BY
                            device_id
                        ORDER BY
                            create_time DESC
                        ) AS rn
                FROM
                    ja_fw_device_track
                WHERE
                    out_target IS NOT NULL
            ) t ON d.id = t.device_id
                AND t.rn = 1
        WHERE
            d.is_deleted = 0
          AND t.out_target IS NOT NULL
            AND d.is_enabled = 1
            AND d.final_outbound_area IS NOT NULL
        <if test="effectiveRangeKmIsNotNull != null and effectiveRangeKmIsNotNull == 1">
            and d.effective_range_km is not null
            and d.effective_range_km > 0
@@ -392,7 +345,7 @@
            </foreach>
        </if>
        GROUP BY
            t.out_target
            d.final_outbound_area
    </select>
    <!--  设备生产厂商统计  -->
@@ -422,29 +375,14 @@
                 COUNT(*)
             FROM
                 ja_fw_device d
            LEFT JOIN (
            SELECT
                device_id,
                out_target,
                ROW_NUMBER() OVER (
                PARTITION BY
                device_id
                ORDER BY
                create_time DESC
                ) AS rn
            FROM
                ja_fw_device_track
            WHERE
            out_target IS NOT NULL
            ) t
                ON d.id = t.device_id AND t.rn = 1
             WHERE
                 d.is_deleted = 0
               and d.is_enabled = 1
               and effective_range_km is not null
               and effective_range_km > 0
                AND track_status = 1
                <if test="regionName != null and regionName != ''">
                    and (t.out_target = #{regionName}
                    and (d.final_outbound_area = #{regionName}
                    <!-- 或者设备是共享给当前部门的 -->
                    <if test="currentDeptId != null and currentDeptId != '' ">
                        or d.id in (
@@ -461,30 +399,15 @@
                 COUNT(*)
             FROM
                 ja_fw_device d
            LEFT JOIN (
                SELECT
                    device_id,
                    out_target,
                    ROW_NUMBER() OVER (
                    PARTITION BY
                    device_id
                    ORDER BY
                    create_time DESC
                    ) AS rn
                FROM
                    ja_fw_device_track
                WHERE
                    out_target IS NOT NULL
                ) t
                ON d.id = t.device_id AND t.rn = 1
             WHERE
                 d.is_deleted = 0
               and d.is_enabled = 1
               AND device_att = '1'
               and effective_range_km is not null
               and effective_range_km > 0
               AND track_status = 1
                <if test="regionName != null and regionName != ''">
                and (t.out_target = #{regionName}
                and (d.final_outbound_area = #{regionName}
                <!-- 或者设备是共享给当前部门的 -->
                    <if test="currentDeptId != null and currentDeptId != '' ">
                        or d.id in (
@@ -501,29 +424,14 @@
                 COUNT(*)
             FROM
                 ja_fw_device d
            LEFT JOIN (
                SELECT
                    device_id,
                    out_target,
                    ROW_NUMBER() OVER (
                    PARTITION BY
                    device_id
                    ORDER BY
                    create_time DESC
                    ) AS rn
                FROM
                    ja_fw_device_track
                WHERE
                    out_target IS NOT NULL
                ) t
                ON d.id = t.device_id AND t.rn = 1
             WHERE d.is_deleted = 0
               and d.is_enabled = 1
               AND device_att = '2'
               and effective_range_km is not null
               and effective_range_km > 0
               AND track_status = 1
            <if test="regionName != null and regionName != ''">
                and (t.out_target = #{regionName}
                and (d.final_outbound_area = #{regionName}
                <!-- 或者设备是共享给当前部门的 -->
                <if test="currentDeptId != null and currentDeptId != '' ">
                    or d.id in (
@@ -539,29 +447,14 @@
            (SELECT
                 COUNT(*)
             FROM ja_fw_device d
            LEFT JOIN (
            SELECT
                device_id,
                out_target,
                ROW_NUMBER() OVER (
                PARTITION BY
                device_id
                ORDER BY
                create_time DESC
                ) AS rn
            FROM
                ja_fw_device_track
            WHERE
            out_target IS NOT NULL
            ) t
            ON d.id = t.device_id AND t.rn = 1
             WHERE d.is_deleted = 0
               and d.is_enabled = 1
               AND device_att = '3'
               and effective_range_km is not null
               and effective_range_km > 0
               AND track_status = 1
                <if test="regionName != null and regionName != ''">
                    and (t.out_target = #{regionName}
                    and (d.final_outbound_area = #{regionName}
                    <!-- 或者设备是共享给当前部门的 -->
                    <if test="currentDeptId != null and currentDeptId != '' ">
                        or d.id in (
@@ -576,30 +469,15 @@
            -- 设备告警
            (SELECT
                 COUNT(*)
             FROM ja_fw_device  d
            LEFT JOIN (
                SELECT
                    device_id,
                    out_target,
                    ROW_NUMBER() OVER (
                    PARTITION BY
                    device_id
                    ORDER BY
                    create_time DESC
                    ) AS rn
                FROM
                    ja_fw_device_track
                WHERE
                    out_target IS NOT NULL
                ) t
                ON d.id = t.device_id AND t.rn = 1
             FROM ja_fw_device d
             WHERE d.is_deleted = 0
               and d.is_enabled = 1
               AND status in ('1', '2', '3' )
               and effective_range_km is not null
               and effective_range_km > 0
               AND track_status = 1
                <if test="regionName != null and regionName != ''">
                    and (t.out_target = #{regionName}
                    and (d.final_outbound_area = #{regionName}
                    <!-- 或者设备是共享给当前部门的 -->
                    <if test="currentDeptId != null and currentDeptId != '' ">
                        or d.id in (
@@ -618,29 +496,14 @@
            d.*
        from
            ja_fw_device d
        LEFT JOIN (
            SELECT
                device_id,
                out_target,
                ROW_NUMBER() OVER (
                PARTITION BY
                device_id
                ORDER BY
                create_time DESC
                ) AS rn
            FROM
                ja_fw_device_track
            WHERE
                out_target IS NOT NULL
            ) t
            ON d.id = t.device_id AND t.rn = 1
        <where>
            d.is_deleted = 0
            and d.effective_range_km is not null
            and d.effective_range_km > 0
--             and d.effective_range_km is not null
--             and d.effective_range_km > 0
            and d.track_status = 1
            and d.is_enabled = 1
            <if test="param2.regionName != null and param2.regionName != ''">
                and (t.out_target = #{param2.regionName}
                and (d.final_outbound_area = #{param2.regionName}
                <!-- 或者设备是共享给当前部门的 -->
                <if test="param2.currentDeptId != null and param2.currentDeptId != '' ">
                    or d.id in (
@@ -720,31 +583,16 @@
            END AS isShared
        FROM
            ja_fw_device d
            LEFT JOIN (
            SELECT
            device_id,
            out_target,
            ROW_NUMBER() OVER (
            PARTITION BY
            device_id
            ORDER BY
            create_time DESC
            ) AS rn
            FROM
            ja_fw_device_track
            WHERE
            out_target IS NOT NULL
            ) t ON d.id = t.device_id
            AND t.rn = 1
            LEFT JOIN ja_fw_device_per_share ps ON ps.device_id = d.id
            AND ps.loan_to_dept_id = #{currentDeptId}
            AND ps.is_deleted = 0
        WHERE
            d.is_deleted = 0
          and d.is_enabled = 1
          and d.effective_range_km is not null
          and d.effective_range_km > 0
          and d.track_status = 1
          AND t.out_target != #{regionName}
          AND d.final_outbound_area != #{regionName}
    </select>
</mapper>
drone-service/drone-fw/src/main/java/org/sxkj/fw/record/mapper/FwDroneAlarmRecordMapper.xml
@@ -38,7 +38,7 @@
            dar.*,
            d.device_name,
            d.status deviceStatus,
            t.out_target,
            d.final_outbound_area,
            /* 1=已关注,0=未关注 */
            EXISTS (
                SELECT
@@ -54,28 +54,12 @@
            ja_fw_drone_alarm_record dar
        left join
            ja_fw_device d on dar.device_id = d.id
        /* 关联出库去向表,看设备去了哪里  */
        LEFT JOIN (
            SELECT
                device_id,
                out_target,
                ROW_NUMBER() OVER (
                PARTITION BY
                device_id
                ORDER BY
                create_time DESC
            ) AS rn
            FROM
                ja_fw_device_track
            WHERE
                out_target IS NOT NULL
            ) t
            ON d.id = t.device_id AND t.rn = 1
        <where>
                dar.is_deleted = 0
                and d.track_status = 1
                and d.is_enabled = 1
            <if test="param2.regionName != null and param2.regionName != ''">
                and (t.out_target = #{param2.regionName}
                and (d.final_outbound_area = #{param2.regionName}
                <!-- 或者设备是共享给当前部门的 -->
                <if test="param2.currentDeptId != null and param2.currentDeptId != '' ">
                    or dar.device_id in (
@@ -187,28 +171,12 @@
            ja_fw_drone_alarm_record  dar
        left join
            ja_fw_device d on dar.device_id = d.id
        /* 关联出库去向表,看设备去了哪里  */
        LEFT JOIN (
            SELECT
                device_id,
                out_target,
                ROW_NUMBER() OVER (
                PARTITION BY
                device_id
                ORDER BY
                create_time DESC
                ) AS rn
            FROM
                ja_fw_device_track
            WHERE
            out_target IS NOT NULL
            ) t
            ON d.id = t.device_id AND t.rn = 1
        WHERE dar.is_deleted = 0
            AND d.track_status = 1
            AND d.is_deleted = 0
            and d.is_enabled = 1
        <if test="regionName != null and regionName != ''">
            and (t.out_target = #{regionName}
            and (d.final_outbound_area = #{regionName}
            <!-- 或者设备是共享给当前部门的 -->
            <if test="currentDeptId != null and currentDeptId != '' ">
                or dar.device_id in (
drone-service/drone-fw/src/main/java/org/sxkj/fw/record/mapper/FwDroneFlightRecordMapper.xml
@@ -29,28 +29,12 @@
            ja_fw_drone_flight_record dfr
        left join
            ja_fw_device d on dfr.device_id = d.id
        /* 关联出库去向表,看设备去了哪里  */
        LEFT JOIN (
            SELECT
                device_id,
                out_target,
                ROW_NUMBER() OVER (
                PARTITION BY
                device_id
                ORDER BY
                create_time DESC
                ) AS rn
            FROM
                ja_fw_device_track
            WHERE
                out_target IS NOT NULL
            ) t
            ON d.id = t.device_id AND t.rn = 1
        <where>
                dfr.is_deleted = 0
                and d.track_status = 1
                and d.is_enabled = 1
            <if test="param2.regionName != null and param2.regionName != ''">
                and (t.out_target = #{param2.regionName}
                and (d.final_outbound_area = #{param2.regionName}
                <!-- 或者设备是共享给当前部门的 -->
                <if test="param2.currentDeptId != null and param2.currentDeptId != '' ">
                    or dfr.device_id in (
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/controller/GdImplementListController.java
New file
@@ -0,0 +1,123 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
import javax.validation.Valid;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.sxkj.gd.common.GenericConverter;
import org.sxkj.gd.common.IdParam;
import org.sxkj.gd.implement.dto.GdImplementListDTO;
import org.sxkj.gd.implement.entity.GdImplementListEntity;
import org.sxkj.gd.implement.param.GdImplementListPageParam;
import org.sxkj.gd.implement.vo.GdImplementListVO;
import org.sxkj.gd.implement.excel.GdImplementListExcel;
import org.sxkj.gd.implement.wrapper.GdImplementListWrapper;
import org.sxkj.gd.implement.service.IGdImplementListService;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.tool.constant.BladeConstant;
import springfox.documentation.annotations.ApiIgnore;
import java.util.Map;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
/**
 * 实施清单主表 控制器
 *
 * @author Aix
 * @since 2026-01-31
 */
@RestController
@AllArgsConstructor
@RequestMapping("implement/gdImplementList")
@Api(value = "实施清单主表", tags = "实施清单主表接口")
public class GdImplementListController extends BladeController {
    private final IGdImplementListService gdImplementListService;
    /**
     * 实施清单主表 详情
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "详情", notes = "传入gdImplementList")
    public R<GdImplementListVO> detail(IdParam idParam) {
        GdImplementListEntity detail = gdImplementListService.getOne(Condition.getQueryWrapper(GenericConverter.convert(idParam, GdImplementListEntity.class)));
        return R.data(GdImplementListWrapper.build().entityVO(detail));
    }
    /**
     * 实施清单主表 自定义分页
     */
    @GetMapping("/page")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "分页", notes = "传入gdImplementList")
    public R<IPage<GdImplementListVO>> page(GdImplementListPageParam param, Query query) {
        IPage<GdImplementListVO> pages = gdImplementListService.selectGdImplementListPage(
            Condition.getPage(query), param);
        return R.data(pages);
    }
    /**
     * 实施清单主表 新增或修改
     */
    @PostMapping("/submit")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "新增或修改", notes = "传入gdImplementList")
    public R submit(@Valid @RequestBody GdImplementListDTO gdImplementList) {
        return R.status(gdImplementListService.saveOrUpdate(GenericConverter.convert(gdImplementList, GdImplementListEntity.class)));
    }
    /**
     * 实施清单主表 删除
     */
    @PostMapping("/remove")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "逻辑删除", notes = "传入ids")
    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
        return R.status(gdImplementListService.deleteLogic(Func.toLongList(ids)));
    }
    /**
     * 导出数据
     */
    @GetMapping("/export-gdImplementList")
    @ApiOperationSupport(order = 99)
    @ApiOperation(value = "导出数据", notes = "传入gdImplementList")
    @ApiIgnore
    public void exportGdImplementList(@ApiIgnore @RequestParam Map<String, Object> gdImplementList, BladeUser bladeUser, HttpServletResponse response) {
        QueryWrapper<GdImplementListEntity> queryWrapper = Condition.getQueryWrapper(gdImplementList, GdImplementListEntity.class);
        queryWrapper.lambda().eq(GdImplementListEntity::getIsDeleted, BladeConstant.DB_NOT_DELETED);
        List<GdImplementListExcel> list = gdImplementListService.exportGdImplementList(queryWrapper);
        ExcelUtil.export(response, "实施清单主表数据" + DateUtil.time(), "实施清单主表数据表", list, GdImplementListExcel.class);
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/controller/GdMaterialController.java
New file
@@ -0,0 +1,121 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
import javax.validation.Valid;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.sxkj.gd.common.GenericConverter;
import org.sxkj.gd.common.IdParam;
import org.sxkj.gd.implement.dto.GdMaterialDTO;
import org.sxkj.gd.implement.entity.GdMaterialEntity;
import org.sxkj.gd.implement.vo.GdMaterialVO;
import org.sxkj.gd.implement.excel.GdMaterialExcel;
import org.sxkj.gd.implement.wrapper.GdMaterialWrapper;
import org.sxkj.gd.implement.service.IGdMaterialService;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.tool.constant.BladeConstant;
import springfox.documentation.annotations.ApiIgnore;
import java.util.Map;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
/**
 * 材料信息表 控制器
 *
 * @author Aix
 * @since 2026-01-31
 */
@RestController
@AllArgsConstructor
@RequestMapping("implement/gdMaterial")
@Api(value = "材料信息表", tags = "材料信息表接口")
public class GdMaterialController extends BladeController {
    private final IGdMaterialService gdMaterialService;
    /**
     * 材料信息表 详情
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "详情", notes = "传入gdMaterial")
    public R<GdMaterialVO> detail(IdParam idParam) {
        GdMaterialEntity detail = gdMaterialService.getOne(Condition.getQueryWrapper(GenericConverter.convert(idParam, GdMaterialEntity.class)));
        return R.data(GdMaterialWrapper.build().entityVO(detail));
    }
    /**
     * 材料信息表 自定义分页
     */
    @GetMapping("/page")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "分页", notes = "传入gdMaterial")
    public R<IPage<GdMaterialVO>> page(GdMaterialDTO gdMaterial, Query query) {
        IPage<GdMaterialVO> pages = gdMaterialService.selectGdMaterialPage(Condition.getPage(query), gdMaterial);
        return R.data(pages);
    }
    /**
     * 材料信息表 新增或修改
     */
    @PostMapping("/submit")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "新增或修改", notes = "传入gdMaterial")
    public R submit(@Valid @RequestBody GdMaterialDTO gdMaterial) {
        return R.status(gdMaterialService.saveOrUpdate(GenericConverter.convert(gdMaterial, GdMaterialEntity.class)));
    }
    /**
     * 材料信息表 删除
     */
    @PostMapping("/remove")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "逻辑删除", notes = "传入ids")
    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
        return R.status(gdMaterialService.deleteLogic(Func.toLongList(ids)));
    }
    /**
     * 导出数据
     */
    @GetMapping("/export-gdMaterial")
    @ApiOperationSupport(order = 99)
    @ApiOperation(value = "导出数据", notes = "传入gdMaterial")
    @ApiIgnore
    public void exportGdMaterial(@ApiIgnore @RequestParam Map<String, Object> gdMaterial, BladeUser bladeUser, HttpServletResponse response) {
        QueryWrapper<GdMaterialEntity> queryWrapper = Condition.getQueryWrapper(gdMaterial, GdMaterialEntity.class);
        queryWrapper.lambda().eq(GdMaterialEntity::getIsDeleted, BladeConstant.DB_NOT_DELETED);
        List<GdMaterialExcel> list = gdMaterialService.exportGdMaterial(queryWrapper);
        ExcelUtil.export(response, "材料信息表数据" + DateUtil.time(), "材料信息表数据表", list, GdMaterialExcel.class);
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/dto/GdImplementListDTO.java
New file
@@ -0,0 +1,101 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty;
import org.sxkj.gd.implement.entity.GdImplementListEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * 实施清单主表 数据传输对象实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
public class GdImplementListDTO implements Serializable {
    private static final long serialVersionUID = 1L;
    @JsonSerialize(
        using = ToStringSerializer.class
    )
    @ApiModelProperty("主键id")
    private Long id;
    /**
     * 事项名称
     */
    @ApiModelProperty(value = "事项名称")
    private String matterName;
    /**
     * 事项编码
     */
    @ApiModelProperty(value = "事项编码")
    private String matterCode;
    /**
     * 所属区划编码
     */
    @ApiModelProperty(value = "所属区划编码")
    private String areaCode;
    /**
     * 所属区划名称
     */
    @ApiModelProperty(value = "所属区划名称")
    private String areaName;
    /**
     * 所属机构编码
     */
    @ApiModelProperty(value = "所属机构编码")
    private String orgCode;
    /**
     * 所属机构名称
     */
    @ApiModelProperty(value = "所属机构名称")
    private String orgName;
    /**
     * 目录编码
     */
    @ApiModelProperty(value = "目录编码")
    private String catalogCode;
    /**
     * 实施编码
     */
    @ApiModelProperty(value = "实施编码")
    private String implementCode;
    /**
     * 实施清单名称
     */
    @ApiModelProperty(value = "实施清单名称")
    private String implementName;
    /**
     * 流程定义主键
     */
    @ApiModelProperty(value = "流程定义主键")
    private String processDefinitionId;
    /**
     * 流程实例主键
     */
    @ApiModelProperty(value = "流程实例主键")
    private String processInstanceId;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/dto/GdMaterialDTO.java
New file
@@ -0,0 +1,69 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
 * 材料信息表 数据传输对象实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
public class GdMaterialDTO implements Serializable {
    private static final long serialVersionUID = 1L;
    @JsonSerialize(
        using = ToStringSerializer.class
    )
    @ApiModelProperty("主键id")
    private Long id;
    /**
     * 材料名称(列表展示字段)
     */
    @ApiModelProperty(value = "材料名称(列表展示字段)")
    private String materialName;
    /**
     * 必要性:必填/可选/容缺
     */
    @ApiModelProperty(value = "必要性:必填/可选/容缺")
    private String necessity;
    /**
     * 是否适用全部情形:1是 0否
     */
    @ApiModelProperty(value = "是否适用全部情形:1是 0否")
    private Integer isAllScenario;
    /**
     * 材料说明
     */
    @ApiModelProperty(value = "材料说明")
    private String materialDesc;
    /**
     * 区域编码
     */
    @ApiModelProperty(value = "区域编码")
    private String areaCode;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/dto/GdThingListMaterialRelDTO.java
File was renamed from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/dto/GdImplementationListDTO.java
@@ -14,22 +14,21 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.dto;
package org.sxkj.gd.implement.dto;
import java.io.Serializable;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implement.entity.GdThingListMaterialRelEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 实施清单表(实时清单管理) 数据传输对象实体类
 * 实施清单-材料关联表(情形化配置) 数据传输对象实体类
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class GdImplementationListDTO extends GdImplementationListEntity implements Serializable {
public class GdThingListMaterialRelDTO extends GdThingListMaterialRelEntity {
    private static final long serialVersionUID = 1L;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/entity/GdImplementListEntity.java
New file
@@ -0,0 +1,94 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
/**
 * 实施清单主表 实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
@TableName("ja_gd_implement_list")
@ApiModel(value = "GdImplementList对象", description = "实施清单主表")
@EqualsAndHashCode(callSuper = true)
public class GdImplementListEntity extends BaseEntity {
    /**
     * 事项名称
     */
    @ApiModelProperty(value = "事项名称")
    private String matterName;
    /**
     * 事项编码
     */
    @ApiModelProperty(value = "事项编码")
    private String matterCode;
    /**
     * 所属区划编码
     */
    @ApiModelProperty(value = "所属区划编码")
    private String areaCode;
    /**
     * 所属区划名称
     */
    @ApiModelProperty(value = "所属区划名称")
    private String areaName;
    /**
     * 所属机构编码
     */
    @ApiModelProperty(value = "所属机构编码")
    private String orgCode;
    /**
     * 所属机构名称
     */
    @ApiModelProperty(value = "所属机构名称")
    private String orgName;
    /**
     * 目录编码
     */
    @ApiModelProperty(value = "目录编码")
    private String catalogCode;
    /**
     * 实施编码
     */
    @ApiModelProperty(value = "实施编码")
    private String implementCode;
    /**
     * 实施清单名称
     */
    @ApiModelProperty(value = "实施清单名称")
    private String implementName;
    /**
     * 流程定义主键
     */
    @ApiModelProperty(value = "流程定义主键")
    private String processDefinitionId;
    /**
     * 流程实例主键
     */
    @ApiModelProperty(value = "流程实例主键")
    private String processInstanceId;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/entity/GdMaterialEntity.java
New file
@@ -0,0 +1,64 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
/**
 * 材料信息表 实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
@TableName("ja_gd_material")
@ApiModel(value = "GdMaterial对象", description = "材料信息表")
@EqualsAndHashCode(callSuper = true)
public class GdMaterialEntity extends BaseEntity {
    /**
     * 材料名称(列表展示字段)
     */
    @ApiModelProperty(value = "材料名称(列表展示字段)")
    private String materialName;
    /**
     * 必要性:必填/可选/容缺
     */
    @ApiModelProperty(value = "必要性:必填/可选/容缺")
    private String necessity;
    /**
     * 是否适用全部情形:1是 0否
     */
    @ApiModelProperty(value = "是否适用全部情形:1是 0否")
    private Integer isAllScenario;
    /**
     * 材料说明
     */
    @ApiModelProperty(value = "材料说明")
    private String materialDesc;
    /**
     * 区域编码
     */
    @ApiModelProperty(value = "区域编码")
    private String areaCode;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/entity/GdThingListMaterialRelEntity.java
New file
@@ -0,0 +1,59 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
/**
 * 实施清单-材料关联表(情形化配置) 实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
@TableName("ja_gd_thing_list_material_rel")
@ApiModel(value = "GdThingListMaterialRel对象", description = "实施清单-材料关联表(情形化配置)")
@EqualsAndHashCode(callSuper = true)
public class GdThingListMaterialRelEntity extends BaseEntity {
    /**
     * 关联实施清单ID
     */
    @ApiModelProperty(value = "关联实施清单ID")
    private Long implementListId;
    /**
     * 关联材料ID
     */
    @ApiModelProperty(value = "关联材料ID")
    private Long materialId;
    /**
     * 材料序号(列表展示字段)
     */
    @ApiModelProperty(value = "材料序号(列表展示字段)")
    private Integer sort;
    /**
     * 材料情形化配置:{"scenario_name":"情形1","is_need":1,"remark":"仅情形1需提供"}
     */
    @ApiModelProperty(value = "材料情形化配置:{\"scenario_name\":\"情形1\",\"is_need\":1,\"remark\":\"仅情形1需提供\"}")
    private String scenarioConfig;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/excel/GdImplementListExcel.java
File was renamed from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/excel/GdImplementationListExcel.java
@@ -14,7 +14,7 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.excel;
package org.sxkj.gd.implement.excel;
import com.alibaba.excel.annotation.ExcelProperty;
@@ -27,73 +27,85 @@
/**
 * 实施清单表(实时清单管理) Excel实体类
 * 实施清单主表 Excel实体类
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class GdImplementationListExcel implements Serializable {
public class GdImplementListExcel implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 实施编码(唯一)
     * 事项名称
     */
    @ColumnWidth(20)
    @ExcelProperty("实施编码(唯一)")
    private String implementationCode;
    @ExcelProperty("事项名称")
    private String matterName;
    /**
     * 事项编码
     */
    @ColumnWidth(20)
    @ExcelProperty("事项编码")
    private String matterCode;
    /**
     * 所属区划编码
     */
    @ColumnWidth(20)
    @ExcelProperty("所属区划编码")
    private String areaCode;
    /**
     * 所属区划名称
     */
    @ColumnWidth(20)
    @ExcelProperty("所属区划名称")
    private String areaName;
    /**
     * 所属机构编码
     */
    @ColumnWidth(20)
    @ExcelProperty("所属机构编码")
    private String orgCode;
    /**
     * 所属机构名称
     */
    @ColumnWidth(20)
    @ExcelProperty("所属机构名称")
    private String orgName;
    /**
     * 目录编码
     */
    @ColumnWidth(20)
    @ExcelProperty("目录编码")
    private String catalogCode;
    /**
     * 实施编码
     */
    @ColumnWidth(20)
    @ExcelProperty("实施编码")
    private String implementCode;
    /**
     * 实施清单名称
     */
    @ColumnWidth(20)
    @ExcelProperty("实施清单名称")
    private String listName;
    private String implementName;
    /**
     * 所属区划
     * 流程定义主键
     */
    @ColumnWidth(20)
    @ExcelProperty("所属区划")
    private String belongArea;
    @ExcelProperty("流程定义主键")
    private String processDefinitionId;
    /**
     * 所属机构
     * 流程实例主键
     */
    @ColumnWidth(20)
    @ExcelProperty("所属机构")
    private String belongOrg;
    /**
     * 项目编码
     */
    @ColumnWidth(20)
    @ExcelProperty("项目编码")
    private String projectCode;
    /**
     * 材料数量
     */
    @ColumnWidth(20)
    @ExcelProperty("材料数量")
    private Integer materialQuantity;
    /**
     * 结果送达方式(短信方式等)
     */
    @ColumnWidth(20)
    @ExcelProperty("结果送达方式(短信方式等)")
    private String resultDeliveryMethod;
    /**
     * 受条件规则(已注册用户等)
     */
    @ColumnWidth(20)
    @ExcelProperty("受条件规则(已注册用户等)")
    private String acceptanceRules;
    /**
     * 区域编码
     */
    @ColumnWidth(20)
    @ExcelProperty("区域编码")
    private String areaCode;
    @ExcelProperty("流程实例主键")
    private String processInstanceId;
    /**
     * 删除标志(0存在 1删除)
     */
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/excel/GdMaterialExcel.java
New file
@@ -0,0 +1,80 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import java.io.Serializable;
/**
 * 材料信息表 Excel实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class GdMaterialExcel implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 材料名称(列表展示字段)
     */
    @ColumnWidth(20)
    @ExcelProperty("材料名称(列表展示字段)")
    private String materialName;
    /**
     * 必要性:必填/可选/容缺
     */
    @ColumnWidth(20)
    @ExcelProperty("必要性:必填/可选/容缺")
    private String necessity;
    /**
     * 是否适用全部情形:1是 0否
     */
    @ColumnWidth(20)
    @ExcelProperty("是否适用全部情形:1是 0否")
    private Byte isAllScenario;
    /**
     * 材料说明
     */
    @ColumnWidth(20)
    @ExcelProperty("材料说明")
    private String materialDesc;
    /**
     * 区域编码
     */
    @ColumnWidth(20)
    @ExcelProperty("区域编码")
    private String areaCode;
    /**
     * 删除标志(0存在 1删除)
     */
    @ColumnWidth(20)
    @ExcelProperty("删除标志(0存在 1删除)")
    private Byte isDeleted;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/excel/GdThingListMaterialRelExcel.java
New file
@@ -0,0 +1,75 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.excel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
 * 实施清单-材料关联表(情形化配置) Excel实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class GdThingListMaterialRelExcel implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 关联实施清单ID
     */
    @ColumnWidth(20)
    @ExcelProperty("关联实施清单ID")
    private Long implementListId;
    /**
     * 关联材料ID
     */
    @ColumnWidth(20)
    @ExcelProperty("关联材料ID")
    private Long materialId;
    /**
     * 材料序号(列表展示字段)
     */
    @ColumnWidth(20)
    @ExcelProperty("材料序号(列表展示字段)")
    private Integer sort;
    /**
     * 材料情形化配置:{"scenario_name":"情形1","is_need":1,"remark":"仅情形1需提供"}
     */
    @ColumnWidth(20)
    @ExcelProperty("材料情形化配置:{\"scenario_name\":\"情形1\",\"is_need\":1,\"remark\":\"仅情形1需提供\"}")
    private String scenarioConfig;
    /**
     * 删除标志(0存在 1删除)
     */
    @ColumnWidth(20)
    @ExcelProperty("删除标志(0存在 1删除)")
    private Byte isDeleted;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdImplementListMapper.java
copy from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/mapper/GdImplementationListMapper.java copy to drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdImplementListMapper.java
File was copied from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/mapper/GdImplementationListMapper.java
@@ -14,11 +14,13 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.mapper;
package org.sxkj.gd.implement.mapper;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implementation.vo.GdImplementationListVO;
import org.sxkj.gd.implementation.excel.GdImplementationListExcel;
import org.sxkj.gd.implement.dto.GdImplementListDTO;
import org.sxkj.gd.implement.entity.GdImplementListEntity;
import org.sxkj.gd.implement.param.GdImplementListPageParam;
import org.sxkj.gd.implement.vo.GdImplementListVO;
import org.sxkj.gd.implement.excel.GdImplementListExcel;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -26,21 +28,21 @@
import java.util.List;
/**
 * 实施清单表(实时清单管理) Mapper 接口
 * 实施清单主表 Mapper 接口
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
public interface GdImplementationListMapper extends BaseMapper<GdImplementationListEntity> {
public interface GdImplementListMapper extends BaseMapper<GdImplementListEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param gdImplementationList
     * @param gdImplementList
     * @return
     */
    List<GdImplementationListVO> selectGdImplementationListPage(IPage page, GdImplementationListVO gdImplementationList);
    List<GdImplementListVO> selectGdImplementListPage(IPage page, GdImplementListPageParam gdImplementList);
    /**
@@ -49,6 +51,6 @@
     * @param queryWrapper
     * @return
     */
    List<GdImplementationListExcel> exportGdImplementationList(@Param("ew") Wrapper<GdImplementationListEntity> queryWrapper);
    List<GdImplementListExcel> exportGdImplementList(@Param("ew") Wrapper<GdImplementListEntity> queryWrapper);
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdImplementListMapper.xml
New file
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.sxkj.gd.implement.mapper.GdImplementListMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="gdImplementListResultMap" type="org.sxkj.gd.implement.vo.GdImplementListVO">
        <result column="id" property="id"/>
        <result column="matter_name" property="matterName"/>
        <result column="matter_code" property="matterCode"/>
        <result column="area_code" property="areaCode"/>
        <result column="area_name" property="areaName"/>
        <result column="org_code" property="orgCode"/>
        <result column="org_name" property="orgName"/>
        <result column="catalog_code" property="catalogCode"/>
        <result column="implement_code" property="implementCode"/>
        <result column="implement_name" property="implementName"/>
        <result column="process_definition_id" property="processDefinitionId"/>
        <result column="process_instance_id" property="processInstanceId"/>
    </resultMap>
    <select id="selectGdImplementListPage" resultMap="gdImplementListResultMap">
        select * from ja_gd_implement_list where is_deleted = 0
        <if test="param2.matterName != null and param2.matterName != ''">
            and matter_name like concat('%',#{param2.matterName},'%')
        </if>
        <if test="param2.matterCode != null and param2.matterCode != ''">
            and matter_code like concat('%',#{param2.matterCode},'%')
        </if>
        <if test="param2.areaCode != null and param2.areaCode != ''">
            and area_code like concat('%',#{param2.areaCode},'%')
        </if>
        <if test="param2.orgCode != null and param2.orgCode != ''">
            and org_code like concat('%',#{param2.orgCode},'%')
        </if>
        <if test="param2.catalogCode != null and param2.catalogCode != ''">
            and catalog_code like concat('%',#{param2.catalogCode},'%')
        </if>
        <if test="param2.deptList != null and param2.deptList.size > 0">
            AND create_dept in
            <foreach collection="param2.deptList" item="deptId" open="(" separator="," close=")">
                #{deptId}
            </foreach>
        </if>
    </select>
    <select id="exportGdImplementList" resultType="org.sxkj.gd.implement.excel.GdImplementListExcel">
        SELECT * FROM ja_gd_implement_list ${ew.customSqlSegment}
    </select>
</mapper>
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdMaterialMapper.java
File was renamed from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/mapper/GdImplementationListMapper.java
@@ -14,11 +14,12 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.mapper;
package org.sxkj.gd.implement.mapper;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implementation.vo.GdImplementationListVO;
import org.sxkj.gd.implementation.excel.GdImplementationListExcel;
import org.sxkj.gd.implement.dto.GdMaterialDTO;
import org.sxkj.gd.implement.entity.GdMaterialEntity;
import org.sxkj.gd.implement.vo.GdMaterialVO;
import org.sxkj.gd.implement.excel.GdMaterialExcel;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -26,21 +27,21 @@
import java.util.List;
/**
 * 实施清单表(实时清单管理) Mapper 接口
 * 材料信息表 Mapper 接口
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
public interface GdImplementationListMapper extends BaseMapper<GdImplementationListEntity> {
public interface GdMaterialMapper extends BaseMapper<GdMaterialEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param gdImplementationList
     * @param gdMaterial
     * @return
     */
    List<GdImplementationListVO> selectGdImplementationListPage(IPage page, GdImplementationListVO gdImplementationList);
    List<GdMaterialVO> selectGdMaterialPage(IPage page, GdMaterialDTO gdMaterial);
    /**
@@ -49,6 +50,6 @@
     * @param queryWrapper
     * @return
     */
    List<GdImplementationListExcel> exportGdImplementationList(@Param("ew") Wrapper<GdImplementationListEntity> queryWrapper);
    List<GdMaterialExcel> exportGdMaterial(@Param("ew") Wrapper<GdMaterialEntity> queryWrapper);
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdMaterialMapper.xml
New file
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.sxkj.gd.implement.mapper.GdMaterialMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="gdMaterialResultMap" type="org.sxkj.gd.implement.vo.GdMaterialVO">
        <result column="id" property="id"/>
        <result column="material_name" property="materialName"/>
        <result column="necessity" property="necessity"/>
        <result column="is_all_scenario" property="isAllScenario"/>
        <result column="material_desc" property="materialDesc"/>
        <result column="area_code" property="areaCode"/>
        <result column="create_user" property="createUser"/>
        <result column="create_dept" property="createDept"/>
        <result column="create_time" property="createTime"/>
        <result column="update_user" property="updateUser"/>
        <result column="update_time" property="updateTime"/>
        <result column="status" property="status"/>
        <result column="is_deleted" property="isDeleted"/>
    </resultMap>
    <select id="selectGdMaterialPage" resultMap="gdMaterialResultMap">
        select * from ja_gd_material where is_deleted = 0
    </select>
    <select id="exportGdMaterial" resultType="org.sxkj.gd.implement.excel.GdMaterialExcel">
        SELECT * FROM ja_gd_material ${ew.customSqlSegment}
    </select>
</mapper>
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdThingListMaterialRelMapper.java
copy from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/mapper/GdImplementationListMapper.java copy to drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdThingListMaterialRelMapper.java
File was copied from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/mapper/GdImplementationListMapper.java
@@ -14,11 +14,11 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.mapper;
package org.sxkj.gd.implement.mapper;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implementation.vo.GdImplementationListVO;
import org.sxkj.gd.implementation.excel.GdImplementationListExcel;
import org.sxkj.gd.implement.entity.GdThingListMaterialRelEntity;
import org.sxkj.gd.implement.vo.GdThingListMaterialRelVO;
import org.sxkj.gd.implement.excel.GdThingListMaterialRelExcel;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -26,21 +26,21 @@
import java.util.List;
/**
 * 实施清单表(实时清单管理) Mapper 接口
 * 实施清单-材料关联表(情形化配置) Mapper 接口
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
public interface GdImplementationListMapper extends BaseMapper<GdImplementationListEntity> {
public interface GdThingListMaterialRelMapper extends BaseMapper<GdThingListMaterialRelEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param gdImplementationList
     * @param gdThingListMaterialRel
     * @return
     */
    List<GdImplementationListVO> selectGdImplementationListPage(IPage page, GdImplementationListVO gdImplementationList);
    List<GdThingListMaterialRelVO> selectGdThingListMaterialRelPage(IPage page, GdThingListMaterialRelVO gdThingListMaterialRel);
    /**
@@ -49,6 +49,6 @@
     * @param queryWrapper
     * @return
     */
    List<GdImplementationListExcel> exportGdImplementationList(@Param("ew") Wrapper<GdImplementationListEntity> queryWrapper);
    List<GdThingListMaterialRelExcel> exportGdThingListMaterialRel(@Param("ew") Wrapper<GdThingListMaterialRelEntity> queryWrapper);
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/mapper/GdThingListMaterialRelMapper.xml
New file
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.sxkj.gd.implement.mapper.GdThingListMaterialRelMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="gdThingListMaterialRelResultMap" type="org.sxkj.gd.implement.entity.GdThingListMaterialRelEntity">
        <result column="id" property="id"/>
        <result column="implement_list_id" property="implementListId"/>
        <result column="material_id" property="materialId"/>
        <result column="sort" property="sort"/>
        <result column="scenario_config" property="scenarioConfig"/>
        <result column="status" property="status"/>
        <result column="create_user" property="createUser"/>
        <result column="create_dept" property="createDept"/>
        <result column="create_time" property="createTime"/>
        <result column="update_user" property="updateUser"/>
        <result column="update_time" property="updateTime"/>
        <result column="is_deleted" property="isDeleted"/>
    </resultMap>
    <select id="selectGdThingListMaterialRelPage" resultMap="gdThingListMaterialRelResultMap">
        select * from ja_gd_thing_list_material_rel where is_deleted = 0
    </select>
    <select id="exportGdThingListMaterialRel" resultType="org.sxkj.gd.implement.excel.GdThingListMaterialRelExcel">
        SELECT * FROM ja_gd_thing_list_material_rel ${ew.customSqlSegment}
    </select>
</mapper>
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/param/GdImplementListPageParam.java
New file
@@ -0,0 +1,39 @@
package org.sxkj.gd.implement.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * @Description TODO
 * @Author AIX
 * @Date 2026/1/31 11:07
 * @Version 1.0
 */
@Data
public class GdImplementListPageParam implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 事项名称
     */
    @ApiModelProperty(value = "事项名称")
    private String matterName;
    /**
     * 事项编码
     */
    @ApiModelProperty(value = "事项编码")
    private String matterCode;
    /**
     * 所属区划编码
     */
    @ApiModelProperty(value = "所属区划编码")
    private String areaCode;
    @ApiModelProperty(value = "部门集合",hidden = true)
    private List<Long> deptList;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdImplementListService.java
copy from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/service/IGdImplementationListService.java copy to drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdImplementListService.java
File was copied from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/service/IGdImplementationListService.java
@@ -14,31 +14,33 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.service;
package org.sxkj.gd.implement.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implementation.vo.GdImplementationListVO;
import org.sxkj.gd.implementation.excel.GdImplementationListExcel;
import org.sxkj.gd.implement.dto.GdImplementListDTO;
import org.sxkj.gd.implement.entity.GdImplementListEntity;
import org.sxkj.gd.implement.param.GdImplementListPageParam;
import org.sxkj.gd.implement.vo.GdImplementListVO;
import org.sxkj.gd.implement.excel.GdImplementListExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import java.util.List;
/**
 * 实施清单表(实时清单管理) 服务类
 * 实施清单主表 服务类
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
public interface IGdImplementationListService extends BaseService<GdImplementationListEntity> {
public interface IGdImplementListService extends BaseService<GdImplementListEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param gdImplementationList
     * @param gdImplementList
     * @return
     */
    IPage<GdImplementationListVO> selectGdImplementationListPage(IPage<GdImplementationListVO> page, GdImplementationListVO gdImplementationList);
    IPage<GdImplementListVO> selectGdImplementListPage(IPage<GdImplementListVO> page, GdImplementListPageParam gdImplementList);
    /**
@@ -47,6 +49,6 @@
     * @param queryWrapper
     * @return
     */
    List<GdImplementationListExcel> exportGdImplementationList(Wrapper<GdImplementationListEntity> queryWrapper);
    List<GdImplementListExcel> exportGdImplementList(Wrapper<GdImplementListEntity> queryWrapper);
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdMaterialService.java
copy from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/service/IGdImplementationListService.java copy to drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdMaterialService.java
File was copied from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/service/IGdImplementationListService.java
@@ -14,31 +14,32 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.service;
package org.sxkj.gd.implement.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implementation.vo.GdImplementationListVO;
import org.sxkj.gd.implementation.excel.GdImplementationListExcel;
import org.sxkj.gd.implement.dto.GdMaterialDTO;
import org.sxkj.gd.implement.entity.GdMaterialEntity;
import org.sxkj.gd.implement.vo.GdMaterialVO;
import org.sxkj.gd.implement.excel.GdMaterialExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import java.util.List;
/**
 * 实施清单表(实时清单管理) 服务类
 * 材料信息表 服务类
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
public interface IGdImplementationListService extends BaseService<GdImplementationListEntity> {
public interface IGdMaterialService extends BaseService<GdMaterialEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param gdImplementationList
     * @param gdMaterial
     * @return
     */
    IPage<GdImplementationListVO> selectGdImplementationListPage(IPage<GdImplementationListVO> page, GdImplementationListVO gdImplementationList);
    IPage<GdMaterialVO> selectGdMaterialPage(IPage<GdMaterialVO> page, GdMaterialDTO gdMaterial);
    /**
@@ -47,6 +48,6 @@
     * @param queryWrapper
     * @return
     */
    List<GdImplementationListExcel> exportGdImplementationList(Wrapper<GdImplementationListEntity> queryWrapper);
    List<GdMaterialExcel> exportGdMaterial(Wrapper<GdMaterialEntity> queryWrapper);
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/IGdThingListMaterialRelService.java
File was renamed from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/service/IGdImplementationListService.java
@@ -14,31 +14,31 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.service;
package org.sxkj.gd.implement.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implementation.vo.GdImplementationListVO;
import org.sxkj.gd.implementation.excel.GdImplementationListExcel;
import org.sxkj.gd.implement.entity.GdThingListMaterialRelEntity;
import org.sxkj.gd.implement.vo.GdThingListMaterialRelVO;
import org.sxkj.gd.implement.excel.GdThingListMaterialRelExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import java.util.List;
/**
 * 实施清单表(实时清单管理) 服务类
 * 实施清单-材料关联表(情形化配置) 服务类
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
public interface IGdImplementationListService extends BaseService<GdImplementationListEntity> {
public interface IGdThingListMaterialRelService extends BaseService<GdThingListMaterialRelEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param gdImplementationList
     * @param gdThingListMaterialRel
     * @return
     */
    IPage<GdImplementationListVO> selectGdImplementationListPage(IPage<GdImplementationListVO> page, GdImplementationListVO gdImplementationList);
    IPage<GdThingListMaterialRelVO> selectGdThingListMaterialRelPage(IPage<GdThingListMaterialRelVO> page, GdThingListMaterialRelVO gdThingListMaterialRel);
    /**
@@ -47,6 +47,6 @@
     * @param queryWrapper
     * @return
     */
    List<GdImplementationListExcel> exportGdImplementationList(Wrapper<GdImplementationListEntity> queryWrapper);
    List<GdThingListMaterialRelExcel> exportGdThingListMaterialRel(Wrapper<GdThingListMaterialRelEntity> queryWrapper);
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/impl/GdImplementListServiceImpl.java
New file
@@ -0,0 +1,60 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.stereotype.Service;
import org.sxkj.gd.implement.entity.GdImplementListEntity;
import org.sxkj.gd.implement.excel.GdImplementListExcel;
import org.sxkj.gd.implement.mapper.GdImplementListMapper;
import org.sxkj.gd.implement.param.GdImplementListPageParam;
import org.sxkj.gd.implement.service.IGdImplementListService;
import org.sxkj.gd.implement.vo.GdImplementListVO;
import org.sxkj.system.cache.SysCache;
import java.util.List;
/**
 * 实施清单主表 服务实现类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Service
public class GdImplementListServiceImpl extends BaseServiceImpl<GdImplementListMapper, GdImplementListEntity> implements IGdImplementListService {
    @Override
    public IPage<GdImplementListVO> selectGdImplementListPage(IPage<GdImplementListVO> page, GdImplementListPageParam gdImplementList) {
        List<Long> deptList = SysCache.getDeptChildIds(Long.valueOf(AuthUtil.getDeptId()));
        gdImplementList.setDeptList(deptList);
        return page.setRecords(baseMapper.selectGdImplementListPage(page, gdImplementList));
    }
    @Override
    public List<GdImplementListExcel> exportGdImplementList(Wrapper<GdImplementListEntity> queryWrapper) {
        List<GdImplementListExcel> gdImplementListList = baseMapper.exportGdImplementList(queryWrapper);
        //gdImplementListList.forEach(gdImplementList -> {
        //    gdImplementList.setTypeName(DictCache.getValue(DictEnum.YES_NO, GdImplementList.getType()));
        //});
        return gdImplementListList;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/impl/GdMaterialServiceImpl.java
New file
@@ -0,0 +1,55 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.service.impl;
import org.sxkj.gd.implement.dto.GdMaterialDTO;
import org.sxkj.gd.implement.entity.GdMaterialEntity;
import org.sxkj.gd.implement.vo.GdMaterialVO;
import org.sxkj.gd.implement.excel.GdMaterialExcel;
import org.sxkj.gd.implement.mapper.GdMaterialMapper;
import org.sxkj.gd.implement.service.IGdMaterialService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseServiceImpl;
import java.util.List;
/**
 * 材料信息表 服务实现类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Service
public class GdMaterialServiceImpl extends BaseServiceImpl<GdMaterialMapper, GdMaterialEntity> implements IGdMaterialService {
    @Override
    public IPage<GdMaterialVO> selectGdMaterialPage(IPage<GdMaterialVO> page, GdMaterialDTO gdMaterial) {
        return page.setRecords(baseMapper.selectGdMaterialPage(page, gdMaterial));
    }
    @Override
    public List<GdMaterialExcel> exportGdMaterial(Wrapper<GdMaterialEntity> queryWrapper) {
        List<GdMaterialExcel> gdMaterialList = baseMapper.exportGdMaterial(queryWrapper);
        //gdMaterialList.forEach(gdMaterial -> {
        //    gdMaterial.setTypeName(DictCache.getValue(DictEnum.YES_NO, GdMaterial.getType()));
        //});
        return gdMaterialList;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/service/impl/GdThingListMaterialRelServiceImpl.java
New file
@@ -0,0 +1,54 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.service.impl;
import org.sxkj.gd.implement.entity.GdThingListMaterialRelEntity;
import org.sxkj.gd.implement.vo.GdThingListMaterialRelVO;
import org.sxkj.gd.implement.excel.GdThingListMaterialRelExcel;
import org.sxkj.gd.implement.mapper.GdThingListMaterialRelMapper;
import org.sxkj.gd.implement.service.IGdThingListMaterialRelService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseServiceImpl;
import java.util.List;
/**
 * 实施清单-材料关联表(情形化配置) 服务实现类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Service
public class GdThingListMaterialRelServiceImpl extends BaseServiceImpl<GdThingListMaterialRelMapper, GdThingListMaterialRelEntity> implements IGdThingListMaterialRelService {
    @Override
    public IPage<GdThingListMaterialRelVO> selectGdThingListMaterialRelPage(IPage<GdThingListMaterialRelVO> page, GdThingListMaterialRelVO gdThingListMaterialRel) {
        return page.setRecords(baseMapper.selectGdThingListMaterialRelPage(page, gdThingListMaterialRel));
    }
    @Override
    public List<GdThingListMaterialRelExcel> exportGdThingListMaterialRel(Wrapper<GdThingListMaterialRelEntity> queryWrapper) {
        List<GdThingListMaterialRelExcel> gdThingListMaterialRelList = baseMapper.exportGdThingListMaterialRel(queryWrapper);
        //gdThingListMaterialRelList.forEach(gdThingListMaterialRel -> {
        //    gdThingListMaterialRel.setTypeName(DictCache.getValue(DictEnum.YES_NO, GdThingListMaterialRel.getType()));
        //});
        return gdThingListMaterialRelList;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/vo/GdImplementListVO.java
New file
@@ -0,0 +1,102 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty;
import org.sxkj.gd.implement.entity.GdImplementListEntity;
import org.springblade.core.tool.node.INode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * 实施清单主表 视图实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
public class GdImplementListVO implements Serializable {
    private static final long serialVersionUID = 1L;
    @JsonSerialize(
        using = ToStringSerializer.class
    )
    @ApiModelProperty("主键id")
    private Long id;
    /**
     * 事项名称
     */
    @ApiModelProperty(value = "事项名称")
    private String matterName;
    /**
     * 事项编码
     */
    @ApiModelProperty(value = "事项编码")
    private String matterCode;
    /**
     * 所属区划编码
     */
    @ApiModelProperty(value = "所属区划编码")
    private String areaCode;
    /**
     * 所属区划名称
     */
    @ApiModelProperty(value = "所属区划名称")
    private String areaName;
    /**
     * 所属机构编码
     */
    @ApiModelProperty(value = "所属机构编码")
    private String orgCode;
    /**
     * 所属机构名称
     */
    @ApiModelProperty(value = "所属机构名称")
    private String orgName;
    /**
     * 目录编码
     */
    @ApiModelProperty(value = "目录编码")
    private String catalogCode;
    /**
     * 实施编码
     */
    @ApiModelProperty(value = "实施编码")
    private String implementCode;
    /**
     * 实施清单名称
     */
    @ApiModelProperty(value = "实施清单名称")
    private String implementName;
    /**
     * 流程定义主键
     */
    @ApiModelProperty(value = "流程定义主键")
    private String processDefinitionId;
    /**
     * 流程实例主键
     */
    @ApiModelProperty(value = "流程实例主键")
    private String processInstanceId;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/vo/GdMaterialVO.java
New file
@@ -0,0 +1,69 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
 * 材料信息表 视图实体类
 *
 * @author Aix
 * @since 2026-01-31
 */
@Data
public class GdMaterialVO implements Serializable {
    private static final long serialVersionUID = 1L;
    @JsonSerialize(
        using = ToStringSerializer.class
    )
    @ApiModelProperty("主键id")
    private Long id;
    /**
     * 材料名称(列表展示字段)
     */
    @ApiModelProperty(value = "材料名称(列表展示字段)")
    private String materialName;
    /**
     * 必要性:必填/可选/容缺
     */
    @ApiModelProperty(value = "必要性:必填/可选/容缺")
    private String necessity;
    /**
     * 是否适用全部情形:1是 0否
     */
    @ApiModelProperty(value = "是否适用全部情形:1是 0否")
    private Byte isAllScenario;
    /**
     * 材料说明
     */
    @ApiModelProperty(value = "材料说明")
    private String materialDesc;
    /**
     * 区域编码
     */
    @ApiModelProperty(value = "区域编码")
    private String areaCode;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/vo/GdThingListMaterialRelVO.java
File was renamed from drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/vo/GdImplementationListVO.java
@@ -14,23 +14,22 @@
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implementation.vo;
package org.sxkj.gd.implement.vo;
import java.io.Serializable;
import org.sxkj.gd.implementation.entity.GdImplementationListEntity;
import org.sxkj.gd.implement.entity.GdThingListMaterialRelEntity;
import org.springblade.core.tool.node.INode;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 实施清单表(实时清单管理) 视图实体类
 * 实施清单-材料关联表(情形化配置) 视图实体类
 *
 * @author lw
 * @since 2026-01-14
 * @author Aix
 * @since 2026-01-31
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class GdImplementationListVO extends GdImplementationListEntity implements Serializable {
public class GdThingListMaterialRelVO extends GdThingListMaterialRelEntity {
    private static final long serialVersionUID = 1L;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/wrapper/GdImplementListWrapper.java
New file
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.sxkj.gd.implement.entity.GdImplementListEntity;
import org.sxkj.gd.implement.vo.GdImplementListVO;
import java.util.Objects;
/**
 * 实施清单主表 包装类,返回视图层所需的字段
 *
 * @author Aix
 * @since 2026-01-31
 */
public class GdImplementListWrapper extends BaseEntityWrapper<GdImplementListEntity, GdImplementListVO>  {
    public static GdImplementListWrapper build() {
        return new GdImplementListWrapper();
     }
    @Override
    public GdImplementListVO entityVO(GdImplementListEntity gdImplementList) {
        GdImplementListVO gdImplementListVO = Objects.requireNonNull(BeanUtil.copy(gdImplementList, GdImplementListVO.class));
        //User createUser = UserCache.getUser(gdImplementList.getCreateUser());
        //User updateUser = UserCache.getUser(gdImplementList.getUpdateUser());
        //gdImplementListVO.setCreateUserName(createUser.getName());
        //gdImplementListVO.setUpdateUserName(updateUser.getName());
        return gdImplementListVO;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/wrapper/GdMaterialWrapper.java
New file
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.sxkj.gd.implement.entity.GdMaterialEntity;
import org.sxkj.gd.implement.vo.GdMaterialVO;
import java.util.Objects;
/**
 * 材料信息表 包装类,返回视图层所需的字段
 *
 * @author Aix
 * @since 2026-01-31
 */
public class GdMaterialWrapper extends BaseEntityWrapper<GdMaterialEntity, GdMaterialVO>  {
    public static GdMaterialWrapper build() {
        return new GdMaterialWrapper();
     }
    @Override
    public GdMaterialVO entityVO(GdMaterialEntity gdMaterial) {
        GdMaterialVO gdMaterialVO = Objects.requireNonNull(BeanUtil.copy(gdMaterial, GdMaterialVO.class));
        //User createUser = UserCache.getUser(gdMaterial.getCreateUser());
        //User updateUser = UserCache.getUser(gdMaterial.getUpdateUser());
        //gdMaterialVO.setCreateUserName(createUser.getName());
        //gdMaterialVO.setUpdateUserName(updateUser.getName());
        return gdMaterialVO;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implement/wrapper/GdThingListMaterialRelWrapper.java
New file
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.sxkj.gd.implement.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.sxkj.gd.implement.entity.GdThingListMaterialRelEntity;
import org.sxkj.gd.implement.vo.GdThingListMaterialRelVO;
import java.util.Objects;
/**
 * 实施清单-材料关联表(情形化配置) 包装类,返回视图层所需的字段
 *
 * @author Aix
 * @since 2026-01-31
 */
public class GdThingListMaterialRelWrapper extends BaseEntityWrapper<GdThingListMaterialRelEntity, GdThingListMaterialRelVO>  {
    public static GdThingListMaterialRelWrapper build() {
        return new GdThingListMaterialRelWrapper();
     }
    @Override
    public GdThingListMaterialRelVO entityVO(GdThingListMaterialRelEntity gdThingListMaterialRel) {
        GdThingListMaterialRelVO gdThingListMaterialRelVO = Objects.requireNonNull(BeanUtil.copy(gdThingListMaterialRel, GdThingListMaterialRelVO.class));
        //User createUser = UserCache.getUser(gdThingListMaterialRel.getCreateUser());
        //User updateUser = UserCache.getUser(gdThingListMaterialRel.getUpdateUser());
        //gdThingListMaterialRelVO.setCreateUserName(createUser.getName());
        //gdThingListMaterialRelVO.setUpdateUserName(updateUser.getName());
        return gdThingListMaterialRelVO;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/controller/GdImplementationListController.java
File was deleted
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/entity/GdImplementationListEntity.java
File was deleted
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/mapper/GdImplementationListMapper.xml
File was deleted
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/service/impl/GdImplementationListServiceImpl.java
File was deleted
drone-service/drone-gd/src/main/java/org/sxkj/gd/implementation/wrapper/GdImplementationListWrapper.java
File was deleted
drone-service/drone-gd/src/main/java/org/sxkj/gd/orderdata/mapper/GdDataObjectionMapper.xml
@@ -50,7 +50,13 @@
                and do.objection_status = #{param2.objectionStatus}
            </if>
            <if test="param2.deptList != null and param2.deptList.size > 0">
                and do.create_dept in
                and (
                do.create_dept in
                <foreach collection="param2.deptList" item="deptId" open="(" separator="," close=")">
                    #{deptId}
                </foreach>
                )
                or do.apply_target_dept_id in
                <foreach collection="param2.deptList" item="deptId" open="(" separator="," close=")">
                    #{deptId}
                </foreach>
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdWorkOrderFlowController.java
@@ -17,6 +17,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.sxkj.gd.workorder.entity.GdWorkOrderFlowEntity;
import org.sxkj.gd.workorder.vo.GdWorkOrderFlowVO;
import org.sxkj.gd.workorder.vo.WorkOrderStageVO;
import org.sxkj.gd.workorder.excel.GdWorkOrderFlowExcel;
import org.sxkj.gd.workorder.wrapper.GdWorkOrderFlowWrapper;
import org.sxkj.gd.workorder.service.IGdWorkOrderFlowService;
@@ -55,11 +56,28 @@
    }
    /**
     * 流程记录表 列表
     * 返回分层结构的流程数据,包含所有状态(已到达和未到达的)
     *
     * @param gdWorkOrderFlow 查询参数
     * @return 分层结构的流程数据
     */
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "列表", notes = "传入gdWorkOrderFlow")
    public R<List<GdWorkOrderFlowVO>> list(@ApiIgnore @RequestParam Map<String, Object> gdWorkOrderFlow) {
    @ApiOperation(value = "工单流程列表", notes = "传入gdWorkOrderFlow")
    public R<List<WorkOrderStageVO>> list(@ApiIgnore @RequestParam Map<String, Object> gdWorkOrderFlow) {
        // 调用服务层方法获取分层结构的流程数据
        List<WorkOrderStageVO> stages = gdWorkOrderFlowService.getHierarchicalFlow(Condition.getQueryWrapper(gdWorkOrderFlow, GdWorkOrderFlowEntity.class));
        return R.data(stages);
    }
    /**
     * 流程记录表 列表
     */
    @GetMapping("/patrolList")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "巡查流程列表", notes = "传入gdWorkOrderFlow")
    public R<List<GdWorkOrderFlowVO>> patrolList(@ApiIgnore @RequestParam Map<String, Object> gdWorkOrderFlow) {
        List<GdWorkOrderFlowEntity> list = gdWorkOrderFlowService.list(Condition.getQueryWrapper(gdWorkOrderFlow, GdWorkOrderFlowEntity.class));
        return R.data(GdWorkOrderFlowWrapper.build().entityVOList(list));
    }
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdWorkOrderFlowEntity.java
@@ -45,6 +45,17 @@
     */
    @ApiModelProperty(value = "流转描述")
    private String flowDesc;
    /**
     * 流程状态
     */
    @ApiModelProperty(value = "流程状态 1.工单发布,2.接单响应,3.执行中 4.完成待验 5.验收通过 6.结算完成")
    private String flowStatus;
    /**
     * 工单状态
     */
    @ApiModelProperty(value = "工单状态工单状态:0草稿、10发布中_接单中、11发布中_拒绝接单、20响应中_待拆分、21响应中_申请取消、22响应中_申请修改、23响应中_已取消、30执行中_待全部完成、31执行中_协商修改、40完成待验_待全部验收、50验收通过_待结算、60结算完成_已结算")
    private String workStatus;
    /**
     * 关联工单任务表ID/巡查任务ID
     */
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/enums/PatrolTaskStatusEnum.java
@@ -13,13 +13,12 @@
 * @date 2026-01-19
 */
@Getter
@AllArgsConstructor
public enum PatrolTaskStatusEnum {
    /**
     * 待签收
     */
    PENDING_SIGNING("0", "待签收","待签收"),
    PENDING_SIGNING("0", "待签收","巡检任务拆分"),
    /**
     * 拒绝签收
@@ -34,7 +33,7 @@
    /**
     * 待审核
     */
    PENDING_AUDIT("3", "待审核","待审核"),
    PENDING_AUDIT("3", "待审核","待签收"),
    /**
     * 审核驳回
@@ -79,6 +78,18 @@
    @JsonValue
    private final String stageDesc;
    PatrolTaskStatusEnum(String stageDesc) {
        this.value = "";
        this.desc = "";
        this.stageDesc = stageDesc;
    }
    PatrolTaskStatusEnum(String value, String desc, String stageDesc) {
        this.value = value;
        this.desc = desc;
        this.stageDesc = stageDesc;
    }
    /**
     * 根据值获取对应的枚举
     *
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/enums/WorkOrderStatusEnum.java
@@ -2,252 +2,257 @@
/**
 * 工单状态枚举
 *
 * @author lw
 * @since 2026-01-17
 */
public enum WorkOrderStatusEnum {
    /**
     * 工单阶段:工单发布
     */
    STAGE_WORK_ORDER_RELEASE("工单发布"),
    /**
     * 工单阶段:工单发布
     */
    STAGE_WORK_ORDER_RELEASE("工单发布", "1"),
    /**
     * 工单阶段:接单响应
     */
    STAGE_ORDER_RESPONSE("接单响应"),
    /**
     * 工单阶段:接单响应
     */
    STAGE_ORDER_RESPONSE("接单响应", "2"),
    /**
     * 工单阶段:执行中
     */
    STAGE_IN_EXECUTION("执行中"),
    /**
     * 工单阶段:执行中
     */
    STAGE_IN_EXECUTION("执行中", "3"),
    /**
     * 工单阶段:完成待验
     */
    STAGE_COMPLETED_PENDING_INSPECTION("完成待验"),
    /**
     * 工单阶段:完成待验
     */
    STAGE_COMPLETED_PENDING_INSPECTION("完成待验", "4"),
    /**
     * 工单阶段:验收通过
     */
    STAGE_ACCEPTED("验收通过"),
    /**
     * 工单阶段:验收通过
     */
    STAGE_ACCEPTED("验收通过", "5"),
    /**
     * 工单阶段:结算完成
     */
    STAGE_SETTLEMENT_COMPLETED("结算完成"),
    /**
     * 工单阶段:结算完成
     */
    STAGE_SETTLEMENT_COMPLETED("结算完成", "6"),
    // ------------------ 以下是工单状态 ------------------
    // ------------------ 以下是工单状态 ------------------
    /**
     * 草稿
     */
    DRAFT("0", "草稿", null),
    /**
     * 发布中_接单中
     */
    PUBLISHING_ACCEPTING("10", "1", "工单发布_接单中", "接单中"),
    /**
     * 发布中_接单中
     */
    PUBLISHING_ACCEPTING("10", "发布中_接单中", "工单发布"),
    /**
     * 发布中_拒绝接单
     */
    PUBLISHING_REJECTING("11", "1", "工单发布_拒绝接单", "拒绝接单"),
    /**
     * 发布中_拒绝接单
     */
    PUBLISHING_REJECTING("11", "发布中_拒绝接单", "拒绝接单"),
    /**
     * 响应中_待拆分
     */
    RESPONDING_TO_BE_SPLIT("20", "2", "接单响应_待拆分", "待拆分"),
    /**
     * 响应中_待拆分
     */
    RESPONDING_TO_BE_SPLIT("20", "响应中_待拆分", "接单响应"),
    /**
     * 响应中_申请取消
     */
    RESPONDING_APPLY_CANCEL("21", "2", "接单响应_申请取消", "申请取消"),
    /**
     * 响应中_申请取消
     */
    RESPONDING_APPLY_CANCEL("21", "响应中_申请取消", "申请取消"),
    /**
     * 响应中_申请修改
     */
    RESPONDING_APPLY_MODIFY("22", "2", "接单响应_申请修改", "申请修改"),
    /**
     * 响应中_申请修改
     */
    RESPONDING_APPLY_MODIFY("22", "响应中_申请修改", "申请修改"),
    /**
     * 响应中_已取消
     */
    RESPONDING_CANCELED("23", "2", "接单响应_已取消", "已取消"),
    /**
     * 响应中_已取消
     */
    RESPONDING_CANCELED("23", "响应中_已取消", "已取消"),
    /**
     * 执行中_待全部完成
     */
    EXECUTING_TO_BE_COMPLETED("30", "3", "执行中_待全部完成", "待全部完成"),
    /**
     * 响应中_拒绝取消
     */
    // RESPONDING_REJECT_CANCEL("24", "响应中_拒绝取消", "拒绝取消"),
    /**
     * 执行中_协商修改
     */
    EXECUTING_NEGOTIATE_MODIFY("31", "3", "执行中_协商修改", "协商修改"),
    /**
     * 响应中_拒绝修改
     */
    // RESPONDING_REJECT_MODIFY("25", "响应中_拒绝修改", "拒绝修改"),
    /**
     * 完成待验_待全部验收
     */
    COMPLETED_TO_BE_INSPECTED("40", "4", "完成待验_待全部验收", "待全部验收"),
    /**
     * 执行中_待全部完成
     */
    EXECUTING_TO_BE_COMPLETED("30", "执行中_待全部完成", "执行中"),
    /**
     * 验收通过_待结算
     */
    ACCEPTED_TO_BE_SETTLED("50", "5", "验收通过_待结算", "待结算"),
    /**
     * 执行中_协商修改
     */
    EXECUTING_NEGOTIATE_MODIFY("31", "执行中_协商修改", "执行中"),
    /**
     * 结算完成_已结算
     */
    SETTLEMENT_COMPLETED("60", "6", "结算完成_已结算", "已结算");
    /**
     * 完成待验_待全部验收
     */
    COMPLETED_TO_BE_INSPECTED("40", "完成待验_待全部验收", "完成待验"),
    private final String code;
    private final String maxCode;
    private final String desc;
    private final String stageDesc;
    private final boolean isStage;
    /**
     * 验收通过_待结算
     */
    ACCEPTED_TO_BE_SETTLED("50", "验收通过_待结算", "验收通过"),
    /**
     * 工单阶段构造函数
     */
    WorkOrderStatusEnum(String stageDesc, String maxCode) {
        this.code = null;
        this.maxCode = maxCode;
        this.desc = null;
        this.stageDesc = stageDesc;
        this.isStage = true;
    }
    /**
     * 结算完成_已结算
     */
    SETTLEMENT_COMPLETED("60", "结算完成_已结算", "结算完成");
    /**
     * 工单状态构造函数
     */
    WorkOrderStatusEnum(String code, String maxCode, String desc, String stageDesc) {
        this.code = code;
        this.maxCode = maxCode;
        this.desc = desc;
        this.stageDesc = stageDesc;
        this.isStage = false;
    }
    private final String code;
    private final String desc;
    private final String stageDesc;
    private final boolean isStage;
    /**
     * 获取状态码
     *
     * @return 状态码
     */
    public String getCode() {
        return code;
    }
    /**
     * 工单阶段构造函数
     */
    WorkOrderStatusEnum(String stageDesc) {
        this.code = null;
        this.desc = null;
        this.stageDesc = stageDesc;
        this.isStage = true;
    }
    /**
     * 获取状态描述
     *
     * @return 状态描述
     */
    public String getDesc() {
        return desc;
    }
    /**
     * 工单状态构造函数
     */
    WorkOrderStatusEnum(String code, String desc, String stageDesc) {
        this.code = code;
        this.desc = desc;
        this.stageDesc = stageDesc;
        this.isStage = false;
    }
    /**
     * 获取工单阶段描述
     *
     * @return 工单阶段描述
     */
    public String getStageDesc() {
        return stageDesc;
    }
    /**
     * 获取状态码
     * @return 状态码
     */
    public String getCode() {
        return code;
    }
    public String getMaxCode() {
        return maxCode;
    }
    /**
     * 获取状态描述
     * @return 状态描述
     */
    public String getDesc() {
        return desc;
    }
    /**
     * 是否为工单阶段
     *
     * @return 是否为工单阶段
     */
    public boolean isStage() {
        return isStage;
    }
    /**
     * 获取工单阶段描述
     * @return 工单阶段描述
     */
    public String getStageDesc() {
        return stageDesc;
    }
    /**
     * 是否为工单状态
     *
     * @return 是否为工单状态
     */
    public boolean isStatus() {
        return !isStage;
    }
    /**
     * 是否为工单阶段
     * @return 是否为工单阶段
     */
    public boolean isStage() {
        return isStage;
    }
    /**
     * 根据状态码获取枚举对象
     *
     * @param code 状态码
     * @return 枚举对象
     */
    public static WorkOrderStatusEnum getByCode(String code) {
        if (code == null) {
            return null;
        }
        for (WorkOrderStatusEnum status : values()) {
            if (code.equals(status.getCode())) {
                return status;
            }
        }
        return null;
    }
    /**
     * 是否为工单状态
     * @return 是否为工单状态
     */
    public boolean isStatus() {
        return !isStage;
    }
    /**
     * 根据状态码获取状态描述
     *
     * @param code 状态码
     * @return 状态描述
     */
    public static String getDescByCode(String code) {
        WorkOrderStatusEnum status = getByCode(code);
        return status != null ? status.getDesc() : null;
    }
    /**
     * 根据状态码获取枚举对象
     * @param code 状态码
     * @return 枚举对象
     */
    public static WorkOrderStatusEnum getByCode(String code) {
        if (code == null) {
            return null;
        }
        for (WorkOrderStatusEnum status : values()) {
            if (code.equals(status.getCode())) {
                return status;
            }
        }
        return null;
    }
    /**
     * 判断状态码是否有效
     *
     * @param code 状态码
     * @return 是否有效
     */
    public static boolean isValid(String code) {
        return getByCode(code) != null;
    }
    /**
     * 根据状态码获取状态描述
     * @param code 状态码
     * @return 状态描述
     */
    public static String getDescByCode(String code) {
        WorkOrderStatusEnum status = getByCode(code);
        return status != null ? status.getDesc() : null;
    }
    /**
     * 检查当前状态是否允许指定的操作类型
     *
     * @param operationType 操作类型:1接单,2拒接接单,3申请取消,4申请修改, 5同意取消  6不同意取消 7.同意修改 8.不同意修改 9.协商修改 10.同意修改 11.结算
     * @return 是否允许操作
     */
    public boolean isAllowedOperation(Integer operationType) {
        if (operationType == null) {
            return false;
        }
    /**
     * 判断状态码是否有效
     * @param code 状态码
     * @return 是否有效
     */
    public static boolean isValid(String code) {
        return getByCode(code) != null;
    }
    /**
     * 检查当前状态是否允许指定的操作类型
     * @param operationType 操作类型:1接单,2拒接接单,3申请取消,4申请修改, 5同意取消  6不同意取消 7.同意修改 8.不同意修改 9.协商修改 10.同意修改 11.结算
     * @return 是否允许操作
     */
    public boolean isAllowedOperation(Integer operationType) {
        if (operationType == null) {
            return false;
        }
        switch (this) {
            case PUBLISHING_ACCEPTING:
                // 发布中_接单中状态允许:1接单,2拒接接单
                return operationType == 1 || operationType == 2;
            case RESPONDING_TO_BE_SPLIT:
                // 响应中_待拆分状态允许:3申请取消,4申请修改
                return operationType == 3 || operationType == 4 ;
            case RESPONDING_APPLY_CANCEL:
                // 响应中_申请取消状态允许:5同意取消,6不同意取消
                return operationType == 5 || operationType == 6;
            case RESPONDING_APPLY_MODIFY:
                // 响应中_申请修改状态允许:7同意修改,8不同意修改
                return operationType ==7 || operationType == 8 ;
            // case RESPONDING_REJECT_CANCEL:
            //     // 响应中_拒绝取消状态允许:3申请取消
            //     return operationType == 3;
            // case RESPONDING_REJECT_MODIFY:
            //     // 响应中_拒绝修改状态允许:4申请修改
            //     return operationType == 4 || operationType == 3;
        switch (this) {
            case PUBLISHING_ACCEPTING:
                // 发布中_接单中状态允许:1接单,2拒接接单
                return operationType == 1 || operationType == 2;
            case RESPONDING_TO_BE_SPLIT:
                // 响应中_待拆分状态允许:3申请取消,4申请修改
                return operationType == 3 || operationType == 4;
            case RESPONDING_APPLY_CANCEL:
                // 响应中_申请取消状态允许:5同意取消,6不同意取消
                return operationType == 5 || operationType == 6;
            case RESPONDING_APPLY_MODIFY:
                // 响应中_申请修改状态允许:7同意修改,8不同意修改
                return operationType == 7 || operationType == 8;
            // case RESPONDING_REJECT_CANCEL:
            //     // 响应中_拒绝取消状态允许:3申请取消
            //     return operationType == 3;
            // case RESPONDING_REJECT_MODIFY:
            //     // 响应中_拒绝修改状态允许:4申请修改
            //     return operationType == 4 || operationType == 3;
            case ACCEPTED_TO_BE_SETTLED:
                // 验收通过_待结算状态允许:11结算完成
                return operationType == 11;
                return operationType == 11;
            case EXECUTING_TO_BE_COMPLETED:
                // 执行中_待全部完成状态允许:9.协商修改
                return operationType == 9;
            default:
                // 其他状态不允许操作
                return false;
        }
    }
                return operationType == 9;
            case EXECUTING_NEGOTIATE_MODIFY:
                // 执行中_状态状态允许:10.同意协商修改
                return operationType == 10;
            default:
                // 其他状态不允许操作
                return false;
        }
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdWorkOrderFlowService.java
@@ -19,6 +19,7 @@
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import org.sxkj.gd.workorder.entity.GdWorkOrderFlowEntity;
import org.sxkj.gd.workorder.vo.GdWorkOrderFlowVO;
import org.sxkj.gd.workorder.vo.WorkOrderStageVO;
import org.sxkj.gd.workorder.excel.GdWorkOrderFlowExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
@@ -49,4 +50,12 @@
     */
    List<GdWorkOrderFlowExcel> exportGdWorkOrderFlow(Wrapper<GdWorkOrderFlowEntity> queryWrapper);
    /**
     * 获取分层结构的流程数据
     *
     * @param queryWrapper 查询条件
     * @return 分层结构的流程数据
     */
    List<WorkOrderStageVO> getHierarchicalFlow(Wrapper<GdWorkOrderFlowEntity> queryWrapper);
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java
@@ -113,6 +113,11 @@
        return total;
    }
    /**
     * 同步星图无人机设备并入库
     *
     * @return 新增或更新数量
     */
    private int syncPilotDevices() throws Exception {
        R response = jianXingtuApiService.getDevicePilotList(null);
        List<GdXingtuPilotListDTO> items = parseList(response, GdXingtuPilotListDTO.class);
@@ -132,6 +137,11 @@
        return count;
    }
    /**
     * 同步星图机巢设备并入库
     *
     * @return 新增或更新数量
     */
    private int syncAirportDevices() throws Exception {
        R response = jianXingtuApiService.getDeviceAirportList(null);
        List<GdXingtuAirportListDTO> items = parseList(response, GdXingtuAirportListDTO.class);
@@ -151,6 +161,12 @@
        return count;
    }
    /**
     * 按机场ID保存或更新设备信息
     *
     * @param entity 设备信息
     * @return 是否保存成功
     */
    private boolean saveOrUpdateByAirportId(GdManageDeviceEntity entity) throws Exception {
        if (StringUtil.isBlank(entity.getAirportId())) {
            return false;
@@ -173,6 +189,12 @@
        return saveOrUpdateDevice(entity);
    }
    /**
     * 从星图无人机数据构建设备实体
     *
     * @param item 星图无人机数据
     * @return 设备实体
     */
    private GdManageDeviceEntity buildFromPilot(GdXingtuPilotListDTO item) {
        if (item == null) {
            return null;
@@ -192,6 +214,12 @@
        return entity;
    }
    /**
     * 从星图机巢数据构建设备实体
     *
     * @param item 星图机巢数据
     * @return 设备实体
     */
    private GdManageDeviceEntity buildFromAirport(GdXingtuAirportListDTO item) {
        if (item == null) {
            return null;
@@ -212,6 +240,12 @@
        return entity;
    }
    /**
     * 将设备在线状态转换为模式码
     *
     * @param status 状态文本
     * @return 模式码
     */
    private Long parseModeCode(String status) {
        if ("在线".equals(status)) {
            return 0L;
@@ -222,6 +256,12 @@
        return null;
    }
    /**
     * 安全解析字符串为 Double
     *
     * @param value 字符串值
     * @return Double 或 null
     */
    private Double parseDouble(String value) {
        if (StringUtil.isBlank(value)) {
            return null;
@@ -233,6 +273,12 @@
        }
    }
    /**
     * 提取区域编码中的末级编码
     *
     * @param regionCode 区域编码
     * @return 末级区域编码
     */
    private String extractAreaCode(String regionCode) {
        if (StringUtil.isBlank(regionCode)) {
            return null;
@@ -249,6 +295,12 @@
        return regionCode;
    }
    /**
     * 解析保险信息并获取最新保险日期
     *
     * @param insuranceInfo 保险信息JSON
     * @return 保险日期
     */
    private Date parseInsuranceDate(String insuranceInfo) {
        if (StringUtil.isBlank(insuranceInfo)) {
            return null;
@@ -282,6 +334,13 @@
        }
    }
    /**
     * 解析星图接口返回的列表数据
     *
     * @param response 接口响应
     * @param clazz    目标类型
     * @return 列表数据
     */
    private <T> List<T> parseList(R response, Class<T> clazz) {
        if (response == null || !response.isSuccess() || response.getData() == null) {
            return Collections.emptyList();
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdPatrolTaskServiceImpl.java
@@ -67,6 +67,8 @@
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * 巡查任务表 服务实现类
@@ -94,288 +96,304 @@
    private JianXingtuApiService jianXingtuApiService;
    @Autowired
    private IGdManageDeviceService gdManageDeviceService;
    @Override
    public IPage<GdPatrolTaskVO> selectGdPatrolTaskPage(IPage<GdPatrolTaskVO> page, GdPatrolTaskPageParam gdPatrolTask) {
    @Override
    public IPage<GdPatrolTaskVO> selectGdPatrolTaskPage(IPage<GdPatrolTaskVO> page, GdPatrolTaskPageParam gdPatrolTask) {
        List<Long> deptList = SysCache.getDeptChildIds(Long.valueOf(AuthUtil.getDeptId()));
        gdPatrolTask.setDeptList(deptList);
        return page.setRecords(baseMapper.selectGdPatrolTaskPage(page, gdPatrolTask));
    }
        List<GdPatrolTaskVO> gdPatrolTaskVOS = baseMapper.selectGdPatrolTaskPage(page, gdPatrolTask);
        return page.setRecords(gdPatrolTaskVOS);
    }
    @Override
    public List<GdPatrolTaskExcel> exportGdPatrolTask(Wrapper<GdPatrolTaskEntity> queryWrapper) {
        List<GdPatrolTaskExcel> gdPatrolTaskList = baseMapper.exportGdPatrolTask(queryWrapper);
        // gdPatrolTaskList.forEach(gdPatrolTask -> {
        //    gdPatrolTask.setTypeName(DictCache.getValue(DictEnum.YES_NO, GdPatrolTask.getType()));
        //});
        return gdPatrolTaskList;
    }
    @Override
    public List<GdPatrolTaskExcel> exportGdPatrolTask(Wrapper<GdPatrolTaskEntity> queryWrapper) {
        List<GdPatrolTaskExcel> gdPatrolTaskList = baseMapper.exportGdPatrolTask(queryWrapper);
        // gdPatrolTaskList.forEach(gdPatrolTask -> {
        //    gdPatrolTask.setTypeName(DictCache.getValue(DictEnum.YES_NO, GdPatrolTask.getType()));
        //});
        return gdPatrolTaskList;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean savePatrolTask(List<GdPatrolTaskEntity> taskEntityList) {
        // 更新流程节点
        for (GdPatrolTaskEntity gdPatrolTaskEntity : taskEntityList) {
            // 生成巡查任务编号
            if (StringUtils.isBlank(gdPatrolTaskEntity.getTaskNo())) {
                // 使用时间戳生成唯一巡查任务编号
                String timestamp = OrderNumUtils.initOrderNum(WordOrderConstant.PATROL_TASK_KEY);
                gdPatrolTaskEntity.setTaskNo(WordOrderConstant.PATROL_TASK_PREFIX + timestamp);
            }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean savePatrolTask(List<GdPatrolTaskEntity> taskEntityList) {
        // 更新流程节点
        for (GdPatrolTaskEntity gdPatrolTaskEntity : taskEntityList) {
            // 生成巡查任务编号
            if (StringUtils.isBlank(gdPatrolTaskEntity.getTaskNo())) {
                // 使用时间戳生成唯一巡查任务编号
                String timestamp = OrderNumUtils.initOrderNum(WordOrderConstant.PATROL_TASK_KEY);
                gdPatrolTaskEntity.setTaskNo(WordOrderConstant.PATROL_TASK_PREFIX + timestamp);
            }
            // 设置初始状态为待签收(对应流程图:等待接单)
            gdPatrolTaskEntity.setTaskStatus(PatrolTaskStatusEnum.PENDING_SIGNING.getValue());
            // 设置初始状态为待签收(对应流程图:等待接单)
            gdPatrolTaskEntity.setTaskStatus(PatrolTaskStatusEnum.PENDING_SIGNING.getValue());
            // 保存巡逻任务
            boolean save = save(gdPatrolTaskEntity);
            if (!save) {
                // 任务保存失败,抛出异常触发回滚
                throw new RuntimeException("保存巡逻任务失败:" + gdPatrolTaskEntity.toString());
            }
            // 保存巡逻任务
            boolean save = save(gdPatrolTaskEntity);
            if (!save) {
                // 任务保存失败,抛出异常触发回滚
                throw new RuntimeException("保存巡逻任务失败:" + gdPatrolTaskEntity.toString());
            }
            // 保存流转记录(发布任务,等待接单)
            GdWorkOrderFlowEntity gdWorkOrderFlowEntity = new GdWorkOrderFlowEntity();
            gdWorkOrderFlowEntity.setCreateUser(AuthUtil.getUserId());
            gdWorkOrderFlowEntity.setWorkOrderId(gdPatrolTaskEntity.getId());
            gdWorkOrderFlowEntity.setFlowName(PatrolTaskStatusEnum.PENDING_SIGNING.getStageDesc());
            gdWorkOrderFlowEntity.setFlowDesc(AuthUtil.getUserName() + " " + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " 发布任务,等待接单");
            gdWorkOrderFlowEntity.setOperator(AuthUtil.getUserName());
            gdWorkOrderFlowEntity.setType(WorkOrderTypeEnum.PATROL_TASK.getValue());
            gdWorkOrderFlowEntity.setAreaCode(gdPatrolTaskEntity.getAreaCode());
            gdWorkOrderFlowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
            boolean save1 = gdWorkOrderFlowService.save(gdWorkOrderFlowEntity);
            if (!save1) {
                // 流转记录保存失败,抛出异常触发回滚
                throw new RuntimeException("保存流转记录失败:" + gdWorkOrderFlowEntity.toString());
            }
        }
        // 所有任务和流转记录都保存成功
        return true;
    }
    /**
     * 审核巡查任务
     *
     * @param auditParam 审核参数,包含任务ID、审核状态和拒绝原因
     * @return 是否审核成功
     * @throws RuntimeException 当任务不存在、状态不允许转换或操作失败时抛出
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditPatrolTask(GdPatrolTaskAuditParam auditParam) {
        // 1. 获取巡查任务
        GdPatrolTaskEntity task = getById(auditParam.getId());
        if (task == null) {
            throw new RuntimeException("巡查任务不存在");
        }
        // 2. 状态权限校验
        PatrolTaskStatusEnum currentStatus = PatrolTaskStatusEnum.getByValue(task.getTaskStatus());
        Integer auditStatus = auditParam.getAuditStatus();
        if (currentStatus == null || !currentStatus.isAllowedTransition(auditStatus)) {
            throw new RuntimeException("当前任务状态无法进行该操作");
        }
        // 1.同意签收、2.拒绝签收 、3.撤回任务 、4.同意审核、 5.拒绝审核、 6.验收通过、 7.验收拒绝
        // 3. 确定新状态和流转名称
        PatrolTaskStatusEnum newStatusEnum;
        switch (auditStatus) {
            case 1: // 接单
                newStatusEnum = PatrolTaskStatusEnum.PENDING_AUDIT;
                break;
            case 2: // 拒接接单
                newStatusEnum = PatrolTaskStatusEnum.REJECTED_SIGNING;
                break;
            case 3: // 撤回任务
                newStatusEnum = PatrolTaskStatusEnum.WITHDRAWN;
                break;
            case 4: // 同意审核
                newStatusEnum = PatrolTaskStatusEnum.AUDIT_PASSED;
                break;
            case 5: // 拒绝审核
                newStatusEnum = PatrolTaskStatusEnum.AUDIT_REJECTED;
                break;
            case 6: // 验收通过
                newStatusEnum = PatrolTaskStatusEnum.ACCEPTANCE_PASSED;
                break;
            case 7: // 验收拒绝
                newStatusEnum = PatrolTaskStatusEnum.REJECTED_ACCEPTANCE;
                break;
            default: // 无效操作类型
                return false;
        }
        // 4. 更新任务状态
        Date now = new Date();
        task.setTaskStatus(newStatusEnum.getValue());
        task.setUpdateUser(AuthUtil.getUserId());
        task.setUpdateTime(now);
        task.setRejectReason(auditParam.getRejectReason());
        boolean updateResult = updateById(task);
        if (!updateResult) {
            throw new RuntimeException("更新任务状态失败");
        }
        // 5. 保存流转记录
        boolean b = saveWorkOrderFlow(task.getId(), newStatusEnum, auditParam.getRejectReason(), task.getAreaCode());
        // 6. 判断是否审核成功,如果是,需要判断是否整个订单的子任务都审核成功了,除了被撤回和验收拒绝的
        if (auditStatus == 4) {
            //将审核后的任务信息推送到星图
            pushXingtuFlyTask(auditParam.getId());
            // 查询同一个工单下的所有子任务
            List<GdPatrolTaskEntity> subTasks = list(Wrappers.<GdPatrolTaskEntity>lambdaQuery()
                    .eq(GdPatrolTaskEntity::getWorkOrderId, task.getWorkOrderId()));
            // 检查是否所有子任务都审核成功(除了被撤回和验收拒绝的)
            boolean allSubTasksAudited = checkAllSubTasksStatus(subTasks, PatrolTaskStatusEnum.AUDIT_PASSED);
            // 示例:如果所有子任务都审核成功,可以更新工单状态为已完成
            if (allSubTasksAudited) {
                // 执行工单状态更新逻辑
                return updateWorkOrderStatusAndFlow(task.getWorkOrderId(),
                    WorkOrderStatusEnum.EXECUTING_TO_BE_COMPLETED);
            }
        }
        // 7. 验收拒绝
        if (auditStatus == 7) {
            return updateWorkOrderStatusAndFlow(task.getWorkOrderId(),
                WorkOrderStatusEnum.EXECUTING_TO_BE_COMPLETED);
        }
        // 8. 验收通过
        if (auditStatus == 6) {
            // 查询同一个工单下的所有子任务
            List<GdPatrolTaskEntity> subTasks = list(Wrappers.<GdPatrolTaskEntity>lambdaQuery()
                    .eq(GdPatrolTaskEntity::getWorkOrderId, task.getWorkOrderId()));
            // 检查是否所有子任务都验收通过(除了被撤回和验收拒绝的)
            boolean allSubTasksAudited = checkAllSubTasksStatus(subTasks, PatrolTaskStatusEnum.ACCEPTANCE_PASSED);
            // 这里可以根据allSubTasksAudited的结果执行后续逻辑,比如更新工单状态等
            if (allSubTasksAudited) {
                // 1.验收通过,生成报告
                asyncExportPatrolReport(task.getId());
                // 2.执行工单状态更新逻辑
                return updateWorkOrderStatusAndFlow(task.getWorkOrderId(),
                    WorkOrderStatusEnum.ACCEPTED_TO_BE_SETTLED);
            }
        }
        return b;
    }
    /**
     * 检查是否所有子任务都达到指定状态(除了被撤回和验收拒绝的)
     *
     * @param subTasks 子任务列表
     * @param targetStatus 目标状态枚举
     * @return 是否所有子任务都达到指定状态
     */
    private boolean checkAllSubTasksStatus(List<GdPatrolTaskEntity> subTasks, PatrolTaskStatusEnum targetStatus) {
        for (GdPatrolTaskEntity subTask : subTasks) {
            String taskStatus = subTask.getTaskStatus();
            PatrolTaskStatusEnum statusEnum = PatrolTaskStatusEnum.getByValue(taskStatus);
            // 如果任务状态不是目标状态,且不是被撤回和验收拒绝的,则返回false
            if (statusEnum != targetStatus &&
                    statusEnum != PatrolTaskStatusEnum.WITHDRAWN &&
                    statusEnum != PatrolTaskStatusEnum.REJECTED_ACCEPTANCE) {
                return false;
            }
        }
        return true;
    }
    /**
     * 更新工单状态并保存流转记录
     *
     * @param workOrderId 工单ID
     * @param newStatus 新的工单状态枚举
     * @return 是否更新成功
     */
    private boolean updateWorkOrderStatusAndFlow(Long workOrderId, WorkOrderStatusEnum newStatus) {
        // 1. 更新工单状态
        GdWorkOrderEntity gdWorkOrderEntity = new GdWorkOrderEntity();
        gdWorkOrderEntity.setId(workOrderId);
        gdWorkOrderEntity.setWorkOrderStatus(newStatus.getCode());
        Integer updateResult = baseMapper.updateWorkOrderById(gdWorkOrderEntity);
        if (updateResult <= 0) {
            return false;
        }
        // 2. 保存流转记录
        GdWorkOrderFlowEntity flowEntity = new GdWorkOrderFlowEntity();
        flowEntity.setCreateUser(AuthUtil.getUserId());
        flowEntity.setWorkOrderId(workOrderId);
        flowEntity.setFlowName(newStatus.getStageDesc());
        flowEntity.setFlowDesc(String.format("%s %s 更新了任务信息,状态转换为:%s",
            AuthUtil.getUserName(),
            DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"),
            newStatus.getStageDesc()));
        flowEntity.setOperator(AuthUtil.getUserName());
        flowEntity.setType(WorkOrderTypeEnum.WORK_ORDER_TASK.getValue());
        flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
        return gdWorkOrderFlowService.save(flowEntity);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean republishPatrolTask(GdPatrolTaskEntity taskEntity) {
        if (taskEntity == null || taskEntity.getId() == null) {
            throw new RuntimeException("任务信息或ID不能为空");
            // 保存流转记录(发布任务,等待接单)
            GdWorkOrderFlowEntity gdWorkOrderFlowEntity = new GdWorkOrderFlowEntity();
            gdWorkOrderFlowEntity.setCreateUser(AuthUtil.getUserId());
            gdWorkOrderFlowEntity.setWorkOrderId(gdPatrolTaskEntity.getId());
            gdWorkOrderFlowEntity.setFlowName(PatrolTaskStatusEnum.PENDING_SIGNING.getStageDesc());
            gdWorkOrderFlowEntity.setFlowDesc(PatrolTaskStatusEnum.PENDING_SIGNING.getStageDesc());
            gdWorkOrderFlowEntity.setOperator(AuthUtil.getNickName());
            gdWorkOrderFlowEntity.setType(WorkOrderTypeEnum.PATROL_TASK.getValue());
            gdWorkOrderFlowEntity.setAreaCode(gdPatrolTaskEntity.getAreaCode());
            gdWorkOrderFlowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
            boolean save1 = gdWorkOrderFlowService.save(gdWorkOrderFlowEntity);
            if (!save1) {
                // 流转记录保存失败,抛出异常触发回滚
                throw new RuntimeException("保存流转记录失败:" + gdWorkOrderFlowEntity.toString());
            }
        }
        // 1. 验证任务是否存在
        GdPatrolTaskEntity existingTask = getById(taskEntity.getId());
        taskEntity.setId(existingTask.getId());
        if (existingTask == null) {
            throw new RuntimeException("巡查任务不存在");
        }
        // 所有任务和流转记录都保存成功
        return true;
    }
        // 2. 先确定枚举状态:根据当前状态确定新的枚举状态
        PatrolTaskStatusEnum targetStatus;
        String currentStatus = existingTask.getTaskStatus();
        // 1.发布中_拒绝接单 、 4.响应中_审核驳回
        switch (currentStatus) {
            case "1": // 发布中_拒绝接单 → 发布中_接单中
                targetStatus = PatrolTaskStatusEnum.PENDING_SIGNING;
                break;
            case "4": // 响应中_审核驳回 → 响应中_待审核
                targetStatus = PatrolTaskStatusEnum.PENDING_AUDIT;
                break;
            default:
                // 其他状态,保持原有状态
                targetStatus = PatrolTaskStatusEnum.getByValue(currentStatus);
                // 如果无法获取枚举,使用待签收作为默认状态
                if (targetStatus == null) {
                    targetStatus = PatrolTaskStatusEnum.PENDING_SIGNING;
                }
                break;
        }
    /**
     * 审核巡查任务
     *
     * @param auditParam 审核参数,包含任务ID、审核状态和拒绝原因
     * @return 是否审核成功
     * @throws RuntimeException 当任务不存在、状态不允许转换或操作失败时抛出
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditPatrolTask(GdPatrolTaskAuditParam auditParam) {
        // 1. 获取巡查任务
        GdPatrolTaskEntity task = getById(auditParam.getId());
        if (task == null) {
            throw new RuntimeException("巡查任务不存在");
        }
        // 3. 设置任务状态:使用枚举设置任务状态
        taskEntity.setTaskStatus(targetStatus.getValue());
        // 2. 状态权限校验
        PatrolTaskStatusEnum currentStatus = PatrolTaskStatusEnum.getByValue(task.getTaskStatus());
        Integer auditStatus = auditParam.getAuditStatus();
        if (currentStatus == null || !currentStatus.isAllowedTransition(auditStatus)) {
            throw new RuntimeException("当前任务状态无法进行该操作");
        }
        // 1.同意签收、2.拒绝签收 、3.撤回任务 、4.同意审核、 5.拒绝审核、 6.验收通过、 7.验收拒绝
        // 3. 确定新状态和流转名称
        PatrolTaskStatusEnum newStatusEnum;
        switch (auditStatus) {
            case 1: // 接单
                newStatusEnum = PatrolTaskStatusEnum.PENDING_AUDIT;
                break;
            case 2: // 拒接接单
                newStatusEnum = PatrolTaskStatusEnum.REJECTED_SIGNING;
                break;
            case 3: // 撤回任务
                newStatusEnum = PatrolTaskStatusEnum.WITHDRAWN;
                break;
            case 4: // 同意审核
                newStatusEnum = PatrolTaskStatusEnum.AUDIT_PASSED;
                break;
            case 5: // 拒绝审核
                newStatusEnum = PatrolTaskStatusEnum.AUDIT_REJECTED;
                break;
            case 6: // 验收通过
                newStatusEnum = PatrolTaskStatusEnum.ACCEPTANCE_PASSED;
                break;
            case 7: // 验收拒绝
                newStatusEnum = PatrolTaskStatusEnum.REJECTED_ACCEPTANCE;
                break;
            default: // 无效操作类型
                return false;
        }
        // 4. 更新任务信息:合并传入的任务信息
        taskEntity.setUpdateUser(AuthUtil.getUserId());
        taskEntity.setUpdateTime(new Date());
        // 4. 更新任务状态
        Date now = new Date();
        task.setTaskStatus(newStatusEnum.getValue());
        task.setUpdateUser(AuthUtil.getUserId());
        task.setUpdateTime(now);
        task.setRejectReason(auditParam.getRejectReason());
        boolean updateResult = updateById(task);
        if (!updateResult) {
            throw new RuntimeException("更新任务状态失败");
        }
        // 5. 更新数据库
        boolean updateResult = updateById(taskEntity);
        if (!updateResult) {
            throw new RuntimeException("更新任务信息失败");
        }
        // 5. 保存流转记录
        boolean b = saveWorkOrderFlow(task.getId(), newStatusEnum, auditParam.getRejectReason(), task.getAreaCode());
        // 6. 判断是否审核成功,如果是,需要判断是否整个订单的子任务都审核成功了,除了被撤回和验收拒绝的
        if (auditStatus == 4) {
            // 将审核后的任务信息推送到星图
            pushXingtuFlyTask(auditParam.getId());
            // 查询同一个工单下的所有子任务
            List<GdPatrolTaskEntity> subTasks = list(Wrappers.<GdPatrolTaskEntity>lambdaQuery()
                .eq(GdPatrolTaskEntity::getWorkOrderId, task.getWorkOrderId()));
        // 6. 保存流转记录:使用枚举设置flowName
        GdWorkOrderFlowEntity flowEntity = new GdWorkOrderFlowEntity();
        flowEntity.setCreateUser(AuthUtil.getUserId());
        flowEntity.setWorkOrderId(taskEntity.getId());
        flowEntity.setFlowName(targetStatus.getDesc());
        flowEntity.setFlowDesc(AuthUtil.getUserName() + " " + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " 更新了任务信息,状态转换为:" + targetStatus.getDesc());
        flowEntity.setOperator(AuthUtil.getUserName());
        flowEntity.setType(WorkOrderTypeEnum.PATROL_TASK.getValue());
        flowEntity.setAreaCode(existingTask.getAreaCode());
        flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
            // 检查是否所有子任务都审核成功(除了被撤回和验收拒绝的)
            boolean allSubTasksAudited = checkAllSubTasksStatus(subTasks, PatrolTaskStatusEnum.AUDIT_PASSED);
            // 示例:如果所有子任务都审核成功,可以更新工单状态为已完成
            if (allSubTasksAudited) {
                // 执行工单状态更新逻辑
                return updateWorkOrderStatusAndFlow(task.getWorkOrderId(),
                    WorkOrderStatusEnum.EXECUTING_TO_BE_COMPLETED);
            }
        }
        if (auditStatus == 3) {
            // 查询同一个工单下的所有子任务
            List<GdPatrolTaskEntity> subTasks = list(Wrappers.<GdPatrolTaskEntity>lambdaQuery()
                .eq(GdPatrolTaskEntity::getWorkOrderId, task.getWorkOrderId()));
        return gdWorkOrderFlowService.save(flowEntity);
    }
            boolean allSubTasksWithdrawn = subTasks.stream()
                .allMatch(item -> item.getTaskStatus().equals(PatrolTaskStatusEnum.WITHDRAWN.getValue()));
            // 示例:如果所有子任务都审核成功,可以更新工单状态为已完成
            if (allSubTasksWithdrawn) {
                // 执行工单状态更新逻辑
                return updateWorkOrderStatusAndFlow(task.getWorkOrderId(),
                    WorkOrderStatusEnum.RESPONDING_CANCELED);
            }
        }
        // 7. 验收拒绝
        if (auditStatus == 7) {
            return updateWorkOrderStatusAndFlow(task.getWorkOrderId(),
                WorkOrderStatusEnum.EXECUTING_TO_BE_COMPLETED);
        }
        // 8. 验收通过
        if (auditStatus == 6) {
            // 查询同一个工单下的所有子任务
            List<GdPatrolTaskEntity> subTasks = list(Wrappers.<GdPatrolTaskEntity>lambdaQuery()
                .eq(GdPatrolTaskEntity::getWorkOrderId, task.getWorkOrderId()));
            // 检查是否所有子任务都验收通过(除了被撤回和验收拒绝的)
            boolean allSubTasksAudited = checkAllSubTasksStatus(subTasks, PatrolTaskStatusEnum.ACCEPTANCE_PASSED);
            // 这里可以根据allSubTasksAudited的结果执行后续逻辑,比如更新工单状态等
            if (allSubTasksAudited) {
                // 1.验收通过,生成报告
                asyncExportPatrolReport(task.getId());
                // 2.执行工单状态更新逻辑
                return updateWorkOrderStatusAndFlow(task.getWorkOrderId(),
                    WorkOrderStatusEnum.ACCEPTED_TO_BE_SETTLED);
            }
        }
        return b;
    }
    /**
     * 检查是否所有子任务都达到指定状态(除了被撤回和验收拒绝的)
     *
     * @param subTasks     子任务列表
     * @param targetStatus 目标状态枚举
     * @return 是否所有子任务都达到指定状态
     */
    private boolean checkAllSubTasksStatus(List<GdPatrolTaskEntity> subTasks, PatrolTaskStatusEnum targetStatus) {
        for (GdPatrolTaskEntity subTask : subTasks) {
            String taskStatus = subTask.getTaskStatus();
            PatrolTaskStatusEnum statusEnum = PatrolTaskStatusEnum.getByValue(taskStatus);
            // 如果任务状态不是目标状态,且不是被撤回和验收拒绝的,则返回false
            if (statusEnum != targetStatus &&
                statusEnum != PatrolTaskStatusEnum.WITHDRAWN &&
                statusEnum != PatrolTaskStatusEnum.REJECTED_ACCEPTANCE) {
                return false;
            }
        }
        return true;
    }
    /**
     * 更新工单状态并保存流转记录
     *
     * @param workOrderId 工单ID
     * @param newStatus   新的工单状态枚举
     * @return 是否更新成功
     */
    private boolean updateWorkOrderStatusAndFlow(Long workOrderId, WorkOrderStatusEnum newStatus) {
        // 1. 更新工单状态
        GdWorkOrderEntity gdWorkOrderEntity = new GdWorkOrderEntity();
        gdWorkOrderEntity.setId(workOrderId);
        gdWorkOrderEntity.setWorkOrderStatus(newStatus.getCode());
        Integer updateResult = baseMapper.updateWorkOrderById(gdWorkOrderEntity);
        if (updateResult <= 0) {
            return false;
        }
        // 2. 保存流转记录
        GdWorkOrderFlowEntity flowEntity = new GdWorkOrderFlowEntity();
        flowEntity.setCreateUser(AuthUtil.getUserId());
        flowEntity.setWorkOrderId(workOrderId);
        flowEntity.setFlowName(newStatus.getStageDesc());
        flowEntity.setFlowDesc(newStatus.getDesc());
        flowEntity.setOperator(AuthUtil.getNickName());
        flowEntity.setType(WorkOrderTypeEnum.WORK_ORDER_TASK.getValue());
        flowEntity.setFlowStatus(newStatus.getMaxCode());
        flowEntity.setWorkStatus(newStatus.getCode());
        flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
        return gdWorkOrderFlowService.save(flowEntity);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean republishPatrolTask(GdPatrolTaskEntity taskEntity) {
        if (taskEntity == null || taskEntity.getId() == null) {
            throw new RuntimeException("任务信息或ID不能为空");
        }
        // 1. 验证任务是否存在
        GdPatrolTaskEntity existingTask = getById(taskEntity.getId());
        taskEntity.setId(existingTask.getId());
        if (existingTask == null) {
            throw new RuntimeException("巡查任务不存在");
        }
        // 2. 先确定枚举状态:根据当前状态确定新的枚举状态
        PatrolTaskStatusEnum targetStatus;
        String currentStatus = existingTask.getTaskStatus();
        // 1.发布中_拒绝接单 、 4.响应中_审核驳回
        switch (currentStatus) {
            case "1": // 发布中_拒绝接单 → 发布中_接单中
                targetStatus = PatrolTaskStatusEnum.PENDING_SIGNING;
                break;
            case "4": // 响应中_审核驳回 → 响应中_待审核
                targetStatus = PatrolTaskStatusEnum.PENDING_AUDIT;
                break;
            default:
                // 其他状态,保持原有状态
                targetStatus = PatrolTaskStatusEnum.getByValue(currentStatus);
                // 如果无法获取枚举,使用待签收作为默认状态
                if (targetStatus == null) {
                    targetStatus = PatrolTaskStatusEnum.PENDING_SIGNING;
                }
                break;
        }
        // 3. 设置任务状态:使用枚举设置任务状态
        taskEntity.setTaskStatus(targetStatus.getValue());
        // 4. 更新任务信息:合并传入的任务信息
        taskEntity.setUpdateUser(AuthUtil.getUserId());
        taskEntity.setUpdateTime(new Date());
        // 5. 更新数据库
        boolean updateResult = updateById(taskEntity);
        if (!updateResult) {
            throw new RuntimeException("更新任务信息失败");
        }
        // 6. 保存流转记录:使用枚举设置flowName
        GdWorkOrderFlowEntity flowEntity = new GdWorkOrderFlowEntity();
        flowEntity.setCreateUser(AuthUtil.getUserId());
        flowEntity.setWorkOrderId(taskEntity.getId());
        flowEntity.setFlowName(targetStatus.getDesc());
        flowEntity.setFlowDesc(AuthUtil.getNickName() + " " + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " 更新了任务信息,状态转换为:" + targetStatus.getDesc());
        flowEntity.setOperator(AuthUtil.getNickName());
        flowEntity.setType(WorkOrderTypeEnum.PATROL_TASK.getValue());
        flowEntity.setAreaCode(existingTask.getAreaCode());
        flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
        return gdWorkOrderFlowService.save(flowEntity);
    }
    @Override
    public boolean exportPatrolReport(Long patrolTaskId) {
@@ -414,79 +432,60 @@
        }
    }
    /**
     * 检查拒绝原因是否必填
     *
     * @param newStatus     新状态
     * @param rejectReason  拒绝原因
     * @throws RuntimeException 当需要拒绝原因但未提供时抛出
     */
    // private void checkRejectReason(PatrolTaskStatusEnum newStatus, String rejectReason) {
    //     // 拒绝类状态需要填写拒绝原因
    //     if ((newStatus == PatrolTaskStatusEnum.REJECTED_SIGNING ||
    //          newStatus == PatrolTaskStatusEnum.AUDIT_REJECTED ||
    //          newStatus == PatrolTaskStatusEnum.REJECTED_ACCEPTANCE) &&
    //         (rejectReason == null || rejectReason.trim().isEmpty())) {
    //         throw new RuntimeException("拒绝操作时必须填写拒绝原因");
    //     }
    // }
    /**
     * 检查拒绝原因是否必填
     *
     * @param newStatus     新状态
     * @param rejectReason  拒绝原因
     * @throws RuntimeException 当需要拒绝原因但未提供时抛出
     */
    // private void checkRejectReason(PatrolTaskStatusEnum newStatus, String rejectReason) {
    //     // 拒绝类状态需要填写拒绝原因
    //     if ((newStatus == PatrolTaskStatusEnum.REJECTED_SIGNING ||
    //          newStatus == PatrolTaskStatusEnum.AUDIT_REJECTED ||
    //          newStatus == PatrolTaskStatusEnum.REJECTED_ACCEPTANCE) &&
    //         (rejectReason == null || rejectReason.trim().isEmpty())) {
    //         throw new RuntimeException("拒绝操作时必须填写拒绝原因");
    //     }
    // }
    /**
     * 保存工单流转记录
     *
     * @param workOrderId  工单ID
     * @param newStatus    新状态
     * @param rejectReason 拒绝原因
     * @param areaCode     区域编码
     * @return 是否保存成功
     * @throws RuntimeException 当保存失败时抛出
     */
    private boolean saveWorkOrderFlow(Long workOrderId, PatrolTaskStatusEnum newStatus,
                                      String rejectReason, String areaCode) {
        GdWorkOrderFlowEntity flowEntity = new GdWorkOrderFlowEntity();
        flowEntity.setCreateUser(AuthUtil.getUserId());
        flowEntity.setWorkOrderId(workOrderId);
        flowEntity.setFlowName(newStatus.getStageDesc());
    /**
     * 保存工单流转记录
     *
     * @param workOrderId  工单ID
     * @param newStatus    新状态
     * @param rejectReason 拒绝原因
     * @param areaCode     区域编码
     * @return 是否保存成功
     * @throws RuntimeException 当保存失败时抛出
     */
    private boolean saveWorkOrderFlow(Long workOrderId, PatrolTaskStatusEnum newStatus,
                                      String rejectReason, String areaCode) {
        GdWorkOrderFlowEntity flowEntity = new GdWorkOrderFlowEntity();
        flowEntity.setCreateUser(AuthUtil.getUserId());
        flowEntity.setWorkOrderId(workOrderId);
        flowEntity.setFlowName(newStatus.getStageDesc());
        flowEntity.setFlowDesc(newStatus.getStageDesc());
        flowEntity.setOperator(AuthUtil.getNickName());
        flowEntity.setType(WorkOrderTypeEnum.PATROL_TASK.getValue());
        flowEntity.setAreaCode(areaCode);
        flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
        // 构建流转描述
        String flowDesc = buildFlowDesc(newStatus, rejectReason);
        flowEntity.setFlowDesc(flowDesc);
        boolean saveResult = gdWorkOrderFlowService.save(flowEntity);
        if (!saveResult) {
            throw new RuntimeException("保存流转记录失败");
        }
        return true;
    }
        flowEntity.setOperator(AuthUtil.getUserName());
        flowEntity.setType(WorkOrderTypeEnum.PATROL_TASK.getValue());
        flowEntity.setAreaCode(areaCode);
        flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
        boolean saveResult = gdWorkOrderFlowService.save(flowEntity);
        if (!saveResult) {
            throw new RuntimeException("保存流转记录失败");
        }
        return true;
    }
    /**
     * 构建流转描述
     *
     * @param newStatus    新状态
     * @param rejectReason 拒绝原因
     * @return 流转描述
     */
    private String buildFlowDesc(PatrolTaskStatusEnum newStatus, String rejectReason) {
        String baseDesc = String.format("%s %s ",
                AuthUtil.getUserName(),
                DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        // 拒绝类状态需要添加拒绝原因
        if (newStatus == PatrolTaskStatusEnum.REJECTED_SIGNING ||
            newStatus == PatrolTaskStatusEnum.AUDIT_REJECTED ||
            newStatus == PatrolTaskStatusEnum.REJECTED_ACCEPTANCE) {
            return String.format("%s%s:%s", baseDesc, newStatus.getDesc(), rejectReason);
        }
        // 其他状态直接使用枚举描述
        return baseDesc + newStatus.getDesc();
    }
    /**
     * 根据部门ID获取部门名称
     *
     * @param deptId 部门ID
     * @return 部门名称,缺失时返回"/"
     */
    private String getDeptName(Long deptId) {
        if (deptId == null) {
            return "/";
@@ -499,6 +498,12 @@
        return dept.getDeptName();
    }
    /**
     * 根据用户ID获取用户姓名
     *
     * @param userId 用户ID
     * @return 用户姓名,缺失时返回"/"
     */
    private String getUserName(Long userId) {
        if (userId == null) {
            return "/";
@@ -515,6 +520,13 @@
        return StringUtil.isBlank(realName) ? "/" : realName;
    }
    /**
     * 上传巡查报告并保存附件信息
     *
     * @param reportFile 报告文件
     * @param taskEntity 巡查任务
     * @return 是否保存成功
     */
    private boolean saveAttachFile(File reportFile, GdPatrolTaskEntity taskEntity) throws IOException {
        if (reportFile == null || !reportFile.exists()) {
            throw new RuntimeException("巡查报告文件不存在");
@@ -538,6 +550,16 @@
        return true;
    }
    /**
     * 构建附件元数据
     *
     * @param taskEntity  巡查任务
     * @param reportFile  报告文件
     * @param bladeFile   文件上传结果
     * @param resultType  结果类型
     * @param desiredName 期望文件名
     * @return 附件信息
     */
    private Attach buildAttachInfo(GdPatrolTaskEntity taskEntity, File reportFile, BladeFile bladeFile, Integer resultType, String desiredName) {
        Attach attach = new Attach();
        attach.setDomainUrl(bladeFile.getDomain());
@@ -569,6 +591,13 @@
        return attach;
    }
    /**
     * 生成报告附件名称
     *
     * @param taskEntity   巡查任务
     * @param fallbackName 兜底文件名
     * @return 附件名称
     */
    private String buildReportAttachName(GdPatrolTaskEntity taskEntity, String fallbackName) {
        String taskNo = taskEntity != null ? taskEntity.getTaskNo() : null;
        if (StringUtil.isBlank(taskNo)) {
@@ -577,6 +606,12 @@
        return taskNo + ".docx";
    }
    /**
     * 解析巡查任务类型为结果类型
     *
     * @param patrolTaskType 巡查任务类型
     * @return 结果类型
     */
    private Integer parseResultType(String patrolTaskType) {
        if (StringUtil.isBlank(patrolTaskType)) {
            return null;
@@ -607,6 +642,7 @@
    /**
     * 构建巡察任务推送的巡察任务信息
     *
     * @param gdPatrolTaskVO
     * @return
     */
@@ -620,7 +656,7 @@
        if (StringUtil.isNotBlank(gdPatrolTaskVO.getPatrolTaskType())) {
            param.setInspectionType(gdPatrolTaskVO.getPatrolTaskType());
        }
        if ((gdPatrolTaskVO.getId()!=null)) {
        if ((gdPatrolTaskVO.getId() != null)) {
            param.setPatrolTaskld(String.valueOf(gdPatrolTaskVO.getId()));
        }
        param.setTimingType("单次执行");
@@ -650,40 +686,8 @@
            //     param.setAirportId(taskEntity.getAirportId());
            // }
        }
        String status = parseStatus(gdPatrolTaskVO.getTaskStatus());
        if (StringUtil.isNotBlank(status)) {
            param.setStatus(status);
        }
        param.setTaskType("定时执行");
        param.setStatus("待执行");
        param.setTaskType("航线飞行");
        return param;
    }
    private String parseStatus(String taskStatus) {
        if (StringUtil.isBlank(taskStatus)) {
            return null;
        }
        switch (taskStatus) {
            case "0":
                return "待签收";
            case "1":
                return "拒绝签收";
            case "2":
                return "已撤回";
            case "3":
                return "待审核";
            case "4":
                return "审核驳回";
            case "5":
                return "审核通过";
            case "6":
                return "待验收";
            case "7":
                return "拒绝验收";
            case "8":
                return "验收通过";
            default:
                return taskStatus;
        }
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdWorkOrderFlowServiceImpl.java
@@ -16,16 +16,22 @@
 */
package org.sxkj.gd.workorder.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.sxkj.gd.workorder.entity.GdWorkOrderFlowEntity;
import org.sxkj.gd.workorder.vo.GdWorkOrderFlowVO;
import org.sxkj.gd.workorder.vo.WorkOrderStageVO;
import org.sxkj.gd.workorder.vo.WorkOrderStatusDetailVO;
import org.sxkj.gd.workorder.excel.GdWorkOrderFlowExcel;
import org.sxkj.gd.workorder.mapper.GdWorkOrderFlowMapper;
import org.sxkj.gd.workorder.service.IGdWorkOrderFlowService;
import org.sxkj.gd.workorder.enums.WorkOrderStatusEnum;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseServiceImpl;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
/**
 * 流程记录表 服务实现类
@@ -33,6 +39,7 @@
 * @author lw
 * @since 2026-01-14
 */
@Slf4j
@Service
public class GdWorkOrderFlowServiceImpl extends BaseServiceImpl<GdWorkOrderFlowMapper, GdWorkOrderFlowEntity> implements IGdWorkOrderFlowService {
@@ -51,4 +58,183 @@
        return gdWorkOrderFlowList;
    }
    @Override
    public List<WorkOrderStageVO> getHierarchicalFlow(Wrapper<GdWorkOrderFlowEntity> queryWrapper) {
        // 1. 从数据库获取实际流程记录
        List<GdWorkOrderFlowEntity> actualFlows = list(queryWrapper);
        // 2. 构建分层结构
        return buildHierarchicalFlow(actualFlows);
    }
    /**
     * 构建分层结构的流程数据
     *
     * @param actualFlows 实际流程记录
     * @return 分层结构的流程数据
     */
    private List<WorkOrderStageVO> buildHierarchicalFlow(List<GdWorkOrderFlowEntity> actualFlows) {
        List<WorkOrderStageVO> stages = new ArrayList<>();
        // 确定当前阶段代码
        String currentStageCode = "0"; // 默认未开始
        if (actualFlows != null && !actualFlows.isEmpty()) {
            // 获取最后一个流程的状态作为当前阶段
            GdWorkOrderFlowEntity lastFlow = actualFlows.get(actualFlows.size() - 1);
            currentStageCode = lastFlow.getFlowStatus();
        }
        // 3. 遍历所有工单阶段
        // 工单发布阶段
        stages.add(buildStage(WorkOrderStatusEnum.STAGE_WORK_ORDER_RELEASE.getStageDesc(), Arrays.asList(
                WorkOrderStatusEnum.PUBLISHING_ACCEPTING.getStageDesc(),
                WorkOrderStatusEnum.PUBLISHING_REJECTING.getStageDesc()
        ), actualFlows, WorkOrderStatusEnum.STAGE_WORK_ORDER_RELEASE.getMaxCode(), currentStageCode));
        // 接单响应阶段
        stages.add(buildStage(WorkOrderStatusEnum.STAGE_ORDER_RESPONSE.getStageDesc(), Arrays.asList(
                WorkOrderStatusEnum.RESPONDING_TO_BE_SPLIT.getStageDesc(),
                WorkOrderStatusEnum.RESPONDING_APPLY_CANCEL.getStageDesc(),
                WorkOrderStatusEnum.RESPONDING_APPLY_MODIFY.getStageDesc(),
                WorkOrderStatusEnum.RESPONDING_CANCELED.getStageDesc()
        ), actualFlows, WorkOrderStatusEnum.STAGE_ORDER_RESPONSE.getMaxCode(), currentStageCode));
        // 执行中阶段
        stages.add(buildStage(WorkOrderStatusEnum.STAGE_IN_EXECUTION.getStageDesc(), Arrays.asList(
                WorkOrderStatusEnum.EXECUTING_TO_BE_COMPLETED.getStageDesc(),
                WorkOrderStatusEnum.EXECUTING_NEGOTIATE_MODIFY.getStageDesc()
        ), actualFlows, WorkOrderStatusEnum.STAGE_IN_EXECUTION.getMaxCode(), currentStageCode));
        // 完成待验阶段
        stages.add(buildStage(WorkOrderStatusEnum.STAGE_COMPLETED_PENDING_INSPECTION.getStageDesc(), Arrays.asList(
                WorkOrderStatusEnum.COMPLETED_TO_BE_INSPECTED.getStageDesc()
        ), actualFlows, WorkOrderStatusEnum.STAGE_COMPLETED_PENDING_INSPECTION.getMaxCode(), currentStageCode));
        // 验收通过阶段
        stages.add(buildStage(WorkOrderStatusEnum.STAGE_ACCEPTED.getStageDesc(), Arrays.asList(
                WorkOrderStatusEnum.ACCEPTED_TO_BE_SETTLED.getStageDesc()
        ), actualFlows, WorkOrderStatusEnum.STAGE_ACCEPTED.getMaxCode(), currentStageCode));
        // 结算完成阶段
        stages.add(buildStage(WorkOrderStatusEnum.STAGE_SETTLEMENT_COMPLETED.getStageDesc(), Arrays.asList(
                WorkOrderStatusEnum.SETTLEMENT_COMPLETED.getStageDesc()
        ), actualFlows, WorkOrderStatusEnum.STAGE_SETTLEMENT_COMPLETED.getMaxCode(), currentStageCode));
        return stages;
    }
    /**
     * 构建单个阶段的流程数据
     *
     * @param stageName     阶段名称
     * @param statusNames   状态名称列表
     * @param actualFlows   实际流程记录
     * @param flowStatus    流程状态码
     * @param currentStageCode 当前阶段代码
     * @return 阶段流程数据
     */
    private WorkOrderStageVO buildStage(String stageName, List<String> statusNames, List<GdWorkOrderFlowEntity> actualFlows, String flowStatus, String currentStageCode) {
        List<WorkOrderStatusDetailVO> statuses = new ArrayList<>();
        // 检查该阶段是否在当前阶段之后
        // 注意:即使流程回退,之前到达过的阶段仍然需要显示其记录
        // 而是让所有阶段都能显示其已到达的状态,只对未到达的状态进行处理
        // boolean isStageAfterCurrent = false;
        // try {
        //     int stageCode = Integer.parseInt(flowStatus);
        //     int currentCode = Integer.parseInt(currentStageCode);
        //     isStageAfterCurrent = stageCode > currentCode;
        // } catch (NumberFormatException e) {
        //     // 如果转换失败,默认不视为在当前阶段之后
        // }
        // 临时列表,用于收集所有状态详情
        List<WorkOrderStatusDetailVO> tempStatuses = new ArrayList<>();
        // 遍历该阶段的所有状态
        for (String statusName : statusNames) {
            log.info("正在处理状态:{}", statusName);
            // 查找所有对应的实际流程记录
            List<GdWorkOrderFlowEntity> matchingFlows = findMatchingFlows(actualFlows, statusName, flowStatus);
            if (!matchingFlows.isEmpty()) {
                // 对匹配的流程记录按创建时间排序
                matchingFlows.sort((f1, f2) -> {
                    if (f1.getCreateTime() != null && f2.getCreateTime() != null) {
                        return f1.getCreateTime().compareTo(f2.getCreateTime());
                    } else if (f1.getCreateTime() != null) {
                        return -1;
                    } else {
                        return 1;
                    }
                });
                // 为每个排序后的流程记录创建状态详情
                // 无论阶段是否在当前阶段之后,只要有匹配的流程记录,就标记为已到达
                for (GdWorkOrderFlowEntity matchingFlow : matchingFlows) {
                    tempStatuses.add(new WorkOrderStatusDetailVO(
                        statusName,
                    true,
                        matchingFlow.getOperator(),
                        matchingFlow.getCreateTime()
                ));
                }
            } else {
                // 未到达的状态
                // 如果阶段在当前阶段之后,则标记为未到达
                // 如果阶段在当前阶段之前或等于,则也标记为未到达(因为没有匹配的流程记录)
                tempStatuses.add(new WorkOrderStatusDetailVO(statusName));
            }
        }
        // 分离已到达和未到达的状态
        List<WorkOrderStatusDetailVO> reachedStatuses = new ArrayList<>();
        List<WorkOrderStatusDetailVO> unreachedStatuses = new ArrayList<>();
        for (WorkOrderStatusDetailVO status : tempStatuses) {
            if (status.isReached()) {
                reachedStatuses.add(status);
            } else {
                unreachedStatuses.add(status);
            }
        }
        // 对已到达的状态按创建时间排序
        reachedStatuses.sort((s1, s2) -> {
            if (s1.getCreateTime() != null && s2.getCreateTime() != null) {
                return s1.getCreateTime().compareTo(s2.getCreateTime());
            } else if (s1.getCreateTime() != null) {
                return -1;
            } else {
                return 1;
            }
        });
        // 合并已到达和未到达的状态(已到达的在前,未到达的在后)
        statuses.addAll(reachedStatuses);
        statuses.addAll(unreachedStatuses);
        return new WorkOrderStageVO(stageName, statuses);
    }
    /**
     * 查找所有匹配的流程记录
     *
     * @param actualFlows 实际流程记录
     * @param statusName  状态名称
     * @param flowStatus  流程状态码
     * @return 匹配的流程记录列表,没有则返回空列表
     */
    private List<GdWorkOrderFlowEntity> findMatchingFlows(List<GdWorkOrderFlowEntity> actualFlows, String statusName, String flowStatus) {
        List<GdWorkOrderFlowEntity> matchingFlows = new ArrayList<>();
        if (actualFlows != null) {
            for (GdWorkOrderFlowEntity flow : actualFlows) {
                if (flow.getFlowStatus().equals(flowStatus) && flow.getFlowName().equals(statusName)) {
                    matchingFlows.add(flow);
                }
            }
        }
        return matchingFlows;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdWorkOrderServiceImpl.java
@@ -1,6 +1,5 @@
package org.sxkj.gd.workorder.service.impl;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -35,7 +34,6 @@
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
 * 工单任务表 服务实现类
@@ -114,10 +112,6 @@
                    entity.setWorkOrderStatus(WorkOrderStatusEnum.PUBLISHING_ACCEPTING.getCode());
                    newStatusEnum = WorkOrderStatusEnum.PUBLISHING_ACCEPTING;
                    break;
                // case "24": // 响应中_拒绝取消 → 响应中_申请取消
                //     entity.setWorkOrderStatus(WorkOrderStatusEnum.RESPONDING_APPLY_CANCEL.getCode());
                //     newStatusEnum = WorkOrderStatusEnum.RESPONDING_APPLY_CANCEL;
                //     break;
                case "20": // 响应中_待拆分 → 响应中_申请修改
                    entity.setWorkOrderStatus(WorkOrderStatusEnum.RESPONDING_APPLY_MODIFY.getCode());
                    newStatusEnum = WorkOrderStatusEnum.RESPONDING_APPLY_MODIFY;
@@ -126,10 +120,6 @@
                    // 直接生成快照,无需处理geom字段
                    entity.setFullSnapshot(JSON.toJSONString(orderEntity));
                    break;
                // case "25": // 响应中_拒绝修改 → 响应中_申请修改
                //     entity.setWorkOrderStatus(WorkOrderStatusEnum.RESPONDING_APPLY_MODIFY.getCode());
                //     newStatusEnum = WorkOrderStatusEnum.RESPONDING_APPLY_MODIFY;
                //     break;
            }
            saveResult = updateById(entity);
        } else {
@@ -149,9 +139,11 @@
            flowEntity.setCreateUser(AuthUtil.getUserId());
            flowEntity.setWorkOrderId(entity.getId());
            flowEntity.setFlowName(newStatusEnum.getStageDesc());
            flowEntity.setFlowDesc(String.format("%s %s", AuthUtil.getUserName(), org.springblade.core.tool.utils.DateUtil.format(now, "yyyy-MM-dd HH:mm:ss")));
            flowEntity.setOperator(AuthUtil.getUserName());
            flowEntity.setFlowDesc(newStatusEnum.getDesc());
            flowEntity.setOperator(AuthUtil.getNickName());
            flowEntity.setType(WorkOrderTypeEnum.WORK_ORDER_TASK.getValue());
            flowEntity.setFlowStatus(newStatusEnum.getMaxCode());
            flowEntity.setWorkStatus(newStatusEnum.getCode());
            flowEntity.setAreaCode(entity.getAreaCode());
            flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
            return gdWorkOrderFlowService.save(flowEntity);
@@ -243,26 +235,30 @@
        }
        boolean updateResult = updateById(workOrder);
        // 5. 保存流转记录
        // 5. 把待验收的都改为待签收状态
        if (operationType == 10) {
            return gdPatrolTaskService.update(Wrappers.<GdPatrolTaskEntity>lambdaUpdate()
                .set(GdPatrolTaskEntity::getTaskStatus, PatrolTaskStatusEnum.PENDING_SIGNING.getValue())
                .eq(GdPatrolTaskEntity::getWorkOrderId, workOrder.getId())
                .in(GdPatrolTaskEntity::getTaskStatus,
                    PatrolTaskStatusEnum.AUDIT_PASSED.getValue(),
                    PatrolTaskStatusEnum.PENDING_ACCEPTANCE.getValue())
            );
        }
        // 6. 保存流转记录
        if (updateResult) {
            GdWorkOrderFlowEntity flowEntity = new GdWorkOrderFlowEntity();
            flowEntity.setCreateUser(AuthUtil.getUserId());
            flowEntity.setWorkOrderId(workOrder.getId());
            flowEntity.setFlowName(newStatusEnum.getStageDesc());
            flowEntity.setFlowDesc(String.format("%s %s", AuthUtil.getUserName(), org.springblade.core.tool.utils.DateUtil.format(now, CommonConstant.YYYY_MM_DD_HH_MM_SS)));
            flowEntity.setOperator(AuthUtil.getUserName());
            flowEntity.setFlowDesc(newStatusEnum.getDesc());
            flowEntity.setOperator(AuthUtil.getNickName());
            flowEntity.setType(WorkOrderTypeEnum.WORK_ORDER_TASK.getValue());
            flowEntity.setFlowStatus(newStatusEnum.getMaxCode());
            flowEntity.setWorkStatus(newStatusEnum.getCode());
            flowEntity.setAreaCode(workOrder.getAreaCode());
            flowEntity.setCreateDept(Long.valueOf(AuthUtil.getDeptId()));
            return gdWorkOrderFlowService.save(flowEntity);
        }
        // 6. 把待验收的都改为待签收状态
        if (operationType == 10) {
            boolean update = gdPatrolTaskService.update(Wrappers.<GdPatrolTaskEntity>lambdaUpdate()
                .set(GdPatrolTaskEntity::getTaskStatus, PatrolTaskStatusEnum.PENDING_SIGNING.getValue())
                .eq(GdPatrolTaskEntity::getWorkOrderId, workOrder.getId())
                .eq(GdPatrolTaskEntity::getTaskStatus, PatrolTaskStatusEnum.PENDING_ACCEPTANCE.getValue())
            );
        }
        return false;
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/vo/WorkOrderStageVO.java
New file
@@ -0,0 +1,63 @@
package org.sxkj.gd.workorder.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * 工单阶段视图对象
 * 表示工单流程中的一个主阶段,包含该阶段的名称和对应的子状态列表
 *
 * @author lw
 * @since 2026-01-31
 */
@Data
public class WorkOrderStageVO implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 阶段名称
     */
    @ApiModelProperty(value = "阶段名称")
    private String stageName;
    /**
     * 是否已到达该状态
     */
    @ApiModelProperty(value = "是否已到达该状态")
    private boolean reached;
    /**
     * 子状态列表
     */
    @ApiModelProperty(value = "子状态列表")
    private List<WorkOrderStatusDetailVO> child;
    /**
     * 构造函数
     *
     * @param stageName 阶段名称
     * @param child     子状态列表
     */
    public WorkOrderStageVO(String stageName, List<WorkOrderStatusDetailVO> child) {
        this.stageName = stageName;
        this.child = child;
        // 计算阶段的到达状态:如果有任何子状态已到达,则阶段视为已到达
        this.reached = child != null && child.stream().anyMatch(WorkOrderStatusDetailVO::isReached);
    }
    /**
     * 构造函数
     *
     * @param stageName 阶段名称
     * @param child     子状态列表
     * @param reached   是否已到达该阶段
     */
    public WorkOrderStageVO(String stageName, List<WorkOrderStatusDetailVO> child, boolean reached) {
        this.stageName = stageName;
        this.child = child;
        this.reached = reached;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/vo/WorkOrderStatusDetailVO.java
New file
@@ -0,0 +1,72 @@
package org.sxkj.gd.workorder.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * 工单状态详情视图对象
 * 表示工单流程中一个具体状态的详细信息
 *
 * @author lw
 * @since 2026-01-31
 */
@Data
public class WorkOrderStatusDetailVO implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 状态名称
     */
    @ApiModelProperty(value = "状态名称")
    private String statusName;
    /**
     * 是否已到达该状态
     */
    @ApiModelProperty(value = "是否已到达该状态")
    private boolean reached;
    /**
     * 操作人
     */
    @ApiModelProperty(value = "操作人")
    private String operator;
    /**
     * 创建时间
     */
    @ApiModelProperty(value = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;
    /**
     * 构造函数
     *
     * @param statusName 状态名称
     * @param reached    是否已到达
     * @param operator   操作人
     * @param createTime 创建时间
     */
    public WorkOrderStatusDetailVO(String statusName, boolean reached, String operator, Date createTime) {
        this.statusName = statusName;
        this.reached = reached;
        this.operator = operator;
        this.createTime = createTime;
    }
    /**
     * 构造函数(用于未到达的状态)
     *
     * @param statusName 状态名称
     */
    public WorkOrderStatusDetailVO(String statusName) {
        this.statusName = statusName;
        this.reached = false;
        this.operator = null;
        this.createTime = null;
    }
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java
@@ -1,6 +1,7 @@
package org.sxkj.gd.xingtu;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
@@ -23,6 +24,7 @@
 * @Date 2026/1/26 15:22
 * @Version 1.0
 */
@Slf4j
@Service
public class JianXingtuApiService {
@@ -123,9 +125,10 @@
        }
        HttpHeaders headers = new HttpHeaders();
        headers.set("authorization", token);
        log.info("请求外部接口: {} {}", url, body);
        HttpEntity<Object> entity = new HttpEntity<>(body, headers);
        ResponseEntity<R> response = restTemplate.exchange(url, HttpMethod.POST, entity, R.class);
        log.info("响应外部接口: {}", response);
        if (response.getStatusCode().is2xxSuccessful()) {
            R responseBody = response.getBody();
            if (responseBody != null) {
drone-service/drone-system/src/main/java/org/sxkj/system/service/impl/RegionServiceImpl.java
@@ -71,6 +71,33 @@
        if (regionParentCode.startsWith(MAIN_CODE)) {
            region.setParentCode(StringUtil.removePrefix(regionParentCode, MAIN_CODE));
        }
        region.setCityName("吉安市");
        region.setCityCode("360800000000");
        region.setProvinceCode("360000000000");
        region.setProvinceName("江西省");
        if (region.getRegionLevel().equals(DISTRICT_LEVEL)) {
            region.setDistrictCode(region.getCode());
            region.setDistrictName(region.getName());
        }
        if (region.getRegionLevel().equals(TOWN_LEVEL)) {
            String parentCode = region.getParentCode();
            Region byCode = getByCode(parentCode);
            region.setDistrictCode(byCode.getCode());
            region.setDistrictName(byCode.getName());
            region.setTownCode(region.getCode());
            region.setTownName(region.getName());
        }
        if (region.getRegionLevel().equals(VILLAGE_LEVEL)) {
            String parentCode = region.getParentCode();
            Region byCode = getByCode(parentCode);
            region.setTownCode(byCode.getCode());
            region.setTownName(byCode.getName());
            Region byCode2 = getByCode(byCode.getParentCode());
            region.setDistrictCode(byCode2.getCode());
            region.setDistrictName(byCode2.getName());
            region.setVillageCode(region.getCode());
            region.setVillageName(region.getName());
        }
        // 查询是否已存在
        Long cnt = baseMapper.selectCount(Wrappers.<Region>query().lambda().eq(Region::getCode, region.getCode()));
        if (cnt > 0L) {