This commit is contained in:
2025-05-04 10:51:27 +08:00
parent 6197f13e8e
commit ef978529ac
16 changed files with 157 additions and 41 deletions

View File

@ -40,6 +40,13 @@ public class AppGoodsController {
return ApiResponse.success(goodsDetailVOS);
}
@ApiOperation("源素材(原片/照片)商品数量")
@PostMapping("/sourceGoodsCount")
public ApiResponse<Integer> sourceGoodsCount(@RequestBody GoodsReqQuery query) {
Integer count = goodsService.sourceGoodsCount(query);
return ApiResponse.success(count);
}
@PostMapping("/sourceGoodsList/preview")
public ApiResponse<List<GoodsUrlVO>> sourceGoodsListPreview(@RequestBody GoodsReqQuery query) {
List<GoodsUrlVO> goodsUrlList = goodsService.sourceGoodsListPreview(query);

View File

@ -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);
});
}

View File

@ -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();

View File

@ -51,6 +51,7 @@ public interface SourceMapper {
int addRelation(MemberSourceEntity source);
List<SourceRespVO> listUser(SourceReqQuery sourceReqQuery);
Integer countUser(SourceReqQuery sourceReqQuery);
SourceRespVO listUserOne(Long userId, Long sourceId);
int addRelations(List<MemberSourceEntity> list);

View File

@ -91,4 +91,6 @@ public class ScenicConfigEntity {
private String imageSourcePackHint;
private String videoSourcePackHint;
private String extraNotificationTime;
}

View File

@ -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;
}

View File

@ -48,4 +48,6 @@ public interface GoodsService {
List<GoodsUrlVO> sourceGoodsListPreview(GoodsReqQuery query);
List<GoodsUrlVO> sourceGoodsListDownload(GoodsReqQuery query);
Integer sourceGoodsCount(GoodsReqQuery query);
}

View File

@ -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<GoodsUrlVO> 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);
}
}

View File

@ -202,14 +202,11 @@ public class TaskFaceServiceImpl implements TaskFaceService {
SearchFaceRespVo respVo = new SearchFaceRespVo();
List<SearchFaceResultItem> 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;

View File

@ -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) {

View File

@ -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());

View File

@ -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<ScenicRespVO> 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<String> 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<String, Object> params = new HashMap<>();
Map<String, Object> dataParam = new HashMap<>();
Map<String, String> videoMap = new HashMap<>();
videoMap.put("value", title);
dataParam.put("thing1", videoMap);
Map<String, String> 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());
});
});
}
}

View File

@ -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<String> currentUnFinPlaceholder = new ArrayList<>();

View File

@ -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);

View File

@ -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}
</set>
where id = #{id}
</update>

View File

@ -139,7 +139,7 @@
<if test="isBuy!=null">and ms.is_buy = #{isBuy} </if>
<if test="type!=null">and ms.type = #{type} </if>
<if test="faceId!=null">and ms.face_id = #{faceId} </if>
order by so.create_time asc
order by ms.is_free desc, so.create_time asc
</select>
<select id="listUserOne" resultType="com.ycwl.basic.model.pc.source.resp.SourceRespVO">
@ -214,4 +214,14 @@
</if>
and watermark_type = #{watermarkType}
</select>
<select id="countUser" resultType="java.lang.Integer">
select count(1)
from member_source ms
where
ms.member_id = #{memberId}
<if test="scenicId!= null">and ms.scenic_id = #{scenicId} </if>
<if test="isBuy!=null">and ms.is_buy = #{isBuy} </if>
<if test="type!=null">and ms.type = #{type} </if>
<if test="faceId!=null">and ms.face_id = #{faceId} </if>
</select>
</mapper>