diff --git a/src/main/java/com/ycwl/basic/controller/mobile/AppGoodsController.java b/src/main/java/com/ycwl/basic/controller/mobile/AppGoodsController.java index bc1d732..c3af24f 100644 --- a/src/main/java/com/ycwl/basic/controller/mobile/AppGoodsController.java +++ b/src/main/java/com/ycwl/basic/controller/mobile/AppGoodsController.java @@ -40,6 +40,13 @@ public class AppGoodsController { return ApiResponse.success(goodsDetailVOS); } + @ApiOperation("源素材(原片/照片)商品数量") + @PostMapping("/sourceGoodsCount") + public ApiResponse sourceGoodsCount(@RequestBody GoodsReqQuery query) { + Integer count = goodsService.sourceGoodsCount(query); + return ApiResponse.success(count); + } + @PostMapping("/sourceGoodsList/preview") public ApiResponse> sourceGoodsListPreview(@RequestBody GoodsReqQuery query) { List goodsUrlList = goodsService.sourceGoodsListPreview(query); diff --git a/src/main/java/com/ycwl/basic/controller/viid/ViidController.java b/src/main/java/com/ycwl/basic/controller/viid/ViidController.java index c3fa914..476b714 100644 --- a/src/main/java/com/ycwl/basic/controller/viid/ViidController.java +++ b/src/main/java/com/ycwl/basic/controller/viid/ViidController.java @@ -97,8 +97,8 @@ public class ViidController { .setNamePrefix("VIID-" + scenicId + "-t") .build(); return new ThreadPoolExecutor( - 4, 4096, 0L, TimeUnit.MILLISECONDS, - new ArrayBlockingQueue<>(4096), + 4, 1024, 0L, TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(1024), threadFactory); }); } diff --git a/src/main/java/com/ycwl/basic/facebody/adapter/AliFaceBodyAdapter.java b/src/main/java/com/ycwl/basic/facebody/adapter/AliFaceBodyAdapter.java index c856fb7..c902545 100644 --- a/src/main/java/com/ycwl/basic/facebody/adapter/AliFaceBodyAdapter.java +++ b/src/main/java/com/ycwl/basic/facebody/adapter/AliFaceBodyAdapter.java @@ -109,6 +109,7 @@ public class AliFaceBodyAdapter implements IFaceBodyAdapter { IRateLimiter deleteEntityLimiter = getLimiter(LOCK_TYPE.DELETE_ENTITY); IRateLimiter deleteDbLimiter = getLimiter(LOCK_TYPE.DELETE_DB); request.setDbName(dbName); + request.setOrder("asc"); request.setLimit(200); try (ClientWrapper clientWrapper = getClient()) { IAcsClient client = clientWrapper.getClient(); diff --git a/src/main/java/com/ycwl/basic/mapper/SourceMapper.java b/src/main/java/com/ycwl/basic/mapper/SourceMapper.java index b9e2240..265ca85 100644 --- a/src/main/java/com/ycwl/basic/mapper/SourceMapper.java +++ b/src/main/java/com/ycwl/basic/mapper/SourceMapper.java @@ -51,6 +51,7 @@ public interface SourceMapper { int addRelation(MemberSourceEntity source); List listUser(SourceReqQuery sourceReqQuery); + Integer countUser(SourceReqQuery sourceReqQuery); SourceRespVO listUserOne(Long userId, Long sourceId); int addRelations(List list); diff --git a/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java b/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java index 74783f5..2d8bafd 100644 --- a/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java +++ b/src/main/java/com/ycwl/basic/model/pc/scenic/entity/ScenicConfigEntity.java @@ -91,4 +91,6 @@ public class ScenicConfigEntity { private String imageSourcePackHint; private String videoSourcePackHint; + + private String extraNotificationTime; } diff --git a/src/main/java/com/ycwl/basic/model/pc/source/resp/SourceRespVO.java b/src/main/java/com/ycwl/basic/model/pc/source/resp/SourceRespVO.java index 90572c6..102e343 100644 --- a/src/main/java/com/ycwl/basic/model/pc/source/resp/SourceRespVO.java +++ b/src/main/java/com/ycwl/basic/model/pc/source/resp/SourceRespVO.java @@ -45,6 +45,6 @@ public class SourceRespVO { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date createTime; @ApiModelProperty("是否购买:0未购买,1已购买") - private Integer isBuy; - private Integer isFree; + private int isBuy; + private int isFree; } diff --git a/src/main/java/com/ycwl/basic/service/mobile/GoodsService.java b/src/main/java/com/ycwl/basic/service/mobile/GoodsService.java index 2755698..3ef19c8 100644 --- a/src/main/java/com/ycwl/basic/service/mobile/GoodsService.java +++ b/src/main/java/com/ycwl/basic/service/mobile/GoodsService.java @@ -48,4 +48,6 @@ public interface GoodsService { List sourceGoodsListPreview(GoodsReqQuery query); List sourceGoodsListDownload(GoodsReqQuery query); + + Integer sourceGoodsCount(GoodsReqQuery query); } diff --git a/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java b/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java index 0f3a4fc..fd43f9e 100644 --- a/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.extra.qrcode.QrCodeUtil; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.ycwl.basic.biz.OrderBiz; import com.ycwl.basic.biz.TaskStatusBiz; @@ -199,6 +200,8 @@ public class GoodsServiceImpl implements GoodsService { goodsDetailVO.setScenicName(sourceRespVO.getScenicName()); goodsDetailVO.setGoodsType(sourceType); goodsDetailVO.setGoodsId(sourceRespVO.getId()); + goodsDetailVO.setIsFree(sourceRespVO.getIsFree()); + goodsDetailVO.setIsBuy(sourceRespVO.getIsBuy()); if (sourceRespVO.getVideoUrl() != null) { try { URL url = new URL(sourceRespVO.getVideoUrl()); @@ -278,9 +281,14 @@ public class GoodsServiceImpl implements GoodsService { paramJson.entrySet().stream() .filter(entry -> StringUtils.isNumeric(entry.getKey())) .forEach(entry -> { - if (templatePlaceholder.contains(entry.getKey())) { - deviceCount.getAndIncrement(); - templatePlaceholder.remove(entry.getKey()); + JSONArray jsonArray = paramJson.getJSONArray(entry.getKey()); + if (jsonArray != null && !jsonArray.isEmpty()) { + for (Object ignored : jsonArray) { + if (templatePlaceholder.contains(entry.getKey())) { + deviceCount.getAndIncrement(); + templatePlaceholder.remove(entry.getKey()); + } + } } }); } @@ -573,14 +581,9 @@ public class GoodsServiceImpl implements GoodsService { if (face == null) { return Collections.emptyList(); } - IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), query.getScenicId(), query.getSourceType(), query.getFaceId()); - if (!isBuy.isBuy()) { - return Collections.emptyList(); - } Integer sourceType = query.getSourceType(); SourceReqQuery sourceReqQuery = new SourceReqQuery(); - sourceReqQuery.setScenicId(query.getScenicId()); - sourceReqQuery.setIsBuy(query.getIsBuy()); + sourceReqQuery.setScenicId(face.getScenicId()); sourceReqQuery.setMemberId(face.getMemberId()); sourceReqQuery.setType(sourceType); sourceReqQuery.setFaceId(query.getFaceId()); @@ -598,6 +601,21 @@ public class GoodsServiceImpl implements GoodsService { return goodsUrlVO; }).collect(Collectors.toList()); } + long count = list.stream().filter((item) -> { + if (item.getIsFree() > 0) { + return false; + } + if (item.getIsBuy() > 0) { + return false; + } + return true; + }).count(); + if (count > 0) { + IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), query.getScenicId(), query.getSourceType(), query.getFaceId()); + if (!isBuy.isBuy()) { + return Collections.emptyList(); + } + } List defaultUrlList = list.stream().map(source -> { GoodsUrlVO goodsUrlVO = new GoodsUrlVO(); goodsUrlVO.setGoodsType(source.getType()); @@ -678,4 +696,20 @@ public class GoodsServiceImpl implements GoodsService { } return defaultUrlList; } + + @Override + public Integer sourceGoodsCount(GoodsReqQuery query) { + FaceEntity face = faceRepository.getFace(query.getFaceId()); + if (face == null) { + return 0; + } + Integer sourceType = query.getSourceType(); + SourceReqQuery sourceReqQuery = new SourceReqQuery(); + sourceReqQuery.setScenicId(query.getScenicId()); + sourceReqQuery.setIsBuy(query.getIsBuy()); + sourceReqQuery.setMemberId(face.getMemberId()); + sourceReqQuery.setType(sourceType); + sourceReqQuery.setFaceId(query.getFaceId()); + return sourceMapper.countUser(sourceReqQuery); + } } diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java index eb6af1e..f5e79fc 100644 --- a/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java @@ -202,14 +202,11 @@ public class TaskFaceServiceImpl implements TaskFaceService { SearchFaceRespVo respVo = new SearchFaceRespVo(); List records = response.getResult(); respVo.setScore(response.getOriginalFaceScore()); - if (records.isEmpty()) { - return respVo; - } respVo.setSearchResultJson(JSON.toJSONString(records)); + logEntity.setMatchRawRecord(records); if (records.isEmpty()) { return respVo; } - logEntity.setMatchRawRecord(records); acceptFaceSampleIds = records.stream() .filter(record -> record.getScore() > _threshold) .map(SearchFaceResultItem::getExtData) @@ -268,12 +265,12 @@ public class TaskFaceServiceImpl implements TaskFaceService { record.setMatched(item.getScore() > _threshold); collect.add(record); } + logEntity.setMatchLocalRecord(JSONObject.toJSONString(collect)); if (acceptFaceSampleIds.isEmpty()) { respVo.setFirstMatchRate(0f); respVo.setSampleListIds(Collections.emptyList()); return respVo; } - logEntity.setMatchLocalRecord(JSONObject.toJSONString(collect)); respVo.setFirstMatchRate(response.getFirstMatchRate()); respVo.setSampleListIds(acceptFaceSampleIds); return respVo; diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java index e93bf6d..f957b71 100644 --- a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java @@ -45,7 +45,6 @@ import com.ycwl.basic.notify.entity.NotifyContent; import com.ycwl.basic.notify.enums.NotifyType; import com.ycwl.basic.repository.DeviceRepository; import com.ycwl.basic.repository.FaceRepository; -import com.ycwl.basic.repository.OrderRepository; import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.VideoRepository; import com.ycwl.basic.repository.VideoTaskRepository; @@ -74,10 +73,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -603,7 +599,7 @@ public class TaskTaskServiceImpl implements TaskService { IStorageAdapter adapter = scenicService.getScenicTmpStorageAdapter(task.getScenicId()); String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getId() + "_" + task.getScenicId() + ".mp4"); adapter.setAcl(StorageAcl.PUBLIC_READ, filename); - videoReUploader.addVideoTask(task.getVideoUrl(), video.getId()); + videoReUploader.addVideoTask(video.getId()); int isBuy = 0; FaceEntity face = faceRepository.getFace(task.getFaceId()); if (face != null) { diff --git a/src/main/java/com/ycwl/basic/storage/adapters/AliOssAdapter.java b/src/main/java/com/ycwl/basic/storage/adapters/AliOssAdapter.java index 8c663fc..247251f 100644 --- a/src/main/java/com/ycwl/basic/storage/adapters/AliOssAdapter.java +++ b/src/main/java/com/ycwl/basic/storage/adapters/AliOssAdapter.java @@ -150,6 +150,7 @@ final public class AliOssAdapter extends AStorageAdapter { object.setPath(getRelativePath(item.getKey().substring(0, item.getKey().lastIndexOf("/")))); object.setName(item.getKey().substring(item.getKey().lastIndexOf("/") + 1)); object.setSize(item.getSize()); + object.setModifyTime(item.getLastModified()); object.setRawObject(item); return object; }).collect(Collectors.toList()); diff --git a/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java b/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java index 597b2a3..f109cd2 100644 --- a/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java +++ b/src/main/java/com/ycwl/basic/task/DownloadNotificationTasker.java @@ -2,11 +2,14 @@ package com.ycwl.basic.task; import cn.hutool.core.date.DateUtil; import com.ycwl.basic.mapper.MemberMapper; +import com.ycwl.basic.mapper.ScenicMapper; import com.ycwl.basic.mapper.VideoMapper; import com.ycwl.basic.model.pc.member.resp.MemberRespVO; import com.ycwl.basic.model.pc.mp.MpConfigEntity; import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity; import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity; +import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery; +import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO; import com.ycwl.basic.model.pc.template.resp.TemplateRespVO; import com.ycwl.basic.notify.NotifyFactory; import com.ycwl.basic.notify.adapters.INotifyAdapter; @@ -22,8 +25,11 @@ import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.util.Arrays; +import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; @Component @@ -39,6 +45,8 @@ public class DownloadNotificationTasker { private MemberMapper memberMapper; @Autowired private TemplateRepository templateRepository; + @Autowired + private ScenicMapper scenicMapper; @Scheduled(cron = "0 0 21 * * *") public void sendDownloadNotification() { @@ -131,4 +139,69 @@ public class DownloadNotificationTasker { adapter.sendTo(new NotifyContent(title, page, params), member.getOpenId()); }); } + + @Scheduled(cron = "0 0 * * * *") + public void sendExtraDownloadNotification() { + log.info("开始执行定时任务"); + List scenicList = scenicMapper.list(new ScenicReqQuery()); + if (scenicList.isEmpty()) { + return; + } + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + int currentHour = calendar.get(Calendar.HOUR_OF_DAY); + calendar.clear(); + scenicList.parallelStream().forEach(scenic -> { + Long scenicId = scenic.getId(); + ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId); + if (scenicConfig == null) { + return; + } + if (StringUtils.isEmpty(scenicConfig.getExtraNotificationTime())) { + return; + } + List timeList = Arrays.asList(StringUtils.split(scenicConfig.getExtraNotificationTime(), ",")); + if (!timeList.contains(String.valueOf(currentHour))) { + return; + } + log.info("当前景区{},配置了{}", scenic.getName(), scenicConfig.getExtraNotificationTime()); + + videoMapper.listRelationByCreateTime(DateUtil.beginOfDay(new Date()), new Date()) + .parallelStream() + .forEach(item -> { + if (item.getIsBuy() == 1) { + return; + } + MemberRespVO member = memberMapper.getById(item.getMemberId()); + MpConfigEntity scenicMp = scenicRepository.getScenicMpConfig(member.getScenicId()); + // 发送模板消息 + String templateId = scenicRepository.getVideoDownloadTemplateId(item.getScenicId()); + if (StringUtils.isBlank(templateId)) { + log.info("模板消息为空"); + return; + } + log.info("发送模板消息"); + String title = "您在【" + scenic.getName() + "】的专属影像"; + String page = "pages/videoSynthesis/index?type=2&scenicId=" + item.getScenicId() + "&faceId=" + item.getFaceId(); + /** + * 景区 {{thing1.DATA}} + * 备注 {{thing3.DATA}} + */ + Map params = new HashMap<>(); + Map dataParam = new HashMap<>(); + Map videoMap = new HashMap<>(); + videoMap.put("value", title); + dataParam.put("thing1", videoMap); + Map remarkMap = new HashMap<>(); + remarkMap.put("value", "请及时购买并下载好您的旅行视频"); + dataParam.put("thing3", remarkMap); + params.put("data", dataParam); + params.put("page", page); + params.put("template_id", templateId); + log.info("视频下载通知模板参数:{},用户ID:{}", params, member.getOpenId()); + INotifyAdapter adapter = NotifyFactory.get(NotifyType.WX_MP_SRV, scenicMp.toMap()); + adapter.sendTo(new NotifyContent(title, page, params), member.getOpenId()); + }); + }); + } } diff --git a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java index def99c5..08dad9d 100644 --- a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java +++ b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java @@ -126,8 +126,8 @@ public class VideoPieceGetter { final ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNamePrefix("VPG-" + task.faceId + "-t") .build(); - final ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 512, 0L, TimeUnit.MILLISECONDS, - new ArrayBlockingQueue<>(512), + final ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 128, 0L, TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(128), threadFactory ); List currentUnFinPlaceholder = new ArrayList<>(); diff --git a/src/main/java/com/ycwl/basic/utils/VideoReUploader.java b/src/main/java/com/ycwl/basic/utils/VideoReUploader.java index f2b3df0..1723a53 100644 --- a/src/main/java/com/ycwl/basic/utils/VideoReUploader.java +++ b/src/main/java/com/ycwl/basic/utils/VideoReUploader.java @@ -10,7 +10,6 @@ import com.ycwl.basic.model.pc.source.entity.SourceEntity; import com.ycwl.basic.model.pc.video.entity.VideoEntity; import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.VideoRepository; -import com.ycwl.basic.repository.VideoTaskRepository; import com.ycwl.basic.service.pc.ScenicService; import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.enums.StorageAcl; @@ -21,19 +20,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.MalformedURLException; -import java.net.URL; import java.util.UUID; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; @Component @Slf4j @@ -102,7 +93,7 @@ public class VideoReUploader { } }); } - public void addVideoTask(String url, Long videoId) { + public void addVideoTask(Long videoId) { VideoEntity entity = videoMapper.getEntity(videoId); if (entity == null) { return; @@ -112,16 +103,16 @@ public class VideoReUploader { } final String dstFilePath = StorageUtil.joinPath(StorageConstant.VLOG_PATH, entity.getTaskId() + "_" + entity.getScenicId() + ".mp4"); final IStorageAdapter adapter = scenicService.getScenicStorageAdapter(entity.getScenicId()); - if (StringUtils.equals(url, adapter.getUrl(dstFilePath))) { + if (StringUtils.equals(entity.getVideoUrl(), adapter.getUrl(dstFilePath))) { return; } String tmpFilePath = UUID.randomUUID().toString(); executor.execute(() -> { // 先下载,后上传 File dstFile = new File(tmpFilePath); - log.info("下载视频:{};videoId:{}", url, videoId); - long size = HttpUtil.downloadFile(url, dstFile); - log.info("下载视频完成:{};大小:{};videoId:{}", url, size, videoId); + log.info("下载视频:{};videoId:{}", entity.getVideoUrl(), videoId); + long size = HttpUtil.downloadFile(entity.getVideoUrl(), dstFile); + log.info("下载视频完成:{};大小:{};videoId:{}", entity.getVideoUrl(), size, videoId); try { log.info("开始上传:{};videoId:{}", dstFilePath, videoId); String newUrl = adapter.uploadFile("video/mp4", dstFile, dstFilePath); diff --git a/src/main/resources/mapper/ScenicMapper.xml b/src/main/resources/mapper/ScenicMapper.xml index 4accb24..df2d7dc 100644 --- a/src/main/resources/mapper/ScenicMapper.xml +++ b/src/main/resources/mapper/ScenicMapper.xml @@ -125,7 +125,8 @@ pay_type=#{payType}, pay_config_json=#{payConfigJson}, image_source_pack_hint=#{imageSourcePackHint}, - video_source_pack_hint=#{videoSourcePackHint} + video_source_pack_hint=#{videoSourcePackHint}, + extra_notification_time=#{extraNotificationTime} where id = #{id} diff --git a/src/main/resources/mapper/SourceMapper.xml b/src/main/resources/mapper/SourceMapper.xml index 0d88de9..2ea2ff4 100644 --- a/src/main/resources/mapper/SourceMapper.xml +++ b/src/main/resources/mapper/SourceMapper.xml @@ -139,7 +139,7 @@ and ms.is_buy = #{isBuy} and ms.type = #{type} and ms.face_id = #{faceId} - order by so.create_time asc + order by ms.is_free desc, so.create_time asc +