You've already forked FrameTour-BE
Compare commits
46 Commits
b0adf414d0
...
1059d30c21
Author | SHA1 | Date | |
---|---|---|---|
1059d30c21 | |||
4d53986277 | |||
156c487c0f | |||
38e9763033 | |||
1dc9e16c55 | |||
4f0d1813c9 | |||
d2577f0c0f | |||
2adce97503 | |||
1eb527574b | |||
22dea22fc1 | |||
a425c155d0 | |||
ceaf10977d | |||
a5a7957f9e | |||
ce0cbb1c91 | |||
2274ca7010 | |||
18fd50f5d6 | |||
13ef1d1334 | |||
8b957ee96d | |||
b3df268964 | |||
f54595466a | |||
d7d503212f | |||
52086dbea4 | |||
f084b7a21f | |||
3aa039f0ea | |||
1ca7182979 | |||
78079b242a | |||
fd66448f4d | |||
64c4180e4d | |||
af141161de | |||
0317600910 | |||
eda2c75533 | |||
0ecd9d5e20 | |||
722b8a9e90 | |||
69f4ad11ad | |||
49c313b4a0 | |||
5bac59653b | |||
0dbaf5eaba | |||
d180128edb | |||
bd308f35ae | |||
cb312b1a74 | |||
6862ddbf58 | |||
51ba702d82 | |||
ecc011269c | |||
f84adc8ebe | |||
17d63688c6 | |||
3f5dc41310 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.idea/
|
||||
logs/
|
||||
target/
|
||||
|
||||
.claude
|
123
CLAUDE.md
Normal file
123
CLAUDE.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# CLAUDE.md
|
||||
|
||||
本文件为 Claude Code (claude.ai/code) 在此代码仓库中工作时提供指导。
|
||||
|
||||
## 构建和开发命令
|
||||
|
||||
### 构建应用程序
|
||||
```bash
|
||||
# 清理构建(默认跳过测试)
|
||||
mvn clean package
|
||||
|
||||
# 清理构建并执行测试
|
||||
mvn clean package -DskipTests=false
|
||||
|
||||
# 运行应用程序
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
### 测试命令
|
||||
```bash
|
||||
# 运行特定测试类
|
||||
mvn test -Dtest=FaceCleanerTest
|
||||
|
||||
# 运行特定包的测试
|
||||
mvn test -Dtest="com.ycwl.basic.storage.adapters.*Test"
|
||||
|
||||
# 运行所有测试
|
||||
mvn test -DskipTests=false
|
||||
```
|
||||
|
||||
### 开发环境配置
|
||||
应用程序使用 Spring 配置文件:
|
||||
- 默认激活配置文件:`dev`
|
||||
- 生产环境配置文件:`prod`(启用定时任务)
|
||||
- 配置文件:`application-dev.yml`、`application-prod.yml`
|
||||
|
||||
## 架构概览
|
||||
|
||||
这是一个 Spring Boot 3.3.5 应用程序(Java 21),采用多租户架构,通过不同的 API 端点为不同的客户端类型提供服务。
|
||||
|
||||
### 控制器架构
|
||||
- **移动端 APIs** (`/api/mobile/`):面向移动应用的客户端端点
|
||||
- **PC 端 APIs** (`/api/`):Web 仪表板/管理面板端点
|
||||
- **任务 APIs** (`/task/`):后台工作和渲染任务端点
|
||||
- **外部 APIs**:专用集成(打印机、代理、viid、vpt、wvp)
|
||||
|
||||
### 核心业务模块
|
||||
|
||||
#### 工厂模式实现
|
||||
三个主要工厂类管理第三方集成:
|
||||
|
||||
1. **StorageFactory** (`com.ycwl.basic.storage.StorageFactory`)
|
||||
- 管理:本地存储、AWS S3、阿里云 OSS 存储适配器
|
||||
- 配置节:`storage.configs[]`
|
||||
|
||||
2. **PayFactory** (`com.ycwl.basic.pay.PayFactory`)
|
||||
- 管理:微信支付、聪明支付适配器
|
||||
- 配置节:`pay.configs[]`
|
||||
|
||||
3. **FaceBodyFactory** (`com.ycwl.basic.facebody.FaceBodyFactory`)
|
||||
- 管理:阿里云、百度人脸识别适配器
|
||||
- 配置节:`facebody.configs[]`
|
||||
|
||||
#### 适配器模式
|
||||
每个工厂使用标准化接口:
|
||||
- `IStorageAdapter`:文件操作(上传/下载/删除/ACL)
|
||||
- `IPayAdapter`:支付生命周期(创建/回调/退款)
|
||||
- `IFaceBodyAdapter`:人脸识别操作
|
||||
|
||||
#### 定时任务系统
|
||||
`com.ycwl.basic.task` 包中的后台任务(仅生产环境):
|
||||
- `VideoTaskGenerator`:人脸识别和视频处理
|
||||
- `FaceCleaner`:人脸和存储清理任务
|
||||
- `DynamicTaskGenerator`:带延迟队列的动态任务创建
|
||||
- `ScenicStatsTask`:统计数据聚合
|
||||
|
||||
### 数据库和持久化
|
||||
- **MyBatis Plus**:具有自动 CRUD 操作的 ORM
|
||||
- **MapperScan**:扫描 `com.ycwl.basic.mapper` 及子包
|
||||
- **数据库**:MySQL 配合 HikariCP 连接池
|
||||
- **Redis**:会话管理和缓存
|
||||
|
||||
### 主要库和依赖
|
||||
- Spring Boot 3.3.5 启用 Java 21 虚拟线程
|
||||
- MyBatis Plus 3.5.5 用于数据库操作
|
||||
- JWT (jjwt 0.9.0) 用于身份验证
|
||||
- 微信支付 SDK 用于支付处理
|
||||
- 阿里云 OSS 和 AWS S3 用于文件存储
|
||||
- 阿里云和百度 SDK 用于人脸识别
|
||||
- OpenTelemetry 用于可观测性(开发环境中禁用)
|
||||
|
||||
### 业务逻辑组织
|
||||
- **Service 层**:`service` 包中的业务逻辑实现
|
||||
- **Biz 层**:`biz` 包中的高级业务编排
|
||||
- **Repository 模式**:`repository` 包中的数据访问抽象
|
||||
- **自定义异常**:特定领域的异常处理
|
||||
|
||||
### 配置管理
|
||||
每个模块使用 Spring Boot 自动配置启动器:
|
||||
- 支持多供应商的命名配置
|
||||
- 通过配置进行默认供应商选择
|
||||
- 针对不同环境的特定配置文件
|
||||
|
||||
## 常见开发模式
|
||||
|
||||
### 添加新的存储/支付/人脸识别供应商
|
||||
1. 实现相应接口(`IStorageAdapter`、`IPayAdapter`、`IFaceBodyAdapter`)
|
||||
2. 在相应的类型枚举中添加枚举值
|
||||
3. 更新工厂的 switch 表达式
|
||||
4. 如需要,添加配置类
|
||||
5. 在 application.yml 中更新新供应商配置
|
||||
|
||||
### 身份验证上下文
|
||||
在整个应用程序中使用 `BaseContextHandler.getUserId()` 获取当前已认证用户 ID。
|
||||
|
||||
### API 响应模式
|
||||
所有 API 都返回 `ApiResponse<T>` 包装器,通过 `CustomExceptionHandle` 进行一致的错误处理。
|
||||
|
||||
### 添加新的定时任务
|
||||
1. 在 `com.ycwl.basic.task` 包中创建类
|
||||
2. 添加 `@Component` 和 `@Profile("prod")` 注解
|
||||
3. 使用 `@Scheduled` 进行基于 cron 的执行
|
||||
4. 遵循现有的错误处理和日志记录模式
|
148
src/main/java/com/ycwl/basic/controller/extern/AioDeviceController.java
vendored
Normal file
148
src/main/java/com/ycwl/basic/controller/extern/AioDeviceController.java
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package com.ycwl.basic.controller.extern;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.mapper.AioDeviceMapper;
|
||||
import com.ycwl.basic.mapper.MemberMapper;
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceBannerEntity;
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceEntity;
|
||||
import com.ycwl.basic.model.aio.entity.AioDevicePriceConfigEntity;
|
||||
import com.ycwl.basic.model.aio.req.AioDeviceCreateOrderReq;
|
||||
import com.ycwl.basic.model.aio.resp.AioDeviceCreateOrderResp;
|
||||
import com.ycwl.basic.model.aio.resp.AioDeviceInfoResp;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
|
||||
import com.ycwl.basic.model.mobile.goods.GoodsDetailVO;
|
||||
import com.ycwl.basic.model.mobile.goods.GoodsReqQuery;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.model.pc.member.entity.MemberEntity;
|
||||
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
|
||||
import com.ycwl.basic.pay.entity.PayResponse;
|
||||
import com.ycwl.basic.service.aio.AioDeviceService;
|
||||
import com.ycwl.basic.service.mobile.GoodsService;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
@RequestMapping("/api/aio")
|
||||
public class AioDeviceController {
|
||||
@Autowired
|
||||
private GoodsService goodsService;
|
||||
@Autowired
|
||||
private FaceService faceService;
|
||||
@Autowired
|
||||
private MemberMapper memberMapper;
|
||||
@Autowired
|
||||
private AioDeviceMapper aioDeviceMapper;
|
||||
@Autowired
|
||||
private AioDeviceService aioDeviceService;
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
@GetMapping("/info")
|
||||
public ApiResponse<AioDeviceInfoResp> getDeviceInfo(HttpServletRequest request) {
|
||||
String deviceId = request.getHeader("X-DeviceId");
|
||||
AioDeviceEntity aioDevice = aioDeviceMapper.getByKey(deviceId);
|
||||
if (aioDevice == null) {
|
||||
return ApiResponse.fail("设备不存在");
|
||||
}
|
||||
List<AioDeviceBannerEntity> banners = aioDeviceMapper.getBannerByDeviceId(aioDevice.getId());
|
||||
return ApiResponse.success(new AioDeviceInfoResp(aioDevice, banners));
|
||||
}
|
||||
|
||||
@GetMapping("/banners")
|
||||
public ApiResponse<List<AioDeviceBannerEntity>> getBanners(HttpServletRequest request) {
|
||||
String deviceId = request.getHeader("X-DeviceId");
|
||||
AioDeviceEntity aioDevice = aioDeviceMapper.getByKey(deviceId);
|
||||
if (aioDevice == null) {
|
||||
return ApiResponse.fail("设备不存在");
|
||||
}
|
||||
List<AioDeviceBannerEntity> banners = aioDeviceMapper.getBannerByDeviceId(aioDevice.getId());
|
||||
return ApiResponse.success(banners);
|
||||
}
|
||||
|
||||
@GetMapping("/config")
|
||||
public ApiResponse<AioDevicePriceConfigEntity> getPriceConfig(HttpServletRequest request) {
|
||||
String deviceId = request.getHeader("X-DeviceId");
|
||||
AioDeviceEntity aioDevice = aioDeviceMapper.getByKey(deviceId);
|
||||
if (aioDevice == null) {
|
||||
return ApiResponse.fail("设备不存在");
|
||||
}
|
||||
AioDevicePriceConfigEntity config = aioDeviceMapper.getPriceConfigByDeviceId(aioDevice.getId());
|
||||
return ApiResponse.success(config);
|
||||
}
|
||||
|
||||
@PostMapping("/faceUpload")
|
||||
public ApiResponse<FaceRecognizeResp> faceUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
|
||||
String deviceId = request.getHeader("X-DeviceId");
|
||||
AioDeviceEntity aioDevice = aioDeviceMapper.getByKey(deviceId);
|
||||
if (aioDevice == null) {
|
||||
return ApiResponse.fail("设备不存在");
|
||||
}
|
||||
MemberEntity memberEntity = new MemberEntity();
|
||||
memberEntity.setScenicId(aioDevice.getScenicId());
|
||||
memberEntity.setCreateDate(new Date());
|
||||
memberEntity.setId(SnowFlakeUtil.getLongId());
|
||||
memberEntity.setNickname("用户");
|
||||
memberMapper.add(memberEntity);
|
||||
FaceRecognizeResp resp = faceService.faceUpload(file, aioDevice.getScenicId(), memberEntity.getId());
|
||||
return ApiResponse.success(resp);
|
||||
}
|
||||
|
||||
@ApiOperation("人脸信息")
|
||||
@GetMapping("/{faceId}")
|
||||
public ApiResponse<FaceRespVO> faceInfo(@PathVariable Long faceId) {
|
||||
return faceService.getById(faceId);
|
||||
}
|
||||
@ApiOperation("照片商品列表")
|
||||
@GetMapping("/{faceId}/photo")
|
||||
public ApiResponse<List<GoodsDetailVO>> sourceGoodsList(@PathVariable Long faceId) {
|
||||
GoodsReqQuery query = new GoodsReqQuery();
|
||||
query.setSourceType(2);
|
||||
query.setFaceId(faceId);
|
||||
List<GoodsDetailVO> goodsDetailVOS = goodsService.sourceGoodsList(query);
|
||||
return ApiResponse.success(goodsDetailVOS);
|
||||
}
|
||||
|
||||
@ApiOperation("创建订单")
|
||||
@PostMapping("/order")
|
||||
public ApiResponse<AioDeviceCreateOrderResp> createOrder(HttpServletRequest request, @RequestBody AioDeviceCreateOrderReq req) {
|
||||
String deviceId = request.getHeader("X-DeviceId");
|
||||
AioDeviceEntity aioDevice = aioDeviceMapper.getByKey(deviceId);
|
||||
if (aioDevice == null) {
|
||||
return ApiResponse.fail("设备不存在");
|
||||
}
|
||||
return ApiResponse.success(aioDeviceService.createOrder(aioDevice, req));
|
||||
}
|
||||
|
||||
@ApiOperation("查询订单")
|
||||
@GetMapping("/order/{orderId}")
|
||||
public ApiResponse<PayResponse> queryOrder(HttpServletRequest request, @PathVariable("orderId") Long orderId) {
|
||||
String deviceId = request.getHeader("X-DeviceId");
|
||||
AioDeviceEntity aioDevice = aioDeviceMapper.getByKey(deviceId);
|
||||
if (aioDevice == null) {
|
||||
return ApiResponse.fail("设备不存在");
|
||||
}
|
||||
return ApiResponse.success(orderService.queryOrder(orderId));
|
||||
}
|
||||
}
|
@@ -14,8 +14,10 @@ import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.model.pc.member.entity.MemberEntity;
|
||||
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
|
||||
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
|
||||
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
import com.ycwl.basic.repository.VideoTaskRepository;
|
||||
import com.ycwl.basic.service.mobile.AppScenicService;
|
||||
import com.ycwl.basic.service.mobile.GoodsService;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
@@ -62,6 +64,8 @@ public class LyCompatibleController {
|
||||
private TaskTaskServiceImpl taskTaskServiceImpl;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private VideoTaskRepository videoTaskRepository;
|
||||
|
||||
@PostMapping("sendPhoto")
|
||||
@IgnoreToken
|
||||
@@ -198,6 +202,7 @@ public class LyCompatibleController {
|
||||
R response = R.ok();
|
||||
if (collect.get(0) == null) {
|
||||
response.put("isgen", 1)
|
||||
.put("face_id", faceVO.getId().toString())
|
||||
.put("newvideo", Collections.emptyList())
|
||||
.put("newuservideo", Collections.emptyList());
|
||||
return response;
|
||||
@@ -208,6 +213,11 @@ public class LyCompatibleController {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
VideoEntity videoRespVO = videoRepository.getVideo(contentPageVO.getContentId());
|
||||
map.put("id", videoRespVO.getId().toString());
|
||||
map.put("task_id", videoRespVO.getTaskId().toString());
|
||||
TaskEntity task = videoTaskRepository.getTaskById(videoRespVO.getTaskId());
|
||||
if (task != null) {
|
||||
map.put("face_id", String.valueOf(task.getFaceId()));
|
||||
}
|
||||
map.put("template_cover_image", contentPageVO.getTemplateCoverUrl());
|
||||
Date taskShotDate = taskTaskServiceImpl.getTaskShotDate(videoRespVO.getTaskId());
|
||||
map.put("shoottime", DateUtil.format(taskShotDate, "yyyy-MM-dd HH:mm"));
|
||||
@@ -224,6 +234,7 @@ public class LyCompatibleController {
|
||||
List<Map<String, Object>> userVideoList = sourceGoodsList.stream().map(goodsDetailVO -> {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("id", goodsDetailVO.getGoodsId().toString());
|
||||
map.put("face_id", String.valueOf(goodsDetailVO.getFaceId()));
|
||||
map.put("openid", openId);
|
||||
map.put("template_cover_image", goodsDetailVO.getUrl());
|
||||
map.put("scenicname", goodsDetailVO.getScenicName());
|
||||
@@ -233,6 +244,8 @@ public class LyCompatibleController {
|
||||
}).collect(Collectors.toList());
|
||||
response
|
||||
.put("isgen", taskStatusVO.getStatus() == 1 ? 0 : 1)
|
||||
.put("member_id", faceVO.getMemberId().toString())
|
||||
.put("face_id", faceVO.getId().toString())
|
||||
.put("newvideo", videoList)
|
||||
.put("newuservideo", userVideoList);
|
||||
redisTemplate.opsForValue().set("ly:"+openId, JSON.toJSONString(response), 5, TimeUnit.SECONDS);
|
||||
|
@@ -78,4 +78,13 @@ AppFaceController {
|
||||
List<ContentPageVO> contentPageVOS = faceService.faceContentList(faceId);
|
||||
return ApiResponse.success(contentPageVOS);
|
||||
}
|
||||
|
||||
@ApiOperation("绑定人脸")
|
||||
@PostMapping("/{faceId}/bind")
|
||||
public ApiResponse<String> bind(@PathVariable Long faceId) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
Long userId = worker.getUserId();
|
||||
faceService.bindFace(faceId, userId);
|
||||
return ApiResponse.success("OK");
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package com.ycwl.basic.controller.mobile.manage;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginOldRespVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
|
||||
import com.ycwl.basic.model.mobile.weChat.DTO.WeChatUserInfoDTO;
|
||||
@@ -49,8 +50,20 @@ public class AppScenicAccountController {
|
||||
@ApiOperation("登录")
|
||||
@PostMapping("/login")
|
||||
@IgnoreToken
|
||||
public ApiResponse<ScenicLoginRespVO> login(@RequestBody ScenicLoginReq scenicLoginReq) throws Exception {
|
||||
return scenicService.login(scenicLoginReq);
|
||||
public ApiResponse<ScenicLoginOldRespVO> login(@RequestBody ScenicLoginReq scenicLoginReq) throws Exception {
|
||||
ApiResponse<ScenicLoginRespVO> logined = scenicService.login(scenicLoginReq);
|
||||
ScenicLoginOldRespVO vo = new ScenicLoginOldRespVO();
|
||||
if (!logined.isSuccess()) {
|
||||
return ApiResponse.fail(logined.getMsg());
|
||||
}
|
||||
vo.setId(logined.getData().getId());
|
||||
vo.setScenicId(logined.getData().getScenicId().getFirst());
|
||||
vo.setIsSuper(logined.getData().getIsSuper());
|
||||
vo.setName(logined.getData().getName());
|
||||
vo.setAccount(logined.getData().getAccount());
|
||||
vo.setStatus(logined.getData().getStatus());
|
||||
vo.setToken(logined.getData().getToken());
|
||||
return ApiResponse.success(vo);
|
||||
}
|
||||
|
||||
@GetMapping("/myScenicList")
|
||||
|
@@ -1,45 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.model.pc.menu.entity.MenuEntity;
|
||||
import com.ycwl.basic.service.pc.MenuService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/3 10:03
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/menu/v1")
|
||||
@Api(tags = "系统菜单管理")
|
||||
public class MenuController {
|
||||
|
||||
private MenuService menuService;
|
||||
|
||||
|
||||
@GetMapping(value = "/list/{type}")
|
||||
@ApiOperation(value = " 菜单列表")
|
||||
@IgnoreToken
|
||||
public ApiResponse list(@PathVariable("type") Integer type) {
|
||||
return menuService.list(type);
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
@ApiOperation(value = "添加菜单")
|
||||
public ApiResponse add(@RequestBody MenuEntity menu) {
|
||||
return menuService.add(menu);
|
||||
}
|
||||
@PostMapping("/update")
|
||||
@ApiOperation(value = "修改菜单")
|
||||
public ApiResponse update(@RequestBody MenuEntity menu) {
|
||||
return menuService.update(menu);
|
||||
}
|
||||
@GetMapping("/delete/{id}")
|
||||
@ApiOperation(value = "删除菜单")
|
||||
public ApiResponse delete(@PathVariable("id") Long id) {
|
||||
return menuService.deleteById(id);
|
||||
}
|
||||
}
|
@@ -1,10 +1,14 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.mapper.AdminUserMapper;
|
||||
import com.ycwl.basic.model.pc.adminUser.entity.LoginEntity;
|
||||
import com.ycwl.basic.model.pc.permission.entity.PermissionEntity;
|
||||
import com.ycwl.basic.model.pc.permission.req.PermissionSaveReq;
|
||||
import com.ycwl.basic.model.pc.permission.resp.PermissionResp;
|
||||
import com.ycwl.basic.model.pc.role.resp.RolePermissionResp;
|
||||
import com.ycwl.basic.service.pc.PermissionService;
|
||||
import com.ycwl.basic.service.pc.RoleService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -28,15 +32,29 @@ import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
public class PermissionController {
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
@Autowired
|
||||
private AdminUserMapper adminUserMapper;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
|
||||
@GetMapping("/get/")
|
||||
public ApiResponse<PermissionResp> getPermissionByUser() {
|
||||
String userId = BaseContextHandler.getUserId();
|
||||
PermissionEntity permission = permissionService.getPermissionByUserId(Long.parseLong(userId));
|
||||
if (permission == null || StringUtils.isEmpty(permission.getPermString())) {
|
||||
return ApiResponse.success(new PermissionResp(new ArrayList<>(), new ArrayList<>()));
|
||||
if (MERCHANT.type.equals(BaseContextHandler.getRoleId())) {
|
||||
PermissionEntity permission = permissionService.getPermissionByUserId(Long.parseLong(userId));
|
||||
if (permission == null || StringUtils.isEmpty(permission.getPermString())) {
|
||||
return ApiResponse.success(new PermissionResp(new ArrayList<>(), new ArrayList<>()));
|
||||
}
|
||||
return ApiResponse.success(new PermissionResp(Arrays.asList(StringUtils.split(permission.getPermString(), ",")), Arrays.asList(StringUtils.split(permission.getMenuString(), ","))));
|
||||
} else {
|
||||
// admin
|
||||
LoginEntity login = adminUserMapper.getById(Long.parseLong(userId));
|
||||
RolePermissionResp permissionByRoleId = roleService.getPermissionByRoleId(login.getRoleId());
|
||||
if (permissionByRoleId == null) {
|
||||
return ApiResponse.success(new PermissionResp(new ArrayList<>(), new ArrayList<>()));
|
||||
}
|
||||
return ApiResponse.success(new PermissionResp(Arrays.asList(StringUtils.split(permissionByRoleId.getPermStr(), ",")), Arrays.asList(StringUtils.split(permissionByRoleId.getMenuStr(), ","))));
|
||||
}
|
||||
return ApiResponse.success(new PermissionResp(Arrays.asList(StringUtils.split(permission.getPermString(), ",")), Arrays.asList(StringUtils.split(permission.getMenuString(), ","))));
|
||||
}
|
||||
|
||||
@ApiOperation("根据用户ID查询权限信息")
|
||||
|
@@ -2,16 +2,20 @@ package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.model.pc.permission.resp.PermissionResp;
|
||||
import com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO;
|
||||
import com.ycwl.basic.model.pc.role.req.RoleListReqVO;
|
||||
import com.ycwl.basic.model.pc.role.resp.RoleListRespVO;
|
||||
import com.ycwl.basic.model.pc.role.resp.RolePermissionResp;
|
||||
import com.ycwl.basic.service.pc.RoleService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@@ -24,34 +28,38 @@ public class RoleController {
|
||||
|
||||
@PostMapping(value = "/page")
|
||||
@ApiOperation(value = "角色列表分页查询")
|
||||
@IgnoreToken
|
||||
public ApiResponse<PageInfo<RoleListRespVO>> page(@RequestBody RoleListReqVO roleListReqVO) {
|
||||
return roleService.pageQuery(roleListReqVO);
|
||||
}
|
||||
@PostMapping(value = "/list")
|
||||
@ApiOperation(value = "角色列表")
|
||||
@IgnoreToken
|
||||
public ApiResponse<List<RoleListRespVO>> list(@RequestBody RoleListReqVO roleListReqVO) {
|
||||
return roleService.list(roleListReqVO);
|
||||
}
|
||||
@GetMapping("/{roleId}/permission")
|
||||
@ApiOperation(value = "角色权限列表")
|
||||
public ApiResponse<PermissionResp> getPermissionByRoleId(@PathVariable("roleId") Long roleId) {
|
||||
RolePermissionResp permission = roleService.getPermissionByRoleId(roleId);
|
||||
if (permission == null) {
|
||||
return ApiResponse.fail("角色不存在");
|
||||
}
|
||||
return ApiResponse.success(new PermissionResp(Arrays.asList(StringUtils.split(permission.getPermStr(), ",")), Arrays.asList(StringUtils.split(permission.getMenuStr(), ","))));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/addOrUpdate")
|
||||
@ApiOperation(value = "添加或更新角色")
|
||||
@IgnoreToken
|
||||
public ApiResponse addOrUpdate(@RequestBody AddOrUpdateRoleReqVO addOrUpdateRoleReqVO) {
|
||||
return roleService.addOrUpdate(addOrUpdateRoleReqVO);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/delete/{id}")
|
||||
@ApiOperation(value = "删除")
|
||||
@IgnoreToken
|
||||
public ApiResponse delete(@PathVariable("id") String id) {
|
||||
return roleService.delete(id);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/updateReturnMenu/{id}")
|
||||
@ApiOperation(value = "编辑回显该角色当前菜单")
|
||||
@IgnoreToken
|
||||
public ApiResponse updateReturnMenu(@PathVariable("id") String id) {
|
||||
return roleService.updateReturnMenu(id);
|
||||
}
|
||||
@@ -60,7 +68,6 @@ public class RoleController {
|
||||
|
||||
@GetMapping(value = "/updateStatus/{id}")
|
||||
@ApiOperation(value = "更改角色类型状态")
|
||||
//@IgnoreToken
|
||||
public ApiResponse updateStatus(@PathVariable("id") String id) {
|
||||
return roleService.updateStatus(id);
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import com.ycwl.basic.mapper.DeviceMapper;
|
||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceCropConfig;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
@@ -53,6 +54,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.awt.image.RasterFormatException;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -66,7 +69,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.ycwl.basic.constant.StorageConstant.PHOTO_PATH;
|
||||
import static com.ycwl.basic.constant.StorageConstant.VIID_FACE;
|
||||
@@ -244,8 +246,14 @@ public class ViidController {
|
||||
continue;
|
||||
}
|
||||
DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(device.getId());
|
||||
if (deviceConfig == null) {
|
||||
log.warn("设备配置不存在:" + deviceID);
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject(faceId, "/VIID/Faces", "0", "OK", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
int viidMode = 0;
|
||||
if (deviceConfig != null && deviceConfig.getViidType() != null) {
|
||||
if (deviceConfig.getViidType() != null) {
|
||||
viidMode = deviceConfig.getViidType();
|
||||
}
|
||||
Date shotTime = null;
|
||||
@@ -285,13 +293,15 @@ public class ViidController {
|
||||
if (viidMode == 0) {
|
||||
// 遍历每个图片对象
|
||||
// 先找到type14的图片
|
||||
List<SubImageInfoObject> type14ImageList = subImageList.getSubImageInfoObject().stream().filter(subImage -> "14".equals(subImage.getType())).collect(Collectors.toList());
|
||||
List<SubImageInfoObject> type14ImageList = subImageList.getSubImageInfoObject().stream().filter(subImage -> "14".equals(subImage.getType())).toList();
|
||||
for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
|
||||
// base64转换成MultipartFIle
|
||||
MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
|
||||
String ext = subImage.getFileFormat();
|
||||
if (ext.equalsIgnoreCase("jpeg")) {
|
||||
String ext;
|
||||
if (subImage.getFileFormat().equalsIgnoreCase("jpeg")) {
|
||||
ext = "jpg";
|
||||
} else {
|
||||
ext = subImage.getFileFormat();
|
||||
}
|
||||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||||
// Type=11 人脸
|
||||
@@ -318,7 +328,7 @@ public class ViidController {
|
||||
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore());
|
||||
}
|
||||
}
|
||||
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
|
||||
if (Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
|
||||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||||
}
|
||||
});
|
||||
@@ -328,7 +338,6 @@ public class ViidController {
|
||||
facePosition.setImgHeight(_subImage.getHeight());
|
||||
facePosition.setImgWidth(_subImage.getWidth());
|
||||
SourceEntity source = new SourceEntity();
|
||||
source.setId(SnowFlakeUtil.getLongId());
|
||||
source.setDeviceId(device.getId());
|
||||
source.setScenicId(device.getScenicId());
|
||||
source.setFaceSampleId(newFaceSampleId);
|
||||
@@ -336,12 +345,43 @@ public class ViidController {
|
||||
source.setType(2);
|
||||
// 上传oss
|
||||
MultipartFile _file = ImageUtils.base64ToMultipartFile(_subImage.getData());
|
||||
String filename = StorageUtil.joinPath(PHOTO_PATH, UUID.randomUUID() + "." + ext);
|
||||
String _sourceUrl = scenicStorageAdapter.uploadFile(_file, filename);
|
||||
scenicStorageAdapter.setAcl(StorageAcl.PUBLIC_READ, filename);
|
||||
source.setUrl(_sourceUrl);
|
||||
source.setPosJson(JSON.toJSONString(facePosition));
|
||||
sourceMapper.add(source);
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
List<DeviceCropConfig> cropConfigs = deviceConfig._getCropConfig();
|
||||
for (DeviceCropConfig cropConfig : cropConfigs) {
|
||||
source.setId(SnowFlakeUtil.getLongId());
|
||||
String filename = StorageUtil.joinPath(PHOTO_PATH, UUID.randomUUID() + "." + ext);
|
||||
MultipartFile _finalFile = _file;
|
||||
if (cropConfig.getCropType() == 1) {
|
||||
// 按固定位置截图
|
||||
try {
|
||||
_finalFile = ImageUtils.cropImage(_file, cropConfig.getTargetX(), cropConfig.getTargetY(), cropConfig.getTargetWidth(), cropConfig.getTargetHeight());
|
||||
} catch (IOException e) {
|
||||
log.error("裁切图片失败!", e);
|
||||
} catch (RasterFormatException e) {
|
||||
log.error("裁切图片出错!", e);
|
||||
}
|
||||
} else if (cropConfig.getCropType() == 2) {
|
||||
// 按人脸位置
|
||||
try {
|
||||
int targetX = facePosition.getLtX() - (cropConfig.getTargetWidth() - facePosition.getWidth())/2;
|
||||
int targetY = facePosition.getLtY() - (cropConfig.getTargetHeight() - facePosition.getHeight())/2;
|
||||
_finalFile = ImageUtils.cropImage(_file, targetX, targetY, cropConfig.getTargetWidth(), cropConfig.getTargetHeight());
|
||||
} catch (IOException e) {
|
||||
log.error("裁切图片失败!", e);
|
||||
} catch (RasterFormatException e) {
|
||||
log.error("裁切图片出错!", e);
|
||||
}
|
||||
facePosition.setImgHeight(cropConfig.getTargetHeight());
|
||||
facePosition.setImgWidth(cropConfig.getTargetWidth());
|
||||
}
|
||||
String _sourceUrl = scenicStorageAdapter.uploadFile(_finalFile, filename);
|
||||
scenicStorageAdapter.setAcl(StorageAcl.PUBLIC_READ, filename);
|
||||
source.setUrl(_sourceUrl);
|
||||
source.setPosJson(JSON.toJSONString(facePosition));
|
||||
sourceMapper.add(source);
|
||||
}
|
||||
});
|
||||
}
|
||||
log.info("人脸信息及原图{}张入库成功!设备ID:{}", type14ImageList.size(), deviceID);
|
||||
}
|
||||
|
@@ -278,7 +278,6 @@ public class BceFaceBodyAdapter implements IFaceBodyAdapter {
|
||||
try {
|
||||
AipFace client = getClient();
|
||||
HashMap<String, Object> options = new HashMap<>();
|
||||
options.put("quality_control", "LOW");
|
||||
options.put("max_user_num", "50");
|
||||
try {
|
||||
searchFaceLimiter.acquire();
|
||||
|
@@ -52,8 +52,9 @@ public class LeicaWatermarkOperator implements IOperator {
|
||||
public static int LOGO_EXTRA_BORDER = 20;
|
||||
public static int LOGO_FONT_SIZE = 38;
|
||||
public static Color logoTextColor = new Color(0x33, 0x33, 0x33);
|
||||
public static int QRCODE_SIZE = 80;
|
||||
public static int QRCODE_SIZE = 120;
|
||||
public static int QRCODE_OFFSET_X = 5;
|
||||
public static int QRCODE_OFFSET_Y = 20;
|
||||
public static int OFFSET_X = 80;
|
||||
public static int OFFSET_Y = 30;
|
||||
public static int SCENIC_FONT_SIZE = 32;
|
||||
@@ -106,13 +107,30 @@ public class LeicaWatermarkOperator implements IOperator {
|
||||
int dtLineHeight = datetimeFontMetrics.getHeight();
|
||||
int scenicLineWidth = scenicFontMetrics.stringWidth(info.getScenicLine());
|
||||
int datetimeLineWidth = scenicFontMetrics.stringWidth(info.getDatetimeLine());
|
||||
g2d.drawImage(qrcodeImage, newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - newQrcodeWidth - QRCODE_OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y, newQrcodeWidth, newQrcodeHeight, null);
|
||||
// 计算二维码的位置
|
||||
int qrcodeX = newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - newQrcodeWidth - QRCODE_OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth);
|
||||
int qrcodeY = EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y - QRCODE_OFFSET_Y;
|
||||
|
||||
g2d.drawImage(qrcodeImage, qrcodeX, qrcodeY, newQrcodeWidth, newQrcodeHeight, null);
|
||||
|
||||
// 计算文字与二维码垂直居中对齐的Y坐标
|
||||
int qrcodeTop = qrcodeY;
|
||||
int qrcodeBottom = qrcodeTop + newQrcodeHeight;
|
||||
int qrcodeCenter = (qrcodeTop + qrcodeBottom) / 2;
|
||||
|
||||
// 两行文字的总高度
|
||||
int totalTextHeight = scenicLineHeight + dtLineHeight;
|
||||
|
||||
// 计算第一行文字的Y坐标(基线位置),使两行文字整体垂直居中于二维码
|
||||
int textStartY = qrcodeCenter - totalTextHeight / 2 + scenicFontMetrics.getAscent();
|
||||
|
||||
g2d.setFont(scenicFont);
|
||||
g2d.setColor(scenicColor);
|
||||
g2d.drawString(info.getScenicLine(), newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y + scenicLineHeight + scenicLineHeight * FONT_GLOBAL_OFFSET_PERCENT);
|
||||
g2d.drawString(info.getScenicLine(), newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), textStartY);
|
||||
|
||||
g2d.setFont(datetimeFont);
|
||||
g2d.setColor(datetimeColor);
|
||||
g2d.drawString(info.getDatetimeLine(), newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y + scenicLineHeight + dtLineHeight + dtLineHeight * FONT_GLOBAL_OFFSET_PERCENT);
|
||||
g2d.drawString(info.getDatetimeLine(), newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), textStartY + scenicLineHeight);
|
||||
String fileName = info.getWatermarkedFile().getName();
|
||||
String formatName = "jpg"; // 默认格式为 jpg
|
||||
if (fileName.endsWith(".png")) {
|
||||
@@ -133,7 +151,7 @@ public class LeicaWatermarkOperator implements IOperator {
|
||||
ImageWriteParam writeParam = writer.getDefaultWriteParam();
|
||||
if (writeParam.canWriteCompressed()) {
|
||||
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
writeParam.setCompressionQuality(0.95f); // 设置写入质量为 95%
|
||||
writeParam.setCompressionQuality(0.75f); // 设置写入质量为 75%
|
||||
}
|
||||
writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
|
||||
} catch (IOException e) {
|
||||
|
@@ -9,6 +9,7 @@ import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -45,8 +46,9 @@ public class NormalWatermarkOperator implements IOperator {
|
||||
public static int EXTRA_BORDER_PX = 0;
|
||||
public static int OFFSET_Y = 90;
|
||||
public static Color BG_COLOR = Color.WHITE;
|
||||
public static int QRCODE_SIZE = 100;
|
||||
public static int QRCODE_SIZE = 150;
|
||||
public static int QRCODE_OFFSET_X = 10;
|
||||
public static int QRCODE_OFFSET_Y = -20;
|
||||
|
||||
public static int SCENIC_FONT_SIZE = 42;
|
||||
public static Color scenicColor = Color.white;
|
||||
@@ -82,13 +84,29 @@ public class NormalWatermarkOperator implements IOperator {
|
||||
int datetimeLineWidth = scenicFontMetrics.stringWidth(info.getDatetimeLine());
|
||||
int offsetX = (newImage.getWidth() - newQrcodeWidth - QRCODE_OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth)) / 2;
|
||||
int offsetY = EXTRA_BORDER_PX + baseImage.getHeight() - OFFSET_Y - newQrcodeHeight;
|
||||
g2d.drawImage(qrcodeImage, offsetX, offsetY, newQrcodeWidth, newQrcodeHeight, null);
|
||||
Shape originalClip = g2d.getClip();
|
||||
Ellipse2D circle = new Ellipse2D.Double(offsetX, offsetY + QRCODE_OFFSET_Y, newQrcodeWidth, newQrcodeHeight);
|
||||
g2d.setClip(circle);
|
||||
g2d.drawImage(qrcodeImage, offsetX, offsetY + QRCODE_OFFSET_Y, newQrcodeWidth, newQrcodeHeight, null);
|
||||
g2d.setClip(originalClip);
|
||||
// 计算文字与二维码垂直居中对齐的Y坐标
|
||||
int qrcodeTop = offsetY + QRCODE_OFFSET_Y;
|
||||
int qrcodeBottom = qrcodeTop + newQrcodeHeight;
|
||||
int qrcodeCenter = (qrcodeTop + qrcodeBottom) / 2;
|
||||
|
||||
// 两行文字的总高度
|
||||
int totalTextHeight = scenicLineHeight + dtLineHeight;
|
||||
|
||||
// 计算第一行文字的Y坐标(基线位置),使两行文字整体垂直居中于二维码
|
||||
int textStartY = qrcodeCenter - totalTextHeight / 2 + scenicFontMetrics.getAscent();
|
||||
|
||||
g2d.setFont(scenicFont);
|
||||
g2d.setColor(scenicColor);
|
||||
g2d.drawString(info.getScenicLine(), offsetX + newQrcodeWidth + QRCODE_OFFSET_X, offsetY + scenicLineHeight + FONT_GLOBAL_OFFSET_PERCENT * scenicLineHeight);
|
||||
g2d.drawString(info.getScenicLine(), offsetX + newQrcodeWidth + QRCODE_OFFSET_X, textStartY);
|
||||
|
||||
g2d.setFont(datetimeFont);
|
||||
g2d.setColor(datetimeColor);
|
||||
g2d.drawString(info.getDatetimeLine(), offsetX + newQrcodeWidth + QRCODE_OFFSET_X, offsetY + scenicLineHeight + dtLineHeight + FONT_GLOBAL_OFFSET_PERCENT * dtLineHeight);
|
||||
g2d.drawString(info.getDatetimeLine(), offsetX + newQrcodeWidth + QRCODE_OFFSET_X, textStartY + scenicLineHeight);
|
||||
String fileName = info.getWatermarkedFile().getName();
|
||||
String formatName = "jpg"; // 默认格式为 jpg
|
||||
if (fileName.endsWith(".png")) {
|
||||
@@ -109,7 +127,7 @@ public class NormalWatermarkOperator implements IOperator {
|
||||
ImageWriteParam writeParam = writer.getDefaultWriteParam();
|
||||
if (writeParam.canWriteCompressed()) {
|
||||
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
writeParam.setCompressionQuality(0.95f); // 设置写入质量为 95%
|
||||
writeParam.setCompressionQuality(0.75f); // 设置写入质量为 75%
|
||||
}
|
||||
writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
|
||||
} catch (IOException e) {
|
||||
|
@@ -8,7 +8,12 @@ import com.ycwl.basic.constant.RequestConstant;
|
||||
import com.ycwl.basic.exception.CheckTokenException;
|
||||
import com.ycwl.basic.exception.MissTokenException;
|
||||
import com.ycwl.basic.exception.PermissionException;
|
||||
import com.ycwl.basic.exception.TokenExpireException;
|
||||
import com.ycwl.basic.mapper.AdminUserMapper;
|
||||
import com.ycwl.basic.mapper.ScenicAccountMapper;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.pc.adminUser.entity.LoginEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -23,14 +28,24 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.ADMIN;
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AuthInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired
|
||||
RedisTemplate redisTemplate;
|
||||
@Autowired
|
||||
private ScenicAccountMapper scenicAccountMapper;
|
||||
@Autowired
|
||||
private AdminUserMapper adminUserMapper;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
@@ -68,10 +83,22 @@ public class AuthInterceptor implements HandlerInterceptor {
|
||||
JwtInfo jwtInfo;
|
||||
try {
|
||||
jwtInfo = JwtTokenUtil.parsingToken(token);
|
||||
// LocalDateTime expireTime = jwtInfo.getExpireTime();
|
||||
// if (LocalDateTime.now(ZoneId.systemDefault()).isAfter(expireTime)) {
|
||||
// throw new TokenExpireException("token过期");
|
||||
// }
|
||||
if (StringUtils.equals(jwtInfo.getRoleId(), MERCHANT.type)) {
|
||||
Long merchantId = jwtInfo.getUserId();
|
||||
ScenicAccountEntity account = scenicAccountMapper.findAccountById(merchantId.toString());
|
||||
LocalDateTime expireTime = jwtInfo.getExpireTime();
|
||||
if (account.getUpdateTime().toInstant().getEpochSecond() != expireTime.atZone(ZoneId.systemDefault()).toEpochSecond()) {
|
||||
throw new TokenExpireException("token过期");
|
||||
}
|
||||
}
|
||||
if (StringUtils.equals(jwtInfo.getRoleId(), ADMIN.type)) {
|
||||
Long adminId = jwtInfo.getUserId();
|
||||
LoginEntity account = adminUserMapper.getById(adminId);
|
||||
LocalDateTime expireTime = jwtInfo.getExpireTime();
|
||||
if (account.getUpdateAt().toInstant().getEpochSecond() != expireTime.atZone(ZoneId.systemDefault()).toEpochSecond()) {
|
||||
throw new TokenExpireException("token过期");
|
||||
}
|
||||
}
|
||||
BaseContextHandler.setToken(token);
|
||||
BaseContextHandler.setName(jwtInfo.getName());
|
||||
BaseContextHandler.setUserId(String.valueOf(jwtInfo.getUserId()));
|
||||
|
@@ -25,4 +25,6 @@ public interface AdminUserMapper {
|
||||
int updatePassword(UpdatePasswordReqVO updatePasswordReqVO);
|
||||
|
||||
String getPasswordByAccount(@Param("id")String id);
|
||||
|
||||
LoginEntity getById(Long id);
|
||||
}
|
||||
|
14
src/main/java/com/ycwl/basic/mapper/AioDeviceMapper.java
Normal file
14
src/main/java/com/ycwl/basic/mapper/AioDeviceMapper.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.ycwl.basic.mapper;
|
||||
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceBannerEntity;
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceEntity;
|
||||
import com.ycwl.basic.model.aio.entity.AioDevicePriceConfigEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AioDeviceMapper {
|
||||
AioDeviceEntity getById(Long id);
|
||||
AioDeviceEntity getByKey(String key);
|
||||
List<AioDeviceBannerEntity> getBannerByDeviceId(Long deviceId);
|
||||
AioDevicePriceConfigEntity getPriceConfigByDeviceId(Long deviceId);
|
||||
}
|
11
src/main/java/com/ycwl/basic/mapper/ExtraDeviceMapper.java
Normal file
11
src/main/java/com/ycwl/basic/mapper/ExtraDeviceMapper.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.ycwl.basic.mapper;
|
||||
|
||||
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ExtraDeviceMapper {
|
||||
List<DeviceRespVO> listExtraDeviceByScenicId(Long scenicId);
|
||||
}
|
@@ -2,6 +2,7 @@ package com.ycwl.basic.mapper;
|
||||
|
||||
import com.ycwl.basic.model.pc.menu.MenuNode;
|
||||
import com.ycwl.basic.model.pc.menu.entity.MenuEntity;
|
||||
import com.ycwl.basic.model.pc.role.resp.RolePermissionResp;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -15,18 +16,6 @@ public interface MenuMapper {
|
||||
* @return
|
||||
*/
|
||||
int deleteRoleMenuByRoleId(@Param("id")String roleId);
|
||||
int addRoleMenu(@Param("id")String roleId,@Param("list") List<Integer> list);
|
||||
int add(MenuEntity menuEntity);
|
||||
|
||||
List<MenuNode>getListByType(@Param("type")Integer type);
|
||||
|
||||
int update(MenuEntity menuEntity);
|
||||
int deleteById(@Param("id")Long id);
|
||||
|
||||
/**
|
||||
* 根据菜单id删除角色菜单
|
||||
* @param menuId
|
||||
* @return
|
||||
*/
|
||||
int deleteRoleMenuByMenuId(@Param("id")String menuId);
|
||||
int addRoleMenu(@Param("id")String roleId,@Param("menuStr") String menuStr, @Param("permStr") String permStr);
|
||||
RolePermissionResp getPermissionByRoleId(Long roleId);
|
||||
}
|
||||
|
@@ -21,4 +21,6 @@ public interface RenderWorkerMapper {
|
||||
int updateStatus(Long id);
|
||||
|
||||
RenderWorkerEntity findByAccessKey(String accessKey);
|
||||
|
||||
int updateHost(Long id, RenderWorkerEntity status);
|
||||
}
|
||||
|
@@ -57,6 +57,7 @@ public interface SourceMapper {
|
||||
int addRelations(List<MemberSourceEntity> list);
|
||||
|
||||
int updateRelation(MemberSourceEntity memberSourceEntity);
|
||||
int freeRelations(List<Long> ids, int type);
|
||||
|
||||
List<SourceRespVO> queryByRelation(SourceReqQuery sourceReqQuery);
|
||||
|
||||
@@ -68,6 +69,7 @@ public interface SourceMapper {
|
||||
List<SourceEntity> listVideoByFaceRelation(Long memberId, Long faceId);
|
||||
|
||||
List<SourceEntity> listImageByFaceRelation(Long memberId, Long faceId);
|
||||
List<MemberSourceEntity> listByFaceRelation(Long memberId, Long faceId, Integer type);
|
||||
|
||||
SourceEntity getEntity(Long id);
|
||||
|
||||
|
@@ -0,0 +1,35 @@
|
||||
package com.ycwl.basic.model.aio.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 智能设备横幅实体类
|
||||
*/
|
||||
@Data
|
||||
public class AioDeviceBannerEntity {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 横幅URL
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 状态 (0-禁用 1-启用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createAt;
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package com.ycwl.basic.model.aio.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 智能设备实体类
|
||||
*/
|
||||
@Data
|
||||
public class AioDeviceEntity {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 景区ID
|
||||
*/
|
||||
private Long scenicId;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 接入密钥
|
||||
*/
|
||||
private String accessKey;
|
||||
|
||||
/**
|
||||
* 状态 (0-离线 1-在线)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createAt;
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package com.ycwl.basic.model.aio.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class AioDevicePriceConfigEntity {
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long id;
|
||||
private BigDecimal eachPrice;
|
||||
private Integer status;
|
||||
private Date createAt;
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package com.ycwl.basic.model.aio.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class AioDeviceCreateOrderReq {
|
||||
private Long faceId;
|
||||
private String payType;
|
||||
private List<AioDeviceOrderItem> items;
|
||||
|
||||
@Data
|
||||
public static class AioDeviceOrderItem {
|
||||
private Long goodsId;
|
||||
private Integer count;
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package com.ycwl.basic.model.aio.resp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AioDeviceCreateOrderResp {
|
||||
private boolean skipPay;
|
||||
private Long orderId;
|
||||
private String payCode;
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package com.ycwl.basic.model.aio.resp;
|
||||
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceBannerEntity;
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class AioDeviceInfoResp {
|
||||
private AioDeviceEntity info;
|
||||
private List<AioDeviceBannerEntity> banners;
|
||||
}
|
@@ -19,6 +19,8 @@ import java.util.Date;
|
||||
public class GoodsDetailVO {
|
||||
@ApiModelProperty("商品名称")
|
||||
private String goodsName;
|
||||
@ApiModelProperty("人脸id")
|
||||
private Long faceId;
|
||||
@ApiModelProperty("景区id")
|
||||
private Long scenicId;
|
||||
@ApiModelProperty("景区名称")
|
||||
@@ -41,6 +43,7 @@ public class GoodsDetailVO {
|
||||
private Integer isBuy;
|
||||
private Integer isFree;
|
||||
private Integer parts;
|
||||
private Integer sort;
|
||||
public Integer getSourceType() {
|
||||
return goodsType;
|
||||
}
|
||||
|
@@ -0,0 +1,28 @@
|
||||
package com.ycwl.basic.model.mobile.scenic.account;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/13 9:44
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("景区账号登录响应类")
|
||||
public class ScenicLoginOldRespVO {
|
||||
private Long id;
|
||||
@ApiModelProperty("景区id")
|
||||
private Long scenicId;
|
||||
@ApiModelProperty("是否是超级管理员")
|
||||
private Integer isSuper;
|
||||
@ApiModelProperty("账号名称")
|
||||
private String name;
|
||||
@ApiModelProperty("账号")
|
||||
private String account;
|
||||
@ApiModelProperty("1启用 0禁用")
|
||||
private Integer status;
|
||||
private String token;
|
||||
}
|
@@ -34,4 +34,6 @@ public class ContentPageVO {
|
||||
private Integer isBuy;
|
||||
private BigDecimal duration;
|
||||
private Integer goodsType;
|
||||
private int freeCount;
|
||||
private Integer sort;
|
||||
}
|
||||
|
@@ -2,12 +2,15 @@ package com.ycwl.basic.model.pc.adminUser.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class LoginEntity {
|
||||
private Long staffId;
|
||||
private String staffName;
|
||||
private String account;
|
||||
private String password;
|
||||
private String roleId;
|
||||
private Long roleId;
|
||||
private String typeName;
|
||||
private Date updateAt;
|
||||
}
|
||||
|
@@ -17,6 +17,5 @@ public class LoginRespVO {
|
||||
private String name;
|
||||
@ApiModelProperty(value = "角色名")
|
||||
private String typeName;
|
||||
@ApiModelProperty(value = "菜单列表")
|
||||
private List<MenuNode> menuNodeList;
|
||||
private boolean superAdmin;
|
||||
}
|
||||
|
@@ -1,11 +1,15 @@
|
||||
package com.ycwl.basic.model.pc.device.entity;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@TableName("device_config")
|
||||
@@ -62,4 +66,18 @@ public class DeviceConfigEntity {
|
||||
private Integer videoFree;
|
||||
private Long pairDevice;
|
||||
private String videoCrop;
|
||||
private String cropConfig;
|
||||
|
||||
public List<DeviceCropConfig> _getCropConfig() {
|
||||
if (cropConfig == null || cropConfig.isEmpty()) {
|
||||
return Collections.singletonList(new DeviceCropConfig());
|
||||
}
|
||||
if (StringUtils.startsWith(cropConfig, "{")) {
|
||||
return Collections.singletonList(JSON.parseObject(cropConfig, DeviceCropConfig.class));
|
||||
}
|
||||
if (StringUtils.startsWith(cropConfig, "[")) {
|
||||
return JSON.parseArray(cropConfig, DeviceCropConfig.class);
|
||||
}
|
||||
return Collections.singletonList(new DeviceCropConfig());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,13 @@
|
||||
package com.ycwl.basic.model.pc.device.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeviceCropConfig {
|
||||
// 截图类型 0:无截图 1:固定截图 2:按人脸位置截图
|
||||
private int cropType;
|
||||
private Integer targetWidth;
|
||||
private Integer targetHeight;
|
||||
private Integer targetX;
|
||||
private Integer targetY;
|
||||
}
|
@@ -26,5 +26,6 @@ public class OrderItemEntity {
|
||||
* 商品ID,goods_type=1关联video.id,=2关联source.id
|
||||
*/
|
||||
private Long goodsId;
|
||||
private int count = 1;
|
||||
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ public class AddOrUpdateRoleReqVO {
|
||||
private String name;
|
||||
// @ApiModelProperty(value = "0系统角色 1业务角色")
|
||||
// private Integer type;
|
||||
@ApiModelProperty(value = "菜单ID列表")
|
||||
private List<Integer> menuIdList;
|
||||
private List<String> permissions;
|
||||
private List<String> menus;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,10 @@
|
||||
package com.ycwl.basic.model.pc.role.resp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RolePermissionResp {
|
||||
private String roleId;
|
||||
private String permStr;
|
||||
private String menuStr;
|
||||
}
|
@@ -93,4 +93,7 @@ public class ScenicConfigEntity {
|
||||
private String videoSourcePackHint;
|
||||
|
||||
private String extraNotificationTime;
|
||||
|
||||
private Integer photoFreeNum;
|
||||
private Integer videoFreeNum;
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ import com.wechat.pay.java.service.payments.jsapi.model.Payer;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.SettleInfo;
|
||||
import com.wechat.pay.java.service.payments.model.Transaction;
|
||||
import com.wechat.pay.java.service.refund.RefundService;
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
@@ -55,6 +56,7 @@ import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_NONCE;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SERIAL;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SIGNATURE;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_TIMESTAMP;
|
||||
import static com.wechat.pay.java.service.refund.model.Status.PROCESSING;
|
||||
import static com.wechat.pay.java.service.refund.model.Status.SUCCESS;
|
||||
|
||||
public class WxMpPayAdapter implements IPayAdapter {
|
||||
@@ -66,6 +68,9 @@ public class WxMpPayAdapter implements IPayAdapter {
|
||||
public WxMpPayAdapter(WxMpPayConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
public WxMpPayConfig _config() {
|
||||
return config;
|
||||
}
|
||||
@Override
|
||||
public void loadConfig(Map<String, String> _config) {
|
||||
this.config = new WxMpPayConfig();
|
||||
@@ -77,12 +82,15 @@ public class WxMpPayAdapter implements IPayAdapter {
|
||||
this.config.setWxPublicKey(_config.get("wxPublicKey"));
|
||||
this.config.setWxPublicKeyId(_config.get("wxPublicKeyId"));
|
||||
this.config.setApiV3Key(_config.get("apiV3Key"));
|
||||
if (_config.containsKey("enableProfitSharing")) {
|
||||
this.config.setEnableProfitSharing(_config.get("enableProfitSharing").equals("true"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config clientConfig;
|
||||
|
||||
private Config getConfig() {
|
||||
public Config getConfig() {
|
||||
if (clientConfig == null) {
|
||||
if (StringUtils.isNotBlank(config.getWxPublicKeyId())) {
|
||||
clientConfig = new RSAPublicKeyConfig.Builder()
|
||||
@@ -126,6 +134,9 @@ public class WxMpPayAdapter implements IPayAdapter {
|
||||
Payer payer = new Payer();
|
||||
payer.setOpenid(request.getUserIdentify());
|
||||
prepayRequest.setPayer(payer);
|
||||
SettleInfo settleInfo = new SettleInfo();
|
||||
settleInfo.setProfitSharing(config.isEnableProfitSharing());
|
||||
prepayRequest.setSettleInfo(settleInfo);
|
||||
PrepayResponse response = service.prepay(prepayRequest);
|
||||
resp.setSuccess(true);
|
||||
resp.setSkipPay(false);
|
||||
@@ -265,7 +276,7 @@ public class WxMpPayAdapter implements IPayAdapter {
|
||||
createRequest.setAmount(amountReq);
|
||||
createRequest.setNotifyUrl(request.getNotifyUrl());
|
||||
Refund refund = service.create(createRequest);
|
||||
if (refund.getStatus() == SUCCESS) {
|
||||
if (refund.getStatus() == SUCCESS || refund.getStatus() == PROCESSING) {
|
||||
resp.setSuccess(true);
|
||||
resp.setRefundNo(refund.getOutRefundNo());
|
||||
} else {
|
||||
|
@@ -11,4 +11,5 @@ public class WxMpPayConfig {
|
||||
private String wxPublicKeyId;
|
||||
private String serialNumber;
|
||||
private String apiV3Key;
|
||||
private boolean enableProfitSharing;
|
||||
}
|
||||
|
@@ -8,6 +8,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -52,6 +54,21 @@ public class RenderWorkerRepository {
|
||||
return;
|
||||
}
|
||||
status.setUpdateAt(new Date());
|
||||
RenderWorkerEntity worker = new RenderWorkerEntity();
|
||||
worker.setCpuCount(status.getCpu_count());
|
||||
worker.setCpuUsage(status.getCpu_usage());
|
||||
// 上报的是字节,存储的是兆
|
||||
worker.setMemoryAvailable(status.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
|
||||
worker.setMemoryTotal(status.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
|
||||
|
||||
worker.setPlatform(status.getPlatform());
|
||||
worker.setRuntimeVersion(status.getRuntime_version());
|
||||
worker.setSupportFeature(String.join(",", status.getSupport_feature()));
|
||||
worker.setVersion(status.getVersion());
|
||||
worker.setUpdateAt(status.getUpdateAt());
|
||||
if (!redisTemplate.hasKey(key)) {
|
||||
mapper.updateHost(id, worker);
|
||||
}
|
||||
redisTemplate.opsForValue().set(key, JSONObject.toJSONString(status), 1, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,9 @@
|
||||
package com.ycwl.basic.service.aio;
|
||||
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceEntity;
|
||||
import com.ycwl.basic.model.aio.req.AioDeviceCreateOrderReq;
|
||||
import com.ycwl.basic.model.aio.resp.AioDeviceCreateOrderResp;
|
||||
|
||||
public interface AioDeviceService {
|
||||
AioDeviceCreateOrderResp createOrder(AioDeviceEntity aioDevice, AioDeviceCreateOrderReq req);
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
package com.ycwl.basic.service.aio.impl;
|
||||
|
||||
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
|
||||
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
|
||||
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
|
||||
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
|
||||
import com.ycwl.basic.enums.OrderStateEnum;
|
||||
import com.ycwl.basic.exception.BaseException;
|
||||
import com.ycwl.basic.mapper.AioDeviceMapper;
|
||||
import com.ycwl.basic.mapper.OrderMapper;
|
||||
import com.ycwl.basic.model.aio.entity.AioDeviceEntity;
|
||||
import com.ycwl.basic.model.aio.entity.AioDevicePriceConfigEntity;
|
||||
import com.ycwl.basic.model.aio.req.AioDeviceCreateOrderReq;
|
||||
import com.ycwl.basic.model.aio.resp.AioDeviceCreateOrderResp;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
|
||||
import com.ycwl.basic.model.pc.order.entity.OrderItemEntity;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.pay.adapter.WxMpPayAdapter;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.service.aio.AioDeviceService;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class AioDeviceServiceImpl implements AioDeviceService {
|
||||
@Autowired
|
||||
private AioDeviceMapper aioDeviceMapper;
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
@Autowired
|
||||
private FaceRepository faceRepository;
|
||||
@Autowired
|
||||
private OrderMapper orderMapper;
|
||||
|
||||
@Override
|
||||
public AioDeviceCreateOrderResp createOrder(AioDeviceEntity aioDevice, AioDeviceCreateOrderReq req) {
|
||||
// 询价
|
||||
AioDevicePriceConfigEntity config = aioDeviceMapper.getPriceConfigByDeviceId(aioDevice.getId());
|
||||
if (config == null) {
|
||||
throw new BaseException("询价失败");
|
||||
}
|
||||
if (req.getItems() == null || req.getItems().isEmpty()) {
|
||||
throw new BaseException("请选择商品");
|
||||
}
|
||||
FaceEntity face = faceRepository.getFace(req.getFaceId());
|
||||
if (face == null) {
|
||||
throw new BaseException("请选择人脸");
|
||||
}
|
||||
AioDeviceCreateOrderResp resp = new AioDeviceCreateOrderResp();
|
||||
int sum = req.getItems().stream().mapToInt(AioDeviceCreateOrderReq.AioDeviceOrderItem::getCount).sum();
|
||||
BigDecimal totalPrice = config.getEachPrice().multiply(new BigDecimal(sum));
|
||||
if (totalPrice.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
resp.setSkipPay(true);
|
||||
return resp;
|
||||
}
|
||||
OrderEntity order = new OrderEntity();
|
||||
Long orderId = SnowFlakeUtil.getLongId();
|
||||
order.setId(orderId);
|
||||
order.setMemberId(face.getMemberId());
|
||||
order.setFaceId(face.getId());
|
||||
order.setScenicId(face.getScenicId());
|
||||
order.setType(0);
|
||||
List<OrderItemEntity> orderItems = req.getItems().stream().map(item -> {
|
||||
OrderItemEntity orderItem = new OrderItemEntity();
|
||||
orderItem.setOrderId(orderId);
|
||||
orderItem.setGoodsId(item.getGoodsId());
|
||||
orderItem.setGoodsType(4);
|
||||
if (item.getCount() == null) {
|
||||
item.setCount(1);
|
||||
}
|
||||
orderItem.setCount(item.getCount());
|
||||
return orderItem;
|
||||
}).toList();
|
||||
order.setSlashPrice(totalPrice);
|
||||
order.setPrice(totalPrice);
|
||||
order.setPayPrice(totalPrice);
|
||||
order.setStatus(OrderStateEnum.UNPAID.getState());
|
||||
orderMapper.add(order);
|
||||
int addOrderItems = orderMapper.addOrderItems(orderItems);
|
||||
// 支付
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(aioDevice.getScenicId());
|
||||
if (scenicPayAdapter instanceof WxMpPayAdapter adapter) {
|
||||
NativePayService service = new NativePayService.Builder().config(adapter.getConfig()).build();
|
||||
PrepayRequest request = new PrepayRequest();
|
||||
request.setAppid(adapter._config().getAppId());
|
||||
request.setMchid(adapter._config().getMerchantId());
|
||||
request.setDescription("打印订单");
|
||||
request.setOutTradeNo(SnowFlakeUtil.getId());
|
||||
request.setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/"+aioDevice.getScenicId()+"/payNotify");
|
||||
Amount amount = new Amount();
|
||||
amount.setTotal(totalPrice.multiply(new BigDecimal(100)).intValue());
|
||||
request.setAmount(amount);
|
||||
PrepayResponse response = service.prepay(request);
|
||||
resp.setPayCode(response.getCodeUrl());
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
}
|
@@ -29,6 +29,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.APP_USER;
|
||||
|
||||
/**
|
||||
* @Author:songmingsong
|
||||
*/
|
||||
@@ -116,6 +118,7 @@ public class AppMemberServiceImpl implements AppMemberService {
|
||||
jwtInfo.setUserId(memberRespVO.getId());
|
||||
jwtInfo.setName(memberRespVO.getNickname());
|
||||
jwtInfo.setPhone(memberRespVO.getPhone());
|
||||
jwtInfo.setRoleId(APP_USER.type);
|
||||
|
||||
String jwt = jwtTokenUtil.generateToken(jwtInfo);
|
||||
Map<String, Object> resMap = new HashMap<>();
|
||||
|
@@ -11,19 +11,24 @@ import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.service.mobile.AppScenicService;
|
||||
import com.ycwl.basic.service.pc.ScenicAccountService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
@@ -46,6 +51,12 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
private JwtTokenUtil jwtTokenUtil;
|
||||
@Autowired
|
||||
private ScenicAccountService scenicAccountService;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
private ExtraDeviceMapper extraDeviceMapper;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
@Override
|
||||
public ApiResponse<PageInfo<ScenicAppVO>> pageQuery(ScenicReqQuery scenicReqQuery) {
|
||||
@@ -88,7 +99,7 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
jwtInfo.setAccount(scenicAccount.getAccount());
|
||||
jwtInfo.setUserId(scenicAccount.getId());
|
||||
jwtInfo.setRoleId(MERCHANT.type);
|
||||
String token = jwtTokenUtil.generateToken(jwtInfo);
|
||||
String token = jwtTokenUtil.generateToken(jwtInfo, scenicAccount.getUpdateTime());
|
||||
|
||||
ScenicLoginRespVO scenicLoginRespVO = new ScenicLoginRespVO();
|
||||
BeanUtil.copyProperties(scenicAccount,scenicLoginRespVO);
|
||||
@@ -105,6 +116,40 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
@Override
|
||||
public ApiResponse<List<DeviceRespVO>> getDevices(Long scenicId) {
|
||||
List<DeviceRespVO> deviceRespVOList = deviceMapper.listByScenicIdWithWVP(scenicId);
|
||||
for (DeviceRespVO deviceRespVO : deviceRespVOList) {
|
||||
DeviceEntity onlineStatus = deviceRepository.getOnlineStatus(deviceRespVO.getId());
|
||||
if (onlineStatus != null) {
|
||||
deviceRespVO.setUpdateAt(onlineStatus.getKeepaliveAt());
|
||||
deviceRespVO.setKeepaliveAt(onlineStatus.getKeepaliveAt());
|
||||
if (new Date().getTime() - onlineStatus.getKeepaliveAt().getTime() > 300000) {
|
||||
deviceRespVO.setOnline(0);
|
||||
} else {
|
||||
deviceRespVO.setOnline(onlineStatus.getOnline());
|
||||
}
|
||||
} else {
|
||||
deviceRespVO.setOnline(0);
|
||||
deviceRespVO.setKeepaliveAt(null);
|
||||
deviceRespVO.setUpdateAt(null);
|
||||
}
|
||||
}
|
||||
List<DeviceRespVO> extraDeviceList = extraDeviceMapper.listExtraDeviceByScenicId(scenicId);
|
||||
for (DeviceRespVO deviceRespVO : extraDeviceList) {
|
||||
if (redisTemplate.hasKey("ext_device:online:"+deviceRespVO.getNo())) {
|
||||
String onlineTs = redisTemplate.opsForValue().get("ext_device:online:"+deviceRespVO.getNo());
|
||||
if (!StringUtils.isNumeric(onlineTs)) {
|
||||
deviceRespVO.setOnline(0);
|
||||
continue;
|
||||
}
|
||||
Long ts = Long.parseLong(onlineTs);
|
||||
Date keepaliveAt = new Date(ts*1000);
|
||||
deviceRespVO.setUpdateAt(keepaliveAt);
|
||||
deviceRespVO.setKeepaliveAt(keepaliveAt);
|
||||
deviceRespVO.setOnline(keepaliveAt.getTime() > System.currentTimeMillis()-1000*60*5 ? 1 : 0);
|
||||
} else {
|
||||
deviceRespVO.setOnline(0);
|
||||
}
|
||||
}
|
||||
deviceRespVOList.addAll(0, extraDeviceList);
|
||||
return ApiResponse.success(deviceRespVOList);
|
||||
}
|
||||
}
|
||||
|
@@ -370,14 +370,14 @@ public class AppStatisticsServiceImpl implements AppStatisticsService {
|
||||
//当前周期的推送订阅人数
|
||||
vo.setNowPushOfPeopleNum(data.getPushOfMemberNum());
|
||||
//当前周期的预览视频人数
|
||||
vo.setNowPreviewVideoOfPeopleNum(data.getPreviewOfVideoNum());
|
||||
vo.setNowPreviewVideoOfPeopleNum(data.getPreviewVideoOfMemberNum());
|
||||
}else if(cycle==2){
|
||||
//上一个周期的扫码访问人数
|
||||
vo.setPreviousScanCodeOfPeopleNum(data.getScanCodeVisitorOfMemberNum());
|
||||
//上一个周期的推送订阅人数
|
||||
vo.setPreviousPushOfPeopleNum(data.getPushOfMemberNum());
|
||||
//上一个周期的预览视频人数
|
||||
vo.setPreviousPreviewVideoOfPeopleNum(data.getPreviewOfVideoNum());
|
||||
vo.setPreviousPreviewVideoOfPeopleNum(data.getPreviewVideoOfMemberNum());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -75,8 +75,6 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
@Autowired
|
||||
private ScenicMapper scenicMapper;
|
||||
@Autowired
|
||||
private FaceMapper faceMapper;
|
||||
@Autowired
|
||||
private TemplateRepository templateRepository;
|
||||
@@ -87,8 +85,6 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
@Autowired
|
||||
private OrderRepository orderRepository;
|
||||
@Autowired
|
||||
private OrderBiz orderBiz;
|
||||
@Autowired
|
||||
private FaceRepository faceRepository;
|
||||
@@ -98,10 +94,18 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
private DeviceRepository deviceRepository;
|
||||
|
||||
public ApiResponse<List<GoodsPageVO>> goodsList(GoodsReqQuery query) {
|
||||
Long scenicId = query.getScenicId();
|
||||
if (query.getFaceId() != null) {
|
||||
FaceEntity face = faceRepository.getFace(query.getFaceId());
|
||||
if (face == null) {
|
||||
return ApiResponse.success(Collections.emptyList());
|
||||
}
|
||||
scenicId = face.getScenicId();
|
||||
}
|
||||
//查询原素材
|
||||
List<GoodsPageVO> goodsList = new ArrayList<>();
|
||||
VideoReqQuery videoReqQuery = new VideoReqQuery();
|
||||
videoReqQuery.setScenicId(query.getScenicId());
|
||||
videoReqQuery.setScenicId(scenicId);
|
||||
videoReqQuery.setIsBuy(query.getIsBuy());
|
||||
videoReqQuery.setFaceId(query.getFaceId());
|
||||
videoReqQuery.setMemberId(Long.valueOf(BaseContextHandler.getUserId()));
|
||||
@@ -121,25 +125,21 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
});
|
||||
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setScenicId(query.getScenicId());
|
||||
sourceReqQuery.setScenicId(scenicId);
|
||||
sourceReqQuery.setIsBuy(query.getIsBuy());
|
||||
sourceReqQuery.setFaceId(query.getFaceId());
|
||||
sourceReqQuery.setMemberId(Long.valueOf(BaseContextHandler.getUserId()));
|
||||
//查询源素材
|
||||
List<SourceRespVO> sourceList = sourceMapper.queryByRelation(sourceReqQuery);
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(query.getScenicId());
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
List<GoodsPageVO> sourceGoods = sourceList.stream().collect(Collectors.groupingBy(SourceRespVO::getFaceId)).entrySet().stream().flatMap((faceEntry) -> {
|
||||
Long faceId = faceEntry.getKey();
|
||||
List<SourceRespVO> goods = faceEntry.getValue();
|
||||
return goods.stream().collect(Collectors.groupingBy(SourceRespVO::getType)).keySet().stream().filter(type -> {
|
||||
if (Integer.valueOf(1).equals(type)) {
|
||||
if (Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
|
||||
return false;
|
||||
}
|
||||
return !Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo());
|
||||
} else if (Integer.valueOf(2).equals(type)) {
|
||||
if (Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage())) {
|
||||
return false;
|
||||
}
|
||||
return !Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage());
|
||||
}
|
||||
return true;
|
||||
}).map(type -> {
|
||||
@@ -156,7 +156,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsPageVO.setScenicId(query.getScenicId());
|
||||
return goodsPageVO;
|
||||
});
|
||||
}).collect(Collectors.toList());
|
||||
}).toList();
|
||||
if (!sourceGoods.isEmpty()) {
|
||||
if (goodsList.size() > 2) {
|
||||
goodsList.addAll(2, sourceGoods);
|
||||
@@ -175,11 +175,11 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
}
|
||||
Integer sourceType = query.getSourceType();
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setScenicId(query.getScenicId());
|
||||
sourceReqQuery.setScenicId(face.getScenicId());
|
||||
sourceReqQuery.setIsBuy(query.getIsBuy());
|
||||
sourceReqQuery.setMemberId(face.getMemberId());
|
||||
sourceReqQuery.setType(sourceType);
|
||||
sourceReqQuery.setFaceId(query.getFaceId());
|
||||
sourceReqQuery.setFaceId(face.getId());
|
||||
List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery);
|
||||
List<GoodsDetailVO> goodsDetailVOList = new ArrayList<>();
|
||||
|
||||
@@ -195,6 +195,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
int i=1;
|
||||
for (SourceRespVO sourceRespVO : list) {
|
||||
GoodsDetailVO goodsDetailVO = new GoodsDetailVO();
|
||||
goodsDetailVO.setFaceId(sourceRespVO.getFaceId());
|
||||
goodsDetailVO.setGoodsId(sourceRespVO.getId());
|
||||
String shootingTime = DateUtil.format(sourceRespVO.getCreateTime(), "yyyy.MM.dd HH:mm:ss");
|
||||
if (i < 10) {
|
||||
@@ -205,6 +206,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsDetailVO.setScenicId(sourceRespVO.getScenicId());
|
||||
goodsDetailVO.setScenicName(sourceRespVO.getScenicName());
|
||||
goodsDetailVO.setGoodsType(sourceType);
|
||||
goodsDetailVO.setFaceId(face.getId());
|
||||
goodsDetailVO.setGoodsId(sourceRespVO.getId());
|
||||
goodsDetailVO.setIsFree(sourceRespVO.getIsFree());
|
||||
goodsDetailVO.setIsBuy(sourceRespVO.getIsBuy());
|
||||
@@ -277,6 +279,9 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
}
|
||||
}
|
||||
TaskEntity task = videoTaskRepository.getTaskById(videoRespVO.getTaskId());
|
||||
if (task == null) {
|
||||
return ApiResponse.fail("该vlog不存在或已失效");
|
||||
}
|
||||
JSONObject paramJson = JSON.parseObject(task.getTaskParams());
|
||||
AtomicInteger deviceCount = new AtomicInteger();
|
||||
goodsDetailVO.setShotTime(taskTaskService.getTaskShotDate(task.getId()));
|
||||
@@ -511,11 +516,11 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
}
|
||||
Integer sourceType = query.getSourceType();
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setScenicId(query.getScenicId());
|
||||
sourceReqQuery.setScenicId(face.getScenicId());
|
||||
sourceReqQuery.setIsBuy(query.getIsBuy());
|
||||
sourceReqQuery.setMemberId(face.getMemberId());
|
||||
sourceReqQuery.setType(sourceType);
|
||||
sourceReqQuery.setFaceId(query.getFaceId());
|
||||
sourceReqQuery.setFaceId(face.getId());
|
||||
List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery);
|
||||
if (!Integer.valueOf(2).equals(query.getSourceType())) {
|
||||
return list.stream().map(source -> {
|
||||
@@ -535,7 +540,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsUrlVO.setCreateTime(source.getCreateTime());
|
||||
return goodsUrlVO;
|
||||
}).collect(Collectors.toList());
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), query.getScenicId(), query.getSourceType(), query.getFaceId());
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), query.getSourceType(), face.getId());
|
||||
if (!isBuy.isBuy()) {
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
|
||||
if (scenicConfig != null && ((scenicConfig.getAntiScreenRecordType() & 2) == 0)) {
|
||||
@@ -607,7 +612,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
sourceReqQuery.setFaceId(query.getFaceId());
|
||||
List<SourceRespVO> list = sourceMapper.listUser(sourceReqQuery);
|
||||
if (query.getGoodsId() != null) {
|
||||
list = list.stream().filter(source -> source.getId().equals(query.getGoodsId())).collect(Collectors.toList());
|
||||
list = list.stream().filter(source -> source.getId().equals(query.getGoodsId())).toList();
|
||||
}
|
||||
if (!Integer.valueOf(2).equals(query.getSourceType())) {
|
||||
return list.stream().map(source -> {
|
||||
@@ -628,8 +633,8 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
}
|
||||
return true;
|
||||
}).count();
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), query.getSourceType(), face.getId());
|
||||
if (count > 0) {
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), query.getScenicId(), query.getSourceType(), query.getFaceId());
|
||||
if (!isBuy.isBuy()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -648,7 +653,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
log.warn("未配置小程序参数,无法生成二维码");
|
||||
return defaultUrlList;
|
||||
}
|
||||
if (scenicConfig != null && scenicConfig.getWatermarkType() != null) {
|
||||
if (scenicConfig != null && scenicConfig.getWatermarkType() != null && !isBuy.isBuy()) {
|
||||
ImageWatermarkOperatorEnum type = ImageWatermarkOperatorEnum.getByCode(scenicConfig.getWatermarkType());
|
||||
if (type != null) {
|
||||
IStorageAdapter adapter;
|
||||
@@ -662,8 +667,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
List<SourceWatermarkEntity> watermarkEntityList = sourceMapper.listSourceWatermark(list.stream().map(SourceRespVO::getId).collect(Collectors.toList()), face.getId(), type.getType());
|
||||
File qrcode = new File("qrcode_"+face.getId()+".jpg");
|
||||
try {
|
||||
String urlLink = WxMpUtil.generateUrlLink(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), "pages/videoSynthesis/index", "scenicId=" + face.getScenicId() + "&faceId=" + face.getId());
|
||||
QrCodeUtil.generate(urlLink + "?cq=", 300, 300, qrcode);
|
||||
WxMpUtil.generateUnlimitedWXAQRCode(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), "pages/videoSynthesis/from_face", face.getId().toString(), qrcode);
|
||||
} catch (Exception e) {
|
||||
log.error("generateWXQRCode error", e);
|
||||
return defaultUrlList;
|
||||
@@ -733,7 +737,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
}
|
||||
Integer sourceType = query.getSourceType();
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setScenicId(query.getScenicId());
|
||||
sourceReqQuery.setScenicId(face.getScenicId());
|
||||
sourceReqQuery.setIsBuy(query.getIsBuy());
|
||||
sourceReqQuery.setMemberId(face.getMemberId());
|
||||
sourceReqQuery.setType(sourceType);
|
||||
|
@@ -36,4 +36,6 @@ public interface FaceService {
|
||||
List<ContentPageVO> faceContentList(Long faceId);
|
||||
|
||||
ApiResponse<List<ContentPageVO>> contentListUseDefaultFace();
|
||||
|
||||
void bindFace(Long faceId, Long userId);
|
||||
}
|
||||
|
@@ -1,18 +0,0 @@
|
||||
package com.ycwl.basic.service.pc;
|
||||
|
||||
import com.ycwl.basic.model.pc.menu.MenuNode;
|
||||
import com.ycwl.basic.model.pc.menu.entity.MenuEntity;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/3 10:40
|
||||
*/
|
||||
public interface MenuService {
|
||||
ApiResponse<List<MenuNode>> list(Integer type);
|
||||
ApiResponse<Integer> add(MenuEntity menu);
|
||||
ApiResponse<Integer> update(MenuEntity menu);
|
||||
ApiResponse<Integer> deleteById(Long id);
|
||||
}
|
@@ -4,11 +4,14 @@ import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO;
|
||||
import com.ycwl.basic.model.pc.role.req.RoleListReqVO;
|
||||
import com.ycwl.basic.model.pc.role.resp.RoleListRespVO;
|
||||
import com.ycwl.basic.model.pc.role.resp.RolePermissionResp;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RoleService {
|
||||
RolePermissionResp getPermissionByRoleId(Long roleId);
|
||||
|
||||
ApiResponse<PageInfo<RoleListRespVO>> pageQuery(RoleListReqVO roleListReqVO);
|
||||
ApiResponse list(RoleListReqVO roleListReqVO);
|
||||
ApiResponse addOrUpdate(AddOrUpdateRoleReqVO addOrUpdateRoleReqVO);
|
||||
|
@@ -21,4 +21,5 @@ public interface SourceService {
|
||||
ApiResponse<Integer> update(SourceEntity source);
|
||||
|
||||
ApiResponse cutVideo(Long id);
|
||||
ApiResponse<String> uploadAndUpdateUrl(Long id, org.springframework.web.multipart.MultipartFile file);
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.ADMIN;
|
||||
import static com.ycwl.basic.constant.PermissionConstant.ROLE_STATUS;
|
||||
|
||||
|
||||
@@ -56,12 +57,17 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
|
||||
@Override
|
||||
public ApiResponse addOrUpdate(AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO) {
|
||||
addOrUpdateAdminUserReqVO.setPassword(DigestUtil.md5Hex(addOrUpdateAdminUserReqVO.getPassword()));
|
||||
if (StringUtils.isNotBlank(addOrUpdateAdminUserReqVO.getPassword())) {
|
||||
addOrUpdateAdminUserReqVO.setPassword(DigestUtil.md5Hex(addOrUpdateAdminUserReqVO.getPassword()));
|
||||
} else {
|
||||
addOrUpdateAdminUserReqVO.setPassword(null);
|
||||
}
|
||||
String id = addOrUpdateAdminUserReqVO.getId();
|
||||
if (StringUtils.isBlank(id)) {
|
||||
addOrUpdateAdminUserReqVO.setId(SnowFlakeUtil.getId());
|
||||
// String password = addOrUpdateAdminUserReqVO.getPassword();
|
||||
// addOrUpdateAdminUserReqVO.setPassword(password);
|
||||
if (StringUtils.isBlank(addOrUpdateAdminUserReqVO.getPassword())) {
|
||||
return ApiResponse.fail("密码不能为空");
|
||||
}
|
||||
int add = adminUserMapper.add(addOrUpdateAdminUserReqVO);
|
||||
if (add > 0) {
|
||||
return ApiResponse.success(null);
|
||||
@@ -105,7 +111,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
if (!login.getPassword().equals(DigestUtil.md5Hex(password))) {
|
||||
return ApiResponse.fail("账号不存在或密码错误");
|
||||
}
|
||||
String roleId = login.getRoleId();
|
||||
Long roleId = login.getRoleId();
|
||||
|
||||
Object roleObject = redisTemplate.opsForValue().get(ROLE_STATUS + roleId);
|
||||
|
||||
@@ -114,27 +120,12 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
throw new RoleStatusException("该角色下的账号已被封禁,请联系管理员");
|
||||
}
|
||||
}
|
||||
List<MenuNode> menuById = roleMapper.getMenuById(roleId);
|
||||
List<MenuNode> MenuList = new ArrayList<>();
|
||||
for (MenuNode item : menuById) {
|
||||
if ("-1".equals(item.getParentId())) {
|
||||
MenuList.add(item);
|
||||
}
|
||||
for (MenuNode item2 : menuById) {
|
||||
if (item2.getParentId().equals(item.getId())) {
|
||||
if (item.getChildrenList() == null) {
|
||||
item.setChildrenList(new ArrayList<>());
|
||||
}
|
||||
item.getChildrenList().add(item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
LoginRespVO loginRespVO = new LoginRespVO();
|
||||
String token = jwtTokenUtil.generateToken(new JwtInfo(login.getStaffName(), login.getStaffId(), roleId, login.getAccount(), login.getAccount(), null));
|
||||
String token = jwtTokenUtil.generateToken(new JwtInfo(login.getStaffName(), login.getStaffId(), ADMIN.type, login.getAccount(), login.getAccount(), null), login.getUpdateAt());
|
||||
loginRespVO.setToken(token);
|
||||
loginRespVO.setName(login.getStaffName());
|
||||
loginRespVO.setTypeName(login.getTypeName());
|
||||
loginRespVO.setMenuNodeList(MenuList);
|
||||
loginRespVO.setSuperAdmin(Long.valueOf(1L).equals(login.getStaffId()));
|
||||
return ApiResponse.success(loginRespVO);
|
||||
}
|
||||
|
||||
|
@@ -8,10 +8,7 @@ import com.ycwl.basic.biz.TemplateBiz;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.enums.StatisticEnum;
|
||||
import com.ycwl.basic.exception.BaseException;
|
||||
import com.ycwl.basic.facebody.FaceBodyFactory;
|
||||
import com.ycwl.basic.facebody.adapter.AliFaceBodyAdapter;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.mapper.StatisticsMapper;
|
||||
import com.ycwl.basic.mapper.FaceMapper;
|
||||
@@ -21,6 +18,7 @@ import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
|
||||
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
||||
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.face.req.FaceReqQuery;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
@@ -34,6 +32,7 @@ import com.ycwl.basic.model.pc.task.entity.TaskEntity;
|
||||
import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
|
||||
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
|
||||
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
@@ -45,6 +44,7 @@ import com.ycwl.basic.service.task.TaskService;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import com.ycwl.basic.task.VideoPieceGetter;
|
||||
import com.ycwl.basic.utils.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -52,11 +52,12 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -99,6 +100,8 @@ public class FaceServiceImpl implements FaceService {
|
||||
private VideoTaskRepository videoTaskRepository;
|
||||
@Autowired
|
||||
private TemplateBiz templateBiz;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
|
||||
@Override
|
||||
public ApiResponse<PageInfo<FaceRespVO>> pageQuery(FaceReqQuery faceReqQuery) {
|
||||
@@ -280,30 +283,72 @@ public class FaceServiceImpl implements FaceService {
|
||||
if (sampleListIds != null && !sampleListIds.isEmpty()) {// 匹配原片:照片
|
||||
List<SourceEntity> sourceEntities = sourceMapper.listBySampleIds(sampleListIds);
|
||||
List<MemberSourceEntity> memberSourceEntityList = sourceEntities.stream().map(sourceEntity -> {
|
||||
DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(sourceEntity.getDeviceId());
|
||||
MemberSourceEntity memberSourceEntity = new MemberSourceEntity();
|
||||
memberSourceEntity.setScenicId(face.getScenicId());
|
||||
memberSourceEntity.setFaceId(face.getId());
|
||||
memberSourceEntity.setMemberId(face.getMemberId());
|
||||
memberSourceEntity.setSourceId(sourceEntity.getId());
|
||||
memberSourceEntity.setType(sourceEntity.getType());
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), sourceEntity.getType(), faceEntity.getId());
|
||||
if (isBuy.isBuy()) { // 如果用户买过
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else if (isBuy.isFree()) { // 全免费逻辑
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else {
|
||||
memberSourceEntity.setIsBuy(0);
|
||||
memberSourceEntity.setIsFree(0);
|
||||
if (deviceConfig != null) {
|
||||
if (sourceEntity.getType() == 1) {
|
||||
if (Integer.valueOf(1).equals(deviceConfig.getVideoFree())) {
|
||||
memberSourceEntity.setIsFree(1);
|
||||
}
|
||||
} else if (sourceEntity.getType() == 2) {
|
||||
if (Integer.valueOf(1).equals(deviceConfig.getImageFree())) {
|
||||
memberSourceEntity.setIsFree(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return memberSourceEntity;
|
||||
}).collect(Collectors.toList());
|
||||
List<Long> freeSourceIds = new ArrayList<>();
|
||||
List<MemberSourceEntity> photoSource = memberSourceEntityList.stream().filter(item -> item.getIsFree() == 0).filter(item -> Integer.valueOf(2).equals(item.getType())).toList();
|
||||
if (isNew) {
|
||||
// 送照片逻辑
|
||||
if (scenicConfig != null && scenicConfig.getPhotoFreeNum() != null && scenicConfig.getPhotoFreeNum() > 0) {
|
||||
if (scenicConfig.getPhotoFreeNum() > photoSource.size()) {
|
||||
freeSourceIds.addAll(photoSource.stream().map(MemberSourceEntity::getSourceId).toList());
|
||||
} else {
|
||||
freeSourceIds.addAll(photoSource.stream().limit(scenicConfig.getPhotoFreeNum()).map(MemberSourceEntity::getSourceId).toList());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 重新切视频逻辑
|
||||
if (scenicConfig != null && !Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
|
||||
long videoCount = memberSourceEntityList.stream().filter(item -> item.getType().equals(1)).count();
|
||||
long photoCount = memberSourceEntityList.stream().filter(item -> item.getType().equals(2)).count();
|
||||
if (photoCount > videoCount) {
|
||||
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
||||
task.faceId = faceId;
|
||||
task.faceSampleIds = sampleListIds;
|
||||
task.templateId = null;
|
||||
task.memberId = face.getMemberId();
|
||||
task.callback = () -> {
|
||||
log.info("task callback: {}", task);
|
||||
};
|
||||
VideoPieceGetter.addTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!memberSourceEntityList.isEmpty()) {
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), memberSourceEntityList.getFirst().getType(), faceEntity.getId());
|
||||
for (MemberSourceEntity memberSourceEntity : memberSourceEntityList) {
|
||||
if (isBuy.isBuy()) { // 如果用户买过
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else if (isBuy.isFree()) { // 全免费逻辑
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else {
|
||||
memberSourceEntity.setIsBuy(0);
|
||||
}
|
||||
if (freeSourceIds.contains(memberSourceEntity.getSourceId())) {
|
||||
memberSourceEntity.setIsFree(1);
|
||||
}
|
||||
}
|
||||
sourceMapper.addRelations(memberSourceEntityList);
|
||||
taskTaskService.autoCreateTaskByFaceId(face.getId());
|
||||
// VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
||||
// task.faceId = face.getId();
|
||||
// task.faceSampleIds = sampleListIds;
|
||||
// task.memberId = face.getMemberId();
|
||||
// VideoPieceGetter.addTask(task);
|
||||
}
|
||||
}
|
||||
return scenicDbSearchResult;
|
||||
@@ -336,6 +381,7 @@ public class FaceServiceImpl implements FaceService {
|
||||
List<MemberVideoEntity> memberVideoEntityList = videoMapper.userFaceTemplateVideo(userId, faceId, contentPageVO.getTemplateId());
|
||||
contentPageVO.setGoodsType(0);
|
||||
contentPageVO.setContentType(1);
|
||||
contentPageVO.setSort(contentPageVO.getSort());
|
||||
if (!memberVideoEntityList.isEmpty()) {
|
||||
contentPageVO.setIsBuy(memberVideoEntityList.getFirst().getIsBuy());
|
||||
contentPageVO.setContentId(memberVideoEntityList.getFirst().getVideoId());
|
||||
@@ -375,6 +421,8 @@ public class FaceServiceImpl implements FaceService {
|
||||
ContentPageVO sourceImageContent = new ContentPageVO();
|
||||
sourceVideoContent.setName("录像集");
|
||||
sourceImageContent.setName("照片集");
|
||||
sourceVideoContent.setSort(9999);
|
||||
sourceImageContent.setSort(9999);
|
||||
sourceVideoContent.setScenicId(faceRespVO.getScenicId());
|
||||
sourceImageContent.setScenicId(faceRespVO.getScenicId());
|
||||
sourceVideoContent.setGoodsType(1);
|
||||
@@ -393,12 +441,14 @@ public class FaceServiceImpl implements FaceService {
|
||||
} else {
|
||||
sourceImageContent.setIsBuy(0);
|
||||
}
|
||||
List<SourceEntity> sourceEntities = sourceMapper.listImageByFaceRelation(faceRespVO.getMemberId(), faceId);
|
||||
if (!sourceEntities.isEmpty()) {
|
||||
List<MemberSourceEntity> relations = sourceMapper.listByFaceRelation(faceRespVO.getMemberId(), faceId, 2);
|
||||
if (!relations.isEmpty()) {
|
||||
sourceImageContent.setLockType(-1);
|
||||
} else {
|
||||
sourceImageContent.setLockType(1);
|
||||
}
|
||||
long freeCount = relations.stream().filter(entity -> Integer.valueOf(1).equals(entity.getIsFree())).count();
|
||||
sourceImageContent.setFreeCount((int) freeCount);
|
||||
contentList.add(sourceImageContent);
|
||||
}
|
||||
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
|
||||
@@ -410,12 +460,14 @@ public class FaceServiceImpl implements FaceService {
|
||||
} else {
|
||||
sourceVideoContent.setIsBuy(0);
|
||||
}
|
||||
List<SourceEntity> sourceEntities = sourceMapper.listVideoByFaceRelation(faceRespVO.getMemberId(), faceId);
|
||||
if (!sourceEntities.isEmpty()) {
|
||||
List<MemberSourceEntity> relations = sourceMapper.listByFaceRelation(faceRespVO.getMemberId(), faceId, 1);
|
||||
if (!relations.isEmpty()) {
|
||||
sourceVideoContent.setLockType(-1);
|
||||
} else {
|
||||
sourceVideoContent.setLockType(1);
|
||||
}
|
||||
long freeCount = relations.stream().filter(entity -> Integer.valueOf(1).equals(entity.getIsFree())).count();
|
||||
sourceVideoContent.setFreeCount((int) freeCount);
|
||||
contentList.add(sourceVideoContent);
|
||||
}
|
||||
sourceList.stream().collect(Collectors.groupingBy(SourceRespVO::getType)).forEach((type, list) -> {
|
||||
@@ -440,5 +492,10 @@ public class FaceServiceImpl implements FaceService {
|
||||
return ApiResponse.success(contentPageVOS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindFace(Long faceId, Long userId) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,78 +0,0 @@
|
||||
package com.ycwl.basic.service.pc.impl;
|
||||
|
||||
import com.ycwl.basic.mapper.MenuMapper;
|
||||
import com.ycwl.basic.model.pc.menu.MenuNode;
|
||||
import com.ycwl.basic.model.pc.menu.entity.MenuEntity;
|
||||
import com.ycwl.basic.service.pc.MenuService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/3 10:16
|
||||
*/
|
||||
@Service
|
||||
public class MenuServiceImpl implements MenuService {
|
||||
|
||||
@Autowired
|
||||
private MenuMapper menuMapper;
|
||||
|
||||
@Override
|
||||
public ApiResponse<List<MenuNode>> list(Integer type) {
|
||||
// if(type==null){
|
||||
// type=1;
|
||||
// }
|
||||
List<MenuNode> listByType = menuMapper.getListByType(type);
|
||||
List<MenuNode> MenuList = new ArrayList<>();
|
||||
for (MenuNode item :listByType) {
|
||||
if ("-1".equals(item.getParentId())) {
|
||||
MenuList.add(item);
|
||||
}
|
||||
for (MenuNode item2 : listByType) {
|
||||
if (item2.getParentId().equals(item.getId())) {
|
||||
if (item.getChildrenList() == null) {
|
||||
item.setChildrenList(new ArrayList<>());
|
||||
}
|
||||
item.getChildrenList().add(item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ApiResponse.success(MenuList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<Integer> add(MenuEntity menu) {
|
||||
menu.setId(SnowFlakeUtil.getId());
|
||||
int add = menuMapper.add(menu);
|
||||
if(add>0){
|
||||
return ApiResponse.success(add);
|
||||
}else {
|
||||
return ApiResponse.fail("添加失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<Integer> update(MenuEntity menu) {
|
||||
int update = menuMapper.update(menu);
|
||||
if(update>0){
|
||||
return ApiResponse.success(update);
|
||||
}else {
|
||||
return ApiResponse.fail("更新失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<Integer> deleteById(Long id) {
|
||||
int deleteById = menuMapper.deleteById(id);
|
||||
if(deleteById>0){
|
||||
return ApiResponse.success(deleteById);
|
||||
}else {
|
||||
return ApiResponse.fail("删除失败");
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@ import com.ycwl.basic.model.pc.menu.MenuNode;
|
||||
import com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO;
|
||||
import com.ycwl.basic.model.pc.role.req.RoleListReqVO;
|
||||
import com.ycwl.basic.model.pc.role.resp.RoleListRespVO;
|
||||
import com.ycwl.basic.model.pc.role.resp.RolePermissionResp;
|
||||
import com.ycwl.basic.service.pc.RoleService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
@@ -34,6 +35,11 @@ public class RoleServiceImpl implements RoleService {
|
||||
@Autowired
|
||||
RedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
public RolePermissionResp getPermissionByRoleId(Long roleId) {
|
||||
return menuMapper.getPermissionByRoleId(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<PageInfo<RoleListRespVO>> pageQuery(RoleListReqVO roleListReqVO) {
|
||||
PageHelper.startPage(roleListReqVO.getPageNum(),roleListReqVO.getPageSize());
|
||||
@@ -55,23 +61,22 @@ public class RoleServiceImpl implements RoleService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse addOrUpdate(AddOrUpdateRoleReqVO addOrUpdateRoleReqVO) {
|
||||
String id = addOrUpdateRoleReqVO.getId();
|
||||
public ApiResponse addOrUpdate(AddOrUpdateRoleReqVO vo) {
|
||||
String id = vo.getId();
|
||||
if(StringUtils.isBlank(id)){
|
||||
String roleId = SnowFlakeUtil.getId();
|
||||
addOrUpdateRoleReqVO.setId(roleId);
|
||||
if(roleMapper.add(addOrUpdateRoleReqVO)>0){
|
||||
if (addOrUpdateRoleReqVO.getMenuIdList() != null && !addOrUpdateRoleReqVO.getMenuIdList().isEmpty()) {
|
||||
menuMapper.addRoleMenu(roleId, addOrUpdateRoleReqVO.getMenuIdList());
|
||||
}
|
||||
vo.setId(roleId);
|
||||
if(roleMapper.add(vo)>0){
|
||||
String menuStr = StringUtils.join(vo.getMenus(), ",");
|
||||
String permStr = StringUtils.join(vo.getPermissions(), ",");
|
||||
menuMapper.addRoleMenu(roleId, menuStr, permStr);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
}else {
|
||||
if(roleMapper.update(addOrUpdateRoleReqVO)>0){
|
||||
menuMapper.deleteRoleMenuByRoleId(addOrUpdateRoleReqVO.getId());
|
||||
if (addOrUpdateRoleReqVO.getMenuIdList() != null && !addOrUpdateRoleReqVO.getMenuIdList().isEmpty()) {
|
||||
menuMapper.addRoleMenu(addOrUpdateRoleReqVO.getId(), addOrUpdateRoleReqVO.getMenuIdList());
|
||||
}
|
||||
if(roleMapper.update(vo)>0){
|
||||
String menuStr = StringUtils.join(vo.getMenus(), ",");
|
||||
String permStr = StringUtils.join(vo.getPermissions(), ",");
|
||||
menuMapper.addRoleMenu(id, menuStr, permStr);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
}
|
||||
|
@@ -145,6 +145,11 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
int i = scenicMapper.update(scenicUpdateReq);
|
||||
if (i > 0) {
|
||||
scenicRepository.clearCache(scenicUpdateReq.getId());
|
||||
scenicFaceBodyAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicStorageAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicTmpStorageAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicLocalStorageAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicPayAdapterMap.remove(scenicUpdateReq.getId());
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区修改失败");
|
||||
@@ -157,6 +162,11 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
int i = scenicMapper.updateStatus(id);
|
||||
if (i > 0) {
|
||||
scenicRepository.clearCache(id);
|
||||
scenicFaceBodyAdapterMap.remove(id);
|
||||
scenicStorageAdapterMap.remove(id);
|
||||
scenicTmpStorageAdapterMap.remove(id);
|
||||
scenicLocalStorageAdapterMap.remove(id);
|
||||
scenicPayAdapterMap.remove(id);
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区状态修改失败");
|
||||
@@ -182,6 +192,11 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
int i = scenicMapper.updateConfigById(scenicConfig);
|
||||
if (i > 0) {
|
||||
scenicRepository.clearCache(scenicConfig.getScenicId());
|
||||
scenicFaceBodyAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicStorageAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicTmpStorageAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicLocalStorageAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicPayAdapterMap.remove(scenicConfig.getScenicId());
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区配置修改失败");
|
||||
|
@@ -7,13 +7,17 @@ import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.model.pc.source.req.SourceReqQuery;
|
||||
import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
|
||||
import com.ycwl.basic.repository.SourceRepository;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.service.pc.SourceService;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.task.VideoPieceGetter;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
@@ -30,6 +34,8 @@ public class SourceServiceImpl implements SourceService {
|
||||
private SourceMapper sourceMapper;
|
||||
@Autowired
|
||||
private SourceRepository sourceRepository;
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
@Override
|
||||
public ApiResponse<PageInfo<SourceRespVO>> pageQuery(SourceReqQuery sourceReqQuery) {
|
||||
@@ -137,4 +143,29 @@ public class SourceServiceImpl implements SourceService {
|
||||
}
|
||||
return ApiResponse.success("任务已下发");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<String> uploadAndUpdateUrl(Long id, MultipartFile file) {
|
||||
SourceRespVO source = sourceMapper.getById(id);
|
||||
if (source == null) {
|
||||
return ApiResponse.fail("该素材不存在");
|
||||
}
|
||||
try {
|
||||
IStorageAdapter adapter = scenicService.getScenicStorageAdapter(source.getScenicId());
|
||||
String uploadedUrl = adapter.uploadFile(file, "source", String.valueOf(id));
|
||||
|
||||
SourceEntity sourceUpd = new SourceEntity();
|
||||
sourceUpd.setId(id);
|
||||
sourceUpd.setUrl(uploadedUrl);
|
||||
|
||||
int updateResult = sourceMapper.update(sourceUpd);
|
||||
if (updateResult > 0) {
|
||||
return ApiResponse.success(uploadedUrl);
|
||||
} else {
|
||||
return ApiResponse.fail("更新URL失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return ApiResponse.fail("文件上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -87,13 +87,13 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
|
||||
@Override
|
||||
public SearchFaceRespVo searchFace(Long faceId) {
|
||||
FaceRespVO faceRespVO = faceMapper.getById(faceId);
|
||||
if (faceRespVO == null) {
|
||||
FaceRespVO face = faceMapper.getById(faceId);
|
||||
if (face == null) {
|
||||
SearchFaceRespVo vo = new SearchFaceRespVo();
|
||||
vo.setSampleListIds(new ArrayList<>());
|
||||
return vo;
|
||||
}
|
||||
Long scenicId = faceRespVO.getScenicId();
|
||||
Long scenicId = face.getScenicId();
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
IFaceBodyAdapter faceBodyAdapter;
|
||||
if (scenicConfig != null && scenicConfig.getFaceType() != null) {
|
||||
@@ -102,7 +102,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
} else {
|
||||
faceBodyAdapter = FaceBodyFactory.use();
|
||||
}
|
||||
SearchFaceRespVo respVo = searchFace(faceBodyAdapter, scenicId.toString(), faceRespVO.getFaceUrl(), "系统定时任务检索");
|
||||
SearchFaceRespVo respVo = searchFace(faceBodyAdapter, scenicId.toString(), face.getFaceUrl(), "系统定时任务检索");
|
||||
if (respVo != null) {
|
||||
FaceEntity faceEntity = new FaceEntity();
|
||||
faceEntity.setId(faceId);
|
||||
@@ -120,17 +120,9 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
MemberSourceEntity memberSourceEntity = new MemberSourceEntity();
|
||||
memberSourceEntity.setScenicId(scenicId);
|
||||
memberSourceEntity.setFaceId(faceEntity.getId());
|
||||
memberSourceEntity.setMemberId(faceRespVO.getMemberId());
|
||||
memberSourceEntity.setMemberId(face.getMemberId());
|
||||
memberSourceEntity.setSourceId(sourceEntity.getId());
|
||||
memberSourceEntity.setType(sourceEntity.getType());
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(faceRespVO.getMemberId(), scenicId, sourceEntity.getType(), sourceEntity.getId());
|
||||
if (isBuy.isBuy()) { // 如果用户买过
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else if (isBuy.isFree()) { // 全免费逻辑
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else {
|
||||
memberSourceEntity.setIsBuy(0);
|
||||
}
|
||||
memberSourceEntity.setIsFree(0);
|
||||
if (deviceConfig != null) {
|
||||
if (sourceEntity.getType() == 1) {
|
||||
@@ -146,11 +138,21 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
return memberSourceEntity;
|
||||
}).collect(Collectors.toList());
|
||||
if (!memberSourceEntityList.isEmpty()) {
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), memberSourceEntityList.getFirst().getType(), faceEntity.getId());
|
||||
for (MemberSourceEntity memberSourceEntity : memberSourceEntityList) {
|
||||
if (isBuy.isBuy()) { // 如果用户买过
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else if (isBuy.isFree()) { // 全免费逻辑
|
||||
memberSourceEntity.setIsBuy(1);
|
||||
} else {
|
||||
memberSourceEntity.setIsBuy(0);
|
||||
}
|
||||
}
|
||||
sourceMapper.addRelations(memberSourceEntityList);
|
||||
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
||||
task.faceId = faceEntity.getId();
|
||||
task.faceSampleIds = sampleListIds;
|
||||
task.memberId = faceRespVO.getMemberId();
|
||||
task.memberId = face.getMemberId();
|
||||
VideoPieceGetter.addTask(task);
|
||||
}
|
||||
}
|
||||
|
@@ -175,6 +175,7 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
taskList.forEach(task -> {
|
||||
taskMapper.assignToWorker(task.getId(), worker.getId());
|
||||
videoTaskRepository.clearTaskCache(task.getId());
|
||||
repository.clearCache(worker.getId());
|
||||
});
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@@ -445,6 +446,10 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
.peek(item -> item.setUrl(item.getVideoUrl()))
|
||||
.filter(item -> {
|
||||
DeviceEntity device = deviceRepository.getDevice(item.getDeviceId());
|
||||
if (device == null) {
|
||||
log.info("task callback: deviceId:{} is not exist", item.getDeviceId());
|
||||
return false;
|
||||
}
|
||||
return Integer.valueOf(1).equals(device.getStatus());
|
||||
})
|
||||
.filter(item -> item.getDeviceId() != null) // 添加对 deviceId 为 null 的检查
|
||||
|
@@ -33,25 +33,37 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
final public class AliOssAdapter extends AStorageAdapter {
|
||||
private AliOssStorageConfig config;
|
||||
private volatile AliOssStorageConfig config;
|
||||
private volatile OSS ossClient;
|
||||
private final Object clientLock = new Object();
|
||||
private final Object configLock = new Object();
|
||||
|
||||
@Override
|
||||
public String identity() {
|
||||
return config.identity();
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
return "ALI_OSS_UNCONFIGURED";
|
||||
}
|
||||
return currentConfig.identity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConfig(Map<String, String> _config) {
|
||||
AliOssStorageConfig config = new AliOssStorageConfig();
|
||||
config.setAccessKeyId(_config.get("accessKeyId"));
|
||||
config.setAccessKeySecret(_config.get("accessKeySecret"));
|
||||
config.setBucketName(_config.get("bucketName"));
|
||||
config.setEndpoint(_config.get("endpoint"));
|
||||
config.setRegion(_config.get("region"));
|
||||
config.setUrl(_config.get("url"));
|
||||
config.setPrefix(_config.get("prefix"));
|
||||
config.checkEverythingOK();
|
||||
this.config = config;
|
||||
AliOssStorageConfig newConfig = new AliOssStorageConfig();
|
||||
newConfig.setAccessKeyId(_config.get("accessKeyId"));
|
||||
newConfig.setAccessKeySecret(_config.get("accessKeySecret"));
|
||||
newConfig.setBucketName(_config.get("bucketName"));
|
||||
newConfig.setEndpoint(_config.get("endpoint"));
|
||||
newConfig.setRegion(_config.get("region"));
|
||||
newConfig.setUrl(_config.get("url"));
|
||||
newConfig.setPrefix(_config.get("prefix"));
|
||||
newConfig.checkEverythingOK();
|
||||
|
||||
synchronized (configLock) {
|
||||
this.config = newConfig;
|
||||
// 配置更新后,需要重置客户端连接
|
||||
resetClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,11 +71,15 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
if (config == null) {
|
||||
throw new StorageConfigException("配置为空");
|
||||
}
|
||||
if (config instanceof AliOssStorageConfig) {
|
||||
this.config = (AliOssStorageConfig) config;
|
||||
} else {
|
||||
if (!(config instanceof AliOssStorageConfig)) {
|
||||
throw new StorageConfigException("配置类型错误,传入的类为:" + config.getClass().getName());
|
||||
}
|
||||
|
||||
synchronized (configLock) {
|
||||
this.config = (AliOssStorageConfig) config;
|
||||
// 配置更新后,需要重置客户端连接
|
||||
resetClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,12 +91,25 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
try (OSSWrapper wrapper = getOssClient()) {
|
||||
OSS ossClient = wrapper.getOSSClient();
|
||||
ObjectMetadata metadata = new ObjectMetadata();
|
||||
metadata.setContentLength(inputStream.available());
|
||||
|
||||
// 读取完整内容并计算实际长度
|
||||
byte[] bytes = inputStream.readAllBytes();
|
||||
metadata.setContentLength(bytes.length);
|
||||
|
||||
if (StringUtils.isNotBlank(contentType)) {
|
||||
metadata.setContentType(contentType);
|
||||
}
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, inputStream);
|
||||
ossClient.putObject(putObjectRequest);
|
||||
|
||||
// 使用字节数组创建新的 InputStream
|
||||
try (InputStream byteInputStream = new java.io.ByteArrayInputStream(bytes)) {
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(currentConfig.getBucketName(), fullPath, byteInputStream, metadata);
|
||||
ossClient.putObject(putObjectRequest);
|
||||
}
|
||||
|
||||
return getUrl(path);
|
||||
} catch (Exception e) {
|
||||
throw new UploadFileFailedException("上传文件失败:" + e.getMessage());
|
||||
@@ -92,7 +121,11 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
public boolean deleteFile(String... path) {
|
||||
try (OSSWrapper wrapper = getOssClient()) {
|
||||
OSS ossClient = wrapper.getOSSClient();
|
||||
ossClient.deleteObject(config.getBucketName(), buildPath(path));
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
return false;
|
||||
}
|
||||
ossClient.deleteObject(currentConfig.getBucketName(), buildPath(path));
|
||||
return true;
|
||||
} catch (ClientException e) {
|
||||
return false;
|
||||
@@ -101,14 +134,22 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
|
||||
@Override
|
||||
public String getUrl(String... path) {
|
||||
return config.getUrl() + "/" + buildPath(path);
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
return currentConfig.getUrl() + "/" + buildPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlForDownload(Date expireDate, String... path) {
|
||||
try (OSSWrapper wrapper = getOssClient()) {
|
||||
OSS ossClient = wrapper.getOSSClient();
|
||||
URL url = ossClient.generatePresignedUrl(config.getBucketName(), buildPath(path), expireDate, HttpMethod.GET);
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
URL url = ossClient.generatePresignedUrl(currentConfig.getBucketName(), buildPath(path), expireDate, HttpMethod.GET);
|
||||
return url.toString();
|
||||
}
|
||||
}
|
||||
@@ -117,7 +158,11 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
public String getUrlForUpload(Date expireDate, String contentType, String... path) {
|
||||
try (OSSWrapper wrapper = getOssClient()) {
|
||||
OSS ossClient = wrapper.getOSSClient();
|
||||
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(config.getBucketName(), buildPath(path), HttpMethod.PUT);
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(currentConfig.getBucketName(), buildPath(path), HttpMethod.PUT);
|
||||
if (StringUtils.isNotBlank(contentType)) {
|
||||
request.setContentType(contentType);
|
||||
}
|
||||
@@ -129,7 +174,11 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
|
||||
@Override
|
||||
public List<StorageFileObject> listDir(String... path) {
|
||||
ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(config.getBucketName());
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(currentConfig.getBucketName());
|
||||
listObjectsV2Request.setPrefix(buildPath(path) + "/");
|
||||
listObjectsV2Request.setMaxKeys(1000);
|
||||
boolean isTruncated = true;
|
||||
@@ -180,7 +229,11 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
}
|
||||
List<StorageFileObject> subList = objectList.subList(idx, idx + batchSize);
|
||||
idx += batchSize;
|
||||
DeleteObjectsRequest request = new DeleteObjectsRequest(config.getBucketName());
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
return false;
|
||||
}
|
||||
DeleteObjectsRequest request = new DeleteObjectsRequest(currentConfig.getBucketName());
|
||||
request.setKeys(subList.stream().map(StorageFileObject::getFullPath).collect(Collectors.toList()));
|
||||
try {
|
||||
ossClient.deleteObjects(request);
|
||||
@@ -208,7 +261,11 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
public boolean setAcl(StorageAcl acl, String... path) {
|
||||
try (OSSWrapper wrapper = getOssClient()) {
|
||||
OSS ossClient = wrapper.getOSSClient();
|
||||
ossClient.setObjectAcl(config.getBucketName(), buildPath(path), convertAcl(acl));
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
return false;
|
||||
}
|
||||
ossClient.setObjectAcl(currentConfig.getBucketName(), buildPath(path), convertAcl(acl));
|
||||
return true;
|
||||
} catch (OSSException e) {
|
||||
return false;
|
||||
@@ -219,32 +276,85 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
public boolean isExists(String ...path) {
|
||||
try (OSSWrapper wrapper = getOssClient()) {
|
||||
OSS ossClient = wrapper.getOSSClient();
|
||||
return ossClient.doesObjectExist(config.getBucketName(), buildPath(path));
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
return false;
|
||||
}
|
||||
return ossClient.doesObjectExist(currentConfig.getBucketName(), buildPath(path));
|
||||
}
|
||||
}
|
||||
|
||||
private OSSWrapper getOssClient() {
|
||||
OSS ossClient = new OSSClientBuilder().build(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
|
||||
return new OSSWrapper(ossClient);
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
|
||||
if (ossClient == null) {
|
||||
synchronized (clientLock) {
|
||||
if (ossClient == null) {
|
||||
// 在同步块内再次检查配置,确保配置一致性
|
||||
currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
ossClient = new OSSClientBuilder().build(
|
||||
currentConfig.getEndpoint(),
|
||||
currentConfig.getAccessKeyId(),
|
||||
currentConfig.getAccessKeySecret()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new OSSWrapper(ossClient, false); // false 表示不自动关闭共享客户端
|
||||
}
|
||||
|
||||
// 重置客户端连接(配置更新时调用)
|
||||
private void resetClient() {
|
||||
synchronized (clientLock) {
|
||||
if (ossClient != null) {
|
||||
ossClient.shutdown();
|
||||
ossClient = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 手动关闭客户端的方法,用于适配器销毁时
|
||||
public void shutdown() {
|
||||
synchronized (clientLock) {
|
||||
if (ossClient != null) {
|
||||
ossClient.shutdown();
|
||||
ossClient = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String buildPath(String ...paths) {
|
||||
if (StringUtils.isNotBlank(config.getPrefix())) {
|
||||
return StorageUtil.joinPath(config.getPrefix(), paths);
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig != null && StringUtils.isNotBlank(currentConfig.getPrefix())) {
|
||||
return StorageUtil.joinPath(currentConfig.getPrefix(), paths);
|
||||
} else {
|
||||
return StorageUtil.joinPath(paths);
|
||||
}
|
||||
}
|
||||
|
||||
private String getRelativePath(String path) {
|
||||
return StorageUtil.getRelativePath(path, config.getPrefix());
|
||||
AliOssStorageConfig currentConfig = this.config;
|
||||
String prefix = currentConfig != null ? currentConfig.getPrefix() : null;
|
||||
return StorageUtil.getRelativePath(path, prefix);
|
||||
}
|
||||
|
||||
public static class OSSWrapper implements AutoCloseable {
|
||||
private final OSS ossClient;
|
||||
private final boolean autoClose;
|
||||
|
||||
public OSSWrapper(OSS ossClient) {
|
||||
this(ossClient, true);
|
||||
}
|
||||
|
||||
public OSSWrapper(OSS ossClient, boolean autoClose) {
|
||||
this.ossClient = ossClient;
|
||||
this.autoClose = autoClose;
|
||||
}
|
||||
|
||||
// 提供对原始对象的方法访问
|
||||
@@ -254,8 +364,10 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// 在此处实现资源关闭逻辑(如调用 OSS 的关闭方法)
|
||||
ossClient.shutdown(); // 假设 OSS 提供 shutdown 方法关闭资源
|
||||
// 只有非共享客户端才自动关闭
|
||||
if (autoClose && ossClient != null) {
|
||||
ossClient.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,25 +26,37 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AwsOssAdapter extends AStorageAdapter {
|
||||
private AwsOssStorageConfig config;
|
||||
private volatile AwsOssStorageConfig config;
|
||||
private volatile AmazonS3Client s3Client;
|
||||
private final Object clientLock = new Object();
|
||||
private final Object configLock = new Object();
|
||||
|
||||
@Override
|
||||
public String identity() {
|
||||
return config.identity();
|
||||
AwsOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
return "AWS_OSS_UNCONFIGURED";
|
||||
}
|
||||
return currentConfig.identity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConfig(Map<String, String> _config) {
|
||||
AwsOssStorageConfig config = new AwsOssStorageConfig();
|
||||
config.setAccessKeyId(_config.get("accessKeyId"));
|
||||
config.setAccessKeySecret(_config.get("accessKeySecret"));
|
||||
config.setBucketName(_config.get("bucketName"));
|
||||
config.setEndpoint(_config.get("endpoint"));
|
||||
config.setRegion(_config.get("region"));
|
||||
config.setUrl(_config.get("url"));
|
||||
config.setPrefix(_config.get("prefix"));
|
||||
config.checkEverythingOK();
|
||||
this.config = config;
|
||||
AwsOssStorageConfig newConfig = new AwsOssStorageConfig();
|
||||
newConfig.setAccessKeyId(_config.get("accessKeyId"));
|
||||
newConfig.setAccessKeySecret(_config.get("accessKeySecret"));
|
||||
newConfig.setBucketName(_config.get("bucketName"));
|
||||
newConfig.setEndpoint(_config.get("endpoint"));
|
||||
newConfig.setRegion(_config.get("region"));
|
||||
newConfig.setUrl(_config.get("url"));
|
||||
newConfig.setPrefix(_config.get("prefix"));
|
||||
newConfig.checkEverythingOK();
|
||||
|
||||
synchronized (configLock) {
|
||||
this.config = newConfig;
|
||||
// 配置更新后,需要重置客户端连接
|
||||
resetClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,11 +64,15 @@ public class AwsOssAdapter extends AStorageAdapter {
|
||||
if (config == null) {
|
||||
throw new StorageConfigException("配置为空");
|
||||
}
|
||||
if (config instanceof AwsOssStorageConfig) {
|
||||
this.config = (AwsOssStorageConfig) config;
|
||||
} else {
|
||||
if (!(config instanceof AwsOssStorageConfig)) {
|
||||
throw new StorageConfigException("配置类型错误,传入的类为:" + config.getClass().getName());
|
||||
}
|
||||
|
||||
synchronized (configLock) {
|
||||
this.config = (AwsOssStorageConfig) config;
|
||||
// 配置更新后,需要重置客户端连接
|
||||
resetClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,13 +84,22 @@ public class AwsOssAdapter extends AStorageAdapter {
|
||||
try (S3Wrapper wrapper = getS3Client()) {
|
||||
AmazonS3Client s3Client = wrapper.s3Client();
|
||||
ObjectMetadata metadata = new ObjectMetadata();
|
||||
metadata.setContentLength(inputStream.available());
|
||||
|
||||
// 读取完整内容并计算实际长度
|
||||
byte[] bytes = inputStream.readAllBytes();
|
||||
metadata.setContentLength(bytes.length);
|
||||
|
||||
if (StringUtils.isNotBlank(contentType)) {
|
||||
metadata.setContentType(contentType);
|
||||
}
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, inputStream, metadata);
|
||||
putObjectRequest.withCannedAcl(CannedAccessControlList.PublicRead); // 设置访问权限,让所有用户都允许访问
|
||||
s3Client.putObject(putObjectRequest);
|
||||
|
||||
// 使用字节数组创建新的 InputStream
|
||||
try (InputStream byteInputStream = new java.io.ByteArrayInputStream(bytes)) {
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, byteInputStream, metadata);
|
||||
putObjectRequest.withCannedAcl(CannedAccessControlList.PublicRead); // 设置访问权限,让所有用户都允许访问
|
||||
s3Client.putObject(putObjectRequest);
|
||||
}
|
||||
|
||||
return getUrl(path);
|
||||
} catch (Exception e) {
|
||||
throw new UploadFileFailedException("上传文件失败:" + e.getMessage());
|
||||
@@ -150,6 +175,7 @@ public class AwsOssAdapter 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());
|
||||
@@ -220,14 +246,57 @@ public class AwsOssAdapter extends AStorageAdapter {
|
||||
}
|
||||
|
||||
private S3Wrapper getS3Client() {
|
||||
BasicAWSCredentials basicAwsCred = new BasicAWSCredentials(config.getAccessKeyId(), config.getAccessKeySecret());
|
||||
ClientConfiguration clientConfiguration = new ClientConfiguration();
|
||||
clientConfiguration.setProtocol(Protocol.HTTPS);
|
||||
AmazonS3Client s3 = new AmazonS3Client(basicAwsCred,clientConfiguration);
|
||||
S3ClientOptions options = S3ClientOptions.builder().setPathStyleAccess(true).setPayloadSigningEnabled(true).disableChunkedEncoding().build();
|
||||
s3.setS3ClientOptions(options);
|
||||
s3.setEndpoint(config.getEndpoint());
|
||||
return new S3Wrapper(s3);
|
||||
AwsOssStorageConfig currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
|
||||
if (s3Client == null) {
|
||||
synchronized (clientLock) {
|
||||
if (s3Client == null) {
|
||||
// 在同步块内再次检查配置,确保配置一致性
|
||||
currentConfig = this.config;
|
||||
if (currentConfig == null) {
|
||||
throw new StorageConfigException("存储适配器未配置");
|
||||
}
|
||||
BasicAWSCredentials basicAwsCred = new BasicAWSCredentials(
|
||||
currentConfig.getAccessKeyId(),
|
||||
currentConfig.getAccessKeySecret()
|
||||
);
|
||||
ClientConfiguration clientConfiguration = new ClientConfiguration();
|
||||
clientConfiguration.setProtocol(Protocol.HTTPS);
|
||||
s3Client = new AmazonS3Client(basicAwsCred, clientConfiguration);
|
||||
S3ClientOptions options = S3ClientOptions.builder()
|
||||
.setPathStyleAccess(true)
|
||||
.setPayloadSigningEnabled(true)
|
||||
.disableChunkedEncoding()
|
||||
.build();
|
||||
s3Client.setS3ClientOptions(options);
|
||||
s3Client.setEndpoint(currentConfig.getEndpoint());
|
||||
}
|
||||
}
|
||||
}
|
||||
return new S3Wrapper(s3Client, false); // false 表示不自动关闭共享客户端
|
||||
}
|
||||
|
||||
// 重置客户端连接(配置更新时调用)
|
||||
private void resetClient() {
|
||||
synchronized (clientLock) {
|
||||
if (s3Client != null) {
|
||||
s3Client.shutdown();
|
||||
s3Client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 手动关闭客户端的方法,用于适配器销毁时
|
||||
public void shutdown() {
|
||||
synchronized (clientLock) {
|
||||
if (s3Client != null) {
|
||||
s3Client.shutdown();
|
||||
s3Client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String buildPath(String... paths) {
|
||||
@@ -242,10 +311,18 @@ public class AwsOssAdapter extends AStorageAdapter {
|
||||
return StorageUtil.getRelativePath(path, config.getPrefix());
|
||||
}
|
||||
|
||||
public record S3Wrapper(AmazonS3Client s3Client) implements AutoCloseable {
|
||||
public record S3Wrapper(AmazonS3Client s3Client, boolean autoClose) implements AutoCloseable {
|
||||
|
||||
public S3Wrapper(AmazonS3Client s3Client) {
|
||||
this(s3Client, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
s3Client.shutdown();
|
||||
// 只有非共享客户端才自动关闭
|
||||
if (autoClose && s3Client != null) {
|
||||
s3Client.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,71 +3,207 @@ package com.ycwl.basic.storage.adapters;
|
||||
import com.ycwl.basic.storage.entity.StorageConfig;
|
||||
import com.ycwl.basic.storage.entity.StorageFileObject;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.storage.exceptions.StorageConfigException;
|
||||
import com.ycwl.basic.storage.exceptions.StorageException;
|
||||
import com.ycwl.basic.storage.exceptions.UploadFileFailedException;
|
||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class LocalStorageAdapter extends AStorageAdapter {
|
||||
private volatile String basePath;
|
||||
private volatile String baseUrl;
|
||||
private volatile String prefix = "";
|
||||
private final Object configLock = new Object();
|
||||
|
||||
public class LocalStorageAdapter extends AStorageAdapter{
|
||||
@Override
|
||||
public String identity() {
|
||||
return "";
|
||||
return "LOCAL_STORAGE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConfig(Map<String, String> config) {
|
||||
|
||||
String newBasePath = config.get("basePath");
|
||||
String newBaseUrl = config.get("baseUrl");
|
||||
String newPrefix = StringUtils.isNotBlank(config.get("prefix")) ? config.get("prefix") : "";
|
||||
|
||||
if (StringUtils.isBlank(newBasePath)) {
|
||||
throw new StorageConfigException("本地存储配置错误:basePath 不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(newBaseUrl)) {
|
||||
throw new StorageConfigException("本地存储配置错误:baseUrl 不能为空");
|
||||
}
|
||||
|
||||
// 确保基础目录存在
|
||||
try {
|
||||
Files.createDirectories(Paths.get(newBasePath));
|
||||
} catch (IOException e) {
|
||||
throw new StorageConfigException("创建本地存储目录失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
synchronized (configLock) {
|
||||
this.basePath = newBasePath;
|
||||
this.baseUrl = newBaseUrl;
|
||||
this.prefix = newPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig(StorageConfig config) {
|
||||
|
||||
throw new StorageConfigException("LocalStorageAdapter 不支持 StorageConfig 类型配置");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(String contentType, InputStream inputStream, String... path) {
|
||||
return "";
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String fullPath = buildLocalPath(path);
|
||||
try {
|
||||
// 确保父目录存在
|
||||
Path filePath = Paths.get(fullPath);
|
||||
Files.createDirectories(filePath.getParent());
|
||||
|
||||
// 复制文件内容到本地
|
||||
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
return getUrl(path);
|
||||
} catch (IOException e) {
|
||||
throw new UploadFileFailedException("本地文件保存失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteFile(String... path) {
|
||||
return false;
|
||||
try {
|
||||
String fullPath = buildLocalPath(path);
|
||||
return Files.deleteIfExists(Paths.get(fullPath));
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl(String... path) {
|
||||
return "";
|
||||
String relativePath = buildRelativePath(path);
|
||||
return baseUrl + "/" + relativePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlForDownload(Date expireDate, String... path) {
|
||||
return "";
|
||||
// 本地存储不支持带过期时间的URL,直接返回普通URL
|
||||
return getUrl(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlForUpload(Date expireDate, String contentType, String... path) {
|
||||
return "";
|
||||
// 本地存储不支持预签名上传URL
|
||||
return getUrl(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StorageFileObject> listDir(String... path) {
|
||||
return Collections.emptyList();
|
||||
String fullPath = buildLocalPath(path);
|
||||
Path dirPath = Paths.get(fullPath);
|
||||
|
||||
if (!Files.exists(dirPath) || !Files.isDirectory(dirPath)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<StorageFileObject> result = new ArrayList<>();
|
||||
try (Stream<Path> paths = Files.list(dirPath)) {
|
||||
paths.forEach(filePath -> {
|
||||
try {
|
||||
StorageFileObject obj = new StorageFileObject();
|
||||
obj.setName(filePath.getFileName().toString());
|
||||
obj.setPath(getRelativePath(filePath.getParent().toString()));
|
||||
obj.setSize(Files.size(filePath));
|
||||
obj.setModifyTime(new Date(Files.getLastModifiedTime(filePath).toMillis()));
|
||||
obj.setRawObject(filePath.toFile());
|
||||
result.add(obj);
|
||||
} catch (IOException e) {
|
||||
// 忽略无法读取的文件
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("列举本地文件失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteDir(String... path) {
|
||||
return false;
|
||||
String fullPath = buildLocalPath(path);
|
||||
Path dirPath = Paths.get(fullPath);
|
||||
|
||||
if (!Files.exists(dirPath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
// 递归删除目录及其内容
|
||||
try (Stream<Path> paths = Files.walk(dirPath)) {
|
||||
paths.sorted((a, b) -> b.compareTo(a)) // 从深到浅排序,确保先删除文件再删除目录
|
||||
.forEach(filePath -> {
|
||||
try {
|
||||
Files.deleteIfExists(filePath);
|
||||
} catch (IOException e) {
|
||||
// 忽略删除失败的文件
|
||||
}
|
||||
});
|
||||
}
|
||||
return !Files.exists(dirPath);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAcl(StorageAcl acl, String... path) {
|
||||
return false;
|
||||
// 本地存储不支持ACL设置
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExists(String... path) {
|
||||
return false;
|
||||
String fullPath = buildLocalPath(path);
|
||||
return Files.exists(Paths.get(fullPath));
|
||||
}
|
||||
|
||||
private String buildLocalPath(String... paths) {
|
||||
String relativePath = buildRelativePath(paths);
|
||||
return Paths.get(basePath, relativePath).toString();
|
||||
}
|
||||
|
||||
private String buildRelativePath(String... paths) {
|
||||
if (StringUtils.isNotBlank(prefix)) {
|
||||
return StorageUtil.joinPath(prefix, paths);
|
||||
} else {
|
||||
return StorageUtil.joinPath(paths);
|
||||
}
|
||||
}
|
||||
|
||||
private String getRelativePath(String fullPath) {
|
||||
String basePathNormalized = Paths.get(basePath).toString();
|
||||
if (fullPath.startsWith(basePathNormalized)) {
|
||||
String relative = fullPath.substring(basePathNormalized.length());
|
||||
if (relative.startsWith(File.separator)) {
|
||||
relative = relative.substring(1);
|
||||
}
|
||||
return StorageUtil.getRelativePath(relative, prefix);
|
||||
}
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
|
@@ -131,7 +131,7 @@ public class DynamicTaskGenerator {
|
||||
return false;
|
||||
}
|
||||
return face.getScenicId().equals(faceSample.getScenicId());
|
||||
}).collect(Collectors.toList());
|
||||
}).toList();
|
||||
if (faceIdList.isEmpty()) {
|
||||
log.info("本景区人脸样本ID不在人脸样本库中,忽略任务:{}", task);
|
||||
return;
|
||||
|
70
src/main/java/com/ycwl/basic/task/N9eSyncTask.java
Normal file
70
src/main/java/com/ycwl/basic/task/N9eSyncTask.java
Normal file
@@ -0,0 +1,70 @@
|
||||
package com.ycwl.basic.task;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@EnableScheduling
|
||||
public class N9eSyncTask {
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
@Scheduled(fixedRate = 1000 * 60L)
|
||||
public void syncN9e() {
|
||||
// 构建Basic认证头
|
||||
String auth = "Basic " + Base64.encode("user001:ccc26da7b9aba533cbb263a36c07dcc4");
|
||||
|
||||
// 构建请求体
|
||||
JSONObject requestBody = new JSONObject();
|
||||
JSONArray queries = new JSONArray();
|
||||
JSONObject query = new JSONObject();
|
||||
query.put("key", "group_ids");
|
||||
query.put("op", "==");
|
||||
JSONArray values = new JSONArray();
|
||||
values.add(4);
|
||||
query.put("values", values);
|
||||
queries.add(query);
|
||||
requestBody.put("queries", queries);
|
||||
|
||||
// 发送POST请求
|
||||
HttpResponse response = HttpUtil.createPost("https://n9e.jerryyan.top/v1/n9e/target/list")
|
||||
.header("Authorization", auth)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(requestBody.toJSONString())
|
||||
.execute();
|
||||
JSONObject respData = JSON.parseObject(response.body());
|
||||
if (StringUtils.isNotBlank(respData.getString("err"))) {
|
||||
log.warn("N9E信息获取失败");
|
||||
return;
|
||||
}
|
||||
JSONObject data = respData.getJSONObject("dat");
|
||||
if (data.getInteger("total") <= 0) {
|
||||
log.warn("N9E信息为空");
|
||||
return;
|
||||
}
|
||||
JSONArray list = data.getJSONArray("list");
|
||||
list.forEach(item -> {
|
||||
JSONObject itemObj = (JSONObject) item;
|
||||
String ident = itemObj.getString("ident");
|
||||
Long updateAt = itemObj.getLong("update_at");
|
||||
redisTemplate.opsForValue().set("ext_device:online:" + ident, updateAt.toString(), 1, TimeUnit.DAYS);
|
||||
});
|
||||
}
|
||||
}
|
@@ -7,7 +7,9 @@ import com.ycwl.basic.constant.StorageConstant;
|
||||
import com.ycwl.basic.device.DeviceFactory;
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.operator.IDeviceStorageOperator;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
@@ -16,6 +18,8 @@ import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
@@ -57,6 +61,8 @@ public class VideoPieceGetter {
|
||||
@Autowired
|
||||
private FaceSampleMapper faceSampleMapper;
|
||||
@Autowired
|
||||
private FaceRepository faceRepository;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
@@ -68,6 +74,8 @@ public class VideoPieceGetter {
|
||||
private TaskStatusBiz taskStatusBiz;
|
||||
@Autowired
|
||||
private VideoReUploader videoReUploader;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
@Data
|
||||
public static class Task {
|
||||
@@ -208,7 +216,7 @@ public class VideoPieceGetter {
|
||||
log.info("executor已结束![A:{}/T:{}/F:{}]", executor.getActiveCount(), executor.getTaskCount(), executor.getCompletedTaskCount());
|
||||
executor.close();
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
log.info("executor已中断![A:{}/T:{}/F:{}]", executor.getActiveCount(), executor.getTaskCount(), executor.getCompletedTaskCount());
|
||||
} finally {
|
||||
if (task.faceId != null) {
|
||||
taskStatusBiz.setFaceCutStatus(task.faceId, 1);
|
||||
@@ -220,6 +228,29 @@ public class VideoPieceGetter {
|
||||
task.getCallback().onInvoke();
|
||||
}
|
||||
}
|
||||
if (task.getFaceId() != null) {
|
||||
FaceEntity face = faceRepository.getFace(task.getFaceId());
|
||||
if (face != null) {
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
|
||||
if (scenicConfig != null) {
|
||||
// 免费送
|
||||
List<MemberSourceEntity> sourceEntities = sourceMapper.listByFaceRelation(face.getScenicId(), face.getId(), 1);
|
||||
if (sourceEntities.stream().noneMatch(item -> Integer.valueOf(1).equals(item.getIsFree()))) {
|
||||
List<Long> freeSourceRelationIds = new ArrayList<>();
|
||||
if (scenicConfig.getVideoFreeNum() != null && scenicConfig.getVideoFreeNum() > 0) {
|
||||
if (scenicConfig.getVideoFreeNum() > sourceEntities.size()) {
|
||||
freeSourceRelationIds.addAll(sourceEntities.stream().map(MemberSourceEntity::getId).toList());
|
||||
} else {
|
||||
freeSourceRelationIds.addAll(sourceEntities.stream().limit(scenicConfig.getVideoFreeNum()).map(MemberSourceEntity::getId).toList());
|
||||
}
|
||||
}
|
||||
if (!freeSourceRelationIds.isEmpty()) {
|
||||
sourceMapper.freeRelations(freeSourceRelationIds, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doCut(Long deviceId, Long faceSampleId, Date baseTime, Task task) {
|
||||
|
@@ -1,14 +1,19 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@Slf4j
|
||||
public class ImageUtils {
|
||||
public static MultipartFile base64ToMultipartFile(String base64) {
|
||||
String[] baseStrs = base64.split(",");
|
||||
@@ -21,6 +26,37 @@ public class ImageUtils {
|
||||
}
|
||||
return new Base64DecodedMultipartFile(b, baseStrs[0]);
|
||||
}
|
||||
|
||||
public static MultipartFile cropImage(MultipartFile file, int x, int y, int w, int h) throws IOException {
|
||||
BufferedImage image = ImageIO.read(file.getInputStream());
|
||||
log.info("图片宽高:{}", image.getWidth() + "x" + image.getHeight());
|
||||
log.info("图片裁切:{}@{}", w + "x" + h, x + "," + y);
|
||||
if (image.getWidth() < w) {
|
||||
w = image.getWidth();
|
||||
}
|
||||
if (image.getHeight() < h) {
|
||||
h = image.getHeight();
|
||||
}
|
||||
int targetX = x;
|
||||
if (x < 0) {
|
||||
targetX = 0;
|
||||
} else if ((x + w) > image.getWidth()) {
|
||||
targetX = image.getWidth() - w;
|
||||
}
|
||||
int targetY = y;
|
||||
if (y < 0) {
|
||||
targetY = 0;
|
||||
} else if ((y + h) > image.getHeight()) {
|
||||
targetY = image.getHeight() - h;
|
||||
}
|
||||
log.info("图片实际裁切:{}@{}", w + "x" + h, targetX + "," + targetY);
|
||||
BufferedImage targetImage = image.getSubimage(targetX, targetY, w, h);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(targetImage, "jpg", baos);
|
||||
baos.close();
|
||||
return new Base64DecodedMultipartFile(baos.toByteArray(), "image/jpeg");
|
||||
}
|
||||
|
||||
public static class Base64DecodedMultipartFile implements MultipartFile {
|
||||
|
||||
private final byte[] imgContent;
|
||||
|
@@ -13,6 +13,8 @@ import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -49,10 +51,19 @@ public class JwtTokenUtil {
|
||||
|
||||
public static String generateToken(JwtInfo jwtInfo, int expire) throws Exception {
|
||||
LocalDateTime expireTime = LocalDateTime.now().plusDays(expire);
|
||||
if (jwtInfo.getExpireTime() != null) {
|
||||
expireTime = jwtInfo.getExpireTime();
|
||||
}
|
||||
byte[] bytes = RsaKeyUtil.toBytes(PRI_KEY);
|
||||
String token = JwtAnalysisUtil.generateToken(jwtInfo, bytes, expireTime);
|
||||
return token;
|
||||
}
|
||||
public static String generateToken(JwtInfo jwtInfo, Date expireTime) throws Exception {
|
||||
byte[] bytes = RsaKeyUtil.toBytes(PRI_KEY);
|
||||
LocalDateTime dt = expireTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
String token = JwtAnalysisUtil.generateToken(jwtInfo, bytes, dt);
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -3,6 +3,7 @@ package com.ycwl.basic.utils;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
@@ -12,8 +13,10 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class WxMpUtil {
|
||||
private static final String GET_WXA_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacode?access_token=%s";
|
||||
private static final String GET_WXA_CODE_UNLIMITED_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";
|
||||
private static final String GET_URL_LICK_URL = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=%s";
|
||||
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
|
||||
private static final String STABLE_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/stable_token?grant_type=client_credential&appid=%s&secret=%s&force_refresh=false";
|
||||
public static final String GET_USER_PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";
|
||||
private static final Map<String, String> tokens = new ConcurrentHashMap<>();
|
||||
private static final Map<String, Date> expireTimes = new ConcurrentHashMap<>();
|
||||
@@ -31,12 +34,27 @@ public class WxMpUtil {
|
||||
tokens.remove(appId);
|
||||
}
|
||||
return tokens.computeIfAbsent(appId, (k) -> {
|
||||
String url = String.format(ACCESS_TOKEN_URL, appId, appSecret);
|
||||
String response = HttpUtil.get(url);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
String token = jsonObject.getString("access_token");
|
||||
Date expireTime = new Date(System.currentTimeMillis() + jsonObject.getInteger("expires_in") * 1000 / 2);
|
||||
expireTimes.put(appId, expireTime);
|
||||
String token;
|
||||
if (!System.getProperty("os.name").toLowerCase().startsWith("win")) {
|
||||
String url = String.format(STABLE_ACCESS_TOKEN_URL, appId, appSecret);
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("grant_type", "client_credential");
|
||||
params.put("appid", appId);
|
||||
params.put("secret", appSecret);
|
||||
params.put("force_refresh", false);
|
||||
String response = HttpUtil.post(url, params.toJSONString());
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
token = jsonObject.getString("access_token");
|
||||
Date expireTime = new Date(System.currentTimeMillis() + jsonObject.getInteger("expires_in") * 1000 / 2);
|
||||
expireTimes.put(appId, expireTime);
|
||||
} else {
|
||||
String url = String.format(ACCESS_TOKEN_URL, appId, appSecret);
|
||||
String response = HttpUtil.get(url);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
token = jsonObject.getString("access_token");
|
||||
Date expireTime = new Date(System.currentTimeMillis() + jsonObject.getInteger("expires_in") * 1000 / 2);
|
||||
expireTimes.put(appId, expireTime);
|
||||
}
|
||||
return token;
|
||||
});
|
||||
} finally {
|
||||
@@ -66,6 +84,28 @@ public class WxMpUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateUnlimitedWXAQRCode(String appId, String appSecret, String path, String scene, File targetFile) throws Exception {
|
||||
String url = String.format(GET_WXA_CODE_UNLIMITED_URL, getAccessToken(appId, appSecret));
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("page", path);
|
||||
json.put("scene", scene);
|
||||
json.put("check_path", false);
|
||||
|
||||
try (HttpResponse response = HttpUtil.createPost(url).body(json.toJSONString()).header("Content-Type", "application/json").execute()) {
|
||||
if (response.getStatus() != 200) {
|
||||
throw new Exception("获取小程序二维码失败,原因为:" + response.body());
|
||||
}
|
||||
InputStream inputStream = response.bodyStream();
|
||||
try (FileOutputStream fos = new FileOutputStream(targetFile)) {
|
||||
int len;
|
||||
byte[] buffer = new byte[1024];
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String generateUrlLink(String appId, String appSecret, String path, String query) throws Exception {
|
||||
String url = String.format(GET_URL_LICK_URL, getAccessToken(appId, appSecret));
|
||||
JSONObject json = new JSONObject();
|
||||
|
@@ -28,6 +28,7 @@
|
||||
<update id="update" parameterType="com.ycwl.basic.model.pc.adminUser.req.AddOrUpdateAdminUserReqVO">
|
||||
update admin_user
|
||||
set `role_id` =#{roleId}, `account`=#{account}, `name`=#{name}, `phone`=#{phone}
|
||||
<if test="password != null">, `password`=#{password}</if>, update_at = NOW()
|
||||
where id = #{id}
|
||||
</update>
|
||||
<update id="updatePassword">
|
||||
@@ -77,7 +78,8 @@
|
||||
au.name as staffName,
|
||||
au.id as staffId,
|
||||
au.password,
|
||||
au.role_id
|
||||
au.role_id,
|
||||
au.update_at
|
||||
from admin_user au
|
||||
where account = #{account}
|
||||
and au.status = 1
|
||||
@@ -89,4 +91,16 @@
|
||||
where id = #{id}
|
||||
and status = 1
|
||||
</select>
|
||||
<select id="getById" resultType="com.ycwl.basic.model.pc.adminUser.entity.LoginEntity">
|
||||
select
|
||||
au.account,
|
||||
au.name as staffName,
|
||||
au.id as staffId,
|
||||
au.password,
|
||||
au.role_id,
|
||||
au.update_at
|
||||
from admin_user au
|
||||
where id = #{id}
|
||||
and au.status = 1
|
||||
</select>
|
||||
</mapper>
|
||||
|
17
src/main/resources/mapper/AioDeviceMapper.xml
Normal file
17
src/main/resources/mapper/AioDeviceMapper.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?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="com.ycwl.basic.mapper.AioDeviceMapper">
|
||||
<select id="getById" resultType="com.ycwl.basic.model.aio.entity.AioDeviceEntity">
|
||||
select * from aio_device where id = #{id} limit 1
|
||||
</select>
|
||||
<select id="getByKey" resultType="com.ycwl.basic.model.aio.entity.AioDeviceEntity">
|
||||
select * from aio_device where access_key = #{accessKey} limit 1
|
||||
</select>
|
||||
<select id="getBannerByDeviceId" resultType="com.ycwl.basic.model.aio.entity.AioDeviceBannerEntity">
|
||||
select * from aio_device_banner where device_id = #{deviceId}
|
||||
</select>
|
||||
<select id="getPriceConfigByDeviceId"
|
||||
resultType="com.ycwl.basic.model.aio.entity.AioDevicePriceConfigEntity">
|
||||
select * from aio_device_price_config where id = #{deviceId}
|
||||
</select>
|
||||
</mapper>
|
@@ -109,6 +109,7 @@
|
||||
from device d
|
||||
left join device_preview_config p on d.id = p.device_id and p.status = 1
|
||||
where d.scenic_id = #{scenicId}
|
||||
order by d.sort
|
||||
</select>
|
||||
<select id="deviceCountByScenicId" resultType="com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO">
|
||||
select count(1) totalDeviceCount
|
||||
|
11
src/main/resources/mapper/ExtraDeviceMapper.xml
Normal file
11
src/main/resources/mapper/ExtraDeviceMapper.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?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="com.ycwl.basic.mapper.ExtraDeviceMapper">
|
||||
<select id="listExtraDeviceByScenicId" resultType="com.ycwl.basic.model.pc.device.resp.DeviceRespVO">
|
||||
select d.id, d.ident as no, d.scenic_id, d.name, d.status, s.name as scenic_name
|
||||
from extra_device d
|
||||
left join scenic s on d.scenic_id = s.id
|
||||
where d.scenic_id = #{scenicId}
|
||||
and d.status = 1
|
||||
</select>
|
||||
</mapper>
|
@@ -2,75 +2,18 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ycwl.basic.mapper.MenuMapper">
|
||||
<insert id="addRoleMenu">
|
||||
insert into role_menu(`role_id`, `menu_id`)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{id},#{item})
|
||||
</foreach>
|
||||
replace role_menu(`role_id`, `menu_str`, `perm_str`, `update_time`)
|
||||
values (#{id}, #{menuStr}, #{permStr}, NOW())
|
||||
</insert>
|
||||
<insert id="add">
|
||||
insert into menu(id, parent_id, target, `name`, type, sort, permission_url, is_remove, business_type, icon)
|
||||
values
|
||||
(#{id}, #{parentId}, #{target}, #{name}, #{type}, #{sort}, #{permissionUrl}, #{isRemove}, #{businessType}, #{icon})
|
||||
</insert>
|
||||
<update id="update">
|
||||
update menu
|
||||
<set>
|
||||
<if test="parentId!= null ">
|
||||
parent_id = #{parentId},
|
||||
</if>
|
||||
<if test="target!= null and target!= ''">
|
||||
target = #{target},
|
||||
</if>
|
||||
<if test="name!= null and name!= ''">
|
||||
`name` = #{name},
|
||||
</if>
|
||||
<if test="type!= null ">
|
||||
`type` = #{type},
|
||||
</if>
|
||||
<if test="sort!= null ">
|
||||
sort = #{sort},
|
||||
</if>
|
||||
<if test="permissionUrl!= null and permissionUrl!= ''">
|
||||
permission_url = #{permissionUrl},
|
||||
</if>
|
||||
<if test="businessType!= null ">
|
||||
business_type = #{businessType},
|
||||
</if>
|
||||
<if test="icon!= null and icon!= ''">
|
||||
icon = #{icon},
|
||||
</if>
|
||||
</set>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteRoleMenuByRoleId">
|
||||
delete
|
||||
from role_menu
|
||||
where role_id = #{id}
|
||||
</delete>
|
||||
<delete id="deleteById">
|
||||
update menu set is_remove=1 where id = #{id}
|
||||
</delete>
|
||||
<delete id="deleteRoleMenuByMenuId">
|
||||
delete
|
||||
<select id="getPermissionByRoleId" resultType="com.ycwl.basic.model.pc.role.resp.RolePermissionResp">
|
||||
select role_id, menu_str, perm_str
|
||||
from role_menu
|
||||
where menu_id = #{id}
|
||||
</delete>
|
||||
|
||||
<select id="getListByType" resultType="com.ycwl.basic.model.pc.menu.MenuNode">
|
||||
select id,
|
||||
parent_id,
|
||||
target,
|
||||
`name`,
|
||||
`type`,
|
||||
sort
|
||||
from menu
|
||||
where is_remove = 0
|
||||
<if test="type!= null ">
|
||||
and business_type = #{type}
|
||||
</if>
|
||||
where role_id = #{id}
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
|
@@ -121,6 +121,7 @@
|
||||
WHEN '1' THEN '录像集'
|
||||
WHEN '2' THEN '照片集'
|
||||
WHEN '3' THEN '照片打印'
|
||||
WHEN '4' THEN '一体机照片打印'
|
||||
ELSE '其他'
|
||||
END AS goods_name,
|
||||
CASE oi.goods_type
|
||||
@@ -141,6 +142,7 @@
|
||||
WHEN '1' THEN msd.url
|
||||
WHEN '2' THEN msd.url
|
||||
WHEN '3' THEN mpd.url
|
||||
WHEN '4' THEN msd.url
|
||||
END AS imgUrl
|
||||
FROM order_item oi
|
||||
LEFT JOIN `order` o ON oi.order_id = o.id
|
||||
|
@@ -65,6 +65,19 @@
|
||||
END)
|
||||
where id = #{id}
|
||||
</update>
|
||||
<update id="updateHost">
|
||||
update render_worker
|
||||
set platform = #{status.platform},
|
||||
runtime_version = #{status.runtimeVersion},
|
||||
version = #{status.version},
|
||||
cpu_count = #{status.cpuCount},
|
||||
cpu_usage = #{status.cpuUsage},
|
||||
memory_total = #{status.memoryTotal},
|
||||
memory_available = #{status.memoryAvailable},
|
||||
support_feature = #{status.supportFeature},
|
||||
update_at = #{status.updateAt}
|
||||
where id = #{id}
|
||||
</update>
|
||||
<delete id="deleteById">
|
||||
delete from render_worker where id = #{id}
|
||||
</delete>
|
||||
|
@@ -9,14 +9,16 @@
|
||||
<update id="delete">
|
||||
update
|
||||
role
|
||||
set is_remove=1
|
||||
set is_remove=1,
|
||||
`update_time`=NOW()
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<update id="update" parameterType="com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO">
|
||||
update
|
||||
role
|
||||
set `name`=#{name}
|
||||
set `name`=#{name},
|
||||
`update_time`=NOW()
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
|
@@ -59,7 +59,7 @@
|
||||
select s.scenic_id, s.device_id
|
||||
from member_source ms
|
||||
left join source s on ms.source_id = s.id
|
||||
where ms.type = 1
|
||||
where ms.type = 2
|
||||
and s.create_time >= #{start}
|
||||
and s.create_time <= #{end}
|
||||
group by s.scenic_id, s.device_id, ms.face_id
|
||||
|
@@ -126,7 +126,9 @@
|
||||
pay_config_json=#{payConfigJson},
|
||||
image_source_pack_hint=#{imageSourcePackHint},
|
||||
video_source_pack_hint=#{videoSourcePackHint},
|
||||
extra_notification_time=#{extraNotificationTime}
|
||||
extra_notification_time=#{extraNotificationTime},
|
||||
photo_free_num= #{photoFreeNum},
|
||||
video_free_num= #{videoFreeNum}
|
||||
</set>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
@@ -6,11 +6,11 @@
|
||||
values (#{id}, #{scenicId}, #{deviceId}, #{url}, #{videoUrl}, #{type}, #{faceSampleId}, #{posJson}, #{createTime})
|
||||
</insert>
|
||||
<insert id="addRelation">
|
||||
replace member_source(scenic_id, face_id, member_id, source_id, is_buy, type, order_id, is_free)
|
||||
values (#{scenicId}, #{faceId}, #{memberId}, #{sourceId}, #{isBuy}, #{type}, #{orderId}, #{isFree})
|
||||
replace member_source(scenic_id, face_id, member_id, source_id, is_buy, type, order_id<if test="isFree">, is_free</if>)
|
||||
values (#{scenicId}, #{faceId}, #{memberId}, #{sourceId}, #{isBuy}, #{type}, #{orderId}<if test="isFree">, #{isFree}</if>)
|
||||
</insert>
|
||||
<insert id="addRelations">
|
||||
replace member_source(scenic_id, face_id, member_id, source_id, is_buy, type, order_id, is_free)
|
||||
insert IGNORE member_source(scenic_id, face_id, member_id, source_id, is_buy, type, order_id, is_free)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.scenicId}, #{item.faceId}, #{item.memberId}, #{item.sourceId}, #{item.isBuy}, #{item.type}, #{item.orderId}, #{item.isFree})
|
||||
@@ -42,6 +42,14 @@
|
||||
</set>
|
||||
where member_id = #{memberId} and face_id = #{faceId} and `type` = #{type}
|
||||
</update>
|
||||
<update id="freeRelations">
|
||||
update member_source
|
||||
set is_free = 1
|
||||
where type = #{type} and id in
|
||||
<foreach item="item" collection="ids" open="(" separator="," close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
</update>
|
||||
<delete id="deleteById">
|
||||
delete from source where id = #{id}
|
||||
</delete>
|
||||
@@ -227,4 +235,11 @@
|
||||
<if test="type!=null">and ms.type = #{type} </if>
|
||||
<if test="faceId!=null">and ms.face_id = #{faceId} </if>
|
||||
</select>
|
||||
<select id="listByFaceRelation" resultType="com.ycwl.basic.model.pc.source.entity.MemberSourceEntity">
|
||||
select *
|
||||
from member_source ms
|
||||
where ms.member_id = #{memberId}
|
||||
and ms.face_id = #{faceId}
|
||||
<if test="type!=null">and ms.type = #{type} </if>
|
||||
</select>
|
||||
</mapper>
|
||||
|
@@ -12,10 +12,10 @@
|
||||
where
|
||||
(status = 1 or status = 2) and scenic_id = #{scenicId}
|
||||
<if test="startTime!= null">
|
||||
and create_at >= #{startTime}
|
||||
and pay_at >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime!= null">
|
||||
and create_at <= #{endTime}
|
||||
and pay_at <= #{endTime}
|
||||
</if>
|
||||
</select>
|
||||
<select id="countPreviewVideoOfMember" resultType="java.lang.Integer">
|
||||
@@ -61,17 +61,20 @@
|
||||
SELECT
|
||||
IFNULL(count(1), 0) AS count
|
||||
FROM (
|
||||
select count(1) as count
|
||||
from `order`
|
||||
where scenic_id = #{scenicId}
|
||||
select 1
|
||||
FROM `t_stats_record` r
|
||||
left join `t_stats` s on r.trace_id=s.trace_id
|
||||
where r.trace_id in (select trace_id from `t_stats_record` where action = 'ENTER_SCENIC' and `identifier`=#{scenicId})
|
||||
and action = 'CLICK'
|
||||
and identifier = 'BUY'
|
||||
<if test="startTime!= null">
|
||||
and create_at >= #{startTime}
|
||||
and s.create_time >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime!= null">
|
||||
and create_at <= #{endTime}
|
||||
and s.create_time <= #{endTime}
|
||||
</if>
|
||||
group by member_id
|
||||
)a
|
||||
group by s.member_id
|
||||
) AS subquery;
|
||||
</select>
|
||||
<select id="countPayOfMember" resultType="java.lang.Integer">
|
||||
SELECT
|
||||
|
@@ -112,7 +112,7 @@
|
||||
</select>
|
||||
<select id="listFor" resultType="com.ycwl.basic.model.mobile.scenic.content.ContentPageVO">
|
||||
select t.id templateId, t.scenic_id, s.name as scenic_name, t.`name`, pid, t.cover_url templateCoverUrl,
|
||||
0 as sourceType,
|
||||
0 as sourceType, sort,
|
||||
t.create_time, t.price
|
||||
from template t left join scenic s on s.id = t.scenic_id
|
||||
where t.scenic_id = #{scenicId} and pid = 0 and t.status = 1
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 1.3 MiB |
@@ -16,7 +16,7 @@ public class WatermarkOperatorTest {
|
||||
@Test
|
||||
public void testProcess() throws Exception {
|
||||
WatermarkInfo info = new WatermarkInfo();
|
||||
info.setOriginalFile(new File("e2d32de7-6e85-4e07-b42f-477347073539.jpg"));
|
||||
info.setOriginalFile(new File("38e1285c-84d0-464a-810d-053e9502e257.jpg"));
|
||||
info.setQrcodeFile(new File("cxzh_t.jpg"));
|
||||
info.setScenicLine("川西竹海一日游!");
|
||||
info.setDatetimeLine("2XXX年XX月XX日 留念");
|
||||
|
Reference in New Issue
Block a user