You've already forked FrameTour-BE
Compare commits
1 Commits
master
...
8a17392ae5
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a17392ae5 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,7 +1,3 @@
|
||||
.idea/
|
||||
logs/
|
||||
target/
|
||||
.serena
|
||||
.claude
|
||||
.vscode
|
||||
*.jpg
|
||||
|
||||
27
AGENTS.md
27
AGENTS.md
@@ -1,27 +0,0 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- Build artifact: `mvn clean package` (tests are skipped by default via `pom.xml`).
|
||||
- Run locally (dev): `mvn spring-boot:run -Dspring-boot.run.profiles=dev`.
|
||||
- Run jar: `java -jar target/basic21-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev`.
|
||||
- Execute all tests: `mvn -DskipTests=false test` (note: `pom.xml` excludes `**/*Test.java` from test-compile; temporarily remove/override that config if you need to compile and run tests).
|
||||
- Run single test: `mvn -DskipTests=false test -Dtest=ClassNameTest` (after removing testExcludes from maven-compiler-plugin).
|
||||
|
||||
## Code Style Guidelines
|
||||
- Java 21. Use 4-space indentation; UTF-8; no wildcard imports.
|
||||
- Packages: `com.ycwl.basic.*`; classes PascalCase; methods/fields camelCase; constants UPPER_SNAKE_CASE.
|
||||
- Controllers in `controller`, business logic in `service`, persistence in `mapper` + `resources/mapper/*.xml`.
|
||||
- Prefer Lombok for boilerplate and constructor injection where applicable.
|
||||
- Error handling: Use custom exceptions in `exception` package; proper logging with SLF4J.
|
||||
- Testing: Spring Boot testing + JUnit; test names end with `Test` or `Tests` and mirror package structure.
|
||||
|
||||
## Project Structure
|
||||
- Application code: `src/main/java/com/ycwl/basic/**` (controllers, services, mapper/repository, dto/model, config, util).
|
||||
- Resources: `src/main/resources/**` (Spring configs, `mapper/*.xml`, static assets, logging).
|
||||
- Tests: `src/test/java/**` mirrors main packages.
|
||||
- Build output: `target/` (never commit).
|
||||
|
||||
## Agent-Specific Notes
|
||||
- Keep changes minimal and within existing package boundaries.
|
||||
- Do not reorganize MyBatis XML names or mapper interfaces without updating both sides.
|
||||
- If altering APIs, update affected tests and documentation in the same PR.
|
||||
27
CLAUDE.md
27
CLAUDE.md
@@ -1,27 +0,0 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- Build artifact: `mvn clean package` (tests are skipped by default via `pom.xml`).
|
||||
- Run locally (dev): `mvn spring-boot:run -Dspring-boot.run.profiles=dev`.
|
||||
- Run jar: `java -jar target/basic21-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev`.
|
||||
- Execute all tests: `mvn -DskipTests=false test` (note: `pom.xml` excludes `**/*Test.java` from test-compile; temporarily remove/override that config if you need to compile and run tests).
|
||||
- Run single test: `mvn -DskipTests=false test -Dtest=ClassNameTest` (after removing testExcludes from maven-compiler-plugin).
|
||||
|
||||
## Code Style Guidelines
|
||||
- Java 21. Use 4-space indentation; UTF-8; no wildcard imports.
|
||||
- Packages: `com.ycwl.basic.*`; classes PascalCase; methods/fields camelCase; constants UPPER_SNAKE_CASE.
|
||||
- Controllers in `controller`, business logic in `service`, persistence in `mapper` + `resources/mapper/*.xml`.
|
||||
- Prefer Lombok for boilerplate and constructor injection where applicable.
|
||||
- Error handling: Use custom exceptions in `exception` package; proper logging with SLF4J.
|
||||
- Testing: Spring Boot testing + JUnit; test names end with `Test` or `Tests` and mirror package structure.
|
||||
|
||||
## Project Structure
|
||||
- Application code: `src/main/java/com/ycwl/basic/**` (controllers, services, mapper/repository, dto/model, config, util).
|
||||
- Resources: `src/main/resources/**` (Spring configs, `mapper/*.xml`, static assets, logging).
|
||||
- Tests: `src/test/java/**` mirrors main packages.
|
||||
- Build output: `target/` (never commit).
|
||||
|
||||
## Agent-Specific Notes
|
||||
- Keep changes minimal and within existing package boundaries.
|
||||
- Do not reorganize MyBatis XML names or mapper interfaces without updating both sides.
|
||||
- If altering APIs, update affected tests and documentation in the same PR.
|
||||
12
Jenkinsfile
vendored
12
Jenkinsfile
vendored
@@ -1,20 +1,20 @@
|
||||
pipeline {
|
||||
agent any
|
||||
tools {
|
||||
jdk 'openjdk21'
|
||||
maven 'Default'
|
||||
environment {
|
||||
JAVA_HOME = "/opt/openjdk21.0.7"
|
||||
MAVEN_HOME = "/opt/apache-maven-3.9.9"
|
||||
PATH = "${env.JAVA_HOME}/bin:${env.MAVEN_HOME}/bin:${env.PATH}"
|
||||
}
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn clean package -DskipTests=true'
|
||||
bat 'mvn clean package -DskipTests=true'
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: 'target/*.jar', allowEmptyArchive: true, onlyIfSuccessful: true
|
||||
publishGiteaAssets assets: 'target/*.jar', followSymlinks: false, onlyIfSuccessful: true
|
||||
archiveArtifacts artifacts: 'target/*.jar', allowEmptyArchive: false
|
||||
}
|
||||
}
|
||||
}
|
||||
139
pom.xml
139
pom.xml
@@ -19,30 +19,21 @@
|
||||
<java.version>21</java.version>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<spring.cloud.alibaba.version>2023.0.1.2</spring.cloud.alibaba.version>
|
||||
<spring.cloud.version>2023.0.3</spring.cloud.version>
|
||||
<hutool-all.version>5.8.24</hutool-all.version>
|
||||
<mysql-connector.version>8.0.33</mysql-connector.version>
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<knife4j-spring-boot-starter.version>2.0.7</knife4j-spring-boot-starter.version>
|
||||
<pagehelper.version>5.3.1</pagehelper.version>
|
||||
<!--跳过单元测试-->
|
||||
<skipTests>true</skipTests>
|
||||
</properties>
|
||||
<!-- Dependency Management -->
|
||||
<!-- OpenTelemetry -->
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- Spring Cloud BOM -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring.cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- Spring Cloud Alibaba BOM -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>${spring.cloud.alibaba.version}</version>
|
||||
<groupId>io.opentelemetry.instrumentation</groupId>
|
||||
<artifactId>opentelemetry-instrumentation-bom</artifactId>
|
||||
<version>2.16.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -75,47 +66,6 @@
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- WebSocket -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Nacos服务发现 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Nacos配置中心 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- OpenFeign -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud Bootstrap -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Validation -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 引入redis,并且redis使用jedis连接 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -124,9 +74,9 @@
|
||||
|
||||
<!-- 引入mysql连接 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>8.3.0</version>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql-connector.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -173,30 +123,24 @@
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.3.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson JSON处理库 -->
|
||||
<!-- json处理工具 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 引入commons-lang3 工具类 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.18.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 引入接口文档工具 -->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>${knife4j-spring-boot-starter.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- pageHelper -->
|
||||
@@ -225,7 +169,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.11.0</version>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里云对象存储 -->
|
||||
@@ -266,36 +210,9 @@
|
||||
<version>4.16.19</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里云媒体处理 -->
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>mts20140618</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 智谱AI SDK -->
|
||||
<dependency>
|
||||
<groupId>ai.z.openapi</groupId>
|
||||
<artifactId>zai-sdk</artifactId>
|
||||
<version>0.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Kafka -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.kafka</groupId>
|
||||
<artifactId>spring-kafka</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache POI - 处理Excel文件 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>5.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.4.0</version>
|
||||
<groupId>io.opentelemetry.instrumentation</groupId>
|
||||
<artifactId>opentelemetry-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -324,6 +241,16 @@
|
||||
<skip>${skipTests}</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- 跳过测试编译 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<testExcludes>
|
||||
<testExclude>**/*Test.java</testExclude>
|
||||
</testExcludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.ycwl.basic;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients
|
||||
@MapperScan(basePackages = "com.ycwl.basic.mapper")
|
||||
@MapperScan(basePackages = "com.ycwl.basic.*.mapper")
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.ycwl.basic.aspectj;
|
||||
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ycwl.basic.annotation.IgnoreLogReq;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
@@ -67,10 +67,10 @@ public class RequestParameterAspectj {
|
||||
}
|
||||
|
||||
if (parameterUrlMap.isEmpty()) {
|
||||
LOGGER.info("当前请求的路径为-> {} 请求方式为-> {} 参数为-> {}", requestURI, method, JacksonUtil.toJSONString(parameterValueSet));
|
||||
LOGGER.info("当前请求的路径为-> {} 请求方式为-> {} 参数为-> {}", requestURI, method, JSON.toJSONString(parameterValueSet));
|
||||
} else {
|
||||
LOGGER.info("当前请求的路径为-> {} 请求方式为-> {} 参数为-> {} 路径传参为-> {}", requestURI, method,
|
||||
JacksonUtil.toJSONString(parameterValueSet), JacksonUtil.toJSONString(parameterUrlMap));
|
||||
JSON.toJSONString(parameterValueSet), JSON.toJSONString(parameterUrlMap));
|
||||
}
|
||||
}
|
||||
return joinPoint.proceed();
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.ycwl.basic.biz;
|
||||
|
||||
import com.ycwl.basic.enums.StatisticEnum;
|
||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||
import com.ycwl.basic.mapper.OrderMapper;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.mapper.StatisticsMapper;
|
||||
import com.ycwl.basic.mapper.VideoMapper;
|
||||
import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO;
|
||||
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
||||
import com.ycwl.basic.model.mobile.order.PriceObj;
|
||||
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
|
||||
@@ -15,18 +13,17 @@ import com.ycwl.basic.model.pc.couponRecord.resp.CouponRecordQueryResp;
|
||||
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.model.pc.order.req.OrderUpdateReq;
|
||||
import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO;
|
||||
import com.ycwl.basic.model.pc.order.resp.OrderItemVO;
|
||||
import com.ycwl.basic.model.pc.order.resp.OrderRespVO;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
|
||||
import com.ycwl.basic.pricing.dto.PriceCalculationRequest;
|
||||
import com.ycwl.basic.pricing.dto.PriceCalculationResult;
|
||||
import com.ycwl.basic.pricing.dto.ProductItem;
|
||||
import com.ycwl.basic.pricing.enums.ProductType;
|
||||
import com.ycwl.basic.pricing.service.IPriceCalculationService;
|
||||
import com.ycwl.basic.model.pc.video.resp.VideoRespVO;
|
||||
import com.ycwl.basic.profitsharing.biz.ProfitSharingBiz;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.OrderRepository;
|
||||
@@ -36,12 +33,13 @@ import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
import com.ycwl.basic.repository.VideoTaskRepository;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.Calendar;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -81,16 +79,16 @@ public class OrderBiz {
|
||||
@Autowired
|
||||
@Lazy
|
||||
private PrinterService printerService;
|
||||
@Autowired
|
||||
private IPriceCalculationService iPriceCalculationService;
|
||||
|
||||
public PriceObj queryPrice(Long scenicId, int goodsType, Long goodsId) {
|
||||
PriceObj priceObj = new PriceObj();
|
||||
priceObj.setGoodsType(goodsType);
|
||||
priceObj.setGoodsId(goodsId);
|
||||
ScenicEntity scenic = scenicRepository.getScenic(scenicId);
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
priceObj.setScenicAllPrice(scenic.getPrice());
|
||||
if (scenicConfig != null) {
|
||||
if (Boolean.TRUE.equals(scenicConfig.getAllFree())) {
|
||||
if (Integer.valueOf(1).equals(scenicConfig.getAllFree())) {
|
||||
// 景区全免
|
||||
priceObj.setFree(true);
|
||||
priceObj.setPrice(BigDecimal.ZERO);
|
||||
@@ -112,62 +110,31 @@ public class OrderBiz {
|
||||
if (template == null) {
|
||||
return priceObj;
|
||||
}
|
||||
PriceCalculationRequest vlogCalculationRequest = new PriceCalculationRequest();
|
||||
ProductItem vlogProductItem = new ProductItem();
|
||||
vlogProductItem.setProductType(ProductType.VLOG_VIDEO);
|
||||
vlogProductItem.setProductId(template.getId().toString());
|
||||
vlogProductItem.setQuantity(videoTaskRepository.getTaskLensNum(video.getTaskId()));
|
||||
vlogProductItem.setScenicId(scenicId.toString());
|
||||
vlogCalculationRequest.setProducts(Collections.singletonList(vlogProductItem));
|
||||
vlogCalculationRequest.setFaceId(priceObj.getFaceId());
|
||||
vlogCalculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult vlogCalculationResult = iPriceCalculationService.calculatePrice(vlogCalculationRequest);
|
||||
priceObj.setPrice(vlogCalculationResult.getFinalAmount());
|
||||
priceObj.setSlashPrice(vlogCalculationResult.getOriginalAmount());
|
||||
priceObj.setFaceId(goodsId);
|
||||
priceObj.setPrice(template.getPrice());
|
||||
BigDecimal slashPrice = template.getSlashPrice();
|
||||
if (slashPrice == null) {
|
||||
priceObj.setSlashPrice(priceObj.getPrice());
|
||||
} else {
|
||||
priceObj.setSlashPrice(slashPrice);
|
||||
}
|
||||
priceObj.setScenicId(video.getScenicId());
|
||||
break;
|
||||
case 1: // source
|
||||
case 2: // source
|
||||
FaceEntity face = faceRepository.getFace(goodsId);
|
||||
PriceCalculationRequest calculationRequest = new PriceCalculationRequest();
|
||||
ProductItem productItem = new ProductItem();
|
||||
productItem.setProductType(goodsType == 1 ? ProductType.RECORDING_SET : ProductType.PHOTO_SET);
|
||||
productItem.setProductId(scenicId.toString());
|
||||
productItem.setPurchaseCount(1);
|
||||
productItem.setScenicId(scenicId.toString());
|
||||
calculationRequest.setProducts(Collections.singletonList(productItem));
|
||||
if (face != null) {
|
||||
calculationRequest.setUserId(face.getMemberId());
|
||||
}
|
||||
calculationRequest.setFaceId(goodsId);
|
||||
calculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult priceCalculationResult = iPriceCalculationService.calculatePrice(calculationRequest);
|
||||
priceObj.setPrice(priceCalculationResult.getFinalAmount());
|
||||
priceObj.setSlashPrice(priceCalculationResult.getOriginalAmount());
|
||||
priceObj.setPrice(scenic.getSourceVideoPrice());
|
||||
priceObj.setSlashPrice(scenic.getSourceVideoPrice());
|
||||
priceObj.setFaceId(goodsId);
|
||||
break;
|
||||
case 13:
|
||||
PriceCalculationRequest aiCamCalculationRequest = new PriceCalculationRequest();
|
||||
ProductItem aiCamProductItem = new ProductItem();
|
||||
aiCamProductItem.setProductType(ProductType.AI_CAM_PHOTO_SET);
|
||||
aiCamProductItem.setProductId(scenicId.toString());
|
||||
aiCamProductItem.setPurchaseCount(1);
|
||||
aiCamProductItem.setScenicId(scenicId.toString());
|
||||
aiCamCalculationRequest.setProducts(Collections.singletonList(aiCamProductItem));
|
||||
aiCamCalculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult aiCamPriceCalculationResult = iPriceCalculationService.calculatePrice(aiCamCalculationRequest);
|
||||
priceObj.setPrice(aiCamPriceCalculationResult.getFinalAmount());
|
||||
priceObj.setSlashPrice(aiCamPriceCalculationResult.getOriginalAmount());
|
||||
case 2: // source
|
||||
priceObj.setPrice(scenic.getSourceImagePrice());
|
||||
priceObj.setSlashPrice(scenic.getSourceImagePrice());
|
||||
priceObj.setFaceId(goodsId);
|
||||
priceObj.setScenicId(scenicId);
|
||||
break;
|
||||
}
|
||||
return priceObj;
|
||||
}
|
||||
|
||||
public OrderEntity hasTypeOrder(Long userId, Long faceId, Long scenicId, int orderType, Integer configId) {
|
||||
OrderEntity orderEntity = orderMapper.queryTypeOrder(userId, faceId, scenicId, orderType, configId);
|
||||
public OrderEntity hasTypeOrder(Long userId, Long scenicId, int orderType, Integer configId) {
|
||||
OrderEntity orderEntity = orderMapper.queryTypeOrder(userId, scenicId, orderType, configId);
|
||||
if (orderEntity == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -177,46 +144,82 @@ public class OrderBiz {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public IsBuyRespVO isBuy(Long scenicId, Long memberId, Long faceId, int goodsType, Long goodsId) {
|
||||
|
||||
public IsBuyRespVO isBuy(Long userId, Long scenicId, int goodsType, Long goodsId) {
|
||||
IsBuyRespVO respVO = new IsBuyRespVO();
|
||||
respVO.setGoodsType(goodsType);
|
||||
respVO.setGoodsId(goodsId);
|
||||
OrderEntity orderEntity = orderMapper.getUserBuyFaceItem(memberId, faceId, goodsType, goodsId);
|
||||
boolean isBuy = orderRepository.checkUserBuyItem(userId, goodsType, goodsId);
|
||||
// 模板购买逻辑
|
||||
if (!isBuy) {
|
||||
if (goodsType == 0) {
|
||||
VideoEntity video = videoRepository.getVideo(goodsId);
|
||||
TaskEntity task = videoTaskRepository.getTaskById(video.getTaskId());
|
||||
Long templateId = video.getTemplateId();
|
||||
// -1为整个模板购买
|
||||
OrderEntity orderEntity = orderRepository.getUserBuyItem(userId, -1, templateId);
|
||||
if (orderEntity != null && task != null) {
|
||||
respVO.setOrderId(orderEntity.getId());
|
||||
if (orderEntity.getFaceId() != null && task.getFaceId() != null) {
|
||||
isBuy = orderEntity.getFaceId().equals(task.getFaceId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 免费送逻辑,之前已经赠送了的
|
||||
if (!isBuy) {
|
||||
isBuy = switch (goodsType) {
|
||||
case 0 -> videoRepository.getUserIsBuy(userId, goodsId);
|
||||
case 1, 2 -> sourceRepository.getUserIsBuy(userId, goodsType, goodsId);
|
||||
default -> false;
|
||||
};
|
||||
} else {
|
||||
OrderEntity orderEntity = orderRepository.getUserBuyItem(userId, goodsType, goodsId);
|
||||
if (orderEntity != null) {
|
||||
respVO.setOrderId(orderEntity.getId());
|
||||
respVO.setBuy(true);
|
||||
respVO.setFree(false);
|
||||
return respVO;
|
||||
}
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
if (Boolean.TRUE.equals(scenicConfig.getBoolean("all_free"))) {
|
||||
// 景区全免
|
||||
respVO.setFree(true);
|
||||
respVO.setOrigPrice(BigDecimal.ZERO);
|
||||
respVO.setSlashPrice(BigDecimal.ZERO);
|
||||
return respVO;
|
||||
}
|
||||
// 未来模板一口价
|
||||
if (goodsType == 0) {
|
||||
// 视频,可以买断模板
|
||||
VideoEntity video = videoRepository.getVideo(goodsId);
|
||||
if (video != null && video.getTemplateId() != null) {
|
||||
OrderEntity templateBuy = orderMapper.getUserBuyFaceItem(memberId, faceId, -1, video.getTemplateId());
|
||||
if (templateBuy != null) {
|
||||
respVO.setOrderId(templateBuy.getId());
|
||||
respVO.setBuy(true);
|
||||
respVO.setFree(false);
|
||||
return respVO;
|
||||
}
|
||||
}
|
||||
}
|
||||
respVO.setBuy(isBuy);
|
||||
// 还是没买
|
||||
if (!isBuy) {
|
||||
PriceObj priceObj = queryPrice(scenicId, goodsType, goodsId);
|
||||
if (priceObj == null) {
|
||||
return respVO;
|
||||
}
|
||||
respVO.setBuy(false);
|
||||
respVO.setFree(priceObj.isFree());
|
||||
respVO.setGoodsType(goodsType);
|
||||
respVO.setGoodsId(goodsId);
|
||||
respVO.setOrigPrice(priceObj.getPrice());
|
||||
respVO.setSlashPrice(priceObj.getSlashPrice());
|
||||
switch (goodsType) {
|
||||
case 0: // vlog
|
||||
VideoEntity video = videoRepository.getVideo(goodsId);
|
||||
TaskEntity taskById = videoTaskRepository.getTaskById(video.getTaskId());
|
||||
if (taskById != null) {
|
||||
CouponRecordQueryResp recordQueryResp = couponBiz.queryUserCouponRecord(scenicId, userId, taskById.getFaceId(), taskById.getTemplateId().toString());
|
||||
if (recordQueryResp.isUsable()) {
|
||||
respVO.setCouponId(recordQueryResp.getCouponId());
|
||||
respVO.setCouponRecordId(recordQueryResp.getId());
|
||||
CouponEntity coupon = recordQueryResp.getCoupon();
|
||||
if (coupon != null) {
|
||||
respVO.setCouponPrice(coupon.calculateDiscountPrice(priceObj.getPrice()));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
CouponRecordQueryResp recordQueryResp = couponBiz.queryUserCouponRecord(scenicId, userId, goodsId, String.valueOf(goodsType));
|
||||
if (recordQueryResp.isUsable()) {
|
||||
respVO.setCouponId(recordQueryResp.getCouponId());
|
||||
respVO.setCouponRecordId(recordQueryResp.getId());
|
||||
CouponEntity coupon = recordQueryResp.getCoupon();
|
||||
if (coupon != null) {
|
||||
respVO.setCouponPrice(coupon.calculateDiscountPrice(priceObj.getPrice()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@@ -230,27 +233,51 @@ public class OrderBiz {
|
||||
orderRepository.updateOrder(orderId, orderUpdate);
|
||||
orderItems.forEach(item -> {
|
||||
switch (item.getGoodsType()) {
|
||||
case -1: // vlog视频模板
|
||||
videoRepository.setUserIsBuyTemplate(order.getMemberId(), item.getGoodsId(), order.getId(), order.getFaceId());
|
||||
break;
|
||||
case 0: // vlog视频
|
||||
videoRepository.setUserIsBuyItem(order.getMemberId(), item.getGoodsId(), order.getId());
|
||||
break;
|
||||
case 1: // 视频原素材
|
||||
case 2: // 照片原素材
|
||||
case 13: // AI微单
|
||||
sourceRepository.setUserIsBuyItem(order.getMemberId(), item.getGoodsType(), item.getGoodsId(), order.getId());
|
||||
break;
|
||||
case 3:
|
||||
printerService.setUserIsBuyItem(order.getMemberId(), item.getGoodsId(), order.getId());
|
||||
break;
|
||||
}
|
||||
});
|
||||
orderRepository.clearOrderCache(orderId); // 更新完了,清理下
|
||||
Integer couponRecordId = order.getCouponRecordId();
|
||||
if (couponRecordId != null) {
|
||||
couponBiz.userUseCoupon(order.getMemberId(), order.getFaceId(), couponRecordId, orderId);
|
||||
if (order.getCouponRecordId() != null) {
|
||||
couponBiz.userUseCoupon(order.getMemberId(), order.getFaceId(), order.getCouponRecordId(), orderId);
|
||||
}
|
||||
|
||||
//支付时间
|
||||
OrderAppRespVO orderDetail = orderMapper.appDetail(orderId);
|
||||
Date payAt = orderDetail.getPayAt();
|
||||
//商品创建时间
|
||||
Date goodsCreateTime = new Date();
|
||||
if (!orderDetail.getOrderItemList().isEmpty()) {
|
||||
OrderItemVO orderItemVO = orderDetail.getOrderItemList().getFirst();
|
||||
switch (orderItemVO.getGoodsType()) {
|
||||
case 0:
|
||||
VideoEntity video = videoRepository.getVideo(orderItemVO.getGoodsId());
|
||||
if (video != null) {
|
||||
goodsCreateTime = video.getCreateTime();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
List<SourceEntity> imageSource = sourceMapper.listImageByFaceRelation(order.getMemberId(), orderItemVO.getGoodsId());
|
||||
Optional<SourceEntity> min = imageSource.stream().min(Comparator.comparing(SourceEntity::getCreateTime));
|
||||
if (min.isPresent()) {
|
||||
goodsCreateTime = min.get().getCreateTime();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
List<SourceEntity> videoSource = sourceMapper.listImageByFaceRelation(order.getMemberId(), orderItemVO.getGoodsId());
|
||||
Optional<SourceEntity> minTime = videoSource.stream().min(Comparator.comparing(SourceEntity::getCreateTime));
|
||||
if (minTime.isPresent()) {
|
||||
goodsCreateTime = minTime.get().getCreateTime();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
|
||||
statisticsRecordAddReq.setMemberId(order.getMemberId());
|
||||
Long enterType = statisticsMapper.getUserRecentEnterType(order.getMemberId(), order.getCreateAt());
|
||||
@@ -278,11 +305,9 @@ public class OrderBiz {
|
||||
switch (item.getGoodsType()) {
|
||||
case 0: // vlog视频
|
||||
videoRepository.setUserNotBuyItem(order.getMemberId(), item.getGoodsId());
|
||||
break;
|
||||
case 1: // 视频原素材
|
||||
case 2: // 照片原素材
|
||||
sourceRepository.setUserNotBuyItem(order.getMemberId(), item.getGoodsType(), item.getGoodsId());
|
||||
break;
|
||||
}
|
||||
});
|
||||
orderRepository.clearOrderCache(orderId); // 更新完了,清理下
|
||||
@@ -302,26 +327,12 @@ public class OrderBiz {
|
||||
switch (item.getGoodsType()) {
|
||||
case 0: // vlog视频
|
||||
videoRepository.setUserNotBuyItem(order.getMemberId(), item.getGoodsId());
|
||||
break;
|
||||
case 1: // 视频原素材
|
||||
case 2: // 照片原素材
|
||||
sourceRepository.setUserNotBuyItem(order.getMemberId(), item.getGoodsType(), item.getGoodsId());
|
||||
break;
|
||||
}
|
||||
});
|
||||
orderRepository.clearOrderCache(orderId); // 更新完了,清理下
|
||||
profitSharingBiz.revokeProfitSharing(order.getScenicId(), orderId, "订单已退款");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否购买了指定商品,并额外校验订单的faceId是否匹配
|
||||
* @param userId 用户ID
|
||||
* @param faceId 人脸ID
|
||||
* @param goodsType 商品类型
|
||||
* @param goodsId 商品ID
|
||||
* @return 是否已购买且faceId匹配
|
||||
*/
|
||||
public boolean checkUserBuyFaceItem(Long userId, Long faceId, int goodsType, Long goodsId) {
|
||||
return orderRepository.checkUserBuyFaceItem(userId, faceId, goodsType, goodsId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,23 +7,14 @@ import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
|
||||
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
|
||||
import com.ycwl.basic.model.pc.price.resp.SimpleGoodsRespVO;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
|
||||
import com.ycwl.basic.product.capability.ProductTypeCapability;
|
||||
import com.ycwl.basic.product.service.IProductTypeCapabilityManagementService;
|
||||
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
|
||||
import com.ycwl.basic.puzzle.mapper.PuzzleTemplateMapper;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.MemberRelationRepository;
|
||||
import com.ycwl.basic.repository.PriceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import org.apache.commons.lang3.Strings;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -45,16 +36,7 @@ public class PriceBiz {
|
||||
@Autowired
|
||||
private FaceRepository faceRepository;
|
||||
@Autowired
|
||||
@Lazy
|
||||
private FaceService faceService;
|
||||
@Autowired
|
||||
private CouponBiz couponBiz;
|
||||
@Autowired
|
||||
private MemberRelationRepository memberRelationRepository;
|
||||
@Autowired
|
||||
private PuzzleTemplateMapper puzzleTemplateMapper;
|
||||
@Autowired
|
||||
private IProductTypeCapabilityManagementService productTypeCapabilityManagementService;
|
||||
|
||||
public List<GoodsListRespVO> listGoodsByScenic(Long scenicId) {
|
||||
List<GoodsListRespVO> goodsList = new ArrayList<>();
|
||||
@@ -64,129 +46,17 @@ public class PriceBiz {
|
||||
GoodsListRespVO goods = new GoodsListRespVO();
|
||||
goods.setGoodsId(template.getId());
|
||||
goods.setGoodsName(template.getName());
|
||||
goods.setGoodsType(0);
|
||||
return goods;
|
||||
}).forEach(goodsList::add);
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null) {
|
||||
if (!Boolean.TRUE.equals(scenicConfig.getDisableSourceVideo())) {
|
||||
goodsList.add(new GoodsListRespVO(1L, "录像集", 1));
|
||||
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
|
||||
goodsList.add(new GoodsListRespVO(1L, "录像集"));
|
||||
}
|
||||
if (!Boolean.TRUE.equals(scenicConfig.getDisableSourceImage())) {
|
||||
goodsList.add(new GoodsListRespVO(2L, "照片集", 2));
|
||||
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage())) {
|
||||
goodsList.add(new GoodsListRespVO(2L, "照片集"));
|
||||
}
|
||||
}
|
||||
// 拼图
|
||||
puzzleTemplateMapper.list(scenicId, null, 1).forEach(puzzleTemplate -> {
|
||||
GoodsListRespVO goods = new GoodsListRespVO();
|
||||
goods.setGoodsId(puzzleTemplate.getId());
|
||||
goods.setGoodsName(puzzleTemplate.getName());
|
||||
goods.setGoodsType(5);
|
||||
goodsList.add(goods);
|
||||
});
|
||||
return goodsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据景区ID和商品类型查询简化的商品列表
|
||||
*
|
||||
* @param scenicId 景区ID
|
||||
* @param productType 商品类型(可选,为空时返回所有商品)
|
||||
* @return 简化的商品列表
|
||||
*/
|
||||
public List<SimpleGoodsRespVO> listSimpleGoodsByScenic(Long scenicId, String productType) {
|
||||
List<SimpleGoodsRespVO> goodsList = new ArrayList<>();
|
||||
|
||||
// 如果 productType 为空,兼容旧逻辑
|
||||
if (productType == null || productType.isEmpty()) {
|
||||
return listAllSimpleGoods(scenicId);
|
||||
}
|
||||
|
||||
// 根据 productType 查询不同数据源
|
||||
switch (productType) {
|
||||
case "VLOG_VIDEO":
|
||||
// 从 template 表查询视频模板
|
||||
List<TemplateRespVO> templateList = templateRepository.getTemplateListByScenicId(scenicId);
|
||||
templateList.stream()
|
||||
.map(template -> new SimpleGoodsRespVO(template.getId(), template.getName(), productType))
|
||||
.forEach(goodsList::add);
|
||||
break;
|
||||
|
||||
case "PHOTO_VLOG":
|
||||
// TODO
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "【待实现】pLog视频", productType));
|
||||
break;
|
||||
|
||||
case "PHOTO":
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "单张照片", productType));
|
||||
break;
|
||||
|
||||
case "PHOTO_SET":
|
||||
// 返回固定的照片集条目
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "照片集", productType));
|
||||
break;
|
||||
|
||||
case "AI_CAM_PHOTO_SET":
|
||||
// 返回固定的照片集条目
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "AI微单照片集", productType));
|
||||
break;
|
||||
|
||||
case "PHOTO_LOG":
|
||||
// 从 template 表查询pLog模板
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "pLog图<景区打包>", productType));
|
||||
List<PuzzleTemplateEntity> puzzleList = puzzleTemplateMapper.list(scenicId, null, null);
|
||||
puzzleList.stream()
|
||||
.map(template -> new SimpleGoodsRespVO(template.getId(), template.getName(), productType))
|
||||
.forEach(goodsList::add);
|
||||
break;
|
||||
|
||||
case "RECORDING_SET":
|
||||
// 返回固定的录像集条目
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "录像集", productType));
|
||||
break;
|
||||
|
||||
case "PHOTO_PRINT":
|
||||
// 打印类返回单一通用条目
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "照片打印", productType));
|
||||
break;
|
||||
case "PHOTO_PRINT_MU":
|
||||
// 打印类返回单一通用条目
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "手机照片打印", productType));
|
||||
break;
|
||||
case "PHOTO_PRINT_FX":
|
||||
// 打印类返回单一通用条目
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "效果图片打印", productType));
|
||||
break;
|
||||
case "MACHINE_PRINT":
|
||||
// 打印类返回单一通用条目
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "一体机打印", productType));
|
||||
break;
|
||||
|
||||
default:
|
||||
// 不支持的 productType,返回空列表
|
||||
break;
|
||||
}
|
||||
|
||||
return goodsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧逻辑:返回所有商品
|
||||
* 通过查询系统中所有已知的 productType,将结果综合到一起
|
||||
*/
|
||||
private List<SimpleGoodsRespVO> listAllSimpleGoods(Long scenicId) {
|
||||
List<SimpleGoodsRespVO> goodsList = new ArrayList<>();
|
||||
|
||||
// 从 ProductTypeCapability 服务查询所有已知的商品类型(仅包含启用的)
|
||||
List<ProductTypeCapability> capabilities = productTypeCapabilityManagementService.queryAll(false);
|
||||
|
||||
// 轮询每个商品类型,获取对应的商品列表
|
||||
for (ProductTypeCapability capability : capabilities) {
|
||||
String productType = capability.getProductType();
|
||||
List<SimpleGoodsRespVO> typeGoodsList = listSimpleGoodsByScenic(scenicId, productType);
|
||||
goodsList.addAll(typeGoodsList);
|
||||
}
|
||||
|
||||
return goodsList;
|
||||
}
|
||||
|
||||
@@ -202,7 +72,7 @@ public class PriceBiz {
|
||||
String[] goodsIds = priceConfig.getGoodsIds().split(",");
|
||||
return goodsList.stream().filter(goods -> {
|
||||
for (String goodsId : goodsIds) {
|
||||
if (Strings.CS.equals(goods.getGoodsId().toString(), goodsId)) {
|
||||
if (StringUtils.equals(goods.getGoodsId().toString(), goodsId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +80,7 @@ public class PriceBiz {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public IsBuyBatchRespVO isOnePriceBuy(Long userId, Long faceId, Long scenicId, Integer type, String goodsIds) {
|
||||
public IsBuyBatchRespVO isBuy(Long userId, Long faceId, Long scenicId, Integer type, String goodsIds) {
|
||||
IsBuyBatchRespVO respVO = new IsBuyBatchRespVO();
|
||||
PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(scenicId, type, goodsIds);
|
||||
if (priceConfig == null) {
|
||||
@@ -222,7 +92,7 @@ public class PriceBiz {
|
||||
}
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null) {
|
||||
if (Boolean.TRUE.equals(scenicConfig.getAllFree())) {
|
||||
if (Integer.valueOf(1).equals(scenicConfig.getAllFree())) {
|
||||
// 景区全免
|
||||
respVO.setFree(true);
|
||||
respVO.setSlashPrice(BigDecimal.ZERO);
|
||||
@@ -262,62 +132,12 @@ public class PriceBiz {
|
||||
// 查询用户是否有此类订单
|
||||
respVO.setBuy(false);
|
||||
if (userId != null) {
|
||||
OrderEntity orderEntity = orderBiz.hasTypeOrder(userId, faceId, scenicId, type, priceConfig.getId());
|
||||
OrderEntity orderEntity = orderBiz.hasTypeOrder(userId, scenicId, type, priceConfig.getId());
|
||||
if (orderEntity != null) {
|
||||
respVO.setOrderId(orderEntity.getId());
|
||||
respVO.setBuy(Integer.valueOf(1).equals(orderEntity.getStatus()));
|
||||
}
|
||||
}
|
||||
if (type == -1 && !respVO.isBuy()) {
|
||||
// 直接查询用户购买状态,避免调用faceContentList造成循环调用
|
||||
boolean allContentsPurchased = true;
|
||||
|
||||
// 检查视频模板购买状态
|
||||
List<TemplateRespVO> templateList = templateRepository.getTemplateListByScenicId(scenicId);
|
||||
for (TemplateRespVO template : templateList) {
|
||||
// 使用OrderRepository直接检查是否购买了该模板下的内容
|
||||
List<MemberVideoEntity> videoEntities = memberRelationRepository.listRelationByFaceAndTemplate(faceId, template.getId());
|
||||
if (videoEntities == null || videoEntities.isEmpty()) {
|
||||
allContentsPurchased = false;
|
||||
break;
|
||||
}
|
||||
boolean hasPurchasedTemplate = orderBiz.checkUserBuyFaceItem(userId, faceId, -1, videoEntities.getFirst().getVideoId());
|
||||
if (!hasPurchasedTemplate) {
|
||||
allContentsPurchased = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查源文件购买状态(录像集和照片集)
|
||||
if (allContentsPurchased) {
|
||||
if (scenicConfig != null) {
|
||||
// 检查录像集
|
||||
if (!Boolean.TRUE.equals(scenicConfig.getDisableSourceVideo())) {
|
||||
boolean hasPurchasedRecording = orderBiz.checkUserBuyFaceItem(userId, faceId, 1, faceId);
|
||||
if (!hasPurchasedRecording) {
|
||||
allContentsPurchased = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查照片集
|
||||
if (allContentsPurchased && !Boolean.TRUE.equals(scenicConfig.getDisableSourceImage())) {
|
||||
boolean hasPurchasedPhoto = orderBiz.checkUserBuyFaceItem(userId, faceId, 2, faceId);
|
||||
if (!hasPurchasedPhoto) {
|
||||
allContentsPurchased = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果所有内容都已购买,则认为已购买套餐
|
||||
if (allContentsPurchased) {
|
||||
respVO.setBuy(true);
|
||||
}
|
||||
}
|
||||
respVO.setShare(false);
|
||||
if (face == null || !face.getMemberId().equals(userId)) {
|
||||
respVO.setShare(true);
|
||||
}
|
||||
return respVO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -32,6 +29,8 @@ public class TemplateBiz {
|
||||
private FaceRepository faceRepository;
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
@Autowired
|
||||
private SourceRepository sourceRepository;
|
||||
|
||||
public boolean determineTemplateCanGenerate(Long templateId, Long faceId) {
|
||||
return determineTemplateCanGenerate(templateId, faceId, true);
|
||||
@@ -54,7 +53,6 @@ public class TemplateBiz {
|
||||
if (scanSource) {
|
||||
List<SourceEntity> sourceEntities = sourceMapper.listVideoByScenicFaceRelation(face.getScenicId(), faceId);
|
||||
if (sourceEntities == null || sourceEntities.isEmpty()) {
|
||||
log.info("faceId:{} has no source", faceId);
|
||||
return false;
|
||||
}
|
||||
count = sourceEntities.stream()
|
||||
@@ -66,7 +64,6 @@ public class TemplateBiz {
|
||||
} else {
|
||||
List<FaceSampleEntity> faceSampleList = faceRepository.getFaceSampleList(faceId);
|
||||
if (faceSampleList == null || faceSampleList.isEmpty()) {
|
||||
log.info("faceId:{} has no faceSample", faceId);
|
||||
return false;
|
||||
}
|
||||
count = faceSampleList.stream()
|
||||
@@ -94,8 +91,8 @@ public class TemplateBiz {
|
||||
}
|
||||
if (minimalPlaceholderFill == null) {
|
||||
// 未开启
|
||||
log.info("模板:{},未配置最小自动生成功能,默认生成!", templateId);
|
||||
minimalPlaceholderFill = 1;
|
||||
log.info("模板:{},未配置最小自动生成功能,默认不生成", templateId);
|
||||
return false;
|
||||
}
|
||||
if (minimalPlaceholderFill <= 0) {
|
||||
return true;
|
||||
@@ -124,97 +121,4 @@ public class TemplateBiz {
|
||||
return count >= minimalPlaceholderFill;
|
||||
}
|
||||
|
||||
public Map<String, List<SourceEntity>> filterTaskParams(Long templateId, Map<String, List<SourceEntity>> allTaskParams) {
|
||||
if (allTaskParams == null || allTaskParams.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
List<String> templatePlaceholders = templateRepository.getTemplatePlaceholder(templateId);
|
||||
if (templatePlaceholders == null || templatePlaceholders.isEmpty()) {
|
||||
log.info("filterTaskParams: templateId:{} has no placeholders", templateId);
|
||||
return Map.of();
|
||||
}
|
||||
TemplateConfigEntity templateConfig = templateRepository.getTemplateConfig(templateId);
|
||||
|
||||
// 统计每个 placeholder 在模板中出现的次数
|
||||
Map<String, Long> placeholderCounts = templatePlaceholders.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
placeholder -> placeholder,
|
||||
Collectors.counting()
|
||||
));
|
||||
|
||||
Map<String, List<SourceEntity>> filteredParams = new HashMap<>();
|
||||
|
||||
// 判断是否允许片段重复
|
||||
boolean allowDuplicate = templateConfig != null && Integer.valueOf(1).equals(templateConfig.getDuplicateEnable());
|
||||
|
||||
for (Map.Entry<String, Long> entry : placeholderCounts.entrySet()) {
|
||||
String placeholder = entry.getKey();
|
||||
Long requiredCount = entry.getValue();
|
||||
|
||||
if (placeholder.startsWith("P")) {
|
||||
// 图片源:占位符格式为 "P{deviceId}"
|
||||
String imageKey = placeholder;
|
||||
if (allTaskParams.containsKey(imageKey)) {
|
||||
List<SourceEntity> allSources = allTaskParams.get(imageKey);
|
||||
List<SourceEntity> selectedSources = selectSources(allSources, requiredCount.intValue(), allowDuplicate);
|
||||
if (!selectedSources.isEmpty()) {
|
||||
filteredParams.put(imageKey, selectedSources);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 视频源:占位符直接对应设备ID
|
||||
String videoKey = placeholder;
|
||||
if (allTaskParams.containsKey(videoKey)) {
|
||||
List<SourceEntity> allSources = allTaskParams.get(videoKey);
|
||||
List<SourceEntity> selectedSources = selectSources(allSources, requiredCount.intValue(), allowDuplicate);
|
||||
if (!selectedSources.isEmpty()) {
|
||||
filteredParams.put(videoKey, selectedSources);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("filterTaskParams: templateId:{}, original keys:{}, filtered keys:{}, placeholder counts:{}, allowDuplicate:{}",
|
||||
templateId, allTaskParams.keySet().size(), filteredParams.keySet().size(), placeholderCounts, allowDuplicate);
|
||||
|
||||
return filteredParams;
|
||||
}
|
||||
|
||||
private List<SourceEntity> selectSources(List<SourceEntity> allSources, int requiredCount, boolean allowDuplicate) {
|
||||
if (allSources == null || allSources.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
if (!allowDuplicate) {
|
||||
// 不允许重复,使用原有逻辑
|
||||
int actualCount = Math.min(requiredCount, allSources.size());
|
||||
return new ArrayList<>(allSources.subList(0, actualCount));
|
||||
}
|
||||
|
||||
// 允许重复,循环填充到所需数量
|
||||
List<SourceEntity> selectedSources = new ArrayList<>();
|
||||
int sourceIndex = 0;
|
||||
|
||||
for (int i = 0; i < requiredCount; i++) {
|
||||
selectedSources.add(allSources.get(sourceIndex));
|
||||
sourceIndex = (sourceIndex + 1) % allSources.size();
|
||||
}
|
||||
|
||||
return selectedSources;
|
||||
}
|
||||
|
||||
public Long findFirstAvailableTemplate(List<Long> templateIds, Long faceId, boolean scanSource) {
|
||||
if (templateIds == null || templateIds.isEmpty() || faceId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Long templateId : templateIds) {
|
||||
if (determineTemplateCanGenerate(templateId, faceId, scanSource)) {
|
||||
return templateId;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,34 @@
|
||||
package com.ycwl.basic.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
|
||||
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @author wenshijia
|
||||
* @date 2021年07月05日 18:34
|
||||
* 修改redis缓存序列化器
|
||||
*/
|
||||
@Configuration
|
||||
public class CustomRedisCacheManager {
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
@EnableCaching
|
||||
public class CustomRedisCacheManager extends CachingConfigurerSupport {
|
||||
|
||||
@Bean
|
||||
public RedisCacheConfiguration redisCacheConfiguration() {
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
||||
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofMinutes(1));
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理redis连接工具显示redis key值显示乱码问题,value值没处理
|
||||
@@ -37,23 +45,10 @@ public class CustomRedisCacheManager {
|
||||
|
||||
final StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||
redisTemplate.setKeySerializer(stringRedisSerializer);
|
||||
redisTemplate.setValueSerializer(stringRedisSerializer);
|
||||
|
||||
redisTemplate.setHashKeySerializer(stringRedisSerializer);
|
||||
|
||||
// Configure Jackson2JsonRedisSerializer with JavaTimeModule for value serialization
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
|
||||
// Configure type handling to prevent ClassCastException
|
||||
PolymorphicTypeValidator typeValidator = BasicPolymorphicTypeValidator.builder()
|
||||
.allowIfBaseType(Object.class)
|
||||
.build();
|
||||
objectMapper.activateDefaultTyping(typeValidator, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
|
||||
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
package com.ycwl.basic.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Configuration
|
||||
public class JacksonConfiguration {
|
||||
|
||||
@@ -19,16 +13,6 @@ public class JacksonConfiguration {
|
||||
return builder -> {
|
||||
// 把 Long 类型序列化为 String
|
||||
builder.serializerByType(Long.class, ToStringSerializer.instance);
|
||||
|
||||
// 添加 JavaTimeModule 以支持 Java 8 时间类型
|
||||
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
builder.deserializers(new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JavaTimeModule javaTimeModule() {
|
||||
return new JavaTimeModule();
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package com.ycwl.basic.config;
|
||||
|
||||
import org.apache.kafka.clients.consumer.ConsumerConfig;
|
||||
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||
import org.apache.kafka.common.serialization.StringDeserializer;
|
||||
import org.apache.kafka.common.serialization.StringSerializer;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
|
||||
import org.springframework.kafka.core.*;
|
||||
import org.springframework.kafka.listener.ContainerProperties;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(name = "kafka.enabled", havingValue = "true", matchIfMissing = false)
|
||||
public class KafkaConfig {
|
||||
|
||||
@Value("${kafka.bootstrap-servers:100.64.0.12:39092}")
|
||||
private String bootstrapServers;
|
||||
|
||||
@Value("${kafka.consumer.group-id:liuying-microservice}")
|
||||
private String consumerGroupId;
|
||||
|
||||
@Value("${kafka.consumer.auto-offset-reset:earliest}")
|
||||
private String autoOffsetReset;
|
||||
|
||||
@Value("${kafka.producer.acks:all}")
|
||||
private String acks;
|
||||
|
||||
@Value("${kafka.producer.retries:3}")
|
||||
private Integer retries;
|
||||
|
||||
@Value("${kafka.producer.batch-size:16384}")
|
||||
private Integer batchSize;
|
||||
|
||||
@Value("${kafka.producer.linger-ms:1}")
|
||||
private Integer lingerMs;
|
||||
|
||||
@Value("${kafka.producer.buffer-memory:33554432}")
|
||||
private Integer bufferMemory;
|
||||
|
||||
@Value("${kafka.producer.enable-idempotence:true}")
|
||||
private boolean enableIdempotence;
|
||||
|
||||
@Value("${kafka.producer.compression-type:snappy}")
|
||||
private String compressionType;
|
||||
|
||||
@Bean
|
||||
public ProducerFactory<String, String> producerFactory() {
|
||||
Map<String, Object> configProps = new HashMap<>();
|
||||
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
||||
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
configProps.put(ProducerConfig.ACKS_CONFIG, acks);
|
||||
configProps.put(ProducerConfig.RETRIES_CONFIG, retries);
|
||||
configProps.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize);
|
||||
configProps.put(ProducerConfig.LINGER_MS_CONFIG, lingerMs);
|
||||
configProps.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory);
|
||||
configProps.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, enableIdempotence);
|
||||
configProps.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, compressionType);
|
||||
|
||||
return new DefaultKafkaProducerFactory<>(configProps);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KafkaTemplate<String, String> kafkaTemplate() {
|
||||
return new KafkaTemplate<>(producerFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsumerFactory<String, String> consumerFactory() {
|
||||
Map<String, Object> props = new HashMap<>();
|
||||
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
||||
props.put(ConsumerConfig.GROUP_ID_CONFIG, consumerGroupId);
|
||||
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
||||
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
||||
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);
|
||||
|
||||
return new DefaultKafkaConsumerFactory<>(props);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
|
||||
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
|
||||
factory.setConsumerFactory(consumerFactory());
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConcurrentKafkaListenerContainerFactory<String, String> manualCommitKafkaListenerContainerFactory() {
|
||||
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
|
||||
|
||||
Map<String, Object> props = new HashMap<>();
|
||||
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
||||
props.put(ConsumerConfig.GROUP_ID_CONFIG, consumerGroupId);
|
||||
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
||||
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
||||
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);
|
||||
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
|
||||
|
||||
factory.setConsumerFactory(new DefaultKafkaConsumerFactory<>(props));
|
||||
factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.ycwl.basic.config;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -12,15 +11,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
* @date 2021年06月04日 9:42
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan(basePackages = {
|
||||
"com.ycwl.basic.mapper",
|
||||
"com.ycwl.basic.order.mapper",
|
||||
"com.ycwl.basic.pricing.mapper",
|
||||
"com.ycwl.basic.product.mapper",
|
||||
"com.ycwl.basic.profitsharing.mapper",
|
||||
"com.ycwl.basic.puzzle.mapper",
|
||||
"com.ycwl.basic.stats.mapper"
|
||||
})
|
||||
public class MybatisPlusPageConfig {
|
||||
|
||||
/* 旧版本配置
|
||||
|
||||
74
src/main/java/com/ycwl/basic/config/SwaggerConfig.java
Normal file
74
src/main/java/com/ycwl/basic/config/SwaggerConfig.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package com.ycwl.basic.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.ParameterBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.schema.ModelRef;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.service.Parameter;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Swagger 配置类
|
||||
* 原生: /swagger-ui.html
|
||||
* 美化: /doc.html
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2WebMvc
|
||||
@Profile({"test"})
|
||||
public class SwaggerConfig {
|
||||
|
||||
/**
|
||||
* Swagger 实例 Bean 是 Docket, 所以通过配置 Docket 实例来配置 Swagger
|
||||
*/
|
||||
@Bean
|
||||
public Docket docket() {
|
||||
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
// 展示在 Swagger 页面上的自定义工程描述信息
|
||||
.apiInfo(apiInfo())
|
||||
// 选择展示哪些接口
|
||||
.select()
|
||||
//只有com.zcy.e.firstaid包内的才去展示
|
||||
.apis(RequestHandlerSelectors.basePackage("com.ycwl.basic.controller.mobile"))
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
.globalOperationParameters(getGlobalRequestParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Swagger 的描述信息
|
||||
*/
|
||||
public ApiInfo apiInfo() {
|
||||
|
||||
return new ApiInfoBuilder()
|
||||
.title("liuyin-re")
|
||||
.description("流影重构")
|
||||
.contact(new Contact("ycwl", "www.xxx.com", "xxxxxxxxx.com"))
|
||||
.version("1.0")
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<Parameter> getGlobalRequestParameters() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(new ParameterBuilder()
|
||||
.name("token")
|
||||
.description("登录令牌")
|
||||
.parameterType("header")
|
||||
.modelRef(new ModelRef("String"))
|
||||
.required(true)
|
||||
.build());
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.ycwl.basic.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 视频更新检查配置
|
||||
* @author Claude
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "video.update")
|
||||
public class VideoUpdateConfig {
|
||||
|
||||
/**
|
||||
* 是否将片段变化检测为新增
|
||||
* true: 任何变化都视为新增
|
||||
* false: 只有数量增加才视为新增
|
||||
*/
|
||||
private boolean detectChangesAsNew = true;
|
||||
|
||||
/**
|
||||
* 最小新增片段数量才认为可更新
|
||||
*/
|
||||
private int minNewSegmentCount = 1;
|
||||
|
||||
/**
|
||||
* 是否启用视频更新检查功能
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.ycwl.basic.constant;
|
||||
|
||||
/**
|
||||
* 购买状态枚举
|
||||
* 定义源文件的已购买和未购买两种状态
|
||||
*
|
||||
* @author Claude
|
||||
* @since 2025-10-31
|
||||
*/
|
||||
public enum BuyStatus {
|
||||
/**
|
||||
* 未购买状态
|
||||
*/
|
||||
NOT_BOUGHT(0, "未购买"),
|
||||
|
||||
/**
|
||||
* 已购买状态
|
||||
*/
|
||||
BOUGHT(1, "已购买");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
BuyStatus(int code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码值获取枚举
|
||||
*
|
||||
* @param code 状态代码
|
||||
* @return 对应的枚举值,如果不存在返回 null
|
||||
*/
|
||||
public static BuyStatus fromCode(int code) {
|
||||
for (BuyStatus status : values()) {
|
||||
if (status.code == code) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的代码是否为已购买状态
|
||||
*
|
||||
* @param code 状态代码
|
||||
* @return true-已购买,false-未购买
|
||||
*/
|
||||
public static boolean isBought(Integer code) {
|
||||
return code != null && code == BOUGHT.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的代码是否为未购买状态
|
||||
*
|
||||
* @param code 状态代码
|
||||
* @return true-未购买,false-已购买
|
||||
*/
|
||||
public static boolean isNotBought(Integer code) {
|
||||
return code != null && code == NOT_BOUGHT.code;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,4 @@ public class FaceConstant {
|
||||
public static final String FACE_DB_NAME_PFX="face:db:";
|
||||
public static final String USER_FACE_DB_NAME="userFace";
|
||||
public static final String FACE_USER_URL_PFX="face:user:url:";
|
||||
public static final String FACE_RECOGNITION_COUNT_PFX="face:recognition:count:";
|
||||
public static final String FACE_CUSTOM_MATCH_COUNT_PFX="face:custom:match:count:";
|
||||
public static final String FACE_LOW_THRESHOLD_PFX="face:low:threshold:";
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.ycwl.basic.constant;
|
||||
|
||||
/**
|
||||
* 免费状态枚举
|
||||
* 定义源文件的收费和免费两种状态
|
||||
*
|
||||
* @author Claude
|
||||
* @since 2025-10-31
|
||||
*/
|
||||
public enum FreeStatus {
|
||||
/**
|
||||
* 收费状态
|
||||
*/
|
||||
PAID(0, "收费"),
|
||||
|
||||
/**
|
||||
* 免费状态
|
||||
*/
|
||||
FREE(1, "免费");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
FreeStatus(int code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码值获取枚举
|
||||
*
|
||||
* @param code 状态代码
|
||||
* @return 对应的枚举值,如果不存在返回 null
|
||||
*/
|
||||
public static FreeStatus fromCode(int code) {
|
||||
for (FreeStatus status : values()) {
|
||||
if (status.code == code) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的代码是否为免费状态
|
||||
*
|
||||
* @param code 状态代码
|
||||
* @return true-免费,false-收费
|
||||
*/
|
||||
public static boolean isFree(Integer code) {
|
||||
return code != null && code == FREE.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的代码是否为收费状态
|
||||
*
|
||||
* @param code 状态代码
|
||||
* @return true-收费,false-免费
|
||||
*/
|
||||
public static boolean isPaid(Integer code) {
|
||||
return code != null && code == PAID.code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.ycwl.basic.constant;
|
||||
|
||||
public class ShareParkingSpaceRedisKeyConstant {
|
||||
// 更改数量时候的锁
|
||||
public final static String UPDATE_NUMBER_LOCK_KEY="ShareParking:updateNumberLockKey";
|
||||
// 地上车位
|
||||
public final static String GROUND_PARKING_SPACE_NUMBER="ShareParking:groundParkingSpaceNumber";
|
||||
// 地下车位数
|
||||
public final static String UNDERGROUND_PARKING_SPACE_NUMBER="ShareParking:undergroundParkingSpaceNumber";
|
||||
// 每日开放预约时间
|
||||
public final static String OPEN_TIME="ShareParking:openTime";
|
||||
// 预约后当日车辆最晚停留时间
|
||||
public final static String RESIDENCE_TIME="ShareParking:residenceTime";
|
||||
//取消时间
|
||||
public final static String CANCEL_TIME="ShareParking:cancelTime";
|
||||
//支付时间
|
||||
public final static String PAY_TIME="ShareParking:payTime";
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package com.ycwl.basic.constant;
|
||||
|
||||
/**
|
||||
* 源文件类型枚举
|
||||
* 定义视频和图片两种源文件类型
|
||||
*
|
||||
* @author Claude
|
||||
* @since 2025-10-31
|
||||
*/
|
||||
public enum SourceType {
|
||||
/**
|
||||
* 视频类型
|
||||
*/
|
||||
VIDEO(1, "视频"),
|
||||
|
||||
/**
|
||||
* 图片类型
|
||||
*/
|
||||
IMAGE(2, "图片"),
|
||||
|
||||
/**
|
||||
* AI微单类型
|
||||
*/
|
||||
AI_CAM(3, "AI微单");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
SourceType(int code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码值获取枚举
|
||||
*
|
||||
* @param code 类型代码
|
||||
* @return 对应的枚举值,如果不存在返回 null
|
||||
*/
|
||||
public static SourceType fromCode(int code) {
|
||||
for (SourceType type : values()) {
|
||||
if (type.code == code) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的代码是否为视频类型
|
||||
*
|
||||
* @param code 类型代码
|
||||
* @return true-是视频,false-不是视频
|
||||
*/
|
||||
public static boolean isVideo(Integer code) {
|
||||
return code != null && code == VIDEO.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的代码是否为图片类型
|
||||
*
|
||||
* @param code 类型代码
|
||||
* @return true-是图片,false-不是图片
|
||||
*/
|
||||
public static boolean isImage(Integer code) {
|
||||
return code != null && code == IMAGE.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的代码是否为AI微单类型
|
||||
*
|
||||
* @param code 类型代码
|
||||
* @return true-是AI微单,false-不是AI微单
|
||||
*/
|
||||
public static boolean isAiCam(Integer code) {
|
||||
return code != null && code == AI_CAM.code;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@ package com.ycwl.basic.constant;
|
||||
public class StorageConstant {
|
||||
public static final String VLOG_PATH = "vlog";
|
||||
public static final String VIDEO_PIECE_PATH = "source_video";
|
||||
public static final String PHOTO_PATH = "viid";
|
||||
public static final String PHOTO_PATH = "source_photo";
|
||||
public static final String PHOTO_WATERMARKED_PATH = "photo_w";
|
||||
public static final String VIID_FACE = "viid_face";
|
||||
public static final String USER_FACE = "user_face";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.enums.BizCodeEnum;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -24,10 +26,10 @@ import java.util.UUID;
|
||||
@RestController
|
||||
@RequestMapping("/api/file/v1")
|
||||
@Slf4j
|
||||
// 文件接口
|
||||
@Api(tags = "文件接口")
|
||||
public class FileController {
|
||||
|
||||
// 上传文件
|
||||
@ApiOperation(value = "上传文件")
|
||||
@PostMapping("/upload")
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> upload(@RequestParam(value = "file") MultipartFile file) throws IOException {
|
||||
@@ -37,7 +39,7 @@ public class FileController {
|
||||
return ApiResponse.success(url);
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
@ApiOperation(value = "删除文件")
|
||||
@PostMapping("/delete")
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> delete(@RequestParam(value = "fileName") String fileName) throws IOException {
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package com.ycwl.basic.controller;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.model.pc.videoreview.dto.VideoReviewAddReqDTO;
|
||||
import com.ycwl.basic.model.pc.videoreview.dto.VideoReviewListReqDTO;
|
||||
import com.ycwl.basic.model.pc.videoreview.dto.VideoReviewRespDTO;
|
||||
import com.ycwl.basic.model.pc.videoreview.dto.VideoReviewStatisticsRespDTO;
|
||||
import com.ycwl.basic.service.VideoReviewService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* 视频评价Controller
|
||||
* 管理端使用,通过token角色控制权限
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/video-review/v1")
|
||||
public class VideoReviewController {
|
||||
|
||||
@Autowired
|
||||
private VideoReviewService videoReviewService;
|
||||
|
||||
/**
|
||||
* 新增视频评价
|
||||
*
|
||||
* @param reqDTO 评价信息
|
||||
* @return 评价ID
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<Long> addReview(@RequestBody VideoReviewAddReqDTO reqDTO) {
|
||||
log.info("新增视频评价,videoId: {}", reqDTO.getVideoId());
|
||||
Long reviewId = videoReviewService.addReview(reqDTO);
|
||||
return ApiResponse.success(reviewId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询评价列表
|
||||
*
|
||||
* @param reqDTO 查询条件
|
||||
* @return 分页结果
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public ApiResponse<PageInfo<VideoReviewRespDTO>> getReviewList(VideoReviewListReqDTO reqDTO) {
|
||||
log.info("查询视频评价列表,pageNum: {}, pageSize: {}", reqDTO.getPageNum(), reqDTO.getPageSize());
|
||||
PageInfo<VideoReviewRespDTO> pageInfo = videoReviewService.getReviewList(reqDTO);
|
||||
return ApiResponse.success(pageInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取评价统计数据
|
||||
*
|
||||
* @return 统计结果
|
||||
*/
|
||||
@GetMapping("/statistics")
|
||||
public ApiResponse<VideoReviewStatisticsRespDTO> getStatistics() {
|
||||
log.info("获取视频评价统计数据");
|
||||
VideoReviewStatisticsRespDTO statistics = videoReviewService.getStatistics();
|
||||
return ApiResponse.success(statistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出评价数据到Excel
|
||||
*
|
||||
* @param reqDTO 查询条件
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
@GetMapping("/export")
|
||||
public void exportReviews(VideoReviewListReqDTO reqDTO, HttpServletResponse response) {
|
||||
log.info("导出视频评价数据");
|
||||
|
||||
try {
|
||||
// 设置响应头
|
||||
String fileName = "video_reviews_" + System.currentTimeMillis() + ".xlsx";
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||
|
||||
// 导出数据
|
||||
videoReviewService.exportReviews(reqDTO, response.getOutputStream());
|
||||
|
||||
response.getOutputStream().flush();
|
||||
} catch (IOException e) {
|
||||
log.error("导出视频评价数据失败", e);
|
||||
throw new RuntimeException("导出失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
package com.ycwl.basic.controller.extern;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.image.enhancer.adapter.BceImageEnhancer;
|
||||
import com.ycwl.basic.image.enhancer.entity.BceEnhancerConfig;
|
||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||
import com.ycwl.basic.image.pipeline.stages.DownloadStage;
|
||||
import com.ycwl.basic.image.pipeline.stages.ImageEnhanceStage;
|
||||
import com.ycwl.basic.image.pipeline.stages.ImageSRStage;
|
||||
import com.ycwl.basic.image.pipeline.stages.SourcePhotoUpdateStage;
|
||||
import com.ycwl.basic.image.pipeline.stages.CleanupStage;
|
||||
import com.ycwl.basic.pipeline.core.Pipeline;
|
||||
import com.ycwl.basic.pipeline.core.PipelineBuilder;
|
||||
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.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.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.service.pc.SourceService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
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.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.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@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;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private SourceService sourceService;
|
||||
|
||||
@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(), "");
|
||||
// 尝试超分
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
GoodsReqQuery query = new GoodsReqQuery();
|
||||
query.setSourceType(2);
|
||||
query.setFaceId(resp.getFaceId());
|
||||
List<GoodsDetailVO> sourcePhotoList = goodsService.sourceGoodsList(query);
|
||||
if (sourcePhotoList == null || sourcePhotoList.isEmpty()) {
|
||||
log.info("无源图片");
|
||||
redisTemplate.opsForValue().set("aio:faceId:"+resp.getFaceId().toString()+":pass", "1", 1, TimeUnit.DAYS);
|
||||
return;
|
||||
}
|
||||
log.info("超分开始!共{}张图片待处理", sourcePhotoList.size());
|
||||
|
||||
sourcePhotoList.forEach(photo -> {
|
||||
if (StringUtils.contains(photo.getUrl(), "_q_")) {
|
||||
log.debug("跳过已增强的图片: {}", photo.getUrl());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建超分Pipeline
|
||||
Pipeline<PhotoProcessContext> superResolutionPipeline = createSuperResolutionPipeline(photo.getGoodsId());
|
||||
|
||||
// 使用静态工厂方法创建Context
|
||||
PhotoProcessContext context = PhotoProcessContext.forSuperResolution(
|
||||
photo.getGoodsId(), photo.getUrl(), photo.getScenicId()
|
||||
);
|
||||
|
||||
// 启用图像增强和超分的Stage
|
||||
context.enableStage("image_enhance");
|
||||
context.enableStage("image_sr");
|
||||
|
||||
// 执行Pipeline
|
||||
boolean success = superResolutionPipeline.execute(context);
|
||||
|
||||
if (success) {
|
||||
log.info("超分成功: {} -> {}", photo.getUrl(), context.getResultUrl());
|
||||
} else {
|
||||
log.error("超分失败: {}", photo.getGoodsId());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("超分失败:{}", photo.getGoodsId(), e);
|
||||
}
|
||||
});
|
||||
redisTemplate.opsForValue().set("aio:faceId:"+sourcePhotoList.getFirst().getFaceId().toString()+":pass", "1", 1, TimeUnit.DAYS);
|
||||
}).start();
|
||||
return ApiResponse.success(resp);
|
||||
}
|
||||
|
||||
// 人脸信息
|
||||
@GetMapping("/{faceId}")
|
||||
public ApiResponse<FaceRespVO> faceInfo(@PathVariable Long faceId) {
|
||||
return faceService.getById(faceId);
|
||||
}
|
||||
@GetMapping("/face/{faceId}/check")
|
||||
public ApiResponse<Boolean> faceCheck(@PathVariable Long faceId) {
|
||||
if (redisTemplate.hasKey("aio:faceId:"+faceId.toString()+":pass")) {
|
||||
return ApiResponse.success(true);
|
||||
} else {
|
||||
return ApiResponse.success(false);
|
||||
}
|
||||
}
|
||||
@GetMapping("/face/{faceId}/bindWxaCode")
|
||||
public ApiResponse<String> bindWxaCode(@PathVariable Long faceId) {
|
||||
return ApiResponse.success(faceService.bindWxaCode(faceId));
|
||||
}
|
||||
// 照片商品列表
|
||||
@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);
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
@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));
|
||||
}
|
||||
|
||||
// 查询订单
|
||||
@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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建源图片超分辨率增强Pipeline
|
||||
*
|
||||
* @param sourceId 源图片ID
|
||||
* @return 超分Pipeline
|
||||
*/
|
||||
private Pipeline<PhotoProcessContext> createSuperResolutionPipeline(Long sourceId) {
|
||||
// 创建带有百度云配置的ImageEnhanceStage
|
||||
BceEnhancerConfig config = new BceEnhancerConfig();
|
||||
config.setQps(1);
|
||||
config.setAppId("119554288");
|
||||
config.setApiKey("OX6QoijgKio3eVtA0PiUVf7f");
|
||||
config.setSecretKey("dYatXReVriPeiktTjUblhfubpcmYfuMk");
|
||||
|
||||
return new PipelineBuilder<PhotoProcessContext>("SourcePhotoSuperResolutionPipeline")
|
||||
.addStage(new DownloadStage()) // 1. 下载图片
|
||||
.addStage(new ImageEnhanceStage(config)).addStage(new ImageSRStage(config)) // 2. 图像增强(超分)
|
||||
.addStage(new SourcePhotoUpdateStage(sourceService, sourceId)) // 3. 上传并更新数据库
|
||||
.addStage(new CleanupStage()) // 4. 清理临时文件
|
||||
.build();
|
||||
}
|
||||
|
||||
private BceImageEnhancer getEnhancer() {
|
||||
BceImageEnhancer enhancer = new BceImageEnhancer();
|
||||
BceEnhancerConfig config = new BceEnhancerConfig();
|
||||
config.setQps(1);
|
||||
config.setAppId("119554288");
|
||||
config.setApiKey("OX6QoijgKio3eVtA0PiUVf7f");
|
||||
config.setSecretKey("dYatXReVriPeiktTjUblhfubpcmYfuMk");
|
||||
enhancer.setConfig(config);
|
||||
return enhancer;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package com.ycwl.basic.controller.extern;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.model.custom.req.AliyunCallbackReq;
|
||||
import com.ycwl.basic.model.custom.req.CreateUploadTaskReq;
|
||||
import com.ycwl.basic.model.custom.req.UploadCompleteReq;
|
||||
import com.ycwl.basic.model.custom.req.UploadFailedReq;
|
||||
import com.ycwl.basic.model.custom.resp.CreateUploadTaskResp;
|
||||
import com.ycwl.basic.service.custom.CustomUploadTaskService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
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.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;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/extern/custom-device")
|
||||
@IgnoreToken
|
||||
public class CustomDeviceController {
|
||||
|
||||
@Autowired
|
||||
private CustomUploadTaskService customUploadTaskService;
|
||||
|
||||
@PostMapping("/upload/create")
|
||||
public ApiResponse<CreateUploadTaskResp> createUploadTask(@RequestBody CreateUploadTaskReq req) {
|
||||
try {
|
||||
CreateUploadTaskResp resp = customUploadTaskService.createUploadTask(req);
|
||||
return ApiResponse.success(resp);
|
||||
} catch (Exception e) {
|
||||
log.error("创建上传任务失败", e);
|
||||
return ApiResponse.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/upload/complete")
|
||||
public ApiResponse<String> uploadComplete(@RequestBody UploadCompleteReq req) {
|
||||
try {
|
||||
customUploadTaskService.completeUpload(req.getAccessKey(), req.getTaskId());
|
||||
return ApiResponse.success("上传完成,人脸识别任务已提交");
|
||||
} catch (Exception e) {
|
||||
log.error("上传完成处理失败", e);
|
||||
return ApiResponse.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/upload/failed")
|
||||
public ApiResponse<String> uploadFailed(@RequestBody UploadFailedReq req) {
|
||||
try {
|
||||
customUploadTaskService.markTaskFailed(req.getAccessKey(), req.getTaskId(), req.getErrorMsg());
|
||||
return ApiResponse.success("任务已标记为失败");
|
||||
} catch (Exception e) {
|
||||
log.error("标记任务失败处理异常", e);
|
||||
return ApiResponse.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/aliyun/mps/callback")
|
||||
public ApiResponse<String> aliyunCallback(@RequestBody AliyunCallbackReq req) {
|
||||
try {
|
||||
customUploadTaskService.handleAliyunCallback(req.getJobId(), req.getStatus());
|
||||
return ApiResponse.success("回调处理完成");
|
||||
} catch (Exception e) {
|
||||
log.error("阿里云回调处理失败", e);
|
||||
return ApiResponse.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/aliyun/mps/callback")
|
||||
public ApiResponse<String> aliyunCallback(@RequestParam("jobId") String jobId, @RequestParam("status") String status) {
|
||||
try {
|
||||
customUploadTaskService.handleAliyunCallback(jobId, status);
|
||||
return ApiResponse.success("回调处理完成");
|
||||
} catch (Exception e) {
|
||||
log.error("阿里云回调处理失败", e);
|
||||
return ApiResponse.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.ycwl.basic.controller.extern;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.mapper.FaceMapper;
|
||||
import com.ycwl.basic.mapper.MemberMapper;
|
||||
@@ -14,10 +14,9 @@ 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;
|
||||
import com.ycwl.basic.service.task.impl.TaskTaskServiceImpl;
|
||||
@@ -63,8 +62,6 @@ public class LyCompatibleController {
|
||||
private TaskTaskServiceImpl taskTaskServiceImpl;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private VideoTaskRepository videoTaskRepository;
|
||||
|
||||
@PostMapping("sendPhoto")
|
||||
@IgnoreToken
|
||||
@@ -87,7 +84,7 @@ public class LyCompatibleController {
|
||||
if (StringUtils.isBlank(scid)) {
|
||||
return R.error("景区ID为空!");
|
||||
}
|
||||
// if (Strings.CS.equals("288",scid)) {
|
||||
// if (StringUtils.equals("288",scid)) {
|
||||
scenicId = 3955650120997015552L;
|
||||
// } else {
|
||||
// scenicId = 3946669713328836608L;
|
||||
@@ -113,7 +110,7 @@ public class LyCompatibleController {
|
||||
}
|
||||
FaceRecognizeResp resp;
|
||||
try {
|
||||
resp = faceService.faceUpload(file, scenicId, member.getId(), "");
|
||||
resp = faceService.faceUpload(file, scenicId, member.getId());
|
||||
} catch (Exception e) {
|
||||
return R.error("上传失败!报错:"+e.getMessage());
|
||||
}
|
||||
@@ -183,7 +180,7 @@ public class LyCompatibleController {
|
||||
}
|
||||
String openId = headersMap.get("client");
|
||||
if (redisTemplate.hasKey("ly:"+openId)) {
|
||||
return JacksonUtil.parseObject(redisTemplate.opsForValue().get("ly:"+openId), R.class);
|
||||
return JSON.parseObject(redisTemplate.opsForValue().get("ly:"+openId), R.class);
|
||||
}
|
||||
MemberRespVO member = memberMapper.getByOpenId(openId);
|
||||
if (member == null) {
|
||||
@@ -201,7 +198,6 @@ 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;
|
||||
@@ -212,11 +208,6 @@ 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"));
|
||||
@@ -233,7 +224,6 @@ 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());
|
||||
@@ -243,11 +233,9 @@ 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, JacksonUtil.toJSONString(response), 5, TimeUnit.SECONDS);
|
||||
redisTemplate.opsForValue().set("ly:"+openId, JSON.toJSONString(response), 5, TimeUnit.SECONDS);
|
||||
log.info("> {}", response);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
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.service.mobile.AppAiCamService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI相机相关接口
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/ai_cam/v1")
|
||||
@RequiredArgsConstructor
|
||||
public class AppAiCamController {
|
||||
|
||||
private final AppAiCamService appAiCamService;
|
||||
|
||||
/**
|
||||
* 根据faceId获取AI相机识别到的商品列表
|
||||
* @param faceId 人脸ID
|
||||
* @return 商品详情列表
|
||||
*/
|
||||
@GetMapping("/{faceId}/content")
|
||||
public ApiResponse<List<GoodsDetailVO>> getAiCamGoods(@PathVariable Long faceId) {
|
||||
try {
|
||||
List<GoodsDetailVO> goods = appAiCamService.getAiCamGoodsByFaceId(faceId);
|
||||
return ApiResponse.success(goods);
|
||||
} catch (Exception e) {
|
||||
log.error("获取AI相机商品失败: faceId={}", faceId, e);
|
||||
return ApiResponse.fail("获取商品列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加会员与source的关联关系
|
||||
* @param faceId 人脸ID
|
||||
* @param sourceIds source ID列表
|
||||
* @return 添加结果
|
||||
*/
|
||||
@PostMapping("/{faceId}/relations")
|
||||
public ApiResponse<String> addMemberSourceRelations(
|
||||
@PathVariable Long faceId,
|
||||
@RequestBody List<Long> sourceIds
|
||||
) {
|
||||
try {
|
||||
int count = appAiCamService.addMemberSourceRelations(faceId, sourceIds);
|
||||
return ApiResponse.success("成功添加" + count + "条关联记录");
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("添加关联失败: faceId={}, error={}", faceId, e.getMessage());
|
||||
return ApiResponse.fail(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("添加关联失败: faceId={}", faceId, e);
|
||||
return ApiResponse.fail("添加关联失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用人脸样本创建或获取Face记录
|
||||
* @param faceSampleId 人脸样本ID
|
||||
* @return 人脸识别响应
|
||||
*/
|
||||
@GetMapping("/useSample/{faceSampleId}")
|
||||
public ApiResponse<FaceRecognizeResp> useSample(@PathVariable Long faceSampleId) {
|
||||
try {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
FaceRecognizeResp resp = appAiCamService.useSample(worker.getUserId(), faceSampleId);
|
||||
return ApiResponse.success(resp);
|
||||
} catch (Exception e) {
|
||||
log.error("使用人脸样本失败: faceSampleId={}", faceSampleId, e);
|
||||
return ApiResponse.fail("使用人脸样本失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.chat.*;
|
||||
import com.ycwl.basic.service.mobile.FaceChatService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* 小程序人脸智能聊天接口。
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/chat/v1")
|
||||
@RequiredArgsConstructor
|
||||
public class AppChatController {
|
||||
|
||||
private final FaceChatService faceChatService;
|
||||
|
||||
/**
|
||||
* 获取或创建会话(同一人脸只保留一条)。
|
||||
*/
|
||||
@PostMapping("/faces/{faceId}/conversation")
|
||||
public ApiResponse<ChatConversationVO> createConversation(@PathVariable Long faceId) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
ChatConversationVO vo = faceChatService.getOrCreateConversation(faceId, worker.getUserId());
|
||||
return ApiResponse.success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步发送消息,适用于短回复或前端自行轮询。
|
||||
*/
|
||||
@PostMapping("/conversations/{conversationId}/messages")
|
||||
public ApiResponse<ChatSendMessageResp> sendMessage(@PathVariable Long conversationId,
|
||||
@RequestBody ChatSendMessageReq req) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
ChatSendMessageResp resp = faceChatService.sendMessage(conversationId, worker.getUserId(),
|
||||
req.getContent(), req.getTraceId());
|
||||
return ApiResponse.success(resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 流式返回,使用 HTTP chunked。小程序侧用 wx.request 的 onChunkReceived 消费。
|
||||
*/
|
||||
@PostMapping(value = "/conversations/{conversationId}/messages/stream", produces = "text/plain;charset=UTF-8")
|
||||
public ResponseBodyEmitter streamMessage(@PathVariable Long conversationId,
|
||||
@RequestBody ChatSendMessageReq req) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
ResponseBodyEmitter emitter = new ResponseBodyEmitter(30_000L);
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
faceChatService.sendMessageStream(
|
||||
conversationId,
|
||||
worker.getUserId(),
|
||||
req.getContent(),
|
||||
req.getTraceId(),
|
||||
chunk -> {
|
||||
try {
|
||||
emitter.send(chunk, new MediaType("text", "plain", java.nio.charset.StandardCharsets.UTF_8));
|
||||
} catch (Exception e) {
|
||||
emitter.completeWithError(e);
|
||||
}
|
||||
});
|
||||
emitter.complete();
|
||||
} catch (Exception e) {
|
||||
log.error("streamMessage error", e);
|
||||
emitter.completeWithError(e);
|
||||
}
|
||||
});
|
||||
return emitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询历史消息,cursor 为最后一条 seq,limit 为条数。
|
||||
*/
|
||||
@GetMapping("/conversations/{conversationId}/messages")
|
||||
public ApiResponse<ChatMessagePageResp> listMessages(@PathVariable Long conversationId,
|
||||
@RequestParam(value = "cursor", required = false) Integer cursor,
|
||||
@RequestParam(value = "limit", required = false) Integer limit) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
ChatMessagePageResp resp = faceChatService.listMessages(conversationId, cursor, limit, worker.getUserId());
|
||||
return ApiResponse.success(resp);
|
||||
}
|
||||
|
||||
@PostMapping("/conversations/{conversationId}/close")
|
||||
public ApiResponse<String> closeConversation(@PathVariable Long conversationId) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
faceChatService.closeConversation(conversationId, worker.getUserId());
|
||||
return ApiResponse.success("OK");
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.model.mobile.claim.ClaimReq;
|
||||
import com.ycwl.basic.model.mobile.claim.ClaimResp;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.pricing.dto.CouponClaimRequest;
|
||||
import com.ycwl.basic.pricing.dto.CouponClaimResult;
|
||||
import com.ycwl.basic.pricing.dto.req.VoucherPrintReq;
|
||||
import com.ycwl.basic.pricing.dto.resp.VoucherPrintResp;
|
||||
import com.ycwl.basic.pricing.enums.CouponType;
|
||||
import com.ycwl.basic.pricing.service.ICouponService;
|
||||
import com.ycwl.basic.pricing.service.VoucherPrintService;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
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.RestController;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/claim/v1")
|
||||
@AllArgsConstructor
|
||||
public class AppClaimController {
|
||||
private final FaceRepository faceRepository;
|
||||
private final ScenicRepository scenicRepository;
|
||||
private final VoucherPrintService voucherPrintService;
|
||||
private final ICouponService couponService;
|
||||
|
||||
|
||||
@PostMapping("tryClaim")
|
||||
public ApiResponse<ClaimResp> tryClaim(@RequestBody ClaimReq req) {
|
||||
FaceEntity face = faceRepository.getFace(req.getFaceId());
|
||||
if (face == null) {
|
||||
return ApiResponse.fail("请选择人脸");
|
||||
}
|
||||
ClaimResp claimResp = new ClaimResp();
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(face.getScenicId());
|
||||
if (Boolean.TRUE.equals(scenicConfig.getBoolean("voucher_enable"))) {
|
||||
// 可以领券
|
||||
VoucherPrintResp voucherPrintResp = voucherPrintService.queryPrintedVoucher(face.getId());
|
||||
if (voucherPrintResp == null) {
|
||||
// 打印
|
||||
if (req.getMorphId() != null) {
|
||||
voucherPrintResp = voucherPrintService.printVoucherTicket(new VoucherPrintReq(face.getId(), req.getMorphId(), face.getScenicId()));
|
||||
}
|
||||
}
|
||||
if (voucherPrintResp != null) {
|
||||
claimResp.setHasCoupon(false);
|
||||
claimResp.setHasPrint(true);
|
||||
claimResp.setPrintCode(voucherPrintResp.getCode());
|
||||
claimResp.setPrintType(voucherPrintResp.getType());
|
||||
return ApiResponse.success(claimResp);
|
||||
}
|
||||
}
|
||||
if (Boolean.TRUE.equals(scenicConfig.getBoolean("booking_enable"))) {
|
||||
VoucherPrintResp voucherPrintResp = voucherPrintService.queryPrintedVoucher(face.getId());
|
||||
if (voucherPrintResp == null) {
|
||||
// 打印
|
||||
if (req.getMorphId() != null) {
|
||||
voucherPrintResp = voucherPrintService.printBookingTicket(new VoucherPrintReq(face.getId(), req.getMorphId(), face.getScenicId()));
|
||||
}
|
||||
}
|
||||
if (voucherPrintResp != null) {
|
||||
claimResp.setHasCoupon(false);
|
||||
claimResp.setHasPrint(true);
|
||||
claimResp.setPrintCode(voucherPrintResp.getCode());
|
||||
claimResp.setPrintType(voucherPrintResp.getType());
|
||||
return ApiResponse.success(claimResp);
|
||||
}
|
||||
}
|
||||
if (req.getType() != null) {
|
||||
// 第几次进入
|
||||
Integer couponId = scenicConfig.getInteger("coupon_id_for_type_" + req.getType());
|
||||
if (couponId != null) {
|
||||
// 可以领券
|
||||
CouponClaimRequest request = new CouponClaimRequest(face.getMemberId(), Long.valueOf(couponId));
|
||||
CouponClaimResult claimResult = couponService.claimCoupon(request);
|
||||
if (claimResult.isSuccess()) {
|
||||
// 领到了
|
||||
claimResp.setHasCoupon(true);
|
||||
switch (claimResult.getCoupon().getCouponType()) {
|
||||
case CouponType.PERCENTAGE:
|
||||
claimResp.setCouponType("折扣优惠券");
|
||||
claimResp.setCouponDesc("打" + (BigDecimal.valueOf(1).setScale(2, RoundingMode.HALF_UP).subtract(claimResult.getCoupon().getDiscountValue())).multiply(BigDecimal.valueOf(10)) + "折");
|
||||
break;
|
||||
case CouponType.FIXED_AMOUNT:
|
||||
if (claimResult.getCoupon().getMinAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
claimResp.setCouponType("满减优惠券");
|
||||
claimResp.setCouponDesc("满" + claimResult.getCoupon().getMinAmount() + "减" + claimResult.getCoupon().getDiscountValue());
|
||||
} else {
|
||||
claimResp.setCouponType("直减优惠券");
|
||||
claimResp.setCouponDesc("直减" + claimResult.getCoupon().getDiscountValue());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
claimResp.setCouponType("普通优惠券");
|
||||
break;
|
||||
}
|
||||
claimResp.setCouponDesc(scenicConfig.getString("coupon_desc_for_type_" + req.getType(), "专属折扣券"));
|
||||
claimResp.setCouponCountdown(scenicConfig.getString("coupon_countdown_for_type_" + req.getType(), "送你优惠,保存美好!"));
|
||||
return ApiResponse.success(claimResp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ApiResponse.fail("异常");
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,9 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.model.mobile.coupon.req.ClaimCouponReq;
|
||||
import com.ycwl.basic.model.pc.coupon.entity.CouponEntity;
|
||||
import com.ycwl.basic.model.pc.couponRecord.entity.CouponRecordEntity;
|
||||
import com.ycwl.basic.service.mobile.AppCouponRecordService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/coupon/v1")
|
||||
@RequestMapping("/api/mobile/controller/v1")
|
||||
public class AppCouponController {
|
||||
|
||||
@Autowired
|
||||
private AppCouponRecordService appCouponRecordService;
|
||||
|
||||
/**
|
||||
* 根据memberId、faceId和type查找优惠券记录
|
||||
*/
|
||||
@GetMapping("/record")
|
||||
public ApiResponse<CouponRecordEntity> getCouponRecords(
|
||||
@RequestParam Long faceId,
|
||||
@RequestParam Integer type) {
|
||||
CouponRecordEntity record = appCouponRecordService.queryByMemberIdAndFaceIdAndType(Long.valueOf(BaseContextHandler.getUserId()), faceId, type);
|
||||
return ApiResponse.success(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取优惠券
|
||||
*/
|
||||
@PostMapping("/claim")
|
||||
public ApiResponse<CouponEntity> claimCoupon(@RequestBody ClaimCouponReq request) {
|
||||
request.setMemberId(Long.valueOf(BaseContextHandler.getUserId()));
|
||||
try {
|
||||
CouponEntity coupon = appCouponRecordService.claimCoupon(
|
||||
request.getMemberId(),
|
||||
request.getFaceId(),
|
||||
request.getType()
|
||||
);
|
||||
return ApiResponse.success(coupon);
|
||||
} catch (RuntimeException e) {
|
||||
return ApiResponse.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.exception.BaseException;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
|
||||
import com.ycwl.basic.model.mobile.face.FaceStatusResp;
|
||||
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
||||
import com.ycwl.basic.model.mobile.face.FaceRecognitionUpdateReq;
|
||||
import com.ycwl.basic.model.mobile.face.FaceRecognitionDetailVO;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -26,13 +21,12 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/face/v1")
|
||||
// 用户人脸相关接口
|
||||
public class AppFaceController {
|
||||
@Api(tags = "用户人脸相关接口")
|
||||
public class
|
||||
AppFaceController {
|
||||
|
||||
@Autowired
|
||||
private FaceService faceService;
|
||||
@Autowired
|
||||
private FaceRepository faceRepository;
|
||||
|
||||
/**
|
||||
* 1、上传人脸照片
|
||||
@@ -43,15 +37,13 @@ public class AppFaceController {
|
||||
* @param scenicId
|
||||
* @return
|
||||
*/
|
||||
// 人脸照片上传
|
||||
@ApiOperation("人脸照片上传")
|
||||
@PostMapping("/faceUPload")
|
||||
public ApiResponse<FaceRecognizeResp> faceUpload(@RequestParam("file")MultipartFile file,
|
||||
@RequestParam(value = "scene", defaultValue = "", required = false) String scene,
|
||||
@RequestParam("scenicId") Long scenicId) {
|
||||
public ApiResponse<FaceRecognizeResp> faceUpload(@RequestParam("file")MultipartFile file, @RequestParam("scenicId") Long scenicId) {
|
||||
//获取用户id
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
Long userId = worker.getUserId();
|
||||
FaceRecognizeResp resp = faceService.faceUpload(file, scenicId, userId, scene);
|
||||
FaceRecognizeResp resp = faceService.faceUpload(file, scenicId, userId);
|
||||
return ApiResponse.success(resp);
|
||||
}
|
||||
|
||||
@@ -59,7 +51,7 @@ public class AppFaceController {
|
||||
public ApiResponse<List<FaceRespVO>> list(@PathVariable("scenicId") String scenicId) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
Long userId = worker.getUserId();
|
||||
List<FaceRespVO> list = faceService.listByUser(userId, Long.parseLong(scenicId));
|
||||
List<FaceRespVO> list = faceService.listByUser(userId, scenicId);
|
||||
return ApiResponse.success(list);
|
||||
}
|
||||
|
||||
@@ -70,18 +62,6 @@ public class AppFaceController {
|
||||
|
||||
@DeleteMapping("/{faceId}")
|
||||
public ApiResponse<String> deleteFace(@PathVariable("faceId") Long faceId) {
|
||||
// 添加权限检查:验证当前用户是否拥有该 face
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
Long userId = worker.getUserId();
|
||||
|
||||
FaceEntity face = faceRepository.getFace(faceId);
|
||||
if (face == null) {
|
||||
throw new BaseException("人脸数据不存在");
|
||||
}
|
||||
if (!face.getMemberId().equals(userId)) {
|
||||
throw new BaseException("无权删除此人脸");
|
||||
}
|
||||
|
||||
return faceService.deleteFace(faceId);
|
||||
}
|
||||
|
||||
@@ -92,55 +72,10 @@ public class AppFaceController {
|
||||
}
|
||||
|
||||
|
||||
// 景区视频源素材列表
|
||||
@ApiOperation("景区视频源素材列表")
|
||||
@GetMapping("/{faceId}/contentList")
|
||||
public ApiResponse<List<ContentPageVO>> contentList(@PathVariable Long faceId) {
|
||||
List<ContentPageVO> contentPageVOS = faceService.faceContentList(faceId);
|
||||
return ApiResponse.success(contentPageVOS);
|
||||
}
|
||||
|
||||
// 绑定人脸
|
||||
@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");
|
||||
}
|
||||
|
||||
@GetMapping("/{faceId}/status")
|
||||
public ApiResponse<FaceStatusResp> status(@PathVariable Long faceId) {
|
||||
return ApiResponse.success(faceService.getFaceStatus(faceId));
|
||||
}
|
||||
|
||||
@GetMapping("/{faceId}/extraCheck")
|
||||
public ApiResponse<Boolean> hasExtraCheck(@PathVariable Long faceId) {
|
||||
return ApiResponse.success(faceService.checkHasExtraCheck(faceId));
|
||||
}
|
||||
|
||||
@GetMapping("/{faceId}/queryOtherFace")
|
||||
public ApiResponse<List<FaceSampleEntity>> queryOtherFace(@PathVariable Long faceId) {
|
||||
return ApiResponse.success(faceService.getLowMatchedFaceSamples(faceId));
|
||||
}
|
||||
|
||||
@PostMapping("/{faceId}/queryOtherFace")
|
||||
public ApiResponse<String> queryOtherFace(@PathVariable Long faceId, @RequestBody List<Long> faceIds) {
|
||||
faceService.matchCustomFaceId(faceId, faceIds);
|
||||
return ApiResponse.success("OK");
|
||||
}
|
||||
|
||||
@PutMapping("/{faceId}/recognition")
|
||||
public ApiResponse<?> updateRecognition(@PathVariable Long faceId,
|
||||
@RequestBody FaceRecognitionUpdateReq req) {
|
||||
req.setFaceId(faceId);
|
||||
faceService.updateRecognition(req);
|
||||
return ApiResponse.success("OK");
|
||||
}
|
||||
|
||||
@GetMapping("/{faceId}/recognition/detail")
|
||||
public ApiResponse<FaceRecognitionDetailVO> recognitionDetail(@PathVariable Long faceId) {
|
||||
return ApiResponse.success(faceService.getRecognitionDetail(faceId));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.exception.CheckTokenException;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.goods.*;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.service.mobile.GoodsService;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -21,32 +21,26 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/goods/v1")
|
||||
// 商品相关接口
|
||||
@Api(tags = "商品相关接口")
|
||||
public class AppGoodsController {
|
||||
|
||||
@Autowired
|
||||
private GoodsService goodsService;
|
||||
@Autowired
|
||||
private FaceService faceService;
|
||||
|
||||
// 商品列表
|
||||
@ApiOperation("商品列表")
|
||||
@PostMapping("/goodsList")
|
||||
public ApiResponse<List<GoodsPageVO>> goodsList(@RequestBody GoodsReqQuery query) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
Long userId = worker.getUserId();
|
||||
List<FaceRespVO> faceRespVOS = faceService.listByUser(userId, query.getScenicId());
|
||||
List<Long> faceIds = faceRespVOS.stream().map(FaceRespVO::getId).toList();
|
||||
return goodsService.listGoodsByFaceIdList(faceIds, query.getIsBuy(), query.getScenicId());
|
||||
return goodsService.goodsList(query);
|
||||
}
|
||||
|
||||
// 源素材(原片/照片)商品列表
|
||||
@ApiOperation("源素材(原片/照片)商品列表")
|
||||
@PostMapping("/sourceGoodsList")
|
||||
public ApiResponse<List<GoodsDetailVO>> sourceGoodsList(@RequestBody GoodsReqQuery query) {
|
||||
List<GoodsDetailVO> goodsDetailVOS = goodsService.sourceGoodsList(query);
|
||||
return ApiResponse.success(goodsDetailVOS);
|
||||
}
|
||||
|
||||
// 源素材(原片/照片)商品数量
|
||||
@ApiOperation("源素材(原片/照片)商品数量")
|
||||
@PostMapping("/sourceGoodsCount")
|
||||
public ApiResponse<Integer> sourceGoodsCount(@RequestBody GoodsReqQuery query) {
|
||||
Integer count = goodsService.sourceGoodsCount(query);
|
||||
@@ -66,7 +60,7 @@ public class AppGoodsController {
|
||||
}
|
||||
|
||||
|
||||
// 成片vlog商品详情
|
||||
@ApiOperation("成片vlog商品详情")
|
||||
@GetMapping("/getVideoGoodsDetail/{videoId}")
|
||||
@IgnoreToken
|
||||
public ApiResponse<VideoGoodsDetailVO> videoGoodsDetail(@PathVariable("videoId") Long videoId) {
|
||||
@@ -88,7 +82,7 @@ public class AppGoodsController {
|
||||
*
|
||||
* @return 0没有任务 1 合成中 2 合成成功
|
||||
*/
|
||||
// 查询用户当前景区的整体视频合成任务状态 0没有任务 1 合成中 2 合成成功
|
||||
@ApiOperation("查询用户当前景区的整体视频合成任务状态 0没有任务 1 合成中 2 合成成功 ")
|
||||
@GetMapping("/getTaskStatus/")
|
||||
public ApiResponse<VideoTaskStatusVO> getAllTaskStatus() {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
@@ -101,22 +95,10 @@ public class AppGoodsController {
|
||||
* @param templateId 模版id
|
||||
* @return 1 合成中 2 合成成功
|
||||
*/
|
||||
// 查询用户当前景区的具体模版视频合成任务状态 1 合成中 2 合成成功
|
||||
@ApiOperation("查询用户当前景区的具体模版视频合成任务状态 1 合成中 2 合成成功 ")
|
||||
@GetMapping("/task/face/{faceId}/template/{templateId}")
|
||||
public ApiResponse<VideoTaskStatusVO> getTemplateTaskStatus(@PathVariable("faceId") Long faceId, @PathVariable("templateId") Long templateId) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
return ApiResponse.success(goodsService.getTaskStatusByTemplateId(faceId, templateId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查视频是否可更新
|
||||
*
|
||||
* @param videoId 视频ID
|
||||
* @return 视频更新检查结果
|
||||
*/
|
||||
@GetMapping("/video/{videoId}/updateCheck")
|
||||
public ApiResponse<VideoUpdateCheckVO> checkVideoUpdate(@PathVariable("videoId") Long videoId) {
|
||||
VideoUpdateCheckVO result = goodsService.checkVideoUpdate(videoId);
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import com.ycwl.basic.model.mobile.weChat.DTO.WeChatUserInfoUpdateDTO;
|
||||
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
|
||||
import com.ycwl.basic.service.mobile.AppMemberService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -16,7 +18,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/member/v1")
|
||||
// 用户相关接口
|
||||
@Api(tags = "用户相关接口")
|
||||
@Slf4j
|
||||
public class AppMemberController {
|
||||
|
||||
@@ -30,29 +32,19 @@ public class AppMemberController {
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
// 登录
|
||||
@ApiOperation("登录")
|
||||
@PostMapping("/{scenicId}/login")
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> login(@PathVariable("scenicId") Long scenicId ,@RequestBody WeChatUserInfoDTO userInfoDTO) throws Exception {
|
||||
return memberService.login(scenicId, userInfoDTO.getCode(), userInfoDTO);
|
||||
}
|
||||
@PostMapping("/undefined/login")
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> loginUndefined(@RequestBody WeChatUserInfoDTO userInfoDTO) throws Exception {
|
||||
return memberService.login(null, userInfoDTO.getCode(), userInfoDTO);
|
||||
}
|
||||
@PostMapping({"//login", "/login"})
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> loginNoScenicId(@RequestBody WeChatUserInfoDTO userInfoDTO) throws Exception {
|
||||
return memberService.login(null, userInfoDTO.getCode(), userInfoDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
// 获取用户信息
|
||||
@ApiOperation("获取用户信息")
|
||||
@GetMapping("/getUserInfo")
|
||||
public ApiResponse<MemberRespVO> getUserInfo() {
|
||||
return memberService.getUserInfo();
|
||||
@@ -64,19 +56,19 @@ public class AppMemberController {
|
||||
* @param userInfoUpdateDTO
|
||||
* @return
|
||||
*/
|
||||
// 修改用户信息
|
||||
@ApiOperation("修改用户信息")
|
||||
@PostMapping("/update")
|
||||
public ApiResponse<?> update(@RequestBody WeChatUserInfoUpdateDTO userInfoUpdateDTO) {
|
||||
return memberService.update(userInfoUpdateDTO);
|
||||
}
|
||||
|
||||
// 新增或修改景区服务通知状态
|
||||
@ApiOperation("新增或修改景区服务通知状态")
|
||||
@GetMapping("/updateScenicServiceNoticeStatus")
|
||||
public ApiResponse<String> updateScenicServiceNoticeStatus(Long scenicId) {
|
||||
return memberService.updateScenicServiceNoticeStatus(scenicId);
|
||||
}
|
||||
|
||||
// 查看景区服务通知状态 0关闭 1开启
|
||||
@ApiOperation("查看景区服务通知状态 0关闭 1开启")
|
||||
@GetMapping("/getScenicServiceNoticeStatus")
|
||||
public ApiResponse<Integer> getScenicServiceNoticeStatus(Long scenicId) {
|
||||
return memberService.getScenicServiceNoticeStatus(scenicId);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.biz.PriceBiz;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
@@ -19,6 +18,8 @@ import com.ycwl.basic.pay.entity.PayResponse;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -30,7 +31,7 @@ import java.util.Map;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/order/v1")
|
||||
// 订单相关接口
|
||||
@Api(tags = "订单相关接口")
|
||||
public class AppOrderController {
|
||||
|
||||
@Autowired
|
||||
@@ -42,7 +43,7 @@ public class AppOrderController {
|
||||
@Autowired
|
||||
private FaceMapper faceMapper;
|
||||
|
||||
// 用户端订单列表查询
|
||||
@ApiOperation("用户端订单列表查询")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<OrderAppRespVO>> pageQuery(@RequestBody OrderAppPageReq orderReqQuery) {
|
||||
String userId = BaseContextHandler.getUserId();
|
||||
@@ -50,27 +51,26 @@ public class AppOrderController {
|
||||
return orderService.appPageQuery(orderReqQuery);
|
||||
}
|
||||
|
||||
// 用户端订单详情查询
|
||||
@ApiOperation("用户端订单详情查询")
|
||||
@GetMapping("getOrderDetails/{id}")
|
||||
@IgnoreToken
|
||||
public ApiResponse<OrderAppRespVO> getOrderDetails(@PathVariable("id") Long id) {
|
||||
return orderService.appDetail(id);
|
||||
}
|
||||
|
||||
// 用户端订单新增
|
||||
@ApiOperation("用户端订单新增")
|
||||
@PostMapping("/addOrder")
|
||||
public ApiResponse<Map<String, Object>> addOrder(@RequestBody CreateOrderReqVO orderAddReq) throws Exception {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
return orderService.createOrder(worker.getUserId(), orderAddReq);
|
||||
}
|
||||
|
||||
// 查询订单
|
||||
@ApiOperation("查询订单")
|
||||
@GetMapping("/queryOrder")
|
||||
public ApiResponse<PayResponse> queryOrder(@RequestParam("orderId") Long orderId) {
|
||||
return ApiResponse.success(orderService.queryOrder(orderId));
|
||||
}
|
||||
|
||||
// 用户端打包订单新增
|
||||
@ApiOperation("用户端打包订单新增")
|
||||
@PostMapping("/addBatchOrder")
|
||||
public ApiResponse<Map<String, Object>> addOrder(@RequestBody CreateBatchOrderReqVO batchOrderReqVO) throws Exception {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
@@ -78,7 +78,7 @@ public class AppOrderController {
|
||||
}
|
||||
|
||||
|
||||
// 获取用户订单数量
|
||||
@ApiOperation("获取用户订单数量")
|
||||
@GetMapping("/getUserOrderCount")
|
||||
public ApiResponse<Integer> getUserOrderCount() {
|
||||
Long userId = Long.parseLong(BaseContextHandler.getUserId());
|
||||
@@ -86,16 +86,16 @@ public class AppOrderController {
|
||||
return orderService.getOrderCountByUserId(userId);
|
||||
}
|
||||
|
||||
// 发起退款
|
||||
@ApiOperation(value = "发起退款", notes = "发起退款")
|
||||
@PostMapping("/refundOrder")
|
||||
public ApiResponse<?> refundOrder(@RequestBody RefundOrderReq refundOrderReq) {
|
||||
return orderService.refundOrder(refundOrderReq);
|
||||
}
|
||||
|
||||
@GetMapping("/scenic/{scenicId}/query")
|
||||
public ApiResponse<IsBuyRespVO> isBuy(@PathVariable("scenicId") Long scenicId, @RequestParam("type") Integer type, @RequestParam("goodsId") Long goodsId, @RequestParam(value = "faceId", required = false) Long faceId) {
|
||||
public ApiResponse<IsBuyRespVO> isBuy(@PathVariable("scenicId") Long scenicId, @RequestParam("type") Integer type, @RequestParam("goodsId") Long goodsId) {
|
||||
Long userId = Long.parseLong(BaseContextHandler.getUserId());
|
||||
return ApiResponse.success(orderBiz.isBuy(scenicId, userId, faceId, type, goodsId));
|
||||
return ApiResponse.success(orderBiz.isBuy(userId, scenicId, type, goodsId));
|
||||
}
|
||||
|
||||
@GetMapping("/scenic/{scenicId}/queryBatchPrice")
|
||||
@@ -108,7 +108,7 @@ public class AppOrderController {
|
||||
}
|
||||
faceId = lastFaceByUserId.getId();
|
||||
}
|
||||
IsBuyBatchRespVO buy = priceBiz.isOnePriceBuy(userId, faceId, scenicId, type, goodsIds);
|
||||
IsBuyBatchRespVO buy = priceBiz.isBuy(userId, faceId, scenicId, type, goodsIds);
|
||||
if (buy == null) {
|
||||
return ApiResponse.fail("该套餐暂未开放购买");
|
||||
}
|
||||
|
||||
@@ -1,359 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.mapper.VideoMapper;
|
||||
import com.ycwl.basic.model.pc.source.req.SourceReqQuery;
|
||||
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.pricing.enums.ProductType;
|
||||
import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
import com.ycwl.basic.repository.VideoTaskRepository;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.pricing.dto.*;
|
||||
import com.ycwl.basic.pricing.service.IPriceCalculationService;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.service.PriceCacheService;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.dto.MobileOrderRequest;
|
||||
import com.ycwl.basic.order.service.IOrderService;
|
||||
import com.ycwl.basic.order.dto.OrderV2DetailResponse;
|
||||
import com.ycwl.basic.order.dto.OrderV2ListResponse;
|
||||
import com.ycwl.basic.order.dto.OrderV2PageRequest;
|
||||
import com.ycwl.basic.order.dto.PaymentParamsRequest;
|
||||
import com.ycwl.basic.order.dto.PaymentParamsResponse;
|
||||
import com.ycwl.basic.order.dto.PaymentCallbackResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 移动端订单控制器V2
|
||||
* 包含价格查询和订单管理功能
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/order/v2")
|
||||
@RequiredArgsConstructor
|
||||
public class AppOrderV2Controller {
|
||||
|
||||
private final IPriceCalculationService priceCalculationService;
|
||||
private final FaceService faceService;
|
||||
private final PriceCacheService priceCacheService;
|
||||
private final IOrderService orderService;
|
||||
private final OrderService oldOrderService;
|
||||
private final SourceMapper sourceMapper;
|
||||
private final VideoMapper videoMapper;
|
||||
private final VideoTaskRepository videoTaskRepository;
|
||||
private final TemplateRepository templateRepository;
|
||||
private final VideoRepository videoRepository;
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 移动端价格计算
|
||||
* 包含权限验证:验证人脸所属景区与当前用户匹配
|
||||
* 集成Redis缓存机制,提升查询性能
|
||||
*/
|
||||
@PostMapping("/calculate")
|
||||
public ApiResponse<PriceCalculationResult> calculatePrice(@RequestBody MobilePriceCalculationRequest request) {
|
||||
// 获取当前登录用户ID
|
||||
String currentUserIdStr = BaseContextHandler.getUserId();
|
||||
if (currentUserIdStr == null) {
|
||||
log.warn("移动端价格计算:用户未登录");
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long currentUserId = Long.valueOf(currentUserIdStr);
|
||||
log.info("移动端价格计算请求: userId={}, faceId={}, products={}",
|
||||
currentUserId, request.getFaceId(), request.getProducts().size());
|
||||
|
||||
// 验证faceId参数
|
||||
if (request.getFaceId() == null) {
|
||||
log.warn("移动端价格计算:faceId参数缺失");
|
||||
// return ApiResponse.fail("faceId参数不能为空");
|
||||
// 兼容:兼容旧版本
|
||||
ProductItem productItem = request.getProducts().getFirst();
|
||||
switch (productItem.getProductType()) {
|
||||
case VLOG_VIDEO -> {
|
||||
VideoEntity video = videoRepository.getVideo(Long.valueOf(productItem.getProductId()));
|
||||
TaskEntity task = videoTaskRepository.getTaskById(video.getTaskId());
|
||||
request.setFaceId(task.getFaceId());
|
||||
}
|
||||
case RECORDING_SET, PHOTO_SET, AI_CAM_PHOTO_SET -> request.setFaceId(Long.valueOf(productItem.getProductId()));
|
||||
}
|
||||
}
|
||||
|
||||
// 查询人脸信息进行权限验证
|
||||
ApiResponse<FaceRespVO> faceResponse = faceService.getById(request.getFaceId());
|
||||
if (!faceResponse.isSuccess() || faceResponse.getData() == null) {
|
||||
log.warn("移动端价格计算:人脸信息不存在, faceId={}", request.getFaceId());
|
||||
return ApiResponse.fail("人脸信息不存在");
|
||||
}
|
||||
|
||||
FaceRespVO face = faceResponse.getData();
|
||||
Long scenicId = face.getScenicId();
|
||||
|
||||
request.getProducts().forEach(product -> {
|
||||
switch (product.getProductType()) {
|
||||
case VLOG_VIDEO:
|
||||
List<MemberVideoEntity> videoEntities = videoMapper.listRelationByFaceAndTemplate(face.getId(), Long.valueOf(product.getProductId()));
|
||||
if (videoEntities != null && !videoEntities.isEmpty()) {
|
||||
product.setQuantity(videoTaskRepository.getTaskLensNum(videoEntities.getFirst().getTaskId()));
|
||||
} else {
|
||||
product.setQuantity(1);
|
||||
}
|
||||
break;
|
||||
case RECORDING_SET:
|
||||
case PHOTO_SET:
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setMemberId(currentUserId);
|
||||
sourceReqQuery.setType(product.getProductType() == ProductType.RECORDING_SET ? 1 : 2);
|
||||
sourceReqQuery.setFaceId(face.getId());
|
||||
Integer count = sourceMapper.countUser(sourceReqQuery);
|
||||
product.setQuantity(count);
|
||||
break;
|
||||
case AI_CAM_PHOTO_SET:
|
||||
SourceReqQuery aiPhotoSetReqQuery = new SourceReqQuery();
|
||||
aiPhotoSetReqQuery.setMemberId(currentUserId);
|
||||
aiPhotoSetReqQuery.setType(13);
|
||||
aiPhotoSetReqQuery.setFaceId(face.getId());
|
||||
Integer _count = sourceMapper.countUser(aiPhotoSetReqQuery);
|
||||
product.setQuantity(_count);
|
||||
break;
|
||||
default:
|
||||
log.warn("未知的商品类型,跳过重复购买检查: productType={}", product.getProductType());
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 转换为标准价格计算请求
|
||||
PriceCalculationRequest standardRequest = request.toStandardRequest(currentUserId, scenicId);
|
||||
|
||||
// 执行价格计算
|
||||
PriceCalculationResult result = priceCalculationService.calculatePrice(standardRequest);
|
||||
|
||||
// 将计算结果缓存到Redis
|
||||
String cacheKey = priceCacheService.cachePriceResult(currentUserId, scenicId, request.getProducts(), result);
|
||||
|
||||
log.info("移动端价格计算完成: userId={}, scenicId={}, originalAmount={}, finalAmount={}, cacheKey={}",
|
||||
currentUserId, scenicId, result.getOriginalAmount(), result.getFinalAmount(), cacheKey);
|
||||
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动端下单接口
|
||||
* 验证价格缓存有效性,确保5分钟内使用缓存价格下单
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<String> addOrder(@RequestBody MobileOrderRequest request) {
|
||||
// 获取当前登录用户ID
|
||||
String currentUserIdStr = BaseContextHandler.getUserId();
|
||||
if (currentUserIdStr == null) {
|
||||
log.warn("移动端下单:用户未登录");
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long currentUserId = Long.valueOf(currentUserIdStr);
|
||||
log.info("移动端下单请求: userId={}, faceId={}, products={}, expectedFinalAmount={}",
|
||||
currentUserId, request.getFaceId(), request.getProducts().size(), request.getExpectedFinalAmount());
|
||||
|
||||
// 验证必填参数
|
||||
if (request.getFaceId() == null) {
|
||||
log.warn("移动端下单:faceId参数缺失");
|
||||
return ApiResponse.fail("faceId参数不能为空");
|
||||
}
|
||||
|
||||
if (request.getProducts() == null || request.getProducts().isEmpty()) {
|
||||
log.warn("移动端下单:商品列表为空");
|
||||
return ApiResponse.fail("商品列表不能为空");
|
||||
}
|
||||
|
||||
if (request.getExpectedFinalAmount() == null) {
|
||||
log.warn("移动端下单:预期价格参数缺失");
|
||||
return ApiResponse.fail("预期价格不能为空");
|
||||
}
|
||||
|
||||
// 查询人脸信息进行权限验证
|
||||
ApiResponse<FaceRespVO> faceResponse = faceService.getById(request.getFaceId());
|
||||
if (!faceResponse.isSuccess() || faceResponse.getData() == null) {
|
||||
log.warn("移动端下单:人脸信息不存在, faceId={}", request.getFaceId());
|
||||
return ApiResponse.fail("人脸信息不存在");
|
||||
}
|
||||
|
||||
FaceRespVO face = faceResponse.getData();
|
||||
Long scenicId = face.getScenicId();
|
||||
|
||||
// 验证并消费价格缓存(一次性使用)
|
||||
PriceCalculationResult cachedResult = priceCacheService.validateAndConsumePriceCache(
|
||||
currentUserId, scenicId, request.getProducts());
|
||||
|
||||
if (cachedResult == null) {
|
||||
log.warn("移动端下单:价格缓存已过期或不存在, userId={}, scenicId={}", currentUserId, scenicId);
|
||||
return ApiResponse.fail("请重新下单!");
|
||||
}
|
||||
|
||||
// 验证价格是否匹配
|
||||
if (cachedResult.getFinalAmount().compareTo(request.getExpectedFinalAmount()) != 0) {
|
||||
log.warn("移动端下单:价格不匹配, cached={}, expected={}, userId={}, scenicId={}",
|
||||
cachedResult.getFinalAmount(), request.getExpectedFinalAmount(), currentUserId, scenicId);
|
||||
return ApiResponse.fail("价格信息变化,请退出后重新查询价格!");
|
||||
}
|
||||
|
||||
// 验证原价是否匹配(可选)
|
||||
if (request.getExpectedOriginalAmount() != null &&
|
||||
cachedResult.getOriginalAmount().compareTo(request.getExpectedOriginalAmount()) != 0) {
|
||||
log.warn("移动端下单:原价不匹配, cached={}, expected={}, userId={}, scenicId={}",
|
||||
cachedResult.getOriginalAmount(), request.getExpectedOriginalAmount(), currentUserId, scenicId);
|
||||
return ApiResponse.fail("原价信息不匹配,请重新查询价格后再下单");
|
||||
}
|
||||
|
||||
log.info("价格缓存验证通过: userId={}, scenicId={}, finalAmount={}",
|
||||
currentUserId, scenicId, cachedResult.getFinalAmount());
|
||||
|
||||
// 使用旧版创建订单逻辑
|
||||
try {
|
||||
Long orderId = oldOrderService.createOrderCompact(currentUserId, request, cachedResult);
|
||||
return ApiResponse.success(String.valueOf(orderId));
|
||||
} catch (Exception e) {
|
||||
log.warn("移动端下单:订单创建失败, userId={}, scenicId={}, error={}", currentUserId, scenicId, e.getMessage(), e);
|
||||
return ApiResponse.fail("订单创建失败,请稍后重试");
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
// try {
|
||||
// Long orderId = orderService.createOrder(request, currentUserId, scenicId, cachedResult);
|
||||
//
|
||||
// log.info("移动端订单创建成功: orderId={}, userId={}, scenicId={}, finalAmount={}",
|
||||
// orderId, currentUserId, scenicId, cachedResult.getFinalAmount());
|
||||
//
|
||||
// return ApiResponse.success(orderId.toString());
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// log.error("订单创建失败: userId={}, scenicId={}, error={}", currentUserId, scenicId, e.getMessage(), e);
|
||||
// return ApiResponse.fail("订单创建失败,请稍后重试");
|
||||
// }
|
||||
}
|
||||
|
||||
// ====== 新增移动端订单查询功能 ======
|
||||
|
||||
/**
|
||||
* 用户分页查询自己的订单列表
|
||||
*/
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<OrderV2ListResponse>> pageUserOrders(@RequestBody OrderV2PageRequest request) {
|
||||
String currentUserIdStr = BaseContextHandler.getUserId();
|
||||
if (currentUserIdStr == null) {
|
||||
log.warn("用户未登录");
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long currentUserId = Long.valueOf(currentUserIdStr);
|
||||
request.setMemberId(currentUserId); // 设置当前用户ID,确保只查询自己的订单
|
||||
|
||||
log.info("用户查询订单列表: userId={}, request={}", currentUserId, request);
|
||||
|
||||
try {
|
||||
PageInfo<OrderV2ListResponse> pageInfo = orderService.pageOrdersByUser(request);
|
||||
return ApiResponse.success(pageInfo);
|
||||
} catch (Exception e) {
|
||||
log.error("查询用户订单列表失败: userId={}", currentUserId, e);
|
||||
return ApiResponse.fail("查询失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单详情
|
||||
*/
|
||||
@GetMapping("/detail/{orderId}")
|
||||
public ApiResponse<OrderV2DetailResponse> getUserOrderDetail(@PathVariable("orderId") Long orderId) {
|
||||
log.info("查询订单详情: orderId={}", orderId);
|
||||
|
||||
try {
|
||||
OrderV2DetailResponse detail = orderService.getOrderDetail(orderId);
|
||||
if (detail == null) {
|
||||
return ApiResponse.fail("订单不存在");
|
||||
}
|
||||
|
||||
return ApiResponse.success(detail);
|
||||
} catch (Exception e) {
|
||||
log.error("查询订单详情失败: orderId={}", orderId, e);
|
||||
return ApiResponse.fail("查询失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 支付相关接口 ======
|
||||
|
||||
/**
|
||||
* 获取订单支付参数
|
||||
* 用于小程序调起支付
|
||||
*/
|
||||
@PostMapping("/{orderId}/payment-params")
|
||||
public ApiResponse<PaymentParamsResponse> getPaymentParams(
|
||||
@PathVariable("orderId") Long orderId,
|
||||
@RequestBody PaymentParamsRequest request) {
|
||||
|
||||
String currentUserIdStr = BaseContextHandler.getUserId();
|
||||
if (currentUserIdStr == null) {
|
||||
log.warn("用户未登录");
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long currentUserId = Long.valueOf(currentUserIdStr);
|
||||
|
||||
log.info("获取支付参数: userId={}, orderId={}", currentUserId, orderId);
|
||||
|
||||
return oldOrderService.getPaymentParams(orderId, currentUserId, request);
|
||||
|
||||
//
|
||||
// try {
|
||||
// PaymentParamsResponse response = orderService.getPaymentParams(orderId, currentUserId, request);
|
||||
// return ApiResponse.success(response);
|
||||
// } catch (Exception e) {
|
||||
// log.error("获取支付参数失败: userId={}, orderId={}", currentUserId, orderId, e);
|
||||
// return ApiResponse.fail(e.getMessage());
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付回调处理接口
|
||||
* 供第三方支付平台回调使用
|
||||
*/
|
||||
@PostMapping("/payment/callback/{scenicId}")
|
||||
public String handlePaymentCallback(
|
||||
@PathVariable("scenicId") Long scenicId,
|
||||
HttpServletRequest request) {
|
||||
|
||||
log.info("接收支付回调: scenicId={}", scenicId);
|
||||
|
||||
try {
|
||||
PaymentCallbackResponse response = orderService.handlePaymentCallback(scenicId, request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
log.info("支付回调处理成功: scenicId={}, orderId={}, statusChangeType={}",
|
||||
scenicId, response.getOrderId(), response.getStatusChangeType());
|
||||
return "SUCCESS"; // 返回给第三方支付平台的成功标识
|
||||
} else {
|
||||
log.error("支付回调处理失败: scenicId={}, message={}", scenicId, response.getMessage());
|
||||
return "FAIL"; // 返回给第三方支付平台的失败标识
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("支付回调异常: scenicId={}", scenicId, e);
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/downloadable/{orderId}")
|
||||
public ApiResponse<Boolean> getDownloadableOrder(@PathVariable("orderId") Long orderId) {
|
||||
return ApiResponse.success(!redisTemplate.hasKey("order_content_not_downloadable_" + orderId));
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
|
||||
import com.ycwl.basic.model.pc.printer.resp.MemberPrintResp;
|
||||
import com.ycwl.basic.model.pc.printer.resp.PrinterResp;
|
||||
import com.ycwl.basic.model.printer.req.FromSourceReq;
|
||||
@@ -17,7 +16,6 @@ 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.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -37,16 +35,10 @@ public class AppPrinterController {
|
||||
return ApiResponse.success(printerService.listByScenicId(scenicId));
|
||||
}
|
||||
|
||||
@GetMapping("/useSample/{sampleId}")
|
||||
public ApiResponse<FaceRecognizeResp> useSample(@PathVariable("sampleId") Long sampleId) throws IOException {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
return ApiResponse.success(printerService.useSample(worker.getUserId(), sampleId));
|
||||
}
|
||||
|
||||
@GetMapping("/getListFor/{scenicId}")
|
||||
public ApiResponse<List<MemberPrintResp>> getListFor(@PathVariable("scenicId") Long scenicId, @RequestParam(required = false) String faceId) {
|
||||
public ApiResponse<List<MemberPrintResp>> getListFor(@PathVariable("scenicId") Long scenicId) {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
return ApiResponse.success(printerService.getUserPhotoList(worker.getUserId(), scenicId, parseFaceId(faceId)));
|
||||
return ApiResponse.success(printerService.getUserPhotoList(worker.getUserId(), scenicId));
|
||||
}
|
||||
|
||||
@GetMapping("/getItem/{scenicId}/{id}")
|
||||
@@ -60,38 +52,31 @@ public class AppPrinterController {
|
||||
}
|
||||
|
||||
@PostMapping("/deleteFrom/{scenicId}/{id}")
|
||||
public ApiResponse<?> deleteFrom(@PathVariable("scenicId") Long scenicId, @PathVariable("id") Long id) {
|
||||
public ApiResponse<?> deleteFrom(@PathVariable("scenicId") Long scenicId, @PathVariable("id") Long id) throws IOException {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
printerService.deleteUserPhoto(worker.getUserId(), scenicId, id);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
@PostMapping("/uploadTo/{scenicId}")
|
||||
public ApiResponse<?> upload(@PathVariable("scenicId") Long scenicId,
|
||||
@RequestParam(value = "file") MultipartFile file,
|
||||
@RequestParam(value = "faceId", required = false) String faceId) {
|
||||
public ApiResponse<?> upload(@PathVariable("scenicId") Long scenicId, @RequestParam(value = "file") MultipartFile file) throws IOException {
|
||||
String[] split = file.getOriginalFilename().split("\\.");
|
||||
String ext = split[split.length - 1];
|
||||
String url = StorageFactory.use().uploadFile(file, "printer", UUID.randomUUID() + "." + ext);
|
||||
Integer id = printerService.addUserPhoto(JwtTokenUtil.getWorker().getUserId(), scenicId, url, parseFaceId(faceId), null);
|
||||
return ApiResponse.success(id);
|
||||
printerService.addUserPhoto(JwtTokenUtil.getWorker().getUserId(), scenicId, url);
|
||||
return ApiResponse.success(url);
|
||||
}
|
||||
@PostMapping(value = "/uploadTo/{scenicId}/cropped/{id}", consumes = "multipart/form-data")
|
||||
public ApiResponse<?> uploadReplace(@PathVariable("scenicId") Long scenicId,
|
||||
@PathVariable("id") Long id,
|
||||
@RequestPart(value = "crop", required = false) String crop,
|
||||
@RequestPart(value = "file") MultipartFile file) {
|
||||
@PostMapping("/uploadTo/{scenicId}/cropped/{id}")
|
||||
public ApiResponse<?> uploadReplace(@PathVariable("scenicId") Long scenicId, @PathVariable("id") Long id, @RequestParam(value = "file") MultipartFile file) throws IOException {
|
||||
String[] split = file.getOriginalFilename().split("\\.");
|
||||
String ext = split[split.length - 1];
|
||||
String url = StorageFactory.use().uploadFile(file, "printer", UUID.randomUUID() + "." + ext);
|
||||
printerService.setPhotoCropped(JwtTokenUtil.getWorker().getUserId(), scenicId, id, url, crop);
|
||||
printerService.setPhotoCropped(JwtTokenUtil.getWorker().getUserId(), scenicId, id, url);
|
||||
return ApiResponse.success(url);
|
||||
}
|
||||
@PostMapping("/uploadTo/{scenicId}/formSource")
|
||||
public ApiResponse<?> uploadFromSource(@PathVariable("scenicId") Long scenicId,
|
||||
@RequestBody FromSourceReq req,
|
||||
@RequestParam(value = "faceId", required = false) String faceId) {
|
||||
List<Integer> list = printerService.addUserPhotoFromSource(JwtTokenUtil.getWorker().getUserId(), scenicId, req, parseFaceId(faceId));
|
||||
return ApiResponse.success(list);
|
||||
public ApiResponse<?> uploadFromSource(@PathVariable("scenicId") Long scenicId, @RequestBody FromSourceReq req) throws IOException {
|
||||
printerService.addUserPhotoFromSource(JwtTokenUtil.getWorker().getUserId(), scenicId, req);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@PostMapping("/setQuantity/{scenicId}/{id}")
|
||||
@@ -106,35 +91,16 @@ public class AppPrinterController {
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
@GetMapping("/price/{scenicId}")
|
||||
public ApiResponse<?> queryPrice(@PathVariable("scenicId") Long scenicId,
|
||||
@RequestParam(value = "faceId", required = false) String faceId) {
|
||||
return ApiResponse.success(printerService.queryPrice(JwtTokenUtil.getWorker().getUserId(), scenicId, parseFaceId(faceId)));
|
||||
public ApiResponse<?> queryPrice(@PathVariable("scenicId") Long scenicId) {
|
||||
return ApiResponse.success(printerService.queryPrice(JwtTokenUtil.getWorker().getUserId(), scenicId));
|
||||
}
|
||||
|
||||
@PostMapping("/order/{scenicId}")
|
||||
public ApiResponse<Map<String, Object>> createOrder(@PathVariable("scenicId") Long scenicId,
|
||||
@RequestParam(value = "faceId", required = false) String faceId) {
|
||||
return ApiResponse.success(printerService.createOrder(JwtTokenUtil.getWorker().getUserId(), scenicId, null, parseFaceId(faceId)));
|
||||
public ApiResponse<Map<String, Object>> createOrder(@PathVariable("scenicId") Long scenicId) {
|
||||
return ApiResponse.success(printerService.createOrder(JwtTokenUtil.getWorker().getUserId(), scenicId, null));
|
||||
}
|
||||
@PostMapping("/order/{scenicId}/toPrinter/{printerId}")
|
||||
public ApiResponse<Map<String, Object>> createOrderToPrinter(@PathVariable("scenicId") Long scenicId,
|
||||
@PathVariable("printerId") Integer printerId,
|
||||
@RequestParam(value = "faceId", required = false) String faceId) {
|
||||
return ApiResponse.success(printerService.createOrder(JwtTokenUtil.getWorker().getUserId(), scenicId, printerId, parseFaceId(faceId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 faceId 字符串为 Long 类型
|
||||
* 如果字符串不是有效数字,则返回 null
|
||||
*/
|
||||
private Long parseFaceId(String faceId) {
|
||||
if (faceId == null || faceId.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(faceId.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
public ApiResponse<Map<String, Object>> createOrderToPrinter(@PathVariable("scenicId") Long scenicId, @PathVariable("printerId") Integer printerId) {
|
||||
return ApiResponse.success(printerService.createOrder(JwtTokenUtil.getWorker().getUserId(), scenicId, printerId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.constant.SourceType;
|
||||
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.pricing.dto.PriceCalculationRequest;
|
||||
import com.ycwl.basic.pricing.dto.PriceCalculationResult;
|
||||
import com.ycwl.basic.pricing.dto.ProductItem;
|
||||
import com.ycwl.basic.pricing.enums.ProductType;
|
||||
import com.ycwl.basic.pricing.service.IPriceCalculationService;
|
||||
import com.ycwl.basic.puzzle.entity.PuzzleGenerationRecordEntity;
|
||||
import com.ycwl.basic.puzzle.mapper.PuzzleGenerationRecordMapper;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/puzzle/v1")
|
||||
@RequiredArgsConstructor
|
||||
public class AppPuzzleController {
|
||||
|
||||
private final PuzzleGenerationRecordMapper recordMapper;
|
||||
private final FaceRepository faceRepository;
|
||||
private final IPriceCalculationService iPriceCalculationService;
|
||||
private final PrinterService printerService;
|
||||
private final OrderBiz orderBiz;
|
||||
|
||||
/**
|
||||
* 根据faceId查询三拼图数量
|
||||
*/
|
||||
@GetMapping("/count/{faceId}")
|
||||
public ApiResponse<Integer> countByFaceId(@PathVariable("faceId") Long faceId) {
|
||||
if (faceId == null) {
|
||||
return ApiResponse.fail("faceId不能为空");
|
||||
}
|
||||
int count = recordMapper.countByFaceId(faceId);
|
||||
return ApiResponse.success(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据faceId查询所有三拼图记录
|
||||
*/
|
||||
@GetMapping("/list/{faceId}")
|
||||
public ApiResponse<List<ContentPageVO>> listByFaceId(@PathVariable("faceId") Long faceId) {
|
||||
if (faceId == null) {
|
||||
return ApiResponse.fail("faceId不能为空");
|
||||
}
|
||||
List<PuzzleGenerationRecordEntity> records = recordMapper.listByFaceId(faceId);
|
||||
List<ContentPageVO> result = records.stream()
|
||||
.map(this::convertToContentPageVO)
|
||||
.collect(Collectors.toList());
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据recordId查询单个三拼图记录
|
||||
*/
|
||||
@GetMapping("/detail/{recordId}")
|
||||
public ApiResponse<ContentPageVO> getByRecordId(@PathVariable("recordId") Long recordId) {
|
||||
if (recordId == null) {
|
||||
return ApiResponse.fail("recordId不能为空");
|
||||
}
|
||||
PuzzleGenerationRecordEntity record = recordMapper.getById(recordId);
|
||||
if (record == null) {
|
||||
return ApiResponse.fail("未找到对应的拼图记录");
|
||||
}
|
||||
ContentPageVO result = convertToContentPageVO(record);
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据recordId下载拼图资源
|
||||
*/
|
||||
@GetMapping("/download/{recordId}")
|
||||
public ApiResponse<List<String>> download(@PathVariable("recordId") Long recordId) {
|
||||
if (recordId == null) {
|
||||
return ApiResponse.fail("recordId不能为空");
|
||||
}
|
||||
PuzzleGenerationRecordEntity record = recordMapper.getById(recordId);
|
||||
if (record == null) {
|
||||
return ApiResponse.fail("未找到对应的拼图记录");
|
||||
}
|
||||
String resultImageUrl = record.getResultImageUrl();
|
||||
if (resultImageUrl == null || resultImageUrl.isEmpty()) {
|
||||
return ApiResponse.fail("该拼图记录没有可用的图片URL");
|
||||
}
|
||||
return ApiResponse.success(Collections.singletonList(resultImageUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据recordId查询拼图价格
|
||||
*/
|
||||
@GetMapping("/price/{recordId}")
|
||||
public ApiResponse<PriceCalculationResult> getPriceByRecordId(@PathVariable("recordId") Long recordId) {
|
||||
if (recordId == null) {
|
||||
return ApiResponse.fail("recordId不能为空");
|
||||
}
|
||||
PuzzleGenerationRecordEntity record = recordMapper.getById(recordId);
|
||||
if (record == null) {
|
||||
return ApiResponse.fail("未找到对应的拼图记录");
|
||||
}
|
||||
FaceEntity face = faceRepository.getFace(record.getFaceId());
|
||||
if (face == null) {
|
||||
return ApiResponse.fail("未找到对应的人脸信息");
|
||||
}
|
||||
|
||||
PriceCalculationRequest calculationRequest = new PriceCalculationRequest();
|
||||
ProductItem productItem = new ProductItem();
|
||||
productItem.setProductType(ProductType.PHOTO_LOG);
|
||||
productItem.setProductId(record.getTemplateId().toString());
|
||||
productItem.setPurchaseCount(1);
|
||||
productItem.setScenicId(face.getScenicId().toString());
|
||||
calculationRequest.setProducts(Collections.singletonList(productItem));
|
||||
calculationRequest.setUserId(face.getMemberId());
|
||||
calculationRequest.setFaceId(record.getFaceId());
|
||||
calculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult calculationResult = iPriceCalculationService.calculatePrice(calculationRequest);
|
||||
|
||||
return ApiResponse.success(calculationResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将拼图导入到打印列表
|
||||
*/
|
||||
@PostMapping("/import-to-print/{recordId}")
|
||||
public ApiResponse<Integer> importToPrint(@PathVariable("recordId") Long recordId) {
|
||||
if (recordId == null) {
|
||||
return ApiResponse.fail("recordId不能为空");
|
||||
}
|
||||
|
||||
// 查询拼图记录
|
||||
PuzzleGenerationRecordEntity record = recordMapper.getById(recordId);
|
||||
if (record == null) {
|
||||
return ApiResponse.fail("未找到对应的拼图记录");
|
||||
}
|
||||
|
||||
// 检查是否有图片URL
|
||||
String resultImageUrl = record.getResultImageUrl();
|
||||
if (resultImageUrl == null || resultImageUrl.isEmpty()) {
|
||||
return ApiResponse.fail("该拼图记录没有可用的图片URL");
|
||||
}
|
||||
|
||||
// 获取人脸信息
|
||||
FaceEntity face = faceRepository.getFace(record.getFaceId());
|
||||
if (face == null) {
|
||||
return ApiResponse.fail("未找到对应的人脸信息");
|
||||
}
|
||||
|
||||
// 调用服务添加到打印列表
|
||||
Integer memberPrintId = printerService.addUserPhotoFromPuzzle(
|
||||
face.getMemberId(),
|
||||
face.getScenicId(),
|
||||
record.getFaceId(),
|
||||
resultImageUrl,
|
||||
0L // 打印特有
|
||||
);
|
||||
|
||||
if (memberPrintId == null) {
|
||||
return ApiResponse.fail("添加到打印列表失败");
|
||||
}
|
||||
|
||||
return ApiResponse.success(memberPrintId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将PuzzleGenerationRecordEntity转换为ContentPageVO
|
||||
*/
|
||||
private ContentPageVO convertToContentPageVO(PuzzleGenerationRecordEntity record) {
|
||||
ContentPageVO vo = new ContentPageVO();
|
||||
|
||||
// 内容类型为3(拼图)
|
||||
vo.setContentType(3);
|
||||
|
||||
// 源素材类型为3(拼图)
|
||||
vo.setSourceType(3);
|
||||
vo.setGroup("拼图");
|
||||
|
||||
// 只要存在记录,lockType不为0(设置为-1表示已生成)
|
||||
vo.setLockType(-1);
|
||||
|
||||
// 通过faceId填充scenicId的信息
|
||||
FaceEntity face = faceRepository.getFace(record.getFaceId());
|
||||
if (record.getFaceId() != null) {
|
||||
vo.setScenicId(face.getScenicId());
|
||||
}
|
||||
|
||||
// contentId为生成记录id
|
||||
vo.setContentId(record.getId());
|
||||
|
||||
// templateCoverUrl和生成的图是一致的
|
||||
vo.setTemplateCoverUrl(record.getResultImageUrl());
|
||||
|
||||
// 设置模板ID
|
||||
vo.setTemplateId(record.getTemplateId());
|
||||
IsBuyRespVO isBuyScenic = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), 5, face.getScenicId());
|
||||
if (isBuyScenic.isBuy()) {
|
||||
vo.setIsBuy(1);
|
||||
} else {
|
||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), 5, record.getTemplateId());
|
||||
if (isBuyRespVO.isBuy()) {
|
||||
vo.setIsBuy(1);
|
||||
} else {
|
||||
vo.setIsBuy(0);
|
||||
PriceCalculationRequest calculationRequest = new PriceCalculationRequest();
|
||||
ProductItem productItem = new ProductItem();
|
||||
productItem.setProductType(ProductType.PHOTO_LOG);
|
||||
productItem.setProductId(record.getTemplateId().toString());
|
||||
productItem.setPurchaseCount(1);
|
||||
productItem.setScenicId(face.getScenicId().toString());
|
||||
calculationRequest.setProducts(Collections.singletonList(productItem));
|
||||
calculationRequest.setUserId(face.getMemberId());
|
||||
calculationRequest.setFaceId(record.getFaceId());
|
||||
calculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult calculationResult = iPriceCalculationService.calculatePrice(calculationRequest);
|
||||
if (calculationResult.getFinalAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
vo.setFreeCount(0);
|
||||
} else {
|
||||
vo.setFreeCount(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.integration.questionnaire.dto.answer.ResponseDetailResponse;
|
||||
import com.ycwl.basic.integration.questionnaire.dto.answer.SubmitAnswerRequest;
|
||||
import com.ycwl.basic.integration.questionnaire.dto.questionnaire.QuestionnaireResponse;
|
||||
import com.ycwl.basic.integration.questionnaire.service.QuestionnaireIntegrationService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 移动端问卷接口控制器
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-05
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/questionnaire/v1")
|
||||
@RequiredArgsConstructor
|
||||
public class AppQuestionnaireController {
|
||||
|
||||
private final QuestionnaireIntegrationService questionnaireIntegrationService;
|
||||
|
||||
/**
|
||||
* 获取问卷详情
|
||||
* 包含问卷基本信息和所有题目
|
||||
*/
|
||||
@IgnoreToken
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<QuestionnaireResponse> getQuestionnaire(@PathVariable Long id) {
|
||||
log.info("移动端获取问卷详情, id: {}", id);
|
||||
try {
|
||||
QuestionnaireResponse questionnaire = questionnaireIntegrationService.getQuestionnaire(id);
|
||||
|
||||
// 检查问卷状态,只有已发布的问卷才能被移动端访问
|
||||
if (questionnaire.getStatus() != 2) {
|
||||
return ApiResponse.fail("问卷未发布或已停止");
|
||||
}
|
||||
|
||||
return ApiResponse.success(questionnaire);
|
||||
} catch (Exception e) {
|
||||
log.error("移动端获取问卷详情失败, id: {}", id, e);
|
||||
return ApiResponse.fail("获取问卷详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交问卷答案
|
||||
*/
|
||||
@PostMapping("/{id}/submit")
|
||||
public ApiResponse<ResponseDetailResponse> submitAnswer(
|
||||
@PathVariable Long id,
|
||||
@Valid @RequestBody SubmitAnswerRequest request) {
|
||||
|
||||
String userId = BaseContextHandler.getUserId();
|
||||
log.info("移动端提交问卷答案, questionnaireId: {}, userId: {}, answers count: {}",
|
||||
id, userId, request.getAnswers() != null ? request.getAnswers().size() : 0);
|
||||
|
||||
try {
|
||||
// 设置问卷ID和用户ID
|
||||
request.setQuestionnaireId(id);
|
||||
request.setUserId(userId);
|
||||
|
||||
ResponseDetailResponse response = questionnaireIntegrationService.submitAnswer(request);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("移动端提交问卷答案失败, questionnaireId: {}, userId: {}", id, userId, e);
|
||||
return ApiResponse.fail("提交问卷答案失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,12 @@ package com.ycwl.basic.controller.mobile;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
|
||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicConfigResp;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
@@ -16,14 +16,13 @@ import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.mobile.AppScenicService;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -33,9 +32,10 @@ import java.util.List;
|
||||
* @Date:2024/12/5 10:22
|
||||
*/
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/scenic/v1")
|
||||
// 景区相关接口
|
||||
@Api(tags = "景区相关接口")
|
||||
public class AppScenicController {
|
||||
|
||||
@Autowired
|
||||
@@ -48,12 +48,11 @@ public class AppScenicController {
|
||||
add("3932535453961555968");
|
||||
add("3936121342868459520");
|
||||
add("3936940597855784960");
|
||||
add("4049850382325780480");
|
||||
}};
|
||||
|
||||
// 分页查询景区列表
|
||||
@ApiOperation("分页查询景区列表")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<ScenicEntity>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery){
|
||||
public ApiResponse<PageInfo<ScenicAppVO>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery){
|
||||
String userId = BaseContextHandler.getUserId();
|
||||
if (ENABLED_USER_IDs.contains(userId)) {
|
||||
return appScenicService.pageQuery(scenicReqQuery);
|
||||
@@ -61,7 +60,7 @@ public class AppScenicController {
|
||||
return ApiResponse.success(new PageInfo<>(new ArrayList<>()));
|
||||
}
|
||||
}
|
||||
// 根据id查询景区详情
|
||||
@ApiOperation("根据id查询景区详情")
|
||||
@IgnoreToken
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<ScenicRespVO> getDetails(@PathVariable Long id){
|
||||
@@ -71,41 +70,40 @@ public class AppScenicController {
|
||||
@GetMapping("/{id}/config")
|
||||
@IgnoreToken
|
||||
public ApiResponse<ScenicConfigResp> getConfig(@PathVariable Long id){
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(id);
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(id);
|
||||
ScenicConfigResp resp = new ScenicConfigResp();
|
||||
resp.setWatermarkUrl(scenicConfig.getString("watermark_url"));
|
||||
resp.setVideoStoreDay(scenicConfig.getInteger("video_store_day"));
|
||||
resp.setAntiScreenRecordType(scenicConfig.getInteger("anti_screen_record_type"));
|
||||
resp.setGroupingEnable(scenicConfig.getBoolean("grouping_enable", false));
|
||||
resp.setVoucherEnable(scenicConfig.getBoolean("voucher_enable", false));
|
||||
resp.setShowPhotoWhenWaiting(scenicConfig.getBoolean("show_photo_when_waiting", false));
|
||||
resp.setImageSourcePackHint(scenicConfig.getString("image_source_pack_hint"));
|
||||
resp.setVideoSourcePackHint(scenicConfig.getString("video_source_pack_hint"));
|
||||
resp.setShareBeforeBuy(scenicConfig.getBoolean("share_before_buy"));
|
||||
resp.setFaceSelectFirst(scenicConfig.getBoolean("face_select_first", false));
|
||||
resp.setPrintEnableSource(scenicConfig.getBoolean("print_enable_source", true));
|
||||
resp.setPrintForceFaceUpload(scenicConfig.getBoolean("print_force_face_upload", false));
|
||||
resp.setPrintEnableManual(scenicConfig.getBoolean("print_enable_manual", true));
|
||||
resp.setSceneMode(scenicConfig.getInteger("scene_mode", 0));
|
||||
resp.setPrintEnable(scenicConfig.getBoolean("print_enable", false));
|
||||
resp.setShowMyPagePaid(scenicConfig.getBoolean("show_my_page_paid", true));
|
||||
resp.setShowMyPageUnpaid(scenicConfig.getBoolean("show_my_page_unpaid", true));
|
||||
resp.setBookRoutine(scenicConfig.getBookRoutine());
|
||||
resp.setForceFinishTime(scenicConfig.getForceFinishTime());
|
||||
resp.setTourTime(scenicConfig.getTourTime());
|
||||
resp.setSampleStoreDay(scenicConfig.getSampleStoreDay());
|
||||
resp.setFaceStoreDay(scenicConfig.getFaceStoreDay());
|
||||
resp.setVideoStoreDay(scenicConfig.getVideoStoreDay());
|
||||
resp.setAllFree(scenicConfig.getAllFree());
|
||||
resp.setDisableSourceVideo(scenicConfig.getDisableSourceVideo());
|
||||
resp.setDisableSourceImage(scenicConfig.getDisableSourceImage());
|
||||
resp.setAntiScreenRecordType(scenicConfig.getAntiScreenRecordType());
|
||||
resp.setVideoSourceStoreDay(scenicConfig.getVideoSourceStoreDay());
|
||||
resp.setImageSourceStoreDay(scenicConfig.getImageSourceStoreDay());
|
||||
resp.setUserSourceExpireDay(scenicConfig.getUserSourceExpireDay());
|
||||
resp.setBrokerDirectRate(scenicConfig.getBrokerDirectRate());
|
||||
resp.setVideoSourcePackHint(scenicConfig.getVideoSourcePackHint());
|
||||
resp.setImageSourcePackHint(scenicConfig.getImageSourcePackHint());
|
||||
return ApiResponse.success(resp);
|
||||
}
|
||||
|
||||
// 查询景区设备总数和拍到用户的机位数量
|
||||
@ApiOperation("查询景区设备总数和拍到用户的机位数量")
|
||||
@GetMapping("/{scenicId}/deviceCount/")
|
||||
public ApiResponse<ScenicDeviceCountVO> deviceCountByScenicId(@PathVariable Long scenicId){
|
||||
return appScenicService.deviceCountByScenicId(scenicId);
|
||||
}
|
||||
|
||||
// 景区视频源素材列表
|
||||
@ApiOperation("景区视频源素材列表")
|
||||
@GetMapping("/contentList/")
|
||||
public ApiResponse<List<ContentPageVO>> contentList() {
|
||||
return faceService.contentListUseDefaultFace();
|
||||
}
|
||||
|
||||
// 景区视频源素材列表
|
||||
@ApiOperation("景区视频源素材列表")
|
||||
@GetMapping("/face/{faceId}/contentList")
|
||||
public ApiResponse<List<ContentPageVO>> contentList(@PathVariable Long faceId) {
|
||||
List<ContentPageVO> contentPageVOS = faceService.faceContentList(faceId);
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.ycwl.basic.service.mobile.GoodsService;
|
||||
import com.ycwl.basic.service.task.TaskService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -45,7 +46,7 @@ public class AppTaskController {
|
||||
* @param templateId 模版id
|
||||
* @return 1 合成中 2 合成成功
|
||||
*/
|
||||
// 查询用户当前景区的具体模版视频合成任务状态 1 合成中 2 合成成功
|
||||
@ApiOperation("查询用户当前景区的具体模版视频合成任务状态 1 合成中 2 合成成功 ")
|
||||
@GetMapping("/face/{faceId}/template/{templateId}")
|
||||
@IgnoreLogReq
|
||||
public ApiResponse<VideoTaskStatusVO> getTemplateTaskStatus(@PathVariable("faceId") Long faceId, @PathVariable("templateId") Long templateId) {
|
||||
@@ -55,7 +56,7 @@ public class AppTaskController {
|
||||
|
||||
@PostMapping("/submit")
|
||||
public ApiResponse<String> submitVideoTask(@RequestBody VideoTaskReq videoTaskReq) {
|
||||
taskService.createTaskByFaceIdAndTemplateId(videoTaskReq.getFaceId(),videoTaskReq.getTemplateId(),false);
|
||||
taskService.createTaskByFaceIdAndTempalteId(videoTaskReq.getFaceId(),videoTaskReq.getTemplateId(),0);
|
||||
return ApiResponse.success("成功");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +1,23 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.model.mobile.video.dto.VideoViewPermissionDTO;
|
||||
import com.ycwl.basic.model.task.req.VideoInfoReq;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
import com.ycwl.basic.service.mobile.VideoViewPermissionService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
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.RestController;
|
||||
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/video/v1")
|
||||
public class AppVideoController {
|
||||
|
||||
@Autowired
|
||||
private VideoRepository videoRepository;
|
||||
|
||||
@Autowired
|
||||
private VideoViewPermissionService videoViewPermissionService;
|
||||
|
||||
@PostMapping("/{videoId}/updateMeta")
|
||||
public void updateMeta(@PathVariable("videoId") Long videoId, @RequestBody VideoInfoReq req) {
|
||||
videoRepository.updateMeta(videoId, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录用户查看视频并返回权限信息
|
||||
*
|
||||
* @param videoId 视频ID
|
||||
* @return 查看权限信息
|
||||
*/
|
||||
@PostMapping("/{videoId}/recordView")
|
||||
public ApiResponse<VideoViewPermissionDTO> recordView(@PathVariable("videoId") Long videoId) {
|
||||
try {
|
||||
String userIdStr = BaseContextHandler.getUserId();
|
||||
if (userIdStr == null || userIdStr.isEmpty()) {
|
||||
log.warn("用户未登录,无法记录查看: videoId={}", videoId);
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long userId = Long.valueOf(userIdStr);
|
||||
log.debug("记录用户查看视频: userId={}, videoId={}", userId, videoId);
|
||||
|
||||
VideoViewPermissionDTO permission = videoViewPermissionService.checkAndRecordView(userId, videoId);
|
||||
return ApiResponse.success(permission);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("用户ID格式错误: userId={}, videoId={}", BaseContextHandler.getUserId(), videoId, e);
|
||||
return ApiResponse.fail("用户信息无效");
|
||||
} catch (Exception e) {
|
||||
log.error("记录用户查看视频失败: videoId={}", videoId, e);
|
||||
return ApiResponse.fail("记录查看失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户查看权限(不记录查看次数)
|
||||
*
|
||||
* @param videoId 视频ID
|
||||
* @return 查看权限信息
|
||||
*/
|
||||
@GetMapping("/{videoId}/checkPermission")
|
||||
public ApiResponse<VideoViewPermissionDTO> checkPermission(@PathVariable("videoId") Long videoId) {
|
||||
try {
|
||||
String userIdStr = BaseContextHandler.getUserId();
|
||||
if (userIdStr == null || userIdStr.isEmpty()) {
|
||||
log.warn("用户未登录,无法查看权限: videoId={}", videoId);
|
||||
return ApiResponse.fail("用户未登录");
|
||||
}
|
||||
|
||||
Long userId = Long.valueOf(userIdStr);
|
||||
log.debug("检查用户查看权限: userId={}, videoId={}", userId, videoId);
|
||||
|
||||
VideoViewPermissionDTO permission = videoViewPermissionService.checkViewPermission(userId, videoId);
|
||||
return ApiResponse.success(permission);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("用户ID格式错误: userId={}, videoId={}", BaseContextHandler.getUserId(), videoId, e);
|
||||
return ApiResponse.fail("用户信息无效");
|
||||
} catch (Exception e) {
|
||||
log.error("检查用户查看权限失败: videoId={}", videoId, e);
|
||||
return ApiResponse.fail("权限检查失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.exception.BaseException;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.pricing.dto.req.VoucherClaimReq;
|
||||
import com.ycwl.basic.pricing.dto.req.VoucherPrintReq;
|
||||
import com.ycwl.basic.pricing.dto.resp.VoucherCodeResp;
|
||||
import com.ycwl.basic.pricing.dto.resp.VoucherPrintResp;
|
||||
import com.ycwl.basic.pricing.service.VoucherCodeService;
|
||||
import com.ycwl.basic.pricing.service.VoucherPrintService;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
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.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;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/voucher/v1")
|
||||
public class AppVoucherController {
|
||||
|
||||
@Autowired
|
||||
private VoucherPrintService voucherPrintService;
|
||||
@Autowired
|
||||
private VoucherCodeService voucherCodeService;
|
||||
@Autowired
|
||||
private FaceRepository faceRepository;
|
||||
|
||||
/**
|
||||
* 打印小票
|
||||
* @param request 打印请求
|
||||
* @return 打印结果
|
||||
*/
|
||||
@PostMapping("/print")
|
||||
public ApiResponse<VoucherPrintResp> printVoucherTicket(@RequestBody VoucherPrintReq request) {
|
||||
log.info("收到打印小票请求: faceId={}, brokerId={}, scenicId={}",
|
||||
request.getFaceId(), request.getBrokerId(), request.getScenicId());
|
||||
|
||||
VoucherPrintResp response = voucherPrintService.printVoucherTicket(request);
|
||||
|
||||
log.info("打印小票完成: code={}, voucherCode={}, status={}",
|
||||
response.getCode(), response.getVoucherCode(), response.getPrintStatus());
|
||||
|
||||
return ApiResponse.success(response);
|
||||
}
|
||||
|
||||
@GetMapping("/printed")
|
||||
public ApiResponse<VoucherPrintResp> queryPrintedVoucher(
|
||||
@RequestParam Long faceId
|
||||
) {
|
||||
return ApiResponse.success(voucherPrintService.queryPrintedVoucher(faceId));
|
||||
}
|
||||
|
||||
@PostMapping("/claim")
|
||||
public ApiResponse<VoucherCodeResp> claimVoucher(@RequestBody VoucherClaimReq req) {
|
||||
FaceEntity face = faceRepository.getFace(req.getFaceId());
|
||||
if (face == null) {
|
||||
throw new BaseException("请选择人脸");
|
||||
}
|
||||
req.setScenicId(face.getScenicId());
|
||||
VoucherCodeResp result = voucherCodeService.claimVoucher(req);
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.ycwl.basic.controller.mobile;
|
||||
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: songmingsong
|
||||
* @CreateTime: 2024-12-06
|
||||
* @Description: 微信消息模板通知
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/wx/notify/v1")
|
||||
@Api(tags = "微信消息模板通知")
|
||||
public class AppWxNotifyController {
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
//
|
||||
// @ApiOperation(value = "通知", notes = "通知")
|
||||
// @PostMapping("/pushMessage")
|
||||
// @IgnoreToken
|
||||
// public ApiResponse<?> pushMessage(@RequestBody WechatMessageSubscribeForm req) {
|
||||
// JSONObject resJson = wxNotifyService.pushMessage(req);
|
||||
// return ApiResponse.success(resJson);
|
||||
// }
|
||||
|
||||
@GetMapping({"/getIds", "/"})
|
||||
@IgnoreToken
|
||||
public ApiResponse<List<String>> getIds() {
|
||||
return ApiResponse.success(new ArrayList<>() {{
|
||||
add("5b8vTm7kvwYubqDxb3dxBs0BqxMsgVgGw573aahTEd8");
|
||||
add("vPIzbkA0x4mMj-vdbWx6_45e8juWXzs3FGYnDsIPv3A");
|
||||
add("HB1vp-0BXc2WyYeoYN3a3GuZV9HtPLXUTT7blCBq9eY");
|
||||
}});
|
||||
}
|
||||
|
||||
@GetMapping("/{scenicId}")
|
||||
@IgnoreToken
|
||||
public ApiResponse<List<String>> getIds(@PathVariable("scenicId") Long scenicId) {
|
||||
return ApiResponse.success(new ArrayList<>() {{
|
||||
String videoGeneratedTemplateId = scenicRepository.getVideoGeneratedTemplateId(scenicId);
|
||||
if (StringUtils.isNotBlank(videoGeneratedTemplateId)) {
|
||||
add(videoGeneratedTemplateId);
|
||||
}
|
||||
String videoDownloadTemplateId = scenicRepository.getVideoDownloadTemplateId(scenicId);
|
||||
if (StringUtils.isNotBlank(videoDownloadTemplateId)) {
|
||||
add(videoDownloadTemplateId);
|
||||
}
|
||||
String videoPreExpireTemplateId = scenicRepository.getVideoPreExpireTemplateId(scenicId);
|
||||
if (StringUtils.isNotBlank(videoPreExpireTemplateId)) {
|
||||
add(videoPreExpireTemplateId);
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import com.ycwl.basic.model.wx.WxPayRespVO;
|
||||
import com.ycwl.basic.pay.entity.PayResponse;
|
||||
import com.ycwl.basic.service.mobile.WxPayService;
|
||||
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.PathVariable;
|
||||
@@ -29,13 +31,13 @@ import java.security.GeneralSecurityException;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/wx/pay/v1")
|
||||
// 微信支付相关接口
|
||||
@Api(tags = "微信支付相关接口")
|
||||
public class AppWxPayController {
|
||||
|
||||
@Autowired
|
||||
private WxPayService wxPayService;
|
||||
|
||||
// 微信支付回调
|
||||
@ApiOperation(value = "微信支付回调", notes = "微信支付回调")
|
||||
@PostMapping("/payNotify")
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> payNotify(HttpServletRequest request) {
|
||||
@@ -56,7 +58,7 @@ public class AppWxPayController {
|
||||
return ApiResponse.success(BizCodeEnum.REQUEST_OK);
|
||||
}
|
||||
|
||||
// 微信支付退款回调
|
||||
@ApiOperation(value = "微信支付退款回调", notes = "微信支付退款回调")
|
||||
@PostMapping("/{scenicId}/refundNotify")
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> refundNotify(@PathVariable Long scenicId, HttpServletRequest request) throws GeneralSecurityException, IOException {
|
||||
|
||||
@@ -2,23 +2,21 @@ package com.ycwl.basic.controller.mobile.manage;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
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.scenic.account.ScenicRegisterReq;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicRegisterRespVO;
|
||||
import com.ycwl.basic.model.mobile.weChat.DTO.WeChatUserInfoDTO;
|
||||
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.ScenicRepository;
|
||||
import com.ycwl.basic.service.mobile.AppScenicService;
|
||||
import com.ycwl.basic.service.pc.ScenicAccountService;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import org.apache.commons.lang3.Strings;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -27,10 +25,10 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.ADMIN;
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
|
||||
/**
|
||||
@@ -39,7 +37,7 @@ import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/scenicAccount/v1")
|
||||
// 景区账号相关接口
|
||||
@Api(tags = "景区账号相关接口")
|
||||
public class AppScenicAccountController {
|
||||
@Autowired
|
||||
private ScenicAccountService accountService;
|
||||
@@ -47,51 +45,28 @@ public class AppScenicAccountController {
|
||||
private AppScenicService scenicService;
|
||||
@Autowired
|
||||
private ScenicService adminScenicService;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
// 登录
|
||||
@ApiOperation("登录")
|
||||
@PostMapping("/login")
|
||||
@IgnoreToken
|
||||
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);
|
||||
}
|
||||
|
||||
// 注册
|
||||
@PostMapping("/register")
|
||||
@IgnoreToken
|
||||
public ApiResponse<ScenicRegisterRespVO> register(@RequestBody ScenicRegisterReq scenicRegisterReq) {
|
||||
return scenicService.register(scenicRegisterReq);
|
||||
public ApiResponse<ScenicLoginRespVO> login(@RequestBody ScenicLoginReq scenicLoginReq) throws Exception {
|
||||
return scenicService.login(scenicLoginReq);
|
||||
}
|
||||
|
||||
@GetMapping("/myScenicList")
|
||||
public ApiResponse<List<ScenicV2DTO>> myScenicList() {
|
||||
List<ScenicV2DTO> list = Collections.emptyList();
|
||||
if (Strings.CS.equals(BaseContextHandler.getRoleId(), MERCHANT.type)) {
|
||||
public ApiResponse<List<ScenicRespVO>> myScenicList() {
|
||||
List<ScenicRespVO> list = Collections.emptyList();
|
||||
if (StringUtils.equals(BaseContextHandler.getRoleId(), MERCHANT.type)) {
|
||||
String userId = BaseContextHandler.getUserId();
|
||||
ScenicAccountEntity account = accountService.getScenicAccountById(Long.valueOf(userId));
|
||||
if (account == null || account.getScenicId().isEmpty()) {
|
||||
return ApiResponse.fail("景区账号未绑定景区");
|
||||
}
|
||||
list = account.getScenicId().stream()
|
||||
.map(id -> scenicRepository.getScenicBasic(id))
|
||||
.toList();
|
||||
} else if (Strings.CS.equals(BaseContextHandler.getRoleId(), ADMIN.type)) {
|
||||
ScenicReqQuery query = new ScenicReqQuery();
|
||||
query.setPageSize(1000);
|
||||
list = scenicRepository.list(query);
|
||||
list = account.getScenicId().stream().map(id -> {
|
||||
return scenicService.getDetails(id).getData();
|
||||
}).toList();
|
||||
} else {
|
||||
list = adminScenicService.list(new ScenicReqQuery()).getData();
|
||||
}
|
||||
return ApiResponse.success(list);
|
||||
}
|
||||
@@ -120,7 +95,6 @@ public class AppScenicAccountController {
|
||||
}
|
||||
|
||||
@GetMapping("/devices")
|
||||
@Deprecated
|
||||
public ApiResponse<List<DeviceRespVO>> getDeviceList() {
|
||||
String userId = BaseContextHandler.getUserId();
|
||||
ScenicAccountEntity account = accountService.getScenicAccountById(Long.valueOf(userId));
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.service.pc.ScenicAccountService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -20,7 +21,7 @@ import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/scenic/order/v1")
|
||||
// 景区账号相关接口
|
||||
@Api(tags = "景区账号相关接口")
|
||||
public class AppScenicOrderController {
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
@@ -11,6 +11,8 @@ import com.ycwl.basic.model.mobile.statistic.resp.AppStatisticsFunnelVO;
|
||||
import com.ycwl.basic.service.mobile.AppStatisticsService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -22,38 +24,46 @@ import org.springframework.web.bind.annotation.*;
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/statistics/v1")
|
||||
// 数据统计相关接口
|
||||
@Api(tags = "数据统计相关接口")
|
||||
public class AppStatisticsController {
|
||||
|
||||
@Autowired
|
||||
private AppStatisticsService statisticsService;
|
||||
|
||||
// 支付订单金额、预览_支付转化率、扫码_付费用户转化率
|
||||
@ApiOperation("支付订单金额、预览_支付转化率、扫码_付费用户转化率")
|
||||
@PostMapping("/one")
|
||||
public ApiResponse<AppSta1VO> oneStatistics(@RequestBody CommonQueryReq query) {
|
||||
|
||||
return statisticsService.oneStatistics(query);
|
||||
}
|
||||
|
||||
// 支付订单数、现场订单数、推送订单数统计
|
||||
@ApiOperation("支付订单数、现场订单数、推送订单数统计")
|
||||
@PostMapping("/two")
|
||||
public ApiResponse<AppSta2VO> twoStatistics(@RequestBody CommonQueryReq query) {
|
||||
|
||||
return statisticsService.twoStatistics(query);
|
||||
}
|
||||
|
||||
// 扫码访问人数、推送订阅人数、预览视频人数统计
|
||||
@ApiOperation("扫码访问人数、推送订阅人数、预览视频人数统计")
|
||||
@PostMapping("/free")
|
||||
public ApiResponse<AppSta3VO> freeStatistics(@RequestBody CommonQueryReq query) {
|
||||
|
||||
return statisticsService.freeStatistics(query);
|
||||
}
|
||||
|
||||
// 用户转化漏斗
|
||||
@ApiOperation("用户转化漏斗")
|
||||
@PostMapping("/userConversionFunnel")
|
||||
public ApiResponse<AppStatisticsFunnelVO> userConversionFunnel(@RequestBody CommonQueryReq query) {
|
||||
|
||||
return statisticsService.userConversionFunnel(query);
|
||||
}
|
||||
|
||||
@ApiOperation("统计数据记录")
|
||||
@PostMapping("/addStatistics")
|
||||
@IgnoreToken
|
||||
public ApiResponse<String> addStatistics(@RequestBody StatisticsRecordAddReq req) {
|
||||
|
||||
return statisticsService.addStatistics(req);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
package com.ycwl.basic.controller.mobile.notify;
|
||||
|
||||
import com.ycwl.basic.model.mobile.notify.req.NotificationAuthRecordReq;
|
||||
import com.ycwl.basic.model.mobile.notify.resp.NotificationAuthRecordResp;
|
||||
import com.ycwl.basic.model.mobile.notify.resp.ScenicTemplateAuthResp;
|
||||
import com.ycwl.basic.service.UserNotificationAuthorizationService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户通知授权记录Controller (移动端API)
|
||||
* 只提供用户主动授权记录功能,支持批量授权,其他检查和消费功能由系统内部调用
|
||||
*
|
||||
* @Author: System
|
||||
* @Date: 2024/12/28
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mobile/notify/auth")
|
||||
@Slf4j
|
||||
public class UserNotificationAuthController {
|
||||
|
||||
@Autowired
|
||||
private UserNotificationAuthorizationService userNotificationAuthorizationService;
|
||||
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
/**
|
||||
* 记录用户通知授权 - 支持批量授权
|
||||
* 用户主动同意通知授权时调用
|
||||
*/
|
||||
@PostMapping("/record")
|
||||
public ApiResponse<NotificationAuthRecordResp> recordAuthorization(
|
||||
@RequestBody NotificationAuthRecordReq req) {
|
||||
log.debug("记录用户通知授权: templateIds={}, scenicId={}", req.getTemplateIds(), req.getScenicId());
|
||||
|
||||
try {
|
||||
// 获取当前用户ID
|
||||
Long memberId = JwtTokenUtil.getWorker().getUserId();
|
||||
|
||||
// 调用批量授权记录方法
|
||||
List<UserNotificationAuthorizationService.AuthorizationRecord> records =
|
||||
userNotificationAuthorizationService.batchRecordAuthorization(
|
||||
memberId, req.getTemplateIds(), req.getScenicId());
|
||||
|
||||
NotificationAuthRecordResp resp = new NotificationAuthRecordResp();
|
||||
|
||||
// 转换响应数据
|
||||
List<NotificationAuthRecordResp.AuthorizationRecord> successRecords = new ArrayList<>();
|
||||
List<String> failedTemplateIds = new ArrayList<>();
|
||||
List<String> failureReasons = new ArrayList<>();
|
||||
|
||||
for (UserNotificationAuthorizationService.AuthorizationRecord record : records) {
|
||||
if (record.isSuccess()) {
|
||||
NotificationAuthRecordResp.AuthorizationRecord successRecord =
|
||||
new NotificationAuthRecordResp.AuthorizationRecord();
|
||||
successRecord.setId(record.getId());
|
||||
successRecord.setTemplateId(record.getTemplateId());
|
||||
successRecord.setScenicId(record.getScenicId());
|
||||
successRecord.setAuthorizationCount(record.getAuthorizationCount());
|
||||
successRecord.setConsumedCount(record.getConsumedCount());
|
||||
successRecord.setRemainingCount(record.getRemainingCount());
|
||||
successRecord.setLastAuthorizedTime(record.getLastAuthorizedTime());
|
||||
successRecord.setLastConsumedTime(record.getLastConsumedTime());
|
||||
successRecord.setStatus(record.getStatus());
|
||||
successRecord.setCreateTime(record.getCreateTime());
|
||||
successRecords.add(successRecord);
|
||||
} else {
|
||||
failedTemplateIds.add(record.getTemplateId());
|
||||
failureReasons.add(record.getFailureReason());
|
||||
}
|
||||
}
|
||||
|
||||
resp.setAllSuccess(CollectionUtils.isEmpty(failedTemplateIds));
|
||||
resp.setSuccessRecords(successRecords);
|
||||
resp.setFailedTemplateIds(failedTemplateIds);
|
||||
resp.setFailureReasons(failureReasons);
|
||||
|
||||
return ApiResponse.success(resp);
|
||||
} catch (Exception e) {
|
||||
log.error("记录用户通知授权失败", e);
|
||||
return ApiResponse.fail("记录授权失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取景区通知模板ID及用户授权余额
|
||||
* 复制AppWxNotifyController中的逻辑,并额外返回用户对应的授权余额
|
||||
*/
|
||||
@GetMapping("/{scenicId}/templates")
|
||||
public ApiResponse<ScenicTemplateAuthResp> getScenicTemplatesWithAuth(@PathVariable("scenicId") Long scenicId) {
|
||||
log.debug("获取景区通知模板ID及用户授权余额: scenicId={}", scenicId);
|
||||
|
||||
try {
|
||||
// 获取当前用户ID
|
||||
Long memberId = JwtTokenUtil.getWorker().getUserId();
|
||||
|
||||
// 获取景区的所有模板ID(复制自AppWxNotifyController的逻辑)
|
||||
List<String> templateIds = new ArrayList<>() {{
|
||||
String videoGeneratedTemplateId = scenicRepository.getVideoGeneratedTemplateId(scenicId);
|
||||
if (StringUtils.isNotBlank(videoGeneratedTemplateId)) {
|
||||
add(videoGeneratedTemplateId);
|
||||
}
|
||||
String videoDownloadTemplateId = scenicRepository.getVideoDownloadTemplateId(scenicId);
|
||||
if (StringUtils.isNotBlank(videoDownloadTemplateId)) {
|
||||
add(videoDownloadTemplateId);
|
||||
}
|
||||
String videoPreExpireTemplateId = scenicRepository.getVideoPreExpireTemplateId(scenicId);
|
||||
if (StringUtils.isNotBlank(videoPreExpireTemplateId)) {
|
||||
add(videoPreExpireTemplateId);
|
||||
}
|
||||
}};
|
||||
|
||||
// 构建响应对象
|
||||
ScenicTemplateAuthResp resp = new ScenicTemplateAuthResp();
|
||||
resp.setScenicId(scenicId);
|
||||
|
||||
// 查询每个模板的授权余额信息
|
||||
List<ScenicTemplateAuthResp.TemplateAuthInfo> templateAuthInfos = new ArrayList<>();
|
||||
for (String templateId : templateIds) {
|
||||
ScenicTemplateAuthResp.TemplateAuthInfo templateAuthInfo =
|
||||
new ScenicTemplateAuthResp.TemplateAuthInfo();
|
||||
templateAuthInfo.setTemplateId(templateId);
|
||||
|
||||
if (templateId.equals(scenicRepository.getVideoGeneratedTemplateId(scenicId))) {
|
||||
templateAuthInfo.setTitle("视频生成通知");
|
||||
templateAuthInfo.setDescription("当视频生成完成时,我们将提醒您");
|
||||
} else if (templateId.equals(scenicRepository.getVideoDownloadTemplateId(scenicId))) {
|
||||
templateAuthInfo.setTitle("视频下载通知");
|
||||
templateAuthInfo.setDescription("当您的视频未购买时,我们将提醒您");
|
||||
} else if (templateId.equals(scenicRepository.getVideoPreExpireTemplateId(scenicId))) {
|
||||
templateAuthInfo.setTitle("视频即将过期通知");
|
||||
templateAuthInfo.setDescription("当您的视频即将过期时,我们将提醒您及时下载");
|
||||
} else {
|
||||
templateAuthInfo.setTitle("未知模板类型");
|
||||
templateAuthInfo.setDescription("未知的模板类型");
|
||||
}
|
||||
|
||||
// 获取授权详情
|
||||
try {
|
||||
com.ycwl.basic.model.pc.notify.entity.UserNotificationAuthorizationEntity authEntity =
|
||||
userNotificationAuthorizationService.checkAuthorization(memberId, templateId, scenicId);
|
||||
|
||||
if (authEntity != null) {
|
||||
templateAuthInfo.setAuthorizationCount(authEntity.getAuthorizationCount());
|
||||
templateAuthInfo.setConsumedCount(authEntity.getConsumedCount());
|
||||
templateAuthInfo.setRemainingCount(authEntity.getRemainingCount());
|
||||
templateAuthInfo.setHasAuthorization(authEntity.getRemainingCount() != null && authEntity.getRemainingCount() > 0);
|
||||
} else {
|
||||
// 没有授权记录
|
||||
templateAuthInfo.setAuthorizationCount(0);
|
||||
templateAuthInfo.setConsumedCount(0);
|
||||
templateAuthInfo.setRemainingCount(0);
|
||||
templateAuthInfo.setHasAuthorization(false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("获取模板授权信息失败: templateId={}, scenicId={}, memberId={}, error={}",
|
||||
templateId, scenicId, memberId, e.getMessage());
|
||||
|
||||
// 获取失败时设置为无授权
|
||||
templateAuthInfo.setAuthorizationCount(0);
|
||||
templateAuthInfo.setConsumedCount(0);
|
||||
templateAuthInfo.setRemainingCount(0);
|
||||
templateAuthInfo.setHasAuthorization(false);
|
||||
}
|
||||
|
||||
templateAuthInfos.add(templateAuthInfo);
|
||||
}
|
||||
|
||||
resp.setTemplates(templateAuthInfos);
|
||||
|
||||
log.debug("成功获取景区通知模板ID及用户授权余额: scenicId={}, templateCount={}, memberId={}",
|
||||
scenicId, templateIds.size(), memberId);
|
||||
|
||||
return ApiResponse.success(resp);
|
||||
} catch (Exception e) {
|
||||
log.error("获取景区通知模板ID及用户授权余额失败: scenicId={}", scenicId, e);
|
||||
return ApiResponse.fail("获取授权信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.ycwl.basic.controller.monitor;
|
||||
|
||||
import com.ycwl.basic.integration.kafka.scheduler.AccountFaceSchedulerManager;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 人脸识别监控接口
|
||||
* 提供调度器状态查询功能
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/monitor/face-recognition")
|
||||
@RequiredArgsConstructor
|
||||
public class FaceRecognitionMonitorController {
|
||||
|
||||
private final AccountFaceSchedulerManager schedulerManager;
|
||||
|
||||
/**
|
||||
* 获取所有账号的调度器统计信息
|
||||
* <p>
|
||||
* 示例返回:
|
||||
* {
|
||||
* "LTAI5xxx": {
|
||||
* "accountKey": "LTAI5xxx",
|
||||
* "cloudType": "ALI",
|
||||
* "activeThreads": 3,
|
||||
* "executorQueueSize": 12,
|
||||
* "schedulerQueueSize": 45
|
||||
* },
|
||||
* "245xxx": {
|
||||
* "accountKey": "245xxx",
|
||||
* "cloudType": "BAIDU",
|
||||
* "activeThreads": 8,
|
||||
* "executorQueueSize": 5,
|
||||
* "schedulerQueueSize": 20
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return 所有账号的调度器状态
|
||||
*/
|
||||
@GetMapping("/schedulers")
|
||||
public ApiResponse<Map<String, AccountFaceSchedulerManager.AccountSchedulerStats>> getAllSchedulerStats() {
|
||||
return ApiResponse.success(schedulerManager.getAllStats());
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import com.ycwl.basic.model.pc.adminUser.resp.AdminUserListRespVO;
|
||||
import com.ycwl.basic.model.pc.adminUser.resp.StaffSimpleInfoRespVO;
|
||||
import com.ycwl.basic.service.pc.AdminUserService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -17,7 +19,7 @@ import java.util.List;
|
||||
@RestController
|
||||
@RequestMapping("/api/adminUser/v1")
|
||||
@Slf4j
|
||||
// 系统后台用户管理
|
||||
@Api(tags = "系统后台用户管理")
|
||||
public class AdminUserController {
|
||||
|
||||
@Autowired
|
||||
@@ -25,7 +27,7 @@ public class AdminUserController {
|
||||
|
||||
|
||||
@PostMapping(value = "/login")
|
||||
// 登录
|
||||
@ApiOperation(value = "登录")
|
||||
@IgnoreToken
|
||||
public ApiResponse login(@RequestBody LoginReqVO loginReqVO) throws Exception {
|
||||
log.info("{}:开始登录管理后台", loginReqVO.getAccount());
|
||||
@@ -33,49 +35,49 @@ public class AdminUserController {
|
||||
}
|
||||
|
||||
@PostMapping(value = "/updatePassword")
|
||||
// 用户自己修改密码
|
||||
@ApiOperation(value = "用户自己修改密码")
|
||||
public ApiResponse updatePassword(@RequestBody UpdatePasswordReqVO updatePasswordReqVO) throws Exception {
|
||||
log.info("{}:开始修改管理后台密码", updatePasswordReqVO.getId());
|
||||
return adminUserService.updatePassword(updatePasswordReqVO);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/list")
|
||||
// 系统后台用户列表
|
||||
@ApiOperation(value = "系统后台用户列表")
|
||||
//@IgnoreToken
|
||||
public ApiResponse<PageInfo<List<AdminUserListRespVO>>> list(@RequestBody AdminUserListReqVO adminUserListReqVO) {
|
||||
return adminUserService.list(adminUserListReqVO);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/query/list")
|
||||
// 系统后台用户列表查询
|
||||
@ApiOperation(value = "系统后台用户列表查询")
|
||||
@IgnoreToken
|
||||
public ApiResponse<PageInfo<List<AdminUserListRespVO>>> queryList(@RequestBody AdminUserListReqVO adminUserListReqVO) {
|
||||
return adminUserService.list(adminUserListReqVO);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/add")
|
||||
// 添加系统后台用户
|
||||
@ApiOperation(value = "添加系统后台用户")
|
||||
//@IgnoreToken
|
||||
public ApiResponse add(@RequestBody AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO) {
|
||||
return adminUserService.addOrUpdate(addOrUpdateAdminUserReqVO);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/update")
|
||||
// 更新系统后台用户
|
||||
@ApiOperation(value = "更新系统后台用户")
|
||||
//@IgnoreToken
|
||||
public ApiResponse update(@RequestBody AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO) {
|
||||
return adminUserService.addOrUpdate(addOrUpdateAdminUserReqVO);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/delete/{id}")
|
||||
// 删除
|
||||
@ApiOperation(value = "删除")
|
||||
//@IgnoreToken
|
||||
public ApiResponse delete(@PathVariable("id") String id) {
|
||||
return adminUserService.delete(id);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/resetPassword")
|
||||
// 重置密码
|
||||
@ApiOperation(value = "重置密码")
|
||||
//@IgnoreToken
|
||||
public ApiResponse resetPassword(@RequestBody ResetPasswordReqVO resetPasswordReqVO) {
|
||||
log.info("{}:开始重置后台密码", resetPasswordReqVO.getId());
|
||||
|
||||
@@ -14,6 +14,8 @@ import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -28,7 +30,7 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/broker/v1")
|
||||
// 推客(推广人)管理
|
||||
@Api(tags = "推客(推广人)管理")
|
||||
public class BrokerController {
|
||||
@Autowired
|
||||
private BrokerService brokerService;
|
||||
@@ -39,64 +41,64 @@ public class BrokerController {
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
// 分页查询
|
||||
@ApiOperation("分页查询")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse page(@RequestBody BrokerReqQuery brokerReqQuery){
|
||||
return ApiResponse.success(brokerService.pageQuery(brokerReqQuery));
|
||||
}
|
||||
|
||||
// 列表查询
|
||||
@ApiOperation("列表查询")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse list(@RequestBody BrokerReqQuery brokerReqQuery){
|
||||
return ApiResponse.success(brokerService.list(brokerReqQuery));
|
||||
}
|
||||
|
||||
// 详情查询
|
||||
@ApiOperation("详情查询")
|
||||
@GetMapping("/getDetails/{id}")
|
||||
public ApiResponse getDetails(@PathVariable("id") Long id){
|
||||
return ApiResponse.success(brokerService.getById(id));
|
||||
}
|
||||
// 新增或修改
|
||||
@ApiOperation("新增或修改")
|
||||
@PostMapping("/addOrUpdate")
|
||||
public ApiResponse addOrUpdate(@RequestBody BrokerEntity broker){
|
||||
return ApiResponse.success(brokerService.addOrUpdate(broker));
|
||||
}
|
||||
// 删除
|
||||
@ApiOperation("删除")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse delete(@PathVariable("id") Long id){
|
||||
return ApiResponse.success(brokerService.delete(id));
|
||||
}
|
||||
// 修改状态
|
||||
@ApiOperation("修改状态")
|
||||
@PutMapping("/updateStatus/{id}")
|
||||
public ApiResponse updateStatus(@PathVariable("id") Long id){
|
||||
return ApiResponse.success(brokerService.updateStatus(id));
|
||||
}
|
||||
|
||||
// 修改状态
|
||||
@ApiOperation("修改状态")
|
||||
@PutMapping("/updateBrokerEnable/{id}")
|
||||
public ApiResponse updateBrokerEnable(@PathVariable("id") Long id){
|
||||
return ApiResponse.success(brokerService.updateBrokerEnable(id));
|
||||
}
|
||||
|
||||
// 推客记录分页查询
|
||||
@ApiOperation("推客记录分页查询")
|
||||
@PostMapping("/record/page")
|
||||
public ApiResponse pageRecord(@RequestBody BrokerRecordReqQuery brokerRecordReqQuery) {
|
||||
return ApiResponse.success(brokerRecordService.pageQuery(brokerRecordReqQuery));
|
||||
}
|
||||
|
||||
// 推客记录列表查询
|
||||
@ApiOperation("推客记录列表查询")
|
||||
@PostMapping("/record/list")
|
||||
public ApiResponse listRecord(@RequestBody BrokerRecordReqQuery brokerRecordReqQuery) {
|
||||
return ApiResponse.success(brokerRecordService.list(brokerRecordReqQuery));
|
||||
}
|
||||
|
||||
// 推客记录详情查询
|
||||
@ApiOperation("推客记录详情查询")
|
||||
@GetMapping("/record/getDetails/{id}")
|
||||
public ApiResponse getRecordDetails(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(brokerRecordService.getById(id));
|
||||
}
|
||||
|
||||
// 根据brokerId和时间范围查询每天的记录数量和orderPrice汇总
|
||||
@ApiOperation("根据brokerId和时间范围查询每天的记录数量和orderPrice汇总")
|
||||
@GetMapping("/{id}/record/summary")
|
||||
public ApiResponse<List<DailySummaryRespVO>> getDailySummaryByBrokerId(
|
||||
@PathVariable("id") Long brokerId,
|
||||
@@ -105,7 +107,7 @@ public class BrokerController {
|
||||
return ApiResponse.success(brokerRecordService.getDailySummaryByBrokerId(brokerId, startTime, endTime));
|
||||
}
|
||||
|
||||
// 根据景区ID下载小程序二维码
|
||||
@ApiOperation("根据景区ID下载小程序二维码")
|
||||
@GetMapping("/{id}/QRCode")
|
||||
public ApiResponse<String> downloadQrCode(@PathVariable Long id) {
|
||||
BrokerRespVO broker = brokerService.getById(id);
|
||||
|
||||
@@ -8,6 +8,8 @@ import com.ycwl.basic.model.pc.coupon.resp.CouponRespVO;
|
||||
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
|
||||
import com.ycwl.basic.service.pc.CouponService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -15,7 +17,7 @@ import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/coupon/v1")
|
||||
// 优惠券管理
|
||||
@Api(tags = "优惠券管理")
|
||||
public class CouponController {
|
||||
@Autowired
|
||||
private CouponService couponService;
|
||||
@@ -25,17 +27,17 @@ public class CouponController {
|
||||
@GetMapping("/{scenicId}/goodsList")
|
||||
public ApiResponse<List<GoodsListRespVO>> scenicGoodsList(@PathVariable Long scenicId) {
|
||||
List<GoodsListRespVO> data = priceBiz.listGoodsByScenic(scenicId);
|
||||
data.add(new GoodsListRespVO(-1L, "一口价", -1));
|
||||
data.add(new GoodsListRespVO(-1L, "一口价"));
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
// 新增优惠券
|
||||
@ApiOperation("新增优惠券")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<Integer> add(@RequestBody CouponEntity coupon) {
|
||||
return ApiResponse.success(couponService.add(coupon));
|
||||
}
|
||||
|
||||
// 更新优惠券
|
||||
@ApiOperation("更新优惠券")
|
||||
@PostMapping("/update/{id}")
|
||||
public ApiResponse<Boolean> update(@PathVariable Integer id, @RequestBody CouponEntity coupon) {
|
||||
coupon.setId(id);
|
||||
@@ -47,19 +49,19 @@ public class CouponController {
|
||||
return ApiResponse.success(couponService.updateStatus(id));
|
||||
}
|
||||
|
||||
// 删除优惠券
|
||||
@ApiOperation("删除优惠券")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse<Boolean> delete(@PathVariable Integer id) {
|
||||
return ApiResponse.success(couponService.delete(id));
|
||||
}
|
||||
|
||||
// 根据ID查询优惠券
|
||||
@ApiOperation("根据ID查询优惠券")
|
||||
@GetMapping("/get/{id}")
|
||||
public ApiResponse<CouponEntity> getById(@PathVariable Integer id) {
|
||||
return ApiResponse.success(couponService.getById(id));
|
||||
}
|
||||
|
||||
// 分页查询优惠券列表
|
||||
@ApiOperation("分页查询优惠券列表")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<CouponRespVO>> list(@RequestBody CouponQueryReq couponQuery) {
|
||||
PageHelper.startPage(couponQuery.getPageNum(), couponQuery.getPageSize());
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.model.pc.couponRecord.req.CouponRecordPageQueryReq;
|
||||
import com.ycwl.basic.model.pc.couponRecord.resp.CouponRecordPageResp;
|
||||
import com.ycwl.basic.service.pc.CouponRecordService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/coupon/record/v1")
|
||||
public class CouponRecordController {
|
||||
|
||||
@Autowired
|
||||
private CouponRecordService couponRecordService;
|
||||
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<CouponRecordPageResp>> pageQuery(@RequestBody CouponRecordPageQueryReq query) {
|
||||
return couponRecordService.pageQuery(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.device.req.DeviceAddOrUpdateReq;
|
||||
import com.ycwl.basic.model.pc.device.req.DeviceBatchSortRequest;
|
||||
import com.ycwl.basic.model.pc.device.req.DeviceReqQuery;
|
||||
import com.ycwl.basic.model.pc.device.req.DeviceSortRequest;
|
||||
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
||||
import com.ycwl.basic.model.pc.template.req.TemplateSortRequest;
|
||||
import com.ycwl.basic.service.pc.DeviceService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/2 16:13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/device/v1")
|
||||
@Api(tags = "设备管理")
|
||||
public class DeviceController {
|
||||
@Autowired
|
||||
private DeviceService deviceService;
|
||||
|
||||
@ApiOperation("设备分页查询")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<DeviceRespVO>> pageQuery(@RequestBody DeviceReqQuery deviceReqQuery) {
|
||||
return deviceService.pageQuery(deviceReqQuery);
|
||||
}
|
||||
@ApiOperation("设备列表查询")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse list(@RequestBody DeviceReqQuery deviceReqQuery) {
|
||||
return deviceService.list(deviceReqQuery);
|
||||
}
|
||||
@ApiOperation("设备详情查询")
|
||||
@GetMapping("/getDetails/{id}")
|
||||
public ApiResponse<DeviceRespVO> getDetails(@PathVariable("id") Long id) {
|
||||
return deviceService.getById(id);
|
||||
}
|
||||
@ApiOperation("新增或修改设备")
|
||||
@PostMapping("/addOrUpdate")
|
||||
public ApiResponse addOrUpdate(@RequestBody DeviceAddOrUpdateReq deviceReqQuery) {
|
||||
return deviceService.addOrUpdate(deviceReqQuery);
|
||||
}
|
||||
@ApiOperation("删除设备")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse delete(@PathVariable("id") Long id) {
|
||||
return deviceService.deleteById(id);
|
||||
}
|
||||
@ApiOperation("修改设备状态")
|
||||
@PutMapping("/updateStatus/{id}")
|
||||
public ApiResponse updateStatus(@PathVariable("id") Long id) {
|
||||
return deviceService.updateStatus(id);
|
||||
}
|
||||
|
||||
@ApiOperation("排序设备")
|
||||
@PostMapping("/sort")
|
||||
public ApiResponse<Boolean> sortDevice(@RequestBody DeviceSortRequest request) {
|
||||
return deviceService.sortDevice(request.getDeviceId(), request.getAfterDeviceId());
|
||||
}
|
||||
|
||||
@PostMapping("/scenic/{scenicId}/sortBatch")
|
||||
public ApiResponse<Boolean> sortDeviceBatch(@PathVariable("scenicId") Long scenicId, @RequestBody DeviceBatchSortRequest request) {
|
||||
return deviceService.batchSort(scenicId, request);
|
||||
}
|
||||
|
||||
@GetMapping("/config/{id}")
|
||||
public ApiResponse<DeviceConfigEntity> getConfig(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(deviceService.getConfig(id));
|
||||
}
|
||||
|
||||
@PostMapping("/saveConfig/{configId}")
|
||||
public ApiResponse saveConfig(@PathVariable("configId") Long configId, @RequestBody DeviceConfigEntity deviceConfigEntity) {
|
||||
deviceService.saveConfig(configId, deviceConfigEntity);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
}
|
||||
@@ -1,390 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.integration.device.dto.config.*;
|
||||
import com.ycwl.basic.integration.common.response.PageResponse;
|
||||
import com.ycwl.basic.integration.device.dto.device.*;
|
||||
import com.ycwl.basic.integration.device.dto.status.DeviceStatusDTO;
|
||||
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
|
||||
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
|
||||
import com.ycwl.basic.integration.device.service.DeviceStatusIntegrationService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 设备管理 V2 版本控制器 - 基于 zt-device 集成服务
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-01
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/device/v2")
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceV2Controller {
|
||||
|
||||
private final DeviceIntegrationService deviceIntegrationService;
|
||||
private final DeviceConfigIntegrationService deviceConfigIntegrationService;
|
||||
private final DeviceStatusIntegrationService deviceStatusIntegrationService;
|
||||
|
||||
// ========== 设备基础 CRUD 操作 ==========
|
||||
|
||||
/**
|
||||
* 设备V2核心信息分页列表
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public ApiResponse<PageResponse<DeviceV2DTO>> listDevices(@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) String name,
|
||||
@RequestParam(required = false) String no,
|
||||
@RequestParam(required = false) String type,
|
||||
@RequestParam(required = false) Integer isActive,
|
||||
@RequestParam(required = false) Long scenicId) {
|
||||
log.info("分页查询设备核心信息列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}",
|
||||
page, pageSize, name, no, type, isActive, scenicId);
|
||||
|
||||
// 参数验证:限制pageSize最大值为100
|
||||
if (pageSize > 100) {
|
||||
pageSize = 100;
|
||||
}
|
||||
|
||||
try {
|
||||
PageResponse<DeviceV2DTO> response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, isActive, scenicId, null);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询设备核心信息列表失败", e);
|
||||
return ApiResponse.fail("分页查询设备列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取设备信息
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<DeviceV2DTO> getDevice(@PathVariable Long id) {
|
||||
try {
|
||||
DeviceV2DTO device = deviceIntegrationService.getDevice(id);
|
||||
return ApiResponse.success(device);
|
||||
} catch (Exception e) {
|
||||
log.error("获取设备信息失败, id: {}", id, e);
|
||||
return ApiResponse.fail("获取设备信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备编号获取设备信息
|
||||
*/
|
||||
@GetMapping("/no/{no}")
|
||||
public ApiResponse<DeviceV2DTO> getDeviceByNo(@PathVariable String no) {
|
||||
try {
|
||||
DeviceV2DTO device = deviceIntegrationService.getDeviceByNo(no);
|
||||
return ApiResponse.success(device);
|
||||
} catch (Exception e) {
|
||||
log.error("根据设备编号获取设备信息失败, no: {}", no, e);
|
||||
return ApiResponse.fail("根据设备编号获取设备信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备ID获取设备在线状态
|
||||
*/
|
||||
@GetMapping("/{id}/status")
|
||||
public ApiResponse<DeviceStatusDTO> getDeviceOnlineStatus(@PathVariable Long id) {
|
||||
log.info("获取设备在线状态, deviceId: {}", id);
|
||||
try {
|
||||
// 首先获取设备信息以获得设备编号
|
||||
DeviceV2DTO device = deviceIntegrationService.getDevice(id);
|
||||
if (device == null) {
|
||||
return ApiResponse.fail("设备不存在");
|
||||
}
|
||||
|
||||
// 使用设备编号查询在线状态
|
||||
DeviceStatusDTO onlineStatus = deviceStatusIntegrationService.getDeviceStatus(device.getNo());
|
||||
return ApiResponse.success(onlineStatus);
|
||||
} catch (Exception e) {
|
||||
log.error("获取设备在线状态失败, deviceId: {}", id, e);
|
||||
return ApiResponse.fail("获取设备在线状态失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建设备
|
||||
*/
|
||||
@PostMapping("/")
|
||||
public ApiResponse<DeviceV2DTO> createDevice(@Valid @RequestBody CreateDeviceRequest request) {
|
||||
log.info("创建设备, name: {}, no: {}, type: {}, sort: {}",
|
||||
request.getName(), request.getNo(), request.getType(), request.getSort());
|
||||
try {
|
||||
DeviceV2DTO device = deviceIntegrationService.createDevice(request);
|
||||
return ApiResponse.success(device);
|
||||
} catch (Exception e) {
|
||||
log.error("创建设备失败", e);
|
||||
return ApiResponse.fail("创建设备失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建IPC摄像头设备(快捷方法)
|
||||
*/
|
||||
@PostMapping("/ipc")
|
||||
public ApiResponse<DeviceV2DTO> createIpcDevice(@RequestBody Map<String, Object> request) {
|
||||
String name = (String) request.get("name");
|
||||
String deviceNo = (String) request.get("no");
|
||||
Long scenicId = Long.valueOf(request.get("scenicId").toString());
|
||||
Integer sort = request.get("sort") != null ? Integer.valueOf(request.get("sort").toString()) : null;
|
||||
|
||||
log.info("创建IPC摄像头设备, name: {}, no: {}, scenicId: {}, sort: {}", name, deviceNo, scenicId, sort);
|
||||
try {
|
||||
DeviceV2DTO device;
|
||||
if (sort != null) {
|
||||
device = deviceIntegrationService.createIpcDeviceWithSort(name, deviceNo, scenicId, sort);
|
||||
} else {
|
||||
device = deviceIntegrationService.createIpcDevice(name, deviceNo, scenicId);
|
||||
}
|
||||
return ApiResponse.success(device);
|
||||
} catch (Exception e) {
|
||||
log.error("创建IPC摄像头设备失败", e);
|
||||
return ApiResponse.fail("创建IPC摄像头设备失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义设备(快捷方法)
|
||||
*/
|
||||
@PostMapping("/custom")
|
||||
public ApiResponse<DeviceV2DTO> createCustomDevice(@RequestBody Map<String, Object> request) {
|
||||
String name = (String) request.get("name");
|
||||
String deviceNo = (String) request.get("no");
|
||||
Long scenicId = Long.valueOf(request.get("scenicId").toString());
|
||||
Integer sort = request.get("sort") != null ? Integer.valueOf(request.get("sort").toString()) : null;
|
||||
|
||||
log.info("创建自定义设备, name: {}, no: {}, scenicId: {}, sort: {}", name, deviceNo, scenicId, sort);
|
||||
try {
|
||||
DeviceV2DTO device;
|
||||
if (sort != null) {
|
||||
device = deviceIntegrationService.createCustomDeviceWithSort(name, deviceNo, scenicId, sort);
|
||||
} else {
|
||||
device = deviceIntegrationService.createCustomDevice(name, deviceNo, scenicId);
|
||||
}
|
||||
return ApiResponse.success(device);
|
||||
} catch (Exception e) {
|
||||
log.error("创建自定义设备失败", e);
|
||||
return ApiResponse.fail("创建自定义设备失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备信息
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<String> updateDevice(@PathVariable Long id, @Valid @RequestBody UpdateDeviceRequest request) {
|
||||
log.info("更新设备信息, id: {}", id);
|
||||
try {
|
||||
deviceIntegrationService.updateDevice(id, request);
|
||||
return ApiResponse.success("设备信息更新成功");
|
||||
} catch (Exception e) {
|
||||
log.error("更新设备信息失败, id: {}", id, e);
|
||||
return ApiResponse.fail("更新设备信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备排序
|
||||
*/
|
||||
@PutMapping("/{id}/sort")
|
||||
public ApiResponse<String> updateDeviceSort(@PathVariable Long id, @RequestBody Map<String, Integer> request) {
|
||||
Integer sort = request.get("sort");
|
||||
log.info("更新设备排序, id: {}, sort: {}", id, sort);
|
||||
try {
|
||||
deviceIntegrationService.updateDeviceSort(id, sort);
|
||||
return ApiResponse.success("设备排序更新成功");
|
||||
} catch (Exception e) {
|
||||
log.error("更新设备排序失败, id: {}, sort: {}", id, sort, e);
|
||||
return ApiResponse.fail("更新设备排序失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用设备
|
||||
*/
|
||||
@PutMapping("/{id}/enable")
|
||||
public ApiResponse<String> enableDevice(@PathVariable Long id) {
|
||||
log.info("启用设备, id: {}", id);
|
||||
try {
|
||||
deviceIntegrationService.enableDevice(id);
|
||||
return ApiResponse.success("设备启用成功");
|
||||
} catch (Exception e) {
|
||||
log.error("启用设备失败, id: {}", id, e);
|
||||
return ApiResponse.fail("启用设备失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用设备
|
||||
*/
|
||||
@PutMapping("/{id}/disable")
|
||||
public ApiResponse<String> disableDevice(@PathVariable Long id) {
|
||||
log.info("禁用设备, id: {}", id);
|
||||
try {
|
||||
deviceIntegrationService.disableDevice(id);
|
||||
return ApiResponse.success("设备禁用成功");
|
||||
} catch (Exception e) {
|
||||
log.error("禁用设备失败, id: {}", id, e);
|
||||
return ApiResponse.fail("禁用设备失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<String> deleteDevice(@PathVariable Long id) {
|
||||
log.info("删除设备, id: {}", id);
|
||||
try {
|
||||
deviceIntegrationService.deleteDevice(id);
|
||||
return ApiResponse.success("设备删除成功");
|
||||
} catch (Exception e) {
|
||||
log.error("删除设备失败, id: {}", id, e);
|
||||
return ApiResponse.fail("删除设备失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 设备配置管理操作 ==========
|
||||
|
||||
/**
|
||||
* 获取设备配置列表
|
||||
*/
|
||||
@GetMapping("/{id}/config")
|
||||
public ApiResponse<List<DeviceConfigV2DTO>> getDeviceConfigs(@PathVariable Long id) {
|
||||
try {
|
||||
List<DeviceConfigV2DTO> configs = deviceConfigIntegrationService.getDeviceConfigs(id);
|
||||
return ApiResponse.success(configs);
|
||||
} catch (Exception e) {
|
||||
log.error("获取设备配置列表失败, deviceId: {}", id, e);
|
||||
return ApiResponse.fail("获取设备配置列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置键获取配置
|
||||
*/
|
||||
@GetMapping("/{id}/config/{configKey}")
|
||||
public ApiResponse<DeviceConfigV2DTO> getDeviceConfigByKey(@PathVariable Long id,
|
||||
@PathVariable String configKey) {
|
||||
try {
|
||||
DeviceConfigV2DTO config = deviceConfigIntegrationService.getDeviceConfigByKey(id, configKey);
|
||||
return ApiResponse.success(config);
|
||||
} catch (Exception e) {
|
||||
log.error("根据键获取设备配置失败, deviceId: {}, configKey: {}", id, configKey, e);
|
||||
return ApiResponse.fail("根据键获取设备配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备编号获取配置列表
|
||||
*/
|
||||
@GetMapping("/no/{no}/config")
|
||||
public ApiResponse<List<DeviceConfigV2DTO>> getDeviceConfigsByNo(@PathVariable String no) {
|
||||
log.info("根据设备编号获取配置列表, deviceNo: {}", no);
|
||||
try {
|
||||
List<DeviceConfigV2DTO> configs = deviceConfigIntegrationService.getDeviceConfigsByNo(no);
|
||||
return ApiResponse.success(configs);
|
||||
} catch (Exception e) {
|
||||
log.error("根据设备编号获取配置列表失败, deviceNo: {}", no, e);
|
||||
return ApiResponse.fail("根据设备编号获取配置列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建设备配置
|
||||
*/
|
||||
@PostMapping("/{id}/config")
|
||||
public ApiResponse<DeviceConfigV2DTO> createDeviceConfig(@PathVariable Long id,
|
||||
@Valid @RequestBody CreateDeviceConfigRequest request) {
|
||||
log.info("创建设备配置, deviceId: {}, configKey: {}", id, request.getConfigKey());
|
||||
try {
|
||||
DeviceConfigV2DTO config = deviceConfigIntegrationService.createDeviceConfig(id, request);
|
||||
return ApiResponse.success(config);
|
||||
} catch (Exception e) {
|
||||
log.error("创建设备配置失败, deviceId: {}, configKey: {}", id, request.getConfigKey(), e);
|
||||
return ApiResponse.fail("创建设备配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建/更新设备配置
|
||||
*/
|
||||
@PostMapping("/{id}/config/batch")
|
||||
public ApiResponse<BatchUpdateResponse> batchUpdateDeviceConfig(@PathVariable Long id,
|
||||
@Valid @RequestBody BatchDeviceConfigRequest request) {
|
||||
log.info("批量更新设备配置, deviceId: {}, configs count: {}", id, request.getConfigs().size());
|
||||
try {
|
||||
BatchUpdateResponse result = deviceConfigIntegrationService.batchUpdateDeviceConfig(id, request);
|
||||
return ApiResponse.success(result);
|
||||
} catch (Exception e) {
|
||||
log.error("批量更新设备配置失败, deviceId: {}", id, e);
|
||||
return ApiResponse.fail("批量更新设备配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新设备配置
|
||||
*/
|
||||
@PutMapping("/{id}/config/{configId}")
|
||||
public ApiResponse<String> updateDeviceConfig(@PathVariable Long id, @PathVariable Long configId,
|
||||
@Valid @RequestBody UpdateDeviceConfigRequest request) {
|
||||
log.info("更新设备配置, deviceId: {}, configId: {}", id, configId);
|
||||
try {
|
||||
deviceConfigIntegrationService.updateDeviceConfig(id, configId, request);
|
||||
return ApiResponse.success("设备配置更新成功");
|
||||
} catch (Exception e) {
|
||||
log.error("更新设备配置失败, deviceId: {}, configId: {}", id, configId, e);
|
||||
return ApiResponse.fail("更新设备配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除设备配置
|
||||
*/
|
||||
@DeleteMapping("/{id}/config/{configId}")
|
||||
public ApiResponse<String> deleteDeviceConfig(@PathVariable Long id, @PathVariable Long configId) {
|
||||
log.info("删除设备配置, deviceId: {}, configId: {}", id, configId);
|
||||
try {
|
||||
deviceConfigIntegrationService.deleteDeviceConfig(id, configId);
|
||||
return ApiResponse.success("设备配置删除成功");
|
||||
} catch (Exception e) {
|
||||
log.error("删除设备配置失败, deviceId: {}, configId: {}", id, configId, e);
|
||||
return ApiResponse.fail("删除设备配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 景区设备管理操作 ==========
|
||||
|
||||
/**
|
||||
* 获取景区所有设备列表
|
||||
*/
|
||||
@GetMapping("/scenic/{scenicId}")
|
||||
public ApiResponse<PageResponse<DeviceV2DTO>> getScenicAllDevices(@PathVariable Long scenicId,
|
||||
@RequestParam(required = false) String name,
|
||||
@RequestParam(required = false) String type,
|
||||
@RequestParam(required = false) String no,
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||
log.info("获取景区所有设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize);
|
||||
try {
|
||||
PageResponse<DeviceV2DTO> response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, null, scenicId, null);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取景区所有设备列表失败, scenicId: {}", scenicId, e);
|
||||
return ApiResponse.fail("获取景区所有设备列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.device.entity.common.DeviceVideoContinuityCache;
|
||||
import com.ycwl.basic.task.DeviceVideoContinuityCheckTask;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 设备视频连续性检查控制器
|
||||
* 提供查询设备视频连续性检查结果的接口
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-01
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/device/video-continuity")
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceVideoContinuityController {
|
||||
|
||||
private static final String REDIS_KEY_PREFIX = "device:video:continuity:";
|
||||
|
||||
private final RedisTemplate<String, String> redisTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final DeviceVideoContinuityCheckTask checkTask;
|
||||
|
||||
/**
|
||||
* 查询设备最近的视频连续性检查结果
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 检查结果
|
||||
*/
|
||||
@GetMapping("/{deviceId}")
|
||||
public ApiResponse<DeviceVideoContinuityCache> getDeviceContinuityResult(@PathVariable Long deviceId) {
|
||||
log.info("查询设备 {} 的视频连续性检查结果", deviceId);
|
||||
|
||||
try {
|
||||
String redisKey = REDIS_KEY_PREFIX + deviceId;
|
||||
String cacheJson = redisTemplate.opsForValue().get(redisKey);
|
||||
|
||||
if (cacheJson == null) {
|
||||
log.warn("未找到设备 {} 的视频连续性检查结果", deviceId);
|
||||
return ApiResponse.buildResponse(404, null, "未找到该设备的检查结果,可能设备未配置存储或尚未执行检查");
|
||||
}
|
||||
|
||||
DeviceVideoContinuityCache cache = objectMapper.readValue(cacheJson, DeviceVideoContinuityCache.class);
|
||||
return ApiResponse.success(cache);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("查询设备 {} 视频连续性检查结果失败", deviceId, e);
|
||||
return ApiResponse.buildResponse(500, null, "查询失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发设备视频连续性检查
|
||||
* 注意:仅用于测试和紧急情况,正常情况下由定时任务自动执行
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 检查结果
|
||||
*/
|
||||
@PostMapping("/{deviceId}/check")
|
||||
public ApiResponse<DeviceVideoContinuityCache> manualCheck(@PathVariable Long deviceId) {
|
||||
log.info("手动触发设备 {} 的视频连续性检查", deviceId);
|
||||
|
||||
try {
|
||||
DeviceVideoContinuityCache result = checkTask.manualCheck(deviceId);
|
||||
return ApiResponse.success(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("手动检查设备 {} 视频连续性失败", deviceId, e);
|
||||
return ApiResponse.buildResponse(500, null, "检查失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备的视频连续性检查缓存
|
||||
* 用于清理过期或错误的缓存数据
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
@DeleteMapping("/{deviceId}")
|
||||
public ApiResponse<String> deleteContinuityCache(@PathVariable Long deviceId) {
|
||||
log.info("删除设备 {} 的视频连续性检查缓存", deviceId);
|
||||
|
||||
try {
|
||||
String redisKey = REDIS_KEY_PREFIX + deviceId;
|
||||
Boolean deleted = redisTemplate.delete(redisKey);
|
||||
|
||||
if (deleted != null && deleted) {
|
||||
return ApiResponse.success("缓存删除成功");
|
||||
} else {
|
||||
return ApiResponse.buildResponse(404, null, "未找到该设备的缓存数据");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("删除设备 {} 视频连续性检查缓存失败", deviceId, e);
|
||||
return ApiResponse.buildResponse(500, null, "删除失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import com.ycwl.basic.model.pc.face.req.FaceReqQuery;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -17,40 +19,41 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/face/v1")
|
||||
// 用户人脸管理
|
||||
@Api(tags = "用户人脸管理")
|
||||
public class FaceController {
|
||||
@Autowired
|
||||
private FaceService faceService;
|
||||
|
||||
// 分页查询用户人脸
|
||||
@ApiOperation("分页查询用户人脸")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<FaceRespVO>> pageQuery(@RequestBody FaceReqQuery faceReqQuery) {
|
||||
return faceService.pageQuery(faceReqQuery);
|
||||
}
|
||||
// 用户人脸列表查询
|
||||
@ApiOperation("用户人脸列表查询")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse<List<FaceRespVO>> list(@RequestBody FaceReqQuery faceReqQuery) {
|
||||
return faceService.list(faceReqQuery);
|
||||
}
|
||||
// 用户人脸详情查询
|
||||
@ApiOperation("用户人脸详情查询")
|
||||
@GetMapping("/getDetail/{id}")
|
||||
public ApiResponse<FaceRespVO> getDetail(@PathVariable("id") Long id) {
|
||||
return faceService.getById(id);
|
||||
}
|
||||
// 添加用户人脸信息
|
||||
@ApiOperation("添加用户人脸信息")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<Integer> add(@RequestBody FaceEntity face) {
|
||||
return faceService.add(face);
|
||||
}
|
||||
// 删除用户人脸信息
|
||||
@ApiOperation("删除用户人脸信息")
|
||||
@PostMapping("/deleteById/{id}")
|
||||
public ApiResponse<Integer> deleteById(@PathVariable Long id) {
|
||||
return faceService.deleteById(id);
|
||||
}
|
||||
// 批量删除用户人脸
|
||||
@ApiOperation("批量删除用户人脸")
|
||||
@PostMapping("/deleteByIds")
|
||||
public ApiResponse<Integer> deleteByIds(@RequestBody List<Long> ids) {
|
||||
return faceService.deleteByIds(ids);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
import com.ycwl.basic.integration.kafka.service.FaceProcessingKafkaService;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
@@ -7,6 +6,8 @@ import com.ycwl.basic.model.pc.faceSample.req.FaceSampleReqQuery;
|
||||
import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
|
||||
import com.ycwl.basic.service.pc.FaceSampleService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -16,50 +17,28 @@ import java.util.List;
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/2 16:33
|
||||
*/
|
||||
@Deprecated
|
||||
@RestController
|
||||
@RequestMapping("/api/faceSample/v1")
|
||||
// 人脸样本管理
|
||||
@Api(tags = "人脸样本管理")
|
||||
public class FaceSampleController {
|
||||
@Autowired
|
||||
private FaceSampleService FaceSampleService;
|
||||
@Autowired(required = false)
|
||||
private FaceProcessingKafkaService faceProcessingKafkaService;
|
||||
|
||||
// 分页查询人脸样本
|
||||
@ApiOperation("分页查询人脸样本")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<FaceSampleRespVO>> pageQuery(@RequestBody FaceSampleReqQuery FaceSampleReqQuery) {
|
||||
return FaceSampleService.pageQuery(FaceSampleReqQuery);
|
||||
}
|
||||
// 人脸样本列表查询
|
||||
@ApiOperation("人脸样本列表查询")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse<List<FaceSampleRespVO>> list(@RequestBody FaceSampleReqQuery FaceSampleReqQuery) {
|
||||
return FaceSampleService.list(FaceSampleReqQuery);
|
||||
}
|
||||
// 人脸样本详情查询
|
||||
@ApiOperation("人脸样本详情查询")
|
||||
@GetMapping("/getDetail/{id}")
|
||||
public ApiResponse<FaceSampleRespVO> getDetail(@PathVariable("id") Long id) {
|
||||
return FaceSampleService.getById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试失败的人脸识别
|
||||
* 用于手动重试状态为-1的人脸样本
|
||||
*
|
||||
* @param id 人脸样本ID
|
||||
* @return 重试结果
|
||||
*/
|
||||
@PostMapping("/retry/{id}")
|
||||
public ApiResponse<String> retryFaceRecognition(@PathVariable("id") Long id) {
|
||||
if (faceProcessingKafkaService == null) {
|
||||
return ApiResponse.fail("Kafka服务未启用,无法重试人脸识别");
|
||||
}
|
||||
|
||||
boolean success = faceProcessingKafkaService.retryFaceRecognition(id);
|
||||
if (success) {
|
||||
return ApiResponse.success("人脸识别重试任务已提交");
|
||||
} else {
|
||||
return ApiResponse.fail("提交重试任务失败,请检查人脸样本状态");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import com.ycwl.basic.model.pc.member.req.MemberReqQuery;
|
||||
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
|
||||
import com.ycwl.basic.service.pc.MemberService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -17,37 +19,37 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/member/v1")
|
||||
// 前台用户管理
|
||||
@Api(tags = "前台用户管理")
|
||||
public class MemberController {
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
// 前台用户分页查询
|
||||
@ApiOperation("前台用户分页查询")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<MemberRespVO>> pageQuery(@RequestBody MemberReqQuery memberReqQuery) {
|
||||
return memberService.pageQuery(memberReqQuery);
|
||||
}
|
||||
// 前台用户列表查询
|
||||
@ApiOperation("前台用户列表查询")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse<List<MemberRespVO>> list(@RequestBody MemberReqQuery memberReqQuery) {
|
||||
return memberService.list(memberReqQuery);
|
||||
}
|
||||
// 前台用户详情查询
|
||||
@ApiOperation("前台用户详情查询")
|
||||
@GetMapping("/getDetail/{id}")
|
||||
public ApiResponse<MemberRespVO> getDetail(@PathVariable("id") Long id) {
|
||||
return memberService.getById(id);
|
||||
}
|
||||
// 前台用户删除
|
||||
@ApiOperation("前台用户删除")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse<Integer> delete(@PathVariable("id") Long id) {
|
||||
return memberService.deleteById(id);
|
||||
}
|
||||
// 前台用户新增
|
||||
@ApiOperation("前台用户新增")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<Integer> add(@RequestBody MemberEntity member) {
|
||||
return memberService.add(member);
|
||||
}
|
||||
// 前台用户修改
|
||||
@ApiOperation("前台用户修改")
|
||||
@PostMapping("/update")
|
||||
public ApiResponse<Integer> update(@RequestBody MemberEntity member) {
|
||||
return memberService.update(member);
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
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,60 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.integration.message.dto.ChannelsResponse;
|
||||
import com.ycwl.basic.integration.message.dto.MessageListData;
|
||||
import com.ycwl.basic.integration.message.service.MessageIntegrationService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/message/v1")
|
||||
@RequiredArgsConstructor
|
||||
public class MessageController {
|
||||
|
||||
private final MessageIntegrationService messageService;
|
||||
|
||||
@GetMapping("/messages")
|
||||
public ApiResponse<MessageListData> listMessages(
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "20") Integer pageSize,
|
||||
@RequestParam(required = false) String channelId,
|
||||
@RequestParam(required = false) String title,
|
||||
@RequestParam(required = false) String content,
|
||||
@RequestParam(required = false) String sendBiz,
|
||||
@RequestParam(required = false) String sentAtStart,
|
||||
@RequestParam(required = false) String sentAtEnd,
|
||||
@RequestParam(required = false) String createdAtStart,
|
||||
@RequestParam(required = false) String createdAtEnd
|
||||
) {
|
||||
log.debug("PC|消息列表查询 page={}, pageSize={}, channelId={}, title={}, sendBiz={}", page, pageSize, channelId, title, sendBiz);
|
||||
if (pageSize > 100) {
|
||||
pageSize = 100;
|
||||
}
|
||||
try {
|
||||
MessageListData data = messageService.listMessages(page, pageSize, channelId, title, content, sendBiz,
|
||||
sentAtStart, sentAtEnd, createdAtStart, createdAtEnd);
|
||||
return ApiResponse.success(data);
|
||||
} catch (Exception e) {
|
||||
log.error("PC|消息列表查询失败", e);
|
||||
return ApiResponse.fail("消息列表查询失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/channels")
|
||||
public ApiResponse<ChannelsResponse> listChannels() {
|
||||
log.debug("PC|获取消息通道列表");
|
||||
try {
|
||||
ChannelsResponse data = messageService.listChannels();
|
||||
return ApiResponse.success(data);
|
||||
} catch (Exception e) {
|
||||
log.error("PC|获取消息通道列表失败", e);
|
||||
return ApiResponse.fail("获取消息通道列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.ycwl.basic.model.pc.order.req.OrderReqQuery;
|
||||
import com.ycwl.basic.model.pc.order.resp.OrderRespVO;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -18,38 +20,38 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/order/v1")
|
||||
// 订单管理
|
||||
@Api(tags = "订单管理")
|
||||
public class OrderController {
|
||||
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
// 审核退款: 审核退款
|
||||
@ApiOperation(value = "审核退款", notes = "审核退款")
|
||||
@PostMapping("/auditRefundOrder")
|
||||
public ApiResponse<?> auditRefundOrder(@RequestBody RefundOrderReq refundOrderReq) {
|
||||
return orderService.auditRefundOrder(refundOrderReq);
|
||||
}
|
||||
|
||||
|
||||
// 分页查询订单
|
||||
@ApiOperation("分页查询订单")
|
||||
@PostMapping("page")
|
||||
public ApiResponse<PageInfo<OrderRespVO>> pageQuery(@RequestBody OrderReqQuery query) {
|
||||
return orderService.pageQuery(query);
|
||||
}
|
||||
|
||||
// 订单列表查询
|
||||
@ApiOperation("订单列表查询")
|
||||
@PostMapping("list")
|
||||
public ApiResponse<List<OrderRespVO>> list(@RequestBody OrderReqQuery query) {
|
||||
return orderService.list(query);
|
||||
}
|
||||
// 订单详情查询
|
||||
@ApiOperation("订单详情查询")
|
||||
@GetMapping("detail/{id}")
|
||||
public ApiResponse<OrderRespVO> detail(@PathVariable("id") Long orderId) {
|
||||
return orderService.detail(orderId);
|
||||
}
|
||||
|
||||
|
||||
// 订单备注
|
||||
@ApiOperation("订单备注")
|
||||
@PostMapping("remark/{id}")
|
||||
public ApiResponse<?> updateRemark(@PathVariable("id") Long orderId, @RequestBody OrderEntity query) {
|
||||
orderService.remarkOrder(orderId, query);
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
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;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -26,36 +24,22 @@ import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/permission/v1")
|
||||
// 权限管理接口
|
||||
@Api(tags = "权限管理接口")
|
||||
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();
|
||||
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(), ","))));
|
||||
}
|
||||
}
|
||||
|
||||
// 根据用户ID查询权限信息
|
||||
@ApiOperation("根据用户ID查询权限信息")
|
||||
@GetMapping("/get/{userId}")
|
||||
public ApiResponse<PermissionResp> getPermissionByUser(@PathVariable Long userId) {
|
||||
PermissionEntity permission = permissionService.getPermissionByUserId(userId);
|
||||
@@ -65,7 +49,7 @@ public class PermissionController {
|
||||
return ApiResponse.success(new PermissionResp(Arrays.asList(StringUtils.split(permission.getPermString(), ",")), Arrays.asList(StringUtils.split(permission.getMenuString(), ","))));
|
||||
}
|
||||
|
||||
// 保存或更新权限信息
|
||||
@ApiOperation("保存或更新权限信息")
|
||||
@PostMapping("/save/{userId}")
|
||||
public ApiResponse saveOrUpdate(@PathVariable Long userId, @RequestBody PermissionSaveReq req) {
|
||||
permissionService.saveOrUpdate(userId, StringUtils.join(req.getPermissions(), ","), StringUtils.join(req.getMenus(), ","));
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.biz.PriceBiz;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.price.req.PriceConfigListReq;
|
||||
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
|
||||
import com.ycwl.basic.model.pc.price.resp.SimpleGoodsRespVO;
|
||||
import com.ycwl.basic.model.pc.price.resp.PriceConfigRespVO;
|
||||
import com.ycwl.basic.repository.PriceRepository;
|
||||
import com.ycwl.basic.service.pc.PriceConfigService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -14,13 +19,61 @@ import java.util.List;
|
||||
public class PriceConfigController {
|
||||
|
||||
@Autowired
|
||||
private PriceBiz priceBiz;
|
||||
private PriceConfigService priceConfigService;
|
||||
@Autowired
|
||||
private PriceRepository priceRepository;
|
||||
|
||||
@GetMapping("/goodsList")
|
||||
public ApiResponse<List<SimpleGoodsRespVO>> goodsList(
|
||||
@RequestParam Long scenicId,
|
||||
@RequestParam(required = false) String productType) {
|
||||
return ApiResponse.success(priceBiz.listSimpleGoodsByScenic(scenicId, productType));
|
||||
public ApiResponse<List<GoodsListRespVO>> goodsList(@RequestParam Long scenicId) {
|
||||
return ApiResponse.success(priceConfigService.listGoodsByScenic(scenicId));
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<PriceConfigEntity> addPriceConfig(@RequestBody PriceConfigEntity priceConfig) {
|
||||
priceConfig.setId(null);
|
||||
priceConfigService.save(priceConfig);
|
||||
return ApiResponse.success(priceConfig);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public ApiResponse<PriceConfigEntity> updatePriceConfig(@RequestBody PriceConfigEntity priceConfig) {
|
||||
priceRepository.clearPriceCache(priceConfig.getId());
|
||||
priceConfigService.updateById(priceConfig);
|
||||
priceRepository.clearPriceCache(priceConfig.getId());
|
||||
return ApiResponse.success(priceConfig);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse<Boolean> deletePriceConfig(@PathVariable Integer id) {
|
||||
priceRepository.clearPriceCache(id);
|
||||
priceConfigService.removeById(id);
|
||||
priceRepository.clearPriceCache(id);
|
||||
return ApiResponse.success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/status")
|
||||
public ApiResponse<Boolean> updateStatus(@PathVariable Integer id) {
|
||||
priceRepository.clearPriceCache(id);
|
||||
priceConfigService.updateStatus(id);
|
||||
priceRepository.clearPriceCache(id);
|
||||
return ApiResponse.success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<PriceConfigRespVO> getPriceConfigById(@PathVariable Integer id) {
|
||||
PriceConfigRespVO config = priceConfigService.findById(id);
|
||||
priceConfigService.fillGoodsName(config);
|
||||
return ApiResponse.success(config);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public ApiResponse<PageInfo<PriceConfigRespVO>> list(@RequestParam(defaultValue = "1") int pageNum,
|
||||
@RequestParam(defaultValue = "10") int pageSize,
|
||||
@ModelAttribute PriceConfigListReq req) {
|
||||
PageHelper.startPage(pageNum, pageSize);
|
||||
List<PriceConfigRespVO> result = priceConfigService.listByCondition(req);
|
||||
priceConfigService.fillGoodsName(result);
|
||||
PageInfo<PriceConfigRespVO> pageInfo = new PageInfo<>(result);
|
||||
return ApiResponse.success(pageInfo);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.mapper.PrintTaskMapper;
|
||||
import com.ycwl.basic.model.pc.printer.entity.PrintTaskEntity;
|
||||
import com.ycwl.basic.model.pc.printer.entity.PrinterEntity;
|
||||
import com.ycwl.basic.model.pc.printer.req.PrintTaskReqQuery;
|
||||
import com.ycwl.basic.model.pc.printer.req.ReprintRequest;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -26,97 +22,33 @@ public class PrinterController {
|
||||
@Autowired
|
||||
private PrinterService printerService;
|
||||
|
||||
@Autowired
|
||||
private PrintTaskMapper printTaskMapper;
|
||||
|
||||
// 查询列表
|
||||
@ApiOperation("查询列表")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse<List<PrinterEntity>> list(@RequestBody PrinterEntity condition) {
|
||||
return printerService.list(condition);
|
||||
}
|
||||
|
||||
// 获取详情
|
||||
@ApiOperation("获取详情")
|
||||
@GetMapping("/get/{id}")
|
||||
public ApiResponse<PrinterEntity> get(@PathVariable("id") Integer id) {
|
||||
return printerService.get(id);
|
||||
}
|
||||
|
||||
// 新增
|
||||
@ApiOperation("新增")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<Integer> add(@RequestBody PrinterEntity entity) {
|
||||
return printerService.add(entity);
|
||||
}
|
||||
|
||||
// 更新
|
||||
@ApiOperation("更新")
|
||||
@PostMapping("/update")
|
||||
public ApiResponse<Integer> update(@RequestBody PrinterEntity entity) {
|
||||
return printerService.update(entity);
|
||||
}
|
||||
|
||||
// 删除
|
||||
@ApiOperation("删除")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse<Integer> delete(@PathVariable("id") Integer id) {
|
||||
return printerService.delete(id);
|
||||
}
|
||||
|
||||
// 分页查询打印任务
|
||||
@PostMapping("/task/page")
|
||||
public ApiResponse<PageInfo<PrintTaskEntity>> taskPage(@RequestBody PrintTaskReqQuery req) {
|
||||
PageHelper.startPage(req.getPageNum(), req.getPageSize());
|
||||
List<PrintTaskEntity> list = printTaskMapper.queryByCondition(req.getPrinterId(), req.getStatus());
|
||||
PageInfo<PrintTaskEntity> pageInfo = new PageInfo<>(list);
|
||||
return ApiResponse.success(pageInfo);
|
||||
}
|
||||
|
||||
// 重新打印(将状态设置为0-未开始,并更新打印机名称)
|
||||
@PostMapping("/task/reprint/{id}")
|
||||
public ApiResponse<Integer> reprint(@PathVariable("id") Integer id, @RequestBody ReprintRequest request) {
|
||||
int result = printerService.handleReprint(id, request);
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询待审核的打印任务
|
||||
* @param printerId 打印机ID(可选)
|
||||
* @return 待审核任务列表
|
||||
*/
|
||||
@GetMapping("/task/pending-review")
|
||||
public ApiResponse<List<PrintTaskEntity>> getPendingReviewTasks(Integer printerId) {
|
||||
List<PrintTaskEntity> tasks = printerService.getPendingReviewTasks(printerId);
|
||||
return ApiResponse.success(tasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新待审核任务的URL(重新处理水印等)
|
||||
* @param taskId 任务ID
|
||||
* @param url 新的打印URL
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/task/{taskId}/url")
|
||||
public ApiResponse<Boolean> updateTaskUrl(@PathVariable("taskId") Integer taskId, @RequestBody String url) {
|
||||
boolean success = printerService.updatePendingReviewTaskUrl(taskId, url);
|
||||
return ApiResponse.success(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批准待审核任务,下发到打印队列
|
||||
* @param taskIds 任务ID列表
|
||||
* @return 成功数量
|
||||
*/
|
||||
@PostMapping("/task/approve")
|
||||
public ApiResponse<Integer> approveTasks(@RequestBody List<Integer> taskIds) {
|
||||
int count = printerService.approvePrintTasks(taskIds);
|
||||
return ApiResponse.success(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝待审核任务
|
||||
* @param taskIds 任务ID列表
|
||||
* @return 成功数量
|
||||
*/
|
||||
@PostMapping("/task/reject")
|
||||
public ApiResponse<Integer> rejectTasks(@RequestBody List<Integer> taskIds) {
|
||||
int count = printerService.rejectPrintTasks(taskIds);
|
||||
return ApiResponse.success(count);
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.model.pc.printer.entity.PrinterEntity;
|
||||
import com.ycwl.basic.model.pc.printer.req.PrinterPreferredSizeUpdateReq;
|
||||
import com.ycwl.basic.model.pc.printer.req.PrinterStatusUpdateReq;
|
||||
import com.ycwl.basic.model.pc.printer.req.PrinterUsePrinterUpdateReq;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.utils.ApiConst;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
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 java.util.List;
|
||||
|
||||
/**
|
||||
* 打印机管理接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/pc/printers/v1")
|
||||
@RequiredArgsConstructor
|
||||
public class PrinterManageController {
|
||||
|
||||
private final PrinterService printerService;
|
||||
|
||||
/**
|
||||
* 打印机列表查询
|
||||
*/
|
||||
@GetMapping
|
||||
public ApiResponse<List<PrinterEntity>> list(@RequestParam(value = "scenicId", required = false) Long scenicId,
|
||||
@RequestParam(value = "status", required = false) Integer status,
|
||||
@RequestParam(value = "name", required = false) String name) {
|
||||
PrinterEntity condition = new PrinterEntity();
|
||||
condition.setScenicId(scenicId);
|
||||
condition.setStatus(status);
|
||||
condition.setName(name);
|
||||
return printerService.list(condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印机详情
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<PrinterEntity> detail(@PathVariable("id") Integer id) {
|
||||
ApiResponse<PrinterEntity> response = printerService.get(id);
|
||||
if (response.getData() == null) {
|
||||
return ApiResponse.buildResponse(ApiConst.Code.CODE_NOT_EXIST, "打印机不存在");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增打印机
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResponse<Integer> create(@RequestBody PrinterEntity request) {
|
||||
request.setId(null);
|
||||
return printerService.add(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新打印机信息
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<Integer> update(@PathVariable("id") Integer id, @RequestBody PrinterEntity request) {
|
||||
request.setId(id);
|
||||
return printerService.update(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新打印机状态
|
||||
*/
|
||||
@PatchMapping("/{id}/status")
|
||||
public ApiResponse<Integer> updateStatus(@PathVariable("id") Integer id,
|
||||
@RequestBody PrinterStatusUpdateReq req) {
|
||||
if (req == null || req.getStatus() == null) {
|
||||
return ApiResponse.buildResponse(ApiConst.Code.CODE_PARAM_ERROR, "状态不能为空");
|
||||
}
|
||||
PrinterEntity entity = new PrinterEntity();
|
||||
entity.setId(id);
|
||||
entity.setStatus(req.getStatus());
|
||||
return printerService.update(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新打印机首选尺寸
|
||||
*/
|
||||
@PatchMapping("/{id}/preferred-size")
|
||||
public ApiResponse<Integer> updatePreferredSize(@PathVariable("id") Integer id,
|
||||
@RequestBody PrinterPreferredSizeUpdateReq req) {
|
||||
if (req == null || (req.getPreferW() == null && req.getPreferH() == null)) {
|
||||
return ApiResponse.buildResponse(ApiConst.Code.CODE_PARAM_ERROR, "首选尺寸不能为空");
|
||||
}
|
||||
PrinterEntity entity = new PrinterEntity();
|
||||
entity.setId(id);
|
||||
entity.setPreferW(req.getPreferW());
|
||||
entity.setPreferH(req.getPreferH());
|
||||
return printerService.update(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新当前使用的打印机
|
||||
*/
|
||||
@PatchMapping("/{id}/use-printer")
|
||||
public ApiResponse<Integer> updateUsePrinter(@PathVariable("id") Integer id,
|
||||
@RequestBody PrinterUsePrinterUpdateReq req) {
|
||||
if (req == null) {
|
||||
return ApiResponse.buildResponse(ApiConst.Code.CODE_PARAM_ERROR, "请求参数不能为空");
|
||||
}
|
||||
PrinterEntity entity = new PrinterEntity();
|
||||
entity.setId(id);
|
||||
entity.setUsePrinter(req.getUsePrinter());
|
||||
return printerService.update(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除打印机
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<Integer> delete(@PathVariable("id") Integer id) {
|
||||
return printerService.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.model.pc.project.entity.ProjectEntity;
|
||||
import com.ycwl.basic.model.pc.project.req.ProjectReqQuery;
|
||||
import com.ycwl.basic.model.pc.project.resp.ProjectRespVO;
|
||||
import com.ycwl.basic.service.pc.ProjectService;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.WxMpUtil;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 景区项目管理控制器
|
||||
*
|
||||
* @Author: Claude
|
||||
* @Date: 2025-01-15
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/project/v1")
|
||||
public class ProjectController {
|
||||
|
||||
@Autowired
|
||||
private ProjectService projectService;
|
||||
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
// 分页查询
|
||||
@PostMapping("/page")
|
||||
public ApiResponse page(@RequestBody ProjectReqQuery projectReqQuery) {
|
||||
return ApiResponse.success(projectService.pageQuery(projectReqQuery));
|
||||
}
|
||||
|
||||
// 列表查询
|
||||
@PostMapping("/list")
|
||||
public ApiResponse list(@RequestBody ProjectReqQuery projectReqQuery) {
|
||||
return ApiResponse.success(projectService.list(projectReqQuery));
|
||||
}
|
||||
|
||||
// 详情查询
|
||||
@GetMapping("/getDetails/{id}")
|
||||
public ApiResponse getDetails(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(projectService.getById(id));
|
||||
}
|
||||
|
||||
// 新增或修改
|
||||
@PostMapping("/addOrUpdate")
|
||||
public ApiResponse addOrUpdate(@RequestBody ProjectEntity project) {
|
||||
return ApiResponse.success(projectService.addOrUpdate(project));
|
||||
}
|
||||
|
||||
// 删除
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse delete(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(projectService.delete(id));
|
||||
}
|
||||
|
||||
// 修改状态
|
||||
@PutMapping("/updateStatus/{id}")
|
||||
public ApiResponse updateStatus(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(projectService.updateStatus(id));
|
||||
}
|
||||
|
||||
// 根据项目ID下载小程序二维码
|
||||
@GetMapping("/{id}/QRCode")
|
||||
public ApiResponse<String> downloadQrCode(@PathVariable Long id) {
|
||||
ProjectRespVO project = projectService.getById(id);
|
||||
if (project == null) {
|
||||
return ApiResponse.fail("项目不存在");
|
||||
}
|
||||
MpConfigEntity mpConfig = scenicRepository.getScenicMpConfig(project.getScenicId());
|
||||
if (mpConfig == null) {
|
||||
return ApiResponse.fail("小程序配置不存在");
|
||||
}
|
||||
String appId = mpConfig.getAppId();
|
||||
String appSecret = mpConfig.getAppSecret();
|
||||
String appState = mpConfig.getState();
|
||||
String path = "pages/home/index?scenicId=" + project.getScenicId() + "&projectId=" + id;
|
||||
String filePath = "qr_code_project_" + id + ".jpg";
|
||||
IStorageAdapter adapter = StorageFactory.use();
|
||||
if (adapter.isExists(filePath)) {
|
||||
return ApiResponse.success(adapter.getUrl(filePath));
|
||||
}
|
||||
try {
|
||||
WxMpUtil.generateWXAQRCode(appId, appSecret, appState, path, filePath);
|
||||
File file = new File(filePath);
|
||||
String s = adapter.uploadFile(null, file, filePath);
|
||||
file.delete();
|
||||
adapter.setAcl(StorageAcl.PUBLIC_READ, filePath);
|
||||
return ApiResponse.success(s);
|
||||
} catch (Exception e) {
|
||||
return ApiResponse.fail("生成二维码失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,313 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.integration.questionnaire.dto.answer.ResponseDetailResponse;
|
||||
import com.ycwl.basic.integration.questionnaire.dto.questionnaire.CreateQuestionnaireRequest;
|
||||
import com.ycwl.basic.integration.questionnaire.dto.questionnaire.QuestionnaireResponse;
|
||||
import com.ycwl.basic.integration.questionnaire.dto.statistics.QuestionnaireStatistics;
|
||||
import com.ycwl.basic.integration.questionnaire.service.QuestionnaireIntegrationService;
|
||||
import com.ycwl.basic.integration.common.response.PageResponse;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.WxMpUtil;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 问卷管理 V2 版本控制器 - 基于 zt-questionnaire 集成服务
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-05
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/questionnaire/v2")
|
||||
@RequiredArgsConstructor
|
||||
public class QuestionnaireV2Controller {
|
||||
|
||||
private final QuestionnaireIntegrationService questionnaireIntegrationService;
|
||||
private final ScenicRepository scenicRepository;
|
||||
|
||||
// ========== 问卷管理 CRUD 操作 ==========
|
||||
|
||||
/**
|
||||
* 分页查询问卷列表
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public ApiResponse<PageResponse<QuestionnaireResponse>> listQuestionnaires(
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) Integer status,
|
||||
@RequestParam(required = false) String name) {
|
||||
log.info("分页查询问卷列表, page: {}, pageSize: {}, status: {}, name: {}",
|
||||
page, pageSize, status, name);
|
||||
|
||||
// 参数验证:限制pageSize最大值为100
|
||||
if (pageSize > 100) {
|
||||
pageSize = 100;
|
||||
}
|
||||
|
||||
try {
|
||||
PageResponse<QuestionnaireResponse> response =
|
||||
questionnaireIntegrationService.getQuestionnaireList(page, pageSize, name, status, null);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询问卷列表失败", e);
|
||||
return ApiResponse.fail("分页查询问卷列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取问卷详情
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<QuestionnaireResponse> getQuestionnaire(@PathVariable Long id) {
|
||||
log.info("获取问卷详情, id: {}", id);
|
||||
try {
|
||||
QuestionnaireResponse questionnaire = questionnaireIntegrationService.getQuestionnaire(id);
|
||||
return ApiResponse.success(questionnaire);
|
||||
} catch (Exception e) {
|
||||
log.error("获取问卷详情失败, id: {}", id, e);
|
||||
return ApiResponse.fail("获取问卷详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建问卷
|
||||
*/
|
||||
@PostMapping("/")
|
||||
public ApiResponse<QuestionnaireResponse> createQuestionnaire(@Valid @RequestBody CreateQuestionnaireRequest request) {
|
||||
log.info("创建问卷, name: {}, questions count: {}",
|
||||
request.getName(), request.getQuestions() != null ? request.getQuestions().size() : 0);
|
||||
try {
|
||||
QuestionnaireResponse questionnaire = questionnaireIntegrationService.createQuestionnaire(request, "admin");
|
||||
return ApiResponse.success(questionnaire);
|
||||
} catch (Exception e) {
|
||||
log.error("创建问卷失败", e);
|
||||
return ApiResponse.fail("创建问卷失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新问卷
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<QuestionnaireResponse> updateQuestionnaire(
|
||||
@PathVariable Long id,
|
||||
@Valid @RequestBody CreateQuestionnaireRequest request) {
|
||||
log.info("更新问卷, id: {}", id);
|
||||
try {
|
||||
QuestionnaireResponse questionnaire = questionnaireIntegrationService.updateQuestionnaire(id, request, "admin");
|
||||
return ApiResponse.success(questionnaire);
|
||||
} catch (Exception e) {
|
||||
log.error("更新问卷失败, id: {}", id, e);
|
||||
return ApiResponse.fail("更新问卷失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新问卷状态
|
||||
*/
|
||||
@PutMapping("/{id}/status")
|
||||
public ApiResponse<String> updateQuestionnaireStatus(@PathVariable Long id, @RequestBody Map<String, Integer> request) {
|
||||
Integer status = request.get("status");
|
||||
log.info("更新问卷状态, id: {}, status: {}", id, status);
|
||||
try {
|
||||
// 根据状态调用不同的方法
|
||||
if (status == 2) {
|
||||
questionnaireIntegrationService.publishQuestionnaire(id, "admin");
|
||||
} else if (status == 3) {
|
||||
questionnaireIntegrationService.stopQuestionnaire(id, "admin");
|
||||
}
|
||||
return ApiResponse.success("问卷状态更新成功");
|
||||
} catch (Exception e) {
|
||||
log.error("更新问卷状态失败, id: {}, status: {}", id, status, e);
|
||||
return ApiResponse.fail("更新问卷状态失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布问卷
|
||||
*/
|
||||
@PutMapping("/{id}/publish")
|
||||
public ApiResponse<String> publishQuestionnaire(@PathVariable Long id) {
|
||||
log.info("发布问卷, id: {}", id);
|
||||
try {
|
||||
questionnaireIntegrationService.publishQuestionnaire(id, "admin");
|
||||
return ApiResponse.success("问卷发布成功");
|
||||
} catch (Exception e) {
|
||||
log.error("发布问卷失败, id: {}", id, e);
|
||||
return ApiResponse.fail("发布问卷失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止问卷
|
||||
*/
|
||||
@PutMapping("/{id}/stop")
|
||||
public ApiResponse<String> stopQuestionnaire(@PathVariable Long id) {
|
||||
log.info("停止问卷, id: {}", id);
|
||||
try {
|
||||
questionnaireIntegrationService.stopQuestionnaire(id, "admin");
|
||||
return ApiResponse.success("问卷停止成功");
|
||||
} catch (Exception e) {
|
||||
log.error("停止问卷失败, id: {}", id, e);
|
||||
return ApiResponse.fail("停止问卷失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除问卷
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<String> deleteQuestionnaire(@PathVariable Long id) {
|
||||
log.info("删除问卷, id: {}", id);
|
||||
try {
|
||||
questionnaireIntegrationService.deleteQuestionnaire(id, "admin");
|
||||
return ApiResponse.success("问卷删除成功");
|
||||
} catch (Exception e) {
|
||||
log.error("删除问卷失败, id: {}", id, e);
|
||||
return ApiResponse.fail("删除问卷失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 问卷答案查看操作 ==========
|
||||
|
||||
/**
|
||||
* 分页查询问卷答案
|
||||
*/
|
||||
@GetMapping("/{id}/answers")
|
||||
public ApiResponse<PageResponse<ResponseDetailResponse>> getQuestionnaireAnswers(
|
||||
@PathVariable Long id,
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) String userId,
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime) {
|
||||
log.info("分页查询问卷答案, questionnaireId: {}, page: {}, pageSize: {}, userId: {}",
|
||||
id, page, pageSize, userId);
|
||||
|
||||
// 参数验证:限制pageSize最大值为100
|
||||
if (pageSize > 100) {
|
||||
pageSize = 100;
|
||||
}
|
||||
|
||||
try {
|
||||
PageResponse<ResponseDetailResponse> response =
|
||||
questionnaireIntegrationService.getResponseList(page, pageSize, id, userId, startTime, endTime);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询问卷答案失败, questionnaireId: {}", id, e);
|
||||
return ApiResponse.fail("分页查询问卷答案失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特定答案详情
|
||||
*/
|
||||
@GetMapping("/{id}/answers/{answerId}")
|
||||
public ApiResponse<ResponseDetailResponse> getQuestionnaireAnswer(@PathVariable Long id, @PathVariable Long answerId) {
|
||||
log.info("获取问卷答案详情, questionnaireId: {}, answerId: {}", id, answerId);
|
||||
try {
|
||||
ResponseDetailResponse answer = questionnaireIntegrationService.getResponseDetail(answerId);
|
||||
return ApiResponse.success(answer);
|
||||
} catch (Exception e) {
|
||||
log.error("获取问卷答案详情失败, questionnaireId: {}, answerId: {}", id, answerId, e);
|
||||
return ApiResponse.fail("获取问卷答案详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户答题记录
|
||||
*/
|
||||
@GetMapping("/answers/user/{userId}")
|
||||
public ApiResponse<PageResponse<ResponseDetailResponse>> getUserAnswers(
|
||||
@PathVariable String userId,
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) Long questionnaireId) {
|
||||
log.info("查询用户答题记录, userId: {}, page: {}, pageSize: {}, questionnaireId: {}",
|
||||
userId, page, pageSize, questionnaireId);
|
||||
|
||||
// 参数验证:限制pageSize最大值为100
|
||||
if (pageSize > 100) {
|
||||
pageSize = 100;
|
||||
}
|
||||
|
||||
try {
|
||||
PageResponse<ResponseDetailResponse> response =
|
||||
questionnaireIntegrationService.getResponseList(page, pageSize, questionnaireId, userId, null, null);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("查询用户答题记录失败, userId: {}", userId, e);
|
||||
return ApiResponse.fail("查询用户答题记录失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 统计功能 ==========
|
||||
|
||||
/**
|
||||
* 获取问卷统计信息
|
||||
*/
|
||||
@GetMapping("/{id}/statistics")
|
||||
public ApiResponse<QuestionnaireStatistics> getQuestionnaireStatistics(@PathVariable Long id) {
|
||||
log.info("获取问卷统计信息, id: {}", id);
|
||||
try {
|
||||
QuestionnaireStatistics statistics = questionnaireIntegrationService.getStatistics(id);
|
||||
return ApiResponse.success(statistics);
|
||||
} catch (Exception e) {
|
||||
log.error("获取问卷统计信息失败, id: {}", id, e);
|
||||
return ApiResponse.fail("获取问卷统计信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载问卷小程序二维码
|
||||
*/
|
||||
@GetMapping("/{id}/QRCode")
|
||||
public ApiResponse<String> downloadQrCode(@PathVariable Long id) {
|
||||
log.info("下载问卷小程序二维码, id: {}", id);
|
||||
try {
|
||||
// 获取问卷详情
|
||||
QuestionnaireResponse questionnaire = questionnaireIntegrationService.getQuestionnaire(id);
|
||||
if (questionnaire == null) {
|
||||
return ApiResponse.fail("问卷不存在");
|
||||
}
|
||||
|
||||
MpConfigEntity mpConfig = scenicRepository.getScenicMpConfig(3930324797233434624L);
|
||||
if (mpConfig == null) {
|
||||
return ApiResponse.fail("小程序配置不存在");
|
||||
}
|
||||
|
||||
String appId = mpConfig.getAppId();
|
||||
String appSecret = mpConfig.getAppSecret();
|
||||
String appState = mpConfig.getState();
|
||||
String path = "pages/questionnaire/index?id=" + id;
|
||||
String filePath = "qr_code_questionnaire_" + id + ".jpg";
|
||||
|
||||
IStorageAdapter adapter = StorageFactory.use();
|
||||
if (adapter.isExists(filePath)) {
|
||||
return ApiResponse.success(adapter.getUrl(filePath));
|
||||
}
|
||||
|
||||
WxMpUtil.generateWXAQRCode(appId, appSecret, appState, path, filePath);
|
||||
File file = new File(filePath);
|
||||
String s = adapter.uploadFile(null, file, filePath);
|
||||
file.delete();
|
||||
adapter.setAcl(StorageAcl.PUBLIC_READ, filePath);
|
||||
return ApiResponse.success(s);
|
||||
} catch (Exception e) {
|
||||
log.error("生成问卷二维码失败, id: {}", id, e);
|
||||
return ApiResponse.fail("生成二维码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.ycwl.basic.model.pc.order.req.OrderReqQuery;
|
||||
import com.ycwl.basic.model.pc.order.resp.OrderRespVO;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -23,38 +25,38 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/refund/v1")
|
||||
// 退款订单管理
|
||||
@Api(tags = "退款订单管理")
|
||||
public class RefundController {
|
||||
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
// 审核退款: 审核退款
|
||||
@ApiOperation(value = "审核退款", notes = "审核退款")
|
||||
@PostMapping("/auditRefundOrder")
|
||||
public ApiResponse<?> auditRefundOrder(@RequestBody RefundOrderReq refundOrderReq) {
|
||||
return orderService.auditRefundOrder(refundOrderReq);
|
||||
}
|
||||
|
||||
|
||||
// 分页查询订单
|
||||
@ApiOperation("分页查询订单")
|
||||
@PostMapping("page")
|
||||
public ApiResponse<PageInfo<OrderRespVO>> pageQuery(@RequestBody OrderReqQuery query) {
|
||||
return orderService.refundPageQuery(query);
|
||||
}
|
||||
|
||||
// 订单列表查询
|
||||
@ApiOperation("订单列表查询")
|
||||
@PostMapping("list")
|
||||
public ApiResponse<List<OrderRespVO>> list(@RequestBody OrderReqQuery query) {
|
||||
return orderService.list(query);
|
||||
}
|
||||
// 订单详情查询
|
||||
@ApiOperation("订单详情查询")
|
||||
@GetMapping("detail/{id}")
|
||||
public ApiResponse<OrderRespVO> detail(@PathVariable("id") Long orderId) {
|
||||
return orderService.detail(orderId);
|
||||
}
|
||||
|
||||
|
||||
// 订单备注
|
||||
@ApiOperation("订单备注")
|
||||
@PostMapping("remark/{id}")
|
||||
public ApiResponse<?> updateRemark(@PathVariable("id") Long orderId, @RequestBody OrderEntity query) {
|
||||
orderService.remarkOrder(orderId, query);
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest;
|
||||
import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO;
|
||||
import com.ycwl.basic.integration.render.service.RenderWorkerConfigIntegrationService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 渲染工作器配置管理 V2 版本控制器
|
||||
* 基于 zt-render-worker 微服务标准接口实现
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-06
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/render/worker/config/v2")
|
||||
@RequiredArgsConstructor
|
||||
public class RenderWorkerConfigV2Controller {
|
||||
|
||||
private final RenderWorkerConfigIntegrationService configIntegrationService;
|
||||
|
||||
/**
|
||||
* 获取工作器所有配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @return 工作器配置列表
|
||||
*/
|
||||
@GetMapping("/{workerId}")
|
||||
public ApiResponse<List<RenderWorkerConfigV2DTO>> getWorkerConfigs(@PathVariable Long workerId) {
|
||||
log.info("获取渲染工作器配置列表, workerId: {}", workerId);
|
||||
|
||||
try {
|
||||
List<RenderWorkerConfigV2DTO> configs = configIntegrationService.getWorkerConfigs(workerId);
|
||||
return ApiResponse.success(configs);
|
||||
} catch (Exception e) {
|
||||
log.error("获取渲染工作器配置列表失败, workerId: {}", workerId, e);
|
||||
return ApiResponse.fail("获取渲染工作器配置列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作器平铺配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @return 平铺配置Map
|
||||
*/
|
||||
@GetMapping("/{workerId}/flat")
|
||||
public ApiResponse<Map<String, Object>> getWorkerFlatConfig(@PathVariable Long workerId) {
|
||||
log.info("获取渲染工作器平铺配置, workerId: {}", workerId);
|
||||
|
||||
try {
|
||||
Map<String, Object> flatConfig = configIntegrationService.getWorkerFlatConfig(workerId);
|
||||
return ApiResponse.success(flatConfig);
|
||||
} catch (Exception e) {
|
||||
log.error("获取渲染工作器平铺配置失败, workerId: {}", workerId, e);
|
||||
return ApiResponse.fail("获取渲染工作器平铺配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置键获取特定配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @param configKey 配置键
|
||||
* @return 配置信息
|
||||
*/
|
||||
@GetMapping("/{workerId}/key/{configKey}")
|
||||
public ApiResponse<RenderWorkerConfigV2DTO> getWorkerConfigByKey(@PathVariable Long workerId,
|
||||
@PathVariable String configKey) {
|
||||
log.info("根据配置键获取渲染工作器配置, workerId: {}, configKey: {}", workerId, configKey);
|
||||
|
||||
try {
|
||||
RenderWorkerConfigV2DTO config = configIntegrationService.getWorkerConfigByKey(workerId, configKey);
|
||||
return ApiResponse.success(config);
|
||||
} catch (Exception e) {
|
||||
log.error("根据配置键获取渲染工作器配置失败, workerId: {}, configKey: {}", workerId, configKey, e);
|
||||
return ApiResponse.fail("根据配置键获取渲染工作器配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建工作器配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @param config 配置信息
|
||||
* @return 创建的配置信息
|
||||
*/
|
||||
@PostMapping("/{workerId}")
|
||||
public ApiResponse<RenderWorkerConfigV2DTO> createWorkerConfig(@PathVariable Long workerId,
|
||||
@Valid @RequestBody RenderWorkerConfigV2DTO config) {
|
||||
log.info("创建渲染工作器配置, workerId: {}, configKey: {}", workerId, config.getConfigKey());
|
||||
|
||||
try {
|
||||
RenderWorkerConfigV2DTO result = configIntegrationService.createWorkerConfig(workerId, config);
|
||||
return ApiResponse.success(result);
|
||||
} catch (Exception e) {
|
||||
log.error("创建渲染工作器配置失败, workerId: {}", workerId, e);
|
||||
return ApiResponse.fail("创建渲染工作器配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新工作器配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @param configId 配置ID
|
||||
* @param updates 更新内容
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/{workerId}/{configId}")
|
||||
public ApiResponse<Void> updateWorkerConfig(@PathVariable Long workerId,
|
||||
@PathVariable Long configId,
|
||||
@Valid @RequestBody Map<String, Object> updates) {
|
||||
log.info("更新渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
|
||||
|
||||
try {
|
||||
configIntegrationService.updateWorkerConfig(workerId, configId, updates);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("更新渲染工作器配置失败, workerId: {}, configId: {}", workerId, configId, e);
|
||||
return ApiResponse.fail("更新渲染工作器配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除工作器配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @param configId 配置ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/{workerId}/{configId}")
|
||||
public ApiResponse<Void> deleteWorkerConfig(@PathVariable Long workerId,
|
||||
@PathVariable Long configId) {
|
||||
log.info("删除渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
|
||||
|
||||
try {
|
||||
configIntegrationService.deleteWorkerConfig(workerId, configId);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("删除渲染工作器配置失败, workerId: {}, configId: {}", workerId, configId, e);
|
||||
return ApiResponse.fail("删除渲染工作器配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新工作器配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @param request 批量配置请求
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/{workerId}/batch")
|
||||
public ApiResponse<Void> batchUpdateWorkerConfigs(@PathVariable Long workerId,
|
||||
@Valid @RequestBody BatchRenderWorkerConfigRequest request) {
|
||||
log.info("批量更新渲染工作器配置, workerId: {}, configCount: {}",
|
||||
workerId, request.getConfigs() != null ? request.getConfigs().size() : 0);
|
||||
|
||||
try {
|
||||
configIntegrationService.batchUpdateWorkerConfigs(workerId, request);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("批量更新渲染工作器配置失败, workerId: {}", workerId, e);
|
||||
return ApiResponse.fail("批量更新渲染工作器配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量平铺更新工作器配置
|
||||
*
|
||||
* @param workerId 工作器ID
|
||||
* @param flatConfigs 平铺配置Map
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/{workerId}/flat-batch")
|
||||
public ApiResponse<Void> batchFlatUpdateWorkerConfigs(@PathVariable Long workerId,
|
||||
@Valid @RequestBody Map<String, Object> flatConfigs) {
|
||||
log.info("批量平铺更新渲染工作器配置, workerId: {}, configCount: {}", workerId, flatConfigs.size());
|
||||
|
||||
try {
|
||||
configIntegrationService.batchFlatUpdateWorkerConfigs(workerId, flatConfigs);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("批量平铺更新渲染工作器配置失败, workerId: {}", workerId, e);
|
||||
return ApiResponse.fail("批量平铺更新渲染工作器配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
|
||||
import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery;
|
||||
import com.ycwl.basic.service.pc.RenderWorkerService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/3 14:59
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/renderWorker/v1")
|
||||
@Api(tags = "渲染机管理")
|
||||
public class RenderWorkerController {
|
||||
|
||||
@Autowired
|
||||
private RenderWorkerService renderWorkerService;
|
||||
|
||||
@ApiOperation("分页查询渲染机")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse pageQuery(@RequestBody RenderWorkerReqQuery renderWorkerReqQuery){
|
||||
return renderWorkerService.pageQuery(renderWorkerReqQuery);
|
||||
}
|
||||
@ApiOperation("渲染机列表查询")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse list(@RequestBody RenderWorkerReqQuery renderWorkerReqQuery){
|
||||
return renderWorkerService.list(renderWorkerReqQuery);
|
||||
}
|
||||
@ApiOperation("渲染机详情查询")
|
||||
@GetMapping("/detail/{id}")
|
||||
public ApiResponse detail(@PathVariable Long id){
|
||||
return renderWorkerService.detail(id);
|
||||
}
|
||||
|
||||
@ApiOperation("渲染机新增")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse add(@RequestBody RenderWorkerEntity renderWorker){
|
||||
return renderWorkerService.add(renderWorker);
|
||||
}
|
||||
|
||||
@ApiOperation("渲染机删除")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse deleteById(@PathVariable Long id){
|
||||
return renderWorkerService.deleteById(id);
|
||||
}
|
||||
|
||||
@ApiOperation("渲染机修改")
|
||||
@PostMapping("/update")
|
||||
public ApiResponse update(@RequestBody RenderWorkerEntity renderWorker){
|
||||
return renderWorkerService.update(renderWorker);
|
||||
}
|
||||
|
||||
@ApiOperation("渲染机修改状态")
|
||||
@PutMapping("/updateStatus/{id}")
|
||||
public ApiResponse updateStatus(@PathVariable Long id) {
|
||||
return renderWorkerService.updateStatus(id);
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.dto.RenderWorkerWithStatusDTO;
|
||||
import com.ycwl.basic.integration.common.response.PageResponse;
|
||||
import com.ycwl.basic.integration.render.dto.worker.CreateRenderWorkerRequest;
|
||||
import com.ycwl.basic.integration.render.dto.worker.RenderWorkerV2DTO;
|
||||
import com.ycwl.basic.integration.render.dto.worker.UpdateRenderWorkerRequest;
|
||||
import com.ycwl.basic.integration.render.service.RenderWorkerIntegrationService;
|
||||
import com.ycwl.basic.model.task.req.ClientStatusReqVo;
|
||||
import com.ycwl.basic.repository.RenderWorkerRepository;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 渲染工作器管理 V2 版本控制器
|
||||
* 基于 zt-render-worker 微服务标准接口实现
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-06
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/render/worker/v2")
|
||||
@RequiredArgsConstructor
|
||||
public class RenderWorkerV2Controller {
|
||||
|
||||
private final RenderWorkerIntegrationService renderWorkerIntegrationService;
|
||||
private final RenderWorkerRepository renderWorkerRepository;
|
||||
|
||||
/**
|
||||
* 分页查询渲染工作器列表(带保活信息)
|
||||
*
|
||||
* @param page 页码,从1开始
|
||||
* @param pageSize 每页大小,默认10,最大100
|
||||
* @param isEnabled 是否启用(0-禁用,1-启用)
|
||||
* @param name 工作器名称(模糊搜索)
|
||||
* @return 分页查询结果(包含保活信息)
|
||||
*/
|
||||
@GetMapping
|
||||
public ApiResponse<PageResponse<RenderWorkerWithStatusDTO>> listWorkers(
|
||||
@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) Integer isEnabled,
|
||||
@RequestParam(required = false) String name) {
|
||||
|
||||
log.debug("分页查询渲染工作器列表, page: {}, pageSize: {}, isEnabled: {}, name: {}",
|
||||
page, pageSize, isEnabled, name);
|
||||
|
||||
// 参数验证:限制pageSize最大值为100
|
||||
if (pageSize > 100) {
|
||||
pageSize = 100;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取基础工作器列表
|
||||
PageResponse<RenderWorkerV2DTO> basicResult = renderWorkerIntegrationService.listWorkers(
|
||||
page, pageSize, isEnabled, name);
|
||||
|
||||
// 转换为带保活信息的DTO列表
|
||||
List<RenderWorkerWithStatusDTO> workersWithStatus = new ArrayList<>();
|
||||
for (RenderWorkerV2DTO worker : basicResult.getList()) {
|
||||
RenderWorkerWithStatusDTO workerWithStatus = new RenderWorkerWithStatusDTO();
|
||||
|
||||
// 复制基础信息
|
||||
BeanUtils.copyProperties(worker, workerWithStatus);
|
||||
|
||||
// 查询保活信息
|
||||
ClientStatusReqVo hostStatus = renderWorkerRepository.getWorkerHostStatus(worker.getId());
|
||||
workerWithStatus.setHostStatus(hostStatus);
|
||||
workerWithStatus.setIsOnline(hostStatus != null);
|
||||
|
||||
workersWithStatus.add(workerWithStatus);
|
||||
}
|
||||
|
||||
// 构建带保活信息的分页响应
|
||||
PageResponse<RenderWorkerWithStatusDTO> result = new PageResponse<>();
|
||||
result.setList(workersWithStatus);
|
||||
result.setTotal(basicResult.getTotal());
|
||||
result.setPage(basicResult.getPage());
|
||||
result.setPageSize(basicResult.getPageSize());
|
||||
|
||||
return ApiResponse.success(result);
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询渲染工作器列表失败", e);
|
||||
return ApiResponse.fail("分页查询渲染工作器列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取渲染工作器详情
|
||||
*
|
||||
* @param id 工作器ID
|
||||
* @return 工作器详情
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ApiResponse<RenderWorkerV2DTO> getWorker(@PathVariable Long id) {
|
||||
log.debug("获取渲染工作器详情, id: {}", id);
|
||||
|
||||
try {
|
||||
RenderWorkerV2DTO worker = renderWorkerIntegrationService.getWorker(id);
|
||||
return ApiResponse.success(worker);
|
||||
} catch (Exception e) {
|
||||
log.error("获取渲染工作器详情失败, id: {}", id, e);
|
||||
return ApiResponse.fail("获取渲染工作器详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建渲染工作器
|
||||
*
|
||||
* @param request 创建请求
|
||||
* @return 创建的工作器信息
|
||||
*/
|
||||
@PostMapping
|
||||
public ApiResponse<RenderWorkerV2DTO> createWorker(@Valid @RequestBody CreateRenderWorkerRequest request) {
|
||||
log.debug("创建渲染工作器, name: {}, key: {}, isActive: {}",
|
||||
request.getName(), request.getKey(), request.getIsActive());
|
||||
|
||||
try {
|
||||
RenderWorkerV2DTO worker = renderWorkerIntegrationService.createWorker(request);
|
||||
return ApiResponse.success(worker);
|
||||
} catch (Exception e) {
|
||||
log.error("创建渲染工作器失败", e);
|
||||
return ApiResponse.fail("创建渲染工作器失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新渲染工作器
|
||||
*
|
||||
* @param id 工作器ID
|
||||
* @param request 更新请求
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<Void> updateWorker(@PathVariable Long id,
|
||||
@Valid @RequestBody UpdateRenderWorkerRequest request) {
|
||||
log.debug("更新渲染工作器, id: {}, name: {}, isActive: {}",
|
||||
id, request.getName(), request.getIsActive());
|
||||
|
||||
try {
|
||||
renderWorkerIntegrationService.updateWorker(id, request);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("更新渲染工作器失败, id: {}", id, e);
|
||||
return ApiResponse.fail("更新渲染工作器失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除渲染工作器
|
||||
*
|
||||
* @param id 工作器ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<Void> deleteWorker(@PathVariable Long id) {
|
||||
log.debug("删除渲染工作器, id: {}", id);
|
||||
|
||||
try {
|
||||
renderWorkerIntegrationService.deleteWorker(id);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("删除渲染工作器失败, id: {}", id, e);
|
||||
return ApiResponse.fail("删除渲染工作器失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,62 +2,56 @@ 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 org.apache.commons.lang3.StringUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/role/v1")
|
||||
// 系统角色管理
|
||||
@Api(tags = "系统角色管理")
|
||||
public class RoleController {
|
||||
|
||||
@Autowired
|
||||
RoleService roleService;
|
||||
|
||||
@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")
|
||||
// 角色权限列表
|
||||
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);
|
||||
}
|
||||
@@ -65,7 +59,8 @@ public class RoleController {
|
||||
|
||||
|
||||
@GetMapping(value = "/updateStatus/{id}")
|
||||
// 更改角色类型状态
|
||||
@ApiOperation(value = "更改角色类型状态")
|
||||
//@IgnoreToken
|
||||
public ApiResponse updateStatus(@PathVariable("id") String id) {
|
||||
return roleService.updateStatus(id);
|
||||
}
|
||||
|
||||
@@ -39,13 +39,6 @@ public class ScenicAccountController {
|
||||
return result > 0 ? ApiResponse.success("更新成功") : ApiResponse.fail("更新失败");
|
||||
}
|
||||
|
||||
// 激活/停用景区账号
|
||||
@PostMapping("/updateActiveStatus/{id}")
|
||||
public ApiResponse updateActiveStatus(@PathVariable Long id) {
|
||||
int result = service.updateActiveStatus(id);
|
||||
return result > 0 ? ApiResponse.success("操作成功") : ApiResponse.fail("操作失败");
|
||||
}
|
||||
|
||||
// 更新景区账号
|
||||
@PostMapping("/update")
|
||||
public ApiResponse updateScenicAccount(@RequestBody ScenicAccountEntity entity) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
import com.ycwl.basic.service.mobile.AppScenicService;
|
||||
import com.ycwl.basic.service.mobile.AppStatisticsService;
|
||||
import com.ycwl.basic.service.pc.ScenicAccountService;
|
||||
@@ -16,20 +17,18 @@ import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.WxMpUtil;
|
||||
import org.apache.commons.lang3.Strings;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
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.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.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.ADMIN;
|
||||
import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
|
||||
/**
|
||||
@@ -38,7 +37,7 @@ import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/scenic/v1")
|
||||
// 景区管理
|
||||
@Api(tags = "景区管理")
|
||||
public class ScenicController {
|
||||
|
||||
@Autowired
|
||||
@@ -53,7 +52,69 @@ public class ScenicController {
|
||||
@Autowired
|
||||
private ScenicAccountService accountService;
|
||||
|
||||
// 根据景区ID下载小程序二维码
|
||||
@ApiOperation("分页查询景区")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<ScenicRespVO>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery) {
|
||||
return scenicService.pageQuery(scenicReqQuery);
|
||||
}
|
||||
@ApiOperation("查询景区列表")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse<List<ScenicRespVO>> list(@RequestBody ScenicReqQuery scenicReqQuery) {
|
||||
return scenicService.list(scenicReqQuery);
|
||||
}
|
||||
@ApiOperation("查询景区详情")
|
||||
@GetMapping("/getDetail/{id}")
|
||||
public ApiResponse<ScenicRespVO> getDetail(@PathVariable Long id) {
|
||||
return scenicService.getById(id);
|
||||
}
|
||||
@ApiOperation("新增景区")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<Boolean> add(@RequestBody ScenicAddOrUpdateReq scenicAddReq) {
|
||||
return scenicService.add(scenicAddReq);
|
||||
}
|
||||
@ApiOperation("删除景区")
|
||||
@GetMapping("/delete/{id}")
|
||||
public ApiResponse<Boolean> delete(@PathVariable Long id) {
|
||||
return scenicService.deleteById(id);
|
||||
}
|
||||
@ApiOperation("修改景区")
|
||||
@PostMapping("/update")
|
||||
public ApiResponse<Boolean> update(@RequestBody ScenicAddOrUpdateReq scenicAddReq) {
|
||||
return scenicService.update(scenicAddReq);
|
||||
}
|
||||
@ApiOperation("修改景区状态")
|
||||
@GetMapping("/updateStatus/{id}")
|
||||
public ApiResponse<Boolean> updateStatus(@PathVariable Long id) {
|
||||
return scenicService.updateStatus(id);
|
||||
}
|
||||
@ApiOperation("新增景区配置")
|
||||
@PostMapping("/addConfig")
|
||||
public ApiResponse<Boolean> addConfig(@RequestBody ScenicConfigEntity scenicConfig) {
|
||||
return scenicService.addConfig(scenicConfig);
|
||||
}
|
||||
@ApiOperation("修改景区配置")
|
||||
@PostMapping("/updateConfig")
|
||||
public ApiResponse<Boolean> updateConfig(@RequestBody ScenicConfigEntity scenicConfig) {
|
||||
return scenicService.updateConfigById(scenicConfig);
|
||||
}
|
||||
|
||||
@ApiOperation("查询景区配置")
|
||||
@GetMapping("/config/{id}")
|
||||
public ApiResponse<ScenicConfigEntity> getConfig(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(scenicService.getConfig(id));
|
||||
}
|
||||
@PostMapping("/saveConfig/{id}")
|
||||
public ApiResponse saveConfig(@PathVariable("id") Long id, @RequestBody ScenicConfigEntity config) {
|
||||
scenicService.saveConfig(id, config);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
@PostMapping("/saveConfig/undefined")
|
||||
public ApiResponse saveConfig(@RequestBody ScenicConfigEntity config) {
|
||||
scenicService.addConfig(config);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@ApiOperation("根据景区ID下载小程序二维码")
|
||||
@GetMapping("/{id}/QRCode")
|
||||
public ApiResponse<String> downloadQrCode(@PathVariable Long id) {
|
||||
MpConfigEntity mpConfig = scenicRepository.getScenicMpConfig(id);
|
||||
@@ -108,19 +169,19 @@ public class ScenicController {
|
||||
}
|
||||
|
||||
@GetMapping("/myScenicList")
|
||||
public ApiResponse<List<ScenicV2DTO>> myScenicList() {
|
||||
List<ScenicV2DTO> list = Collections.emptyList();
|
||||
if (Strings.CS.equals(BaseContextHandler.getRoleId(), MERCHANT.type)) {
|
||||
public ApiResponse<List<ScenicRespVO>> myScenicList() {
|
||||
List<ScenicRespVO> list = Collections.emptyList();
|
||||
if (StringUtils.equals(BaseContextHandler.getRoleId(), MERCHANT.type)) {
|
||||
String userId = BaseContextHandler.getUserId();
|
||||
ScenicAccountEntity account = accountService.getScenicAccountById(Long.valueOf(userId));
|
||||
if (account == null || account.getScenicId().isEmpty()) {
|
||||
return ApiResponse.fail("景区账号未绑定景区");
|
||||
}
|
||||
list = account.getScenicId().stream().map(id -> scenicRepository.getScenicBasic(id)).toList();
|
||||
} else if (Strings.CS.equals(BaseContextHandler.getRoleId(), ADMIN.type)) {
|
||||
ScenicReqQuery query = new ScenicReqQuery();
|
||||
query.setPageSize(1000);
|
||||
list = scenicRepository.list(query);
|
||||
list = account.getScenicId().stream().map(id -> {
|
||||
return appScenicService.getDetails(id).getData();
|
||||
}).toList();
|
||||
} else {
|
||||
list = scenicService.list(new ScenicReqQuery()).getData();
|
||||
}
|
||||
return ApiResponse.success(list);
|
||||
}
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.integration.scenic.dto.config.BatchConfigRequest;
|
||||
import com.ycwl.basic.integration.scenic.dto.config.BatchUpdateResponse;
|
||||
import com.ycwl.basic.integration.scenic.dto.config.CreateConfigRequest;
|
||||
import com.ycwl.basic.integration.scenic.dto.config.ScenicConfigV2DTO;
|
||||
import com.ycwl.basic.integration.scenic.dto.config.UpdateConfigRequest;
|
||||
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterPageResponse;
|
||||
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.integration.common.response.PageResponse;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
|
||||
import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService;
|
||||
import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
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.PutMapping;
|
||||
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 java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/26
|
||||
* 景区管理 V2 版本控制器 - 基于 zt-scenic 集成服务
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/scenic/v2")
|
||||
@RequiredArgsConstructor
|
||||
public class ScenicV2Controller {
|
||||
|
||||
private final ScenicIntegrationService scenicIntegrationService;
|
||||
private final ScenicConfigIntegrationService scenicConfigIntegrationService;
|
||||
|
||||
// ========== 景区基础 CRUD 操作 ==========
|
||||
|
||||
/**
|
||||
* 景区V2核心信息分页列表
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public ApiResponse<PageResponse<ScenicV2DTO>> listScenics(@RequestParam(defaultValue = "1") Integer page,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) Integer status,
|
||||
@RequestParam(required = false) String name) {
|
||||
log.info("分页查询景区核心信息列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name);
|
||||
|
||||
// 参数验证:限制pageSize最大值为100
|
||||
if (pageSize > 100) {
|
||||
pageSize = 100;
|
||||
}
|
||||
|
||||
try {
|
||||
PageResponse<ScenicV2DTO> response = scenicIntegrationService.listScenics(page, pageSize, status, name, null);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询景区核心信息列表失败", e);
|
||||
return ApiResponse.fail("分页查询景区列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单个景区详情
|
||||
*/
|
||||
@GetMapping("/{scenicId}")
|
||||
public ApiResponse<ScenicV2DTO> getScenic(@PathVariable Long scenicId) {
|
||||
log.info("查询景区详情, scenicId: {}", scenicId);
|
||||
try {
|
||||
ScenicV2DTO scenic = scenicIntegrationService.getScenic(scenicId);
|
||||
return ApiResponse.success(scenic);
|
||||
} catch (Exception e) {
|
||||
log.error("查询景区详情失败, scenicId: {}", scenicId, e);
|
||||
return ApiResponse.fail("查询景区详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询景区列表(支持筛选和分页)- 高级筛选
|
||||
*/
|
||||
@PostMapping("/filter")
|
||||
public ApiResponse<ScenicFilterPageResponse> filterScenics(@RequestBody @Valid ScenicFilterRequest request) {
|
||||
log.info("高级筛选景区列表, 筛选条件数: {}, 页码: {}, 页大小: {}",
|
||||
request.getFilters().size(), request.getPage(), request.getPageSize());
|
||||
try {
|
||||
ScenicFilterPageResponse response = scenicIntegrationService.filterScenics(request);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("高级筛选景区列表失败", e);
|
||||
return ApiResponse.fail("高级筛选景区列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增景区
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public ApiResponse<ScenicV2DTO> createScenic(@RequestBody @Valid CreateScenicRequest request) {
|
||||
log.info("新增景区, name: {}, mpId: {}", request.getName(), request.getMpId());
|
||||
try {
|
||||
ScenicV2DTO scenic = scenicIntegrationService.createScenic(request);
|
||||
return ApiResponse.success(scenic);
|
||||
} catch (Exception e) {
|
||||
log.error("新增景区失败, name: {}", request.getName(), e);
|
||||
return ApiResponse.fail("新增景区失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改景区
|
||||
*/
|
||||
@PutMapping("/{scenicId}")
|
||||
public ApiResponse<ScenicV2DTO> updateScenic(@PathVariable Long scenicId,
|
||||
@RequestBody @Valid UpdateScenicRequest request) {
|
||||
log.info("修改景区, scenicId: {}", scenicId);
|
||||
try {
|
||||
ScenicV2DTO scenic = scenicIntegrationService.updateScenic(scenicId, request);
|
||||
return ApiResponse.success(scenic);
|
||||
} catch (Exception e) {
|
||||
log.error("修改景区失败, scenicId: {}", scenicId, e);
|
||||
return ApiResponse.fail("修改景区失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除景区
|
||||
*/
|
||||
@DeleteMapping("/{scenicId}")
|
||||
public ApiResponse<Void> deleteScenic(@PathVariable Long scenicId) {
|
||||
log.info("删除景区, scenicId: {}", scenicId);
|
||||
try {
|
||||
scenicIntegrationService.deleteScenic(scenicId);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("删除景区失败, scenicId: {}", scenicId, e);
|
||||
return ApiResponse.fail("删除景区失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 景区列表查询(默认1000条)
|
||||
* 只支持根据状态筛选
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public ApiResponse<PageResponse<ScenicV2DTO>> listScenicsByStatus(@RequestParam(required = false) Integer status) {
|
||||
log.info("查询景区列表, status: {}", status);
|
||||
try {
|
||||
// 默认查询1000条数据,第1页
|
||||
PageResponse<ScenicV2DTO> scenics = scenicIntegrationService.listScenics(1, 1000, status, null, null);
|
||||
return ApiResponse.success(scenics);
|
||||
} catch (Exception e) {
|
||||
log.error("查询景区列表失败, status: {}", status, e);
|
||||
return ApiResponse.fail("查询景区列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ========== 景区配置管理 ==========
|
||||
|
||||
/**
|
||||
* 获取景区配置列表
|
||||
*/
|
||||
@GetMapping("/{scenicId}/config")
|
||||
public ApiResponse<List<ScenicConfigV2DTO>> listConfigs(@PathVariable Long scenicId) {
|
||||
log.info("获取景区配置列表, scenicId: {}", scenicId);
|
||||
try {
|
||||
List<ScenicConfigV2DTO> configs = scenicConfigIntegrationService.listConfigs(scenicId);
|
||||
return ApiResponse.success(configs);
|
||||
} catch (Exception e) {
|
||||
log.error("获取景区配置列表失败, scenicId: {}", scenicId, e);
|
||||
return ApiResponse.fail("获取景区配置列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置键获取配置
|
||||
*/
|
||||
@GetMapping("/{scenicId}/config/{configKey}")
|
||||
public ApiResponse<ScenicConfigV2DTO> getConfigByKey(@PathVariable Long scenicId,
|
||||
@PathVariable String configKey) {
|
||||
log.info("根据键获取景区配置, scenicId: {}, configKey: {}", scenicId, configKey);
|
||||
try {
|
||||
ScenicConfigV2DTO config = scenicConfigIntegrationService.getConfigByKey(scenicId, configKey);
|
||||
return ApiResponse.success(config);
|
||||
} catch (Exception e) {
|
||||
log.error("根据键获取景区配置失败, scenicId: {}, configKey: {}", scenicId, configKey, e);
|
||||
return ApiResponse.fail("获取配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建景区配置
|
||||
*/
|
||||
@PostMapping("/{scenicId}/config")
|
||||
public ApiResponse<ScenicConfigV2DTO> createConfig(@PathVariable Long scenicId,
|
||||
@RequestBody @Valid CreateConfigRequest request) {
|
||||
log.info("创建景区配置, scenicId: {}, configKey: {}", scenicId, request.getConfigKey());
|
||||
try {
|
||||
ScenicConfigV2DTO config = scenicConfigIntegrationService.createConfig(scenicId, request);
|
||||
return ApiResponse.success(config);
|
||||
} catch (Exception e) {
|
||||
log.error("创建景区配置失败, scenicId: {}, configKey: {}", scenicId, request.getConfigKey(), e);
|
||||
return ApiResponse.fail("创建配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新景区配置
|
||||
*/
|
||||
@PutMapping("/{scenicId}/config/{configId}")
|
||||
public ApiResponse<ScenicConfigV2DTO> updateConfig(@PathVariable Long scenicId,
|
||||
@PathVariable String configId,
|
||||
@RequestBody @Valid UpdateConfigRequest request) {
|
||||
log.info("更新景区配置, scenicId: {}, configId: {}", scenicId, configId);
|
||||
try {
|
||||
ScenicConfigV2DTO config = scenicConfigIntegrationService.updateConfig(scenicId, configId, request);
|
||||
return ApiResponse.success(config);
|
||||
} catch (Exception e) {
|
||||
log.error("更新景区配置失败, scenicId: {}, configId: {}", scenicId, configId, e);
|
||||
return ApiResponse.fail("更新配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除景区配置
|
||||
*/
|
||||
@DeleteMapping("/{scenicId}/config/{configId}")
|
||||
public ApiResponse<Void> deleteConfig(@PathVariable Long scenicId, @PathVariable String configId) {
|
||||
log.info("删除景区配置, scenicId: {}, configId: {}", scenicId, configId);
|
||||
try {
|
||||
scenicConfigIntegrationService.deleteConfig(scenicId, configId);
|
||||
return ApiResponse.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("删除景区配置失败, scenicId: {}, configId: {}", scenicId, configId, e);
|
||||
return ApiResponse.fail("删除配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新景区配置
|
||||
*/
|
||||
@PutMapping("/{scenicId}/config/batch")
|
||||
public ApiResponse<BatchUpdateResponse> batchUpdateConfigs(@PathVariable Long scenicId,
|
||||
@RequestBody @Valid BatchConfigRequest request) {
|
||||
log.info("批量更新景区配置, scenicId: {}, configs count: {}", scenicId, request.getConfigs().size());
|
||||
try {
|
||||
BatchUpdateResponse response = scenicConfigIntegrationService.batchUpdateConfigs(scenicId, request);
|
||||
return ApiResponse.success(response);
|
||||
} catch (Exception e) {
|
||||
log.error("批量更新景区配置失败, scenicId: {}", scenicId, e);
|
||||
return ApiResponse.fail("批量更新配置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.ycwl.basic.model.pc.source.req.SourceReqQuery;
|
||||
import com.ycwl.basic.service.pc.SourceService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -16,19 +18,20 @@ import org.springframework.web.bind.annotation.*;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/source/v1")
|
||||
// 视频源管理
|
||||
@Api(tags = "视频源管理")
|
||||
public class SourceController {
|
||||
|
||||
@Autowired
|
||||
private SourceService sourceService;
|
||||
|
||||
// 分页查询视频源
|
||||
@Deprecated
|
||||
@ApiOperation("分页查询视频源")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse pageQuery(@RequestBody SourceReqQuery sourceReqQuery) {
|
||||
return sourceService.pageQuery(sourceReqQuery);
|
||||
}
|
||||
@Deprecated
|
||||
// 查询视频源列表
|
||||
@ApiOperation("查询视频源列表")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse list(@RequestBody SourceReqQuery sourceReqQuery) {
|
||||
return sourceService.list(sourceReqQuery);
|
||||
@@ -39,7 +42,7 @@ public class SourceController {
|
||||
return sourceService.cutVideo(id);
|
||||
}
|
||||
@Deprecated
|
||||
// 删除视频源
|
||||
@ApiOperation("删除视频源")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse deleteById(@PathVariable Long id) {
|
||||
return sourceService.deleteById(id);
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.ycwl.basic.controller.pc;
|
||||
|
||||
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
|
||||
import com.ycwl.basic.model.pc.statistics.resp.OrderStatisticsResp;
|
||||
import com.ycwl.basic.service.mobile.AppStatisticsService;
|
||||
import com.ycwl.basic.service.pc.StatisticsService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/12 14:30
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/statistics/v1")
|
||||
public class StatisticsController {
|
||||
|
||||
@Autowired
|
||||
private StatisticsService statisticsService;
|
||||
|
||||
@Autowired
|
||||
private AppStatisticsService appStatisticsService;
|
||||
|
||||
/**
|
||||
* 智能获取扫码访问人数统计数据(自动选择粒度)
|
||||
* @param query 查询参数(包含景区ID、开始时间、结束时间;如果scenicId为空则统计全部景区,否则统计指定景区)
|
||||
* @return 统计数据(超过7天返回日期级别,否则返回小时级别)
|
||||
*/
|
||||
@PostMapping("/scanCodeMemberChart")
|
||||
public ApiResponse<List<HashMap<String, String>>> getScanCodeMemberChart(@RequestBody CommonQueryReq query) {
|
||||
return ApiResponse.success(statisticsService.getScanCodeMemberChartAuto(query));
|
||||
}
|
||||
|
||||
@PostMapping("/one")
|
||||
public ApiResponse getStatisticsOne(@RequestBody CommonQueryReq query) {
|
||||
return appStatisticsService.oneStatistics(query);
|
||||
}
|
||||
|
||||
@PostMapping("/two")
|
||||
public ApiResponse getStatisticsTwo(@RequestBody CommonQueryReq query) {
|
||||
return appStatisticsService.twoStatistics(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单统计数据(包含订单数量和金额、推送订单数量、现场订单数量)
|
||||
* @param query 查询参数(包含景区ID、开始时间、结束时间;如果scenicId为空则统计全部景区,否则统计指定景区)
|
||||
* @return 统计数据(totalOrderCount: 总订单数量, totalOrderAmount: 总订单金额, pushOrderCount: 推送订单数量, sceneOrderCount: 现场订单数量)
|
||||
*/
|
||||
@PostMapping("/orderStatistics")
|
||||
public ApiResponse<OrderStatisticsResp> getOrderStatistics(@RequestBody CommonQueryReq query) {
|
||||
return ApiResponse.success(statisticsService.getOrderStatistics(query));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import com.ycwl.basic.model.pc.task.entity.TaskEntity;
|
||||
import com.ycwl.basic.model.pc.task.req.TaskReqQuery;
|
||||
import com.ycwl.basic.service.pc.TaskService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -13,38 +15,39 @@ import org.springframework.web.bind.annotation.*;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/task/v1")
|
||||
// 任务列表管理
|
||||
@Deprecated
|
||||
@Api(tags = "任务列表管理")
|
||||
public class TaskController {
|
||||
|
||||
@Autowired
|
||||
private TaskService taskService;
|
||||
|
||||
// 分页查询任务列表
|
||||
@ApiOperation("分页查询任务列表")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse pageQuery(@RequestBody TaskReqQuery taskReqQuery) {
|
||||
return taskService.pageQuery(taskReqQuery);
|
||||
}
|
||||
// 查询任务列表
|
||||
@ApiOperation("查询任务列表")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse list(@RequestBody TaskReqQuery taskReqQuery) {
|
||||
return taskService.list(taskReqQuery);
|
||||
}
|
||||
// 查询任务详情
|
||||
@ApiOperation("查询任务详情")
|
||||
@GetMapping("/getDetail/{id}")
|
||||
public ApiResponse getById(@PathVariable Long id) {
|
||||
return taskService.getById(id);
|
||||
}
|
||||
// 删除任务
|
||||
@ApiOperation("删除任务")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse deleteById(@PathVariable Long id) {
|
||||
return taskService.deleteById(id);
|
||||
}
|
||||
// 修改任务
|
||||
@ApiOperation("修改任务")
|
||||
@PostMapping("/update")
|
||||
public ApiResponse update(@RequestBody TaskEntity taskEntity) {
|
||||
return taskService.update(taskEntity);
|
||||
}
|
||||
// 修改任务状态
|
||||
@ApiOperation("修改任务状态")
|
||||
@PostMapping("/updateStatus")
|
||||
public ApiResponse updateStatus(@RequestParam Long id, @RequestParam Integer status) {
|
||||
return taskService.updateStatus(id,status);
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.ycwl.basic.model.pc.template.req.TemplateSortRequest;
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.service.pc.TemplateService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -20,60 +22,54 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/template/v1")
|
||||
// 模板管理
|
||||
@Api(tags = "模板管理")
|
||||
public class TemplateController {
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
// 分页查询模板
|
||||
@ApiOperation("分页查询模板")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<TemplateRespVO>> pageQuery(@RequestBody TemplateReqQuery templateReqQuery) {
|
||||
return templateService.pageQuery(templateReqQuery);
|
||||
}
|
||||
// 查询模板列表
|
||||
@ApiOperation("查询模板列表")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse<List<TemplateRespVO>> list(@RequestBody TemplateReqQuery templateReqQuery) {
|
||||
return templateService.list(templateReqQuery);
|
||||
}
|
||||
// 查询模板详情
|
||||
@ApiOperation("查询模板详情")
|
||||
@GetMapping("getDetail/{id}")
|
||||
public ApiResponse<TemplateRespVO> getById(@PathVariable Long id) {
|
||||
return templateService.getById(id);
|
||||
}
|
||||
// 添加模板
|
||||
@ApiOperation("添加模板")
|
||||
@PostMapping("/add")
|
||||
public ApiResponse<Boolean> add(@RequestBody TemplateEntity template) {
|
||||
return templateService.add(template);
|
||||
}
|
||||
// 删除模板
|
||||
@ApiOperation("删除模板")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ApiResponse<Integer> deleteById(@PathVariable Long id) {
|
||||
return templateService.deleteById(id);
|
||||
}
|
||||
// 修改模板
|
||||
@ApiOperation("修改模板")
|
||||
@PostMapping("/update")
|
||||
public ApiResponse<Boolean> update(@RequestBody TemplateEntity template) {
|
||||
return templateService.update(template);
|
||||
}
|
||||
// 修改模板状态
|
||||
@ApiOperation("修改模板状态")
|
||||
@PostMapping("/updateStatus/{id}")
|
||||
public ApiResponse<Boolean> updateStatus(@PathVariable("id") Long id) {
|
||||
return templateService.updateStatus(id);
|
||||
}
|
||||
|
||||
// 排序模板
|
||||
@ApiOperation("排序模板")
|
||||
@PostMapping("/sort")
|
||||
public ApiResponse<Boolean> sortTemplate(@RequestBody TemplateSortRequest request) {
|
||||
return templateService.sortTemplate(request.getTemplateId(), request.getAfterTemplateId());
|
||||
}
|
||||
|
||||
// 修改模板排序值
|
||||
@PostMapping("/updateSort/{id}")
|
||||
public ApiResponse<Boolean> updateSort(@PathVariable("id") Long id, @RequestParam Integer sort) {
|
||||
return templateService.updateSort(id, sort);
|
||||
}
|
||||
|
||||
@GetMapping("/config/{id}")
|
||||
public ApiResponse<TemplateConfigEntity> getConfig(@PathVariable("id") Long id) {
|
||||
return ApiResponse.success(templateService.getConfig(id));
|
||||
|
||||
@@ -6,6 +6,8 @@ import com.ycwl.basic.model.pc.video.req.VideoReqQuery;
|
||||
import com.ycwl.basic.model.pc.video.resp.VideoRespVO;
|
||||
import com.ycwl.basic.service.pc.VideoService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -18,38 +20,27 @@ import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/video/v1")
|
||||
// 视频成片管理
|
||||
@Deprecated
|
||||
@Api(tags = "视频成片管理")
|
||||
public class VideoController {
|
||||
|
||||
@Autowired
|
||||
private VideoService videoService;
|
||||
|
||||
// 分页查询成片
|
||||
@ApiOperation("分页查询成片")
|
||||
@PostMapping("/page")
|
||||
public ApiResponse<PageInfo<VideoRespVO>> pageQuery(@RequestBody VideoReqQuery videoReqQuery) {
|
||||
return videoService.pageQuery(videoReqQuery);
|
||||
}
|
||||
// 查询成片列表
|
||||
@ApiOperation("查询成片列表")
|
||||
@PostMapping("/list")
|
||||
public ApiResponse<List<VideoRespVO>> list(@RequestBody VideoReqQuery videoReqQuery) {
|
||||
return videoService.list(videoReqQuery);
|
||||
}
|
||||
// 查询成片详情
|
||||
@ApiOperation("查询成片详情")
|
||||
@GetMapping("/getDetail/{id}")
|
||||
public ApiResponse<VideoRespVO> getById(@PathVariable Long id) {
|
||||
return videoService.getById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询视频是否被购买
|
||||
*
|
||||
* @param videoId 视频ID
|
||||
* @return 是否已购买
|
||||
*/
|
||||
@GetMapping("/checkBuyStatus")
|
||||
public ApiResponse<Boolean> checkBuyStatus(@RequestParam("videoId") Long videoId) {
|
||||
Boolean isBuy = videoService.checkVideoBuyStatus(videoId);
|
||||
return ApiResponse.success(isBuy);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ import com.ycwl.basic.model.printer.resp.PrintTaskResp;
|
||||
import com.ycwl.basic.model.printer.resp.TaskSyncResp;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@IgnoreToken
|
||||
// 打印机对接接口
|
||||
@Api(tags = "打印机对接接口")
|
||||
@RestController
|
||||
@RequestMapping("/printer/v1")
|
||||
public class PrinterTaskController {
|
||||
|
||||
@@ -1,277 +0,0 @@
|
||||
package com.ycwl.basic.controller.printer;
|
||||
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.mapper.FaceMapper;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
|
||||
import com.ycwl.basic.repository.MemberRelationRepository;
|
||||
import com.ycwl.basic.repository.SourceRepository;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.service.task.TaskFaceService;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.model.printer.FaceRecognizeWithSourcesResp;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import com.ycwl.basic.utils.WxMpUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.ycwl.basic.constant.StorageConstant.USER_FACE;
|
||||
|
||||
@IgnoreToken
|
||||
// 打印机大屏对接接口
|
||||
@RestController
|
||||
@RequestMapping("/printer/v1/tv")
|
||||
@RequiredArgsConstructor
|
||||
public class PrinterTvController {
|
||||
|
||||
private final DeviceRepository deviceRepository;
|
||||
private final ScenicRepository scenicRepository;
|
||||
private final FaceRepository faceRepository;
|
||||
private final TaskFaceService faceService;
|
||||
private final FaceService pcFaceService;
|
||||
private final ScenicService scenicService;
|
||||
private final SourceMapper sourceMapper;
|
||||
private final FaceMapper faceMapper;
|
||||
private final MemberRelationRepository memberRelationRepository;
|
||||
private final SourceRepository sourceRepository;
|
||||
private final PrinterService printerService;
|
||||
|
||||
/**
|
||||
* 获取景区列表
|
||||
*
|
||||
* @return 景区列表
|
||||
*/
|
||||
@GetMapping("/scenic/list")
|
||||
public ApiResponse<List<ScenicV2DTO>> getScenicList() {
|
||||
ScenicReqQuery query = new ScenicReqQuery();
|
||||
query.setStatus("1"); // 只查询启用状态的景区
|
||||
query.setPageNum(1);
|
||||
query.setPageSize(1000);
|
||||
return ApiResponse.success(scenicRepository.list(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据景区ID查询设备列表
|
||||
*
|
||||
* @param scenicId 景区ID
|
||||
* @return 设备列表
|
||||
*/
|
||||
@GetMapping("/device/list")
|
||||
public ApiResponse<List<DeviceV2DTO>> getDeviceListByScenicId(@RequestParam Long scenicId) {
|
||||
List<DeviceV2DTO> result = deviceRepository.getAllDeviceByScenicId(scenicId);
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
@GetMapping("/{sampleId}/qrcode")
|
||||
public void getQrcode(@PathVariable("sampleId") Long sampleId, HttpServletResponse response) throws Exception {
|
||||
File qrcode = new File("qrcode_"+sampleId+".jpg");
|
||||
FaceSampleEntity faceSample = faceRepository.getFaceSample(sampleId);
|
||||
if (faceSample == null) {
|
||||
response.setStatus(404);
|
||||
return;
|
||||
}
|
||||
String targetPath = "pages/printer/from_sample";
|
||||
DeviceV2DTO device = deviceRepository.getDeviceBasic(faceSample.getDeviceId());
|
||||
if (device.getType().equals("AI_CAM")) {
|
||||
// AI_CAM,需要修改path
|
||||
targetPath = "pages/ai-cam/from_sample";
|
||||
}
|
||||
try {
|
||||
MpConfigEntity scenicMpConfig = scenicRepository.getScenicMpConfig(faceSample.getScenicId());
|
||||
WxMpUtil.generateUnlimitedWXAQRCode(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), targetPath, sampleId.toString(), qrcode);
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("image/jpeg");
|
||||
response.setHeader("Content-Disposition", "inline; filename=\"" + qrcode.getName() + "\"");
|
||||
|
||||
// 将二维码文件写入响应输出流
|
||||
try (FileInputStream fis = new FileInputStream(qrcode);
|
||||
OutputStream os = response.getOutputStream()) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
os.flush();
|
||||
}
|
||||
} finally {
|
||||
// 删除临时文件
|
||||
if (qrcode.exists()) {
|
||||
qrcode.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取人脸绑定二维码
|
||||
* 生成小程序二维码,用于绑定人脸到用户账号
|
||||
*
|
||||
* @param faceId 人脸ID
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
@GetMapping("/face/{faceId}/qrcode")
|
||||
public void getFaceQrcode(@PathVariable("faceId") Long faceId, HttpServletResponse response) throws Exception {
|
||||
File qrcode = new File("qrcode_face_" + faceId + ".jpg");
|
||||
try {
|
||||
FaceEntity face = faceRepository.getFace(faceId);
|
||||
if (face == null) {
|
||||
response.setStatus(404);
|
||||
return;
|
||||
}
|
||||
MpConfigEntity scenicMpConfig = scenicRepository.getScenicMpConfig(face.getScenicId());
|
||||
if (scenicMpConfig == null) {
|
||||
response.setStatus(500);
|
||||
return;
|
||||
}
|
||||
WxMpUtil.generateUnlimitedWXAQRCode(
|
||||
scenicMpConfig.getAppId(),
|
||||
scenicMpConfig.getAppSecret(),
|
||||
"pages/videoSynthesis/bind_face",
|
||||
faceId.toString(),
|
||||
qrcode
|
||||
);
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("image/jpeg");
|
||||
response.setHeader("Content-Disposition", "inline; filename=\"" + qrcode.getName() + "\"");
|
||||
|
||||
// 将二维码文件写入响应输出流
|
||||
try (FileInputStream fis = new FileInputStream(qrcode);
|
||||
OutputStream os = response.getOutputStream()) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
os.flush();
|
||||
}
|
||||
} finally {
|
||||
// 删除临时文件
|
||||
if (qrcode.exists()) {
|
||||
qrcode.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据人脸样本ID查询图像素材
|
||||
*
|
||||
* @param faceSampleId 人脸样本ID
|
||||
* @return type=2且face_sample_id匹配的source记录
|
||||
*/
|
||||
@GetMapping("/{faceSampleId}/source")
|
||||
public ApiResponse<SourceEntity> getSourceByFaceSampleId(@PathVariable Long faceSampleId) {
|
||||
SourceEntity source = sourceMapper.getBySampleIdAndType(faceSampleId, 2);
|
||||
if (source == null) {
|
||||
return ApiResponse.fail("未找到对应的图像素材");
|
||||
}
|
||||
return ApiResponse.success(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印机大屏人脸识别
|
||||
* 上传照片,在景区人脸库中搜索匹配的人脸样本,返回识别结果和匹配到的图像素材
|
||||
*
|
||||
* @param file 人脸照片文件
|
||||
* @param scenicId 景区ID
|
||||
* @return 人脸识别结果和匹配的source列表
|
||||
*/
|
||||
@PostMapping("/{scenicId}/faceRecognize")
|
||||
public ApiResponse<FaceRecognizeWithSourcesResp> faceRecognize(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@PathVariable Long scenicId) throws Exception {
|
||||
|
||||
// 1. 上传人脸照片到存储
|
||||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||||
String filePath = StorageUtil.joinPath(USER_FACE, DateUtil.format(new Date(), "yyyy-MM-dd"));
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String suffix = originalFilename.split("\\.", 2)[1];
|
||||
String fileName = UUID.randomUUID() + "." + suffix;
|
||||
String faceUrl = adapter.uploadFile(file, filePath, fileName);
|
||||
|
||||
// 2. 保存人脸数据到数据库
|
||||
Long faceId = SnowFlakeUtil.getLongId();
|
||||
FaceEntity faceEntity = new FaceEntity();
|
||||
faceEntity.setId(faceId);
|
||||
faceEntity.setScenicId(scenicId);
|
||||
faceEntity.setFaceUrl(faceUrl);
|
||||
faceEntity.setCreateAt(new Date());
|
||||
faceEntity.setMemberId(0L); // 打印机大屏端没有用户ID
|
||||
faceMapper.add(faceEntity);
|
||||
|
||||
// 3. 在景区人脸库中搜索(注意:这里使用scenicId作为数据库名,搜索的是景区内的人脸样本)
|
||||
pcFaceService.matchFaceId(faceId);
|
||||
|
||||
// 4. 自动添加照片到打印列表,并获取添加成功的照片列表
|
||||
List<SourceEntity> addedSources = printerService.autoAddPhotosToPreferPrint(faceId);
|
||||
|
||||
// 5. 根据自动添加结果决定返回的sources
|
||||
List<SourceEntity> sources;
|
||||
if (addedSources != null && !addedSources.isEmpty()) {
|
||||
// 如果自动添加成功,返回添加的照片列表
|
||||
sources = addedSources;
|
||||
} else {
|
||||
// 如果自动添加为空,按原逻辑查询匹配到的图像素材(type=2)
|
||||
sources = new ArrayList<>();
|
||||
List<MemberSourceEntity> memberSourceEntities = memberRelationRepository.listSourceByFaceRelation(faceId, 2);
|
||||
for (MemberSourceEntity memberSourceEntity : memberSourceEntities) {
|
||||
SourceEntity source = sourceRepository.getSource(memberSourceEntity.getSourceId());
|
||||
if (source != null) {
|
||||
sources.add(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 构造响应
|
||||
FaceRecognizeWithSourcesResp resp = new FaceRecognizeWithSourcesResp();
|
||||
resp.setUrl(faceUrl);
|
||||
resp.setFaceId(faceId);
|
||||
resp.setScenicId(scenicId);
|
||||
resp.setSources(sources);
|
||||
// 只有当添加了照片时才返回二维码URL
|
||||
if (addedSources != null && !addedSources.isEmpty()) {
|
||||
resp.setQrcodeUrl("https://zhentuai.com/printer/v1/tv/face/" + faceId + "/qrcode");
|
||||
} else {
|
||||
resp.setQrcodeUrl(null);
|
||||
}
|
||||
|
||||
return ApiResponse.success(resp);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
|
||||
import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
|
||||
import com.ycwl.basic.service.task.TaskService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -20,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
// 渲染端对接接口
|
||||
@Api(tags = "渲染端对接接口")
|
||||
@RequestMapping("/task/v1/")
|
||||
public class TaskTaskController {
|
||||
|
||||
|
||||
408
src/main/java/com/ycwl/basic/controller/viid/ViidController.java
Normal file
408
src/main/java/com/ycwl/basic/controller/viid/ViidController.java
Normal file
@@ -0,0 +1,408 @@
|
||||
package com.ycwl.basic.controller.viid;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.thread.ThreadFactoryBuilder;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ycwl.basic.annotation.IgnoreLogReq;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.facebody.entity.AddFaceResp;
|
||||
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.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.model.viid.entity.DeviceIdObject;
|
||||
import com.ycwl.basic.model.viid.entity.FaceListObject;
|
||||
import com.ycwl.basic.model.viid.entity.FaceObject;
|
||||
import com.ycwl.basic.model.viid.entity.FacePositionObject;
|
||||
import com.ycwl.basic.model.viid.entity.ResponseStatusObject;
|
||||
import com.ycwl.basic.model.viid.entity.SubImageInfoObject;
|
||||
import com.ycwl.basic.model.viid.entity.SubImageList;
|
||||
import com.ycwl.basic.model.viid.entity.SystemTimeObject;
|
||||
import com.ycwl.basic.model.viid.req.FaceUploadReq;
|
||||
import com.ycwl.basic.model.viid.req.ImageUploadReq;
|
||||
import com.ycwl.basic.model.viid.req.KeepaliveReq;
|
||||
import com.ycwl.basic.model.viid.req.RegisterReq;
|
||||
import com.ycwl.basic.model.viid.req.UnRegisterReq;
|
||||
import com.ycwl.basic.model.viid.resp.SystemTimeResp;
|
||||
import com.ycwl.basic.model.viid.resp.VIIDBaseResp;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.service.task.TaskFaceService;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import com.ycwl.basic.task.DynamicTaskGenerator;
|
||||
import com.ycwl.basic.utils.ImageUtils;
|
||||
import com.ycwl.basic.utils.IpUtils;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
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;
|
||||
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
@Api(tags = "摄像头对接接口")
|
||||
@RequestMapping("/VIID")
|
||||
@Slf4j
|
||||
public class ViidController {
|
||||
@Autowired
|
||||
private DeviceMapper deviceMapper;
|
||||
private static final String serverId = "00000000000000000001";
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
@Autowired
|
||||
private TaskFaceService taskFaceService;
|
||||
private final Map<Long, ThreadPoolExecutor> executors = new ConcurrentHashMap<>();
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
private ThreadPoolExecutor getExecutor(Long scenicId) {
|
||||
return executors.computeIfAbsent(scenicId, k -> {
|
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setNamePrefix("VIID-" + scenicId + "-t")
|
||||
.build();
|
||||
return new ThreadPoolExecutor(
|
||||
4, 1024, 0L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1024),
|
||||
threadFactory);
|
||||
});
|
||||
}
|
||||
|
||||
// region 注册注销基础接口
|
||||
/**
|
||||
* 注册接口
|
||||
*
|
||||
* @param req 注册的信息
|
||||
* @param request 请求
|
||||
* @return 返回
|
||||
*/
|
||||
@RequestMapping(value = "/System/Register", method = RequestMethod.POST)
|
||||
public VIIDBaseResp register(@RequestBody RegisterReq req, HttpServletRequest request) {
|
||||
DeviceIdObject deviceIdObject = req.getRegisterObject();
|
||||
log.info("注册的设备信息:{}", deviceIdObject);
|
||||
// 保存设备注册时间
|
||||
String deviceId = deviceIdObject.getDeviceId();
|
||||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
|
||||
if (device == null) {
|
||||
device = new DeviceEntity();
|
||||
device.setName("未配置设备");
|
||||
device.setNo(deviceId);
|
||||
device.setOnline(1);
|
||||
}
|
||||
device.setKeepaliveAt(new Date());
|
||||
device.setIpAddr(IpUtils.getIpAddr(request));
|
||||
if (device.getId() != null) {
|
||||
deviceMapper.updateEntity(device);
|
||||
} else {
|
||||
device.setId(SnowFlakeUtil.getLongId());
|
||||
deviceMapper.addEntity(device);
|
||||
deviceRepository.clearDeviceCache(deviceId);
|
||||
}
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject(serverId, "/VIID/System/Register", "0", "注册成功", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保活接口
|
||||
*
|
||||
* @param req 保活的设备信息
|
||||
* @param request 请求
|
||||
* @return 返回
|
||||
*/
|
||||
@IgnoreLogReq
|
||||
@RequestMapping(value = "/System/Keepalive", method = RequestMethod.POST)
|
||||
public VIIDBaseResp keepalive(@RequestBody KeepaliveReq req, HttpServletRequest request) {
|
||||
DeviceIdObject keepaliveObject = req.getKeepaliveObject();
|
||||
// log.info("对方发送的心跳的信息:{}", keepaliveObject);
|
||||
|
||||
String deviceId = keepaliveObject.getDeviceId();
|
||||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
|
||||
|
||||
// 判断设备状态
|
||||
if (device == null) {
|
||||
// 不存在设备就注册
|
||||
device = new DeviceEntity();
|
||||
device.setName("未配置设备");
|
||||
device.setNo(deviceId);
|
||||
device.setOnline(1);
|
||||
device.setKeepaliveAt(new Date());
|
||||
device.setIpAddr(IpUtils.getIpAddr(request));
|
||||
device.setId(SnowFlakeUtil.getLongId());
|
||||
deviceMapper.addEntity(device);
|
||||
deviceRepository.clearDeviceCache(deviceId);
|
||||
} else {
|
||||
deviceRepository.updateOnlineStatus(device.getId(), IpUtils.getIpAddr(request), 1, new Date());
|
||||
}
|
||||
// log.info("已经解析过的心跳信息:{}", keepaliveObject);
|
||||
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject(deviceId, "/VIID/System/Keepalive", "0", "保活", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销设备
|
||||
*
|
||||
* @param req 参数
|
||||
* @return 返回
|
||||
*/
|
||||
@RequestMapping(value = "/System/UnRegister", method = RequestMethod.POST)
|
||||
public VIIDBaseResp unRegister(@RequestBody UnRegisterReq req, HttpServletRequest request) {
|
||||
// 获取设备id
|
||||
DeviceIdObject unRegisterObject = req.getUnRegisterObject();
|
||||
String deviceId = unRegisterObject.getDeviceId();
|
||||
log.info("获取的注销的请求参数:{}", unRegisterObject);
|
||||
|
||||
// 首先查询该设备是否存在
|
||||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
|
||||
// 判断
|
||||
if (device != null) {
|
||||
deviceRepository.updateOnlineStatus(device.getId(), IpUtils.getIpAddr(request), 0, new Date());
|
||||
}
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject(deviceId, "/VIID/System/UnRegister", "0", "注销成功", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校时接口
|
||||
*
|
||||
* @return 返回
|
||||
*/
|
||||
@RequestMapping(value = "/System/Time", method = RequestMethod.GET)
|
||||
public SystemTimeResp time() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
return new SystemTimeResp(
|
||||
new SystemTimeObject(serverId, "2", sdf.format(new Date()), TimeZone.getTimeZone("Asia/Shanghai").toString())
|
||||
);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
@Autowired
|
||||
private FaceSampleMapper faceSampleMapper;
|
||||
|
||||
private final SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
|
||||
|
||||
/**
|
||||
* 批量新增人脸
|
||||
*/
|
||||
@RequestMapping(value = "/Faces", method = RequestMethod.POST)
|
||||
@IgnoreLogReq
|
||||
public VIIDBaseResp faces(@RequestBody FaceUploadReq req) {
|
||||
FaceListObject faceListObject = req.getFaceListObject();
|
||||
List<FaceObject> faceObject = faceListObject.getFaceObject();
|
||||
String faceId = null;
|
||||
// 遍历人脸列表
|
||||
for (FaceObject face : faceObject) {
|
||||
// 设置FaceId
|
||||
faceId = face.getFaceID();
|
||||
// 获取图片信息
|
||||
SubImageList subImageList = face.getSubImageList();
|
||||
// 判断人脸对象中的列表是否为空
|
||||
String deviceID = face.getDeviceID();
|
||||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceID);
|
||||
if (device == null) {
|
||||
continue;
|
||||
}
|
||||
DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(device.getId());
|
||||
int viidMode = 0;
|
||||
if (deviceConfig != null && deviceConfig.getViidType() != null) {
|
||||
viidMode = deviceConfig.getViidType();
|
||||
}
|
||||
Date shotTime = null;
|
||||
if (StringUtils.isNotBlank(face.getShotTime())) {
|
||||
try {
|
||||
shotTime = sdfTime.parse(face.getShotTime());
|
||||
} catch (ParseException e) {
|
||||
log.warn("拍摄时间时间转换失败,使用当前时间。错误entity:{}", face);
|
||||
}
|
||||
}
|
||||
if (shotTime == null) {
|
||||
if (StringUtils.isNotBlank(face.getFaceAppearTime())) {
|
||||
try {
|
||||
shotTime = sdfTime.parse(face.getFaceAppearTime());
|
||||
} catch (ParseException e) {
|
||||
log.warn("拍摄时间时间转换失败,使用当前时间。错误entity:{}", face);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shotTime == null) {
|
||||
shotTime = new Date();
|
||||
} else if (Math.abs(shotTime.getTime() - System.currentTimeMillis()) > 24 * 60 * 60 * 1000) {
|
||||
shotTime = new Date();
|
||||
}
|
||||
Long scenicId = device.getScenicId();
|
||||
if (scenicId == null) {
|
||||
continue;
|
||||
}
|
||||
IStorageAdapter scenicStorageAdapter = scenicService.getScenicStorageAdapter(scenicId);
|
||||
IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
|
||||
FacePositionObject facePosition = new FacePositionObject();
|
||||
facePosition.setLtY(face.getLeftTopY());
|
||||
facePosition.setLtX(face.getLeftTopX());
|
||||
facePosition.setRbY(face.getRightBtmY());
|
||||
facePosition.setRbX(face.getRightBtmX());
|
||||
if (ObjectUtil.isNotEmpty(subImageList) && CollUtil.isNotEmpty(subImageList.getSubImageInfoObject())) {
|
||||
if (viidMode == 0) {
|
||||
// 遍历每个图片对象
|
||||
// 先找到type14的图片
|
||||
List<SubImageInfoObject> type14ImageList = subImageList.getSubImageInfoObject().stream().filter(subImage -> "14".equals(subImage.getType())).collect(Collectors.toList());
|
||||
for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
|
||||
// base64转换成MultipartFIle
|
||||
MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
|
||||
String ext = subImage.getFileFormat();
|
||||
if (ext.equalsIgnoreCase("jpeg")) {
|
||||
ext = "jpg";
|
||||
}
|
||||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||||
// Type=11 人脸
|
||||
if (subImage.getType().equals("11")) {
|
||||
// 上传oss
|
||||
Long newFaceSampleId = SnowFlakeUtil.getLongId();
|
||||
if (Integer.valueOf(1).equals(device.getStatus())) {
|
||||
FaceSampleEntity faceSample = new FaceSampleEntity();
|
||||
faceSample.setId(newFaceSampleId);
|
||||
faceSample.setScenicId(scenicId);
|
||||
faceSample.setDeviceId(device.getId());
|
||||
faceSample.setStatus(0);
|
||||
faceSample.setCreateAt(shotTime);
|
||||
String url = adapter.uploadFile(file, VIID_FACE, UUID.randomUUID() + "." + ext);
|
||||
faceSample.setFaceUrl(url);
|
||||
faceSampleMapper.add(faceSample);
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
if (faceBodyAdapter != null) {
|
||||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
|
||||
if (addFaceResp != null) {
|
||||
faceSample.setScore(addFaceResp.getScore());
|
||||
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore());
|
||||
}
|
||||
}
|
||||
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
|
||||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (SubImageInfoObject _subImage : type14ImageList) {
|
||||
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);
|
||||
source.setCreateTime(shotTime);
|
||||
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);
|
||||
}
|
||||
log.info("人脸信息及原图{}张入库成功!设备ID:{}", type14ImageList.size(), deviceID);
|
||||
}
|
||||
}
|
||||
} else if (viidMode == 1) {
|
||||
for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
|
||||
// base64转换成MultipartFIle
|
||||
MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
|
||||
String ext = subImage.getFileFormat();
|
||||
if (ext.equalsIgnoreCase("jpeg")) {
|
||||
ext = "jpg";
|
||||
}
|
||||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||||
// Type=14 人脸,传™的,有这么传的嘛
|
||||
if (subImage.getType().equals("14")) {
|
||||
// 上传oss
|
||||
if (Integer.valueOf(1).equals(device.getStatus())) {
|
||||
FaceSampleEntity faceSample = new FaceSampleEntity();
|
||||
Long newFaceSampleId = SnowFlakeUtil.getLongId();
|
||||
faceSample.setId(newFaceSampleId);
|
||||
faceSample.setScenicId(scenicId);
|
||||
faceSample.setDeviceId(device.getId());
|
||||
faceSample.setStatus(0);
|
||||
faceSample.setCreateAt(shotTime);
|
||||
String url = adapter.uploadFile(file, VIID_FACE, UUID.randomUUID() + "." + ext);
|
||||
faceSample.setFaceUrl(url);
|
||||
faceSampleMapper.add(faceSample);
|
||||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
if (faceBodyAdapter != null) {
|
||||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
|
||||
if (addFaceResp != null) {
|
||||
faceSample.setScore(addFaceResp.getScore());
|
||||
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore());
|
||||
}
|
||||
}
|
||||
if (Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
|
||||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||||
}
|
||||
});
|
||||
log.info("模式1人脸信息入库成功!设备ID:{}", deviceID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject(faceId, "/VIID/Faces", "0", "OK", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/Images", method = RequestMethod.POST)
|
||||
@IgnoreLogReq
|
||||
public VIIDBaseResp images(HttpServletRequest request, @RequestBody ImageUploadReq req) throws IOException {
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject("1", "/VIID/Images", "0", "OK", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -25,7 +26,7 @@ import java.util.List;
|
||||
@Slf4j
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
// 自定义切片工具对接接口
|
||||
@Api(tags = "自定义切片工具对接接口")
|
||||
@RequestMapping("/vpt/v1/")
|
||||
public class VptController {
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ import com.ycwl.basic.constant.StorageConstant;
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.operator.WvpPassiveStorageOperator;
|
||||
import com.ycwl.basic.model.wvp.WvpSyncReqVo;
|
||||
import com.ycwl.basic.service.pc.DeviceService;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -25,16 +27,19 @@ import java.util.List;
|
||||
@Slf4j
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
// WVP对接接口
|
||||
@Api(tags = "WVP对接接口")
|
||||
@RequestMapping("/wvp/v1/")
|
||||
public class WvpController {
|
||||
|
||||
@Autowired
|
||||
private DeviceService deviceService;
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
@IgnoreLogReq
|
||||
@PostMapping("/scenic/{scenicId}/sync")
|
||||
public ApiResponse<List<WvpPassiveStorageOperator.Task>> sync(@PathVariable("scenicId") Long scenicId, @RequestBody WvpSyncReqVo reqVo) {
|
||||
deviceService.updateDevices(scenicId, reqVo);
|
||||
return ApiResponse.success(WvpPassiveStorageOperator.getTaskListByScenicId(scenicId));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,10 @@ import com.ycwl.basic.device.operator.VptPassiveStorageOperator;
|
||||
import com.ycwl.basic.device.operator.WvpActiveStorageOperator;
|
||||
import com.ycwl.basic.device.operator.WvpPassiveStorageOperator;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
|
||||
public class DeviceFactory {
|
||||
public static IDeviceStorageOperator getDeviceStorageOperator(DeviceV2DTO device, DeviceConfigEntity config) {
|
||||
public static IDeviceStorageOperator getDeviceStorageOperator(DeviceEntity device, DeviceConfigEntity config) {
|
||||
IDeviceStorageOperator operator = null;
|
||||
if (config == null) {
|
||||
return null;
|
||||
@@ -38,33 +35,11 @@ public class DeviceFactory {
|
||||
if (operator == null) {
|
||||
return null;
|
||||
}
|
||||
operator.setDevice(convertToEntity(device));
|
||||
operator.setDevice(device);
|
||||
operator.setDeviceConfig(config);
|
||||
return operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将DeviceV2DTO转换为DeviceEntity
|
||||
*/
|
||||
private static DeviceEntity convertToEntity(DeviceV2DTO dto) {
|
||||
if (dto == null) {
|
||||
return null;
|
||||
}
|
||||
DeviceEntity entity = new DeviceEntity();
|
||||
entity.setId(dto.getId());
|
||||
entity.setName(dto.getName());
|
||||
entity.setNo(dto.getNo());
|
||||
entity.setScenicId(dto.getScenicId());
|
||||
entity.setStatus(dto.getIsActive());
|
||||
if (dto.getCreateTime() != null) {
|
||||
entity.setCreateAt(dto.getCreateTime());
|
||||
}
|
||||
if (dto.getUpdateTime() != null) {
|
||||
entity.setUpdateAt(dto.getUpdateTime());
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
public static IDeviceStatusChecker getDeviceStatusChecker(DeviceEntity device, DeviceConfigEntity config) {
|
||||
IDeviceStatusChecker checker = null;
|
||||
if (config.getOnlineCheck() <= 0) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.ycwl.basic.device.checker.helper;
|
||||
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import lombok.Setter;
|
||||
@@ -13,7 +13,7 @@ public abstract class CommonDeviceChecker<C> {
|
||||
protected DeviceConfigEntity deviceConfig;
|
||||
|
||||
public CommonDeviceChecker(String configJson) {
|
||||
config = JacksonUtil.parseObject(configJson, getConfigClass());
|
||||
config = JSON.parseObject(configJson, getConfigClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
package com.ycwl.basic.device.entity.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备视频连续性检查缓存实体
|
||||
* 用于存储在Redis中的检查结果
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-01
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeviceVideoContinuityCache implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 检查时间
|
||||
*/
|
||||
private Date checkTime;
|
||||
|
||||
/**
|
||||
* 检查的开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 检查的结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 是否支持连续性检查
|
||||
*/
|
||||
private Boolean support;
|
||||
|
||||
/**
|
||||
* 视频是否连续
|
||||
*/
|
||||
private Boolean continuous;
|
||||
|
||||
/**
|
||||
* 视频总数
|
||||
*/
|
||||
private Integer totalVideos;
|
||||
|
||||
/**
|
||||
* 总时长(毫秒)
|
||||
*/
|
||||
private Long totalDurationMs;
|
||||
|
||||
/**
|
||||
* 允许的最大间隙(毫秒)
|
||||
*/
|
||||
private Long maxAllowedGapMs;
|
||||
|
||||
/**
|
||||
* 间隙数量
|
||||
*/
|
||||
private Integer gapCount;
|
||||
|
||||
/**
|
||||
* 间隙列表(简化版,只包含关键信息)
|
||||
*/
|
||||
private List<GapInfo> gaps;
|
||||
|
||||
/**
|
||||
* 间隙信息简化类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class GapInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 前一个文件名
|
||||
*/
|
||||
private String beforeFileName;
|
||||
|
||||
/**
|
||||
* 后一个文件名
|
||||
*/
|
||||
private String afterFileName;
|
||||
|
||||
/**
|
||||
* 间隙时长(毫秒)
|
||||
*/
|
||||
private Long gapMs;
|
||||
|
||||
/**
|
||||
* 间隙开始时间
|
||||
*/
|
||||
private Date gapStartTime;
|
||||
|
||||
/**
|
||||
* 间隙结束时间
|
||||
*/
|
||||
private Date gapEndTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从VideoContinuityResult创建缓存对象
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param result 检查结果
|
||||
* @param startTime 检查开始时间
|
||||
* @param endTime 检查结束时间
|
||||
* @return 缓存对象
|
||||
*/
|
||||
public static DeviceVideoContinuityCache fromResult(Long deviceId, VideoContinuityResult result,
|
||||
Date startTime, Date endTime) {
|
||||
DeviceVideoContinuityCache cache = new DeviceVideoContinuityCache();
|
||||
cache.setDeviceId(deviceId);
|
||||
cache.setCheckTime(new Date());
|
||||
cache.setStartTime(startTime);
|
||||
cache.setEndTime(endTime);
|
||||
cache.setSupport(result.isSupport());
|
||||
cache.setContinuous(result.isContinuous());
|
||||
cache.setTotalVideos(result.getTotalVideos());
|
||||
cache.setTotalDurationMs(result.getTotalDurationMs());
|
||||
cache.setMaxAllowedGapMs(result.getMaxAllowedGapMs());
|
||||
cache.setGapCount(result.getGapCount());
|
||||
|
||||
// 转换间隙列表
|
||||
if (result.getGaps() != null && !result.getGaps().isEmpty()) {
|
||||
List<GapInfo> gapInfos = result.getGaps().stream()
|
||||
.map(gap -> new GapInfo(
|
||||
gap.getBeforeFile() != null ? gap.getBeforeFile().getName() : null,
|
||||
gap.getAfterFile() != null ? gap.getAfterFile().getName() : null,
|
||||
gap.getGapMs(),
|
||||
gap.getGapStartTime(),
|
||||
gap.getGapEndTime()
|
||||
))
|
||||
.toList();
|
||||
cache.setGaps(gapInfos);
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.ycwl.basic.device.entity.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 视频连续性检查中的间隙信息
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class VideoContinuityGap {
|
||||
/**
|
||||
* 间隙前的视频文件
|
||||
*/
|
||||
private FileObject beforeFile;
|
||||
|
||||
/**
|
||||
* 间隙后的视频文件
|
||||
*/
|
||||
private FileObject afterFile;
|
||||
|
||||
/**
|
||||
* 间隙时长(毫秒)
|
||||
*/
|
||||
private long gapMs;
|
||||
|
||||
/**
|
||||
* 间隙开始时间(前一个视频的endTime)
|
||||
*/
|
||||
private Date gapStartTime;
|
||||
|
||||
/**
|
||||
* 间隙结束时间(后一个视频的createTime)
|
||||
*/
|
||||
private Date gapEndTime;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.ycwl.basic.device.entity.common;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 视频连续性检查结果
|
||||
*/
|
||||
@Data
|
||||
public class VideoContinuityResult {
|
||||
/**
|
||||
* 是否支持连续性检查功能
|
||||
*/
|
||||
private boolean support;
|
||||
|
||||
/**
|
||||
* 视频是否连续(所有间隙都在允许范围内)
|
||||
*/
|
||||
private boolean continuous;
|
||||
|
||||
/**
|
||||
* 检测到的间隙列表
|
||||
*/
|
||||
private List<VideoContinuityGap> gaps = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 视频文件总数
|
||||
*/
|
||||
private int totalVideos;
|
||||
|
||||
/**
|
||||
* 总时长(毫秒)
|
||||
*/
|
||||
private long totalDurationMs;
|
||||
|
||||
/**
|
||||
* 允许的最大间隙(毫秒)
|
||||
*/
|
||||
private long maxAllowedGapMs;
|
||||
|
||||
/**
|
||||
* 添加一个间隙
|
||||
*/
|
||||
public void addGap(VideoContinuityGap gap) {
|
||||
this.gaps.add(gap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取间隙数量
|
||||
*/
|
||||
public int getGapCount() {
|
||||
return gaps.size();
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,12 @@
|
||||
package com.ycwl.basic.device.operator;
|
||||
|
||||
import com.ycwl.basic.device.entity.common.VideoContinuityResult;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class ADeviceStorageOperator implements IDeviceStorageOperator {
|
||||
@Setter
|
||||
protected DeviceEntity device;
|
||||
@Setter
|
||||
protected DeviceConfigEntity deviceConfig;
|
||||
|
||||
/**
|
||||
* 默认实现:不支持视频连续性检查
|
||||
*
|
||||
* @param startDate 开始时间
|
||||
* @param endDate 结束时间
|
||||
* @param maxGapMs 允许的最大间隔时间(毫秒)
|
||||
* @return support=false的结果
|
||||
*/
|
||||
@Override
|
||||
public VideoContinuityResult checkVideoContinuity(Date startDate, Date endDate, long maxGapMs) {
|
||||
VideoContinuityResult result = new VideoContinuityResult();
|
||||
result.setSupport(false);
|
||||
result.setContinuous(false);
|
||||
result.setTotalVideos(0);
|
||||
result.setTotalDurationMs(0);
|
||||
result.setMaxAllowedGapMs(maxGapMs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认实现:不支持视频连续性检查
|
||||
*
|
||||
* @return support=false的结果
|
||||
*/
|
||||
@Override
|
||||
public VideoContinuityResult checkRecentVideoContinuity() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.MINUTE, -2);
|
||||
Date endDate = calendar.getTime();
|
||||
calendar.add(Calendar.MINUTE, -5);
|
||||
Date startDate = calendar.getTime();
|
||||
return checkVideoContinuity(startDate, endDate, 2000L);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.ycwl.basic.device.operator;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.entity.common.VideoContinuityGap;
|
||||
import com.ycwl.basic.device.entity.common.VideoContinuityResult;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.entity.AliOssStorageConfig;
|
||||
@@ -30,7 +28,7 @@ public class AliOssStorageOperator extends ADeviceStorageOperator {
|
||||
|
||||
@Override
|
||||
public void loadConfig(String configJson) {
|
||||
AliOssStorageConfig config = JacksonUtil.parseObject(configJson, AliOssStorageConfig.class);
|
||||
AliOssStorageConfig config = JSON.parseObject(configJson, AliOssStorageConfig.class);
|
||||
adapter = StorageFactory.get(StorageType.ALI_OSS, config);
|
||||
}
|
||||
|
||||
@@ -71,15 +69,23 @@ public class AliOssStorageOperator extends ADeviceStorageOperator {
|
||||
if (startDate == null || endDate == null) {
|
||||
return null;
|
||||
}
|
||||
List<FileObject> fileList = new ArrayList<>();
|
||||
if (startDate.after(endDate)) {
|
||||
return fileList;
|
||||
}
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(startDate);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
|
||||
while (calendar.getTime().before(endDate)) {
|
||||
String prefix = dateFormat.format(calendar.getTime());
|
||||
List<FileObject> fileList = getOssFileListByPrefix(prefix);
|
||||
if (fileList == null) {
|
||||
List<FileObject> fileListByPrefix = getOssFileListByPrefix(prefix);
|
||||
if (fileListByPrefix == null) {
|
||||
return null;
|
||||
}
|
||||
fileList.addAll(fileListByPrefix);
|
||||
calendar.add(Calendar.MINUTE, 1);
|
||||
}
|
||||
calendar.clear();
|
||||
return fileList.stream()
|
||||
.sorted(Comparator.comparing(FileObject::getCreateTime))
|
||||
@@ -100,104 +106,4 @@ public class AliOssStorageOperator extends ADeviceStorageOperator {
|
||||
String prefix = dateFormat.format(calendar.getTime());
|
||||
return removeFilesByPrefix(prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查视频片段的连续性
|
||||
*
|
||||
* @param startDate 开始时间
|
||||
* @param endDate 结束时间
|
||||
* @param maxGapMs 允许的最大间隔时间(毫秒)
|
||||
* @return 包含缺口信息的验证结果
|
||||
*/
|
||||
@Override
|
||||
public VideoContinuityResult checkVideoContinuity(Date startDate, Date endDate, long maxGapMs) {
|
||||
VideoContinuityResult result = new VideoContinuityResult();
|
||||
result.setSupport(true);
|
||||
result.setMaxAllowedGapMs(maxGapMs);
|
||||
|
||||
// 获取时间范围内的视频列表
|
||||
List<FileObject> fileList = getFileListByDtRange(startDate, endDate);
|
||||
|
||||
if (fileList == null || fileList.isEmpty()) {
|
||||
result.setContinuous(false);
|
||||
result.setTotalVideos(0);
|
||||
result.setTotalDurationMs(0);
|
||||
log.warn("未找到指定时间范围内的视频文件: {} - {}", startDate, endDate);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.setTotalVideos(fileList.size());
|
||||
|
||||
// 只有一个视频文件时,认为是连续的
|
||||
if (fileList.size() == 1) {
|
||||
FileObject file = fileList.get(0);
|
||||
long duration = file.getEndTime().getTime() - file.getCreateTime().getTime();
|
||||
result.setContinuous(true);
|
||||
result.setTotalDurationMs(duration);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 检查相邻视频之间的间隙
|
||||
long totalDuration = 0;
|
||||
for (int i = 0; i < fileList.size() - 1; i++) {
|
||||
FileObject currentFile = fileList.get(i);
|
||||
FileObject nextFile = fileList.get(i + 1);
|
||||
|
||||
// 计算当前视频的时长
|
||||
totalDuration += currentFile.getEndTime().getTime() - currentFile.getCreateTime().getTime();
|
||||
|
||||
// 计算间隙: 后一个视频的开始时间 - 前一个视频的结束时间
|
||||
long gapMs = nextFile.getCreateTime().getTime() - currentFile.getEndTime().getTime();
|
||||
|
||||
// 如果间隙超过允许值,记录该间隙
|
||||
if (gapMs > maxGapMs) {
|
||||
VideoContinuityGap gap = new VideoContinuityGap();
|
||||
gap.setBeforeFile(currentFile);
|
||||
gap.setAfterFile(nextFile);
|
||||
gap.setGapMs(gapMs);
|
||||
gap.setGapStartTime(currentFile.getEndTime());
|
||||
gap.setGapEndTime(nextFile.getCreateTime());
|
||||
result.addGap(gap);
|
||||
log.debug("检测到视频间隙: {} -> {}, 间隙时长: {}ms",
|
||||
currentFile.getName(), nextFile.getName(), gapMs);
|
||||
}
|
||||
}
|
||||
|
||||
// 加上最后一个视频的时长
|
||||
FileObject lastFile = fileList.get(fileList.size() - 1);
|
||||
totalDuration += lastFile.getEndTime().getTime() - lastFile.getCreateTime().getTime();
|
||||
|
||||
result.setTotalDurationMs(totalDuration);
|
||||
result.setContinuous(result.getGapCount() == 0);
|
||||
|
||||
log.info("视频连续性检查完成: 总视频数={}, 总时长={}ms, 间隙数={}, 连续={}",
|
||||
result.getTotalVideos(), result.getTotalDurationMs(), result.getGapCount(), result.isContinuous());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查近期视频的连续性(测试用)
|
||||
* 时间范围: 当前时间向前2分钟后,再向前10分钟(即前12分钟到前2分钟)
|
||||
* 允许的最大间隙: 2秒
|
||||
*
|
||||
* @return 包含缺口信息的验证结果
|
||||
*/
|
||||
@Override
|
||||
public VideoContinuityResult checkRecentVideoContinuity() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
||||
// 结束时间: 当前时间 - 2分钟
|
||||
calendar.add(Calendar.MINUTE, -2);
|
||||
Date endDate = calendar.getTime();
|
||||
|
||||
// 开始时间: 当前时间 - 12分钟 (再向前10分钟)
|
||||
calendar.add(Calendar.MINUTE, -10);
|
||||
Date startDate = calendar.getTime();
|
||||
|
||||
log.info("检查近期视频连续性: {} - {}", startDate, endDate);
|
||||
|
||||
// 允许的最大间隙为2秒(2000毫秒)
|
||||
return checkVideoContinuity(startDate, endDate, 2000L);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.ycwl.basic.device.operator;
|
||||
|
||||
import com.ycwl.basic.device.IDeviceCommon;
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.entity.common.VideoContinuityResult;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -20,29 +19,10 @@ public interface IDeviceStorageOperator extends IDeviceCommon {
|
||||
List<FileObject> getFileListByDtRange(Date startDate, Date endDate);
|
||||
|
||||
/**
|
||||
* 删除指定日期之前的文件,不包含指定的日期当天
|
||||
* 删除指定日期之前的文件,不包含指定的日期当天
|
||||
*
|
||||
* @param date 指定日期,不包含指定日期当天
|
||||
* @param date 指定日期,不包含指定日期当天
|
||||
* @return
|
||||
*/
|
||||
boolean removeFilesBeforeDate(Date date);
|
||||
|
||||
/**
|
||||
* 检查视频片段的连续性
|
||||
*
|
||||
* @param startDate 开始时间
|
||||
* @param endDate 结束时间
|
||||
* @param maxGapMs 允许的最大间隔时间(毫秒)
|
||||
* @return 包含缺口信息的验证结果
|
||||
*/
|
||||
VideoContinuityResult checkVideoContinuity(Date startDate, Date endDate, long maxGapMs);
|
||||
|
||||
/**
|
||||
* 检查近期视频的连续性(便捷方法)
|
||||
* 时间范围: 当前时间向前2分钟后,再向前5分钟(即前7分钟到前2分钟)
|
||||
* 允许的最大间隙: 2秒
|
||||
*
|
||||
* @return 包含缺口信息的验证结果
|
||||
*/
|
||||
VideoContinuityResult checkRecentVideoContinuity();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.ycwl.basic.device.operator;
|
||||
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.entity.common.VideoContinuityResult;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -36,24 +34,4 @@ public class LocalStorageOperator implements IDeviceStorageOperator {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoContinuityResult checkVideoContinuity(Date startDate, Date endDate, long maxGapMs) {
|
||||
VideoContinuityResult result = new VideoContinuityResult();
|
||||
result.setSupport(false);
|
||||
result.setContinuous(false);
|
||||
result.setTotalVideos(0);
|
||||
result.setTotalDurationMs(0);
|
||||
result.setMaxAllowedGapMs(maxGapMs);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoContinuityResult checkRecentVideoContinuity() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.MINUTE, -2);
|
||||
Date endDate = calendar.getTime();
|
||||
calendar.add(Calendar.MINUTE, -5);
|
||||
Date startDate = calendar.getTime();
|
||||
return checkVideoContinuity(startDate, endDate, 2000L);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.ycwl.basic.device.operator;
|
||||
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.entity.vpt_passive.VptPassiveStorageConfig;
|
||||
@@ -28,8 +29,10 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
|
||||
public Long scenicId;
|
||||
public Long deviceId;
|
||||
public String deviceNo;
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
public Date startTime;
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
public Date endTime;
|
||||
}
|
||||
@@ -72,7 +75,7 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
|
||||
|
||||
@Override
|
||||
public void loadConfig(String configJson) {
|
||||
this.config = JacksonUtil.parseObject(configJson, VptPassiveStorageConfig.class);
|
||||
this.config = JSON.parseObject(configJson, VptPassiveStorageConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,15 +87,14 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
|
||||
if (StringUtils.isNotBlank(config.getDeviceNo())) {
|
||||
task.deviceNo = config.getDeviceNo();
|
||||
} else {
|
||||
log.warn("设备未配置deviceNo:{}", device);
|
||||
return Collections.emptyList();
|
||||
task.deviceNo = device.getNo2();
|
||||
}
|
||||
task.startTime = startDate;
|
||||
task.endTime = endDate;
|
||||
if (redisTemplate == null) {
|
||||
taskList.add(task);
|
||||
} else {
|
||||
redisTemplate.opsForValue().set(String.format(TASK_KEY, task.scenicId, task.deviceNo) + task.taskId, JacksonUtil.toJSONString(task), 10 * 60L, TimeUnit.SECONDS);
|
||||
redisTemplate.opsForValue().set(String.format(TASK_KEY, task.scenicId, task.deviceNo) + task.taskId, JSON.toJSONString(task), 10 * 60L, TimeUnit.SECONDS);
|
||||
}
|
||||
log.info("任务{}获取视频开始!共{}", task.taskId, taskList.size());
|
||||
Date taskStartTime = new Date();
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.ycwl.basic.device.operator;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.entity.wvp_active.WvpActiveStorageConfig;
|
||||
import com.ycwl.basic.storage.exceptions.StorageConfigException;
|
||||
@@ -30,7 +30,7 @@ public class WvpActiveStorageOperator extends ADeviceStorageOperator {
|
||||
|
||||
@Override
|
||||
public void loadConfig(String configJson) {
|
||||
this.config = JacksonUtil.parseObject(configJson, WvpActiveStorageConfig.class);
|
||||
this.config = JSON.parseObject(configJson, WvpActiveStorageConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,14 +55,13 @@ public class WvpActiveStorageOperator extends ADeviceStorageOperator {
|
||||
String password = MD5.create().digestHex(this.config.getLoginPassword());
|
||||
params.put("password", password);
|
||||
String jsonResult = HttpUtil.get(url, params);
|
||||
Map<String, Object> result = JacksonUtil.parseObject(jsonResult, Map.class);
|
||||
Integer code = (Integer) result.get("code");
|
||||
if (code != null && code == 0) {
|
||||
Map<String, Object> data = (Map<String, Object>) result.get("data");
|
||||
this.token = (String) data.get("accessToken");
|
||||
JSONObject result = JSON.parseObject(jsonResult);
|
||||
if (result.getInteger("code") == 0) {
|
||||
JSONObject data = result.getJSONObject("data");
|
||||
this.token = data.getString("accessToken");
|
||||
return this.token;
|
||||
} else {
|
||||
throw new StorageConfigException("获取token失败,原因为:" + result.get("msg"));
|
||||
throw new StorageConfigException("获取token失败,原因为:" + result.getString("msg"));
|
||||
}
|
||||
}
|
||||
public List<FileObject> listDirByDtRange(Date startDate, Date endDate) {
|
||||
@@ -76,23 +75,19 @@ public class WvpActiveStorageOperator extends ADeviceStorageOperator {
|
||||
params.put("page", 1);
|
||||
params.put("count", 100);
|
||||
String jsonResult = HttpRequest.get(url).form(params).header("Access-Token", getToken()).execute().body();
|
||||
Map<String, Object> result = JacksonUtil.parseObject(jsonResult, Map.class);
|
||||
Integer code = (Integer) result.get("code");
|
||||
if (code != null && code == 0) {
|
||||
Map<String, Object> data = (Map<String, Object>) result.get("data");
|
||||
List<Map<String, Object>> recordList = JacksonUtil.parseObject(JacksonUtil.toJSONString(((Map<String, Object>) result.get("data")).get("list")), new TypeReference<List<Map<String, Object>>>() {});
|
||||
JSONObject result = JSON.parseObject(jsonResult);
|
||||
if (result.getInteger("code") == 0) {
|
||||
JSONObject data = result.getJSONObject("data");
|
||||
List<JSONObject> recordList = data.getJSONArray("list").toJavaList(JSONObject.class);
|
||||
return recordList.stream()
|
||||
.map(record -> {
|
||||
FileObject object = new FileObject();
|
||||
object.setName((String) record.get("id"));
|
||||
object.setPath((String) record.get("folder"));
|
||||
Integer recordId = (Integer) record.get("id");
|
||||
object.setUrl(getUrlForDownload(recordId != null ? recordId : 0));
|
||||
object.setName(record.getString("id"));
|
||||
object.setPath(record.getString("folder"));
|
||||
object.setUrl(getUrlForDownload(record.getInteger("id")));
|
||||
object.setNeedDownload(true);
|
||||
Number startTime = (Number) record.get("startTime");
|
||||
Number endTime = (Number) record.get("endTime");
|
||||
object.setCreateTime(new Date(startTime != null ? startTime.longValue() : 0));
|
||||
object.setEndTime(new Date(endTime != null ? endTime.longValue() : 0));
|
||||
object.setCreateTime(new Date(record.getLongValue("startTime")));
|
||||
object.setEndTime(new Date(record.getLongValue("endTime")));
|
||||
return object;
|
||||
})
|
||||
.sorted(Comparator.comparing(FileObject::getCreateTime))
|
||||
@@ -105,11 +100,10 @@ public class WvpActiveStorageOperator extends ADeviceStorageOperator {
|
||||
// assume path is recordId
|
||||
String url = this.config.getHost() + "/api/cloud/record/play/path?recordId=" + id;
|
||||
String jsonResult = HttpRequest.get(url).header("Access-Token", getToken()).execute().body();
|
||||
Map<String, Object> result = JacksonUtil.parseObject(jsonResult, Map.class);
|
||||
Integer code = (Integer) result.get("code");
|
||||
if (code != null && code == 0) {
|
||||
Map<String, Object> data = (Map<String, Object>) result.get("data");
|
||||
String httpPath = (String) data.get("httpPath");
|
||||
JSONObject result = JSON.parseObject(jsonResult);
|
||||
if (result.getInteger("code") == 0) {
|
||||
JSONObject data = result.getJSONObject("data");
|
||||
String httpPath = data.getString("httpPath");
|
||||
if (StringUtils.isBlank(this.config.getZlmHost())) {
|
||||
return httpPath;
|
||||
}
|
||||
@@ -120,7 +114,7 @@ public class WvpActiveStorageOperator extends ADeviceStorageOperator {
|
||||
}
|
||||
return this.config.getZlmHost() + uri.getPath() + "?" + uri.getQuery();
|
||||
} else {
|
||||
throw new StorageUnsupportedException("获取播放地址失败,原因为:" + result.get("msg"));
|
||||
throw new StorageUnsupportedException("获取播放地址失败,原因为:" + result.getString("msg"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user