Browse Source

优化入驻保存-许可证存入相应信息

penghao 1 week ago
parent
commit
09a6f8b516

+ 1 - 1
alien-entity/src/main/java/shop/alien/entity/store/StoreImg.java

@@ -30,7 +30,7 @@ public class StoreImg extends Model<StoreImg> {
     @TableField("store_id")
     private Integer storeId;
 
-    @ApiModelProperty(value = "图片类型, 0:其他, 1:入口图, 2:相册, 3:菜品, 4:环境, 5:价目表, 6:推荐菜, 7:菜单, 8:用户评论, 9:商家申诉,10:商家头像,11:店铺轮播图,12:联名卡图片,13:动态折扣, 14:套餐图片,15:合同照片,17:打卡广场小人图片 18: 商品发布图片 19:二手商品与用户举报图片,20头图单图模式,21头图多图模式 , 22续签合同,23,二手商品记录图片类型, 24 食品经营许可证审核前状态 25.食品经营许可证审核后状态, 28:运动器材设施图片, 29:洗浴设施及服务图片 30 酒水")
+    @ApiModelProperty(value = "图片类型, 0:其他, 1:入口图, 2:相册, 3:菜品, 4:环境, 5:价目表, 6:推荐菜, 7:菜单, 8:用户评论, 9:商家申诉,10:商家头像,11:店铺轮播图,12:联名卡图片,13:动态折扣, 14:营业执照,15:合同照片,17:打卡广场小人图片 18: 二手商品发布图片 19:二手商品与用户举报图片,20头图单图模式,21头图多图模式 , 22续签合同, 23 二手商品记录图片类型, 24 食品经营许可证审核前类型 25.食品经营许可证审核后类型 26.运营活动活动标题图 27.运营活动活动详情图 28.运动设施 29.洗浴设施及服务 30.酒水 31.娱乐经营许可证 32.娱乐经营许可证审核前")
     @TableField("img_type")
     private Integer imgType;
 

+ 1 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreInfo.java

@@ -86,6 +86,7 @@ public class StoreInfo {
 
     @ApiModelProperty(value = "到期时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @TableField("expiration_time")
     private Date expirationTime;
 
     @ApiModelProperty(value = "门店坐标")

+ 79 - 57
alien-store/src/main/java/shop/alien/store/service/StoreInfoService.java

@@ -138,6 +138,13 @@ public interface StoreInfoService extends IService<StoreInfo> {
     StoreInfoVo editStoreInfo(StoreInfoDto storeInfoDto);
 
     /**
+     * 新中台web端修改门店及门店用户
+     *
+     * @return ResponseEntity
+     */
+    StoreInfoVo editNewStoreInfo(StoreInfoDto storeInfoDto);
+
+    /**
      * web端删除门店及门店用户
      *
      * @return ResponseEntity
@@ -177,6 +184,11 @@ public interface StoreInfoService extends IService<StoreInfo> {
     StoreInfoVo getStoreDetail(String storeId, String userId, String jingdu, String weidu);
 
     /**
+     * 中台web端查询门店明细
+     */
+    StoreInfoVo getNewStoreDetail(String storeId);
+
+    /**
      * web端审批结果
      */
     void approveStoreInfo(String storeId, Integer approvalStatus, String reason);
@@ -291,6 +303,52 @@ public interface StoreInfoService extends IService<StoreInfo> {
     int foodLicenceType(int id);
 
     /**
+     * 店铺娱乐经营许可证
+     * @param storeImg
+     * @return
+     */
+    int uploadEntertainmentLicence(StoreImg storeImg);
+
+    /**
+     * 获取店铺娱乐经营许可证状态以及店铺状态为审核中合同图片list
+     * @param id
+     * @return
+     */
+    Map<String,Object> getStoreEntertainmentLicenceStatus(int id);
+
+    /**
+     * 娱乐经营许可证审核通过后 图片类型变为审核通过后 img_type26
+     *
+     */
+    int entertainmentLicenceType(int id);
+
+    /**
+     * 获取门店代金券
+     */
+    List<LifeCouponVo> getStoreCouponList(String storeId);
+
+
+    /**
+     * 获取活动banner图
+     */
+    List<StoreImg> getBannerUrl (String storeId);
+    /**
+     * 获取活动banner图
+     */
+
+    List<StoreImg> getBannerUrlInfo(String storeId, Integer businessId);
+
+
+    /**
+     * web-分页查询店铺信息
+     *
+
+     * @return IPage<StoreInfoVo>
+     */
+    List<StoreInfoVo> getMoreRecommendedStores(Double lon , Double lat, String businessSection, String businessTypes, String businessClassify);
+
+
+    /**
      * 根据门店及图片地址查询最新OCR识别数据
      *
      * @param imageUrl 图片URL
@@ -298,9 +356,6 @@ public interface StoreInfoService extends IService<StoreInfo> {
      */
     Map<String, Object> getStoreOcrData(String imageUrl, String merchantName);
 
-    void aiApproveStoreInfo(AiApproveStoreInfo aiApproveStoreInfo);
-
-
     /**
      * 查询四种类型店铺(酒吧、ktv、洗浴汗蒸、按摩足浴)并按距离筛选
      *
@@ -316,7 +371,10 @@ public interface StoreInfoService extends IService<StoreInfo> {
      */
     IPage<StoreInfoVo> getSpecialTypeStoresByDistance(Double lon, Double lat, Double distance, Integer sortType, Integer businessType, Integer categoryId, int pageNum, int pageSize);
 
-
+    /**
+     * web端查询门店明细
+     */
+    StoreInfoVo getClientStoreDetail(String storeId, String userId, String jingdu, String weidu);
 
     /**
      * 获取休闲娱乐分类数据(主分类和子分类)
@@ -337,6 +395,14 @@ public interface StoreInfoService extends IService<StoreInfo> {
      */
     List<StoreDictionary> getAllBusinessSection(String businessSection);
 
+    /**
+     * 获取门店下三级分类结构
+     * 根据门店ID查询该门店的经营板块、经营种类和分类的三级结构
+     *
+     * @param storeId 门店ID
+     * @return StoreThreeLevelStructureVo 包含门店信息和三级分类树形结构
+     */
+    StoreThreeLevelStructureVo getStoreThreeLevelStructure(Integer storeId);
 
     /**
      * 你可能还喜欢(推荐店铺)
@@ -352,9 +418,16 @@ public interface StoreInfoService extends IService<StoreInfo> {
      */
     List<StoreInfoVo> getRecommendedStores(String businessSection, String businessTypes, String businessClassify, Double lon, Double lat);
 
+    /**
+     * 获取三级分类数据
+     * 根据二级分类ID获取该分类下的三级分类
+     *
+     * @param parentId 二级分类ID
+     * @return List<StoreDictionaryVo> 三级分类列表
+     */
+    List<StoreDictionaryVo> getBusinessClassifyData(Integer parentId);
 
-
-
+    void aiApproveStoreInfo(AiApproveStoreInfo aiApproveStoreInfo);
 
 
     /**
@@ -370,55 +443,4 @@ public interface StoreInfoService extends IService<StoreInfo> {
      * @return R<IPage<StoreInfoVo>> 分页的门店信息列表
      */
     IPage<StoreInfoVo> getLifeServicesByDistance(Double lon, Double lat, Double distance, Integer sortType, Integer businessType, Integer categoryId, int pageNum, int pageSize);
-
-    /**
-     * 获取活动banner图
-     */
-    List<StoreImg> getBannerUrl (String storeId);
-    /**
-     * 获取活动详情banner图
-     */
-
-    List<StoreImg> getBannerUrlInfo(String storeId, Integer businessId);
-
-    /**
-     * web-分页查询店铺信息
-     *
-
-     * @return IPage<StoreInfoVo>
-     */
-    List<StoreInfoVo> getMoreRecommendedStores(Double lon , Double lat, String businessSection, String businessTypes, String businessClassify);
-
-
-    /**
-     * web端查询门店明细
-     */
-    StoreInfoVo getClientStoreDetail(String storeId, String userId, String jingdu, String weidu);
-
-    /**
-     * 获取门店代金券
-     */
-    List<LifeCouponVo> getStoreCouponList(String storeId);
-
-    /**
-     * 中台web端查询门店明细
-     */
-    StoreInfoVo getNewStoreDetail(String storeId);
-
-    /**
-     * 新中台web端修改门店及门店用户
-     *
-     * @return ResponseEntity
-     */
-    StoreInfoVo editNewStoreInfo(StoreInfoDto storeInfoDto);
-
-
-    /**
-     * 根据business_classify字段获取字典表数据实现UI图中的功能
-     *
-     * @param parentId 父分类ID(可选),如果提供则只返回该父分类下的子分类;如果为null则返回所有子分类
-     * @return List<StoreDictionaryVo> 分类列表
-     */
-    List<StoreDictionaryVo> getBusinessClassifyData(Integer parentId);
-
 }

+ 333 - 7
alien-store/src/main/java/shop/alien/store/service/impl/StoreInfoServiceImpl.java

@@ -381,6 +381,7 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         } else if (CommonConstant.FOOD_LICENCE_NOT_EXPIRED_STATUS.equals(foodLicenceWhetherExpiredStatus)) {//经营许可证筛选状态 2 查询食品经营许可证未到期 距离到期时间大于30天以上
             queryWrapper.gt("a.food_licence_expiration_time", nowDay.plusDays(31));
         }
+        //查出所有店铺
         IPage<StoreInfoVo> storeInfoVoPage = storeInfoMapper.getStoreInfoVoPage(iPage, queryWrapper);
         List<StoreInfoVo> records = storeInfoVoPage.getRecords();
         if (!records.isEmpty()) {
@@ -860,6 +861,77 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         if (null == storeInfo.getCommissionRate()) {
             storeInfo.setCommissionRate("3");
         }
+
+        // 处理食品经营许可证OCR数据
+        if (StringUtils.isNotEmpty(storeInfoDto.getFoodLicenceUrl())) {
+            // 查询食品经营许可证OCR识别记录
+            OcrImageUpload foodLicenceOcr = ocrImageUploadMapper.selectOne(
+                    new LambdaQueryWrapper<OcrImageUpload>()
+                            .eq(OcrImageUpload::getImageUrl, storeInfoDto.getFoodLicenceUrl())
+                            .eq(OcrImageUpload::getOcrType, OcrTypeEnum.FOOD_MANAGE_LICENSE.getCode())
+                            .orderByDesc(OcrImageUpload::getCreateTime)
+                            .last("limit 1")
+            );
+            if (foodLicenceOcr != null && StringUtils.isNotEmpty(foodLicenceOcr.getOcrResult())) {
+                try {
+                    com.alibaba.fastjson2.JSONObject ocrResult = com.alibaba.fastjson2.JSONObject.parseObject(foodLicenceOcr.getOcrResult());
+                    // 食品经营许可证OCR字段:validToDate(优先)、standardizedValidToDate
+                    Date expirationTime = parseFoodLicenceExpirationDate(ocrResult);
+                    if (expirationTime != null) {
+                        storeInfo.setFoodLicenceExpirationTime(expirationTime);
+                    }
+                    // 设置食品经营许可证状态为"待审核"(字典值2)
+                    storeInfo.setFoodLicenceStatus(2);
+                    storeInfo.setUpdateFoodLicenceTime(new Date());
+                    log.info("食品经营许可证OCR数据解析成功,到期时间:{}", expirationTime);
+                } catch (Exception e) {
+                    log.error("解析食品经营许可证OCR数据失败", e);
+                    // 解析失败时仍设置状态为待审核
+                    storeInfo.setFoodLicenceStatus(2);
+                    storeInfo.setUpdateFoodLicenceTime(new Date());
+                }
+            } else {
+                // 没有OCR记录时,设置状态为待审核
+                storeInfo.setFoodLicenceStatus(2);
+                storeInfo.setUpdateFoodLicenceTime(new Date());
+            }
+        }
+
+        // 处理娱乐经营许可证OCR数据(复用营业执照OCR类型,数据库中ocr_type存的是BUSINESS_LICENSE)
+        if (StringUtils.isNotEmpty(storeInfoDto.getEntertainmentLicenceUrl())) {
+            // 查询娱乐经营许可证OCR识别记录
+            OcrImageUpload entertainmentLicenceOcr = ocrImageUploadMapper.selectOne(
+                    new LambdaQueryWrapper<OcrImageUpload>()
+                            .eq(OcrImageUpload::getImageUrl, storeInfoDto.getEntertainmentLicenceUrl())
+                            .eq(OcrImageUpload::getOcrType, OcrTypeEnum.BUSINESS_LICENSE.getCode())
+                            .orderByDesc(OcrImageUpload::getCreateTime)
+                            .last("limit 1")
+            );
+            if (entertainmentLicenceOcr != null && StringUtils.isNotEmpty(entertainmentLicenceOcr.getOcrResult())) {
+                try {
+                    com.alibaba.fastjson2.JSONObject ocrResult = com.alibaba.fastjson2.JSONObject.parseObject(entertainmentLicenceOcr.getOcrResult());
+                    // 娱乐经营许可证OCR字段(复用营业执照类型):validToDate(优先,格式"20220903")、validPeriod(格式"2020年09月04日至2022年09月03日")
+                    Date expirationTime = parseEntertainmentLicenceExpirationDate(ocrResult);
+                    if (expirationTime != null) {
+                        storeInfo.setEntertainmentLicenceExpirationTime(expirationTime);
+                    }
+                    // 设置娱乐经营许可证状态为"待审核"(字典值2)
+                    storeInfo.setEntertainmentLicenceStatus(2);
+                    storeInfo.setUpdateEntertainmentLicenceTime(new Date());
+                    log.info("娱乐经营许可证OCR数据解析成功,到期时间:{}", expirationTime);
+                } catch (Exception e) {
+                    log.error("解析娱乐经营许可证OCR数据失败", e);
+                    // 解析失败时仍设置状态为待审核
+                    storeInfo.setEntertainmentLicenceStatus(2);
+                    storeInfo.setUpdateEntertainmentLicenceTime(new Date());
+                }
+            } else {
+                // 没有OCR记录时,设置状态为待审核
+                storeInfo.setEntertainmentLicenceStatus(2);
+                storeInfo.setUpdateEntertainmentLicenceTime(new Date());
+            }
+        }
+
         storeInfoMapper.insert(storeInfo);
         result.setId(storeInfo.getId());
         if (StringUtils.isNotEmpty(storeInfoDto.getStorePositionLongitude()) && StringUtils.isNotEmpty(storeInfoDto.getStorePositionLatitude())) {
@@ -1061,7 +1133,7 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         storeInfo.setBusinessSectionName(businessSectionName.getDictDetail());
         storeInfo.setBusinessTypes(String.join(",", businessTypes));
         storeInfo.setBusinessTypesName(String.join(",", businessTypeNames));
-
+        
         //处理分类信息
         List<String> businessClassify = storeInfoDto.getBusinessClassify();
         if (!CollectionUtils.isEmpty(businessClassify)) {
@@ -1092,7 +1164,7 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
             storeInfo.setBusinessClassify(String.join(",", businessClassify));
             storeInfo.setBusinessClassifyName(String.join(",", businessClassifyNames));
         }
-
+        
         //处理一下行政区域信息
         EssentialCityCode essentialCityCode1 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfo.getAdministrativeRegionProvinceAdcode()));
         storeInfo.setAdministrativeRegionProvinceName(essentialCityCode1.getAreaName());
@@ -2131,12 +2203,18 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
     }
 
     /**
-     * 根据过期时间修改状态
+     * 检查并更新过期记录
+     * 将过期时间已到且业务状态为0的店铺状态更新为99(过期状态)
+     *
+     * @return 更新的记录数
      */
-    public void checkAndUpdateExpiredRecords() {
-        LambdaUpdateWrapper<StoreInfo> queryWrapper = new LambdaUpdateWrapper<>();
-        queryWrapper.isNotNull(StoreInfo::getExpirationTime).lt(StoreInfo::getExpirationTime, LocalDateTime.now()).eq(StoreInfo::getBusinessStatus, 0).set(StoreInfo::getBusinessStatus, 99);
-        this.update(queryWrapper);
+    public int checkAndUpdateExpiredRecords() {
+        LambdaUpdateWrapper<StoreInfo> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.isNotNull(StoreInfo::getExpirationTime)
+                .lt(StoreInfo::getExpirationTime, LocalDateTime.now())
+                .eq(StoreInfo::getBusinessStatus, 0)
+                .set(StoreInfo::getStoreStatus, 0);
+        return storeInfoMapper.update(null, updateWrapper);
     }
 
     @Override
@@ -2539,6 +2617,31 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         storeInfo.setFoodLicenceStatus(2);
         storeInfo.setId(storeImg.getStoreId());
         storeInfo.setUpdateFoodLicenceTime(new Date());
+
+        // 从OCR识别记录中获取食品经营许可证到期时间
+        if (StringUtils.isNotEmpty(storeImg.getImgUrl())) {
+            OcrImageUpload foodLicenceOcr = ocrImageUploadMapper.selectOne(
+                    new LambdaQueryWrapper<OcrImageUpload>()
+                            .eq(OcrImageUpload::getImageUrl, storeImg.getImgUrl())
+                            .eq(OcrImageUpload::getOcrType, OcrTypeEnum.FOOD_MANAGE_LICENSE.getCode())
+                            .orderByDesc(OcrImageUpload::getCreateTime)
+                            .last("limit 1")
+            );
+            if (foodLicenceOcr != null && StringUtils.isNotEmpty(foodLicenceOcr.getOcrResult())) {
+                try {
+                    com.alibaba.fastjson2.JSONObject ocrResult = com.alibaba.fastjson2.JSONObject.parseObject(foodLicenceOcr.getOcrResult());
+                    // 解析食品经营许可证到期时间(优先validToDate,其次standardizedValidToDate)
+                    Date expirationTime = parseFoodLicenceExpirationDate(ocrResult);
+                    if (expirationTime != null) {
+                        storeInfo.setFoodLicenceExpirationTime(expirationTime);
+                        log.info("食品经营许可证OCR数据解析成功,门店ID:{},到期时间:{}", storeImg.getStoreId(), expirationTime);
+                    }
+                } catch (Exception e) {
+                    log.error("解析食品经营许可证OCR数据失败,门店ID:{}", storeImg.getStoreId(), e);
+                }
+            }
+        }
+
         return storeInfoMapper.updateById(storeInfo);
     }
 
@@ -4300,6 +4403,229 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
         // SQL已经实现了距离过滤和排序,直接返回结果
         return storeInfoVoList;
     }
+    @Override
+    public int uploadEntertainmentLicence(StoreImg storeImg) {
+        storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 24).eq(StoreImg::getStoreId, storeImg.getStoreId()));
+        storeImg.setImgType(24);
+        storeImg.setImgDescription("娱乐经营许可证审核通过前图片");
+        storeImgMapper.insert(storeImg);
+
+        //更新店铺
+        StoreInfo storeInfo = new StoreInfo();
+        storeInfo.setEntertainmentLicenceStatus(2);
+        storeInfo.setId(storeImg.getStoreId());
+        storeInfo.setUpdateEntertainmentLicenceTime(new Date());
+
+        // 从OCR识别记录中获取娱乐经营许可证到期时间(复用营业执照OCR类型,数据库中ocr_type存的是BUSINESS_LICENSE)
+        if (StringUtils.isNotEmpty(storeImg.getImgUrl())) {
+            OcrImageUpload entertainmentLicenceOcr = ocrImageUploadMapper.selectOne(
+                    new LambdaQueryWrapper<OcrImageUpload>()
+                            .eq(OcrImageUpload::getImageUrl, storeImg.getImgUrl())
+                            .eq(OcrImageUpload::getOcrType, OcrTypeEnum.BUSINESS_LICENSE.getCode())
+                            .orderByDesc(OcrImageUpload::getCreateTime)
+                            .last("limit 1")
+            );
+            if (entertainmentLicenceOcr != null && StringUtils.isNotEmpty(entertainmentLicenceOcr.getOcrResult())) {
+                try {
+                    com.alibaba.fastjson2.JSONObject ocrResult = com.alibaba.fastjson2.JSONObject.parseObject(entertainmentLicenceOcr.getOcrResult());
+                    // 解析娱乐经营许可证到期时间(优先validToDate,其次validPeriod)
+                    Date expirationTime = parseEntertainmentLicenceExpirationDate(ocrResult);
+                    if (expirationTime != null) {
+                        storeInfo.setEntertainmentLicenceExpirationTime(expirationTime);
+                        log.info("娱乐经营许可证OCR数据解析成功,门店ID:{},到期时间:{}", storeImg.getStoreId(), expirationTime);
+                    }
+                } catch (Exception e) {
+                    log.error("解析娱乐经营许可证OCR数据失败,门店ID:{}", storeImg.getStoreId(), e);
+                }
+            }
+        }
+
+        return storeInfoMapper.updateById(storeInfo);
+    }
+
+    @Override
+    public Map<String, Object> getStoreEntertainmentLicenceStatus(int id) {
+        Map<String, Object> map = new HashMap<>();
+        StoreInfo storeInfo = storeInfoMapper.selectOne(new LambdaQueryWrapper<StoreInfo>().eq(StoreInfo::getId, id));
+        //审核通过给前台反显未提交
+        if (storeInfo.getEntertainmentLicenceStatus() == 1) {
+            map.put("entertainmentLicenceStatus", 0);
+        } else {
+            map.put("entertainmentLicenceStatus", storeInfo.getEntertainmentLicenceStatus());
+        }
+        //娱乐经营许可证照片列表
+        List<StoreImg> storeImgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, id).eq(StoreImg::getImgType, 24));
+        if (!CollectionUtils.isEmpty(storeImgList)) {
+            map.put("entertainmentLicenceImgList", storeImgList);
+        } else {
+            map.put("entertainmentLicenceImgList", "");
+        }
+        if (storeInfo.getEntertainmentLicenceReason() != null) {
+            map.put("entertainmentLicenceReason", storeInfo.getEntertainmentLicenceReason());
+        } else {
+            map.put("entertainmentLicenceReason", "");
+        }
+        return map;
+    }
+
+    @Override
+    public int entertainmentLicenceType(int id) {
+        //删除原娱乐经营许可证照片
+        LambdaUpdateWrapper<StoreImg> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+        lambdaUpdateWrapper.eq(StoreImg::getStoreId, id);
+        lambdaUpdateWrapper.eq(StoreImg::getImgType, 26);
+        lambdaUpdateWrapper.set(StoreImg::getDeleteFlag, 1);
+        storeImgMapper.update(null, lambdaUpdateWrapper);
+        //修改娱乐经营许可证类型为审核通过类型
+        List<StoreImg> storeImgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, id).eq(StoreImg::getImgType, 24));
+        List<Integer> imgList = storeImgList.stream().map(StoreImg::getId).collect(Collectors.toList());
+        LambdaUpdateWrapper<StoreImg> imgLambdaUpdateWrapper = new LambdaUpdateWrapper();
+        imgLambdaUpdateWrapper.in(StoreImg::getId, imgList).set(StoreImg::getImgType, 26).set(StoreImg::getImgDescription, "娱乐经营许可证审核通过图片");
+        int num = storeImgMapper.update(null, imgLambdaUpdateWrapper);
+        return num;
+    }
+
+    /**
+     * 解析食品经营许可证OCR结果中的到期时间
+     * 食品经营许可证OCR返回字段:validToDate、standardizedValidToDate
+     *
+     * @param ocrResult OCR识别结果JSON对象
+     * @return 到期日期,如果解析失败则返回null
+     */
+    private Date parseFoodLicenceExpirationDate(com.alibaba.fastjson2.JSONObject ocrResult) {
+        if (ocrResult == null) {
+            return null;
+        }
+
+        // 优先使用validToDate字段(格式可能为空或yyyyMMdd)
+        String validToDate = ocrResult.getString("validToDate");
+        if (StringUtils.isNotEmpty(validToDate)) {
+            Date date = parseDateString(validToDate);
+            if (date != null) {
+                return date;
+            }
+        }
+
+        // 其次使用standardizedValidToDate字段
+        String standardizedValidToDate = ocrResult.getString("standardizedValidToDate");
+        if (StringUtils.isNotEmpty(standardizedValidToDate)) {
+            Date date = parseDateString(standardizedValidToDate);
+            if (date != null) {
+                return date;
+            }
+        }
+
+        log.warn("食品经营许可证OCR结果中未找到有效的到期时间,validToDate={},standardizedValidToDate={}", validToDate, standardizedValidToDate);
+        return null;
+    }
+
+    /**
+     * 解析娱乐经营许可证OCR结果中的到期时间(复用营业执照OCR类型)
+     * 娱乐经营许可证OCR返回字段:validToDate(格式"20220903")、validPeriod(格式"2020年09月04日至2022年09月03日")
+     *
+     * @param ocrResult OCR识别结果JSON对象
+     * @return 到期日期,如果解析失败则返回null
+     */
+    private Date parseEntertainmentLicenceExpirationDate(com.alibaba.fastjson2.JSONObject ocrResult) {
+        if (ocrResult == null) {
+            return null;
+        }
+
+        // 优先使用validToDate字段(格式为yyyyMMdd,如"20220903")
+        String validToDate = ocrResult.getString("validToDate");
+        if (StringUtils.isNotEmpty(validToDate)) {
+            Date date = parseDateString(validToDate);
+            if (date != null) {
+                return date;
+            }
+        }
+
+        // 其次使用validPeriod字段(格式为"2020年09月04日至2022年09月03日")
+        String validPeriod = ocrResult.getString("validPeriod");
+        if (StringUtils.isNotEmpty(validPeriod)) {
+            Date date = parseValidPeriodEndDate(validPeriod);
+            if (date != null) {
+                return date;
+            }
+        }
+
+        log.warn("娱乐经营许可证OCR结果中未找到有效的到期时间,validToDate={},validPeriod={}", validToDate, validPeriod);
+        return null;
+    }
+
+    /**
+     * 解析日期字符串
+     * 支持的格式:yyyyMMdd、yyyy-MM-dd、yyyy/MM/dd、yyyy年MM月dd日
+     *
+     * @param dateStr 日期字符串
+     * @return 日期对象,如果解析失败则返回null
+     */
+    private Date parseDateString(String dateStr) {
+        if (StringUtils.isEmpty(dateStr)) {
+            return null;
+        }
+
+        // 处理"长期"或"永久"情况
+        if (dateStr.contains("长期") || dateStr.contains("永久")) {
+            return null;
+        }
+
+        String normalizedDateStr = dateStr.trim();
+
+        // 如果包含中文年月日,转换格式
+        if (normalizedDateStr.contains("年")) {
+            normalizedDateStr = normalizedDateStr.replaceAll("[年月]", "-").replaceAll("日", "").trim();
+        }
+
+        // 尝试多种日期格式解析
+        String[] dateFormats = {"yyyyMMdd", "yyyy-MM-dd", "yyyy/MM/dd"};
+        for (String format : dateFormats) {
+            try {
+                SimpleDateFormat sdf = new SimpleDateFormat(format);
+                sdf.setLenient(false);
+                return sdf.parse(normalizedDateStr);
+            } catch (Exception ignored) {
+                // 尝试下一个格式
+            }
+        }
+
+        log.warn("无法解析日期字符串: {}", dateStr);
+        return null;
+    }
+
+    /**
+     * 解析有效期字符串,获取结束日期
+     * 支持的格式:
+     * - "2020年09月04日至2022年09月03日"
+     * - "2020-01-01至2025-12-31"
+     * - "长期" 或 "永久" 返回null(表示长期有效)
+     *
+     * @param validPeriod 有效期字符串
+     * @return 结束日期,如果解析失败或为长期有效则返回null
+     */
+    private Date parseValidPeriodEndDate(String validPeriod) {
+        if (StringUtils.isEmpty(validPeriod)) {
+            return null;
+        }
+
+        // 处理"长期"或"永久"情况
+        if (validPeriod.contains("长期") || validPeriod.contains("永久")) {
+            return null;
+        }
+
+        String endDateStr = validPeriod;
+
+        // 如果包含"至",取后半部分作为结束日期
+        if (validPeriod.contains("至")) {
+            String[] parts = validPeriod.split("至");
+            if (parts.length >= 2) {
+                endDateStr = parts[1].trim();
+            }
+        }
+
+        return parseDateString(endDateStr);
+    }
+}
 
 
     @Override