diff --git a/jczxw-java/Dockerfile b/jczxw-java/Dockerfile new file mode 100644 index 0000000..84ae9f9 --- /dev/null +++ b/jczxw-java/Dockerfile @@ -0,0 +1,51 @@ +# 使用更小的 Alpine Linux + OpenJDK 17 镜像 +FROM openjdk:17-jdk-alpine + +# 设置工作目录 +WORKDIR /app + +# 创建日志目录 +RUN mkdir -p /app/logs + +# 创建上传文件目录 +RUN mkdir -p /app/uploads + +# 安装必要工具和中文字体支持 +# fontconfig: 字体配置库 +# ttf-dejavu: 包含DejaVu字体,支持中文显示 +# wqy-zenhei: 文泉驿正黑字体,开源中文字体 +RUN apk add --no-cache wget fontconfig ttf-dejavu && \ + # 下载并安装文泉驿微米黑字体(更好的中文支持) + wget -O /tmp/wqy-microhei.ttc https://github.com/anthonyfok/fonts-wqy-microhei/raw/master/wqy-microhei.ttc && \ + mkdir -p /usr/share/fonts/truetype/wqy && \ + mv /tmp/wqy-microhei.ttc /usr/share/fonts/truetype/wqy/ && \ + # 刷新字体缓存 + fc-cache -fv && \ + # 创建应用用户(安全考虑) + addgroup -g 1000 appgroup && \ + adduser -D -u 1000 -G appgroup appuser + +# 复制jar包到容器 +COPY target/*.jar app.jar + +# 设置目录权限 +RUN chown -R appuser:appgroup /app + +# 切换到应用用户 +USER appuser + +# 暴露端口 +EXPOSE 9200 + +# 设置JVM参数 +ENV JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom" + +# 设置Spring Profile +ENV SPRING_PROFILES_ACTIVE=prod + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:9200/actuator/health || exit 1 + +# 启动应用 +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] diff --git a/jczxw-java/README.md b/jczxw-java/README.md new file mode 100644 index 0000000..ef5a814 --- /dev/null +++ b/jczxw-java/README.md @@ -0,0 +1,286 @@ +
+

🚀 WebSoft API

+

基于 Spring Boot + MyBatis Plus 的企业级后端API服务

+ +

+ Java + Spring Boot + MyBatis Plus + MySQL + Redis + License +

+
+ +## 📖 项目简介 + +WebSoft API 是一个基于 **Spring Boot + MyBatis Plus** 构建的现代化企业级后端API服务,采用最新的Java技术栈: + +- **核心框架**:Spring Boot 2.5.4 + Spring Security + Spring AOP +- **数据访问**:MyBatis Plus 3.4.3 + Druid 连接池 +- **数据库**:MySQL + Redis +- **文档工具**:Swagger 3.0 + Knife4j +- **工具库**:Hutool、Lombok、FastJSON + + + +## 项目演示 +| 后台管理系统 | https://mp.websoft.top | +|--------|-------------------------------------------------------------------------------------------------------------------------------------| +| 测试账号 | 13800010123,123456 +| 正式账号 | [立即注册](https://mp.websoft.top/register/?inviteCode=github) | +| 关注公众号 | ![输入图片说明](https://oss.wsdns.cn/20240327/f1175cc5aae741d3af05484747270bd5.jpeg?x-oss-process=image/resize,m_fixed,w_150/quality,Q_90) | + + + + +## 🛠️ 技术栈 + +### 核心框架 +| 技术 | 版本 | 说明 | +|------|------|------| +| Java | 1.8+ | 编程语言 | +| Spring Boot | 2.5.4 | 微服务框架 | +| Spring Security | 5.5.x | 安全框架 | +| MyBatis Plus | 3.4.3 | ORM框架 | +| MySQL | 8.0+ | 关系型数据库 | +| Redis | 6.0+ | 缓存数据库 | +| Druid | 1.2.6 | 数据库连接池 | + +### 功能组件 +- **Swagger 3.0 + Knife4j** - API文档生成与测试 +- **JWT** - 用户认证与授权 +- **Hutool** - Java工具类库 +- **EasyPOI** - Excel文件处理 +- **阿里云OSS** - 对象存储服务 +- **微信支付/支付宝** - 支付集成 +- **Socket.IO** - 实时通信 +- **MQTT** - 物联网消息传输 + +## 📋 环境要求 + +### 基础环境 +- ☕ **Java 1.8+** +- 🗄️ **MySQL 8.0+** +- 🔴 **Redis 6.0+** +- 📦 **Maven 3.6+** + +### 开发工具 +- **推荐**:IntelliJ IDEA / Eclipse +- **插件**:Lombok Plugin、MyBatis Plugin + +## 🚀 快速开始 + +### 1. 克隆项目 +```bash +git clone https://github.com/websoft-top/mp-java.git +cd mp-java +``` + +### 2. 数据库配置 +```sql +-- 创建数据库 +CREATE DATABASE websoft_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- 导入数据库脚本(如果有的话) +-- source /path/to/database.sql +``` + +### 3. 配置文件 +编辑 `src/main/resources/application-dev.yml` 文件,配置数据库连接: +```yaml +spring: + datasource: + url: jdbc:mysql://localhost:3306/websoft_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 + username: your_username + password: your_password + redis: + host: localhost + port: 6379 + password: your_redis_password +``` + +### 4. 启动项目 +```bash +# 使用 Maven 启动 +mvn spring-boot:run + +# 或者使用 IDE 直接运行 WebSoftApplication.java +``` + +访问 `http://localhost:9200` 即可看到API服务。 + +### 5. API文档 +启动项目后,访问以下地址查看API文档: +- Swagger UI: `http://localhost:9200/swagger-ui/index.html` +- Knife4j: `http://localhost:9200/doc.html` + +## ⚙️ 配置说明 + +### 数据库配置 +在 `application-dev.yml` 中配置数据库连接: +```yaml +spring: + datasource: + url: jdbc:mysql://localhost:3306/websoft_db + username: root + password: your_password + driver-class-name: com.mysql.cj.jdbc.Driver +``` + +### Redis配置 +```yaml +spring: + redis: + host: localhost + port: 6379 + password: your_redis_password + database: 0 +``` + +### 阿里云OSS配置 +```yaml +config: + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: your_access_key_id + accessKeySecret: your_access_key_secret + bucketName: your_bucket_name + bucketDomain: https://your-domain.com +``` + +### 其他配置 +- **JWT密钥**:`config.token-key` 用于JWT令牌加密 +- **文件上传路径**:`config.upload-path` 本地文件存储路径 +- **邮件服务**:配置SMTP服务器用于发送邮件 + +## 🎯 核心功能 + +### 🔐 用户认证与授权 +- **JWT认证**:基于JSON Web Token的用户认证 +- **Spring Security**:完整的安全框架集成 +- **角色权限**:基于RBAC的权限控制 +- **图形验证码**:防止恶意登录 + +### 📝 内容管理系统(CMS) +- **文章管理**:支持富文本内容管理 +- **媒体文件**:图片/视频文件上传与管理 +- **分类管理**:内容分类与标签管理 +- **SEO优化**:搜索引擎优化支持 + +### 🛒 电商系统 +- **商品管理**:商品信息、规格、库存管理 +- **订单系统**:完整的订单流程管理 +- **支付集成**:支持微信支付、支付宝 +- **物流跟踪**:快递100物流查询集成 + +### 🔧 系统管理 +- **用户管理**:用户信息维护与管理 +- **系统配置**:动态配置管理 +- **日志监控**:系统操作日志记录 +- **数据备份**:数据库备份与恢复 + +### 📊 数据分析 +- **统计报表**:业务数据统计分析 +- **图表展示**:数据可视化展示 +- **导出功能**:Excel数据导出 +- **实时监控**:系统性能监控 + +## 🏗️ 项目结构 + +``` +src/main/java/com/gxwebsoft/ +├── WebSoftApplication.java # 启动类 +├── cms/ # 内容管理模块 +│ ├── controller/ # 控制器层 +│ ├── service/ # 业务逻辑层 +│ ├── mapper/ # 数据访问层 +│ └── entity/ # 实体类 +├── shop/ # 商城模块 +│ ├── controller/ +│ ├── service/ +│ ├── mapper/ +│ └── entity/ +├── common/ # 公共模块 +│ ├── core/ # 核心配置 +│ ├── utils/ # 工具类 +│ └── exception/ # 异常处理 +└── resources/ + ├── application.yml # 主配置文件 + ├── application-dev.yml # 开发环境配置 + └── application-prod.yml# 生产环境配置 +``` + +## 🔧 开发规范 + +### 代码结构 +- **Controller层**:处理HTTP请求,参数验证 +- **Service层**:业务逻辑处理,事务管理 +- **Mapper层**:数据访问,SQL映射 +- **Entity层**:数据实体,数据库表映射 + +### 命名规范 +- **类名**:使用大驼峰命名法(PascalCase) +- **方法名**:使用小驼峰命名法(camelCase) +- **常量**:使用全大写,下划线分隔 +- **包名**:使用小写字母,点分隔 + +## 📚 API文档 + +项目集成了Swagger和Knife4j,提供完整的API文档: + +### 访问地址 +- **Swagger UI**: `http://localhost:9200/swagger-ui/index.html` +- **Knife4j**: `http://localhost:9200/doc.html` + +### 主要接口模块 +- **用户认证**: `/api/auth/**` - 登录、注册、权限验证 +- **用户管理**: `/api/user/**` - 用户CRUD操作 +- **内容管理**: `/api/cms/**` - 文章、媒体文件管理 +- **商城管理**: `/api/shop/**` - 商品、订单管理 +- **系统管理**: `/api/system/**` - 系统配置、日志管理 + +## 🚀 部署指南 + +### 开发环境部署 +```bash +# 1. 启动MySQL和Redis服务 +# 2. 创建数据库并导入初始数据 +# 3. 修改配置文件 +# 4. 启动应用 +mvn spring-boot:run +``` + +### 生产环境部署 +```bash +# 1. 打包应用 +mvn clean package -Dmaven.test.skip=true + +# 2. 运行jar包 +java -jar target/com-gxwebsoft-modules-1.5.0.jar --spring.profiles.active=prod + +# 3. 使用Docker部署(可选) +docker build -t websoft-api . +docker run -d -p 9200:9200 websoft-api +``` + +## 🤝 贡献指南 + +1. Fork 本仓库 +2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 打开 Pull Request + +## 📄 许可证 + +本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情 + +## 📞 联系我们 + +- 官网:https://websoft.top +- 邮箱:170083662@qq.top +- QQ群:479713884 + +--- + +⭐ 如果这个项目对您有帮助,请给我们一个星标! \ No newline at end of file diff --git a/jczxw-java/docker-compose.yml b/jczxw-java/docker-compose.yml new file mode 100644 index 0000000..ea6a7d7 --- /dev/null +++ b/jczxw-java/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.8' + +services: + # 应用服务 + cms-api: + build: . + container_name: cms-api + ports: + - "9200:9200" + environment: + - SPRING_PROFILES_ACTIVE=prod + - JAVA_OPTS=-Xms512m -Xmx1024m + volumes: + # 证书挂载卷 - 将宿主机证书目录挂载到容器 + - ./certs:/app/certs:ro + # 日志挂载卷 + - ./logs:/app/logs + # 上传文件挂载卷 + - ./uploads:/app/uploads + networks: + - cms-network + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9200/actuator/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + +networks: + cms-network: + driver: bridge + +volumes: + mysql_data: + driver: local + redis_data: + driver: local diff --git a/jczxw-java/docker-deploy-guide.md b/jczxw-java/docker-deploy-guide.md new file mode 100644 index 0000000..4961d64 --- /dev/null +++ b/jczxw-java/docker-deploy-guide.md @@ -0,0 +1,188 @@ +# Docker容器化部署指南 + +## 支付证书问题解决方案 + +本项目已经解决了Docker容器中支付证书路径失效的问题,支持多种证书加载方式。 + +## 目录结构 + +``` +project-root/ +├── Dockerfile +├── docker-compose.yml +├── certs/ # 证书目录(需要手动创建) +│ ├── wechat/ # 微信支付证书 +│ │ ├── apiclient_key.pem +│ │ ├── apiclient_cert.pem +│ │ └── wechatpay_cert.pem +│ └── alipay/ # 支付宝证书 +│ ├── app_private_key.pem +│ ├── appCertPublicKey.crt +│ ├── alipayCertPublicKey.crt +│ └── alipayRootCert.crt +├── logs/ # 日志目录 +├── uploads/ # 上传文件目录 +└── src/ +``` + +## 部署步骤 + +### 1. 准备证书文件 + +创建证书目录并放置证书文件: + +```bash +# 创建证书目录 +mkdir -p certs/wechat +mkdir -p certs/alipay + +# 复制微信支付证书到对应目录 +cp /path/to/your/apiclient_key.pem certs/wechat/ +cp /path/to/your/apiclient_cert.pem certs/wechat/ +cp /path/to/your/wechatpay_cert.pem certs/wechat/ + +# 复制支付宝证书到对应目录 +cp /path/to/your/app_private_key.pem certs/alipay/ +cp /path/to/your/appCertPublicKey.crt certs/alipay/ +cp /path/to/your/alipayCertPublicKey.crt certs/alipay/ +cp /path/to/your/alipayRootCert.crt certs/alipay/ + +# 设置证书文件权限(只读) +chmod -R 444 certs/ +``` + +### 2. 配置环境变量 + +创建 `.env` 文件(可选): + +```bash +# 应用配置 +SPRING_PROFILES_ACTIVE=prod +JAVA_OPTS=-Xms512m -Xmx1024m + +# 数据库配置 +MYSQL_ROOT_PASSWORD=root123456 +MYSQL_DATABASE=modules +MYSQL_USER=modules +MYSQL_PASSWORD=8YdLnk7KsPAyDXGA + +# Redis配置 +REDIS_PASSWORD=redis_WSDb88 +``` + +### 3. 构建和启动 + +```bash +# 构建应用 +mvn clean package -DskipTests + +# 启动所有服务 +docker-compose up -d + +# 查看服务状态 +docker-compose ps + +# 查看应用日志 +docker-compose logs -f cms-app +``` + +### 4. 验证部署 + +```bash +# 检查应用健康状态 +curl http://localhost:9200/actuator/health + +# 检查证书是否正确加载 +docker exec cms-java-app ls -la /app/certs/ +``` + +## 证书加载模式 + +### 开发环境 (CLASSPATH) +- 证书文件放在 `src/main/resources/certs/` 目录下 +- 打包时会包含在jar包中 +- 适合开发和测试环境 + +### 生产环境 (VOLUME) +- 证书文件通过Docker挂载卷加载 +- 证书文件在宿主机上,挂载到容器的 `/app/certs` 目录 +- 支持证书文件的动态更新(重启容器后生效) + +### 文件系统模式 (FILESYSTEM) +- 直接从文件系统路径加载证书 +- 适合传统部署方式 + +## 配置说明 + +### application.yml 配置 + +```yaml +certificate: + load-mode: VOLUME # 证书加载模式 + cert-root-path: /app/certs # 证书根目录 + + wechat-pay: + dev: + api-v3-key: "your-api-v3-key" + private-key-file: "apiclient_key.pem" + apiclient-cert-file: "apiclient_cert.pem" + wechatpay-cert-file: "wechatpay_cert.pem" +``` + +### 环境特定配置 + +- **开发环境**: `application-dev.yml` - 使用CLASSPATH模式 +- **生产环境**: `application-prod.yml` - 使用VOLUME模式 + +## 故障排除 + +### 1. 证书文件找不到 + +```bash +# 检查证书文件是否存在 +docker exec cms-java-app ls -la /app/certs/ + +# 检查文件权限 +docker exec cms-java-app ls -la /app/certs/wechat/ +``` + +### 2. 支付接口调用失败 + +```bash +# 查看应用日志 +docker-compose logs cms-app | grep -i cert + +# 检查证书配置 +docker exec cms-java-app cat /app/application.yml | grep -A 10 certificate +``` + +### 3. 容器启动失败 + +```bash +# 查看详细错误信息 +docker-compose logs cms-app + +# 检查容器状态 +docker-compose ps +``` + +## 安全建议 + +1. **证书文件权限**: 设置为只读权限 (444) +2. **证书目录权限**: 限制访问权限 +3. **敏感信息**: 使用环境变量或Docker secrets管理敏感配置 +4. **网络安全**: 使用内部网络,限制端口暴露 + +## 更新证书 + +1. 停止应用容器:`docker-compose stop cms-app` +2. 更新证书文件到 `certs/` 目录 +3. 重启应用容器:`docker-compose start cms-app` + +## 监控和日志 + +- 应用日志:`./logs/` 目录 +- 容器日志:`docker-compose logs` +- 健康检查:访问 `/actuator/health` 端点 + +通过以上配置,你的应用在Docker容器中就能正确加载支付证书了! diff --git a/jczxw-java/pom.xml b/jczxw-java/pom.xml new file mode 100644 index 0000000..f4f9e5f --- /dev/null +++ b/jczxw-java/pom.xml @@ -0,0 +1,451 @@ + + + 4.0.0 + + com.gxwebsoft + websopy-api + 1.5.0 + + websopy-api + WebSoftApi project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.7.18 + + + + + 17 + UTF-8 + UTF-8 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-security + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.projectlombok + lombok + true + + + + + + com.mysql + mysql-connector-j + runtime + + + + + org.postgresql + postgresql + runtime + + + + + com.alibaba + druid-spring-boot-starter + 1.2.20 + + + + + com.baomidou + mybatis-plus-boot-starter + 3.4.3.3 + + + + + com.github.yulichang + mybatis-plus-join-boot-starter + 1.4.5 + + + + + com.baomidou + mybatis-plus-generator + 3.4.1 + + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + com.github.ben-manes.caffeine + caffeine + 3.1.8 + + + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + com.github.mwiede + jsch + 0.2.18 + + + + + com.alibaba + fastjson + 2.0.43 + + + + + com.google.code.gson + gson + 2.10.1 + + + + + org.apache.tika + tika-core + 2.9.1 + + + + + cn.hutool + hutool-core + 5.8.25 + + + cn.hutool + hutool-extra + 5.8.25 + + + cn.hutool + hutool-http + 5.8.25 + + + cn.hutool + hutool-crypto + 5.8.25 + + + cn.hutool + hutool-json + 5.8.25 + + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + + + + + com.github.whvcse + easy-captcha + 1.6.2 + + + + + org.springframework.boot + spring-boot-starter-amqp + + + + + + org.springdoc + springdoc-openapi-ui + 1.7.0 + + + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + 4.3.0 + + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + org.springframework.boot + spring-boot-starter-mail + + + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.17 + + + + + com.aliyun + alimt20181012 + 1.0.3 + + + + + cn.afterturn + easypoi-base + 4.4.0 + + + + + com.ibeetl + beetl + 3.15.10.RELEASE + + + + + com.github.binarywang + weixin-java-miniapp + 4.6.0 + + + + + com.github.kuaidi100-api + sdk + 1.0.13 + + + + + com.alipay.sdk + alipay-sdk-java + 4.35.0.ALL + + + + + com.aliyun + aliyun-java-sdk-core + 4.6.2 + + + + + com.aliyun + cloudauth20190307 + 3.13.1 + + + + + com.github.livesense + jodconverter-core + 1.0.5 + + + + + com.google.zxing + core + 3.5.2 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mockito + mockito-core + 4.11.0 + test + + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + + org.apache.httpcomponents + httpclient + 4.5.14 + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.17.4 + + + + + com.qcloud + cos_api + 5.6.157 + + + + + com.huaweicloud + esdk-obs-java + 3.25.10 + + + + + com.qiniu + qiniu-java-sdk + 7.19.0 + + + + + com.github.binarywang + weixin-java-mp + 4.6.0 + + + + + + + + src/main/java + + **/*Mapper.xml + + + + src/main/resources + + ** + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.project-lombok + lombok + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + org.projectlombok + lombok + 1.18.30 + + + org.springframework.boot + spring-boot-configuration-processor + 2.7.18 + + + + + + + + + + aliYunMaven + https://maven.aliyun.com/repository/public + + + aliyun-sdk + https://maven.aliyun.com/nexus/content/groups/public/ + + + central + https://repo.maven.apache.org/maven2 + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/WebSoftApplication.java b/jczxw-java/src/main/java/com/gxwebsoft/WebSoftApplication.java new file mode 100644 index 0000000..1a7fa35 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/WebSoftApplication.java @@ -0,0 +1,31 @@ +package com.gxwebsoft; + +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.config.MqttProperties; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.socket.config.annotation.EnableWebSocket; + +/** + * 启动类 + * Created by WebSoft on 2018-02-22 11:29:03 + */ +@EnableAsync +@EnableTransactionManagement +@MapperScan("com.gxwebsoft.**.mapper") +@EnableConfigurationProperties({ConfigProperties.class, MqttProperties.class}) +@SpringBootApplication +@EnableScheduling +@EnableWebSocket +public class WebSoftApplication { + + public static void main(String[] args) { + SpringApplication.run(WebSoftApplication.class, args); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/config/AppPayProperties.java b/jczxw-java/src/main/java/com/gxwebsoft/app/config/AppPayProperties.java new file mode 100644 index 0000000..8c871fc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/config/AppPayProperties.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.app.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 应用模块微信支付配置属性 + * 微信支付 Native 支付(扫码支付)配置 + */ +@Data +@Component +@ConfigurationProperties(prefix = "app.pay.wx") +public class AppPayProperties { + + /** 是否启用微信支付 */ + private boolean enabled = true; + + /** 商户号 */ + private String mchId; + + /** 商户证书序列号 */ + private String merchantSerialNumber; + + /** APIv3 密钥 */ + private String apiV3Key; + + /** 微信支付 AppId(服务商/直连商户对应的小程序/公众号/网站应用) */ + private String appId; + + /** 证书根目录路径(生产环境 Docker 挂载卷路径) */ + private String certRootPath; + + /** 商户私钥文件相对路径(相对于 certRootPath) */ + private String privateKeyRelativePath = "wechat/apiclient_key.pem"; + + /** 微信支付平台证书文件相对路径 */ + private String wechatpayCertRelativePath = "wechat/wechatpay_cert.pem"; + + /** 微信支付公钥文件相对路径(使用公钥模式时必填) */ + private String wechatpayPublicKeyPath; + + /** 微信支付公钥ID(使用公钥模式时必填) */ + private String wechatpayPublicKeyId; + + /** 支付成功回调地址 */ + private String notifyUrl; + + /** 是否为测试模式(使用测试商户号) */ + private boolean testMode = false; + + // ===================== 测试商户配置(testMode=true 时使用)===================== + + /** 测试商户号 */ + private String testMchId; + + /** 测试商户序列号 */ + private String testMerchantSerialNumber; + + /** 测试 APIv3 密钥 */ + private String testApiV3Key; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppApiKeyController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppApiKeyController.java new file mode 100644 index 0000000..e093352 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppApiKeyController.java @@ -0,0 +1,164 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppApiKey; +import com.gxwebsoft.app.param.AppApiKeyParam; +import com.gxwebsoft.app.service.AppApiKeyService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 应用 API Key 管理控制器 + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Slf4j +@Tag(name = "应用API Key管理") +@RestController +@RequestMapping("/api/app/apikey") +public class AppApiKeyController extends BaseController { + + @Resource + private AppApiKeyService appApiKeyService; + + @Operation(summary = "分页查询API Key列表") + @GetMapping + public ApiResult> page(AppApiKeyParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + param.setUserId(loginUser.getUserId()); + param.setTenantId(loginUser.getTenantId()); + return success(appApiKeyService.pageRel(param)); + } + + @Operation(summary = "查询API Key详情") + @GetMapping("/{id}") + public ApiResult get(@PathVariable Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + AppApiKey apiKey = appApiKeyService.getByIdRel(id); + if (apiKey == null) { + return fail("API Key不存在",null); + } + if (!apiKey.getUserId().equals(loginUser.getUserId())) { + return fail("无权访问此API Key",null); + } + return success(apiKey); + } + + @Operation(summary = "创建API Key") + @PostMapping + public ApiResult create(@RequestBody AppApiKey apiKey) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + try { + AppApiKey result = appApiKeyService.createApiKey( + apiKey, loginUser.getUserId(), loginUser.getTenantId()); + return success("API Key创建成功,请妥善保管", result); + } catch (Exception e) { + log.error("创建API Key失败", e); + return fail(e.getMessage(),null); + } + } + + @Operation(summary = "更新API Key信息") + @PutMapping("/{id}") + public ApiResult update(@PathVariable Long id, @RequestBody AppApiKey apiKey) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + AppApiKey existing = appApiKeyService.getByIdRel(id); + if (existing == null) { + return fail("API Key不存在"); + } + if (!existing.getUserId().equals(loginUser.getUserId())) { + return fail("无权修改此API Key"); + } + apiKey.setId(id); + apiKey.setUserId(loginUser.getUserId()); + try { + appApiKeyService.updateApiKey(apiKey); + return success("更新成功"); + } catch (Exception e) { + log.error("更新API Key失败", e); + return fail(e.getMessage()); + } + } + + @Operation(summary = "更新API Key状态") + @PutMapping("/{id}/status") + public ApiResult updateStatus(@PathVariable Long id, @RequestParam Integer status) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + appApiKeyService.updateStatus(id, status, loginUser.getUserId()); + return success(status == 0 ? "已启用" : "已禁用"); + } catch (Exception e) { + log.error("更新API Key状态失败", e); + return fail(e.getMessage()); + } + } + + @Operation(summary = "删除API Key") + @DeleteMapping("/{id}") + public ApiResult delete(@PathVariable Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + appApiKeyService.removeApiKey(id, loginUser.getUserId()); + return success("删除成功"); + } catch (Exception e) { + log.error("删除API Key失败", e); + return fail(e.getMessage()); + } + } + + @Operation(summary = "获取API Key统计信息") + @GetMapping("/stats") + public ApiResult> stats() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + return success(appApiKeyService.statsByUser( + loginUser.getUserId(), loginUser.getTenantId())); + } + + @Operation(summary = "获取速率限制信息") + @GetMapping("/rate-limits") + public ApiResult> rateLimits() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + // 返回默认速率限制(实际可根据用户等级调整) + Map limits = Map.of( + "plan", "免费版", + "rps", 5, + "dailyLimit", 1000, + "usedToday", 0, + "remainingToday", 1000 + ); + return success(limits); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppArticleCategoryController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppArticleCategoryController.java new file mode 100644 index 0000000..f15068d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppArticleCategoryController.java @@ -0,0 +1,80 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppArticleCategory; +import com.gxwebsoft.app.param.AppArticleCategoryParam; +import com.gxwebsoft.app.service.AppArticleCategoryService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 平台文章分类控制器 + */ +@Tag(name = "平台文章分类管理") +@RestController +@RequestMapping("/api/app/article-category") +public class AppArticleCategoryController extends BaseController { + + @Resource + private AppArticleCategoryService appArticleCategoryService; + + @Operation(summary = "分页查询平台文章分类") + @GetMapping("/page") + public ApiResult> page(AppArticleCategoryParam param) { + if (param.getTenantId() == null) { + param.setTenantId(getTenantId()); + } + return success(appArticleCategoryService.page(param)); + } + + @Operation(summary = "查询平台文章分类列表") + @GetMapping() + public ApiResult> list(AppArticleCategoryParam param) { + if (param.getTenantId() == null) { + param.setTenantId(getTenantId()); + } + return success(appArticleCategoryService.list(param)); + } + + @Operation(summary = "根据ID读取文章分类") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(appArticleCategoryService.getDetail(id)); + } + + @Operation(summary = "新增平台文章分类") + @PostMapping() + public ApiResult save(@RequestBody AppArticleCategory category) { + User loginUser = getLoginUser(); + Integer tenantId = category.getTenantId() != null ? category.getTenantId() : getTenantId(); + if (appArticleCategoryService.saveCategory(category, loginUser, tenantId)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改平台文章分类") + @PutMapping() + public ApiResult update(@RequestBody AppArticleCategory category) { + if (appArticleCategoryService.updateCategory(category)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除平台文章分类") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (appArticleCategoryService.removeCategory(id)) { + return success("删除成功"); + } + return fail("该分类下还有文章,不能删除"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppArticleController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppArticleController.java new file mode 100644 index 0000000..e8c5a9f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppArticleController.java @@ -0,0 +1,100 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppArticle; +import com.gxwebsoft.app.param.AppArticleParam; +import com.gxwebsoft.app.service.AppArticleService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 平台文章控制器 + */ +@Tag(name = "平台文章管理") +@RestController +@RequestMapping("/api/app/article") +public class AppArticleController extends BaseController { + + @Resource + private AppArticleService appArticleService; + + @Operation(summary = "分页查询平台文章") + @GetMapping("/page") + public ApiResult> page(AppArticleParam param) { + if (param.getTenantId() == null) { + param.setTenantId(getTenantId()); + } + return success(appArticleService.page(param)); + } + + @Operation(summary = "查询平台文章列表") + @GetMapping() + public ApiResult> list(AppArticleParam param) { + if (param.getTenantId() == null) { + param.setTenantId(getTenantId()); + } + return success(appArticleService.list(param)); + } + + @Operation(summary = "根据ID读取文章详情") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + AppArticle article = appArticleService.getDetail(id, true); + if (article == null) { + return fail("文章不存在", null); + } + return success(article); + } + + @Operation(summary = "根据编码读取文章详情") + @GetMapping("/getByCode/{code}") + public ApiResult getByCode(@PathVariable("code") String code) { + return success(appArticleService.getByCode(code)); + } + + @Operation(summary = "新增平台文章") + @PostMapping() + public ApiResult save(@RequestBody AppArticle article) { + User loginUser = getLoginUser(); + Integer tenantId = article.getTenantId() != null ? article.getTenantId() : getTenantId(); + if (appArticleService.saveArticle(article, loginUser, tenantId)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改平台文章") + @PutMapping() + public ApiResult update(@RequestBody AppArticle article) { + if (appArticleService.updateArticle(article)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除平台文章") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (appArticleService.removeArticle(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "平台文章统计") + @GetMapping("/data") + public ApiResult> data(AppArticleParam param) { + if (param.getTenantId() == null) { + param.setTenantId(getTenantId()); + } + return success(appArticleService.getStats(param)); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppCloudCredentialController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppCloudCredentialController.java new file mode 100644 index 0000000..c32085a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppCloudCredentialController.java @@ -0,0 +1,201 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppCloudCredential; +import com.gxwebsoft.app.param.AppCloudCredentialParam; +import com.gxwebsoft.app.service.AppCloudCredentialService; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 云账号凭证管理控制器 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +@Tag(name = "云账号凭证管理") +@RestController +@RequestMapping("/api/app/cloud-credential") +public class AppCloudCredentialController extends BaseController { + + @Resource + private AppCloudCredentialService appCloudCredentialService; + + @Operation(summary = "分页查询凭证列表") + @GetMapping("/page") + public ApiResult page(AppCloudCredentialParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + param.setUserId(loginUser.getUserId()); + param.setTenantId(loginUser.getTenantId()); + return success(appCloudCredentialService.pageRel(param)); + } + + @Operation(summary = "查询凭证列表(不分页)") + @GetMapping + public ApiResult list(AppCloudCredentialParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + param.setUserId(loginUser.getUserId()); + param.setTenantId(loginUser.getTenantId()); + return success(appCloudCredentialService.listRel(param)); + } + + @Operation(summary = "获取凭证详情") + @GetMapping("/{id}") + public ApiResult get(@PathVariable Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + AppCloudCredential credential = appCloudCredentialService.getById(id); + if (credential == null) return fail("凭证不存在"); + if (!credential.getUserId().equals(loginUser.getUserId())) { + return fail("无权访问此凭证"); + } + return success(credential); + } + + @OperationLog + @Operation(summary = "新增凭证") + @PostMapping + public ApiResult add(@RequestBody AppCloudCredential credential) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + credential.setUserId(loginUser.getUserId()); + credential.setTenantId(loginUser.getTenantId()); + try { + AppCloudCredential result = appCloudCredentialService.add(credential); + return success("添加成功", result); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + @OperationLog + @Operation(summary = "修改凭证") + @PutMapping + public ApiResult update(@RequestBody AppCloudCredential credential) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + // 检查归属 + AppCloudCredential exist = appCloudCredentialService.getById(credential.getId()); + if (exist == null) return fail("凭证不存在"); + if (!exist.getUserId().equals(loginUser.getUserId())) { + return fail("无权修改此凭证"); + } + try { + AppCloudCredential result = appCloudCredentialService.update(credential); + return success("修改成功", result); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + @OperationLog + @Operation(summary = "删除凭证") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + try { + appCloudCredentialService.remove(id, loginUser.getUserId()); + return success("删除成功"); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + @Operation(summary = "测试凭证连接") + @PostMapping("/test-connection") + public ApiResult testConnection(@RequestBody Map params) { + String provider = (String) params.get("provider"); + String accessKeyId = (String) params.get("accessKeyId"); + String accessKeySecret = (String) params.get("accessKeySecret"); + String configJson = (String) params.get("configJson"); + + if (provider == null || provider.isEmpty()) { + return fail("请指定云服务商"); + } + if (accessKeyId == null || accessKeySecret == null) { + return fail("请提供访问密钥"); + } + + // 构建凭证映射 + java.util.Map credentials = new java.util.HashMap<>(); + credentials.put("accessKeyId", accessKeyId); + credentials.put("accessKeySecret", accessKeySecret); + if (configJson != null) { + try { + Map config = new com.alibaba.fastjson.JSONObject() + .parseObject(configJson, Map.class); + credentials.putAll(config); + } catch (Exception e) { + log.warn("解析配置JSON失败: {}", e.getMessage()); + } + } + + boolean success = appCloudCredentialService.testConnection(provider, credentials); + return success ? success("连接成功") : fail("连接失败"); + } + + @Operation(summary = "根据ID测试凭证连接") + @PostMapping("/test/{id}") + public ApiResult testConnectionById(@PathVariable Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + AppCloudCredential credential = appCloudCredentialService.getById(id); + if (credential == null) return fail("凭证不存在"); + if (!credential.getUserId().equals(loginUser.getUserId())) { + return fail("无权访问此凭证"); + } + try { + // 使用专门的 ID 查询方法,获取已解密的凭证 + java.util.Map credentials = appCloudCredentialService.getCredentialsByCredentialId(id); + if (credentials == null) { + return fail("获取凭证失败"); + } + // 使用返回详细消息的测试方法 + Object[] result = appCloudCredentialService.testConnectionWithMessage(credential.getProvider(), credentials); + boolean success = (Boolean) result[0]; + String message = (String) result[1]; + + credential.setTestStatus(success ? 1 : 2); + credential.setTestMessage(message); + appCloudCredentialService.updateById(credential); + + java.util.Map resultMap = new java.util.HashMap<>(); + resultMap.put("success", success); + resultMap.put("message", success ? "连接成功" : message); + return success(resultMap); + } catch (Exception e) { + log.error("测试连接异常: {}", e.getMessage(), e); + // 即使异常也更新状态 + try { + credential.setTestStatus(2); + credential.setTestMessage("连接失败: " + e.getMessage()); + appCloudCredentialService.updateById(credential); + } catch (Exception ex) { + log.error("更新测试状态失败: {}", ex.getMessage()); + } + java.util.Map errorResult = new java.util.HashMap<>(); + errorResult.put("success", false); + errorResult.put("message", "测试连接失败: " + e.getMessage()); + return success(errorResult); + } + } + + @Operation(summary = "获取支持的云服务商列表") + @GetMapping("/providers") + public ApiResult providers() { + return success(com.gxwebsoft.app.service.cloud.CloudStorageProviderFactory.getSupportedProviders()); + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppConfigController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppConfigController.java new file mode 100644 index 0000000..bf5f665 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppConfigController.java @@ -0,0 +1,129 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.app.entity.AppConfig; +import com.gxwebsoft.app.param.AppConfigParam; +import com.gxwebsoft.app.service.AppConfigService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 应用配置表 Controller + */ +@Slf4j +@Tag(name = "应用配置管理") +@RestController +@RequestMapping("/api/app/app-config") +public class AppConfigController extends BaseController { + + @Resource + private AppConfigService appConfigService; + + /** + * 分页查询应用配置 + */ + @Operation(summary = "分页查询应用配置") + @GetMapping("/page") + public ApiResult> page(AppConfigParam param) { + return success(new PageResult<>(appConfigService.page(param))); + } + + /** + * 获取应用配置列表 + */ + @Operation(summary = "获取应用配置列表") + @GetMapping() + public ApiResult> list(AppConfigParam param) { + return success(appConfigService.list(param)); + } + + /** + * 根据应用ID获取配置映射 + */ + @Operation(summary = "根据应用ID获取配置映射") + @GetMapping("/map/{appId}") + public ApiResult> getConfigsByAppId(@PathVariable Integer appId) { + return success(appConfigService.getConfigsByAppId(appId)); + } + + /** + * 获取单个配置值 + */ + @Operation(summary = "获取单个配置值") + @GetMapping("/value") + public ApiResult getConfigValue(@RequestParam Integer appId, @RequestParam String configKey) { + return success(appConfigService.getConfigValue(appId, configKey),null); + } + + /** + * 保存配置 + */ + @Operation(summary = "保存配置") + @PostMapping() + public ApiResult save(@RequestBody AppConfig config) { + appConfigService.saveConfig(config); + return success("保存成功"); + } + + /** + * 批量保存配置 + */ + @Operation(summary = "批量保存配置") + @PostMapping("/batch") + public ApiResult batchSave(@RequestBody BatchSaveRequest request) { + appConfigService.batchSaveConfig(request.getAppId(), request.getConfigs()); + return success("保存成功"); + } + + /** + * 更新配置 + */ + @Operation(summary = "更新配置") + @PutMapping() + public ApiResult update(@RequestBody AppConfig config) { + appConfigService.updateConfig(config); + return success("更新成功"); + } + + /** + * 删除配置 + */ + @Operation(summary = "删除配置") + @DeleteMapping("/{configId}") + public ApiResult delete(@PathVariable Integer configId) { + appConfigService.deleteConfig(configId); + return success("删除成功"); + } + + /** + * 批量保存请求对象 + */ + public static class BatchSaveRequest { + private Integer appId; + private List configs; + + public Integer getAppId() { + return appId; + } + + public void setAppId(Integer appId) { + this.appId = appId; + } + + public List getConfigs() { + return configs; + } + + public void setConfigs(List configs) { + this.configs = configs; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppContractController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppContractController.java new file mode 100644 index 0000000..a40c26c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppContractController.java @@ -0,0 +1,103 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppContract; +import com.gxwebsoft.app.param.AppContractParam; +import com.gxwebsoft.app.service.AppContractService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 合同管理控制器 + * + * @author 科技小王子 + * @since 2026-04-13 + */ +@Slf4j +@Tag(name = "合同管理") +@RestController +@RequestMapping("/api/app/contract") +public class AppContractController extends BaseController { + + @Resource + private AppContractService appContractService; + + @Operation(summary = "分页查询合同列表") + @GetMapping("/page") + public ApiResult> page(AppContractParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + return success(appContractService.page(param, loginUser.getUserId())); + } + + @Operation(summary = "获取合同详情") + @GetMapping("/{contractId}") + public ApiResult detail(@PathVariable Long contractId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + AppContract contract = appContractService.getById(contractId); + if (contract == null || contract.getDeleted() == 1) { + return fail("合同不存在", null); + } + if (!contract.getUserId().equals(loginUser.getUserId())) { + return fail("无权查看该合同", null); + } + return success(contract); + } + + @Operation(summary = "新增合同") + @PostMapping + public ApiResult create(@RequestBody AppContract contract) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + try { + AppContract result = appContractService.create(contract, loginUser.getUserId()); + return success("合同创建成功", result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + @Operation(summary = "更新合同") + @PutMapping("/{contractId}") + public ApiResult update(@PathVariable Long contractId, @RequestBody AppContract contract) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + contract.setContractId(contractId); + try { + AppContract result = appContractService.update(contract, loginUser.getUserId()); + return success("合同更新成功", result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + @Operation(summary = "删除合同") + @DeleteMapping("/{contractId}") + public ApiResult remove(@PathVariable Long contractId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + try { + appContractService.remove(contractId, loginUser.getUserId()); + return success("合同已删除"); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + @Operation(summary = "合同统计数据") + @GetMapping("/stats") + public ApiResult> stats() { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + return success(appContractService.stats(loginUser.getUserId())); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppCredentialController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppCredentialController.java new file mode 100644 index 0000000..5db2671 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppCredentialController.java @@ -0,0 +1,154 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.app.service.AppCredentialService; +import com.gxwebsoft.app.entity.AppCredential; +import com.gxwebsoft.app.param.AppCredentialParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 应用密钥凭证控制器 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Slf4j +@Tag(name = "应用密钥凭证管理") +@RestController +@RequestMapping("/api/app/app-credential") +public class AppCredentialController extends BaseController { + + @Resource + private AppCredentialService appCredentialService; + + @Operation(summary = "分页查询应用密钥凭证") + @GetMapping("/page") + public ApiResult> page(AppCredentialParam param) { + return success(appCredentialService.pageRel(param)); + } + + @Operation(summary = "查询全部应用密钥凭证") + @GetMapping() + public ApiResult> list(AppCredentialParam param) { + return success(appCredentialService.listRel(param)); + } + + @Operation(summary = "根据id查询应用密钥凭证") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(appCredentialService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('app:appCredential:save')") + @OperationLog + @Operation(summary = "创建应用密钥凭证(自动生成 ClientID 和 ClientSecret)") + @PostMapping() + public ApiResult save(@RequestBody AppCredential appCredential) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + if (appCredential.getAppId() == null) { + return fail("请选择关联应用"); + } + appCredential.setUserId(loginUser.getUserId()); + // 创建并生成密钥 + AppCredential result = appCredentialService.createCredential(appCredential); + return success("创建成功,请保存 ClientSecret,该信息仅展示一次", result); + } + + @PreAuthorize("hasAuthority('app:appCredential:update')") + @OperationLog + @Operation(summary = "修改应用密钥凭证(名称/类型/备注等,不含密钥)") + @PutMapping() + public ApiResult update(@RequestBody AppCredential appCredential) { + // 防止通过此接口直接修改 appId/appSecret + appCredential.setAppId(null); + appCredential.setClientSecret(null); + if (appCredentialService.updateById(appCredential)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appCredential:update')") + @OperationLog + @Operation(summary = "重置 AppSecret(重新生成密钥)") + @PostMapping("/resetSecret/{id}") + public ApiResult resetSecret(@PathVariable("id") Long id) { + try { + AppCredential result = appCredentialService.resetSecret(id); + return success("重置成功,请保存新 AppSecret,该信息仅展示一次", result); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('app:appCredential:update')") + @OperationLog + @Operation(summary = "禁用/启用凭证") + @PutMapping("/status/{id}/{status}") + public ApiResult updateStatus(@PathVariable("id") Long id, @PathVariable("status") Integer status) { + if (appCredentialService.updateStatus(id, status)) { + return success(status == 0 ? "已启用" : "已禁用"); + } + return fail("操作失败"); + } + + @PreAuthorize("hasAuthority('app:appCredential:remove')") + @OperationLog + @Operation(summary = "删除应用密钥凭证") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (appCredentialService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('app:appCredential:save')") + @OperationLog + @Operation(summary = "批量添加应用密钥凭证") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (appCredentialService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('app:appCredential:update')") + @OperationLog + @Operation(summary = "批量修改应用密钥凭证") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(appCredentialService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appCredential:remove')") + @OperationLog + @Operation(summary = "批量删除应用密钥凭证") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (appCredentialService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppEventController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppEventController.java new file mode 100644 index 0000000..04c961c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppEventController.java @@ -0,0 +1,133 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.app.service.AppEventService; +import com.gxwebsoft.app.entity.AppEvent; +import com.gxwebsoft.app.param.AppEventParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 应用操作动态控制器 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Slf4j +@Tag(name = "应用操作动态管理") +@RestController +@RequestMapping("/api/app/app-event") +public class AppEventController extends BaseController { + + @Resource + private AppEventService appEventService; + + @Operation(summary = "分页查询操作动态") + @GetMapping("/page") + public ApiResult> page(AppEventParam param) { + return success(appEventService.pageRel(param)); + } + + @Operation(summary = "查询全部操作动态") + @GetMapping() + public ApiResult> list(AppEventParam param) { + return success(appEventService.listRel(param)); + } + + @Operation(summary = "根据id查询操作动态") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(appEventService.getByIdRel(id)); + } + + @Operation(summary = "获取应用最新一条动态(用于卡片展示)") + @GetMapping("/latest/{appId}") + public ApiResult getLatest(@PathVariable("appId") Long appId) { + return success(appEventService.getLatestEvent(appId)); + } + + @PreAuthorize("hasAuthority('app:appEvent:save')") + @OperationLog + @Operation(summary = "手动记录操作动态") + @PostMapping() + public ApiResult save(@RequestBody AppEvent appEvent) { + User loginUser = getLoginUser(); + if (loginUser != null) { + appEvent.setUserId(loginUser.getUserId()); + appEvent.setTenantId(loginUser.getTenantId()); + if (appEvent.getOperatorId() == null) { + appEvent.setOperatorId(loginUser.getUserId().longValue()); + } + if (appEvent.getOperator() == null) { + appEvent.setOperator(loginUser.getNickname()); + } + } + if (appEventService.save(appEvent)) { + return success("记录成功"); + } + return fail("记录失败"); + } + + @PreAuthorize("hasAuthority('app:appEvent:update')") + @OperationLog + @Operation(summary = "修改操作动态") + @PutMapping() + public ApiResult update(@RequestBody AppEvent appEvent) { + if (appEventService.updateById(appEvent)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appEvent:remove')") + @OperationLog + @Operation(summary = "删除操作动态") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (appEventService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('app:appEvent:remove')") + @OperationLog + @Operation(summary = "清空应用所有动态记录") + @DeleteMapping("/clear/{appId}") + public ApiResult clearByAppId(@PathVariable("appId") Long appId) { + // 只清空当前租户下的数据 + AppEventParam param = new AppEventParam(); + param.setAppId(appId); + List list = appEventService.listRel(param); + if (list.isEmpty()) { + return success("暂无动态记录"); + } + List ids = list.stream().map(AppEvent::getId).collect(java.util.stream.Collectors.toList()); + if (appEventService.removeByIds(ids)) { + return success("已清空 " + ids.size() + " 条动态记录"); + } + return fail("清空失败"); + } + + @PreAuthorize("hasAuthority('app:appEvent:remove')") + @OperationLog + @Operation(summary = "批量删除操作动态") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (appEventService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppInviteController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppInviteController.java new file mode 100644 index 0000000..873ebff --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppInviteController.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.service.AppInviteService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 应用成员邀请 Controller + */ +@Tag(name = "应用成员邀请") +@RestController +@RequestMapping("/api/app/developer/invite") +@RequiredArgsConstructor +public class AppInviteController extends BaseController { + + private final AppInviteService appInviteService; + + @Operation(summary = "生成二维码邀请") + @PreAuthorize("hasAuthority('app:appUser:save')") + @PostMapping("/qrcode") + public ApiResult> generateQrCode(@RequestBody Map params) { + Integer appId = (Integer) params.get("appId"); + String role = (String) params.get("role"); + Integer currentUserId = getLoginUserId(); + + Map result = appInviteService.generateQrCodeInvite(appId, role, currentUserId); + return success(result); + } + + @Operation(summary = "生成链接邀请") + @PreAuthorize("hasAuthority('app:appUser:save')") + @PostMapping("/link") + public ApiResult> generateLink(@RequestBody Map params) { + Integer appId = (Integer) params.get("appId"); + String role = (String) params.get("role"); + Integer currentUserId = getLoginUserId(); + + Map result = appInviteService.generateLinkInvite(appId, role, currentUserId); + return success(result); + } + + @Operation(summary = "验证邀请") + @PostMapping("/verify") + public ApiResult> verifyInvite(@RequestBody Map params) { + String token = (String) params.get("token"); + Integer appId = (Integer) params.get("appId"); + + Map result = appInviteService.verifyInvite(token, appId); + return success(result); + } + + @Operation(summary = "通过Token获取邀请信息(小程序专用)") + @GetMapping("/info") + public ApiResult> getInviteInfo(@RequestParam String token) { + Map result = appInviteService.getInviteInfoByToken(token); + return success(result); + } + + @Operation(summary = "接受邀请(支持小程序手机号自动注册)") + @PostMapping("/accept") + public ApiResult acceptInvite(@RequestBody Map params) { + String token = (String) params.get("token"); + Integer currentUserId = getLoginUserId(); + + // 已登录用户直接加入 + if (currentUserId != null) { + Integer appId = (Integer) params.get("appId"); + appInviteService.acceptInvite(token, appId, currentUserId); + return success("加入成功"); + } + + // 小程序手机号登录 + 加入(需要 code) + String code = (String) params.get("code"); + if (code != null) { + // TODO: 调用微信手机号登录接口,自动注册用户并加入 + // 这里暂时返回提示 + return fail("手机号登录功能开发中,请先在网页端登录"); + } + + return fail("请先登录"); + } + + @Operation(summary = "查询邀请状态(用于轮询检测是否被使用)") + @GetMapping("/status") + public ApiResult> getInviteStatus(@RequestParam String token) { + Map result = appInviteService.getInviteStatus(token); + return success(result); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppMpInviteController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppMpInviteController.java new file mode 100644 index 0000000..78065fb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppMpInviteController.java @@ -0,0 +1,431 @@ +package com.gxwebsoft.app.controller; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.app.entity.AppInviteToken; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.entity.AppUserCache; +import com.gxwebsoft.app.mapper.AppInviteTokenMapper; +import com.gxwebsoft.app.mapper.AppProductMapper; +import com.gxwebsoft.app.mapper.AppUserCacheMapper; +import com.gxwebsoft.app.mapper.AppUserMapper; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 小程序邀请接口(处理 /api/_app 路径) + * 用于小程序扫码加入应用场景 + */ +@Slf4j +@Tag(name = "小程序邀请") +@RestController +@RequestMapping("/api/_app/developer/invite") +@RequiredArgsConstructor +public class AppMpInviteController extends BaseController { + + private final AppInviteTokenMapper appInviteTokenMapper; + private final AppProductMapper appProductMapper; + private final AppUserMapper appUserMapper; + private final AppUserCacheMapper appUserCacheMapper; + private final AppUserCacheService appUserCacheService; + + @Value("${app.invite.base-url:https://websopy.websoft.top}") + private String baseUrl; + + @Value("${spring.redis.host:127.0.0.1}") + private String redisHost; + + @Value("${spring.redis.port:6379}") + private int redisPort; + + @Value("${spring.redis.password:}") + private String redisPassword; + + @Operation(summary = "通过Token获取邀请信息(小程序专用)") + @GetMapping("/info") + public ApiResult> getInviteInfo(@RequestParam String token) { + try { + Map result = getInviteInfoByToken(token); + return success(result); + } catch (Exception e) { + log.error("获取邀请信息失败", e); + return fail("获取邀请信息失败"); + } + } + + @Operation(summary = "验证邀请(PC端和小程序通用)") + @PostMapping("/verify") + public ApiResult> verifyInvite(@RequestBody Map params) { + try { + String token = (String) params.get("token"); + Integer appId = (Integer) params.get("appId"); + + AppInviteToken inviteToken = appInviteTokenMapper.selectByToken(token); + if (inviteToken == null) { + return fail("邀请不存在或已失效"); + } + if (appId != null && !inviteToken.getAppId().equals(appId)) { + return fail("邀请与应用不匹配"); + } + if (inviteToken.getExpireTime().isBefore(LocalDateTime.now())) { + return fail("邀请已过期"); + } + if (inviteToken.getStatus() != 0) { + return fail("邀请已被使用"); + } + + AppProduct app = appProductMapper.selectById(inviteToken.getAppId()); + if (app == null) { + return fail("应用不存在"); + } + + AppUserCache inviter = appUserCacheService.getByUserId(inviteToken.getInviterId()); + + Map result = new HashMap<>(); + result.put("appId", inviteToken.getAppId()); + result.put("appName", app.getProductName()); + result.put("appIcon", app.getIcon()); + result.put("inviterName", inviter != null ? inviter.getNickname() : "未知"); + result.put("inviterAvatar", inviter != null ? inviter.getAvatar() : null); + result.put("role", inviteToken.getRole()); + result.put("expireTime", inviteToken.getExpireTime().toString()); + return success(result); + } catch (Exception e) { + log.error("验证邀请失败", e); + return fail("验证邀请失败"); + } + } + + @Operation(summary = "接受邀请(小程序专用,支持已登录和未注册两种模式)") + @PostMapping("/accept") + @Transactional(rollbackFor = Exception.class) + public ApiResult acceptInvite(@RequestBody Map params) { + String token = (String) params.get("token"); + String code = (String) params.get("code"); + + if (StrUtil.isBlank(token)) { + return fail("邀请 token 不能为空"); + } + + try { + // 1. 验证邀请 token + AppInviteToken inviteToken = appInviteTokenMapper.selectByToken(token); + if (inviteToken == null) { + return fail("邀请不存在或已失效"); + } + if (inviteToken.getExpireTime().isBefore(LocalDateTime.now())) { + return fail("邀请已过期"); + } + if (inviteToken.getStatus() != 0) { + return fail("邀请已被使用"); + } + + Integer userId; + + // 2. 判断是已登录用户还是未注册用户 + if (StrUtil.isBlank(code)) { + // ===== 模式一:已登录用户(通过 Authorization 头识别)===== + log.info("接受邀请 - 已登录用户模式(通过token识别)"); + userId = getLoginUserId(); + if (userId == null) { + return fail("用户未登录,请先登录"); + } + log.info("已登录用户加入应用: userId={}", userId); + } else { + // ===== 模式二:未注册用户(通过微信授权码获取手机号)===== + log.info("接受邀请 - 未注册用户模式(通过手机号授权码)"); + + // 2.1 通过微信手机号 code 获取手机号 + String phone = getPhoneByCode(code); + if (StrUtil.isBlank(phone)) { + return fail("获取手机号失败,请重试"); + } + + // 2.2 查询用户,不存在则创建 + userId = getOrCreateUserByPhone(phone); + if (userId == null) { + return fail("用户创建失败"); + } + log.info("未注册用户加入应用: phone={}, userId={}", phone, userId); + } + + // 4. 检查是否已经是成员 + AppUser existUser = appUserMapper.selectOne( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(AppUser::getAppId, inviteToken.getAppId().longValue()) + .eq(AppUser::getUserId, userId) + ); + if (existUser != null && existUser.getInviteStatus() == 0) { + return fail("你已经是该应用的成员"); + } + + // 5. 添加为应用成员(直接加入,不走待确认流程) + AppUser appUser = new AppUser(); + appUser.setAppId(inviteToken.getAppId().longValue()); + appUser.setUserId(userId); + appUser.setRole(inviteToken.getRole() != null ? inviteToken.getRole() : "developer"); + appUser.setInviteBy(inviteToken.getInviterId().longValue()); + appUser.setInviteTime(LocalDateTime.now()); + appUser.setStatus(0); + appUser.setInviteStatus(0); // 直接确认 + appUser.setSortNumber(0); + + // 从 AppProduct 获取 tenantId + AppProduct app = appProductMapper.selectById(inviteToken.getAppId()); + appUser.setTenantId(app != null ? app.getTenantId() : null); + + // 补充用户信息 + AppUserCache userCache = appUserCacheService.getByUserId(userId); + if (userCache != null) { + appUser.setUsername(userCache.getUsername()); + appUser.setNickname(userCache.getNickname()); + appUser.setAvatar(userCache.getAvatar()); + appUser.setPhone(userCache.getPhone()); + } + + appUserMapper.insert(appUser); + + // 6. 标记邀请已使用 + inviteToken.setStatus(1); + appInviteTokenMapper.updateById(inviteToken); + + log.info("小程序扫码加入应用成功: token={}, userId={}, appId={}", token, userId, inviteToken.getAppId()); + + // 7. 返回应用信息(复用上面查询的 app 对象) + String appName = (app != null) ? app.getProductName() : "应用"; + Map result = new HashMap<>(); + result.put("success", true); + result.put("message", "加入成功"); + result.put("appName", appName); + return success(result); + + } catch (Exception e) { + log.error("接受邀请失败", e); + return fail("加入失败,请重试"); + } + } + + /** + * 通过 token 获取邀请信息 + */ + private Map getInviteInfoByToken(String token) throws Exception { + AppInviteToken inviteToken = appInviteTokenMapper.selectByToken(token); + if (inviteToken == null) { + throw new Exception("邀请不存在或已失效"); + } + + if (inviteToken.getExpireTime().isBefore(LocalDateTime.now())) { + throw new Exception("邀请已过期"); + } + + if (inviteToken.getStatus() != 0) { + throw new Exception("邀请已被使用"); + } + + AppProduct app = appProductMapper.selectById(inviteToken.getAppId()); + if (app == null) { + throw new Exception("应用不存在"); + } + + AppUserCache inviter = appUserCacheService.getByUserId(inviteToken.getInviterId()); + + String roleName = getRoleName(inviteToken.getRole()); + + Map result = new HashMap<>(); + result.put("token", token); + result.put("appId", inviteToken.getAppId()); + result.put("appName", app.getProductName()); + result.put("appLogo", app.getIcon()); + result.put("inviterName", inviter != null ? inviter.getNickname() : "某位用户"); + result.put("roleName", roleName); + result.put("role", inviteToken.getRole()); + result.put("expireTime", inviteToken.getExpireTime().toString()); + return result; + } + + /** + * 获取角色名称 + */ + private String getRoleName(String role) { + if (StrUtil.isBlank(role)) return "成员"; + switch (role) { + case "owner": return "所有者"; + case "admin": return "管理员"; + case "developer": return "开发者"; + default: return "成员"; + } + } + + /** + * 通过微信手机号 code 获取手机号 + */ + private String getPhoneByCode(String code) { + try { + // 获取 access_token(从小程序配置读取) + String accessToken = getMiniprogramAccessToken(); + if (StrUtil.isBlank(accessToken)) { + log.warn("获取小程序access_token失败"); + return null; + } + + String apiUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken; + Map paramMap = new HashMap<>(); + paramMap.put("code", code); + + String response = HttpUtil.post(apiUrl, JSON.toJSONString(paramMap)); + JSONObject json = JSON.parseObject(response); + + if (json.containsKey("errcode") && json.getInteger("errcode") != 0) { + log.error("微信获取手机号失败: {}", json.getString("errmsg")); + return null; + } + + // 解析手机号 + if (json.containsKey("phone_info")) { + JSONObject phoneInfo = json.getJSONObject("phone_info"); + return phoneInfo.getString("phoneNumber"); + } + + return null; + } catch (Exception e) { + log.error("获取手机号异常", e); + return null; + } + } + + /** + * 获取小程序 AccessToken + */ + private String getMiniprogramAccessToken() { + try { + // 使用 WxMiniprogramUtil 获取 access_token + String accessToken = com.gxwebsoft.common.core.utils.WxMiniprogramUtil.getAccessToken(); + if (StrUtil.isBlank(accessToken)) { + log.warn("通过 WxMiniprogramUtil 获取小程序 access_token 失败"); + } + return accessToken; + } catch (Exception e) { + log.error("获取AccessToken失败", e); + return null; + } + } + + /** + * 调用微信 API 获取 AccessToken + */ + private String fetchAccessToken(String appId, String appSecret) { + String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + + appId + "&secret=" + appSecret; + String response = HttpUtil.get(apiUrl); + JSONObject json = JSON.parseObject(response); + return json.getString("access_token"); + } + + /** + * 获取 Spring Bean + */ + private Object getSpringBean(Class clazz) { + try { + Class springContextUtilClass = Class.forName("com.gxwebsoft.common.core.config.SpringContextUtil"); + Object bean = springContextUtilClass.getMethod("getBean", Class.class) + .invoke(null, clazz); + return bean; + } catch (Exception e) { + log.warn("获取Spring Bean失败: {}", e.getMessage()); + return null; + } + } + + /** + * 通过手机号查询或创建用户 + * 优先从 app_user_cache 查询,不存在则通过 HTTP 调用主服务器 API 查询/创建(跨库到 gxwebsoft_core.sys_user) + */ + private Integer getOrCreateUserByPhone(String phone) { + try { + // 1. 优先从 app_user_cache 查询用户 + AppUserCache userCache = appUserCacheMapper.selectOne( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(AppUserCache::getPhone, phone) + ); + + if (userCache != null) { + log.info("从 app_user_cache 找到用户: phone={}, userId={}", phone, userCache.getUserId()); + return userCache.getUserId(); + } + + log.info("app_user_cache 中未找到用户,通过 AppUserCacheService 刷新缓存: phone={}", phone); + + // 2. 通过 AppUserCacheService 从主服务器刷新缓存 + // AppUserCacheService 会调用 server API 获取用户信息并保存到本地缓存 + AppUserCache refreshedCache = appUserCacheService.refreshUserCacheByPhone(phone); + + if (refreshedCache != null) { + log.info("从主服务器刷新缓存成功: phone={}, userId={}", phone, refreshedCache.getUserId()); + return refreshedCache.getUserId(); + } + + log.info("主服务器中未找到用户,需要创建新用户: phone={}", phone); + + // 3. 用户不存在,通过 HTTP 调用主服务器 API 创建新用户 + log.info("主服务器中未找到用户,创建新用户: phone={}", phone); + + String createPath = "/system/user/"; + Map userMap = new HashMap<>(); + userMap.put("phone", phone); + userMap.put("username", "wx_" + phone); + userMap.put("nickname", "微信用户"); + userMap.put("status", 0); + userMap.put("platform", "MP-WEIXIN"); + userMap.put("tenantId", 1); // 默认租户 + + // 3. 用户不存在,调用 AppUserCacheService 创建新用户 + log.info("调用 AppUserCacheService 创建新用户: phone={}", phone); + + // 使用 AppUserCacheService 创建用户(内部会调用 server API) + AppUserCache newUserCache = appUserCacheService.createUserByPhone(phone); + + if (newUserCache != null && newUserCache.getUserId() != null) { + log.info("新用户创建成功: phone={}, userId={}", phone, newUserCache.getUserId()); + return newUserCache.getUserId(); + } + + log.error("保存用户失败: phone={}", phone); + return null; + } catch (Exception e) { + log.error("创建用户失败: phone={}", phone, e); + return null; + } + } + + /** + * 同步用户到缓存表 + */ + private void syncUserToCache(Integer userId) { + try { + if (userId == null) return; + // 简单实现:更新缓存 + Object userCacheService = getSpringBean(Class.forName("com.gxwebsoft.app.service.AppUserCacheService")); + if (userCacheService != null) { + userCacheService.getClass().getMethod("refreshUserCache", Integer.class).invoke(userCacheService, userId); + } + } catch (Exception e) { + log.warn("同步用户缓存失败: {}", e.getMessage()); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppNotificationController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppNotificationController.java new file mode 100644 index 0000000..6f0c913 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppNotificationController.java @@ -0,0 +1,101 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppNotification; +import com.gxwebsoft.app.param.AppNotificationParam; +import com.gxwebsoft.app.service.AppNotificationService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 站内消息通知控制器 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Tag(name = "站内消息通知") +@RestController +@RequestMapping("/api/app/notification") +public class AppNotificationController extends BaseController { + + @Resource + private AppNotificationService appNotificationService; + + // ─── 查询接口 ──────────────────────────────────────────────── + + @Operation(summary = "分页查询通知列表") + @GetMapping("/page") + public ApiResult> page(AppNotificationParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + return success(appNotificationService.pageByUser(param, loginUser.getUserId())); + } + + @Operation(summary = "查询最近通知(铃铛下拉)") + @GetMapping("/recent") + public ApiResult> recent( + @RequestParam(required = false) String type, + @RequestParam(required = false, defaultValue = "20") Integer limit) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + return success(appNotificationService.listRecent(loginUser.getUserId(), type, limit)); + } + + @Operation(summary = "获取未读数量统计") + @GetMapping("/unread-count") + public ApiResult> unreadCount() { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + return success(appNotificationService.getUnreadCount(loginUser.getUserId())); + } + + // ─── 操作接口 ──────────────────────────────────────────────── + + @Operation(summary = "标记单条通知为已读") + @PutMapping("/read/{id}") + public ApiResult markRead(@PathVariable Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + appNotificationService.markRead(id, loginUser.getUserId()); + return success("已标记为已读"); + } + + @Operation(summary = "标记全部已读") + @PutMapping("/read-all") + public ApiResult markAllRead(@RequestBody(required = false) Map body) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + String type = (body != null) ? body.get("type") : null; + appNotificationService.markAllRead(loginUser.getUserId(), type); + return success("已全部标记为已读"); + } + + @Operation(summary = "删除单条通知") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + appNotificationService.removeNotification(id, loginUser.getUserId()); + return success("已删除"); + } + + @Operation(summary = "清空已读通知") + @DeleteMapping("/clear-read") + public ApiResult clearRead(@RequestBody(required = false) Map body) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + String type = (body != null) ? body.get("type") : null; + appNotificationService.clearRead(loginUser.getUserId(), type); + return success("已清空已读通知"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppPermissionRequestController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppPermissionRequestController.java new file mode 100644 index 0000000..e25385b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppPermissionRequestController.java @@ -0,0 +1,157 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppPermissionRequest; +import com.gxwebsoft.app.param.AppPermissionRequestParam; +import com.gxwebsoft.app.service.AppPermissionRequestService; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 权限申请控制器 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Tag(name = "权限申请") +@RestController +@RequestMapping("/api/app/developer/permission-requests") +public class AppPermissionRequestController extends BaseController { + + @Resource + private AppPermissionRequestService appPermissionRequestService; + + @Operation(summary = "获取权限申请列表") + @GetMapping("/page") + public ApiResult> page(AppPermissionRequestParam param) { + User loginUser = getLoginUser(); + if (loginUser != null) { + param.setUserId(loginUser.getUserId()); + } + return success(appPermissionRequestService.pageRel(param)); + } + + @Operation(summary = "查询全部权限申请") + @GetMapping + public ApiResult> list(AppPermissionRequestParam param) { + User loginUser = getLoginUser(); + if (loginUser != null) { + param.setUserId(loginUser.getUserId()); + } + return success(appPermissionRequestService.listRel(param)); + } + + @Operation(summary = "根据id查询权限申请") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Long id) { + return success(appPermissionRequestService.getByIdRel(id)); + } + + @Operation(summary = "获取权限申请统计") + @GetMapping("/stats") + public ApiResult> stats() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + return success(appPermissionRequestService.getPermissionRequestStats(loginUser.getUserId())); + } + + @Operation(summary = "获取可申请的仓库列表") + @GetMapping("/available-repos") + public ApiResult>> availableRepos() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + return success(appPermissionRequestService.getAvailableRepositories(loginUser.getUserId())); + } + + @OperationLog + @Operation(summary = "提交权限申请") + @PostMapping + public ApiResult save(@RequestBody Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + + String repo = params.get("repo"); + String reason = params.get("reason"); + String gitUsername = params.get("gitUsername"); + + if (repo == null || repo.trim().isEmpty()) { + return fail("请选择申请仓库", null); + } + if (reason == null || reason.trim().isEmpty()) { + return fail("请填写申请理由", null); + } + + try { + // 从 repo 中提取仓库名称(假设格式为 owner/repo-name) + String repoName = repo; + if (repo.contains("/")) { + String[] parts = repo.split("/"); + repoName = parts[parts.length - 1]; + } + + AppPermissionRequest request = appPermissionRequestService.createPermissionRequest( + loginUser.getUserId(), gitUsername, repo, repoName, reason.trim(), loginUser.getTenantId() + ); + return success("申请提交成功,请等待审核", request); + } catch (RuntimeException e) { + return fail(e.getMessage(), null); + } + } + + @OperationLog + @Operation(summary = "审核权限申请-通过") + @PutMapping("/{id}/approve") + public ApiResult approve(@PathVariable("id") Long id, @RequestBody(required = false) Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + String note = params != null ? params.get("note") : null; + boolean result = appPermissionRequestService.approveRequest(id, loginUser.getUserId(), loginUser.getRealName(), note); + return result ? success("审核通过") : fail("审核失败"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + @OperationLog + @Operation(summary = "审核权限申请-拒绝") + @PutMapping("/{id}/reject") + public ApiResult reject(@PathVariable("id") Long id, @RequestBody Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + + String reason = params != null ? params.get("reason") : null; + if (reason == null || reason.trim().isEmpty()) { + return fail("请填写拒绝原因"); + } + + try { + boolean result = appPermissionRequestService.rejectRequest(id, loginUser.getUserId(), loginUser.getRealName(), reason.trim()); + return result ? success("已拒绝该申请") : fail("拒绝失败"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppProductController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppProductController.java new file mode 100644 index 0000000..8cf1cf5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppProductController.java @@ -0,0 +1,259 @@ +package com.gxwebsoft.app.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.param.AppProductParam; +import com.gxwebsoft.app.service.AppProductService; +import com.gxwebsoft.app.service.AppUserService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +/** + * 应用产品 前端控制器 + * + * @author 科技小王子 + */ +@RestController +@RequestMapping("/api/app/product") +@RequiredArgsConstructor +@Tag(name = "应用产品管理", description = "应用产品管理接口") +public class AppProductController extends BaseController { + + private final AppProductService appProductService; + private final AppUserService appUserService; + + @GetMapping("/page") + @Operation(summary = "分页查询应用列表") + public ApiResult> page( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Long current, + @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Long size, + @Parameter(description = "应用名称") @RequestParam(required = false) String productName, + @Parameter(description = "应用标识") @RequestParam(required = false) String productCode, + @Parameter(description = "应用类型") @RequestParam(required = false) Integer appType, + @Parameter(description = "分类ID") @RequestParam(required = false) Integer categoryId, + @Parameter(description = "发布状态") @RequestParam(required = false) String publishStatus, + @Parameter(description = "状态") @RequestParam(required = false) Integer status, + @Parameter(description = "用户ID(可选,不传则自动用当前登录用户)") @RequestParam(required = false) Integer userId) { + + // 如果没传 userId,自动用当前登录用户 + if (userId == null) { + userId = getLoginUserId(); + } + + AppProduct product = new AppProduct(); + product.setProductName(productName); + product.setProductCode(productCode); + product.setAppType(appType); + product.setCategoryId(categoryId); + product.setPublishStatus(publishStatus); + product.setStatus(status); + + IPage page = appProductService.selectPageList(new Page<>(current, size), product, userId); + return success(page); + } + + @GetMapping("/list") + @Operation(summary = "获取我的应用列表") + public ApiResult> list() { + Integer userId = getLoginUserId(); + return success(appProductService.getByUserId(userId)); + } + + @GetMapping("/my/page") + @Operation(summary = "分页查询我的应用(创建者)") + public ApiResult> myApps( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Long current, + @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Long size) { + Integer userId = getLoginUserId(); + Page page = new Page<>(current, size); + return success(appProductService.getMyApps(page, userId)); + } + + @GetMapping("/joined/page") + @Operation(summary = "分页查询我参与的应用") + public ApiResult> joinedApps( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Long current, + @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Long size) { + Integer userId = getLoginUserId(); + Page page = new Page<>(current, size); + return success(appProductService.getJoinedApps(page, userId)); + } + + @GetMapping("/detail/{id}") + @Operation(summary = "获取应用详情") + public ApiResult detail( + @Parameter(description = "应用ID") @PathVariable Integer id) { + // 记录用户访问(更新最近访问时间) + Integer userId = getLoginUserId(); + if (userId != null) { + appUserService.recordVisit(id.longValue(), userId); + } + return success(appProductService.getDetail(id)); + } + + @PostMapping("/visit/{id}") + @Operation(summary = "记录应用访问") + public ApiResult visit( + @Parameter(description = "应用ID") @PathVariable Integer id) { + Integer userId = getLoginUserId(); + if (userId != null) { + appUserService.recordVisit(id.longValue(), userId); + } + return success(); + } + + @GetMapping("/info/{code}") + @Operation(summary = "根据标识获取应用") + public ApiResult info( + @Parameter(description = "应用标识") @PathVariable String code) { + return success(appProductService.getByCode(code)); + } + + @PostMapping("/create") + @Operation(summary = "创建应用") + public ApiResult create(@Valid @RequestBody AppProduct product) { + boolean success = appProductService.create(product); + return success ? success("创建成功") : fail("创建失败"); + } + + @PutMapping("/update") + @Operation(summary = "更新应用") + public ApiResult update(@Valid @RequestBody AppProduct product) { + boolean success = appProductService.update(product); + return success ? success("更新成功") : fail("更新失败"); + } + + @DeleteMapping("/delete/{id}") + @Operation(summary = "删除应用") + public ApiResult delete( + @Parameter(description = "应用ID") @PathVariable Integer id) { + boolean success = appProductService.delete(id); + return success ? success("删除成功") : fail("删除失败"); + } + + @PostMapping("/submit/{id}") + @Operation(summary = "提交审核") + public ApiResult submit( + @Parameter(description = "应用ID") @PathVariable Integer id) { + boolean success = appProductService.submitReview(id); + return success ? success("提交成功") : fail("提交失败"); + } + + @PostMapping("/approve/{id}") + @Operation(summary = "审核通过") + public ApiResult approve( + @Parameter(description = "应用ID") @PathVariable Integer id) { + boolean success = appProductService.approve(id); + return success ? success("审核通过") : fail("审核失败"); + } + + @PostMapping("/reject/{id}") + @Operation(summary = "审核拒绝") + public ApiResult reject( + @Parameter(description = "应用ID") @PathVariable Integer id, + @RequestParam String reason) { + boolean success = appProductService.reject(id, reason); + return success ? success("操作成功") : fail("操作失败"); + } + + @PostMapping("/publish/{id}") + @Operation(summary = "上架应用") + public ApiResult publish( + @Parameter(description = "应用ID") @PathVariable Integer id) { + boolean success = appProductService.publish(id); + return success ? success("上架成功") : fail("上架失败"); + } + + @PostMapping("/unpublish/{id}") + @Operation(summary = "下架应用") + public ApiResult unpublish( + @Parameter(description = "应用ID") @PathVariable Integer id) { + boolean success = appProductService.unpublish(id); + return success ? success("下架成功") : fail("下架失败"); + } + + @PostMapping("/regenerateSecret/{id}") + @Operation(summary = "重新生成密钥") + public ApiResult regenerateSecret( + @Parameter(description = "应用ID") @PathVariable Integer id) { + String newSecret = appProductService.regenerateSecret(id); + return success(newSecret,null); + } + + @GetMapping("/market/page") + @Operation(summary = "应用市场分页") + public ApiResult> marketPage( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Long current, + @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Long size, + @Parameter(description = "应用类型") @RequestParam(required = false) Integer appType, + @Parameter(description = "关键词") @RequestParam(required = false) String keyword) { + + IPage page = appProductService.getMarketList(new Page<>(current, size), appType, keyword); + return success(page); + } + + @PostMapping("/view/{id}") + @Operation(summary = "浏览应用") + public ApiResult view( + @Parameter(description = "应用ID") @PathVariable Integer id) { + appProductService.incrementClicks(id); + return success(); + } + + @PostMapping("/install/{id}") + @Operation(summary = "安装应用") + public ApiResult install( + @Parameter(description = "应用ID") @PathVariable Integer id) { + appProductService.incrementInstalls(id); + return success(); + } + + @PostMapping("/download/{id}") + @Operation(summary = "下载应用") + public ApiResult download( + @Parameter(description = "应用ID") @PathVariable Integer id) { + appProductService.incrementDownloads(id); + return success(); + } + + @PostMapping("/like/{id}") + @Operation(summary = "点赞应用") + public ApiResult like( + @Parameter(description = "应用ID") @PathVariable Integer id) { + appProductService.incrementLikes(id); + return success(); + } + + @PostMapping("/user-stats") + @Operation(summary = "按用户ID列表批量统计应用数量") + public ApiResult>> userStats( + @RequestBody List userIds) { + return success(appProductService.getStatsByUserIds(userIds)); + } + + /** + * 获取当前用户可访问的应用列表(带角色信息) + * 用于权限过滤:返回用户创建的应用(owner)和被邀请加入的应用(成员角色) + * 每个应用包含 myRole 字段,标识用户在该应用中的角色 + */ + @GetMapping("/accessible") + @Operation(summary = "获取可访问的应用列表(带角色信息)") + public ApiResult> accessibleApps() { + Integer userId = getLoginUserId(); + if (userId == null) { + return success(List.of()); + } + return success(appProductService.getAccessibleApps(userId)); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppResourceController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppResourceController.java new file mode 100644 index 0000000..2df9920 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppResourceController.java @@ -0,0 +1,368 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.entity.ResourceAccessLevel; +import com.gxwebsoft.app.param.AppResourceParam; +import com.gxwebsoft.app.service.AppResourceService; +import com.gxwebsoft.app.service.AppCloudCredentialService; +import com.gxwebsoft.app.service.DatabaseOperatorFactory; +import com.gxwebsoft.app.service.DatabaseOperatorService; +import com.gxwebsoft.app.service.OnePanelService; +import com.gxwebsoft.app.service.SshService; +import com.gxwebsoft.app.service.cloud.CloudStorageProvider; +import com.gxwebsoft.app.service.cloud.CloudStorageProviderFactory; +import com.gxwebsoft.app.service.impl.AppResourceServiceImpl; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.DbPasswordUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 开发者资源管理控制器(服务器/数据库/云存储/域名/SSL) + * + * @author 科技小王子 + * @since 2026-03-31 + */ +@Slf4j +@Tag(name = "开发者资源管理") +@RestController +@RequestMapping("/api/app/developer-resource") +public class AppResourceController extends BaseController { + + @Resource + private AppResourceService appResourceService; + + @Resource + private AppCloudCredentialService cloudCredentialService; + + @Resource + private DatabaseOperatorFactory databaseOperatorFactory; + + @Resource + private SshService sshService; + + @Resource + private OnePanelService onePanelService; + + @Resource + private RedisUtil redisUtil; + + // ─── 查询接口 ───────────────────────────────────────────────── + + @Operation(summary = "分页查询资源列表(支持协作权限)") + @GetMapping("/page") + public ApiResult> page(AppResourceParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + // **协作权限改进**:不再限制只能查自己的资源,改为查询用户有权访问的资源 + // 通过修改SQL,查询条件改为:owner_user_id = 当前用户 OR app_id IN (用户有权限的应用) + param.setUserId(loginUser.getUserId()); + param.setTenantId(loginUser.getTenantId()); + // 调用新方法,传入当前用户ID以便计算 accessLevel 和屏蔽敏感字段 + return success(appResourceService.pageRel(param, loginUser.getUserId())); + } + + @Operation(summary = "查询资源列表(不分页,支持协作权限)") + @GetMapping + public ApiResult> list(AppResourceParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + param.setUserId(loginUser.getUserId()); + param.setTenantId(loginUser.getTenantId()); + // 调用新方法,传入当前用户ID + return success(appResourceService.listRel(param, loginUser.getUserId())); + } + + @Operation(summary = "获取资源详情(支持协作权限)") + @GetMapping("/{resourceId}") + public ApiResult get(@PathVariable Long resourceId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + AppResource resource = appResourceService.getByIdRel(resourceId, loginUser.getUserId()); + if (resource == null) return fail("资源不存在", null); + // **协作权限改进**:不再直接禁止访问,由 Service 计算 accessLevel,0 表示无权限 + if (resource.getAccessLevel() == null || resource.getAccessLevel() == 0) { + return fail("无权访问此资源", null); + } + return success(resource); + } + + @Operation(summary = "统计各类型资源数量") + @GetMapping("/stats") + public ApiResult> stats() { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + return success(appResourceService.countByType(loginUser.getUserId(), loginUser.getTenantId())); + } + + // ─── 新增/修改接口 ──────────────────────────────────────────── + + @OperationLog + @Operation(summary = "新增资源") + @PostMapping + public ApiResult save(@RequestBody AppResource resource) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + if (resource.getResourceType() == null || resource.getResourceType().isEmpty()) { + return fail("资源类型不能为空", null); + } + if (resource.getName() == null || resource.getName().isEmpty()) { + return fail("资源名称不能为空", null); + } + resource.setTenantId(loginUser.getTenantId()); + try { + AppResource result = appResourceService.addResource(resource, loginUser.getUserId()); + return success("添加成功", result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + @OperationLog + @Operation(summary = "修改资源(只有 Owner 可操作)") + @PutMapping + public ApiResult update(@RequestBody AppResource resource) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + try { + AppResource result = appResourceService.updateResource(resource, loginUser.getUserId()); + return success("修改成功", result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + // ─── 删除接口 ───────────────────────────────────────────────── + + @OperationLog + @Operation(summary = "删除资源(逻辑删除,需要短信验证码)") + @DeleteMapping("/{resourceId}") + public ApiResult remove(@PathVariable Long resourceId, @RequestBody Map body) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + + // 验证短信验证码 + String code = body.get("code"); + if (code == null || code.isEmpty()) { + return fail("请输入短信验证码"); + } + + // 验证验证码(key 为 code:手机号) + String phone = loginUser.getPhone(); + if (phone == null || phone.isEmpty()) { + return fail("请先绑定手机号"); + } + + String cachedCode = redisUtil.get("code:" + phone); + if (cachedCode == null || !cachedCode.equals(code)) { + return fail("验证码错误或已过期"); + } + + // 验证通过,删除验证码 + redisUtil.delete("code:" + phone); + + try { + appResourceService.removeResource(resourceId, loginUser.getUserId()); + return success("删除成功"); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + @OperationLog + @Operation(summary = "批量删除资源") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + try { + for (Long id : ids) { + appResourceService.removeResource(id, loginUser.getUserId()); + } + return success("批量删除成功"); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + // ─── 数据库操作接口 ────────────────────────────────────────── + + @Operation(summary = "测试服务器数据库连接") + @PostMapping("/test-connection") + public ApiResult testConnection(@RequestBody Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + + String host = (String) params.get("host"); + String dbType = (String) params.get("dbType"); + Integer port = params.get("port") != null ? ((Number) params.get("port")).intValue() : null; + String username = (String) params.get("username"); + String password = (String) params.get("password"); + String dbName = (String) params.get("dbName"); + + if (host == null || host.isEmpty()) return fail("服务器地址不能为空", null); + if (username == null || username.isEmpty()) return fail("用户名不能为空", null); + + // 根据数据库类型获取默认端口和对应操作服务 + if (dbType == null || dbType.isEmpty()) { + dbType = "MySQL"; + } + if (port == null) { + port = "PostgreSQL".equals(dbType) ? 5432 : 3306; + } + + DatabaseOperatorService operator = databaseOperatorFactory.getOperator(dbType); + DatabaseOperatorService.DatabaseOperationResult result = + operator.testConnection(host, port, username, password, dbName); + return success(result); + } + + @Operation(summary = "测试服务器 SSH 连接") + @PostMapping("/test-ssh") + public ApiResult testSshConnection(@RequestBody Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + + String host = (String) params.get("host"); + Integer port = params.get("port") != null ? ((Number) params.get("port")).intValue() : 22; + String username = (String) params.get("username"); + String password = (String) params.get("password"); + + SshService.ConnectionResult result = sshService.testConnection(host, port, username, password); + return success(result); + } + + @Operation(summary = "获取1Panel服务器状态") + @GetMapping("/server-status/{resourceId}") + public ApiResult getServerStatus(@PathVariable Long resourceId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + + AppResource resource = appResourceService.getByIdRel(resourceId, loginUser.getUserId()); + if (resource == null) return fail("资源不存在", null); + + // 必须是服务器类型资源 + if (!"server".equals(resource.getResourceType())) { + return fail("只有服务器资源才能获取状态", null); + } + + // 必须有 panelPort 配置 + if (resource.getPanelPort() == null) { + return fail("该服务器未配置1Panel端口", null); + } + + // 必须有连接权限(owner/admin/developer)才能获取状态 + int accessLevel = resource.getAccessLevel() != null ? resource.getAccessLevel() : 0; + if (accessLevel < ResourceAccessLevel.VIEW_CONNECTION.getValue()) { + return fail("没有权限获取服务器状态", null); + } + + // 调用1Panel API获取状态 + OnePanelService.ServerStatus status = onePanelService.getServerStatus( + resource.getIp(), + resource.getPanelPort(), + resource.getPanelPath(), + resource.getPanelUsername(), + resource.getPanelPassword() + ); + + return success(status); + } + + @Operation(summary = "重试创建数据库(只有 Owner 可操作)") + @PostMapping("/retry-create-database/{resourceId}") + public ApiResult retryCreateDatabase(@PathVariable Long resourceId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + + AppResource resource = appResourceService.getByIdRel(resourceId, loginUser.getUserId()); + if (resource == null) return fail("资源不存在"); + if (!loginUser.getUserId().equals(resource.getOwnerUserId())) return fail("只有资源创建者才能操作"); + if (!"failed".equals(resource.getStatus()) && !"pending".equals(resource.getStatus())) { + return fail("只有创建失败或创建中的资源才能重试"); + } + + try { + // 获取 ServiceImpl 实例调用异步方法 + AppResourceServiceImpl serviceImpl = (AppResourceServiceImpl) appResourceService; + serviceImpl.asyncCreateDatabase(resourceId); + return success("已开始重新创建,请稍后查看状态"); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + @Operation(summary = "重置数据库密码(只有 Owner 可操作)") + @PostMapping("/reset-password/{resourceId}") + public ApiResult> resetPassword(@PathVariable Long resourceId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + try { + String newPassword = appResourceService.resetDatabasePassword(resourceId, loginUser.getUserId()); + Map result = new HashMap<>(); + result.put("password", newPassword); + return success(result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + @Operation(summary = "刷新存储桶信息(只有 Owner 可操作)") + @PostMapping("/refresh-storage/{resourceId}") + public ApiResult> refreshStorage(@PathVariable Long resourceId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录", null); + + AppResource resource = appResourceService.getByIdRel(resourceId, loginUser.getUserId()); + if (resource == null) return fail("资源不存在",null); + if (!"storage".equals(resource.getResourceType())) { + return fail("只有存储桶资源才能刷新",null); + } + + try { + // 获取云账号凭证 + Map credentials; + if (resource.getCredentialId() != null) { + credentials = cloudCredentialService.getCredentialsByCredentialId(resource.getCredentialId()); + } else { + credentials = cloudCredentialService.getCredentials(resource.getProvider(), loginUser.getUserId()); + } + + if (credentials == null || credentials.isEmpty()) { + return fail("请先配置云账号凭证",null); + } + + // 调用云厂商 API 获取存储桶信息 + CloudStorageProvider cloudProvider = CloudStorageProviderFactory.getProvider(resource.getProvider()); + Map bucketInfo = cloudProvider.getBucketInfo(resource, credentials); + + // 更新到数据库 + AppResource update = new AppResource(); + update.setResourceId(resourceId); + if (bucketInfo.get("usedBytes") != null) { + update.setUsedBytes(((Number) bucketInfo.get("usedBytes")).longValue()); + } + if (bucketInfo.get("objectCount") != null) { + update.setUsedCount(((Number) bucketInfo.get("objectCount")).intValue()); + } + appResourceService.updateById(update); + + return success(bucketInfo); + } catch (Exception e) { + log.error("刷新存储桶信息失败: resourceId={}, error={}", resourceId, e.getMessage(), e); + return fail("刷新失败: " + e.getMessage(), null); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppSettingController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppSettingController.java new file mode 100644 index 0000000..075decf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppSettingController.java @@ -0,0 +1,160 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.app.entity.AppSetting; +import com.gxwebsoft.app.param.AppSettingParam; +import com.gxwebsoft.app.service.AppSettingService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 平台设置表 Controller + */ +@Slf4j +@Tag(name = "平台设置管理") +@RestController +@RequestMapping("/api/app/setting") +public class AppSettingController extends BaseController { + + @Resource + private AppSettingService appSettingService; + + /** + * 分页查询设置 + */ + @Operation(summary = "分页查询设置") + @GetMapping("/page") + public ApiResult> page(AppSettingParam param) { + return success(new PageResult<>(appSettingService.page(param))); + } + + /** + * 获取设置列表 + */ + @Operation(summary = "获取设置列表") + @GetMapping() + public ApiResult> list(AppSettingParam param) { + return success(appSettingService.list(param)); + } + + /** + * 根据分类获取设置 + */ + @Operation(summary = "根据分类获取设置") + @GetMapping("/category/{category}") + public ApiResult> getByCategory(@PathVariable String category) { + return success(appSettingService.getByCategory(category)); + } + + /** + * 获取分类设置值(Map格式) + */ + @Operation(summary = "获取分类设置值") + @GetMapping("/category/{category}/values") + public ApiResult> getCategoryValues(@PathVariable String category) { + return success(appSettingService.getCategoryValues(category)); + } + + /** + * 根据key获取单个设置值 + */ + @Operation(summary = "根据key获取设置值") + @GetMapping("/key/{key}") + public ApiResult getValue(@PathVariable String key) { + return success("获取成功", appSettingService.getValue(key)); + } + + /** + * 根据key获取完整设置 + */ + @Operation(summary = "根据key获取完整设置") + @GetMapping("/info/{key}") + public ApiResult getByKey(@PathVariable String key) { + return success(appSettingService.getByKey(key)); + } + + /** + * 保存或更新设置 + */ + @Operation(summary = "保存或更新设置") + @PostMapping() + public ApiResult save(@RequestBody AppSetting setting) { + appSettingService.saveOrUpdateSetting(setting); + return success("保存成功"); + } + + /** + * 更新设置 + */ + @Operation(summary = "更新设置") + @PutMapping() + public ApiResult update(@RequestBody AppSetting setting) { + appSettingService.saveOrUpdateSetting(setting); + return success("更新成功"); + } + + /** + * 批量保存分类设置 + */ + @Operation(summary = "批量保存分类设置") + @PostMapping("/batch/{category}") + public ApiResult batchSave(@PathVariable String category, @RequestBody Map values) { + // 处理值类型转换 + Map valuesMap = new java.util.HashMap<>(values.size()); + for (Map.Entry entry : values.entrySet()) { + Object val = entry.getValue(); + if (val == null) { + // 跳过 null 值 + continue; + } else if (val instanceof Boolean || val instanceof Number) { + // 保持原始类型(Boolean, Integer, Long, Double 等) + valuesMap.put(entry.getKey(), val); + } else if (val instanceof String) { + // 尝试将字符串转换为正确的类型 + String strVal = (String) val; + if ("true".equalsIgnoreCase(strVal)) { + valuesMap.put(entry.getKey(), Boolean.TRUE); + } else if ("false".equalsIgnoreCase(strVal)) { + valuesMap.put(entry.getKey(), Boolean.FALSE); + } else { + // 尝试转换为数字 + try { + if (strVal.contains(".")) { + valuesMap.put(entry.getKey(), Double.parseDouble(strVal)); + } else { + valuesMap.put(entry.getKey(), Long.parseLong(strVal)); + } + } catch (NumberFormatException e) { + // 保持字符串 + valuesMap.put(entry.getKey(), strVal); + } + } + } else if (val instanceof java.util.List) { + // List 类型保持不变(Jackson 已经正确处理了数组) + valuesMap.put(entry.getKey(), val); + } else { + valuesMap.put(entry.getKey(), val); + } + } + appSettingService.batchSave(category, valuesMap); + return success("保存成功"); + } + + /** + * 删除设置 + */ + @Operation(summary = "删除设置") + @DeleteMapping("/{settingId}") + public ApiResult delete(@PathVariable Integer settingId) { + appSettingService.removeById(settingId); + return success("删除成功"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppSubscriptionController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppSubscriptionController.java new file mode 100644 index 0000000..95ba403 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppSubscriptionController.java @@ -0,0 +1,593 @@ +package com.gxwebsoft.app.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gxwebsoft.app.config.AppPayProperties; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.entity.AppSubscription; +import com.gxwebsoft.app.mapper.AppSubscriptionMapper; +import com.gxwebsoft.app.mapper.AppProductMapper; +import com.gxwebsoft.app.mapper.SysUserCrossDbMapper; +import com.gxwebsoft.app.utils.WxNativePayUtil; +import com.gxwebsoft.common.core.constants.BalanceConstants; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; + +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.service.payments.nativepay.NativePayService; +import com.wechat.pay.java.service.payments.nativepay.model.Amount; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 应用订阅控制器 + * 路径前缀:/api/app/subscription + */ +@Slf4j +@RestController +@RequestMapping("/api/app/subscription") +@RequiredArgsConstructor +@Tag(name = "应用订阅管理") +public class AppSubscriptionController extends BaseController { + + private final AppSubscriptionMapper subscriptionMapper; + private final AppProductMapper productMapper; + private final WxNativePayUtil wxNativePayUtil; + private final AppPayProperties appPayProperties; + private final SysUserCrossDbMapper sysUserCrossDbMapper; + + @javax.annotation.Resource + private RedisUtil redisUtil; + + @Value("${spring.profiles.active:dev}") + private String active; + + // ============================================================ + // 订阅操作 + // ============================================================ + + /** + * 创建订阅 + * 免费应用:直接激活 + * 付费应用:创建待支付记录 + */ + @PostMapping("/subscribe") + @Operation(summary = "创建订阅") + public Object subscribe(@RequestBody Map params) { + Object productIdObj = params.get("productId"); + if (productIdObj == null) { + return fail("productId 不能为空"); + } + String productIdStr = productIdObj.toString(); + if ("NaN".equals(productIdStr) || "null".equals(productIdStr) || "undefined".equals(productIdStr)) { + return fail("无效的应用ID,请刷新页面后重试"); + } + Integer productId; + try { + productId = Integer.valueOf(productIdStr); + } catch (NumberFormatException e) { + return fail("应用ID格式错误:" + productIdStr); + } + String subscriptionPeriod = (String) params.getOrDefault("subscriptionPeriod", "month"); + + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("请先登录"); + } + + // 1. 查询产品信息 + AppProduct product = productMapper.selectById(productId); + if (product == null || !"published".equals(product.getPublishStatus())) { + return fail("应用不存在或未上架"); + } + + // 2. 检查是否已有 active 订阅(幂等) + LambdaQueryWrapper existQuery = new LambdaQueryWrapper<>(); + existQuery.eq(AppSubscription::getUserId, userId) + .eq(AppSubscription::getProductId, productId) + .eq(AppSubscription::getStatus, "active"); + if (subscriptionMapper.selectCount(existQuery) > 0) { + return fail("您已订阅该应用,无需重复购买"); + } + + // 3. 计算价格 + // app_product.price 单位为分(BigDecimal),转为元存到 app_subscription.pay_price + BigDecimal priceInYuan = BigDecimal.ZERO; + String priceType = product.getPriceType() != null ? product.getPriceType() : "free"; + if (!"free".equals(priceType) && product.getPrice() != null) { + // price 字段单位是分,除以 100 转为元 + priceInYuan = product.getPrice().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); + if ("subscription".equals(priceType) && "year".equals(subscriptionPeriod)) { + // 年付:按10个月价格 + priceInYuan = priceInYuan.multiply(BigDecimal.TEN); + } + } + + // 4. 创建订阅记录 + AppSubscription sub = new AppSubscription(); + sub.setSubscriptionNo(generateSubscriptionNo()); + sub.setUserId(userId); + sub.setProductId(productId); + sub.setTenantId(product.getTenantId()); + sub.setStatus("pending"); + sub.setPriceType(priceType); + sub.setOriginalPrice(priceInYuan); + sub.setPayPrice(priceInYuan); + sub.setPayStatus(0); + sub.setSubscriptionPeriod("subscription".equals(priceType) ? subscriptionPeriod : null); + + // 5. 免费应用直接激活 + boolean isFree = "free".equals(priceType) || priceInYuan.compareTo(BigDecimal.ZERO) == 0; + if (isFree) { + sub.setStatus("active"); + sub.setPayStatus(1); + sub.setPayType(12); // 免费标记 + sub.setPayTime(LocalDateTime.now()); + sub.setStartTime(LocalDateTime.now()); + + if ("subscription".equals(priceType)) { + int months = "year".equals(subscriptionPeriod) ? 12 : 1; + sub.setExpireTime(LocalDateTime.now().plusMonths(months)); + } + + // 更新产品安装量 + product.setInstalls((product.getInstalls() != null ? product.getInstalls() : 0) + 1); + productMapper.updateById(product); + } + + subscriptionMapper.insert(sub); + + // 6. 返回结果 + Map result = new HashMap<>(); + result.put("subscriptionId", sub.getId()); + result.put("subscriptionNo", sub.getSubscriptionNo()); + result.put("status", sub.getStatus()); + result.put("message", isFree ? "订阅成功" : "请完成支付"); + + if (!isFree) { + result.put("payPrice", sub.getPayPrice()); + // TODO: 对接现有支付系统,创建支付订单并返回 orderNo + // result.put("orderNo", payService.createOrder(sub)); + } + + return success(result); + } + + /** + * 获取当前用户余额 + */ + @GetMapping("/balance") + @Operation(summary = "获取用户余额") + public Object getBalance() { + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("请先登录"); + } + // 跨库查询 gxwebsoft_core.sys_user + User freshUser = sysUserCrossDbMapper.selectByUserId(userId); + BigDecimal balance = freshUser != null && freshUser.getBalance() != null + ? freshUser.getBalance() : BigDecimal.ZERO; + Map result = new HashMap<>(); + result.put("balance", balance); + return success(result); + } + + /** + * 余额支付 + * POST /api/app/subscription/pay/{id}?method=balance + */ + @PostMapping("/pay/{id}") + @Operation(summary = "发起支付") + public Object pay(@PathVariable Long id, @RequestParam(defaultValue = "wechat") String method) { + AppSubscription sub = subscriptionMapper.selectById(id); + if (sub == null) { + return fail("订阅不存在"); + } + + Integer userId = getLoginUserId(); + if (userId == null || !userId.equals(sub.getUserId())) { + return fail("无权操作"); + } + + if ("active".equals(sub.getStatus())) { + return fail("该订阅已激活"); + } + + // 免费应用走激活流程 + if (sub.getPayPrice() == null || sub.getPayPrice().compareTo(BigDecimal.ZERO) == 0) { + return fail("该应用为免费应用,无需支付"); + } + + // 余额支付 + if ("balance".equals(method)) { + return handleBalancePay(sub); + } + + // 微信 Native 支付 + return handleWechatPay(sub); + } + + /** + * 余额支付处理 + */ + private Object handleBalancePay(AppSubscription sub) { + Integer userId = getLoginUserId(); + + // 跨库查询用户最新余额(gxwebsoft_core.sys_user) + User user = sysUserCrossDbMapper.selectByUserId(userId); + if (user == null) { + return fail("用户不存在"); + } + + BigDecimal currentBalance = user.getBalance() != null ? user.getBalance() : BigDecimal.ZERO; + BigDecimal payPrice = sub.getPayPrice(); + + // 检查余额是否充足 + if (currentBalance.compareTo(payPrice) < 0) { + return fail("余额不足,当前余额:" + currentBalance + " 元,需要:" + payPrice + " 元"); + } + + // 扣除余额(跨库更新 gxwebsoft_core.sys_user) + BigDecimal newBalance = currentBalance.subtract(payPrice); + int updated = sysUserCrossDbMapper.updateBalance(userId, newBalance); + if (updated <= 0) { + return fail("余额扣除失败"); + } + + // 记录余额变动日志(跨库插入 gxwebsoft_core.sys_user_balance_log) + sysUserCrossDbMapper.insertBalanceLog( + userId, + BalanceConstants.BALANCE_USE, + payPrice, + newBalance, + sub.getSubscriptionNo(), + "应用订阅:" + sub.getProductName(), + user.getTenantId() + ); + + // 激活订阅 + sub.setStatus("active"); + sub.setPayStatus(1); + sub.setPayType(0); // 0-余额支付 + sub.setPayTime(LocalDateTime.now()); + sub.setStartTime(LocalDateTime.now()); + + if ("subscription".equals(sub.getPriceType())) { + int months = "year".equals(sub.getSubscriptionPeriod()) ? 12 : 1; + sub.setExpireTime(LocalDateTime.now().plusMonths(months)); + } + + subscriptionMapper.updateById(sub); + + // 更新产品安装量 + AppProduct product = productMapper.selectById(sub.getProductId()); + if (product != null) { + product.setInstalls((product.getInstalls() != null ? product.getInstalls() : 0) + 1); + productMapper.updateById(product); + } + + // 写入 Redis 标记(兼容轮询) + redisUtil.set("wxpay:paid:" + sub.getSubscriptionNo(), "1", 30L, java.util.concurrent.TimeUnit.MINUTES); + + log.info("余额支付成功 — subscriptionNo: {}, userId: {}, amount: {}, remainingBalance: {}", + sub.getSubscriptionNo(), userId, payPrice, newBalance); + + Map result = new HashMap<>(); + result.put("paid", true); + result.put("balance", newBalance); + result.put("subscriptionNo", sub.getSubscriptionNo()); + return success(result); + } + + /** + * 微信 Native 支付处理 + */ + private Object handleWechatPay(AppSubscription sub) { + // 查询产品名称作为支付描述 + AppProduct product = productMapper.selectById(sub.getProductId()); + String productName = product != null ? product.getProductName() : "应用订阅"; + + // 金额:元转分 + BigDecimal payPriceYuan = sub.getPayPrice(); + int totalFee = payPriceYuan.multiply(new BigDecimal(100)).intValue(); + if (totalFee < 1) { + totalFee = 1; // 微信最低1分 + } + + log.info("========== 微信 Native 支付请求 =========="); + log.info("商户号: {}", appPayProperties.getMchId()); + log.info("AppID: {}", appPayProperties.getAppId()); + log.info("订单号: {}", sub.getSubscriptionNo()); + log.info("商品描述: {}", productName); + log.info("支付金额(分): {}", totalFee); + log.info("回调地址: {}", appPayProperties.getNotifyUrl()); + log.info("=========================================="); + + try { + Config config = wxNativePayUtil.getConfig(appPayProperties); + NativePayService payService = new NativePayService.Builder().config(config).build(); + + PrepayRequest request = new PrepayRequest(); + request.setAppid(appPayProperties.getAppId()); + request.setMchid(appPayProperties.getMchId()); + request.setOutTradeNo(sub.getSubscriptionNo()); + request.setDescription(productName); + request.setNotifyUrl(appPayProperties.getNotifyUrl()); + + Amount amount = new Amount(); + amount.setTotal(totalFee); + request.setAmount(amount); + + PrepayResponse response = payService.prepay(request); + String codeUrl = response.getCodeUrl(); + + log.info("微信 Native 支付下单成功 — subscriptionNo: {}, codeUrl: {}", sub.getSubscriptionNo(), codeUrl); + + Map result = new HashMap<>(); + result.put("subscriptionId", sub.getId()); + result.put("subscriptionNo", sub.getSubscriptionNo()); + result.put("codeUrl", codeUrl); + result.put("payPrice", payPriceYuan); + return success(result); + + } catch (Exception e) { + log.error("========== 微信支付下单失败 =========="); + log.error("商户号: {}", appPayProperties.getMchId()); + log.error("AppID: {}", appPayProperties.getAppId()); + log.error("订单号: {}", sub.getSubscriptionNo()); + log.error("错误类型: {}", e.getClass().getName()); + log.error("错误信息: {}", e.getMessage()); + + if (e instanceof com.wechat.pay.java.core.exception.ServiceException) { + com.wechat.pay.java.core.exception.ServiceException wechatEx = + (com.wechat.pay.java.core.exception.ServiceException) e; + log.error("微信错误码: {}", wechatEx.getErrorCode()); + log.error("微信错误信息: {}", wechatEx.getErrorMessage()); + } + log.error("=========================================="); + + // 测试模式:返回模拟二维码 + if (appPayProperties.isEnabled() && !appPayProperties.isTestMode()) { + return fail("微信支付服务异常,请稍后重试"); + } + + // 测试模式返回可展示的 mock URL + String mockCodeUrl = "weixin://wxpay/bizpayurl?pr=TEST" + System.currentTimeMillis(); + Map result = new HashMap<>(); + result.put("subscriptionId", sub.getId()); + result.put("subscriptionNo", sub.getSubscriptionNo()); + result.put("codeUrl", mockCodeUrl); + result.put("payPrice", payPriceYuan); + result.put("_testMode", true); + return success(result); + } + } + + // ============================================================ + // 我的订阅 + // ============================================================ + + /** + * 我的订阅列表(分页) + */ + @GetMapping("/my/page") + @Operation(summary = "我的订阅列表") + public Object myPage( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer limit, + @RequestParam(required = false) String status) { + + Integer userId = getLoginUserId(); + if (userId == null) { + return success(new Page()); + } + + Page pageParam = new Page<>(page, limit); + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(AppSubscription::getUserId, userId); + if (status != null && !status.isEmpty()) { + query.eq(AppSubscription::getStatus, status); + } + query.orderByDesc(AppSubscription::getCreateTime); + + Page pageResult = subscriptionMapper.selectPage(pageParam, query); + + // 填充产品信息(TODO: 后续改为 LEFT JOIN 优化) + pageResult.getRecords().forEach(sub -> { + AppProduct product = productMapper.selectById(sub.getProductId()); + if (product != null) { + sub.setProductName(product.getProductName()); + sub.setProductLogo(product.getLogo()); + sub.setProductIcon(product.getIcon()); + sub.setProductAppType(product.getAppType()); + sub.setProductDescription(product.getDescription()); + } + }); + + return success(pageResult); + } + + /** + * 订阅详情 + */ + @GetMapping("/detail/{id}") + @Operation(summary = "订阅详情") + public Object detail(@PathVariable Long id) { + AppSubscription sub = subscriptionMapper.selectById(id); + if (sub == null) { + return fail("订阅不存在"); + } + + AppProduct product = productMapper.selectById(sub.getProductId()); + if (product != null) { + sub.setProductName(product.getProductName()); + sub.setProductLogo(product.getLogo()); + sub.setProductIcon(product.getIcon()); + sub.setProductAppType(product.getAppType()); + } + + return success(sub); + } + + // ============================================================ + // 订阅管理 + // ============================================================ + + /** + * 续费 + */ + @PostMapping("/renew/{id}") + @Operation(summary = "续费") + public Object renew(@PathVariable Long id, + @RequestParam(defaultValue = "month") String period) { + AppSubscription sub = subscriptionMapper.selectById(id); + if (sub == null) return fail("订阅不存在"); + + Integer userId = getLoginUserId(); + if (userId == null || !userId.equals(sub.getUserId())) return fail("无权操作"); + + int months = "year".equals(period) ? 12 : 1; + if ("active".equals(sub.getStatus()) && sub.getExpireTime() != null) { + sub.setExpireTime(sub.getExpireTime().plusMonths(months)); + } else { + sub.setExpireTime(LocalDateTime.now().plusMonths(months)); + } + sub.setStatus("active"); + subscriptionMapper.updateById(sub); + return success("续费成功"); + } + + /** + * 退订/取消 + */ + @PostMapping("/cancel/{id}") + @Operation(summary = "退订") + public Object cancel(@PathVariable Long id) { + AppSubscription sub = subscriptionMapper.selectById(id); + if (sub == null) return fail("订阅不存在"); + + Integer userId = getLoginUserId(); + if (userId == null || !userId.equals(sub.getUserId())) return fail("无权操作"); + + sub.setStatus("cancelled"); + subscriptionMapper.updateById(sub); + return success("退订成功"); + } + + /** + * 启用/禁用 + */ + @PostMapping("/toggle-enable/{id}") + @Operation(summary = "启用/禁用") + public Object toggleEnable(@PathVariable Long id, @RequestParam Boolean enabled) { + AppSubscription sub = subscriptionMapper.selectById(id); + if (sub == null) return fail("订阅不存在"); + + Integer userId = getLoginUserId(); + if (userId == null || !userId.equals(sub.getUserId())) return fail("无权操作"); + + if (enabled) { + if ("expired".equals(sub.getStatus()) || + (sub.getExpireTime() != null && sub.getExpireTime().isBefore(LocalDateTime.now()))) { + return fail("订阅已过期,请先续费"); + } + sub.setStatus("active"); + } else { + sub.setStatus("cancelled"); + } + + subscriptionMapper.updateById(sub); + return success(enabled ? "已启用" : "已禁用"); + } + + // ============================================================ + // 查询 + // ============================================================ + + /** + * 查询支付状态(前端轮询用) + * 优先查 Redis(回调写入,加速感知),再查数据库兜底 + */ + @GetMapping("/check-status/{subscriptionNo}") + @Operation(summary = "查询支付状态") + public Object checkStatus(@PathVariable String subscriptionNo) { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(AppSubscription::getSubscriptionNo, subscriptionNo); + AppSubscription sub = subscriptionMapper.selectOne(query); + + if (sub == null) { + return fail("订阅不存在"); + } + + // 优先检查 Redis 支付标记(微信回调写入,加速前端轮询感知) + boolean paidViaRedis = "1".equals(redisUtil.get("wxpay:paid:" + subscriptionNo)); + boolean paidViaDb = sub.getPayStatus() != null && sub.getPayStatus() == 1; + boolean isPaid = paidViaRedis || paidViaDb; + + // 补全产品信息 + AppProduct product = productMapper.selectById(sub.getProductId()); + if (product != null) { + sub.setProductName(product.getProductName()); + sub.setProductLogo(product.getLogo()); + sub.setProductIcon(product.getIcon()); + } + + Map result = new HashMap<>(); + result.put("paid", isPaid); + result.put("payStatus", sub.getPayStatus()); + result.put("status", sub.getStatus()); + result.put("payTime", sub.getPayTime()); + result.put("transactionId", sub.getTransactionId()); + // 补全订单详情字段,前端支付页可直接使用 + result.put("id", sub.getId()); + result.put("subscriptionNo", sub.getSubscriptionNo()); + result.put("productId", sub.getProductId()); + result.put("productName", sub.getProductName()); + result.put("productLogo", sub.getProductLogo()); + result.put("priceType", sub.getPriceType()); + result.put("payPrice", sub.getPayPrice()); + result.put("subscriptionPeriod", sub.getSubscriptionPeriod()); + return success(result); + } + + /** + * 检查是否已购买某应用 + */ + @GetMapping("/check-purchased/{productId}") + @Operation(summary = "检查是否已购买") + public Object checkPurchased(@PathVariable Integer productId) { + Integer userId = getLoginUserId(); + if (userId == null) return success(false); + + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(AppSubscription::getUserId, userId) + .eq(AppSubscription::getProductId, productId) + .in(AppSubscription::getStatus, "active", "pending"); + return success(subscriptionMapper.selectCount(query) > 0); + } + + // ============================================================ + // 内部方法 + // ============================================================ + + private String generateSubscriptionNo() { + String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + int random = ThreadLocalRandom.current().nextInt(1000, 9999); + return "SUB" + date + random; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppTicketController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppTicketController.java new file mode 100644 index 0000000..84ae5a8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppTicketController.java @@ -0,0 +1,161 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.entity.AppTicket; +import com.gxwebsoft.app.entity.AppTicketReply; +import com.gxwebsoft.app.param.AppTicketParam; +import com.gxwebsoft.app.service.AppProductService; +import com.gxwebsoft.app.service.AppTicketService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 应用工单控制器 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Slf4j +@Tag(name = "应用工单管理") +@RestController +@RequestMapping("/api/app/ticket") +public class AppTicketController extends BaseController { + + @Resource + private AppTicketService appTicketService; + + @Resource + private AppProductService appProductService; + + // ─── 客户端接口 ──────────────────────────────────────────────── + + @Operation(summary = "查询我的工单(分页)") + @GetMapping("/my") + public ApiResult> myTickets(AppTicketParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录",null); + return success(appTicketService.myPage(param, loginUser.getUserId())); + } + + @Operation(summary = "提交工单") + @PostMapping("/submit") + public ApiResult submit(@RequestBody AppTicket ticket) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录",null); + try { + AppTicket result = appTicketService.submit(ticket, loginUser.getUserId()); + return success("工单提交成功", result); + } catch (Exception e) { + return fail(e.getMessage(),null); + } + } + + @Operation(summary = "关闭工单(提交人)") + @PutMapping("/{ticketId}/close") + public ApiResult close(@PathVariable Long ticketId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + try { + appTicketService.closeByUser(ticketId, loginUser.getUserId()); + return success("工单已关闭"); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + // ─── 技术端接口 ──────────────────────────────────────────────── + + @Operation(summary = "查询所有工单(技术人员)") + @GetMapping("/list") + public ApiResult> allTickets(AppTicketParam param) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录",null); + // 按用户有权限的应用过滤工单(看到的工单限于自己参与的应用) + List accessibleApps = appProductService.getAccessibleApps(loginUser.getUserId()); + if (accessibleApps != null && !accessibleApps.isEmpty()) { + param.setAppIds(accessibleApps.stream().map(AppProduct::getProductId).collect(Collectors.toList())); + } + return success(appTicketService.allPage(param)); + } + + @Operation(summary = "获取工单详情") + @GetMapping("/{ticketId}") + public ApiResult detail(@PathVariable Long ticketId) { + return success(appTicketService.getById(ticketId)); + } + + @Operation(summary = "更新工单状态(技术人员)") + @PutMapping("/status") + public ApiResult updateStatus(@RequestBody Map body) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + Long ticketId = Long.valueOf(body.get("ticketId").toString()); + String status = body.get("status").toString(); + appTicketService.updateStatus(ticketId, status, loginUser.getUserId()); + return success("状态已更新"); + } + + @Operation(summary = "分配处理人(管理员)") + @PutMapping("/assign") + public ApiResult assign(@RequestBody Map body) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + Long ticketId = Long.valueOf(body.get("ticketId").toString()); + Integer assigneeId = Integer.valueOf(body.get("assigneeId").toString()); + appTicketService.assign(ticketId, assigneeId); + return success("分配成功"); + } + + // ─── 回复接口 ───────────────────────────────────────────────── + + @Operation(summary = "获取工单回复列表") + @GetMapping("/{ticketId}/replies") + public ApiResult> replies(@PathVariable Long ticketId) { + return success(appTicketService.getReplies(ticketId)); + } + + @Operation(summary = "提交工单回复") + @PostMapping("/reply") + public ApiResult reply(@RequestBody AppTicketReply reply) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录",null); + if (reply.getContent() == null || reply.getContent().trim().isEmpty()) { + return fail("回复内容不能为空",null); + } + try { + AppTicketReply result = appTicketService.addReply(reply, loginUser.getUserId()); + return success("回复成功", result); + } catch (Exception e) { + return fail(e.getMessage(),null); + } + } + + // ─── 统计 & 辅助 ───────────────────────────────────────────── + + @Operation(summary = "工单统计数据") + @GetMapping("/stats") + public ApiResult> stats( + @RequestParam(required = false) Long appId) { + User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录",null); + // 技术端不限制用户维度;客户端通过路由区分 + return success(appTicketService.stats(appId, null)); + } + + @Operation(summary = "获取技术人员列表(用于分配)") + @GetMapping("/staff-list") + public ApiResult>> staffList() { + return success(appTicketService.getTechStaffList()); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppUserController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppUserController.java new file mode 100644 index 0000000..98b9a9c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppUserController.java @@ -0,0 +1,293 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.app.service.AppUserService; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.param.AppUserParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.app.mapper.SysUserCrossDbMapper; +import com.gxwebsoft.app.mapper.AppUserMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.*; + +/** + * 应用成员控制器 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Slf4j +@Tag(name = "应用成员管理") +@RestController +@RequestMapping("/api/app/app-user") +public class AppUserController extends BaseController { + + @Resource + private AppUserService appUserService; + + @Resource + private SysUserCrossDbMapper sysUserCrossDbMapper; + + @Resource + private AppUserMapper appUserMapper; + + @Operation(summary = "分页查询应用成员") + @GetMapping("/page") + public ApiResult> page(AppUserParam param) { + return success(appUserService.pageRel(param)); + } + + @Operation(summary = "查询全部应用成员") + @GetMapping() + public ApiResult> list(AppUserParam param) { + return success(appUserService.listRel(param)); + } + + @Operation(summary = "根据id查询应用成员") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(appUserService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('app:appUser:save')") + @OperationLog + @Operation(summary = "添加应用成员(手动添加)") + @PostMapping() + public ApiResult save(@RequestBody AppUser appUser) { + User loginUser = getLoginUser(); + if (loginUser != null) { + appUser.setUserId(loginUser.getUserId()); + appUser.setTenantId(loginUser.getTenantId()); + } + if (appUserService.save(appUser)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "邀请用户成为应用成员(支持用户ID或手机号)") + @PostMapping("/invite") + public ApiResult invite(@RequestBody AppUser appUser) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + // 支持手机号邀请:若 userId 为空但传了 phone,则先按手机号查出用户 + if (appUser.getUserId() == null && appUser.getPhone() != null && !appUser.getPhone().isEmpty()) { + User targetUser = appUserService.findUserByPhone(appUser.getPhone()); + if (targetUser == null) { + return fail("手机号未注册,请确认后再试"); + } + appUser.setUserId(targetUser.getUserId()); + } + if (appUser.getUserId() == null) { + return fail("请输入用户ID或手机号"); + } + try { + AppUser result = appUserService.inviteUser( + appUser.getAppId(), + appUser.getUserId(), + appUser.getRole(), + loginUser.getUserId(), + loginUser.getTenantId() + ); + return success("邀请成功", result); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('app:appUser:update')") + @OperationLog + @Operation(summary = "修改应用成员信息") + @PutMapping() + public ApiResult update(@RequestBody AppUser appUser) { + if (appUserService.updateById(appUser)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appUser:update')") + @OperationLog + @Operation(summary = "修改成员角色") + @PutMapping("/role/{id}/{role}") + public ApiResult updateRole(@PathVariable("id") Long id, @PathVariable("role") String role) { + if (appUserService.updateRole(id, role)) { + return success("角色修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appUser:remove')") + @OperationLog + @Operation(summary = "移除应用成员") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (appUserService.removeById(id)) { + return success("已移除"); + } + return fail("移除失败"); + } + + @PreAuthorize("hasAuthority('app:appUser:save')") + @OperationLog + @Operation(summary = "批量添加应用成员") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (appUserService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('app:appUser:update')") + @OperationLog + @Operation(summary = "批量修改应用成员") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(appUserService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appUser:remove')") + @OperationLog + @Operation(summary = "批量移除应用成员") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (appUserService.removeByIds(ids)) { + return success("移除成功"); + } + return fail("移除失败"); + } + + @Operation(summary = "搜索用户(用于邀请成员,支持手机号/用户名/昵称模糊搜索)") + @GetMapping("/search") + public ApiResult> searchUsers(@RequestParam("keyword") String keyword) { + if (keyword == null || keyword.trim().isEmpty()) { + return success(Collections.emptyList()); + } + List users = appUserService.searchUsers(keyword.trim()); + return success(users); + } + + // ============ 邀请确认相关接口 ============ + + @Operation(summary = "查询当前用户的待确认邀请列表") + @GetMapping("/invites/pending") + public ApiResult> listPendingInvites() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录",null); + } + return success(appUserService.listPendingInvites(loginUser.getUserId())); + } + + @Operation(summary = "统计当前用户的待确认邀请数量") + @GetMapping("/invites/pending/count") + public ApiResult> countPendingInvites() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return success(Map.of("count", 0L)); + } + long count = appUserService.countPendingInvites(loginUser.getUserId()); + return success(Map.of("count", count)); + } + + @Operation(summary = "接受邀请加入应用") + @PostMapping("/invites/{inviteId}/accept") + public ApiResult acceptInvite(@PathVariable("inviteId") Long inviteId) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + if (appUserService.acceptInvite(inviteId, loginUser.getUserId())) { + return success("已接受邀请,加入应用成功"); + } + return fail("接受邀请失败"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + @Operation(summary = "拒绝邀请") + @PostMapping("/invites/{inviteId}/reject") + public ApiResult rejectInvite(@PathVariable("inviteId") Long inviteId) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + if (appUserService.rejectInvite(inviteId, loginUser.getUserId())) { + return success("已拒绝邀请"); + } + return fail("拒绝邀请失败"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + // ============ 权限检查接口 ============ + + /** + * 检查当前用户是否有开发者中心访问权限 + * 判断逻辑: + * 1. sys_user.type === 2 → 平台开发者,直接放行 + * 2. 在 app_user 表中有成员记录 → 协作成员,放行 + * 3. 创建过应用(app_product.user_id) → 自动有权限 + * 返回:accessible, isPlatformDeveloper, apps(可访问应用列表及角色) + */ + @Operation(summary = "检查开发者中心访问权限") + @GetMapping("/check-access") + public ApiResult> checkAccess() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return success(Map.of( + "accessible", false, + "isPlatformDeveloper", false, + "hasJoinedApps", false + )); + } + + Integer userId = loginUser.getUserId(); + + // 1. 判断是否平台级开发者(type === 2) + boolean isPlatformDeveloper = false; + try { + Integer userType = sysUserCrossDbMapper.selectUserType(userId); + isPlatformDeveloper = userType != null && userType == 2; + } catch (Exception e) { + log.warn("查询用户类型失败,userId={}, error={}", userId, e.getMessage()); + } + + // 2. 查询用户参与的应用(创建的 + 被邀请的) + List> apps = appUserMapper.selectUserAccessibleApps(userId); + boolean hasJoinedApps = apps != null && !apps.isEmpty(); + + // 3. 平台开发者 或 有参与的应用 → 可访问 + boolean accessible = isPlatformDeveloper || hasJoinedApps; + + // 4. 构建返回结果 + Map result = new LinkedHashMap<>(); + result.put("accessible", accessible); + result.put("isPlatformDeveloper", isPlatformDeveloper); + result.put("hasJoinedApps", hasJoinedApps); + result.put("apps", apps != null ? apps : Collections.emptyList()); + + return success(result); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppUserSyncController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppUserSyncController.java new file mode 100644 index 0000000..066a953 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppUserSyncController.java @@ -0,0 +1,181 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppUserCache; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; + +/** + * 用户同步控制器(供 server 端调用) + * + * @author WebSoft + * @since 2026-04-04 + */ +@Slf4j +@Tag(name = "用户同步(server 端调用)") +@RestController +@RequestMapping("/api/app/user-sync") +public class AppUserSyncController extends BaseController { + + @Resource + private AppUserCacheService appUserCacheService; + + /** + * 同步单个用户到缓存表 + * 供 server 端用户注册成功后调用 + */ + @Operation(summary = "同步单个用户(server 端调用)") + @PostMapping("/single") + public ApiResult syncSingleUser(@RequestBody AppUserCache userCache) { + log.info("收到用户同步请求: userId={}, username={}, nickname={}, phone={}, tenantId={}", + userCache.getUserId(), userCache.getUsername(), userCache.getNickname(), userCache.getPhone(), userCache.getTenantId()); + + if (userCache.getUserId() == null) { + return fail("userId 不能为空"); + } + + if (userCache.getTenantId() == null) { + return fail("tenantId 不能为空"); + } + + try { + // 设置更新时间(如果为空) + if (userCache.getUpdateTime() == null) { + userCache.setUpdateTime(LocalDateTime.now()); + } + + // 直接保存或更新缓存 + boolean result = appUserCacheService.saveOrUpdate(userCache); + if (result) { + log.info("用户同步成功: userId={}, username={}, tenantId={}", userCache.getUserId(), userCache.getUsername(), userCache.getTenantId()); + } else { + log.warn("用户同步返回失败: userId={}", userCache.getUserId()); + } + return success("同步成功"); + } catch (Exception e) { + log.error("用户同步失败: userId={}, error={}", userCache.getUserId(), e.getMessage(), e); + return fail("同步失败: " + e.getMessage()); + } + } + + /** + * 批量同步用户到缓存表 + */ + @Operation(summary = "批量同步用户(server 端调用)") + @PostMapping("/batch") + public ApiResult syncBatchUsers(@RequestBody List userCaches) { + log.info("收到批量用户同步请求: count={}", userCaches.size()); + + if (userCaches.isEmpty()) { + return fail("用户列表不能为空"); + } + + // 校验每个用户数据 + for (AppUserCache userCache : userCaches) { + if (userCache.getUserId() == null) { + return fail("用户列表中存在 userId 为空的记录"); + } + if (userCache.getTenantId() == null) { + return fail("用户列表中存在 tenantId 为空的记录,userId=" + userCache.getUserId()); + } + } + + try { + appUserCacheService.saveOrUpdateBatch(userCaches); + log.info("批量用户同步成功: count={}", userCaches.size()); + return success("批量同步成功"); + } catch (Exception e) { + log.error("批量用户同步失败: error={}", e.getMessage()); + return fail("批量同步失败: " + e.getMessage()); + } + } + + /** + * 根据 userId 刷新用户缓存 + * server 端可以只传 userId,websopy 端通过 API 回查 server 获取完整信息 + */ + @Operation(summary = "刷新用户缓存(server 端调用)") + @PostMapping("/refresh/{userId}") + public ApiResult refreshUserCache(@PathVariable("userId") Integer userId) { + log.info("收到刷新用户缓存请求: userId={}", userId); + + if (userId == null) { + return fail("userId 不能为空"); + } + + try { + appUserCacheService.refreshUserCache(userId); + log.info("用户缓存刷新成功: userId={}", userId); + return success("刷新成功"); + } catch (Exception e) { + log.error("用户缓存刷新失败: userId={}, error={}", userId, e.getMessage()); + return fail("刷新失败: " + e.getMessage()); + } + } + + /** + * 删除用户缓存 + * 供 server 端删除用户时调用,同步删除本地缓存 + */ + @Operation(summary = "删除用户缓存(server 端调用)") + @PostMapping("/delete/{userId}") + public ApiResult deleteUserCache(@PathVariable("userId") Integer userId) { + log.info("收到删除用户缓存请求: userId={}", userId); + + if (userId == null) { + return fail("userId 不能为空"); + } + + try { + boolean result = appUserCacheService.removeById(userId); + if (result) { + log.info("用户缓存删除成功: userId={}", userId); + return success("删除成功"); + } else { + log.warn("用户缓存删除失败或用户不存在: userId={}", userId); + return success("用户不存在或已删除"); + } + } catch (Exception e) { + log.error("用户缓存删除失败: userId={}, error={}", userId, e.getMessage()); + return fail("删除失败: " + e.getMessage()); + } + } + + /** + * 批量删除用户缓存 + * 供 server 端批量删除用户时调用 + */ + @Operation(summary = "批量删除用户缓存(server 端调用)") + @PostMapping("/delete/batch") + public ApiResult deleteBatchUserCache(@RequestBody List userIds) { + log.info("收到批量删除用户缓存请求: count={}", userIds.size()); + + if (userIds == null || userIds.isEmpty()) { + return fail("userId 列表不能为空"); + } + + try { + boolean result = appUserCacheService.removeByIds(userIds); + if (result) { + log.info("批量用户缓存删除成功: count={}", userIds.size()); + return success("批量删除成功"); + } else { + log.warn("批量用户缓存删除失败: count={}", userIds.size()); + return success("删除失败或用户不存在"); + } + } catch (Exception e) { + log.error("批量用户缓存删除失败: error={}", e.getMessage()); + return fail("批量删除失败: " + e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppVersionController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppVersionController.java new file mode 100644 index 0000000..4b33348 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppVersionController.java @@ -0,0 +1,173 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.app.service.AppVersionService; +import com.gxwebsoft.app.entity.AppVersion; +import com.gxwebsoft.app.param.AppVersionParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 应用版本发布记录控制器 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Slf4j +@Tag(name = "应用版本发布管理") +@RestController +@RequestMapping("/api/app/app-version") +public class AppVersionController extends BaseController { + + @Resource + private AppVersionService appVersionService; + + @Operation(summary = "分页查询版本记录") + @GetMapping("/page") + public ApiResult> page(AppVersionParam param) { + return success(appVersionService.pageRel(param)); + } + + @Operation(summary = "查询全部版本记录") + @GetMapping() + public ApiResult> list(AppVersionParam param) { + return success(appVersionService.listRel(param)); + } + + @Operation(summary = "根据id查询版本") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(appVersionService.getByIdRel(id)); + } + + @Operation(summary = "获取应用当前版本") + @GetMapping("/current/{appId}") + public ApiResult getCurrentVersion(@PathVariable("appId") Long appId) { + return success(appVersionService.getCurrentVersion(appId)); + } + + @PreAuthorize("hasAuthority('app:appVersion:save')") + @OperationLog + @Operation(summary = "新增版本(构建中状态)") + @PostMapping() + public ApiResult save(@RequestBody AppVersion appVersion) { + User loginUser = getLoginUser(); + if (loginUser != null) { + appVersion.setUserId(loginUser.getUserId()); + appVersion.setTenantId(loginUser.getTenantId()); + } + // 默认为构建中状态 + if (appVersion.getStatus() == null) { + appVersion.setStatus(0); + } + if (appVersion.getEnv() == null) { + appVersion.setEnv("production"); + } + appVersion.setIsCurrent(false); + if (appVersionService.save(appVersion)) { + return success("创建成功"); + } + return fail("创建失败"); + } + + @PreAuthorize("hasAuthority('app:appVersion:update')") + @OperationLog + @Operation(summary = "修改版本信息") + @PutMapping() + public ApiResult update(@RequestBody AppVersion appVersion) { + if (appVersionService.updateById(appVersion)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appVersion:update')") + @OperationLog + @Operation(summary = "发布版本(将此版本设为当前运行版本)") + @PostMapping("/publish/{id}") + public ApiResult publish(@PathVariable("id") Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + appVersionService.publish(id, loginUser.getUserId()); + return success("发布成功"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('app:appVersion:update')") + @OperationLog + @Operation(summary = "回滚到指定版本") + @PostMapping("/rollback/{id}") + public ApiResult rollback(@PathVariable("id") Long id) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + appVersionService.rollback(id, loginUser.getUserId()); + return success("回滚成功"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('app:appVersion:remove')") + @OperationLog + @Operation(summary = "删除版本记录") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (appVersionService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('app:appVersion:save')") + @OperationLog + @Operation(summary = "批量添加版本") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (appVersionService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('app:appVersion:update')") + @OperationLog + @Operation(summary = "批量修改版本") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(appVersionService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('app:appVersion:remove')") + @OperationLog + @Operation(summary = "批量删除版本记录") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (appVersionService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppWxPayController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppWxPayController.java new file mode 100644 index 0000000..b1786a9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/AppWxPayController.java @@ -0,0 +1,205 @@ +package com.gxwebsoft.app.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.app.config.AppPayProperties; +import com.gxwebsoft.app.entity.AppSubscription; +import com.gxwebsoft.app.mapper.AppSubscriptionMapper; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.wechat.pay.java.core.cipher.AeadAesCipher; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.util.Base64Utils; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.LocalDateTime; + +/** + * 微信支付回调通知处理 + * 路径:POST /api/app/subscription/wx-notify + * 由微信支付服务器主动调用(Native 扫码支付成功后会回调此地址) + *

+ * 注意:前端同时在轮询 check-status 接口,回调只是加速状态更新。 + * 即使回调失败,前端轮询也能在 3s 内查到已支付状态。 + */ +@Slf4j +@RestController +@RequestMapping("/api/app/subscription") +@RequiredArgsConstructor +@Tag(name = "微信支付回调") +public class AppWxPayController { + + @Resource + private AppSubscriptionMapper subscriptionMapper; + @Resource + private RedisUtil redisUtil; + @Resource + private AppPayProperties appPayProperties; + + @Value("${spring.profiles.active:dev}") + private String active; + + /** + * 微信 Native 支付回调通知 + * 微信支付成功后会 POST JSON 到此地址 + */ + @PostMapping("/wx-notify") + @Operation(summary = "微信支付回调通知") + public String wxNotify( + @RequestHeader(value = "Wechatpay-Serial", required = false) String serialNumber, + @RequestHeader(value = "Wechatpay-Nonce", required = false) String nonce, + @RequestHeader(value = "Wechatpay-Signature", required = false) String signature, + @RequestHeader(value = "Wechatpay-Timestamp", required = false) String timestamp, + @RequestBody String body + ) { + log.info("收到微信支付回调 — headers: serial={}, timestamp={}, body={}", serialNumber, timestamp, body); + + try { + // 1. 解析通知(解密报文体) + JSONObject notification = parseNotification(body); + if (notification == null) { + log.error("通知解析失败"); + return failResult("notification parse failed"); + } + + // 2. 提取关键字段 + String eventType = notification.getString("event_type"); + JSONObject resource = notification.getJSONObject("resource"); + if (resource == null) { + log.error("通知报文体中无 resource 字段"); + return failResult("no resource"); + } + + // 解密资源 + String ciphertext = resource.getString("ciphertext"); + String nonceStr = resource.getString("nonce"); + String associatedData = resource.getString("associated_data"); + String apiV3Key = getApiV3Key(); + + String plainText; + try { + plainText = decryptResource(ciphertext, apiV3Key, nonceStr, associatedData); + } catch (Exception e) { + log.error("资源解密失败: {}", e.getMessage()); + return failResult("decrypt failed"); + } + + JSONObject tradeData = JSON.parseObject(plainText); + String outTradeNo = tradeData.getString("out_trade_no"); + String tradeState = tradeData.getString("trade_state"); + String transactionId = tradeData.getString("transaction_id"); + BigDecimal totalAmount = tradeData.getBigDecimal("amount") != null + ? tradeData.getJSONObject("amount").getBigDecimal("payer_total") : BigDecimal.ZERO; + + log.info("解密后 — outTradeNo={}, tradeState={}, transactionId={}, amount={}", + outTradeNo, tradeState, transactionId, totalAmount); + + // 3. 仅处理支付成功事件 + if (!"TRANSACTION.SUCCESS".equals(eventType) && !"SUCCESS".equals(tradeState)) { + log.warn("非成功回调,忽略 — eventType: {}, tradeState: {}", eventType, tradeState); + return successResult(); + } + + // 4. 查询并更新订阅记录 + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(AppSubscription::getSubscriptionNo, outTradeNo); + AppSubscription sub = subscriptionMapper.selectOne(query); + + if (sub == null) { + log.warn("未找到订阅记录 outTradeNo: {}", outTradeNo); + return successResult(); // 返回成功,避免微信重复回调 + } + + if (sub.getPayStatus() != null && sub.getPayStatus() == 1) { + log.info("订阅 {} 已支付,跳过重复处理", outTradeNo); + return successResult(); + } + + // 5. 更新状态 + sub.setPayStatus(1); + sub.setStatus("active"); + sub.setPayTime(LocalDateTime.now()); + sub.setTransactionId(transactionId); + sub.setPayType(1); // 1=微信支付 + sub.setStartTime(LocalDateTime.now()); + + // 设置到期时间(订阅型) + if ("subscription".equals(sub.getPriceType())) { + int months = "year".equals(sub.getSubscriptionPeriod()) ? 12 : 1; + sub.setExpireTime(LocalDateTime.now().plusMonths(months)); + } + + subscriptionMapper.updateById(sub); + log.info("订阅 {} 支付成功,状态已更新", outTradeNo); + + // 6. 写入 Redis,加速前端轮询感知 + redisUtil.set("wxpay:paid:" + outTradeNo, "1", Duration.ofHours(24)); + + return successResult(); + + } catch (Exception e) { + log.error("微信支付回调处理异常: {}", e.getMessage(), e); + return failResult("internal error: " + e.getMessage()); + } + } + + /** + * 解析通知(V3 API 使用 AES-256-GCM 解密 resource 字段) + */ + private JSONObject parseNotification(String body) { + try { + return JSON.parseObject(body); + } catch (Exception e) { + log.error("JSON 解析失败: {}", body); + return null; + } + } + + /** + * AES-256-GCM 解密微信 V3 通知 resource.ciphertext + * - resource.nonce:Base64 编码的 12 字节随机数 + * - resource.ciphertext:Base64(AEAD_AES_256_GCM(nonce + plaintext)) + * 其中 ciphertext 末尾 16 字节为 tag + */ + private String decryptResource(String ciphertext, String apiV3Key, String nonce, String associatedData) + throws Exception { + byte[] key = apiV3Key.getBytes(StandardCharsets.UTF_8); + // nonce 是 Base64 编码的 12 字节随机数,需要解码 + byte[] nonceBytes = Base64Utils.decodeFromString(nonce); + // associated_data 原样 UTF-8 编码 + byte[] aad = (associatedData == null ? "" : associatedData).getBytes(StandardCharsets.UTF_8); + // ciphertext = Base64(ciphertext_bytes),其中末尾 16 字节为 auth tag + byte[] cipherBytes = Base64Utils.decodeFromString(ciphertext); + + // 新版 SDK:AeadAesCipher.decrypt(nonce, associatedData, ciphertextWithTag) + AeadAesCipher cipher = new AeadAesCipher(key); + return cipher.decrypt(nonceBytes, aad, cipherBytes); + } + + /** + * 获取 APIv3 密钥(根据环境选择正式/测试配置) + */ + private String getApiV3Key() { + if ("dev".equals(active) && appPayProperties.isTestMode()) { + String key = appPayProperties.getTestApiV3Key(); + return key != null ? key : appPayProperties.getApiV3Key(); + } + return appPayProperties.getApiV3Key(); + } + + private String successResult() { + return "{\"code\":\"SUCCESS\",\"message\":\"OK\"}"; + } + + private String failResult(String msg) { + return "{\"code\":\"FAIL\",\"message\":\"" + msg + "\"}"; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/CICDController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/CICDController.java new file mode 100644 index 0000000..e641c99 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/CICDController.java @@ -0,0 +1,256 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppBuild; +import com.gxwebsoft.app.entity.AppPipeline; +import com.gxwebsoft.app.param.AppBuildParam; +import com.gxwebsoft.app.param.AppPipelineParam; +import com.gxwebsoft.app.service.AppBuildService; +import com.gxwebsoft.app.service.AppPipelineService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * CI/CD 控制器 + * 支持 Jenkins / GitHub Actions / Gitea CI + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Tag(name = "CI/CD管理") +@RestController +@RequestMapping("/api/app/cicd") +public class CICDController extends BaseController { + + @Resource + private AppBuildService appBuildService; + + @Resource + private AppPipelineService appPipelineService; + + // ========== 流水线接口 ========== + + @Operation(summary = "分页查询流水线") + @GetMapping("/pipeline/page") + public ApiResult> pagePipeline(AppPipelineParam param) { + User loginUser = getLoginUser(); + if (loginUser != null) { + param.setUserId(loginUser.getUserId()); + } + return success(appPipelineService.pagePipeline(param)); + } + + @Operation(summary = "查询应用的所有流水线") + @GetMapping("/pipeline/app/{appId}") + public ApiResult> listByApp(@PathVariable Long appId) { + return success(appPipelineService.getByAppId(appId)); + } + + @Operation(summary = "查询流水线详情") + @GetMapping("/pipeline/{id}") + public ApiResult getPipeline(@PathVariable Long id) { + return success(appPipelineService.getPipelineDetail(id)); + } + + @PreAuthorize("hasAuthority('app:cicd:pipeline:save')") + @Operation(summary = "创建流水线") + @PostMapping("/pipeline") + public ApiResult createPipeline(@RequestBody AppPipeline pipeline) { + User loginUser = getLoginUser(); + if (loginUser != null) { + pipeline.setUserId(loginUser.getUserId()); + pipeline.setTenantId(loginUser.getTenantId()); + } + if (appPipelineService.createPipeline(pipeline)) { + return success("创建成功"); + } + return fail("创建失败"); + } + + @PreAuthorize("hasAuthority('app:cicd:pipeline:update')") + @Operation(summary = "更新流水线") + @PutMapping("/pipeline") + public ApiResult updatePipeline(@RequestBody AppPipeline pipeline) { + if (appPipelineService.updatePipeline(pipeline)) { + return success("更新成功"); + } + return fail("更新失败"); + } + + @PreAuthorize("hasAuthority('app:cicd:pipeline:remove')") + @Operation(summary = "删除流水线") + @DeleteMapping("/pipeline/{id}") + public ApiResult deletePipeline(@PathVariable Long id) { + if (appPipelineService.deletePipeline(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('app:cicd:pipeline:update')") + @Operation(summary = "启用/禁用流水线") + @PostMapping("/pipeline/{id}/toggle") + public ApiResult togglePipeline(@PathVariable Long id, @RequestParam boolean enabled) { + if (appPipelineService.togglePipeline(id, enabled)) { + return success(enabled ? "已启用" : "已禁用"); + } + return fail("操作失败"); + } + + @Operation(summary = "获取流水线状态") + @GetMapping("/pipeline/{id}/status") + public ApiResult> getPipelineStatus(@PathVariable Long id) { + AppPipeline pipeline = appPipelineService.getById(id); + Map result = new HashMap<>(); + result.put("id", id); + result.put("status", appPipelineService.getPipelineStatus(id)); + result.put("lastBuildId", pipeline != null ? pipeline.getLastBuildId() : null); + result.put("lastBuildTime", pipeline != null ? pipeline.getLastBuildTime() : null); + result.put("successCount", pipeline != null ? pipeline.getSuccessCount() : 0); + result.put("failureCount", pipeline != null ? pipeline.getFailureCount() : 0); + return success(result); + } + + // ========== 构建接口 ========== + + @Operation(summary = "分页查询构建记录") + @GetMapping("/build/page") + public ApiResult> pageBuild(AppBuildParam param) { + User loginUser = getLoginUser(); + if (loginUser != null) { + param.setUserId(loginUser.getUserId()); + } + return success(appBuildService.pageBuild(param)); + } + + @Operation(summary = "查询应用的所有构建记录") + @GetMapping("/build/app/{appId}") + public ApiResult> listBuildByApp(@PathVariable Long appId) { + AppBuildParam param = new AppBuildParam(); + param.setAppId(appId); + return success(appBuildService.pageBuild(param).getList()); + } + + @Operation(summary = "查询构建详情") + @GetMapping("/build/{id}") + public ApiResult getBuild(@PathVariable Long id) { + return success(appBuildService.getBuildDetail(id)); + } + + @Operation(summary = "获取应用最新构建") + @GetMapping("/build/latest/{appId}") + public ApiResult getLatestBuild(@PathVariable Long appId) { + return success(appBuildService.getLatestBuild(appId)); + } + + @PreAuthorize("hasAuthority('app:cicd:build:save')") + @Operation(summary = "触发构建") + @PostMapping("/build/trigger") + public ApiResult> triggerBuild( + @RequestParam Long appId, + @RequestParam(required = false) String branch) { + User loginUser = getLoginUser(); + Integer triggeredBy = loginUser != null ? loginUser.getUserId() : null; + + try { + AppBuild build = appBuildService.triggerBuild(appId, branch, triggeredBy); + Map result = new HashMap<>(); + result.put("id", build.getId()); + result.put("buildNumber", build.getBuildNumber()); + result.put("status", build.getStatus()); + result.put("branch", build.getBranch()); + return success("构建已触发", result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + @Operation(summary = "获取构建日志") + @GetMapping("/build/{id}/log") + public ApiResult> getBuildLog(@PathVariable Long id) { + try { + String log = appBuildService.getBuildLog(id); + Map result = new HashMap<>(); + result.put("log", log); + result.put("buildId", id); + return success(result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + @PreAuthorize("hasAuthority('app:cicd:build:update')") + @Operation(summary = "取消构建") + @PostMapping("/build/{id}/cancel") + public ApiResult cancelBuild(@PathVariable Long id) { + try { + if (appBuildService.cancelBuild(id)) { + return success("构建已取消"); + } + return fail("取消失败"); + } catch (Exception e) { + return fail(e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('app:cicd:build:save')") + @Operation(summary = "重试构建") + @PostMapping("/build/{id}/retry") + public ApiResult> retryBuild(@PathVariable Long id) { + User loginUser = getLoginUser(); + Integer triggeredBy = loginUser != null ? loginUser.getUserId() : null; + + try { + AppBuild build = appBuildService.retryBuild(id, triggeredBy); + Map result = new HashMap<>(); + result.put("id", build.getId()); + result.put("buildNumber", build.getBuildNumber()); + result.put("status", build.getStatus()); + return success("构建已重试", result); + } catch (Exception e) { + return fail(e.getMessage(), null); + } + } + + @Operation(summary = "获取构建统计") + @GetMapping("/build/stats/{appId}") + public ApiResult> getBuildStats(@PathVariable Long appId) { + return success(appBuildService.getBuildStats(appId)); + } + + // ========== Webhook 回调接口 ========== + + @Operation(summary = "Gitea Webhook 回调") + @PostMapping("/webhook/gitea") + public ApiResult giteaWebhook(@RequestBody Map payload) { + try { + appBuildService.handleWebhook("gitea", payload); + return success("回调处理成功"); + } catch (Exception e) { + log.error("Gitea webhook处理失败: {}", e.getMessage()); + return fail("处理失败: " + e.getMessage()); + } + } + + @Operation(summary = "获取CI系统配置") + @GetMapping("/config") + public ApiResult> getCIConfig() { + Map config = new HashMap<>(); + config.put("supportedCI", new String[]{"gitea", "jenkins", "github"}); + config.put("defaultCI", "gitea"); + config.put("giteaUrl", "https://git.websoft.top"); + return success(config); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/controller/GitAccountController.java b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/GitAccountController.java new file mode 100644 index 0000000..af9e409 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/controller/GitAccountController.java @@ -0,0 +1,176 @@ +package com.gxwebsoft.app.controller; + +import com.gxwebsoft.app.entity.AppGitAccount; +import com.gxwebsoft.app.service.AppGitAccountService; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Git账号绑定控制器 + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Slf4j +@Tag(name = "Git账号绑定") +@RestController +@RequestMapping("/api/app/developer") +public class GitAccountController extends BaseController { + + @Resource + private AppGitAccountService appGitAccountService; + + /** + * 保存Git账号绑定信息 + */ + @OperationLog + @Operation(summary = "保存Git账号绑定") + @PostMapping("/git-account") + public ApiResult> saveGitAccount(@RequestBody Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + + String username = params.get("username"); + String email = params.get("email"); + String remark = params.get("remark"); + + try { + AppGitAccount account = appGitAccountService.saveGitAccount(username, email, remark, loginUser.getUserId(), loginUser.getTenantId()); + + Map result = new HashMap<>(); + result.put("userId", account.getUserId()); + result.put("gitUsername", account.getUsername()); + result.put("email", account.getEmail()); + result.put("remark", account.getRemark()); + result.put("savedAt", account.getUpdateTime() != null ? account.getUpdateTime().toString() : account.getCreateTime().toString()); + result.put("status", account.getStatus()); + + return success("Git账号绑定成功", result); + } catch (Exception e) { + log.error("保存Git账号绑定失败: {}", e.getMessage()); + return fail(e.getMessage(), null); + } + } + + /** + * 获取Git账号绑定状态 + */ + @Operation(summary = "获取Git账号绑定状态") + @GetMapping({"/git-account", "/git-account/status"}) + public ApiResult> getGitAccountStatus() { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + + AppGitAccount account = appGitAccountService.getGitAccountStatus(loginUser.getUserId(), loginUser.getTenantId()); + + Map result = new HashMap<>(); + if (account != null && account.getStatus() != null && !"not_bound".equals(account.getStatus())) { + result.put("username", account.getUsername()); + result.put("email", account.getEmail()); + result.put("remark", account.getRemark()); + result.put("status", account.getStatus()); + result.put("verificationNote", account.getVerificationNote()); + if (account.getUpdateTime() != null) { + result.put("lastUpdatedAt", account.getUpdateTime().toString()); + } else if (account.getCreateTime() != null) { + result.put("lastUpdatedAt", account.getCreateTime().toString()); + } + } else { + result.put("status", "not_bound"); + } + + return success(result); + } + + /** + * 获取Gitea服务器信息(静态配置) + */ + @Operation(summary = "获取Gitea服务器信息") + @GetMapping("/gitea-info") + public ApiResult> getGiteaInfo() { + // 这里返回静态配置,后续可以从配置文件中读取 + Map info = new HashMap<>(); + info.put("url", "https://git.websoft.top"); + info.put("version", "1.21"); + info.put("registrationEnabled", true); + info.put("requireEmailConfirmation", false); + info.put("maxRepoCreation", 100); + return success(info); + } + + // ========== 管理端接口 ========== + + /** + * 分页查询Git账号绑定列表(管理端) + */ + @Operation(summary = "分页查询Git账号绑定列表(管理端)") + @GetMapping("/git-account/list") + public ApiResult> pageGitAccounts( + @RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "20") int size, + @RequestParam(required = false) String status, + @RequestParam(required = false) String keyword) { + Map result = appGitAccountService.pageGitAccounts(status, keyword, page, size); + return success(result); + } + + /** + * 审核Git账号绑定 - 通过 + */ + @OperationLog + @Operation(summary = "审核Git账号绑定-通过") + @PutMapping("/git-account/{id}/approve") + public ApiResult approveAccount(@PathVariable("id") Long id, @RequestBody(required = false) Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + try { + String note = params != null ? params.get("note") : null; + boolean result = appGitAccountService.approveAccount(id, loginUser.getUserId(), loginUser.getRealName(), note); + return result ? success("审核通过") : fail("审核失败"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } + + /** + * 审核Git账号绑定 - 拒绝 + */ + @OperationLog + @Operation(summary = "审核Git账号绑定-拒绝") + @PutMapping("/git-account/{id}/reject") + public ApiResult rejectAccount(@PathVariable("id") Long id, @RequestBody Map params) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + + String reason = params != null ? params.get("reason") : null; + if (reason == null || reason.trim().isEmpty()) { + return fail("请填写拒绝原因"); + } + + try { + boolean result = appGitAccountService.rejectAccount(id, loginUser.getUserId(), loginUser.getRealName(), reason.trim()); + return result ? success("已拒绝该绑定申请") : fail("拒绝失败"); + } catch (RuntimeException e) { + return fail(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppApiKey.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppApiKey.java new file mode 100644 index 0000000..5a67033 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppApiKey.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.time.LocalDateTime; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用 API Key 实体 + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppApiKey对象", description = "应用API密钥") +public class AppApiKey implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增主键") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "API Key名称") + private String name; + + @Schema(description = "API Key密钥值(加密存储)") + private String apiKey; + + @Schema(description = "密钥前缀(用于显示,如 sk-xxxxx)") + private String keyPrefix; + + @Schema(description = "状态: 0正常, 1禁用") + private Integer status; + + @Schema(description = "权限范围,JSON数组字符串") + private String scopes; + + @Schema(description = "到期时间,NULL=永不过期") + private LocalDateTime expireTime; + + @Schema(description = "最后使用时间") + private LocalDateTime lastUsedAt; + + @Schema(description = "使用次数") + private Long usageCount; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppArticle.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppArticle.java new file mode 100644 index 0000000..7eac735 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppArticle.java @@ -0,0 +1,100 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 平台文章 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_article") +@Schema(name = "AppArticle对象", description = "平台文章") +public class AppArticle implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章ID") + @TableId(value = "article_id", type = IdType.AUTO) + private Integer articleId; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章类型 0常规 1视频") + private Integer type; + + @Schema(description = "文章模型,article 普通文章,announcement 公告") + private String model; + + @Schema(description = "文章编号") + private String code; + + @Schema(description = "分类ID") + private Integer categoryId; + + @Schema(description = "分类名称") + @TableField(exist = false) + private String categoryName; + + @Schema(description = "父级分类ID") + @TableField(exist = false) + private Integer parentId; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "来源") + private String source; + + @Schema(description = "摘要") + private String overview; + + @Schema(description = "正文内容") + private String content; + + @Schema(description = "实际阅读量") + private Integer actualViews; + + @Schema(description = "点赞数") + private Integer likes; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "作者") + private String author; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "排序值") + private Integer sortNumber; + + @Schema(description = "状态,0已发布 1草稿/待审核 2已驳回 3违规") + private Integer status; + + @Schema(description = "是否删除,0否 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppArticleCategory.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppArticleCategory.java new file mode 100644 index 0000000..4769bff --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppArticleCategory.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 平台文章分类 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_article_category") +@Schema(name = "AppArticleCategory对象", description = "平台文章分类") +public class AppArticleCategory implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "分类ID") + @TableId(value = "category_id", type = IdType.AUTO) + private Integer categoryId; + + @Schema(description = "分类标识") + private String categoryCode; + + @Schema(description = "分类名称") + private String title; + + @Schema(description = "类型 0列表 1单页 2外链") + private Integer type; + + @Schema(description = "分类图片") + private String image; + + @Schema(description = "上级分类ID") + private Integer parentId; + + @Schema(description = "访问路径") + private String path; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "文章数") + @TableField(exist = false) + private Integer count; + + @Schema(description = "排序值") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否隐藏") + private Integer hide; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否显示在首页") + private Integer showIndex; + + @Schema(description = "状态 0正常 1禁用") + private Integer status; + + @Schema(description = "是否删除,0否 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppBuild.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppBuild.java new file mode 100644 index 0000000..265a0cf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppBuild.java @@ -0,0 +1,118 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * CI/CD 构建记录实体 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppBuild对象", description = "CI/CD构建记录") +@TableName("app_build") +public class AppBuild implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "关联应用ID") + private Long appId; + + @Schema(description = "关联版本ID(可选)") + private Long versionId; + + @Schema(description = "构建编号(如 run-123)") + private String buildNumber; + + @Schema(description = "构建名称") + private String name; + + @Schema(description = "触发分支(如 main、develop)") + private String branch; + + @Schema(description = "提交哈希(可选)") + private String commitSha; + + @Schema(description = "提交消息(可选)") + private String commitMessage; + + @Schema(description = "提交作者(可选)") + private String commitAuthor; + + @Schema(description = "CI系统类型: gitea/jenkins/github") + private String ciType; + + @Schema(description = "CI系统中的任务ID") + private String ciJobId; + + @Schema(description = "CI系统中的运行ID") + private String ciRunId; + + @Schema(description = "CI系统API地址") + private String ciApiUrl; + + @Schema(description = "状态: pending/running/success/failed/cancelled") + private String status; + + @Schema(description = "构建开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime startedAt; + + @Schema(description = "构建结束时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime finishedAt; + + @Schema(description = "构建耗时(秒)") + private Integer duration; + + @Schema(description = "构建日志URL") + private String logUrl; + + @Schema(description = "构建产物URL(如 JAR、Docker镜像)") + private String artifactUrl; + + @Schema(description = "构建产物名称") + private String artifactName; + + @Schema(description = "构建产物大小(字节)") + private Long artifactSize; + + @Schema(description = "失败原因") + private String errorMessage; + + @Schema(description = "触发方式: manual/webhook/schedule") + private String triggerType; + + @Schema(description = "触发人用户ID") + private Integer triggeredBy; + + @Schema(description = "扩展配置(JSON)") + private String config; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppCloudCredential.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppCloudCredential.java new file mode 100644 index 0000000..da9fdba --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppCloudCredential.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 云账号凭证(阿里云/腾讯云/华为云等) + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_cloud_credential") +@Schema(name = "AppCloudCredential对象", description = "云账号凭证") +public class AppCloudCredential implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** 云服务商: aliyun/tencent/huawei/qiniu */ + private String provider; + + /** 凭证名称 */ + private String name; + + /** 访问密钥 ID (AK) */ + private String accessKeyId; + + /** 访问密钥密钥 (SK),AES加密存储 */ + private String accessKeySecret; + + /** 额外配置,JSON格式 */ + private String configJson; + + /** 状态: 0正常 1冻结 */ + private Integer status; + + /** 备注 */ + private String remark; + + /** 所属用户ID */ + private Integer userId; + + /** 租户ID */ + private Integer tenantId; + + @Schema(description = "是否删除: 0否 1是") + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + /** 测试状态: 0未测试 1成功 2失败 */ + private Integer testStatus; + + /** 测试消息 */ + private String testMessage; +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppConfig.java new file mode 100644 index 0000000..c61a514 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppConfig.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 应用配置表 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_config") +public class AppConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 配置ID + */ + @TableId(value = "config_id", type = IdType.AUTO) + private Integer configId; + + /** + * 应用ID + */ + private Integer appId; + + /** + * 配置键 + */ + private String configKey; + + /** + * 配置值(JSON或字符串) + */ + private String configValue; + + /** + * 配置类型:general/api/callback/wechat/payment/git等 + */ + private String configType; + + /** + * 是否加密 0否 1是 + */ + private Integer isEncrypted; + + /** + * 是否敏感信息 0否 1是 + */ + private Integer isSecret; + + /** + * 配置说明 + */ + private String description; + + /** + * 排序号 + */ + private Integer sortNumber; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Long createdTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updatedTime; + + /** + * 是否删除 0否 1是 + */ + @TableLogic + private Integer deleted; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppContract.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppContract.java new file mode 100644 index 0000000..8c65ea3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppContract.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 合同管理 + * + * @author 科技小王子 + * @since 2026-04-13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_contract") +@Schema(name = "AppContract对象", description = "合同管理") +public class AppContract implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "合同ID") + @TableId(value = "contract_id", type = IdType.AUTO) + private Long contractId; + + @Schema(description = "合同编号") + private String contractNo; + + @Schema(description = "合同名称") + private String title; + + @Schema(description = "合同类型: service/cooperation/purchase/other") + private String contractType; + + @Schema(description = "甲方名称") + private String partyA; + + @Schema(description = "乙方名称") + private String partyB; + + @Schema(description = "合同金额") + private BigDecimal amount; + + @Schema(description = "合同开始日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate startDate; + + @Schema(description = "合同结束日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate endDate; + + @Schema(description = "状态: draft/pending/active/expired/terminated") + private String status; + + @Schema(description = "合同附件URL") + private String fileUrl; + + @Schema(description = "合同附件原始文件名") + private String fileName; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建用户ID") + private Integer userId; + + @Schema(description = "创建用户名(冗余)") + private String userName; + + @Schema(description = "是否删除: 0否 1是") + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "租户ID") + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppCredential.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppCredential.java new file mode 100644 index 0000000..93e607e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppCredential.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用密钥凭证 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:43 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppCredential对象", description = "应用密钥凭证") +public class AppCredential implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "关联应用ID(AppProduct.productId)") + private String appId; + + @Schema(description = "OAuth Client ID(公开,格式:app_xxxxxxxxxxxx)") + private String clientId; + + @Schema(description = "OAuth Client Secret(加密存储)") + private String clientSecret; + + @Schema(description = "凭证类型: server/client/webhook") + private String type; + + @Schema(description = "权限范围,空格分隔") + private String scopes; + + @Schema(description = "到期时间,NULL=永不过期") + private LocalDateTime expireTime; + + @Schema(description = "最后使用时间") + private LocalDateTime lastUsedAt; + + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppEvent.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppEvent.java new file mode 100644 index 0000000..7636354 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppEvent.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用操作动态 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppEvent对象", description = "应用操作动态") +public class AppEvent implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "关联应用ID") + private Long appId; + + @Schema(description = "事件类型: created/published/updated/domain_bound/member_added/status_changed") + private String eventType; + + @Schema(description = "事件标题,如已发布") + private String title; + + @Schema(description = "详细描述") + private String content; + + @Schema(description = "操作人用户ID") + private Long operatorId; + + @Schema(description = "操作人名称(冗余)") + private String operator; + + @Schema(description = "关联ID,如版本ID") + private Long refId; + + @Schema(description = "关联类型") + private String refType; + + @Schema(description = "扩展数据") + private String extra; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppGitAccount.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppGitAccount.java new file mode 100644 index 0000000..a77982f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppGitAccount.java @@ -0,0 +1,64 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * Git账号绑定(开发者Gitea账号) + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppGitAccount对象", description = "Git账号绑定(开发者Gitea账号)") +@TableName("app_git_account") +public class AppGitAccount implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "Gitea用户名(唯一)") + private String username; + + @Schema(description = "联系邮箱") + private String email; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "状态: pending待审核/verified已通过/rejected已拒绝") + private String status; + + @Schema(description = "审核备注") + private String verificationNote; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppInviteToken.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppInviteToken.java new file mode 100644 index 0000000..8b2e762 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppInviteToken.java @@ -0,0 +1,64 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 应用邀请Token实体 + */ +@Data +@TableName("app_invite_token") +public class AppInviteToken { + + @TableId(type = IdType.AUTO) + private Integer id; + + /** + * 邀请token + */ + private String token; + + /** + * 应用ID + */ + private Integer appId; + + /** + * 邀请角色 + */ + private String role; + + /** + * 邀请人ID + */ + private Integer inviterId; + + /** + * 过期时间 + */ + private LocalDateTime expireTime; + + /** + * 状态:0-未使用,1-已使用 + */ + private Integer status; + + /** + * 接受人ID + */ + private Integer acceptUserId; + + /** + * 接受时间 + */ + private LocalDateTime acceptTime; + + /** + * 创建时间 + */ + private LocalDateTime createTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppNotification.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppNotification.java new file mode 100644 index 0000000..38dd4fe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppNotification.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 站内消息通知 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_notification") +@Schema(name = "AppNotification对象", description = "站内消息通知") +public class AppNotification implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "通知ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "接收用户ID") + private Integer userId; + + @Schema(description = "通知类型: ticket/review/system/resource/permission/member/payment") + private String type; + + @Schema(description = "通知标题") + private String title; + + @Schema(description = "通知内容摘要") + private String content; + + @Schema(description = "是否已读: 0未读 1已读") + private Integer isRead; + + @Schema(description = "关联业务ID(如工单ID、权限申请ID等)") + private Long refId; + + @Schema(description = "关联业务类型(如 ticket、permission_request 等)") + private String refType; + + @Schema(description = "跳转链接") + private String linkUrl; + + @Schema(description = "发送者ID(系统通知为0)") + private Integer senderId; + + @Schema(description = "发送者名称") + private String senderName; + + @Schema(description = "发送者头像") + private String senderAvatar; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppPermissionRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppPermissionRequest.java new file mode 100644 index 0000000..784463f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppPermissionRequest.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 权限申请记录(开发者Git仓库访问申请) + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppPermissionRequest对象", description = "权限申请记录(开发者Git仓库访问申请)") +@TableName("app_permission_request") +public class AppPermissionRequest implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "Git用户名") + private String gitUsername; + + @Schema(description = "申请仓库路径") + private String repo; + + @Schema(description = "仓库名称") + private String repoName; + + @Schema(description = "申请理由") + private String reason; + + @Schema(description = "状态: pending待审核/approved已通过/rejected已拒绝") + private String status; + + @Schema(description = "拒绝原因") + private String rejectReason; + + @Schema(description = "审核人用户ID") + private Integer reviewerId; + + @Schema(description = "审核人姓名") + private String reviewerName; + + @Schema(description = "审核时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime reviewedAt; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户ID") + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppPipeline.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppPipeline.java new file mode 100644 index 0000000..6bc1af2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppPipeline.java @@ -0,0 +1,99 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * CI/CD 流水线配置实体 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppPipeline对象", description = "CI/CD流水线配置") +@TableName("app_pipeline") +public class AppPipeline implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "关联应用ID") + private Long appId; + + @Schema(description = "流水线名称") + private String name; + + @Schema(description = "流水线描述") + private String description; + + @Schema(description = "CI系统类型: gitea/jenkins/github") + private String ciType; + + @Schema(description = "Gitea仓库全称(如 gxwebsoft/my-app)") + private String repoFullName; + + @Schema(description = "Gitea工作流文件名(如 build.yml)") + private String workflowFile; + + @Schema(description = "流水线阶段: build/test/deploy") + private String stages; + + @Schema(description = "环境: development/staging/production") + private String env; + + @Schema(description = "默认触发分支") + private String defaultBranch; + + @Schema(description = "是否启用") + private Boolean enabled; + + @Schema(description = "自动部署") + private Boolean autoDeploy; + + @Schema(description = "构建超时时间(秒)") + private Integer timeout; + + @Schema(description = "配置JSON(变量、环境等)") + private String config; + + @Schema(description = "最近一次构建ID") + private Long lastBuildId; + + @Schema(description = "最近构建状态") + private String lastBuildStatus; + + @Schema(description = "最近构建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastBuildTime; + + @Schema(description = "构建成功次数") + private Integer successCount; + + @Schema(description = "构建失败次数") + private Integer failureCount; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppProduct.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppProduct.java new file mode 100644 index 0000000..18aec32 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppProduct.java @@ -0,0 +1,321 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import javax.validation.constraints.Size; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 应用产品主表 + * + * @author 科技小王子 + * @since 2024-09-10 + */ +@Data +@Schema(name = "AppProduct对象", description = "应用产品主表") +public class AppProduct implements Serializable { + private static final long serialVersionUID = 1L; + + // ==================== 核心字段 ==================== + @Schema(description = "应用ID") + @TableId(value = "product_id", type = IdType.AUTO) + private Integer productId; + + @Schema(description = "应用名称") + @Size(max = 100, message = "应用名称长度不能超过100") + private String productName; + + @Schema(description = "应用标识(唯一)") + @Size(max = 50, message = "应用标识长度不能超过50") + private String productCode; + + @Schema(description = "应用密钥") + private String productSecret; + + // ==================== 应用类型 ==================== + @Schema(description = "应用类型: 10网站 20微信小程序 30抖音小程序 40百度小程序 50支付宝小程序 60Android 70iOS 80macOS 90Windows 100插件") + private Integer appType; + + @Schema(description = "应用类型名称") + @TableField(exist = false) + private String appTypeName; + + // ==================== 分类信息 ==================== + @Schema(description = "分类ID") + private Integer categoryId; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + // ==================== 基础信息 ==================== + @Schema(description = "应用Logo") + private String logo; + + @Schema(description = "应用图标") + private String icon; + + @Schema(description = "二维码") + private String qrcode; + + @Schema(description = "应用截图(JSON数组)") + private String screenshots; + + @Schema(description = "应用简介") + @Size(max = 500, message = "应用简介长度不能超过500") + private String description; + + @Schema(description = "详细说明") + private String content; + + @Schema(description = "关键词") + @Size(max = 200, message = "关键词长度不能超过200") + private String keywords; + + // ==================== 配置信息 ==================== + @Schema(description = "域名") + private String domain; + + @Schema(description = "域名前缀") + private String prefix; + + @Schema(description = "包名/AppID") + private String packageName; + + @Schema(description = "后台地址") + private String adminUrl; + + @Schema(description = "API地址") + private String apiUrl; + + @Schema(description = "下载地址") + private String downloadUrl; + + // ==================== 版本信息 ==================== + @Schema(description = "版本号") + private String version; + + @Schema(description = "版本: standard标准版 professional专业版 perpetual永久授权") + private String edition; + + @Schema(description = "最低版本要求") + private String minVersion; + + // ==================== 价格与交付 ==================== + @Schema(description = "定价: free免费 one_time一次性 subscription订阅") + private String priceType; + + @Schema(description = "价格(元)") + private BigDecimal price; + + @Schema(description = "划线价格") + private BigDecimal linePrice; + + @Schema(description = "续费价格") + private BigDecimal renewPrice; + + @Schema(description = "交付方式: 1源码 2托管 3授权") + private Integer deliveryMethod; + + @Schema(description = "计费方式: 1按年 2按月 3一次性") + private Integer chargingMethod; + + @Schema(description = "订阅周期: month/year") + private String subscriptionPeriod; + + // ==================== 发布管理 ==================== + @Schema(description = "发布状态: developing开发中 pending_review待审核 published已上架 rejected审核未通过 deprecated已下架") + private String publishStatus; + + @Schema(description = "发布时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date publishTime; + + @Schema(description = "审核时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date reviewTime; + + @Schema(description = "审核人ID") + private Integer reviewerId; + + @Schema(description = "拒绝原因") + private String rejectReason; + + // ==================== 统计数据 ==================== + @Schema(description = "浏览次数") + private Integer clicks; + + @Schema(description = "安装次数") + private Integer installs; + + @Schema(description = "下载次数") + private Integer downloads; + + @Schema(description = "评分(1-5)") + private BigDecimal rating; + + @Schema(description = "点赞数") + private Integer likes; + + // ==================== 开发者信息 ==================== + @Schema(description = "开发者") + private String developer; + + @Schema(description = "开发者电话") + private String developerPhone; + + @Schema(description = "开发者邮箱") + private String developerEmail; + + // ==================== 运营配置 ==================== + @Schema(description = "是否推荐: 0否 1是") + private Integer recommend; + + @Schema(description = "是否官方: 0否 1是") + private Integer official; + + @Schema(description = "是否上架市场: 0否 1是") + private Integer market; + + @Schema(description = "是否显示首页: 0否 1是") + private Integer showIndex; + + @Schema(description = "是否可搜索: 0否 1是") + private Integer searchEnabled; + + // ==================== 站点配置 ==================== + @Schema(description = "模板ID") + private Integer templateId; + + @Schema(description = "样式配置JSON") + private String style; + + @Schema(description = "扩展配置JSON") + private String config; + + @Schema(description = "主题色") + private String themeColor; + + @Schema(description = "语言") + private String lang; + + // ==================== 备案信息 ==================== + @Schema(description = "ICP备案号") + private String icpNo; + + @Schema(description = "公安备案号") + private String policeNo; + + // ==================== 状态管理 ==================== + @Schema(description = "状态: 0未开通 1运行中 2维护中 3已关闭 4已欠费 5违规停机") + private Integer status; + + @Schema(description = "状态说明") + private String statusText; + + @Schema(description = "运行状态: 0停止 1运行中 2维护中") + private Integer running; + + @Schema(description = "是否到期") + @TableField(exist = false) + private Integer expired; + + @Schema(description = "剩余天数") + @TableField(exist = false) + private Long expiredDays; + + @Schema(description = "即将过期") + @TableField(exist = false) + private Integer soon; + + @Schema(description = "到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date expirationTime; + + // ==================== 系统字段 ==================== + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除: 0否 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建用户ID") + private Integer userId; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + // ==================== 非数据库字段 ==================== + + @Schema(description = "当前用户在该应用中的角色(仅 accessible 查询返回)") + @TableField(exist = false) + private String myRole; + + // ==================== 应用类型常量 ==================== + public static final int APP_TYPE_WEBSITE = 10; // 网站 + public static final int APP_TYPE_WX_MINI = 20; // 微信小程序 + public static final int APP_TYPE_DOUYIN_MINI = 30; // 抖音小程序 + public static final int APP_TYPE_BAIDU_MINI = 40; // 百度小程序 + public static final int APP_TYPE_ALIPAY_MINI = 50; // 支付宝小程序 + public static final int APP_TYPE_ANDROID = 60; // Android APP + public static final int APP_TYPE_IOS = 70; // iOS APP + public static final int APP_TYPE_MACOS = 80; // macOS 应用 + public static final int APP_TYPE_WINDOWS = 90; // Windows 应用 + public static final int APP_TYPE_PLUGIN = 100; // 插件 + + // ==================== 发布状态常量 ==================== + public static final String PUBLISH_DEVELOPING = "developing"; // 开发中 + public static final String PUBLISH_PENDING_REVIEW = "pending_review"; // 待审核 + public static final String PUBLISH_PUBLISHED = "published"; // 已上架 + public static final String PUBLISH_REJECTED = "rejected"; // 审核未通过 + public static final String PUBLISH_DEPRECATED = "deprecated"; // 已下架 + + // ==================== 价格类型常量 ==================== + public static final String PRICE_FREE = "free"; // 免费 + public static final String PRICE_ONE_TIME = "one_time"; // 一次性 + public static final String PRICE_SUBSCRIPTION = "subscription"; // 订阅 + + // ==================== 版本常量 ==================== + public static final String EDITION_STANDARD = "standard"; // 标准版 + public static final String EDITION_PROFESSIONAL = "professional"; // 专业版 + public static final String EDITION_PERPETUAL = "perpetual"; // 永久授权 + + /** + * 获取应用类型名称 + */ + public String getAppTypeName() { + if (appType == null) return "未知"; + switch (appType) { + case APP_TYPE_WEBSITE: return "网站"; + case APP_TYPE_WX_MINI: return "微信小程序"; + case APP_TYPE_DOUYIN_MINI: return "抖音小程序"; + case APP_TYPE_BAIDU_MINI: return "百度小程序"; + case APP_TYPE_ALIPAY_MINI: return "支付宝小程序"; + case APP_TYPE_ANDROID: return "Android APP"; + case APP_TYPE_IOS: return "iOS APP"; + case APP_TYPE_MACOS: return "macOS 应用"; + case APP_TYPE_WINDOWS: return "Windows 应用"; + case APP_TYPE_PLUGIN: return "插件"; + default: return "未知"; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppResource.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppResource.java new file mode 100644 index 0000000..e4df609 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppResource.java @@ -0,0 +1,208 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 开发者资源(服务器/数据库/云存储/域名/SSL证书) + * + * @author 科技小王子 + * @since 2026-03-31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_resource") +@Schema(name = "AppResource对象", description = "开发者资源") +public class AppResource implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "资源ID") + @TableId(value = "resource_id", type = IdType.AUTO) + private Long resourceId; + + @Schema(description = "资源类型: server/database/storage/domain/ssl") + private String resourceType; + + @Schema(description = "资源名称") + private String name; + + @Schema(description = "服务商: tencent/aliyun/huawei/other") + private String provider; + + @Schema(description = "关联应用ID(可选)") + private Long appId; + + @Schema(description = "关联应用名称(冗余)") + @TableField(exist = false) + private String appName; + + // ─── 服务器字段 ─────────────────────────────────────── + @Schema(description = "IP地址(服务器用)") + private String ip; + + @Schema(description = "SSH端口(服务器用,默认22)") + private Integer sshPort; + + @Schema(description = "SSH用户名(服务器用,用于远程执行命令)") + private String sshUsername; + + @Schema(description = "SSH密码(AES加密,服务器用,用于远程执行命令)") + private String sshPassword; + + @Schema(description = "MySQL端口(服务器用,默认3306)") + private Integer mysqlPort; + + @Schema(description = "PostgreSQL端口(服务器用,默认5432)") + private Integer pgPort; + + @Schema(description = "1Panel面板端口(服务器用,默认8888)") + private Integer panelPort; + + @Schema(description = "1Panel面板用户名(服务器用)") + private String panelUsername; + + @Schema(description = "1Panel面板密码(AES加密,服务器用)") + private String panelPassword; + + @Schema(description = "1Panel面板路径前缀(服务器用,如 /abc123)") + private String panelPath; + + @Schema(description = "MySQL管理员用户名(服务器用,用于远程建库)") + private String adminUsername; + + @Schema(description = "MySQL管理员密码(AES加密,服务器用,用于远程建库)") + private String adminPassword; + + // ─── 数据库字段 ─────────────────────────────────────── + @Schema(description = "数据库类型: MySQL/PostgreSQL/Redis/MongoDB(数据库用)") + private String dbType; + + @Schema(description = "关联服务器资源ID(数据库用)") + private Long serverResourceId; + + @Schema(description = "连接主机地址(数据库用)") + private String host; + + @Schema(description = "数据库连接端口(根据dbType从服务器资源获取,前端显示用)") + private Integer port; + + @Schema(description = "数据库用户名(数据库用)") + private String dbUsername; + + @Schema(description = "数据库密码(数据库用)") + private String dbPassword; + + // ─── 云存储字段 ─────────────────────────────────────── + @Schema(description = "地区/Region(云存储用)") + private String region; + + @Schema(description = "云账号凭证ID(云存储用,关联app_cloud_credential)") + private Long credentialId; + + @Schema(description = "访问权限: public-read/private(云存储用)") + private String acl; + + @Schema(description = "已用空间(字节,云存储用)") + private Long usedBytes; + + @Schema(description = "对象数量(云存储用)") + private Integer usedCount; + + // ─── 域名字段 ───────────────────────────────────────── + @Schema(description = "域名(域名用)") + private String domain; + + @Schema(description = "注册商(域名用)") + private String registrar; + + @Schema(description = "是否已备案(域名用)") + private Boolean icp; + + @Schema(description = "ICP备案号(域名用)") + private String icpNo; + + @Schema(description = "是否已绑定SSL(域名用,冗余)") + private Boolean sslBound; + + // ─── SSL证书字段 ────────────────────────────────────── + @Schema(description = "证书类型: DV/OV/EV(SSL用)") + private String certType; + + @Schema(description = "颁发机构(SSL用)") + private String issuer; + + @Schema(description = "私钥(SSL用,AES加密存储)") + private String privateKey; + + @Schema(description = "公钥(SSL用)") + private String publicKey; + + @Schema(description = "证书内容/证书文件(SSL用)") + private String certificate; + + @Schema(description = "证书链(SSL用,中间证书)") + private String certChain; + + // ─── Git仓库字段 ─────────────────────────────────────── + @Schema(description = "Git仓库路径(git用,如: websopy/core)") + private String gitPath; + + @Schema(description = "Git Clone URL(git用)") + private String gitCloneUrl; + + @Schema(description = "Git Web访问URL(git用,Gitea页面地址)") + private String gitWebUrl; + + @Schema(description = "Git权限级别: read/write/admin(git用)") + private String gitAccessLevel; + + // ─── 通用字段 ───────────────────────────────────────── + @Schema(description = "状态: running/stopped/expired/pending") + private String status; + + @Schema(description = "到期时间") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate expireAt; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "所属用户ID") + private Integer userId; + + @Schema(description = "资源创建者userId(权限控制基准,创建时自动设置)") + private Long ownerUserId; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "是否删除: 0否 1是") + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + // ─── 协作权限(非持久化,由后端查询时计算) ──────────────────── + @TableField(exist = false) + @Schema(description = "当前用户对此资源的访问级别: 0=无权限 1=基础查看 2=连接查看 3=完全权限(Owner)") + private Integer accessLevel; + + @TableField(exist = false) + @Schema(description = "当前用户是否为资源Owner") + private Boolean isOwner; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppSetting.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppSetting.java new file mode 100644 index 0000000..e613566 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppSetting.java @@ -0,0 +1,92 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 平台设置表 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_setting") +public class AppSetting implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 设置ID + */ + @TableId(value = "setting_id", type = IdType.AUTO) + private Integer settingId; + + /** + * 设置分类:basic/review/market/register/notify/maintenance + */ + private String category; + + /** + * 设置项标识 + */ + private String settingKey; + + /** + * 设置项名称 + */ + private String settingName; + + /** + * 设置值(JSON格式) + */ + private String settingValue; + + /** + * 设置类型:string/number/boolean/json + */ + private String valueType; + + /** + * 设置说明 + */ + private String description; + + /** + * 排序号 + */ + private Integer sortNumber; + + /** + * 是否启用 0否 1是 + */ + private Integer isEnabled; + + /** + * 是否公开(前端可读)0否 1是 + */ + private Integer isPublic; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Long createdTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updatedTime; + + /** + * 是否删除 0否 1是 + */ + @TableLogic + private Integer deleted; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppSubscription.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppSubscription.java new file mode 100644 index 0000000..151c615 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppSubscription.java @@ -0,0 +1,116 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 应用订阅实体 + * 对应表:app_subscription + */ +@Data +@TableName("app_subscription") +public class AppSubscription { + + @TableId(type = IdType.AUTO) + private Long id; + + /** 订阅编号(业务唯一) */ + private String subscriptionNo; + + /** 购买用户ID */ + private Integer userId; + + /** 应用产品ID */ + private Integer productId; + + /** 租户ID */ + private Integer tenantId; + + /** 订阅状态: pending/active/expired/cancelled */ + private String status; + + /** 价格类型: free/one_time/subscription */ + private String priceType; + + /** 原价(单位:元) */ + private BigDecimal originalPrice; + + /** 实付金额(单位:元) */ + private BigDecimal payPrice; + + /** 支付方式: 0-余额, 1-微信, 2-支付宝, 12-免费 */ + private Integer payType; + + /** 支付状态: 0-未支付, 1-已支付 */ + private Integer payStatus; + + /** 支付时间 */ + private LocalDateTime payTime; + + /** 第三方交易号 */ + private String transactionId; + + /** 订阅周期: month/year */ + private String subscriptionPeriod; + + /** 生效时间 */ + private LocalDateTime startTime; + + /** 到期时间(订阅型) */ + private LocalDateTime expireTime; + + /** 是否自动续费 0-否 1-是 */ + private Integer autoRenew; + + /** 分配的域名 */ + private String instanceDomain; + + /** 实例管理后台URL */ + private String instanceAdminUrl; + + /** 实例配置(JSON) */ + private String instanceConfig; + + /** 关联的支付订单号 */ + private String orderNo; + + /** 关联的支付订单ID */ + private Long orderId; + + /** 备注 */ + private String remark; + + @TableLogic + private Integer deleted; + + private Integer sortNumber; + + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + // ===== 关联查询字段(非数据库字段) ===== + + @TableField(exist = false) + private String productName; + + @TableField(exist = false) + private String productIcon; + + @TableField(exist = false) + private String productLogo; + + @TableField(exist = false) + private Integer productAppType; + + @TableField(exist = false) + private String productDescription; + + @TableField(exist = false) + private String developerName; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppTicket.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppTicket.java new file mode 100644 index 0000000..faf9a06 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppTicket.java @@ -0,0 +1,104 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.gxwebsoft.common.core.config.JsonArrayToStringDeserializer; +import com.gxwebsoft.common.core.config.JsonStringToArraySerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用工单 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_ticket") +@Schema(name = "AppTicket对象", description = "应用工单") +public class AppTicket implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "工单ID") + @TableId(value = "ticket_id", type = IdType.AUTO) + private Long ticketId; + + @Schema(description = "工单编号(TK-yyyyMMddHHmmss+4位随机)") + private String ticketNo; + + @Schema(description = "工单标题") + private String title; + + @Schema(description = "工单内容描述") + private String content; + + @Schema(description = "关联应用ID") + @com.fasterxml.jackson.annotation.JsonProperty("productId") + private Long appId; + + @Schema(description = "应用名称(冗余)") + private String appName; + + @Schema(description = "工单分类: bug/feature/consultation/complaint/other") + private String category; + + @Schema(description = "优先级: low/normal/high/urgent") + private String priority; + + @Schema(description = "状态: pending/assigned/processing/resolved/closed/rejected") + private String status; + + @Schema(description = "附件JSON数组") + @JsonDeserialize(using = JsonArrayToStringDeserializer.class) + @JsonSerialize(using = JsonStringToArraySerializer.class) + private String attachments; + + @Schema(description = "提交人用户ID") + private Integer submitUserId; + + @Schema(description = "提交人昵称(冗余)") + private String submitUserName; + + @Schema(description = "提交人头像(冗余)") + private String submitUserAvatar; + + @Schema(description = "分配的处理人用户ID") + private Integer assigneeId; + + @Schema(description = "处理人昵称(冗余)") + private String assigneeName; + + @Schema(description = "处理人头像(冗余)") + private String assigneeAvatar; + + @Schema(description = "回复数量") + private Integer replyCount; + + @Schema(description = "解决时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime resolvedTime; + + @Schema(description = "关闭时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime closedTime; + + @Schema(description = "是否删除: 0否 1是") + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppTicketReply.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppTicketReply.java new file mode 100644 index 0000000..2633d94 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppTicketReply.java @@ -0,0 +1,64 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.gxwebsoft.common.core.config.JsonArrayToStringDeserializer; +import com.gxwebsoft.common.core.config.JsonStringToArraySerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 工单回复 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_ticket_reply") +@Schema(name = "AppTicketReply对象", description = "工单回复") +public class AppTicketReply implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "回复ID") + @TableId(value = "reply_id", type = IdType.AUTO) + private Long replyId; + + @Schema(description = "关联工单ID") + private Long ticketId; + + @Schema(description = "回复内容") + private String content; + + @Schema(description = "附件JSON数组") + @JsonDeserialize(using = JsonArrayToStringDeserializer.class) + @JsonSerialize(using = JsonStringToArraySerializer.class) + private String attachments; + + @Schema(description = "回复人用户ID") + private Integer userId; + + @Schema(description = "回复人昵称(冗余)") + private String userName; + + @Schema(description = "回复人头像(冗余)") + private String userAvatar; + + @Schema(description = "是否是技术人员/客服: 0否 1是") + private Integer isStaff; + + @Schema(description = "是否删除: 0否 1是") + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppUser.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppUser.java new file mode 100644 index 0000000..a3be55a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppUser.java @@ -0,0 +1,98 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用成员 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppUser对象", description = "应用成员") +public class AppUser implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "关联应用ID") + private Long appId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "用户名(冗余)") + @TableField(exist = false) + private String username; + + @Schema(description = "昵称(冗余)") + @TableField(exist = false) + private String nickname; + + @Schema(description = "头像(冗余)") + @TableField(exist = false) + private String avatar; + + @Schema(description = "手机号(冗余,脱敏存储)") + @TableField(exist = false) + private String phone; + + @Schema(description = "角色: owner/admin/developer/viewer") + private String role; + + @Schema(description = "邀请人用户ID") + private Long inviteBy; + + @Schema(description = "加入时间") + private LocalDateTime inviteTime; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "邀请状态: 0-正常(直接加入), 1-待确认, 2-已拒绝") + private Integer inviteStatus; + + @Schema(description = "邀请过期时间") + private LocalDateTime inviteExpireTime; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + // ========== 关联字段(非数据库字段)========== + + @Schema(description = "应用名称(关联app_product)") + @TableField(exist = false) + private String productName; + + @Schema(description = "应用图标(关联app_product)") + @TableField(exist = false) + private String icon; + + @Schema(description = "应用编码(关联app_product)") + @TableField(exist = false) + private String productCode; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppUserCache.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppUserCache.java new file mode 100644 index 0000000..befc7ea --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppUserCache.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.app.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 用户信息缓存表 + * 用于缓存 sys_user 的常用字段,方便 app 模块其他表关联查询用户信息 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@TableName("app_user_cache") +@Schema(name = "AppUserCache对象", description = "用户信息缓存") +public class AppUserCache implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户ID(主键)") + @TableId(value = "user_id", type = IdType.INPUT) + private Integer userId; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "手机号(脱敏存储)") + private String phone; + + @Schema(description = "用户状态,0正常,1冻结") + private Integer status; + + @Schema(description = "缓存更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "租户ID") + private Integer tenantId; + + /** + * 获取脱敏手机号 + */ + public String getMobile() { + return DesensitizedUtil.mobilePhone(this.phone); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppVersion.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppVersion.java new file mode 100644 index 0000000..5120799 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/AppVersion.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用版本发布记录 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppVersion对象", description = "应用版本发布记录") +public class AppVersion implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "关联应用ID") + private Long appId; + + @Schema(description = "版本号,如 1.0.0") + private String versionNo; + + @Schema(description = "版本名称") + private String versionName; + + @Schema(description = "版本更新说明") + private String changelog; + + @Schema(description = "安装包地址") + private String packageUrl; + + @Schema(description = "包大小(字节)") + private Long packageSize; + + @Schema(description = "包MD5/SHA256") + private String packageHash; + + @Schema(description = "环境: development/staging/production") + private String env; + + @Schema(description = "状态 0=构建中 1=已发布 2=已回滚 3=构建失败") + private Integer status; + + @Schema(description = "是否为当前版本") + private Boolean isCurrent; + + @Schema(description = "发布人用户ID") + private Long publishBy; + + @Schema(description = "发布时间") + private LocalDateTime publishTime; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/entity/ResourceAccessLevel.java b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/ResourceAccessLevel.java new file mode 100644 index 0000000..423bcd8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/entity/ResourceAccessLevel.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.app.entity; + +/** + * 资源访问级别枚举 + * + *

+ * 0 - 无权限:不是应用团队成员
+ * 1 - 基础查看:所有团队成员,可看名称/IP/端口/状态
+ * 2 - 连接查看:admin/owner 角色,额外可看用户名/Host/连接方式
+ * 3 - 完全权限:资源创建者(Owner),可看密码/私钥,可编辑/删除
+ * 
+ * + * @author 科技小王子 + * @since 2026-04-05 + */ +public enum ResourceAccessLevel { + + NONE(0), + VIEW_BASIC(1), + VIEW_CONNECTION(2), + FULL(3); + + private final int value; + + ResourceAccessLevel(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + /** + * 当前级别是否大于等于指定级别 + */ + public boolean atLeast(ResourceAccessLevel level) { + return this.value >= level.value; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppApiKeyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppApiKeyMapper.java new file mode 100644 index 0000000..68a71e8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppApiKeyMapper.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gxwebsoft.app.entity.AppApiKey; +import com.gxwebsoft.app.param.AppApiKeyParam; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * 应用 API Key Mapper + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Mapper +public interface AppApiKeyMapper extends BaseMapper { + + /** + * 分页查询(关联查询) + */ + IPage selectPageRel(Page page, @Param("param") AppApiKeyParam param); + + /** + * 查询列表(关联查询) + */ + java.util.List selectListRel(@Param("param") AppApiKeyParam param); + + /** + * 根据ID查询详情(关联查询) + */ + AppApiKey selectByIdRel(@Param("id") Long id); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppArticleCategoryMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppArticleCategoryMapper.java new file mode 100644 index 0000000..2f60fc2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppArticleCategoryMapper.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppArticleCategory; + +/** + * 平台文章分类 Mapper + */ +public interface AppArticleCategoryMapper extends BaseMapper { +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppArticleMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppArticleMapper.java new file mode 100644 index 0000000..0f9c22e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppArticleMapper.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppArticle; + +/** + * 平台文章 Mapper + */ +public interface AppArticleMapper extends BaseMapper { +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppBuildMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppBuildMapper.java new file mode 100644 index 0000000..c892972 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppBuildMapper.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppBuild; +import com.gxwebsoft.app.param.AppBuildParam; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * CI/CD 构建记录 Mapper + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Mapper +public interface AppBuildMapper extends BaseMapper { + + /** + * 查询构建列表(关联应用信息) + */ + List selectBuildList(@Param("param") AppBuildParam param); + + /** + * 查询构建详情(关联应用信息) + */ + AppBuild selectBuildDetail(@Param("id") Long id); + + /** + * 查询应用最新构建 + */ + AppBuild selectLatestBuild(@Param("appId") Long appId); + + /** + * 查询应用构建统计 + */ + Integer countBuildsByStatus(@Param("appId") Long appId, @Param("status") String status); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppCloudCredentialMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppCloudCredentialMapper.java new file mode 100644 index 0000000..5dbfc65 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppCloudCredentialMapper.java @@ -0,0 +1,28 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppCloudCredential; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 云账号凭证 Mapper + * + * @author 科技小王子 + * @since 2026-04-04 + */ +public interface AppCloudCredentialMapper extends BaseMapper { + + /** + * 分页查询 + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AppCloudCredential param); + + /** + * 查询列表 + */ + List selectListRel(@Param("param") AppCloudCredential param); +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppConfigMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppConfigMapper.java new file mode 100644 index 0000000..9206978 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppConfigMapper.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppConfig; +import com.gxwebsoft.app.param.AppConfigParam; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 应用配置表 Mapper + * + * @author 科技小王子 + */ +@Mapper +public interface AppConfigMapper extends BaseMapper { + + /** + * 批量获取应用配置 + */ + List> selectConfigsByAppId(Integer appId); + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AppConfigParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") AppConfigParam param); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppContractMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppContractMapper.java new file mode 100644 index 0000000..75880da --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppContractMapper.java @@ -0,0 +1,22 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppContract; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + * 合同管理 Mapper + * + * @author 科技小王子 + * @since 2026-04-13 + */ +public interface AppContractMapper extends BaseMapper { + + /** + * 查询当天最大合同序号 + */ + @Select("SELECT COALESCE(MAX(SUBSTRING_INDEX(contract_no, '-', -1) + 0), 0) " + + "FROM app_contract WHERE contract_no LIKE CONCAT('HT-', #{datePart}, '-%')") + Integer selectMaxSeqForDate(@Param("datePart") String datePart); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppCredentialMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppCredentialMapper.java new file mode 100644 index 0000000..4ab3599 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppCredentialMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppCredential; +import com.gxwebsoft.app.param.AppCredentialParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用密钥凭证Mapper + * + * @author 科技小王子 + * @since 2026-03-28 21:29:43 + */ +public interface AppCredentialMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AppCredentialParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") AppCredentialParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppEventMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppEventMapper.java new file mode 100644 index 0000000..c1fe3ca --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppEventMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppEvent; +import com.gxwebsoft.app.param.AppEventParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用操作动态Mapper + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +public interface AppEventMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AppEventParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") AppEventParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppGitAccountMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppGitAccountMapper.java new file mode 100644 index 0000000..40e969a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppGitAccountMapper.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppGitAccount; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * Git账号绑定 Mapper + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Mapper +public interface AppGitAccountMapper extends BaseMapper { + + /** + * 根据用户ID查询 + */ + AppGitAccount selectByUserId(@Param("userId") Integer userId); + + /** + * 根据用户名查询(检查唯一性) + */ + AppGitAccount selectByUsername(@Param("username") String username); + + /** + * 检查用户名是否被其他用户绑定(同一租户下) + */ + AppGitAccount checkUsernameOccupied(@Param("username") String username, @Param("excludeUserId") Integer excludeUserId, @Param("tenantId") Integer tenantId); + + /** + * 根据用户ID和租户ID查询 + */ + AppGitAccount selectByUserIdAndTenantId(@Param("userId") Integer userId, @Param("tenantId") Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppInviteTokenMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppInviteTokenMapper.java new file mode 100644 index 0000000..1409346 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppInviteTokenMapper.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppInviteToken; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + * 应用邀请Token Mapper + */ +public interface AppInviteTokenMapper extends BaseMapper { + + /** + * 根据token查询 + */ + @Select("SELECT * FROM app_invite_token WHERE token = #{token} LIMIT 1") + AppInviteToken selectByToken(@Param("token") String token); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppNotificationMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppNotificationMapper.java new file mode 100644 index 0000000..e3423c2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppNotificationMapper.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppNotification; + +/** + * 站内消息通知 Mapper + */ +public interface AppNotificationMapper extends BaseMapper { +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppPermissionRequestMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppPermissionRequestMapper.java new file mode 100644 index 0000000..2cfef40 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppPermissionRequestMapper.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppPermissionRequest; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 权限申请Mapper + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Mapper +public interface AppPermissionRequestMapper extends BaseMapper { + + /** + * 获取用户已可访问的仓库列表 + */ + List getAccessibleRepos(@Param("userId") Integer userId); + + /** + * 获取所有可用仓库列表(含访问状态) + */ + List> getAllReposWithAccessStatus(@Param("userId") Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppPipelineMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppPipelineMapper.java new file mode 100644 index 0000000..03426cf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppPipelineMapper.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppPipeline; +import com.gxwebsoft.app.param.AppPipelineParam; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * CI/CD 流水线配置 Mapper + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Mapper +public interface AppPipelineMapper extends BaseMapper { + + /** + * 查询流水线列表 + */ + List selectPipelineList(@Param("param") AppPipelineParam param); + + /** + * 查询流水线详情 + */ + AppPipeline selectPipelineDetail(@Param("id") Long id); + + /** + * 查询应用的所有流水线 + */ + List selectByAppId(@Param("appId") Long appId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppProductMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppProductMapper.java new file mode 100644 index 0000000..5869fac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppProductMapper.java @@ -0,0 +1,88 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gxwebsoft.app.entity.AppProduct; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 应用产品 Mapper 接口 + * + * @author 科技小王子 + */ +@Mapper +public interface AppProductMapper extends BaseMapper { + + /** + * 分页查询应用列表 + * @param userId 用户ID(可选,为空则查所有) + */ + IPage selectPageList(Page page, @Param("ew") AppProduct product, @Param("userId") Integer userId); + + /** + * 查询用户的应用列表(创建者) + */ + List selectByUserId(@Param("userId") Integer userId); + + /** + * 分页查询用户创建的应用 + */ + IPage selectPageByUserId(Page page, @Param("userId") Integer userId); + + /** + * 分页查询用户参与的应用 + */ + IPage selectPageJoinedApps(Page page, @Param("userId") Integer userId); + + /** + * 根据应用标识查询 + */ + AppProduct selectByCode(@Param("code") String code); + + /** + * 更新发布状态 + */ + int updatePublishStatus(@Param("productId") Integer productId, @Param("status") String status); + + /** + * 增加浏览次数 + */ + int incrementClicks(@Param("productId") Integer productId); + + /** + * 增加安装次数 + */ + int incrementInstalls(@Param("productId") Integer productId); + + /** + * 增加下载次数 + */ + int incrementDownloads(@Param("productId") Integer productId); + + /** + * 增加点赞数 + */ + int incrementLikes(@Param("productId") Integer productId); + + /** + * 按用户ID列表批量统计应用数量 + * + * @param userIds 用户ID列表 + * @return 统计结果列表,每项包含 userId, totalCount, publishedCount + */ + List selectStatsByUserIds(@Param("userIds") List userIds); + + /** + * 查询用户可访问的应用列表(带 myRole 字段) + * 包含:用户创建的应用(owner)+ 被邀请加入的应用(成员角色) + * + * @param userId 用户ID + * @return 应用列表(带 myRole 字段) + */ + List selectAccessibleApps(@Param("userId") Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppResourceMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppResourceMapper.java new file mode 100644 index 0000000..edca6de --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppResourceMapper.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.param.AppResourceParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 开发者资源 Mapper + * + * @author 科技小王子 + * @since 2026-03-31 + */ +public interface AppResourceMapper extends BaseMapper { + + /** + * 分页查询(关联应用名称) + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AppResourceParam param); + + /** + * 查询全部列表(关联应用名称) + */ + List selectListRel(@Param("param") AppResourceParam param); + + /** + * 根据用户查询有权限的资源(包括协作资源) + * 查询条件:owner_user_id = #{userId} OR app_id IN (用户有权限的应用ID列表) + */ + List selectListByUserAccess(@Param("param") AppResourceParam param, + @Param("userAppIds") List userAppIds); + + /** + * 统计各类型资源数量(仅个人资源),返回 [{resourceType, cnt}] + */ + List> countByType(@Param("userId") Integer userId, + @Param("tenantId") Integer tenantId); + + /** + * 统计各类型资源数量(包含协作者有权限的资源) + */ + List> countByTypeForUser(@Param("userId") Integer userId, + @Param("tenantId") Integer tenantId, + @Param("userAppIds") List userAppIds); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppSettingMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppSettingMapper.java new file mode 100644 index 0000000..9f00b35 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppSettingMapper.java @@ -0,0 +1,27 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppSetting; +import com.gxwebsoft.app.param.AppSettingParam; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 平台设置表 Mapper + */ +@Mapper +public interface AppSettingMapper extends BaseMapper { + + /** + * 分页查询 + */ + IPage selectPageRel(IPage page, @Param("param") AppSettingParam param); + + /** + * 查询列表 + */ + List selectListRel(@Param("param") AppSettingParam param); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppSubscriptionMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppSubscriptionMapper.java new file mode 100644 index 0000000..5bc684e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppSubscriptionMapper.java @@ -0,0 +1,9 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppSubscription; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface AppSubscriptionMapper extends BaseMapper { +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppTicketMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppTicketMapper.java new file mode 100644 index 0000000..c8e3b27 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppTicketMapper.java @@ -0,0 +1,19 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppTicket; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + * 应用工单 Mapper + */ +public interface AppTicketMapper extends BaseMapper { + + /** + * 查询当天最大序号(ticket_no 格式:TK-YYMMDD-XXXX) + */ + @Select("SELECT COALESCE(MAX(SUBSTRING(ticket_no, 13, 4) + 0), 0) " + + "FROM app_ticket WHERE ticket_no LIKE CONCAT('TK-', #{datePart}, '-%')") + Integer selectMaxSeqForDate(@Param("datePart") String datePart); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppTicketReplyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppTicketReplyMapper.java new file mode 100644 index 0000000..3fc0a16 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppTicketReplyMapper.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppTicketReply; + +/** + * 工单回复 Mapper + */ +public interface AppTicketReplyMapper extends BaseMapper { +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppUserCacheMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppUserCacheMapper.java new file mode 100644 index 0000000..14a3be0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppUserCacheMapper.java @@ -0,0 +1,15 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.app.entity.AppUserCache; +import org.apache.ibatis.annotations.Mapper; + +/** + * 用户缓存 Mapper + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Mapper +public interface AppUserCacheMapper extends BaseMapper { +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppUserMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppUserMapper.java new file mode 100644 index 0000000..af330b3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppUserMapper.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.param.AppUserParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用成员Mapper + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +public interface AppUserMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AppUserParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") AppUserParam param); + + /** + * 查询用户参与的应用列表(含角色信息),用于 check-access 和 accessible 接口 + * 返回:appId, productName, productCode, icon, role, isOwner + * + * @param userId 用户ID + * @return 用户参与的应用及角色信息列表 + */ + List> selectUserAccessibleApps(@Param("userId") Integer userId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppVersionMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppVersionMapper.java new file mode 100644 index 0000000..187b1a6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/AppVersionMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.app.entity.AppVersion; +import com.gxwebsoft.app.param.AppVersionParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用版本发布记录Mapper + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +public interface AppVersionMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AppVersionParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") AppVersionParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/SysUserCrossDbMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/SysUserCrossDbMapper.java new file mode 100644 index 0000000..c9a6e59 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/SysUserCrossDbMapper.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.app.mapper; + +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 跨库查询 Mapper + * 用于从 gxwebsoft_core 库查询 sys_user 表 + */ +@Mapper +public interface SysUserCrossDbMapper { + + /** + * 根据手机号查询用户 + */ + @Select("SELECT user_id AS userId, username, nickname, avatar, phone, email, status, tenant_id AS tenantId, balance " + + "FROM gxwebsoft_core.sys_user WHERE phone = #{phone} AND deleted = 0 LIMIT 1") + User selectByPhone(@Param("phone") String phone); + + /** + * 根据用户ID查询用户 + */ + @Select("SELECT user_id AS userId, username, nickname, avatar, phone, email, status, tenant_id AS tenantId, balance " + + "FROM gxwebsoft_core.sys_user WHERE user_id = #{userId} AND deleted = 0 LIMIT 1") + User selectByUserId(@Param("userId") Integer userId); + + /** + * 搜索用户(按手机号、用户名、昵称模糊搜索) + */ + @Select("") + List searchUsers(@Param("keyword") String keyword); + + /** + * 查询用户类型(type字段:0普通用户 1企业用户 2开发者用户) + */ + @Select("SELECT type FROM gxwebsoft_core.sys_user WHERE user_id = #{userId} AND deleted = 0 LIMIT 1") + Integer selectUserType(@Param("userId") Integer userId); + + /** + * 更新用户余额(跨库更新 gxwebsoft_core.sys_user) + */ + @Update("UPDATE gxwebsoft_core.sys_user SET balance = #{balance} WHERE user_id = #{userId} AND deleted = 0") + int updateBalance(@Param("userId") Integer userId, @Param("balance") BigDecimal balance); + + /** + * 根据用户ID更新(跨库更新 gxwebsoft_core.sys_user) + */ + @Update("") + int updateByUserId(@Param("userId") Integer userId, @Param("balance") BigDecimal balance); + + /** + * 插入余额日志(跨库插入 gxwebsoft_core.sys_user_balance_log) + */ + @Insert("INSERT INTO gxwebsoft_core.sys_user_balance_log " + + "(user_id, scene, money, balance, order_no, comments, tenant_id, create_time) " + + "VALUES (#{userId}, #{scene}, #{money}, #{balance}, #{orderNo}, #{comments}, #{tenantId}, NOW())") + int insertBalanceLog(@Param("userId") Integer userId, + @Param("scene") Integer scene, + @Param("money") BigDecimal money, + @Param("balance") BigDecimal balance, + @Param("orderNo") String orderNo, + @Param("comments") String comments, + @Param("tenantId") Integer tenantId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppApiKeyMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppApiKeyMapper.xml new file mode 100644 index 0000000..b952f23 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppApiKeyMapper.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + id, name, api_key, key_prefix, status, scopes, expire_time, + last_used_at, usage_count, remark, deleted, user_id, tenant_id, + create_time, update_time + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppBuildMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppBuildMapper.xml new file mode 100644 index 0000000..9e36912 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppBuildMapper.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, app_id, version_id, build_number, name, branch, commit_sha, commit_message, + commit_author, ci_type, ci_job_id, ci_run_id, ci_api_url, status, started_at, + finished_at, duration, log_url, artifact_url, artifact_name, artifact_size, + error_message, trigger_type, triggered_by, config, user_id, tenant_id, + create_time, update_time + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppCloudCredentialMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppCloudCredentialMapper.xml new file mode 100644 index 0000000..1d88666 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppCloudCredentialMapper.xml @@ -0,0 +1,49 @@ + + + + + + + SELECT a.* + FROM app_cloud_credential a + + + AND a.id = #{param.id} + + + AND a.provider = #{param.provider} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.user_id = #{param.userId} + + + AND a.tenant_id = #{param.tenantId} + + + + + + + + + + + \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppConfigMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppConfigMapper.xml new file mode 100644 index 0000000..b0a12b3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppConfigMapper.xml @@ -0,0 +1,66 @@ + + + + + + + SELECT a.* + FROM app_config a + + a.deleted = 0 + + AND a.config_id = #{param.configId} + + + AND a.app_id = #{param.appId} + + + AND a.config_key LIKE CONCAT('%', #{param.configKey}, '%') + + + AND a.config_type = #{param.configType} + + + AND a.is_secret = #{param.isSecret} + + + AND a.tenant_id = #{param.tenantId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.config_key LIKE CONCAT('%', #{param.keywords}, '%') + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppCredentialMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppCredentialMapper.xml new file mode 100644 index 0000000..b0a1a25 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppCredentialMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.*, w.product_name, w.product_code, w.icon + FROM app_credential a + LEFT JOIN app_product w ON a.app_id = w.product_id AND w.deleted = 0 + + + AND a.id = #{param.id} + + + AND a.app_id = #{param.appId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.client_id = #{param.clientId} + + + AND a.type = #{param.type} + + + AND a.scopes LIKE CONCAT('%', #{param.scopes}, '%') + + + AND a.remark LIKE CONCAT('%', #{param.remark}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.client_id LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppEventMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppEventMapper.xml new file mode 100644 index 0000000..e544bf3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppEventMapper.xml @@ -0,0 +1,66 @@ + + + + + + + SELECT a.*, w.product_name, w.product_code, w.icon + FROM app_event a + LEFT JOIN app_product w ON a.app_id = w.product_id AND w.deleted = 0 + + + AND a.id = #{param.id} + + + AND a.app_id = #{param.appId} + + + AND a.event_type = #{param.eventType} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.operator_id = #{param.operatorId} + + + AND a.ref_id = #{param.refId} + + + AND a.ref_type = #{param.refType} + + + AND a.status = #{param.status} + + + AND a.user_id = #{param.userId} + + + AND a.tenant_id = #{param.tenantId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.title LIKE CONCAT('%', #{param.keywords}, '%') + OR a.content LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + ORDER BY a.create_time DESC + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppGitAccountMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppGitAccountMapper.xml new file mode 100644 index 0000000..17f40ec --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppGitAccountMapper.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppPermissionRequestMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppPermissionRequestMapper.xml new file mode 100644 index 0000000..4e3b4ce --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppPermissionRequestMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppPipelineMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppPipelineMapper.xml new file mode 100644 index 0000000..460842d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppPipelineMapper.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, app_id, name, description, ci_type, repo_full_name, workflow_file, stages, + env, default_branch, enabled, auto_deploy, timeout, config, last_build_id, + last_build_status, last_build_time, success_count, failure_count, user_id, + tenant_id, create_time, update_time + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppProductMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppProductMapper.xml new file mode 100644 index 0000000..f7a584e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppProductMapper.xml @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE app_product + SET publish_status = #{status}, + update_time = NOW() + + , publish_time = NOW() + + + , review_time = NOW() + + WHERE product_id = #{productId} + + + + + UPDATE app_product SET clicks = clicks + 1 WHERE product_id = #{productId} + + + + + UPDATE app_product SET installs = installs + 1 WHERE product_id = #{productId} + + + + + UPDATE app_product SET downloads = downloads + 1 WHERE product_id = #{productId} + + + + + UPDATE app_product SET likes = likes + 1 WHERE product_id = #{productId} + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppResourceMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppResourceMapper.xml new file mode 100644 index 0000000..537e28f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppResourceMapper.xml @@ -0,0 +1,115 @@ + + + + + + + SELECT a.*, w.product_name as appName + FROM app_resource a + LEFT JOIN app_product w ON a.app_id = w.product_id AND w.deleted = 0 + + a.deleted = 0 + + AND a.resource_id = #{param.resourceId} + + + AND a.resource_type = #{param.resourceType} + + + AND a.app_id = #{param.appId} + + + AND a.provider = #{param.provider} + + + AND a.status = #{param.status} + + + + AND (a.owner_user_id = #{param.userId} + + + OR a.app_id IN + + #{appId} + + + ) + + + AND a.tenant_id = #{param.tenantId} + + + AND ( + a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.ip LIKE CONCAT('%', #{param.keywords}, '%') + OR a.domain LIKE CONCAT('%', #{param.keywords}, '%') + OR a.host LIKE CONCAT('%', #{param.keywords}, '%') + OR w.product_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + ORDER BY a.create_time DESC + + + + + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppSettingMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppSettingMapper.xml new file mode 100644 index 0000000..d31354d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppSettingMapper.xml @@ -0,0 +1,54 @@ + + + + + + + SELECT a.* + FROM app_setting a + + a.deleted = 0 + + AND a.setting_id = #{param.settingId} + + + AND a.category = #{param.category} + + + AND a.setting_key = #{param.settingKey} + + + AND a.setting_name LIKE CONCAT('%', #{param.settingName}, '%') + + + AND a.value_type = #{param.valueType} + + + AND a.is_enabled = #{param.isEnabled} + + + AND a.is_public = #{param.isPublic} + + + AND a.tenant_id = #{param.tenantId} + + + AND (a.setting_key LIKE CONCAT('%', #{param.keywords}, '%') + OR a.setting_name LIKE CONCAT('%', #{param.keywords}, '%')) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppUserCacheMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppUserCacheMapper.xml new file mode 100644 index 0000000..ac183bc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppUserCacheMapper.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppUserMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppUserMapper.xml new file mode 100644 index 0000000..34225e0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppUserMapper.xml @@ -0,0 +1,93 @@ + + + + + + + SELECT a.*, w.product_name, w.product_code, w.icon, + c.username, c.nickname, c.avatar, c.phone + FROM app_user a + LEFT JOIN app_product w ON a.app_id = w.product_id AND w.deleted = 0 AND w.tenant_id = a.tenant_id + LEFT JOIN app_user_cache c ON a.user_id = c.user_id + + + AND a.id = #{param.id} + + + AND a.app_id = #{param.appId} + + + AND a.user_id = #{param.userId} + + + AND (a.username LIKE CONCAT('%', #{param.username}, '%') + OR a.nickname LIKE CONCAT('%', #{param.username}, '%')) + + + AND a.role = #{param.role} + + + AND a.invite_by = #{param.inviteBy} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.tenant_id = #{param.tenantId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.username LIKE CONCAT('%', #{param.keywords}, '%') + OR a.nickname LIKE CONCAT('%', #{param.keywords}, '%')) + + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppVersionMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppVersionMapper.xml new file mode 100644 index 0000000..1e36c1f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/mapper/xml/AppVersionMapper.xml @@ -0,0 +1,66 @@ + + + + + + + SELECT a.*, w.product_name, w.product_code, w.icon + FROM app_version a + LEFT JOIN app_product w ON a.app_id = w.product_id AND w.deleted = 0 + + + AND a.id = #{param.id} + + + AND a.app_id = #{param.appId} + + + AND a.version_no = #{param.versionNo} + + + AND a.version_name LIKE CONCAT('%', #{param.versionName}, '%') + + + AND a.env = #{param.env} + + + AND a.status = #{param.status} + + + AND a.is_current = #{param.isCurrent} + + + AND a.publish_by = #{param.publishBy} + + + AND a.user_id = #{param.userId} + + + AND a.tenant_id = #{param.tenantId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.version_no LIKE CONCAT('%', #{param.keywords}, '%') + OR a.version_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.changelog LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppApiKeyParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppApiKeyParam.java new file mode 100644 index 0000000..57a0aea --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppApiKeyParam.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用 API Key 查询参数 + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppApiKeyParam对象", description = "AppApiKey查询参数") +public class AppApiKeyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "Key名称(模糊搜索)") + private String name; + + @Schema(description = "状态: 0正常, 1禁用") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "应用ID") + @QueryField(type = QueryType.EQ) + private Long appId; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppArticleCategoryParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppArticleCategoryParam.java new file mode 100644 index 0000000..d19f342 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppArticleCategoryParam.java @@ -0,0 +1,21 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 平台文章分类查询参数 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "平台文章分类查询参数") +public class AppArticleCategoryParam extends BaseParam { + + @Schema(description = "分类ID") + private Integer categoryId; + + @Schema(description = "状态") + private Integer status; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppArticleParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppArticleParam.java new file mode 100644 index 0000000..b2e4e6c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppArticleParam.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 平台文章查询参数 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "平台文章查询参数") +public class AppArticleParam extends BaseParam { + + @Schema(description = "文章ID") + private Integer articleId; + + @Schema(description = "文章模型,article/announcement") + private String model; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "分类ID") + private Integer categoryId; + + @Schema(description = "是否推荐") + private Integer recommend; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppBuildParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppBuildParam.java new file mode 100644 index 0000000..7a810e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppBuildParam.java @@ -0,0 +1,35 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * CI/CD 构建查询参数 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppBuildParam对象", description = "构建查询参数") +public class AppBuildParam extends BaseParam { + + @Schema(description = "应用ID") + private Long appId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "构建状态") + private String status; + + @Schema(description = "CI系统类型") + private String ciType; + + @Schema(description = "分支") + private String branch; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppCloudCredentialParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppCloudCredentialParam.java new file mode 100644 index 0000000..d6ff03e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppCloudCredentialParam.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 云账号凭证查询参数 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppCloudCredentialParam对象", description = "云账号凭证查询参数") +public class AppCloudCredentialParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "云服务商: aliyun/tencent/huawei/qiniu") + @QueryField(type = QueryType.EQ) + private String provider; + + @Schema(description = "凭证名称") + private String name; + + @Schema(description = "状态: 0正常 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除: 0否 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppConfigParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppConfigParam.java new file mode 100644 index 0000000..9e2df25 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppConfigParam.java @@ -0,0 +1,38 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.BaseParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用配置表查询参数 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class AppConfigParam extends BaseParam { + + /** + * 配置ID + */ + private Integer configId; + + /** + * 应用ID + */ + private Integer appId; + + /** + * 配置键 + */ + private String configKey; + + /** + * 配置类型 + */ + private String configType; + + /** + * 是否敏感信息 + */ + private Integer isSecret; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppContractParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppContractParam.java new file mode 100644 index 0000000..070f2c5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppContractParam.java @@ -0,0 +1,33 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 合同查询参数 + * + * @author 科技小王子 + * @since 2026-04-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "合同查询参数") +public class AppContractParam extends PageParam { + + @Schema(description = "合同类型: service/cooperation/purchase/other") + private String contractType; + + @Schema(description = "状态: draft/pending/active/expired/terminated") + private String status; + + @Schema(description = "关键词(合同名称/编号)") + private String keywords; + + @Schema(description = "开始日期(用于筛选创建时间范围)") + private String startDate; + + @Schema(description = "结束日期(用于筛选创建时间范围)") + private String endDate; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppCredentialParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppCredentialParam.java new file mode 100644 index 0000000..cced307 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppCredentialParam.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用密钥凭证查询参数 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:43 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppCredentialParam对象", description = "应用密钥凭证查询参数") +public class AppCredentialParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "关联应用ID(AppProduct.productId)") + @QueryField(type = QueryType.EQ) + private String appId; + + @Schema(description = "凭证名称,如生产环境密钥") + private String name; + + @Schema(description = "OAuth Client ID(公开)") + @QueryField(type = QueryType.EQ) + private String clientId; + + @Schema(description = "凭证类型: server/client/webhook") + @QueryField(type = QueryType.EQ) + private String type; + + @Schema(description = "权限范围,空格分隔") + private String scopes; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppEventParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppEventParam.java new file mode 100644 index 0000000..0940758 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppEventParam.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用操作动态查询参数 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppEventParam对象", description = "应用操作动态查询参数") +public class AppEventParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "关联应用ID") + @QueryField(type = QueryType.EQ) + private Long appId; + + @Schema(description = "事件类型: created/published/updated/domain_bound/member_added/status_changed") + @QueryField(type = QueryType.EQ) + private String eventType; + + @Schema(description = "事件标题(模糊)") + private String title; + + @Schema(description = "操作人用户ID") + @QueryField(type = QueryType.EQ) + private Long operatorId; + + @Schema(description = "关联ID,如版本ID") + @QueryField(type = QueryType.EQ) + private Long refId; + + @Schema(description = "关联类型") + @QueryField(type = QueryType.EQ) + private String refType; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppNotificationParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppNotificationParam.java new file mode 100644 index 0000000..9110d73 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppNotificationParam.java @@ -0,0 +1,21 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 通知查询参数 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "通知查询参数") +public class AppNotificationParam extends BaseParam { + + @Schema(description = "通知类型: ticket/review/system/resource/permission/member/payment") + private String type; + + @Schema(description = "是否已读: 0未读 1已读,不传查全部") + private Integer isRead; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppPermissionRequestParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppPermissionRequestParam.java new file mode 100644 index 0000000..d2c54ce --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppPermissionRequestParam.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 权限申请查询参数 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppPermissionRequestParam对象", description = "权限申请查询参数") +public class AppPermissionRequestParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "Git用户名") + private String gitUsername; + + @Schema(description = "申请仓库路径") + private String repo; + + @Schema(description = "状态: pending待审核/approved已通过/rejected已拒绝") + @QueryField(type = QueryType.EQ) + private String status; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppPipelineParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppPipelineParam.java new file mode 100644 index 0000000..680ba31 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppPipelineParam.java @@ -0,0 +1,32 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * CI/CD 流水线查询参数 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AppPipelineParam对象", description = "流水线查询参数") +public class AppPipelineParam extends BaseParam { + + @Schema(description = "应用ID") + private Long appId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "CI系统类型") + private String ciType; + + @Schema(description = "是否启用") + private Boolean enabled; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppProductParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppProductParam.java new file mode 100644 index 0000000..e438852 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppProductParam.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 应用产品查询参数 + * + * @author 科技小王子 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(name = "AppProductParam对象", description = "应用产品查询参数") +public class AppProductParam extends PageParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "应用名称") + private String productName; + + @Schema(description = "应用标识") + private String productCode; + + @Schema(description = "应用类型") + private Integer appType; + + @Schema(description = "分类ID") + private Integer categoryId; + + @Schema(description = "发布状态") + private String publishStatus; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "是否上架市场") + private Integer market; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户ID") + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppResourceParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppResourceParam.java new file mode 100644 index 0000000..6ce04c7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppResourceParam.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.app.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 开发者资源查询参数 + * + * @author 科技小王子 + * @since 2026-03-31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppResourceParam对象", description = "开发者资源查询参数") +public class AppResourceParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "资源ID") + @QueryField(type = QueryType.EQ) + private Long resourceId; + + @Schema(description = "资源类型: server/database/storage/domain/ssl") + @QueryField(type = QueryType.EQ) + private String resourceType; + + @Schema(description = "关联应用ID") + @QueryField(type = QueryType.EQ) + private Long appId; + + @Schema(description = "服务商") + @QueryField(type = QueryType.EQ) + private String provider; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private String status; + + @Schema(description = "所属用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + + @Schema(description = "关键词(名称/IP/域名/Host模糊搜索)") + private String keywords; + + @Schema(description = "用户有权限的应用ID列表(协作权限)") + private List userAppIds; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppSettingParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppSettingParam.java new file mode 100644 index 0000000..672682e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppSettingParam.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.BaseParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 平台设置表查询参数 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class AppSettingParam extends BaseParam { + + /** + * 设置ID + */ + private Integer settingId; + + /** + * 设置分类:basic/review/market/register/notify/maintenance + */ + private String category; + + /** + * 设置项标识 + */ + private String settingKey; + + /** + * 设置项名称 + */ + private String settingName; + + /** + * 设置类型:string/number/boolean/json + */ + private String valueType; + + /** + * 是否启用 + */ + private Integer isEnabled; + + /** + * 是否公开 + */ + private Integer isPublic; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppTicketParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppTicketParam.java new file mode 100644 index 0000000..a0347ab --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppTicketParam.java @@ -0,0 +1,38 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.web.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 工单查询参数 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "工单查询参数") +public class AppTicketParam extends PageParam { + + @Schema(description = "关联应用ID") + private Long appId; + + @Schema(description = "应用ID列表(过滤用户有权限的应用)") + private List appIds; + + @Schema(description = "工单状态") + private String status; + + @Schema(description = "工单分类") + private String category; + + @Schema(description = "优先级") + private String priority; + + @Schema(description = "处理人ID(传0=未分配)") + private Integer assigneeId; + + @Schema(description = "关键词(标题/工单编号)") + private String keywords; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppUserParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppUserParam.java new file mode 100644 index 0000000..56a7e66 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppUserParam.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用成员查询参数 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppUserParam对象", description = "应用成员查询参数") +public class AppUserParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "关联应用ID") + @QueryField(type = QueryType.EQ) + private Long appId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "用户名(模糊搜索)") + private String username; + + @Schema(description = "角色: owner/admin/developer/viewer") + @QueryField(type = QueryType.EQ) + private String role; + + @Schema(description = "邀请人用户ID") + @QueryField(type = QueryType.EQ) + private Long inviteBy; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppVersionParam.java b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppVersionParam.java new file mode 100644 index 0000000..251b71b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/param/AppVersionParam.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.app.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用版本发布记录查询参数 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AppVersionParam对象", description = "应用版本发布记录查询参数") +public class AppVersionParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "关联应用ID") + @QueryField(type = QueryType.EQ) + private Long appId; + + @Schema(description = "版本号,如 1.0.0") + @QueryField(type = QueryType.EQ) + private String versionNo; + + @Schema(description = "版本名称(模糊)") + private String versionName; + + @Schema(description = "环境: development/staging/production") + @QueryField(type = QueryType.EQ) + private String env; + + @Schema(description = "状态 0=构建中 1=已发布 2=已回滚 3=构建失败") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否为当前版本") + @QueryField(type = QueryType.EQ) + private Boolean isCurrent; + + @Schema(description = "发布人用户ID") + @QueryField(type = QueryType.EQ) + private Long publishBy; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppApiKeyService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppApiKeyService.java new file mode 100644 index 0000000..67c84dc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppApiKeyService.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppApiKey; +import com.gxwebsoft.app.param.AppApiKeyParam; + +import java.util.List; +import java.util.Map; + +/** + * 应用 API Key 服务接口 + * + * @author 科技小王子 + * @since 2026-04-02 + */ +public interface AppApiKeyService extends IService { + + /** + * 分页查询 + */ + IPage pageRel(AppApiKeyParam param); + + /** + * 列表查询 + */ + List listRel(AppApiKeyParam param); + + /** + * 根据ID查询 + */ + AppApiKey getByIdRel(Long id); + + /** + * 创建 API Key + */ + AppApiKey createApiKey(AppApiKey apiKey, Integer userId, Integer tenantId); + + /** + * 更新 API Key + */ + boolean updateApiKey(AppApiKey apiKey); + + /** + * 更新状态 + */ + boolean updateStatus(Long id, Integer status, Integer userId); + + /** + * 删除 API Key + */ + boolean removeApiKey(Long id, Integer userId); + + /** + * 统计用户 API Key 信息 + */ + Map statsByUser(Integer userId, Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppArticleCategoryService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppArticleCategoryService.java new file mode 100644 index 0000000..0f039c1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppArticleCategoryService.java @@ -0,0 +1,27 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppArticleCategory; +import com.gxwebsoft.app.param.AppArticleCategoryParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; + +import java.util.List; + +/** + * 平台文章分类服务 + */ +public interface AppArticleCategoryService extends IService { + + PageResult page(AppArticleCategoryParam param); + + List list(AppArticleCategoryParam param); + + AppArticleCategory getDetail(Integer categoryId); + + boolean saveCategory(AppArticleCategory category, User loginUser, Integer tenantId); + + boolean updateCategory(AppArticleCategory category); + + boolean removeCategory(Integer categoryId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppArticleService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppArticleService.java new file mode 100644 index 0000000..c1bf88b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppArticleService.java @@ -0,0 +1,32 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppArticle; +import com.gxwebsoft.app.param.AppArticleParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; + +import java.util.List; +import java.util.Map; + +/** + * 平台文章服务 + */ +public interface AppArticleService extends IService { + + PageResult page(AppArticleParam param); + + List list(AppArticleParam param); + + AppArticle getDetail(Integer articleId, boolean increaseViews); + + AppArticle getByCode(String code); + + boolean saveArticle(AppArticle article, User loginUser, Integer tenantId); + + boolean updateArticle(AppArticle article); + + boolean removeArticle(Integer articleId); + + Map getStats(AppArticleParam param); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppBuildService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppBuildService.java new file mode 100644 index 0000000..ade1a2b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppBuildService.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppBuild; +import com.gxwebsoft.app.param.AppBuildParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; +import java.util.Map; + +/** + * CI/CD 构建记录 Service + * + * @author 科技小王子 + * @since 2026-04-03 + */ +public interface AppBuildService extends IService { + + /** + * 分页查询构建记录 + */ + PageResult pageBuild(AppBuildParam param); + + /** + * 查询构建详情 + */ + AppBuild getBuildDetail(Long id); + + /** + * 查询应用的最新构建 + */ + AppBuild getLatestBuild(Long appId); + + /** + * 触发构建 + * @param appId 应用ID + * @param branch 分支 + * @param triggeredBy 触发人ID + * @return 构建记录 + */ + AppBuild triggerBuild(Long appId, String branch, Integer triggeredBy); + + /** + * 获取构建日志 + * @param buildId 本地构建ID + * @return 构建日志 + */ + String getBuildLog(Long buildId); + + /** + * Webhook 回调 - 更新构建状态 + * @param ciType CI类型 + * @param payload 回调数据 + */ + void handleWebhook(String ciType, Map payload); + + /** + * 获取构建统计 + * @param appId 应用ID + * @return 统计结果 + */ + Map getBuildStats(Long appId); + + /** + * 取消构建 + * @param buildId 构建ID + */ + boolean cancelBuild(Long buildId); + + /** + * 重试构建 + * @param buildId 构建ID + * @param triggeredBy 触发人ID + */ + AppBuild retryBuild(Long buildId, Integer triggeredBy); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppCloudCredentialService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppCloudCredentialService.java new file mode 100644 index 0000000..7aef5dd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppCloudCredentialService.java @@ -0,0 +1,73 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppCloudCredential; +import com.gxwebsoft.app.param.AppCloudCredentialParam; + +import java.util.List; +import java.util.Map; + +/** + * 云账号凭证 Service 接口 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +public interface AppCloudCredentialService extends IService { + + /** + * 分页查询 + */ + com.gxwebsoft.common.core.web.PageResult pageRel(AppCloudCredentialParam param); + + /** + * 列表查询 + */ + List listRel(AppCloudCredentialParam param); + + /** + * 新增凭证 + */ + AppCloudCredential add(AppCloudCredential credential) throws Exception; + + /** + * 修改凭证 + */ + AppCloudCredential update(AppCloudCredential credential) throws Exception; + + /** + * 删除凭证 + */ + void remove(Long id, Integer userId) throws Exception; + + /** + * 获取云账号凭证(解密) + * @param provider 云服务商类型 + * @param userId 用户ID + * @return 凭证映射 (accessKeyId -> xxx, accessKeySecret -> xxx, ...) + */ + Map getCredentials(String provider, Integer userId); + + /** + * 根据凭证ID获取云账号凭证(解密) + * @param credentialId 凭证ID + * @return 凭证映射 (accessKeyId -> xxx, accessKeySecret -> xxx, ...) + */ + Map getCredentialsByCredentialId(Long credentialId); + + /** + * 测试凭证有效性 + * @param provider 云服务商类型 + * @param credentials 凭证 + * @return 是否连接成功 + */ + boolean testConnection(String provider, Map credentials); + + /** + * 测试凭证有效性(返回详细结果) + * @param provider 云服务商类型 + * @param credentials 凭证 + * @return 包含成功状态和错误消息的数组 [success, errorMessage] + */ + Object[] testConnectionWithMessage(String provider, Map credentials); +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppConfigService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppConfigService.java new file mode 100644 index 0000000..b852f57 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppConfigService.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.app.service; + +import com.gxwebsoft.app.entity.AppConfig; +import com.gxwebsoft.app.param.AppConfigParam; + +import java.util.List; +import java.util.Map; + +/** + * 应用配置表 Service + */ +public interface AppConfigService { + + /** + * 分页查询应用配置 + */ + List page(AppConfigParam param); + + /** + * 获取应用配置列表 + */ + List list(AppConfigParam param); + + /** + * 根据应用ID获取配置映射(自动解密) + */ + Map getConfigsByAppId(Integer appId); + + /** + * 获取单个配置值 + */ + String getConfigValue(Integer appId, String configKey); + + /** + * 保存配置 + */ + void saveConfig(AppConfig config); + + /** + * 批量保存配置 + */ + void batchSaveConfig(Integer appId, List configs); + + /** + * 更新配置 + */ + void updateConfig(AppConfig config); + + /** + * 删除配置 + */ + void deleteConfig(Integer configId); + + /** + * 根据应用ID删除所有配置 + */ + void deleteByAppId(Integer appId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppContractService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppContractService.java new file mode 100644 index 0000000..bed7f67 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppContractService.java @@ -0,0 +1,32 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppContract; +import com.gxwebsoft.app.param.AppContractParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.Map; + +/** + * 合同管理 Service + * + * @author 科技小王子 + * @since 2026-04-13 + */ +public interface AppContractService extends IService { + + /** 分页查询(当前用户的合同) */ + PageResult page(AppContractParam param, Integer userId); + + /** 创建合同 */ + AppContract create(AppContract contract, Integer userId); + + /** 更新合同 */ + AppContract update(AppContract contract, Integer userId); + + /** 删除合同(软删除) */ + void remove(Long contractId, Integer userId); + + /** 统计数据 */ + Map stats(Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppCredentialService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppCredentialService.java new file mode 100644 index 0000000..ddd5d66 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppCredentialService.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.app.entity.AppCredential; +import com.gxwebsoft.app.param.AppCredentialParam; + +import java.util.List; + +/** + * 应用密钥凭证Service + * + * @author 科技小王子 + * @since 2026-03-28 21:29:43 + */ +public interface AppCredentialService extends IService { + + /** + * 分页关联查询 + */ + PageResult pageRel(AppCredentialParam param); + + /** + * 关联查询全部 + */ + List listRel(AppCredentialParam param); + + /** + * 根据id查询 + */ + AppCredential getByIdRel(Integer id); + + /** + * 创建凭证(自动生成 appId 和 appSecret) + * + * @param credential 凭证基础信息 + * @return 包含明文 appSecret 的凭证对象(仅此次返回,之后不再展示) + */ + AppCredential createCredential(AppCredential credential); + + /** + * 重置密钥(重新生成 appSecret) + * + * @param id 凭证ID + * @return 包含新明文 appSecret 的凭证对象 + */ + AppCredential resetSecret(Long id); + + /** + * 禁用/启用凭证 + * + * @param id 凭证ID + * @param status 0=正常 1=冻结 + */ + boolean updateStatus(Long id, Integer status); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppEventService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppEventService.java new file mode 100644 index 0000000..ca1c62d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppEventService.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.app.entity.AppEvent; +import com.gxwebsoft.app.param.AppEventParam; + +import java.util.List; + +/** + * 应用操作动态Service + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +public interface AppEventService extends IService { + + /** + * 分页关联查询 + */ + PageResult pageRel(AppEventParam param); + + /** + * 关联查询全部 + */ + List listRel(AppEventParam param); + + /** + * 根据id查询 + */ + AppEvent getByIdRel(Integer id); + + /** + * 记录应用事件(便捷方法,供其他模块调用) + * + * @param appId 应用ID + * @param eventType 事件类型(created/published/updated/domain_bound/member_added/status_changed 等) + * @param title 事件标题 + * @param content 详细描述 + * @param operatorId 操作人用户ID + * @param operatorName 操作人名称 + * @param refId 关联记录ID(如版本ID) + * @param refType 关联记录类型 + */ + void logEvent(Long appId, String eventType, String title, String content, + Long operatorId, String operatorName, Long refId, String refType); + + /** + * 快捷记录事件(无关联记录) + */ + void logEvent(Long appId, String eventType, String title, Long operatorId, String operatorName); + + /** + * 获取指定应用的最新一条事件(用于卡片"最新动态"展示) + * + * @param appId 应用ID + */ + AppEvent getLatestEvent(Long appId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppGitAccountService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppGitAccountService.java new file mode 100644 index 0000000..eddd6f8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppGitAccountService.java @@ -0,0 +1,69 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppGitAccount; + +import java.util.Map; + +/** + * Git账号绑定 Service + * + * @author 科技小王子 + * @since 2026-04-02 + */ +public interface AppGitAccountService extends IService { + + /** + * 保存或更新Git账号绑定信息 + * + * @param username 用户名 + * @param email 邮箱(可选) + * @param remark 备注(可选) + * @param userId 用户ID + * @param tenantId 租户ID + * @return 绑定结果 + */ + AppGitAccount saveGitAccount(String username, String email, String remark, Integer userId, Integer tenantId); + + /** + * 获取用户的Git账号绑定状态 + * + * @param userId 用户ID + * @param tenantId 租户ID + * @return 绑定状态 + */ + AppGitAccount getGitAccountStatus(Integer userId, Integer tenantId); + + /** + * 分页查询Git账号绑定列表(管理端) + * + * @param status 状态筛选(可选) + * @param keyword 关键词搜索(可选,匹配用户名/邮箱) + * @param page 页码 + * @param size 每页数量 + * @return 分页结果 + */ + Map pageGitAccounts(String status, String keyword, int page, int size); + + /** + * 审核Git账号绑定 - 通过 + * + * @param id 记录ID + * @param reviewerId 审核人ID + * @param reviewerName 审核人姓名 + * @param note 审核备注(可选) + * @return 是否成功 + */ + boolean approveAccount(Long id, Integer reviewerId, String reviewerName, String note); + + /** + * 审核Git账号绑定 - 拒绝 + * + * @param id 记录ID + * @param reviewerId 审核人ID + * @param reviewerName 审核人姓名 + * @param reason 拒绝原因(必填) + * @return 是否成功 + */ + boolean rejectAccount(Long id, Integer reviewerId, String reviewerName, String reason); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppInviteService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppInviteService.java new file mode 100644 index 0000000..e67c33e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppInviteService.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.app.service; + +import java.util.Map; + +/** + * 应用成员邀请 Service 接口 + */ +public interface AppInviteService { + + /** + * 生成二维码邀请 + * + * @param appId 应用ID + * @param role 角色 + * @param inviterId 邀请人ID + * @return 包含二维码URL的Map + */ + Map generateQrCodeInvite(Integer appId, String role, Integer inviterId); + + /** + * 生成链接邀请 + * + * @param appId 应用ID + * @param role 角色 + * @param inviterId 邀请人ID + * @return 包含邀请链接的Map + */ + Map generateLinkInvite(Integer appId, String role, Integer inviterId); + + /** + * 验证邀请 + * + * @param token 邀请token + * @param appId 应用ID + * @return 邀请信息 + */ + Map verifyInvite(String token, Integer appId); + + /** + * 接受邀请 + * + * @param token 邀请token + * @param appId 应用ID + * @param userId 接受邀请的用户ID + */ + void acceptInvite(String token, Integer appId, Integer userId); + + /** + * 通过token获取邀请信息(小程序专用,不需要appId) + * + * @param token 邀请token + * @return 邀请信息 + */ + Map getInviteInfoByToken(String token); + + /** + * 查询邀请状态(用于轮询检测是否被使用) + * + * @param token 邀请token + * @return 状态信息 { status: 0-未使用, 1-已使用, usedAt: 使用时间, usedBy: 使用者名称 } + */ + Map getInviteStatus(String token); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppNotificationService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppNotificationService.java new file mode 100644 index 0000000..a2882a7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppNotificationService.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppNotification; +import com.gxwebsoft.app.param.AppNotificationParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; +import java.util.Map; + +/** + * 站内消息通知 Service + */ +public interface AppNotificationService extends IService { + + /** 分页查询当前用户的通知 */ + PageResult pageByUser(AppNotificationParam param, Integer userId); + + /** 查询最近通知(用于铃铛下拉) */ + List listRecent(Integer userId, String type, int limit); + + /** 获取未读数量统计 */ + Map getUnreadCount(Integer userId); + + /** 标记单条通知为已读 */ + void markRead(Long id, Integer userId); + + /** 标记全部已读(可按类型) */ + void markAllRead(Integer userId, String type); + + /** 删除单条通知 */ + void removeNotification(Long id, Integer userId); + + /** 清空已读通知(可按类型) */ + void clearRead(Integer userId, String type); + + /** 发送通知(供其他模块调用) */ + void send(Integer userId, String type, String title, String content, + Long refId, String refType, String linkUrl, + Integer senderId, String senderName, String senderAvatar); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppPermissionRequestService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppPermissionRequestService.java new file mode 100644 index 0000000..39d4b87 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppPermissionRequestService.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppPermissionRequest; +import com.gxwebsoft.app.param.AppPermissionRequestParam; + +import java.util.List; +import java.util.Map; + +/** + * 权限申请Service + * + * @author 科技小王子 + * @since 2026-04-03 + */ +public interface AppPermissionRequestService extends IService { + + /** + * 分页查询 + */ + IPage pageRel(AppPermissionRequestParam param); + + /** + * 列表查询 + */ + List listRel(AppPermissionRequestParam param); + + /** + * 根据ID查询 + */ + AppPermissionRequest getByIdRel(Long id); + + /** + * 获取权限申请统计 + */ + Map getPermissionRequestStats(Integer userId); + + /** + * 创建权限申请 + */ + AppPermissionRequest createPermissionRequest(Integer userId, String gitUsername, String repo, String repoName, String reason, Integer tenantId); + + /** + * 获取可申请的仓库列表 + */ + List> getAvailableRepositories(Integer userId); + + /** + * 审核权限申请 + */ + boolean approveRequest(Long requestId, Integer reviewerId, String reviewerName, String note); + + /** + * 拒绝权限申请 + */ + boolean rejectRequest(Long requestId, Integer reviewerId, String reviewerName, String reason); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppPipelineService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppPipelineService.java new file mode 100644 index 0000000..b15ea1a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppPipelineService.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppPipeline; +import com.gxwebsoft.app.param.AppPipelineParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; + +/** + * CI/CD 流水线 Service + * + * @author 科技小王子 + * @since 2026-04-03 + */ +public interface AppPipelineService extends IService { + + /** + * 分页查询流水线 + */ + PageResult pagePipeline(AppPipelineParam param); + + /** + * 查询流水线详情 + */ + AppPipeline getPipelineDetail(Long id); + + /** + * 查询应用的所有流水线 + */ + List getByAppId(Long appId); + + /** + * 创建流水线 + */ + boolean createPipeline(AppPipeline pipeline); + + /** + * 更新流水线 + */ + boolean updatePipeline(AppPipeline pipeline); + + /** + * 删除流水线 + */ + boolean deletePipeline(Long id); + + /** + * 启用/禁用流水线 + */ + boolean togglePipeline(Long id, boolean enabled); + + /** + * 获取流水线状态 + */ + String getPipelineStatus(Long id); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppProductService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppProductService.java new file mode 100644 index 0000000..65870f7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppProductService.java @@ -0,0 +1,206 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppProduct; + +import java.util.List; +import java.util.Map; + +/** + * 应用产品 服务类 + * + * @author 科技小王子 + */ +public interface AppProductService extends IService { + + /** + * 分页查询应用列表 + * + * @param page 分页参数 + * @param product 查询条件 + * @param userId 用户ID(可选,为空则查所有) + * @return 分页结果 + */ + IPage selectPageList(Page page, AppProduct product, Integer userId); + + /** + * 获取应用详情 + * + * @param productId 应用ID + * @return 应用信息 + */ + AppProduct getDetail(Integer productId); + + /** + * 根据标识获取应用 + * + * @param code 应用标识 + * @return 应用信息 + */ + AppProduct getByCode(String code); + + /** + * 获取用户的应用列表 + * + * @param userId 用户ID + * @return 应用列表 + */ + List getByUserId(Integer userId); + + /** + * 分页查询用户创建的应用(我的应用) + * + * @param page 分页参数 + * @param userId 用户ID + * @return 分页结果 + */ + IPage getMyApps(Page page, Integer userId); + + /** + * 分页查询用户参与的应用 + * + * @param page 分页参数 + * @param userId 用户ID + * @return 分页结果 + */ + IPage getJoinedApps(Page page, Integer userId); + + /** + * 创建应用 + * + * @param product 应用信息 + * @return 是否成功 + */ + boolean create(AppProduct product); + + /** + * 更新应用 + * + * @param product 应用信息 + * @return 是否成功 + */ + boolean update(AppProduct product); + + /** + * 删除应用 + * + * @param productId 应用ID + * @return 是否成功 + */ + boolean delete(Integer productId); + + /** + * 提交审核 + * + * @param productId 应用ID + * @return 是否成功 + */ + boolean submitReview(Integer productId); + + /** + * 审核通过 + * + * @param productId 应用ID + * @return 是否成功 + */ + boolean approve(Integer productId); + + /** + * 审核拒绝 + * + * @param productId 应用ID + * @param reason 拒绝原因 + * @return 是否成功 + */ + boolean reject(Integer productId, String reason); + + /** + * 上架应用 + * + * @param productId 应用ID + * @return 是否成功 + */ + boolean publish(Integer productId); + + /** + * 下架应用 + * + * @param productId 应用ID + * @return 是否成功 + */ + boolean unpublish(Integer productId); + + /** + * 增加浏览次数 + * + * @param productId 应用ID + */ + void incrementClicks(Integer productId); + + /** + * 增加安装次数 + * + * @param productId 应用ID + */ + void incrementInstalls(Integer productId); + + /** + * 增加下载次数 + * + * @param productId 应用ID + */ + void incrementDownloads(Integer productId); + + /** + * 增加点赞数 + * + * @param productId 应用ID + */ + void incrementLikes(Integer productId); + + /** + * 生成应用密钥 + * + * @param productId 应用ID + * @return 新密钥 + */ + String regenerateSecret(Integer productId); + + /** + * 获取应用市场列表 + * + * @param page 分页参数 + * @param appType 应用类型 + * @param keyword 关键词 + * @return 应用列表 + */ + IPage getMarketList(Page page, Integer appType, String keyword); + + /** + * 获取站点配置字段 + * + * @param tenantId 租户ID + * @param code 配置字段代码 + * @return 配置值 + */ + AppProduct getConfigField(Integer tenantId, String code); + + /** + * 按用户ID列表批量统计应用数量 + * + * @param userIds 用户ID列表 + * @return 统计结果列表 + */ + List> getStatsByUserIds(List userIds); + + /** + * 获取用户可访问的应用列表(带 myRole 字段) + * 包含用户创建的应用(owner)+ 被邀请加入的应用(成员角色) + * + * @param userId 用户ID + * @return 应用列表(带 myRole 字段) + */ + List getAccessibleApps(Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppResourceService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppResourceService.java new file mode 100644 index 0000000..e29a256 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppResourceService.java @@ -0,0 +1,75 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.param.AppResourceParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; +import java.util.Map; + +/** + * 开发者资源 Service + * + * @author 科技小王子 + * @since 2026-03-31 + */ +public interface AppResourceService extends IService { + + /** 分页查询(关联应用名称,并为当前用户注入 accessLevel/isOwner) */ + PageResult pageRel(AppResourceParam param, Integer currentUserId); + + /** 分页查询(兼容旧调用) */ + default PageResult pageRel(AppResourceParam param) { + return pageRel(param, null); + } + + /** 列表查询(并为当前用户注入 accessLevel/isOwner) */ + List listRel(AppResourceParam param, Integer currentUserId); + + /** 列表查询(兼容旧调用) */ + default List listRel(AppResourceParam param) { + return listRel(param, null); + } + + /** 详情(关联查询,并为当前用户注入 accessLevel/isOwner) */ + AppResource getByIdRel(Long resourceId, Integer currentUserId); + + /** 详情(兼容旧调用) */ + default AppResource getByIdRel(Long resourceId) { + return getByIdRel(resourceId, null); + } + + /** 新增资源(自动设置 ownerUserId) */ + AppResource addResource(AppResource resource, Integer userId); + + /** 更新资源(只有 Owner 可操作) */ + AppResource updateResource(AppResource resource, Integer currentUserId); + + /** 更新资源(兼容旧调用) */ + default AppResource updateResource(AppResource resource) { + return updateResource(resource, null); + } + + /** 删除资源(只有 Owner 可操作,逻辑删除) */ + void removeResource(Long resourceId, Integer userId); + + /** 按资源类型统计数量(包含协作的资源) */ + Map countByType(Integer userId, Integer tenantId); + + /** + * 为资源列表批量注入当前用户的 accessLevel / isOwner + * (供 Controller 调用;同时根据权限级别屏蔽敏感字段) + * + * @param resources 资源列表 + * @param currentUserId 当前登录用户ID + */ + void enrichWithPermission(List resources, Integer currentUserId); + + /** + * 重置数据库密码(只有 Owner 可操作) + * @return 新密码 + */ + String resetDatabasePassword(Long resourceId, Integer currentUserId); +} + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppSettingService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppSettingService.java new file mode 100644 index 0000000..159e551 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppSettingService.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppSetting; +import com.gxwebsoft.app.param.AppSettingParam; + +import java.util.List; +import java.util.Map; + +/** + * 平台设置表 Service + */ +public interface AppSettingService extends IService { + + /** + * 分页查询 + */ + List page(AppSettingParam param); + + /** + * 获取设置列表 + */ + List list(AppSettingParam param); + + /** + * 根据分类获取所有设置 + */ + List getByCategory(String category); + + /** + * 根据key获取设置值 + */ + String getValue(String settingKey); + + /** + * 根据key获取设置(完整对象) + */ + AppSetting getByKey(String settingKey); + + /** + * 获取分类下的所有设置(以Map返回,key为settingKey) + */ + Map getCategoryValues(String category); + + /** + * 保存或更新设置 + */ + void saveOrUpdateSetting(AppSetting setting); + + /** + * 批量保存分类设置 + */ + void batchSave(String category, Map values); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppSubscriptionService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppSubscriptionService.java new file mode 100644 index 0000000..287ab98 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppSubscriptionService.java @@ -0,0 +1,32 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppSubscription; + +/** + * 应用订阅 Service 接口 + */ +public interface AppSubscriptionService extends IService { + + /** + * 创建订阅 + * @param userId 用户ID + * @param productId 产品ID + * @param priceType 价格类型 + * @param period 订阅周期 + * @return 订阅记录 + */ + AppSubscription createSubscription(Integer userId, Integer productId, String priceType, String period); + + /** + * 激活订阅(支付成功后调用) + * @param subscriptionNo 订阅编号 + * @param transactionId 第三方交易号 + */ + void activateSubscription(String subscriptionNo, String transactionId); + + /** + * 检查用户是否已购买某应用 + */ + boolean isPurchased(Integer userId, Integer productId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppTicketService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppTicketService.java new file mode 100644 index 0000000..fc61a86 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppTicketService.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppTicket; +import com.gxwebsoft.app.entity.AppTicketReply; +import com.gxwebsoft.app.param.AppTicketParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; +import java.util.Map; + +/** + * 应用工单 Service + */ +public interface AppTicketService extends IService { + + /** 客户端:查自己提交的工单(分页) */ + PageResult myPage(AppTicketParam param, Integer userId); + + /** 技术端:查询所有工单(分页) */ + PageResult allPage(AppTicketParam param); + + /** 提交工单(自动分配) */ + AppTicket submit(AppTicket ticket, Integer userId); + + /** 更新状态(技术人员操作) */ + void updateStatus(Long ticketId, String status, Integer operatorId); + + /** 分配处理人 */ + void assign(Long ticketId, Integer assigneeId); + + /** 关闭工单(提交人操作) */ + void closeByUser(Long ticketId, Integer userId); + + /** 获取工单回复列表 */ + List getReplies(Long ticketId); + + /** 添加回复 */ + AppTicketReply addReply(AppTicketReply reply, Integer userId); + + /** 统计数据 */ + Map stats(Long appId, Integer userId); + + /** 获取技术人员列表(角色:developer/admin 的应用成员) */ + List> getTechStaffList(); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppUserCacheService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppUserCacheService.java new file mode 100644 index 0000000..fe8f685 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppUserCacheService.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.app.entity.AppUserCache; + +/** + * 用户缓存 Service + * + * @author 科技小王子 + * @since 2026-04-03 + */ +public interface AppUserCacheService extends IService { + + /** + * 根据用户ID获取缓存的用户信息 + * + * @param userId 用户ID + * @return 缓存的用户信息,不存在返回 null + */ + AppUserCache getByUserId(Integer userId); + + /** + * 刷新单个用户缓存(从 server API 获取最新数据并更新) + * + * @param userId 用户ID + * @return 刷新后的缓存数据 + */ + AppUserCache refreshUserCache(Integer userId); + + /** + * 批量刷新用户缓存 + * + * @param userIds 用户ID列表 + */ + void batchRefreshUserCache(java.util.List userIds); + + /** + * 根据手机号刷新用户缓存 + * 从 server API 根据手机号查询用户并更新缓存 + * + * @param phone 手机号 + * @return 刷新后的缓存数据,不存在返回 null + */ + AppUserCache refreshUserCacheByPhone(String phone); + + /** + * 根据手机号创建新用户 + * 调用 server API 创建用户并同步到本地缓存 + * + * @param phone 手机号 + * @return 创建后的缓存数据,失败返回 null + */ + AppUserCache createUserByPhone(String phone); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppUserService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppUserService.java new file mode 100644 index 0000000..fc6ac8f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppUserService.java @@ -0,0 +1,128 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.param.AppUserParam; + +import java.util.List; + +/** + * 应用成员Service + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +public interface AppUserService extends IService { + + /** + * 分页关联查询 + */ + PageResult pageRel(AppUserParam param); + + /** + * 关联查询全部 + */ + List listRel(AppUserParam param); + + /** + * 根据id查询 + */ + AppUser getByIdRel(Integer id); + + /** + * 邀请成员加入应用 + * + * @param appId 应用ID + * @param userId 被邀请的用户ID + * @param role 分配的角色 + * @param inviteBy 邀请人用户ID + * @param tenantId 租户ID(NOT NULL约束) + * @return 成员记录 + */ + AppUser inviteUser(Long appId, Integer userId, String role, Integer inviteBy, Integer tenantId); + + /** + * 修改成员角色 + * + * @param id 成员记录ID + * @param role 新角色 + */ + boolean updateRole(Long id, String role); + + /** + * 检查用户是否已是应用成员 + * + * @param appId 应用ID + * @param userId 用户ID + */ + boolean isMember(Long appId, Integer userId); + + /** + * 根据手机号查找系统用户(用于手机号邀请) + * + * @param phone 手机号 + * @return 系统用户,不存在返回 null + */ + com.gxwebsoft.common.system.entity.User findUserByPhone(String phone); + + /** + * 搜索用户(支持手机号/用户名/昵称模糊搜索) + * + * @param keyword 搜索关键词 + * @return 用户列表 + */ + List searchUsers(String keyword); + + /** + * 记录用户访问应用(更新最近访问时间) + * + * @param appId 应用ID + * @param userId 用户ID + */ + void recordVisit(Long appId, Integer userId); + + /** + * 接受邀请加入应用 + * + * @param inviteId 邀请记录ID + * @param userId 当前用户ID + * @return 是否成功 + */ + boolean acceptInvite(Long inviteId, Integer userId); + + /** + * 拒绝邀请 + * + * @param inviteId 邀请记录ID + * @param userId 当前用户ID + * @return 是否成功 + */ + boolean rejectInvite(Long inviteId, Integer userId); + + /** + * 查询用户的待确认邀请列表 + * + * @param userId 用户ID + * @return 邀请列表 + */ + List listPendingInvites(Integer userId); + + /** + * 统计用户的待确认邀请数量 + * + * @param userId 用户ID + * @return 待确认数量 + */ + long countPendingInvites(Integer userId); + + /** + * 检查用户是否有待确认的邀请 + * + * @param appId 应用ID + * @param userId 用户ID + * @return 是否有待确认邀请 + */ + boolean hasPendingInvite(Long appId, Integer userId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppVersionService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppVersionService.java new file mode 100644 index 0000000..d5fca40 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/AppVersionService.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.app.entity.AppVersion; +import com.gxwebsoft.app.param.AppVersionParam; + +import java.util.List; + +/** + * 应用版本发布记录Service + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +public interface AppVersionService extends IService { + + /** + * 分页关联查询 + */ + PageResult pageRel(AppVersionParam param); + + /** + * 关联查询全部 + */ + List listRel(AppVersionParam param); + + /** + * 根据id查询 + */ + AppVersion getByIdRel(Integer id); + + /** + * 发布版本(将此版本设为当前版本,其他版本 isCurrent=false) + * + * @param id 版本ID + * @param publishBy 发布人用户ID + */ + boolean publish(Long id, Integer publishBy); + + /** + * 回滚到指定版本(将此版本设为当前版本,当前版本标为已回滚) + * + * @param id 要回滚到的版本ID + * @param publishBy 操作人用户ID + */ + boolean rollback(Long id, Integer publishBy); + + /** + * 获取指定应用的当前版本 + * + * @param appId 应用ID + */ + AppVersion getCurrentVersion(Long appId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/DatabaseOperatorFactory.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/DatabaseOperatorFactory.java new file mode 100644 index 0000000..393cc7b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/DatabaseOperatorFactory.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.app.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 数据库操作工厂 + * 根据 dbType(MySQL/PostgreSQL)分发到对应的 DatabaseOperatorService 实现 + * + * @author WebSoft + * @since 2026-04-04 + */ +@Slf4j +@Component +public class DatabaseOperatorFactory { + + private final List operators; + private final Map operatorMap = new ConcurrentHashMap<>(); + + public DatabaseOperatorFactory(List operators) { + this.operators = operators; + } + + @PostConstruct + public void init() { + for (DatabaseOperatorService operator : operators) { + String dbType = operator.getSupportedDbType(); + operatorMap.put(dbType, operator); + log.info("注册数据库操作服务: {} -> {}", dbType, operator.getClass().getSimpleName()); + } + } + + /** + * 根据 dbType 获取对应的操作服务 + * + * @param dbType 数据库类型(MySQL/PostgreSQL) + * @return 对应的操作服务实现 + * @throws IllegalArgumentException 如果不支持的数据库类型 + */ + public DatabaseOperatorService getOperator(String dbType) { + if (dbType == null || dbType.isEmpty()) { + throw new IllegalArgumentException("数据库类型不能为空"); + } + DatabaseOperatorService operator = operatorMap.get(dbType); + if (operator == null) { + throw new IllegalArgumentException("不支持的数据库类型: " + dbType + ",当前支持: " + operatorMap.keySet()); + } + return operator; + } + + /** + * 判断是否支持该数据库类型的远程创建 + */ + public boolean isSupported(String dbType) { + return dbType != null && operatorMap.containsKey(dbType); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/DatabaseOperatorService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/DatabaseOperatorService.java new file mode 100644 index 0000000..4b2c0a1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/DatabaseOperatorService.java @@ -0,0 +1,141 @@ +package com.gxwebsoft.app.service; + +/** + * 远程数据库操作服务接口 + * 支持 MySQL、PostgreSQL 等多种数据库的远程创建/删除操作 + * 通过 DatabaseOperatorFactory 根据 dbType 获取具体实现 + * + * @author WebSoft + * @since 2026-04-04 + */ +public interface DatabaseOperatorService { + + /** + * 返回此实现支持的数据库类型 + */ + String getSupportedDbType(); + + /** + * 在远程服务器上创建数据库并授权用户 + * + * @param host 服务器地址 + * @param port 端口 + * @param username 管理员用户名 + * @param password 管理员密码(明文) + * @param dbName 要创建的数据库名 + * @param dbUser 业务数据库用户名(可为空,不创建用户) + * @param dbPass 业务数据库密码(可为空,不创建用户) + * @return 操作结果 + */ + DatabaseOperationResult createDatabaseAndGrant(String host, Integer port, + String username, String password, + String dbName, String dbUser, String dbPass); + + /** + * 在远程服务器上删除数据库和用户 + * + * @param host 服务器地址 + * @param port 端口 + * @param username 管理员用户名 + * @param password 管理员密码(明文) + * @param dbName 要删除的数据库名 + * @param dbUser 要删除的用户名(可为空) + * @return 操作结果 + */ + DatabaseOperationResult dropDatabaseAndUser(String host, Integer port, + String username, String password, + String dbName, String dbUser); + + /** + * 测试数据库连接是否可用 + * + * @param host 数据库地址 + * @param port 端口 + * @param username 用户名 + * @param password 密码 + * @param dbName 数据库名(可为空,只测试服务器连通性) + * @return 操作结果 + */ + DatabaseOperationResult testConnection(String host, Integer port, + String username, String password, + String dbName); + + /** + * 在远程服务器上修改数据库用户密码 + * + * @param host 服务器地址 + * @param port 端口 + * @param adminUsername 管理员用户名 + * @param adminPassword 管理员密码(明文) + * @param dbUsername 数据库用户名 + * @param oldPassword 旧密码(明文,可为空) + * @param newPassword 新密码(明文) + * @return 操作结果 + */ + DatabaseOperationResult changePassword(String host, Integer port, + String adminUsername, String adminPassword, + String dbUsername, String oldPassword, String newPassword); + + /** + * 数据库操作结果 + */ + class DatabaseOperationResult { + private boolean success; + private String message; + private String detail; + + public DatabaseOperationResult() { + } + + public DatabaseOperationResult(boolean success, String message) { + this.success = success; + this.message = message; + } + + public DatabaseOperationResult(boolean success, String message, String detail) { + this.success = success; + this.message = message; + this.detail = detail; + } + + public static DatabaseOperationResult ok(String message) { + return new DatabaseOperationResult(true, message); + } + + public static DatabaseOperationResult ok(String message, String detail) { + return new DatabaseOperationResult(true, message, detail); + } + + public static DatabaseOperationResult fail(String message) { + return new DatabaseOperationResult(false, message); + } + + public static DatabaseOperationResult fail(String message, String detail) { + return new DatabaseOperationResult(false, message, detail); + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/OnePanelService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/OnePanelService.java new file mode 100644 index 0000000..86bfa9d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/OnePanelService.java @@ -0,0 +1,258 @@ +package com.gxwebsoft.app.service; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * 1Panel 面板服务 + * 用于调用1Panel API获取服务器状态信息 + * + * @author 科技小王子 + * @since 2026-04-06 + */ +@Slf4j +@Service +public class OnePanelService { + + private final RestTemplate restTemplate = new RestTemplate(); + + /** + * 获取1Panel服务器状态 + */ + @Data + public static class ServerStatus { + private String cpu; // CPU 使用率 % + private String memory; // 内存使用率 % + private String memoryUsed; // 内存已用 (GB) + private String memoryTotal; // 内存总量 (GB) + private String disk; // 磁盘使用率 % + private String diskUsed; // 磁盘已用 (GB) + private String diskTotal; // 磁盘总量 (GB) + private String load; // 系统负载 (1min, 5min, 15min) + private String uptime; // 运行时间 + private Integer online; // 在线状态 1=在线 0=离线 + private String message; // 错误信息 + } + + /** + * 获取服务器状态 + * + * @param host 服务器IP + * @param port 面板端口 + * @param path 安全入口路径 + * @param username 面板用户名 + * @param password 面板密码 + * @return 服务器状态 + */ + public ServerStatus getServerStatus(String host, Integer port, String path, String username, String password) { + ServerStatus status = new ServerStatus(); + status.setOnline(0); + + if (host == null || port == null) { + status.setMessage("服务器地址或端口不能为空"); + return status; + } + + try { + // 构建1Panel API地址 + String baseUrl = buildBaseUrl(host, port, path); + String overviewUrl = baseUrl + "/api/v1/overview"; + + // 设置认证头 + Map headers = new HashMap<>(); + headers.put("Authorization", "Basic " + buildBasicAuth(username, password)); + + // 调用1Panel概览接口 + Map response = callApi(overviewUrl, headers); + + if (response != null) { + parseOverviewResponse(response, status); + status.setOnline(1); + } else { + status.setMessage("接口返回为空"); + } + + } catch (Exception e) { + log.error("获取1Panel状态失败: host={}, port={}, error={}", host, port, e.getMessage()); + status.setMessage("连接失败: " + e.getMessage()); + } + + return status; + } + + /** + * 构建1Panel API基础地址 + */ + private String buildBaseUrl(String host, Integer port, String path) { + String baseUrl = "http://" + host + ":" + port; + if (path != null && !path.isEmpty()) { + // 确保path以/开头 + if (!path.startsWith("/")) { + baseUrl += "/"; + } + baseUrl += path; + } + return baseUrl; + } + + /** + * 构建Basic Auth认证字符串 + */ + private String buildBasicAuth(String username, String password) { + String auth = (username != null ? username : "") + ":" + (password != null ? password : ""); + return Base64.getEncoder().encodeToString(auth.getBytes()); + } + + /** + * 调用1Panel API + */ + @SuppressWarnings("unchecked") + private Map callApi(String url, Map headers) { + try { + org.springframework.http.HttpHeaders httpHeaders = new org.springframework.http.HttpHeaders(); + headers.forEach(httpHeaders::add); + + org.springframework.http.HttpEntity entity = new org.springframework.http.HttpEntity<>(httpHeaders); + org.springframework.http.ResponseEntity response = restTemplate.exchange( + url, + org.springframework.http.HttpMethod.GET, + entity, + Map.class + ); + + if (response.getBody() != null) { + Map body = response.getBody(); + // 1Panel API返回格式通常是 { data: {...}, code: 200 } + if (Boolean.TRUE.equals(body.get("ok")) || "200".equals(String.valueOf(body.get("code")))) { + Object data = body.get("data"); + if (data instanceof Map) { + return (Map) data; + } + } + } + return null; + } catch (Exception e) { + log.error("API调用失败: url={}, error={}", url, e.getMessage()); + throw new RuntimeException("API调用失败: " + e.getMessage()); + } + } + + /** + * 解析概览接口返回的数据 + */ + @SuppressWarnings("unchecked") + private void parseOverviewResponse(Map data, ServerStatus status) { + // CPU信息 + Map cpuInfo = getMapValue(data, "cpu"); + if (cpuInfo != null) { + Object cpuUsed = cpuInfo.get("used"); + status.setCpu(formatPercent(cpuUsed)); + } + + // 内存信息 + Map memoryInfo = getMapValue(data, "memory"); + if (memoryInfo != null) { + Object memUsed = memoryInfo.get("used"); + Object memTotal = memoryInfo.get("total"); + status.setMemory(formatPercent(memUsed)); + status.setMemoryUsed(formatSize(memUsed)); + status.setMemoryTotal(formatSize(memTotal)); + } + + // 磁盘信息 + Map diskInfo = getMapValue(data, "disk"); + if (diskInfo != null) { + Object diskUsed = diskInfo.get("used"); + Object diskTotal = diskInfo.get("total"); + Object diskPercent = diskInfo.get("usedPercent"); + status.setDisk(formatPercent(diskPercent)); + status.setDiskUsed(formatSize(diskUsed)); + status.setDiskTotal(formatSize(diskTotal)); + } + + // 系统负载 + Map loadInfo = getMapValue(data, "load"); + if (loadInfo != null) { + Object load1 = loadInfo.get("load1"); + Object load5 = loadInfo.get("load5"); + Object load15 = loadInfo.get("load15"); + status.setLoad(String.format("%.2f / %.2f / %.2f", load1, load5, load15)); + } + + // 运行时间 + Map uptimeInfo = getMapValue(data, "uptime"); + if (uptimeInfo != null) { + Object uptime = uptimeInfo.get("uptime"); + if (uptime != null) { + status.setUptime(formatUptime(uptime)); + } + } + } + + /** + * 获取Map中的嵌套Map + */ + @SuppressWarnings("unchecked") + private Map getMapValue(Map data, String key) { + Object value = data.get(key); + if (value instanceof Map) { + return (Map) value; + } + return null; + } + + /** + * 格式化百分比 + */ + private String formatPercent(Object value) { + if (value == null) return "0"; + try { + double percent = Double.parseDouble(String.valueOf(value)); + return String.format("%.1f", percent); + } catch (NumberFormatException e) { + return "0"; + } + } + + /** + * 格式化大小(字节转换为GB) + */ + private String formatSize(Object value) { + if (value == null) return "0 GB"; + try { + long bytes = Long.parseLong(String.valueOf(value)); + double gb = bytes / (1024.0 * 1024.0 * 1024.0); + return String.format("%.1f GB", gb); + } catch (NumberFormatException e) { + return "0 GB"; + } + } + + /** + * 格式化运行时间 + */ + private String formatUptime(Object value) { + if (value == null) return "-"; + try { + long seconds = Long.parseLong(String.valueOf(value)); + long days = seconds / 86400; + long hours = (seconds % 86400) / 3600; + long minutes = (seconds % 3600) / 60; + if (days > 0) { + return String.format("%d天 %d小时 %d分钟", days, hours, minutes); + } else if (hours > 0) { + return String.format("%d小时 %d分钟", hours, minutes); + } else { + return String.format("%d分钟", minutes); + } + } catch (NumberFormatException e) { + return "-"; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/SshService.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/SshService.java new file mode 100644 index 0000000..751b05b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/SshService.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.app.service; + +import lombok.Data; + +/** + * SSH 连接测试服务 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +public interface SshService { + + /** + * 测试 SSH 连接 + * + * @param host 服务器 IP + * @param port SSH 端口 + * @param username 用户名 + * @param password 密码 + * @return 连接结果 + */ + ConnectionResult testConnection(String host, Integer port, String username, String password); + + @Data + class ConnectionResult { + private boolean success; + private String message; + private String detail; + + public static ConnectionResult ok(String message, String detail) { + ConnectionResult result = new ConnectionResult(); + result.setSuccess(true); + result.setMessage(message); + result.setDetail(detail); + return result; + } + + public static ConnectionResult fail(String message, String detail) { + ConnectionResult result = new ConnectionResult(); + result.setSuccess(false); + result.setMessage(message); + result.setDetail(detail); + return result; + } + + public static ConnectionResult fail(String message) { + return fail(message, null); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/CloudStorageProvider.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/CloudStorageProvider.java new file mode 100644 index 0000000..cd7f684 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/CloudStorageProvider.java @@ -0,0 +1,89 @@ +package com.gxwebsoft.app.service.cloud; + +import com.gxwebsoft.app.entity.AppResource; +import java.util.Map; + +/** + * 云存储 Provider 接口 + * 支持阿里云OSS、腾讯云COS、华为云OBS、七牛云等 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +public interface CloudStorageProvider { + + /** + * 获取 Provider 类型标识 + * @return aliyun/tencent/huawei/qiniu + */ + String getProviderType(); + + /** + * 测试凭证连接(不需要 bucket) + * 用于验证 accessKeyId/accessKeySecret 是否有效 + * @param credentials 云账号凭证(可能包含 accessKeyId/accessKeySecret 或 secretId/secretKey) + * @return 是否连接成功 + */ + boolean testConnection(Map credentials); + + /** + * 创建存储桶 + * @param resource 资源实体,包含 name(桶名)、region(地区)、acl(访问权限) + * @param credentials 云账号凭证 + * @throws Exception 创建失败时抛出 + */ + void createBucket(AppResource resource, Map credentials) throws Exception; + + /** + * 删除存储桶 + * @param resource 资源实体 + * @param credentials 云账号凭证 + * @throws Exception 删除失败时抛出 + */ + void deleteBucket(AppResource resource, Map credentials) throws Exception; + + /** + * 设置存储桶访问权限 + * @param resource 资源实体 + * @param acl 访问权限:public-read/private + * @param credentials 云账号凭证 + * @throws Exception 设置失败时抛出 + */ + void setBucketAcl(AppResource resource, String acl, Map credentials) throws Exception; + + /** + * 查询存储桶信息 + * @param resource 资源实体 + * @param credentials 云账号凭证 + * @return 存储桶信息,包含 usedBytes(已用空间)、objectCount(对象数量)等 + * @throws Exception 查询失败时抛出 + */ + Map getBucketInfo(AppResource resource, Map credentials) throws Exception; + + /** + * 获取存储桶访问地址(外网/内网) + * @param resource 资源实体 + * @param credentials 云账号凭证 + * @return 访问地址 + */ + String getBucketEndpoint(AppResource resource, Map credentials); + + /** + * 生成带签名的访问URL(针对私有桶) + * @param resource 资源实体 + * @param objectKey 对象Key + * @param expirySeconds 过期秒数 + * @param credentials 云账号凭证 + * @return 签名的URL + * @throws Exception 生成失败时抛出 + */ + String generateSignedUrl(AppResource resource, String objectKey, long expirySeconds, Map credentials) throws Exception; + + /** + * 检查存储桶是否存在 + * @param resource 资源实体 + * @param credentials 云账号凭证 + * @return 是否存在 + */ + boolean bucketExists(AppResource resource, Map credentials); +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/CloudStorageProviderFactory.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/CloudStorageProviderFactory.java new file mode 100644 index 0000000..d27a150 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/CloudStorageProviderFactory.java @@ -0,0 +1,71 @@ +package com.gxwebsoft.app.service.cloud; + +import com.gxwebsoft.app.service.cloud.impl.AliyunOSSProvider; +import com.gxwebsoft.app.service.cloud.impl.HuaweiOBSProvider; +import com.gxwebsoft.app.service.cloud.impl.QiniuKodoProvider; +import com.gxwebsoft.app.service.cloud.impl.TencentCOSProvider; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * 云存储 Provider 工厂 + * 根据 provider 类型返回对应的 Provider 实现 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +public class CloudStorageProviderFactory { + + /** Provider 实例缓存 */ + private static final Map PROVIDERS = new HashMap<>(); + + static { + // 注册所有 Provider + register(new AliyunOSSProvider()); + register(new TencentCOSProvider()); + register(new HuaweiOBSProvider()); + register(new QiniuKodoProvider()); + } + + /** + * 注册 Provider + */ + public static void register(CloudStorageProvider provider) { + PROVIDERS.put(provider.getProviderType(), provider); + log.info("注册云存储 Provider: {}", provider.getProviderType()); + } + + /** + * 获取 Provider 实例 + * @param providerType provider 类型: aliyun/tencent/huawei/qiniu + * @return Provider 实例 + */ + public static CloudStorageProvider getProvider(String providerType) { + CloudStorageProvider provider = PROVIDERS.get(providerType); + if (provider == null) { + throw new IllegalArgumentException("不支持的云存储 provider: " + providerType); + } + return provider; + } + + /** + * 获取所有支持的 Provider 类型 + */ + public static Map getSupportedProviders() { + Map result = new HashMap<>(); + for (Map.Entry entry : PROVIDERS.entrySet()) { + result.put(entry.getKey(), entry.getKey()); + } + return result; + } + + /** + * 检查是否支持指定 provider + */ + public static boolean isSupported(String providerType) { + return PROVIDERS.containsKey(providerType); + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/AliyunOSSProvider.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/AliyunOSSProvider.java new file mode 100644 index 0000000..a99b6b6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/AliyunOSSProvider.java @@ -0,0 +1,298 @@ +package com.gxwebsoft.app.service.cloud.impl; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.model.*; +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.service.cloud.CloudStorageProvider; +import lombok.extern.slf4j.Slf4j; + +import java.net.URL; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 阿里云 OSS Provider 实现 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +public class AliyunOSSProvider implements CloudStorageProvider { + + public static final String PROVIDER_TYPE = "aliyun"; + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public boolean testConnection(Map credentials) { + try { + // 获取 accessKeyId/accessKeySecret + String accessKeyId = credentials.get("accessKeyId"); + String accessKeySecret = credentials.get("accessKeySecret"); + if (accessKeyId == null || accessKeySecret == null) { + log.error("阿里云凭证缺少 accessKeyId 或 accessKeySecret"); + return false; + } + // 获取或构造 endpoint(优先使用配置中的,否则使用默认的) + String endpoint = credentials.get("endpoint"); + if (endpoint == null || endpoint.isEmpty()) { + endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; + } + // 尝试创建客户端并列出 bucket(验证凭证是否有效) + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); + try { + ossClient.listBuckets(); + log.info("阿里云 OSS 凭证验证成功"); + return true; + } finally { + ossClient.shutdown(); + } + } catch (Exception e) { + log.error("阿里云 OSS 凭证验证失败: {}", e.getMessage()); + return false; + } + } + + private OSS createClient(Map credentials) { + String accessKeyId = credentials.get("accessKeyId"); + String accessKeySecret = credentials.get("accessKeySecret"); + String endpoint = credentials.get("endpoint"); + + if (accessKeyId == null || accessKeySecret == null || endpoint == null) { + throw new IllegalArgumentException("阿里云 OSS 凭证缺少必要字段: accessKeyId, accessKeySecret, endpoint"); + } + + return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); + } + + @Override + public void createBucket(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + String region = resource.getRegion(); + + // 构建 endpoint: + // 如果 region 以 "oss-" 开头(如 oss-cn-shenzhen),直接拼接 + // 否则(如 ap-guangzhou),需要加 oss- 前缀 + String endpoint; + if (region != null && region.startsWith("oss-")) { + endpoint = "https://" + region + ".aliyuncs.com"; + } else { + endpoint = "https://oss-" + region + ".aliyuncs.com"; + } + + // 临时构造带 endpoint 的凭证 + Map creds = new HashMap<>(credentials); + // 强制覆盖 endpoint,避免 credentials 中有错误值 + creds.put("endpoint", endpoint); + + OSS ossClient = createClient(creds); + try { + // 检查是否已存在 + if (ossClient.doesBucketExist(bucketName)) { + log.info("存储桶 {} 已存在,跳过创建", bucketName); + return; + } + + // 创建存储桶 + CreateBucketRequest request = new CreateBucketRequest(bucketName); + // 设置 ACL + String acl = resource.getAcl(); + if ("public-read".equals(acl)) { + request.setCannedACL(CannedAccessControlList.PublicRead); + } else { + request.setCannedACL(CannedAccessControlList.Private); + } + + ossClient.createBucket(request); + log.info("阿里云 OSS 存储桶 {} 创建成功,地区: {},ACL: {}", bucketName, region, acl); + } finally { + ossClient.shutdown(); + } + } + + @Override + public void deleteBucket(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + String region = resource.getRegion(); + + // 构建 endpoint(同 createBucket) + String endpoint; + if (region != null && region.startsWith("oss-")) { + endpoint = "https://" + region + ".aliyuncs.com"; + } else { + endpoint = "https://oss-" + region + ".aliyuncs.com"; + } + Map creds = new HashMap<>(credentials); + creds.put("endpoint", endpoint); + + OSS ossClient = createClient(creds); + + try { + if (!ossClient.doesBucketExist(bucketName)) { + log.info("存储桶 {} 不存在,跳过删除", bucketName); + return; + } + + // 清空桶内所有对象 + String marker = ""; + int deleteCount = 0; + do { + ListObjectsRequest request = new ListObjectsRequest(bucketName); + request.setMaxKeys(1000); + if (!marker.isEmpty()) { + request.setMarker(marker); + } + ObjectListing listing = ossClient.listObjects(request); + + // 删除对象 + for (OSSObjectSummary summary : listing.getObjectSummaries()) { + ossClient.deleteObject(bucketName, summary.getKey()); + deleteCount++; + } + + marker = listing.getNextMarker(); + } while (marker != null && !marker.isEmpty()); + + log.info("存储桶 {} 对象已清空,共删除 {} 个对象", bucketName, deleteCount); + + // 再删除存储桶 + ossClient.deleteBucket(bucketName); + log.info("阿里云 OSS 存储桶 {} 删除成功", bucketName); + } finally { + ossClient.shutdown(); + } + } + + @Override + public void setBucketAcl(AppResource resource, String acl, Map credentials) throws Exception { + String bucketName = resource.getName(); + OSS ossClient = createClient(credentials); + + try { + if ("public-read".equals(acl)) { + ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead); + } else { + ossClient.setBucketAcl(bucketName, CannedAccessControlList.Private); + } + log.info("设置阿里云 OSS 存储桶 {} ACL 为 {}", bucketName, acl); + } finally { + ossClient.shutdown(); + } + } + + @Override + public Map getBucketInfo(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + // 构建 endpoint(同 createBucket) + String region = resource.getRegion(); + String endpoint; + if (region != null && region.startsWith("oss-")) { + endpoint = "https://" + region + ".aliyuncs.com"; + } else { + endpoint = "https://oss-" + region + ".aliyuncs.com"; + } + Map creds = new HashMap<>(credentials); + creds.put("endpoint", endpoint); + + OSS ossClient = createClient(creds); + Map result = new HashMap<>(); + + try { + // 获取存储桶元信息 + BucketInfo bucketInfo = ossClient.getBucketInfo(bucketName); + result.put("bucketName", bucketName); + result.put("region", resource.getRegion()); + result.put("createTime", bucketInfo.getBucket().getCreationDate()); + result.put("acl", bucketInfo.getCannedACL() != null ? bucketInfo.getCannedACL().toString() : "private"); + + // 获取存储量统计(需要先设置计量) + try { + // 获取存储量 + String marker = ""; + long totalSize = 0; + int objectCount = 0; + do { + ListObjectsRequest request = new ListObjectsRequest(bucketName); + request.setMaxKeys(1000); + if (!marker.isEmpty()) { + request.setMarker(marker); + } + ObjectListing listing = ossClient.listObjects(request); + for (OSSObjectSummary summary : listing.getObjectSummaries()) { + totalSize += summary.getSize(); + objectCount++; + } + marker = listing.getNextMarker(); + } while (marker != null && !marker.isEmpty()); + + result.put("usedBytes", totalSize); + result.put("objectCount", objectCount); + } catch (Exception e) { + log.warn("获取存储桶使用量失败: {}", e.getMessage()); + result.put("usedBytes", 0L); + result.put("objectCount", 0); + } + } finally { + ossClient.shutdown(); + } + + return result; + } + + @Override + public String getBucketEndpoint(AppResource resource, Map credentials) { + String region = resource.getRegion(); + String bucketName = resource.getName(); + + // 直接根据 resource 的 region 计算,不依赖 credentials + String domainPart; + if (region != null && region.startsWith("oss-")) { + // 用户选择了完整的 endpoint 格式,如 oss-cn-shenzhen + domainPart = region + ".aliyuncs.com"; + } else { + // 旧格式 + domainPart = "oss-" + region + ".aliyuncs.com"; + } + + // 外网 endpoint 格式: {bucket}.{domainPart} + return "https://" + bucketName + "." + domainPart; + } + + @Override + public String generateSignedUrl(AppResource resource, String objectKey, long expirySeconds, Map credentials) throws Exception { + String bucketName = resource.getName(); + OSS ossClient = createClient(credentials); + + try { + // 生成签名 URL + Date expiration = new Date(System.currentTimeMillis() + expirySeconds * 1000); + GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey); + request.setExpiration(expiration); + URL url = ossClient.generatePresignedUrl(request); + return url.toString(); + } finally { + ossClient.shutdown(); + } + } + + @Override + public boolean bucketExists(AppResource resource, Map credentials) { + String bucketName = resource.getName(); + try { + OSS ossClient = createClient(credentials); + try { + return ossClient.doesBucketExist(bucketName); + } finally { + ossClient.shutdown(); + } + } catch (Exception e) { + log.error("检查存储桶是否存在失败: {}", e.getMessage()); + return false; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/HuaweiOBSProvider.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/HuaweiOBSProvider.java new file mode 100644 index 0000000..caebaa4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/HuaweiOBSProvider.java @@ -0,0 +1,210 @@ +package com.gxwebsoft.app.service.cloud.impl; + +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.service.cloud.CloudStorageProvider; +import com.obs.services.ObsClient; +import com.obs.services.model.AccessControlList; +import com.obs.services.model.CreateBucketRequest; +import com.obs.services.model.GroupGrantee; +import com.obs.services.model.HttpMethodEnum; +import com.obs.services.model.Permission; +import com.obs.services.model.TemporarySignatureRequest; +import com.obs.services.model.TemporarySignatureResponse; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * 华为云 OBS Provider 实现 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +public class HuaweiOBSProvider implements CloudStorageProvider { + + public static final String PROVIDER_TYPE = "huawei"; + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public boolean testConnection(Map credentials) { + try { + // 兼容 accessKeyId/accessKeySecret 和 accessKey/secretKey + String ak = credentials.get("accessKey"); + String sk = credentials.get("secretKey"); + if (ak == null && credentials.get("accessKeyId") != null) { + ak = credentials.get("accessKeyId"); + } + if (sk == null && credentials.get("accessKeySecret") != null) { + sk = credentials.get("accessKeySecret"); + } + if (ak == null || sk == null) { + log.error("华为云 OBS 凭证缺少 accessKey/accessKeyId 或 secretKey/accessKeySecret"); + return false; + } + // 获取或构造 endpoint + String endpoint = credentials.get("endpoint"); + if (endpoint == null || endpoint.isEmpty()) { + endpoint = "https://obs.cn-south-1.myhuaweicloud.com"; + } + // 尝试创建客户端并列出 bucket(验证凭证是否有效) + try (ObsClient obsClient = new ObsClient(ak, sk, endpoint)) { + obsClient.listBuckets(); + log.info("华为云 OBS 凭证验证成功"); + return true; + } + } catch (Exception e) { + log.error("华为云 OBS 凭证验证失败: {}", e.getMessage()); + return false; + } + } + + private ObsClient createClient(Map credentials) { + // 兼容 accessKeyId/accessKeySecret 和 accessKey/secretKey + String ak = credentials.get("accessKey"); + String sk = credentials.get("secretKey"); + if (ak == null && credentials.get("accessKeyId") != null) { + ak = credentials.get("accessKeyId"); + } + if (sk == null && credentials.get("accessKeySecret") != null) { + sk = credentials.get("accessKeySecret"); + } + String endpoint = credentials.get("endpoint"); + + if (ak == null || sk == null || endpoint == null) { + throw new IllegalArgumentException("华为云 OBS 凭证缺少必要字段: accessKey/accessKeyId, secretKey/accessKeySecret, endpoint"); + } + + return new ObsClient(ak, sk, endpoint); + } + + @Override + public void createBucket(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + String region = resource.getRegion(); + + ObsClient obsClient = createClient(credentials); + try { + // 检查是否已存在 + if (obsClient.headBucket(bucketName)) { + log.info("存储桶 {} 已存在,跳过创建", bucketName); + return; + } + + // 创建存储桶 + CreateBucketRequest request = new CreateBucketRequest(); + request.setBucketName(bucketName); + request.setLocation(region); + + obsClient.createBucket(request); + log.info("华为云 OBS 存储桶 {} 创建成功,地区: {}", bucketName, region); + + // 设置 ACL + setAclInternal(obsClient, resource); + } finally { + obsClient.close(); + } + } + + @Override + public void deleteBucket(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + ObsClient obsClient = createClient(credentials); + + try { + if (!obsClient.headBucket(bucketName)) { + log.info("存储桶 {} 不存在,跳过删除", bucketName); + return; + } + + // 删除存储桶(需要先清空桶内对象) + obsClient.deleteBucket(bucketName); + log.info("华为云 OBS 存储桶 {} 删除成功", bucketName); + } finally { + obsClient.close(); + } + } + + @Override + public void setBucketAcl(AppResource resource, String acl, Map credentials) throws Exception { + ObsClient obsClient = createClient(credentials); + try { + setAclInternal(obsClient, resource); + } finally { + obsClient.close(); + } + } + + private void setAclInternal(ObsClient obsClient, AppResource resource) throws Exception { + String bucketName = resource.getName(); + String acl = resource.getAcl(); + + AccessControlList accessControlList = new AccessControlList(); + if ("public-read".equals(acl)) { + accessControlList.grantPermission(GroupGrantee.ALL_USERS, Permission.PERMISSION_READ); + } else { + // 私有:移除所有用户的读取权限 + accessControlList.grantPermission(GroupGrantee.ALL_USERS, Permission.PERMISSION_FULL_CONTROL, false); + } + + obsClient.setBucketAcl(bucketName, accessControlList); + log.info("设置华为云 OBS 存储桶 {} ACL 为 {}", bucketName, acl); + } + + @Override + public Map getBucketInfo(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + ObsClient obsClient = createClient(credentials); + Map result = new HashMap<>(); + + try { + result.put("bucketName", bucketName); + result.put("region", resource.getRegion()); + result.put("usedBytes", 0L); + result.put("objectCount", 0); + } finally { + obsClient.close(); + } + + return result; + } + + @Override + public String getBucketEndpoint(AppResource resource, Map credentials) { + String region = resource.getRegion(); + String bucketName = resource.getName(); + + // 外网 endpoint: https://{bucket}.obs.{region}.myhuaweicloud.com + return "https://" + bucketName + ".obs." + region + ".myhuaweicloud.com"; + } + + @Override + public String generateSignedUrl(AppResource resource, String objectKey, long expirySeconds, Map credentials) throws Exception { + String bucketName = resource.getName(); + + TemporarySignatureRequest request = new TemporarySignatureRequest(); + request.setMethod(HttpMethodEnum.GET); + request.setBucketName(bucketName); + request.setObjectKey(objectKey); + request.setExpires((int) expirySeconds); + + TemporarySignatureResponse response = createClient(credentials).createTemporarySignature(request); + return response.getSignedUrl(); + } + + @Override + public boolean bucketExists(AppResource resource, Map credentials) { + String bucketName = resource.getName(); + try (ObsClient obsClient = createClient(credentials)) { + return obsClient.headBucket(bucketName); + } catch (Exception e) { + log.error("检查存储桶是否存在失败: {}", e.getMessage()); + return false; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/QiniuKodoProvider.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/QiniuKodoProvider.java new file mode 100644 index 0000000..97ac0ff --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/QiniuKodoProvider.java @@ -0,0 +1,160 @@ +package com.gxwebsoft.app.service.cloud.impl; + +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.service.cloud.CloudStorageProvider; +import com.qiniu.storage.BucketManager; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.model.BucketInfo; +import com.qiniu.util.Auth; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * 七牛云 Kodo Provider 实现 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +public class QiniuKodoProvider implements CloudStorageProvider { + + public static final String PROVIDER_TYPE = "qiniu"; + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public boolean testConnection(Map credentials) { + try { + // 兼容 accessKeyId/accessKeySecret 和 accessKey/secretKey + String accessKey = credentials.get("accessKey"); + String secretKey = credentials.get("secretKey"); + if (accessKey == null && credentials.get("accessKeyId") != null) { + accessKey = credentials.get("accessKeyId"); + } + if (secretKey == null && credentials.get("accessKeySecret") != null) { + secretKey = credentials.get("accessKeySecret"); + } + if (accessKey == null || secretKey == null) { + log.error("七牛云凭证缺少 accessKey/accessKeyId 或 secretKey/accessKeySecret"); + return false; + } + // 尝试创建凭证并列出 bucket(验证凭证是否有效) + Configuration config = new Configuration(); + Auth auth = Auth.create(accessKey, secretKey); + BucketManager bucketManager = new BucketManager(auth, config); + bucketManager.buckets(); + log.info("七牛云凭证验证成功"); + return true; + } catch (Exception e) { + log.error("七牛云凭证验证失败: {}", e.getMessage()); + return false; + } + } + + private BucketManager createClient(Map credentials) { + // 兼容 accessKeyId/accessKeySecret 和 accessKey/secretKey + String accessKey = credentials.get("accessKey"); + String secretKey = credentials.get("secretKey"); + if (accessKey == null && credentials.get("accessKeyId") != null) { + accessKey = credentials.get("accessKeyId"); + } + if (secretKey == null && credentials.get("accessKeySecret") != null) { + secretKey = credentials.get("accessKeySecret"); + } + + if (accessKey == null || secretKey == null) { + throw new IllegalArgumentException("七牛云凭证缺少必要字段: accessKey/accessKeyId, secretKey/accessKeySecret"); + } + + Configuration config = new Configuration(); + // 构造凭证 + Auth auth = Auth.create(accessKey, secretKey); + + return new BucketManager(auth, config); + } + + @Override + public void createBucket(AppResource resource, Map credentials) throws Exception { + // 七牛云存储空间需要通过控制台或 API 创建 + // 这里只记录元数据,不实际创建 + log.info("七牛云存储桶 {} 创建成功(仅记录元数据,实际创建需在控制台操作)", resource.getName()); + } + + @Override + public void deleteBucket(AppResource resource, Map credentials) throws Exception { + // 七牛云不支持通过 API 删除存储桶,只删除记录 + log.info("七牛云存储桶 {} 删除(仅删除记录,实际删除需在控制台操作)", resource.getName()); + } + + @Override + public void setBucketAcl(AppResource resource, String acl, Map credentials) throws Exception { + // 七牛云 ACL 通过管理后台设置或上传时指定 + log.info("七牛云存储桶 {} ACL 设置: {}(实际操作需通过管理后台)", resource.getName(), acl); + } + + @Override + public Map getBucketInfo(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + BucketManager bucketManager = createClient(credentials); + Map result = new HashMap<>(); + + try { + // 获取存储桶信息 + BucketInfo bucketInfo = bucketManager.getBucketInfo(bucketName); + result.put("bucketName", bucketName); + result.put("region", resource.getRegion()); + result.put("info", bucketInfo); + result.put("usedBytes", 0L); + result.put("objectCount", 0); + } catch (Exception e) { + log.warn("获取七牛云存储桶信息失败: {}", e.getMessage()); + result.put("bucketName", bucketName); + result.put("region", resource.getRegion()); + result.put("usedBytes", 0L); + result.put("objectCount", 0); + } + + return result; + } + + @Override + public String getBucketEndpoint(AppResource resource, Map credentials) { + String bucketName = resource.getName(); + String region = resource.getRegion(); + + // 七牛云需要自定义域名,暂用默认格式 + return "https://" + bucketName + ".qiniucs.com"; + } + + @Override + public String generateSignedUrl(AppResource resource, String objectKey, long expirySeconds, Map credentials) throws Exception { + String bucketName = resource.getName(); + + // 生成私有空间签名访问链接 + String domain = getBucketEndpoint(resource, credentials); + String url = domain + "/" + objectKey; + + // 七牛云需要使用 auth.privateDownloadUrl 生成签名 URL + String accessKey = credentials.get("accessKey"); + String secretKey = credentials.get("secretKey"); + Auth auth = Auth.create(accessKey, secretKey); + + return auth.privateDownloadUrl(url, expirySeconds); + } + + @Override + public boolean bucketExists(AppResource resource, Map credentials) { + try { + BucketManager bucketManager = createClient(credentials); + bucketManager.getBucketInfo(resource.getName()); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/TencentCOSProvider.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/TencentCOSProvider.java new file mode 100644 index 0000000..9ddeb19 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/cloud/impl/TencentCOSProvider.java @@ -0,0 +1,215 @@ +package com.gxwebsoft.app.service.cloud.impl; + +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.service.cloud.CloudStorageProvider; +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.model.*; +import com.qcloud.cos.region.Region; +import lombok.extern.slf4j.Slf4j; + +import java.net.URL; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 腾讯云 COS Provider 实现 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +public class TencentCOSProvider implements CloudStorageProvider { + + public static final String PROVIDER_TYPE = "tencent"; + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public boolean testConnection(Map credentials) { + try { + // 兼容 accessKeyId/accessKeySecret 和 secretId/secretKey + String secretId = credentials.get("secretId"); + String secretKey = credentials.get("secretKey"); + if (secretId == null && credentials.get("accessKeyId") != null) { + secretId = credentials.get("accessKeyId"); + } + if (secretKey == null && credentials.get("accessKeySecret") != null) { + secretKey = credentials.get("accessKeySecret"); + } + if (secretId == null || secretKey == null) { + log.error("腾讯云 COS 凭证缺少 secretId/accessKeyId 或 secretKey/accessKeySecret"); + return false; + } + // 获取或使用默认 region + String region = credentials.get("region"); + if (region == null || region.isEmpty()) { + region = "ap-guangzhou"; + } + // 尝试创建客户端并列出 bucket(验证凭证是否有效) + COSCredentials cosCredentials = new BasicCOSCredentials(secretId, secretKey); + ClientConfig clientConfig = new ClientConfig(new Region(region)); + COSClient cosClient = new COSClient(cosCredentials, clientConfig); + try { + cosClient.listBuckets(); + log.info("腾讯云 COS 凭证验证成功"); + return true; + } finally { + cosClient.shutdown(); + } + } catch (Exception e) { + log.error("腾讯云 COS 凭证验证失败: {}", e.getMessage()); + return false; + } + } + + private COSClient createClient(Map credentials) { + // 兼容 accessKeyId/accessKeySecret 和 secretId/secretKey + String secretId = credentials.get("secretId"); + String secretKey = credentials.get("secretKey"); + if (secretId == null && credentials.get("accessKeyId") != null) { + secretId = credentials.get("accessKeyId"); + } + if (secretKey == null && credentials.get("accessKeySecret") != null) { + secretKey = credentials.get("accessKeySecret"); + } + String region = credentials.get("region"); + + if (secretId == null || secretKey == null || region == null) { + throw new IllegalArgumentException("腾讯云 COS 凭证缺少必要字段: secretId/accessKeyId, secretKey/accessKeySecret, region"); + } + + // 设置凭证 + COSCredentials cosCredentials = new BasicCOSCredentials(secretId, secretKey); + + // 设置地域 + ClientConfig clientConfig = new ClientConfig(new Region(region)); + + return new COSClient(cosCredentials, clientConfig); + } + + @Override + public void createBucket(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + String region = resource.getRegion(); + + COSClient cosClient = createClient(credentials); + try { + // 检查是否已存在 + if (cosClient.doesBucketExist(bucketName)) { + log.info("存储桶 {} 已存在,跳过创建", bucketName); + return; + } + + // 创建存储桶 + CreateBucketRequest request = new CreateBucketRequest(bucketName); + // 设置 ACL + String acl = resource.getAcl(); + if ("public-read".equals(acl)) { + request.setCannedAcl(CannedAccessControlList.PublicRead); + } else { + request.setCannedAcl(CannedAccessControlList.Private); + } + + cosClient.createBucket(request); + log.info("腾讯云 COS 存储桶 {} 创建成功,地区: {},ACL: {}", bucketName, region, acl); + } finally { + cosClient.shutdown(); + } + } + + @Override + public void deleteBucket(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + COSClient cosClient = createClient(credentials); + + try { + if (!cosClient.doesBucketExist(bucketName)) { + log.info("存储桶 {} 不存在,跳过删除", bucketName); + return; + } + + // 删除存储桶(需要先清空桶内对象) + cosClient.deleteBucket(bucketName); + log.info("腾讯云 COS 存储桶 {} 删除成功", bucketName); + } finally { + cosClient.shutdown(); + } + } + + @Override + public void setBucketAcl(AppResource resource, String acl, Map credentials) throws Exception { + String bucketName = resource.getName(); + COSClient cosClient = createClient(credentials); + + try { + // 设置 ACL + if ("public-read".equals(acl)) { + cosClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead); + } else { + cosClient.setBucketAcl(bucketName, CannedAccessControlList.Private); + } + log.info("设置腾讯云 COS 存储桶 {} ACL 为 {}", bucketName, acl); + } finally { + cosClient.shutdown(); + } + } + + @Override + public Map getBucketInfo(AppResource resource, Map credentials) throws Exception { + String bucketName = resource.getName(); + COSClient cosClient = createClient(credentials); + Map result = new HashMap<>(); + + try { + result.put("bucketName", bucketName); + result.put("region", resource.getRegion()); + result.put("usedBytes", 0L); + result.put("objectCount", 0); + } finally { + cosClient.shutdown(); + } + + return result; + } + + @Override + public String getBucketEndpoint(AppResource resource, Map credentials) { + String region = resource.getRegion(); + String bucketName = resource.getName(); + + // 外网 endpoint 格式: {bucket}.cos.{region}.myqcloud.com + return "https://" + bucketName + ".cos." + region + ".myqcloud.com"; + } + + @Override + public String generateSignedUrl(AppResource resource, String objectKey, long expirySeconds, Map credentials) throws Exception { + String bucketName = resource.getName(); + + Date expirationDate = new Date(System.currentTimeMillis() + expirySeconds * 1000); + URL url = createClient(credentials).generatePresignedUrl(bucketName, objectKey, expirationDate); + return url.toString(); + } + + @Override + public boolean bucketExists(AppResource resource, Map credentials) { + String bucketName = resource.getName(); + try { + COSClient cosClient = createClient(credentials); + try { + return cosClient.doesBucketExist(bucketName); + } finally { + cosClient.shutdown(); + } + } catch (Exception e) { + log.error("检查存储桶是否存在失败: {}", e.getMessage()); + return false; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppApiKeyServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppApiKeyServiceImpl.java new file mode 100644 index 0000000..466eafe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppApiKeyServiceImpl.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppApiKey; +import com.gxwebsoft.app.mapper.AppApiKeyMapper; +import com.gxwebsoft.app.param.AppApiKeyParam; +import com.gxwebsoft.app.service.AppApiKeyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.security.SecureRandom; +import java.time.LocalDateTime; +import java.util.*; + +/** + * 应用 API Key 服务实现 + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Slf4j +@Service +public class AppApiKeyServiceImpl + extends ServiceImpl + implements AppApiKeyService { + + private static final String KEY_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final String KEY_PREFIX = "sk-"; + private static final int KEY_LENGTH = 48; + private static final SecureRandom RANDOM = new SecureRandom(); + + @Override + public IPage pageRel(AppApiKeyParam param) { + Page page = new Page<>(param.getPage(), param.getLimit()); + return baseMapper.selectPageRel(page, param); + } + + @Override + public List listRel(AppApiKeyParam param) { + return baseMapper.selectListRel(param); + } + + @Override + public AppApiKey getByIdRel(Long id) { + return baseMapper.selectByIdRel(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AppApiKey createApiKey(AppApiKey apiKey, Integer userId, Integer tenantId) { + // 生成 API Key + String rawKey = generateRawKey(); + String encryptedKey = encryptKey(rawKey); + String prefix = KEY_PREFIX + rawKey.substring(0, 8); + + apiKey.setApiKey(encryptedKey); + apiKey.setKeyPrefix(prefix); + apiKey.setUserId(userId); + apiKey.setTenantId(tenantId); + apiKey.setStatus(0); // 默认正常 + apiKey.setUsageCount(0L); + apiKey.setCreateTime(LocalDateTime.now()); + apiKey.setUpdateTime(LocalDateTime.now()); + + this.save(apiKey); + log.info("创建API Key成功: userId={}, name={}", userId, apiKey.getName()); + return apiKey; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateApiKey(AppApiKey apiKey) { + apiKey.setApiKey(null); // 不允许通过此接口修改密钥 + apiKey.setKeyPrefix(null); + apiKey.setUserId(null); + apiKey.setUpdateTime(LocalDateTime.now()); + return this.updateById(apiKey); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateStatus(Long id, Integer status, Integer userId) { + AppApiKey apiKey = this.getById(id); + if (apiKey == null) { + throw new RuntimeException("API Key不存在"); + } + if (!apiKey.getUserId().equals(userId)) { + throw new RuntimeException("无权操作此API Key"); + } + apiKey.setStatus(status); + apiKey.setUpdateTime(LocalDateTime.now()); + return this.updateById(apiKey); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeApiKey(Long id, Integer userId) { + AppApiKey apiKey = this.getById(id); + if (apiKey == null) { + throw new RuntimeException("API Key不存在"); + } + if (!apiKey.getUserId().equals(userId)) { + throw new RuntimeException("无权删除此API Key"); + } + return this.removeById(id); + } + + @Override + public Map statsByUser(Integer userId, Integer tenantId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppApiKey::getUserId, userId); + wrapper.eq(AppApiKey::getTenantId, tenantId); + + List keys = this.list(wrapper); + long total = keys.size(); + long active = keys.stream().filter(k -> k.getStatus() != null && k.getStatus() == 0).count(); + long expired = keys.stream().filter(k -> k.getExpireTime() != null + && k.getExpireTime().isBefore(LocalDateTime.now())).count(); + long disabled = keys.stream().filter(k -> k.getStatus() != null && k.getStatus() == 1).count(); + long totalUsage = keys.stream() + .filter(k -> k.getUsageCount() != null) + .mapToLong(AppApiKey::getUsageCount) + .sum(); + + Map stats = new HashMap<>(); + stats.put("total", total); + stats.put("active", active); + stats.put("expired", expired); + stats.put("disabled", disabled); + stats.put("totalUsage", totalUsage); + return stats; + } + + /** + * 生成原始密钥 + */ + private String generateRawKey() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < KEY_LENGTH; i++) { + sb.append(KEY_CHARS.charAt(RANDOM.nextInt(KEY_CHARS.length()))); + } + return sb.toString(); + } + + /** + * 加密密钥(实际项目中应使用更强的加密算法) + * 这里简单处理,实际生产环境应使用 AES 或其他加密方式 + */ + private String encryptKey(String rawKey) { + // 这里暂时返回原始值,实际生产环境需要加密存储 + // 存储时使用 Base64 简单编码便于后续扩展 + return Base64.getEncoder().encodeToString(rawKey.getBytes()); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppArticleCategoryServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppArticleCategoryServiceImpl.java new file mode 100644 index 0000000..b324637 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppArticleCategoryServiceImpl.java @@ -0,0 +1,156 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppArticle; +import com.gxwebsoft.app.entity.AppArticleCategory; +import com.gxwebsoft.app.mapper.AppArticleCategoryMapper; +import com.gxwebsoft.app.mapper.AppArticleMapper; +import com.gxwebsoft.app.param.AppArticleCategoryParam; +import com.gxwebsoft.app.service.AppArticleCategoryService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 平台文章分类服务实现 + */ +@Service +public class AppArticleCategoryServiceImpl extends ServiceImpl implements AppArticleCategoryService { + + @Resource + private AppArticleMapper appArticleMapper; + + @Override + public PageResult page(AppArticleCategoryParam param) { + long current = param.getPage() != null ? param.getPage() : 1L; + long size = param.getLimit() != null ? param.getLimit() : 10L; + Page page = new Page<>(current, size); + LambdaQueryWrapper wrapper = buildWrapper(param); + baseMapper.selectPage(page, wrapper); + List records = fillArticleCount(page.getRecords()); + return new PageResult<>(records, page.getTotal()); + } + + @Override + public List list(AppArticleCategoryParam param) { + return fillArticleCount(baseMapper.selectList(buildWrapper(param))); + } + + @Override + public AppArticleCategory getDetail(Integer categoryId) { + AppArticleCategory category = getById(categoryId); + if (category == null) { + return null; + } + return fillArticleCount(List.of(category)).stream().findFirst().orElse(category); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean saveCategory(AppArticleCategory category, User loginUser, Integer tenantId) { + if (category == null || StrUtil.isBlank(category.getTitle())) { + return false; + } + category.setParentId(category.getParentId() == null ? 0 : category.getParentId()); + category.setType(category.getType() == null ? 0 : category.getType()); + category.setSortNumber(category.getSortNumber() == null ? 0 : category.getSortNumber()); + category.setStatus(category.getStatus() == null ? 0 : category.getStatus()); + category.setHide(category.getHide() == null ? 0 : category.getHide()); + category.setRecommend(category.getRecommend() == null ? 0 : category.getRecommend()); + category.setShowIndex(category.getShowIndex() == null ? 0 : category.getShowIndex()); + category.setTenantId(tenantId); + category.setCreateTime(LocalDateTime.now()); + category.setUpdateTime(LocalDateTime.now()); + if (loginUser != null) { + category.setUserId(loginUser.getUserId()); + } + return save(category); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateCategory(AppArticleCategory category) { + if (category == null || category.getCategoryId() == null) { + return false; + } + AppArticleCategory exists = getById(category.getCategoryId()); + if (exists == null) { + return false; + } + category.setUpdateTime(LocalDateTime.now()); + return updateById(category); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeCategory(Integer categoryId) { + long articleCount = appArticleMapper.selectCount(new LambdaQueryWrapper() + .eq(AppArticle::getCategoryId, categoryId)); + if (articleCount > 0) { + return false; + } + return removeById(categoryId); + } + + private LambdaQueryWrapper buildWrapper(AppArticleCategoryParam param) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (param == null) { + return wrapper.orderByAsc(AppArticleCategory::getSortNumber) + .orderByDesc(AppArticleCategory::getCategoryId); + } + wrapper.eq(param.getCategoryId() != null, AppArticleCategory::getCategoryId, param.getCategoryId()) + .eq(param.getStatus() != null, AppArticleCategory::getStatus, param.getStatus()) + .eq(param.getTenantId() != null, AppArticleCategory::getTenantId, param.getTenantId()) + .and(StrUtil.isNotBlank(param.getKeywords()), w -> w + .like(AppArticleCategory::getTitle, param.getKeywords()) + .or() + .like(AppArticleCategory::getCategoryCode, param.getKeywords()) + .or() + .like(AppArticleCategory::getPath, param.getKeywords())) + .orderByAsc(AppArticleCategory::getSortNumber) + .orderByDesc(AppArticleCategory::getCategoryId); + return wrapper; + } + + private List fillArticleCount(List list) { + if (list == null || list.isEmpty()) { + return list; + } + List categoryIds = list.stream() + .map(AppArticleCategory::getCategoryId) + .filter(id -> id != null && id > 0) + .collect(Collectors.toList()); + if (categoryIds.isEmpty()) { + return list; + } + QueryWrapper countWrapper = new QueryWrapper<>(); + countWrapper.select("category_id", "COUNT(*) AS article_count") + .in("category_id", categoryIds) + .groupBy("category_id"); + Integer tenantId = list.get(0).getTenantId(); + if (tenantId != null) { + countWrapper.eq("tenant_id", tenantId); + } + Map countMap = new HashMap<>(); + appArticleMapper.selectMaps(countWrapper).forEach(item -> { + Object categoryId = item.get("category_id"); + Object articleCount = item.get("article_count"); + if (categoryId != null && articleCount != null) { + countMap.put(Integer.parseInt(String.valueOf(categoryId)), Integer.parseInt(String.valueOf(articleCount))); + } + }); + return list.stream().peek(item -> item.setCount(countMap.getOrDefault(item.getCategoryId(), 0))).collect(Collectors.toList()); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppArticleServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppArticleServiceImpl.java new file mode 100644 index 0000000..88f1f6f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppArticleServiceImpl.java @@ -0,0 +1,209 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppArticle; +import com.gxwebsoft.app.entity.AppArticleCategory; +import com.gxwebsoft.app.mapper.AppArticleCategoryMapper; +import com.gxwebsoft.app.mapper.AppArticleMapper; +import com.gxwebsoft.app.param.AppArticleParam; +import com.gxwebsoft.app.service.AppArticleService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 平台文章服务实现 + */ +@Service +public class AppArticleServiceImpl extends ServiceImpl implements AppArticleService { + + private static final String DEFAULT_MODEL = "article"; + + @Resource + private AppArticleCategoryMapper appArticleCategoryMapper; + + @Override + public PageResult page(AppArticleParam param) { + long current = param.getPage() != null ? param.getPage() : 1L; + long size = param.getLimit() != null ? param.getLimit() : 10L; + Page page = new Page<>(current, size); + LambdaQueryWrapper wrapper = buildWrapper(param); + baseMapper.selectPage(page, wrapper); + List records = fillCategoryInfo(page.getRecords()); + return new PageResult<>(records, page.getTotal()); + } + + @Override + public List list(AppArticleParam param) { + return fillCategoryInfo(baseMapper.selectList(buildWrapper(param))); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AppArticle getDetail(Integer articleId, boolean increaseViews) { + AppArticle article = baseMapper.selectById(articleId); + if (article == null) { + return null; + } + if (increaseViews) { + AppArticle update = new AppArticle(); + update.setArticleId(articleId); + update.setActualViews((article.getActualViews() == null ? 0 : article.getActualViews()) + 1); + update.setUpdateTime(LocalDateTime.now()); + updateById(update); + article.setActualViews(update.getActualViews()); + } + return fillCategoryInfo(Collections.singletonList(article)).stream().findFirst().orElse(article); + } + + @Override + public AppArticle getByCode(String code) { + if (StrUtil.isBlank(code)) { + return null; + } + AppArticle article = getOne(new LambdaQueryWrapper() + .eq(AppArticle::getCode, code) + .last("limit 1")); + if (article == null) { + return null; + } + return fillCategoryInfo(Collections.singletonList(article)).stream().findFirst().orElse(article); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean saveArticle(AppArticle article, User loginUser, Integer tenantId) { + if (article == null || StrUtil.isBlank(article.getTitle())) { + return false; + } + article.setModel(StrUtil.blankToDefault(article.getModel(), DEFAULT_MODEL)); + article.setCode(StrUtil.blankToDefault(article.getCode(), generateCode(article.getModel()))); + article.setType(article.getType() == null ? 0 : article.getType()); + article.setActualViews(article.getActualViews() == null ? 0 : article.getActualViews()); + article.setLikes(article.getLikes() == null ? 0 : article.getLikes()); + article.setRecommend(article.getRecommend() == null ? 0 : article.getRecommend()); + article.setSortNumber(article.getSortNumber() == null ? 0 : article.getSortNumber()); + article.setStatus(article.getStatus() == null ? 1 : article.getStatus()); + article.setTenantId(tenantId); + article.setCreateTime(LocalDateTime.now()); + article.setUpdateTime(LocalDateTime.now()); + if (loginUser != null) { + article.setUserId(loginUser.getUserId()); + if (StrUtil.isBlank(article.getAuthor())) { + article.setAuthor(StrUtil.blankToDefault(loginUser.getNickname(), loginUser.getUsername())); + } + } + return save(article); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateArticle(AppArticle article) { + if (article == null || article.getArticleId() == null) { + return false; + } + AppArticle exists = getById(article.getArticleId()); + if (exists == null) { + return false; + } + if (StrUtil.isBlank(article.getModel())) { + article.setModel(exists.getModel()); + } + if (StrUtil.isBlank(article.getCode())) { + article.setCode(exists.getCode()); + } + if (article.getType() == null) { + article.setType(exists.getType()); + } + article.setUpdateTime(LocalDateTime.now()); + return updateById(article); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeArticle(Integer articleId) { + return removeById(articleId); + } + + @Override + public Map getStats(AppArticleParam param) { + Map data = new HashMap<>(); + LambdaQueryWrapper base = buildWrapper(param); + data.put("totalNum", Math.toIntExact(count(base))); + data.put("publishedNum", Math.toIntExact(count(buildWrapper(param).eq(AppArticle::getStatus, 0)))); + data.put("recommendNum", Math.toIntExact(count(buildWrapper(param).eq(AppArticle::getRecommend, 1)))); + return data; + } + + private LambdaQueryWrapper buildWrapper(AppArticleParam param) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (param == null) { + return wrapper.orderByDesc(AppArticle::getRecommend) + .orderByAsc(AppArticle::getSortNumber) + .orderByDesc(AppArticle::getCreateTime); + } + wrapper.eq(param.getArticleId() != null, AppArticle::getArticleId, param.getArticleId()) + .eq(StrUtil.isNotBlank(param.getModel()), AppArticle::getModel, param.getModel()) + .eq(param.getStatus() != null, AppArticle::getStatus, param.getStatus()) + .eq(param.getCategoryId() != null, AppArticle::getCategoryId, param.getCategoryId()) + .eq(param.getRecommend() != null, AppArticle::getRecommend, param.getRecommend()) + .eq(param.getTenantId() != null, AppArticle::getTenantId, param.getTenantId()) + .and(StrUtil.isNotBlank(param.getKeywords()), w -> w + .like(AppArticle::getTitle, param.getKeywords()) + .or() + .like(AppArticle::getOverview, param.getKeywords()) + .or() + .like(AppArticle::getAuthor, param.getKeywords()) + .or() + .like(AppArticle::getCode, param.getKeywords())) + .orderByDesc(AppArticle::getRecommend) + .orderByAsc(AppArticle::getSortNumber) + .orderByDesc(AppArticle::getCreateTime); + return wrapper; + } + + private List fillCategoryInfo(List list) { + if (list == null || list.isEmpty()) { + return list; + } + Set categoryIds = list.stream() + .map(AppArticle::getCategoryId) + .filter(ObjectUtil::isNotNull) + .collect(Collectors.toSet()); + if (categoryIds.isEmpty()) { + return list; + } + Map categoryMap = appArticleCategoryMapper.selectBatchIds(categoryIds) + .stream() + .collect(Collectors.toMap(AppArticleCategory::getCategoryId, item -> item, (a, b) -> a)); + list.forEach(item -> { + AppArticleCategory category = categoryMap.get(item.getCategoryId()); + if (category != null) { + item.setCategoryName(category.getTitle()); + item.setParentId(category.getParentId()); + } + }); + return list; + } + + private String generateCode(String model) { + String prefix = "announcement".equalsIgnoreCase(model) ? "ANN" : "ART"; + return prefix + IdUtil.getSnowflakeNextId(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppBuildServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppBuildServiceImpl.java new file mode 100644 index 0000000..5f933d2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppBuildServiceImpl.java @@ -0,0 +1,321 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppBuild; +import com.gxwebsoft.app.entity.AppPipeline; +import com.gxwebsoft.app.mapper.AppBuildMapper; +import com.gxwebsoft.app.param.AppBuildParam; +import com.gxwebsoft.app.service.AppBuildService; +import com.gxwebsoft.app.service.AppPipelineService; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * CI/CD 构建记录 Service 实现 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Service +public class AppBuildServiceImpl extends ServiceImpl implements AppBuildService { + + @Value("${config.gitea-url:https://git.websoft.top}") + private String giteaUrl; + + @Value("${config.gitea-token:}") + private String giteaToken; + + @Resource + private AppPipelineService appPipelineService; + + @Override + public PageResult pageBuild(AppBuildParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectBuildList(param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public AppBuild getBuildDetail(Long id) { + return baseMapper.selectBuildDetail(id); + } + + @Override + public AppBuild getLatestBuild(Long appId) { + return baseMapper.selectLatestBuild(appId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AppBuild triggerBuild(Long appId, String branch, Integer triggeredBy) { + // 1. 查询应用对应的流水线 + AppPipeline pipeline = appPipelineService.getOne( + new LambdaQueryWrapper() + .eq(AppPipeline::getAppId, appId) + .eq(AppPipeline::getEnabled, true) + .last("LIMIT 1") + ); + + if (pipeline == null) { + throw new RuntimeException("未找到可用的CI/CD流水线配置,请先配置流水线"); + } + + // 2. 创建构建记录 + AppBuild build = new AppBuild(); + build.setAppId(appId); + build.setName("构建 #" + System.currentTimeMillis()); + build.setBranch(branch != null ? branch : pipeline.getDefaultBranch()); + build.setCiType(pipeline.getCiType()); + build.setCiApiUrl(giteaUrl); + build.setStatus("pending"); + build.setTriggerType("manual"); + build.setTriggeredBy(triggeredBy); + build.setUserId(triggeredBy); + build.setCreateTime(LocalDateTime.now()); + + // 3. 调用 Gitea CI 触发构建 + try { + String result = triggerGiteaAction(pipeline, branch); + if (result != null) { + JSONObject json = JSONUtil.parseObj(result); + build.setCiJobId(json.getStr("workflow_id")); + build.setCiRunId(json.getStr("run_id")); + build.setBuildNumber(json.getStr("run_number", "MANUAL-" + System.currentTimeMillis())); + } + } catch (Exception e) { + log.error("触发Gitea构建失败: {}", e.getMessage()); + build.setStatus("failed"); + build.setErrorMessage("触发CI失败: " + e.getMessage()); + } + + save(build); + + // 4. 更新流水线的最后构建信息 + updatePipelineLastBuild(pipeline.getId(), build.getId(), build.getStatus()); + + return build; + } + + @Override + public String getBuildLog(Long buildId) { + AppBuild build = getById(buildId); + if (build == null) { + throw new RuntimeException("构建记录不存在"); + } + + if (!"gitea".equals(build.getCiType())) { + return "当前构建类型不支持日志查看"; + } + + try { + String url = String.format("%s/api/v1/repos/%s/actions/runs/%s/jobs", + giteaUrl, build.getCiJobId(), build.getCiRunId()); + + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + giteaToken); + headers.put("Content-Type", "application/json"); + + String response = HttpUtil.createGet(url) + .headerMap(headers, true) + .timeout(30000) + .execute() + .body(); + + if (response != null) { + JSONObject json = JSONUtil.parseObj(response); + // 返回简化日志 + StringBuilder logBuilder = new StringBuilder(); + logBuilder.append("=== 构建状态: ").append(json.getStr("status", "unknown")).append(" ===\n\n"); + + if (json.containsKey("jobs")) { + logBuilder.append("=== 任务信息 ===\n"); + logBuilder.append(json.getStr("jobs", "")); + } + + return logBuilder.toString(); + } + } catch (Exception e) { + log.error("获取构建日志失败: {}", e.getMessage()); + return "获取日志失败: " + e.getMessage(); + } + + return "暂无日志"; + } + + @Override + public void handleWebhook(String ciType, Map payload) { + if ("gitea".equals(ciType)) { + handleGiteaWebhook(payload); + } + } + + @Override + public Map getBuildStats(Long appId) { + Map stats = new HashMap<>(); + stats.put("total", Math.toIntExact(count(new LambdaQueryWrapper() + .eq(AppBuild::getAppId, appId)))); + stats.put("success", baseMapper.countBuildsByStatus(appId, "success")); + stats.put("failed", baseMapper.countBuildsByStatus(appId, "failed")); + stats.put("running", baseMapper.countBuildsByStatus(appId, "running") + + baseMapper.countBuildsByStatus(appId, "pending")); + return stats; + } + + @Override + public boolean cancelBuild(Long buildId) { + AppBuild build = getById(buildId); + if (build == null) { + throw new RuntimeException("构建记录不存在"); + } + + if (!"pending".equals(build.getStatus()) && !"running".equals(build.getStatus())) { + throw new RuntimeException("当前状态无法取消"); + } + + build.setStatus("cancelled"); + build.setFinishedAt(LocalDateTime.now()); + return updateById(build); + } + + @Override + public AppBuild retryBuild(Long buildId, Integer triggeredBy) { + AppBuild oldBuild = getById(buildId); + if (oldBuild == null) { + throw new RuntimeException("构建记录不存在"); + } + + // 创建新的构建记录,复用原构建的配置 + return triggerBuild(oldBuild.getAppId(), oldBuild.getBranch(), triggeredBy); + } + + // ========== 私有方法 ========== + + /** + * 触发 Gitea Actions 工作流 + */ + private String triggerGiteaAction(AppPipeline pipeline, String branch) { + if (pipeline.getRepoFullName() == null) { + throw new RuntimeException("流水线未配置仓库"); + } + + String workflowFile = pipeline.getWorkflowFile() != null ? pipeline.getWorkflowFile() : "build.yml"; + String url = String.format("%s/api/v1/repos/%s/actions/workflows/%s/runs", + giteaUrl, pipeline.getRepoFullName(), workflowFile); + + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + giteaToken); + headers.put("Content-Type", "application/json"); + + Map body = new HashMap<>(); + if (branch != null) { + body.put("ref", branch); + } + + try { + String response = HttpUtil.createPost(url) + .headerMap(headers, true) + .body(JSONUtil.toJsonStr(body)) + .timeout(30000) + .execute() + .body(); + + log.info("Gitea构建触发成功: {}", response); + return response; + } catch (Exception e) { + log.error("触发Gitea构建失败: {}", e.getMessage()); + throw new RuntimeException("触发CI构建失败: " + e.getMessage()); + } + } + + /** + * 处理 Gitea Webhook 回调 + */ + private void handleGiteaWebhook(Map payload) { + String runId = String.valueOf(payload.get("run_id")); + String status = String.valueOf(payload.get("status")); + + // 根据 run_id 查找构建记录 + AppBuild build = getOne(new LambdaQueryWrapper() + .eq(AppBuild::getCiRunId, runId) + .last("LIMIT 1")); + + if (build == null) { + log.warn("未找到匹配的构建记录, run_id: {}", runId); + return; + } + + // 更新构建状态 + build.setStatus(mapGiteaStatus(status)); + + if ("completed".equals(status) || "success".equals(status) || "failed".equals(status)) { + build.setFinishedAt(LocalDateTime.now()); + + // 计算耗时 + if (build.getStartedAt() != null) { + long seconds = Duration.between(build.getStartedAt(), build.getFinishedAt()).getSeconds(); + build.setDuration(Math.toIntExact(seconds)); + } + } + + if ("failed".equals(status) && payload.containsKey("conclusion")) { + build.setErrorMessage(String.valueOf(payload.get("conclusion"))); + } + + updateById(build); + + // 更新流水线的最后构建状态 + updatePipelineLastBuild(build.getAppId(), build.getId(), build.getStatus()); + } + + /** + * 映射 Gitea 状态到内部状态 + */ + private String mapGiteaStatus(String giteaStatus) { + return switch (giteaStatus) { + case "queued", "waiting", "requested" -> "pending"; + case "in_progress", "progressing" -> "running"; + case "completed" -> "success"; + case "cancelled" -> "cancelled"; + default -> giteaStatus; + }; + } + + /** + * 更新流水线的最后构建信息 + */ + private void updatePipelineLastBuild(Long pipelineId, Long buildId, String status) { + if (pipelineId == null) return; + + AppPipeline pipeline = appPipelineService.getById(pipelineId); + if (pipeline != null) { + pipeline.setLastBuildId(buildId); + pipeline.setLastBuildStatus(status); + pipeline.setLastBuildTime(LocalDateTime.now()); + + if ("success".equals(status)) { + pipeline.setSuccessCount(pipeline.getSuccessCount() != null ? pipeline.getSuccessCount() + 1 : 1); + } else if ("failed".equals(status)) { + pipeline.setFailureCount(pipeline.getFailureCount() != null ? pipeline.getFailureCount() + 1 : 1); + } + + appPipelineService.updateById(pipeline); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppCloudCredentialServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppCloudCredentialServiceImpl.java new file mode 100644 index 0000000..220ee42 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppCloudCredentialServiceImpl.java @@ -0,0 +1,236 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppCloudCredential; +import com.gxwebsoft.app.mapper.AppCloudCredentialMapper; +import com.gxwebsoft.app.service.AppCloudCredentialService; +import com.gxwebsoft.app.service.cloud.CloudStorageProvider; +import com.gxwebsoft.app.service.cloud.CloudStorageProviderFactory; +import com.gxwebsoft.common.core.utils.AesUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.app.param.AppCloudCredentialParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 云账号凭证Service实现 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +@Service +public class AppCloudCredentialServiceImpl extends ServiceImpl + implements AppCloudCredentialService { + + /** AES加密密钥(生产环境应使用配置中心) */ + private static final String AES_KEY = "websopy-cloud-key".substring(0, 16); + + @Override + public PageResult pageRel(AppCloudCredentialParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("id desc"); + // 将 Param 转换为 Entity 用于查询 + AppCloudCredential entity = new AppCloudCredential(); + entity.setProvider(param.getProvider()); + entity.setUserId(param.getUserId()); + entity.setStatus(param.getStatus()); + entity.setDeleted(param.getDeleted() != null ? param.getDeleted() : 0); + List list = baseMapper.selectPageRel(page, entity); + // 脱敏处理 + list.forEach(this::maskSecret); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AppCloudCredentialParam param) { + // 将 Param 转换为 Entity 用于查询 + AppCloudCredential entity = new AppCloudCredential(); + entity.setProvider(param.getProvider()); + entity.setUserId(param.getUserId()); + entity.setStatus(param.getStatus()); + entity.setDeleted(param.getDeleted() != null ? param.getDeleted() : 0); + List list = baseMapper.selectListRel(entity); + list.forEach(this::maskSecret); + return list; + } + + @Override + public AppCloudCredential add(AppCloudCredential credential) throws Exception { + // 加密存储 SK + if (credential.getAccessKeySecret() != null) { + credential.setAccessKeySecret(encrypt(credential.getAccessKeySecret())); + } + if (credential.getStatus() == null) { + credential.setStatus(0); + } + if (credential.getDeleted() == null) { + credential.setDeleted(0); + } + credential.setCreateTime(LocalDateTime.now()); + credential.setUpdateTime(LocalDateTime.now()); + save(credential); + log.info("创建云账号凭证成功,provider={}, name={}", credential.getProvider(), credential.getName()); + // 返回含明文的凭证(仅创建时返回一次) + credential.setAccessKeySecret(decrypt(credential.getAccessKeySecret())); + return credential; + } + + @Override + public AppCloudCredential update(AppCloudCredential credential) throws Exception { + // 如果传了新的 SK,则加密存储 + if (credential.getAccessKeySecret() != null && !credential.getAccessKeySecret().startsWith("****")) { + credential.setAccessKeySecret(encrypt(credential.getAccessKeySecret())); + } + credential.setUpdateTime(LocalDateTime.now()); + updateById(credential); + log.info("更新云账号凭证成功,id={}", credential.getId()); + // 返回脱敏后的对象 + maskSecret(credential); + return credential; + } + + @Override + public void remove(Long id, Integer userId) throws Exception { + // 检查归属 + AppCloudCredential credential = getById(id); + if (credential == null) { + throw new RuntimeException("凭证不存在"); + } + if (!credential.getUserId().equals(userId)) { + throw new RuntimeException("无权删除此凭证"); + } + removeById(id); + log.info("删除云账号凭证成功,id={}", id); + } + + @Override + public Map getCredentials(String provider, Integer userId) { + // 查询用户在该 provider 下的凭证 + AppCloudCredential entity = new AppCloudCredential(); + entity.setProvider(provider); + entity.setUserId(userId); + entity.setStatus(0); + entity.setDeleted(0); + + List list = baseMapper.selectListRel(entity); + if (list == null || list.isEmpty()) { + return null; + } + + // 取第一个 + AppCloudCredential credential = list.get(0); + Map result = new HashMap<>(); + result.put("accessKeyId", credential.getAccessKeyId()); + result.put("accessKeySecret", decrypt(credential.getAccessKeySecret())); + + // 额外配置 + if (credential.getConfigJson() != null) { + try { + Map config = new com.alibaba.fastjson.JSONObject() + .parseObject(credential.getConfigJson(), Map.class); + result.putAll(config); + } catch (Exception e) { + log.warn("解析配置JSON失败: {}", e.getMessage()); + } + } + + return result; + } + + @Override + public Map getCredentialsByCredentialId(Long credentialId) { + if (credentialId == null) { + return null; + } + AppCloudCredential credential = getById(credentialId); + if (credential == null || !Integer.valueOf(0).equals(credential.getDeleted())) { + return null; + } + + Map result = new HashMap<>(); + result.put("accessKeyId", credential.getAccessKeyId()); + result.put("accessKeySecret", decrypt(credential.getAccessKeySecret())); + + // 额外配置 + if (credential.getConfigJson() != null) { + try { + Map config = new com.alibaba.fastjson.JSONObject() + .parseObject(credential.getConfigJson(), Map.class); + result.putAll(config); + } catch (Exception e) { + log.warn("解析配置JSON失败: {}", e.getMessage()); + } + } + + return result; + } + + @Override + public boolean testConnection(String provider, Map credentials) { + try { + CloudStorageProvider cloudProvider = CloudStorageProviderFactory.getProvider(provider); + // 使用专门的测试连接方法,不需要 bucket + return cloudProvider.testConnection(credentials); + } catch (Exception e) { + log.error("测试连接失败: {}", e.getMessage()); + return false; + } + } + + @Override + public Object[] testConnectionWithMessage(String provider, Map credentials) { + try { + CloudStorageProvider cloudProvider = CloudStorageProviderFactory.getProvider(provider); + // 使用专门的测试连接方法,不需要 bucket + boolean success = cloudProvider.testConnection(credentials); + return new Object[]{success, success ? "连接成功" : "连接失败"}; + } catch (Exception e) { + log.error("测试连接失败: {}", e.getMessage()); + return new Object[]{false, e.getMessage()}; + } + } + + /** + * 脱敏处理 + */ + private void maskSecret(AppCloudCredential credential) { + if (credential.getAccessKeySecret() != null && !credential.getAccessKeySecret().startsWith("****")) { + String secret = credential.getAccessKeySecret(); + if (secret.length() > 8) { + credential.setAccessKeySecret(secret.substring(0, 4) + "********"); + } else { + credential.setAccessKeySecret("****"); + } + } + } + + /** + * AES 加密 + */ + private String encrypt(String plaintext) { + try { + return AesUtil.encrypt(plaintext, AES_KEY); + } catch (Exception e) { + throw new RuntimeException("加密失败", e); + } + } + + /** + * AES 解密 + */ + private String decrypt(String ciphertext) { + try { + if (ciphertext == null) return null; + return AesUtil.decrypt(ciphertext, AES_KEY); + } catch (Exception e) { + throw new RuntimeException("解密失败", e); + } + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppConfigServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppConfigServiceImpl.java new file mode 100644 index 0000000..46b4c3b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppConfigServiceImpl.java @@ -0,0 +1,270 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppConfig; +import com.gxwebsoft.app.mapper.AppConfigMapper; +import com.gxwebsoft.app.param.AppConfigParam; +import com.gxwebsoft.app.service.AppConfigService; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 应用配置表 Service 实现类 + * + * @author 科技小王子 + */ +@Slf4j +@Service +public class AppConfigServiceImpl extends ServiceImpl implements AppConfigService { + + @Resource + private UserService userService; + + /** + * 配置加密密钥(从配置文件读取) + */ + @Value("${app.config.encrypt-key:GXWebsoft2024!@#$}") + private String encryptKey; + + /** + * 分页查询应用配置 + */ + @Override + public List page(AppConfigParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, config_id asc"); + List list = baseMapper.selectPageRel(page, param); + return page.sortRecords(list); + } + + /** + * 分页查询应用配置(返回PageResult) + */ + public PageResult pageRel(AppConfigParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, config_id asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + /** + * 获取应用配置列表 + */ + @Override + public List list(AppConfigParam param) { + List list = baseMapper.selectListRel(param); + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, config_id asc"); + return page.sortRecords(list); + } + + /** + * 根据应用ID获取配置映射(自动解密) + */ + @Override + public Map getConfigsByAppId(Integer appId) { + List> configs = baseMapper.selectConfigsByAppId(appId); + Map result = new HashMap<>(); + + for (Map config : configs) { + String configKey = (String) config.get("configKey"); + Object configValue = config.get("configValue"); + Integer isEncrypted = (Integer) config.get("isEncrypted"); + + // 解密 + if (isEncrypted != null && isEncrypted == 1 && configValue != null) { + try { + configValue = decrypt((String) configValue); + } catch (Exception e) { + log.error("配置解密失败: {}", configKey, e); + } + } + + result.put(configKey, configValue); + } + + return result; + } + + /** + * 获取单个配置值 + */ + @Override + public String getConfigValue(Integer appId, String configKey) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppConfig::getAppId, appId); + wrapper.eq(AppConfig::getConfigKey, configKey); + AppConfig config = getOne(wrapper); + + if (config == null || config.getConfigValue() == null) { + return null; + } + + // 解密 + if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1) { + return decrypt(config.getConfigValue()); + } + + return config.getConfigValue(); + } + + /** + * 保存配置 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void saveConfig(AppConfig config) { + // 设置租户ID + Integer tenantId = getCurrentTenantId(); + if (tenantId != null) { + config.setTenantId(Long.valueOf(tenantId)); + } + + // 加密敏感信息 + if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1 && config.getConfigValue() != null) { + config.setConfigValue(encrypt(config.getConfigValue())); + } + + save(config); + } + + /** + * 批量保存配置 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void batchSaveConfig(Integer appId, List configs) { + // 设置租户ID + Integer tenantId = getCurrentTenantId(); + if (tenantId != null) { + for (AppConfig config : configs) { + config.setTenantId(Long.valueOf(tenantId)); + } + } + + // 先删除该应用的所有配置 + remove(new LambdaQueryWrapper() + .eq(AppConfig::getAppId, appId)); + + // 批量插入新配置 + for (AppConfig config : configs) { + config.setAppId(appId); + + // 加密敏感信息 + if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1 && config.getConfigValue() != null) { + config.setConfigValue(encrypt(config.getConfigValue())); + } + + save(config); + } + } + + /** + * 更新配置 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void updateConfig(AppConfig config) { + // 加密敏感信息 + if (config.getIsEncrypted() != null && config.getIsEncrypted() == 1 && config.getConfigValue() != null) { + config.setConfigValue(encrypt(config.getConfigValue())); + } + + updateById(config); + } + + /** + * 删除配置 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteConfig(Integer configId) { + removeById(configId); + } + + /** + * 根据应用ID删除所有配置 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteByAppId(Integer appId) { + remove(new LambdaQueryWrapper() + .eq(AppConfig::getAppId, appId)); + } + + /** + * 构建查询条件 + */ + private LambdaQueryWrapper buildQueryWrapper(AppConfigParam param) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + if (param.getConfigId() != null) { + wrapper.eq(AppConfig::getConfigId, param.getConfigId()); + } + if (param.getAppId() != null) { + wrapper.eq(AppConfig::getAppId, param.getAppId()); + } + if (param.getConfigKey() != null) { + wrapper.like(AppConfig::getConfigKey, param.getConfigKey()); + } + if (param.getConfigType() != null) { + wrapper.eq(AppConfig::getConfigType, param.getConfigType()); + } + if (param.getIsSecret() != null) { + wrapper.eq(AppConfig::getIsSecret, param.getIsSecret()); + } + + wrapper.orderByAsc(AppConfig::getConfigType) + .orderByAsc(AppConfig::getSortNumber) + .orderByAsc(AppConfig::getConfigId); + + return wrapper; + } + + /** + * AES 加密 + */ + private String encrypt(String plainText) { + AES aes = SecureUtil.aes(encryptKey.getBytes()); + return aes.encryptBase64(plainText); + } + + /** + * AES 解密 + */ + private String decrypt(String cipherText) { + AES aes = SecureUtil.aes(encryptKey.getBytes()); + return aes.decryptStr(cipherText); + } + + /** + * 获取当前登录用户的租户ID + */ + private Integer getCurrentTenantId() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.getPrincipal() instanceof User) { + return ((User) authentication.getPrincipal()).getTenantId(); + } + } catch (Exception e) { + log.error("获取当前用户租户ID失败", e); + } + return null; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppContractServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppContractServiceImpl.java new file mode 100644 index 0000000..7936930 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppContractServiceImpl.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppContract; +import com.gxwebsoft.app.mapper.AppContractMapper; +import com.gxwebsoft.app.param.AppContractParam; +import com.gxwebsoft.app.service.AppContractService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +/** + * 合同管理 Service 实现 + * + * @author 科技小王子 + * @since 2026-04-13 + */ +@Slf4j +@Service +public class AppContractServiceImpl extends ServiceImpl + implements AppContractService { + + @Resource + private UserService userService; + + // ─── 生成合同编号(格式:HT-20260413-0001) ──────────────────── + private String generateContractNo() { + LocalDateTime now = LocalDateTime.now(); + String datePart = now.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + Integer maxSeq = baseMapper.selectMaxSeqForDate(datePart); + int seq = (maxSeq == null ? 0 : maxSeq) + 1; + return String.format("HT-%s-%04d", datePart, seq); + } + + // ─── 分页查询 ───────────────────────────────────────────────── + @Override + public PageResult page(AppContractParam param, Integer userId) { + Page page = new Page<>(param.getCurrent(), param.getSize() > 0 ? param.getSize() : 15); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppContract::getDeleted, 0) + .eq(AppContract::getUserId, userId) + .eq(ObjectUtil.isNotEmpty(param.getContractType()), AppContract::getContractType, param.getContractType()) + .eq(ObjectUtil.isNotEmpty(param.getStatus()), AppContract::getStatus, param.getStatus()) + .and(ObjectUtil.isNotEmpty(param.getKeywords()), q -> + q.like(AppContract::getTitle, param.getKeywords()) + .or().like(AppContract::getContractNo, param.getKeywords())) + .orderByDesc(AppContract::getCreateTime); + + baseMapper.selectPage(page, wrapper); + return new PageResult<>(page.getRecords(), page.getTotal()); + } + + // ─── 创建合同 ───────────────────────────────────────────────── + @Override + @Transactional(rollbackFor = Exception.class) + public AppContract create(AppContract contract, Integer userId) { + contract.setUserId(userId); + contract.setContractNo(generateContractNo()); + contract.setDeleted(0); + contract.setCreateTime(LocalDateTime.now()); + contract.setUpdateTime(LocalDateTime.now()); + + // 补充用户名(冗余) + try { + User user = userService.getByIdIgnoreTenant(userId); + if (user != null) { + contract.setUserName(StrUtil.isNotBlank(user.getNickname()) ? user.getNickname() : user.getUsername()); + } + } catch (Exception e) { + log.warn("获取用户信息失败", e); + } + + save(contract); + return contract; + } + + // ─── 更新合同 ───────────────────────────────────────────────── + @Override + @Transactional(rollbackFor = Exception.class) + public AppContract update(AppContract contract, Integer userId) { + AppContract existing = getById(contract.getContractId()); + if (existing == null || !existing.getUserId().equals(userId)) { + throw new RuntimeException("合同不存在或无权操作"); + } + contract.setUpdateTime(LocalDateTime.now()); + // 不允许修改创建人 + contract.setUserId(null); + contract.setUserName(null); + contract.setContractNo(null); + updateById(contract); + return getById(contract.getContractId()); + } + + // ─── 软删除 ─────────────────────────────────────────────────── + @Override + @Transactional(rollbackFor = Exception.class) + public void remove(Long contractId, Integer userId) { + AppContract existing = getById(contractId); + if (existing == null || !existing.getUserId().equals(userId)) { + throw new RuntimeException("合同不存在或无权操作"); + } + update(new LambdaUpdateWrapper() + .eq(AppContract::getContractId, contractId) + .set(AppContract::getDeleted, 1) + .set(AppContract::getUpdateTime, LocalDateTime.now())); + } + + // ─── 统计 ───────────────────────────────────────────────────── + @Override + public Map stats(Integer userId) { + LambdaQueryWrapper base = new LambdaQueryWrapper() + .eq(AppContract::getDeleted, 0) + .eq(AppContract::getUserId, userId); + + Map result = new HashMap<>(); + result.put("total", (long) count(base.clone())); + result.put("active", (long) count(base.clone().eq(AppContract::getStatus, "active"))); + result.put("pending", (long) count(base.clone().eq(AppContract::getStatus, "pending"))); + result.put("expired", (long) count(base.clone().eq(AppContract::getStatus, "expired"))); + result.put("draft", (long) count(base.clone().eq(AppContract::getStatus, "draft"))); + result.put("terminated", (long) count(base.clone().eq(AppContract::getStatus, "terminated"))); + return result; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppCredentialServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppCredentialServiceImpl.java new file mode 100644 index 0000000..4493baf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppCredentialServiceImpl.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.mapper.AppCredentialMapper; +import com.gxwebsoft.app.service.AppCredentialService; +import com.gxwebsoft.app.entity.AppCredential; +import com.gxwebsoft.app.param.AppCredentialParam; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用密钥凭证Service实现 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:43 + */ +@Slf4j +@Service +public class AppCredentialServiceImpl extends ServiceImpl implements AppCredentialService { + + @Override + public PageResult pageRel(AppCredentialParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + // 脱敏处理:appSecret 不对外展示(仅创建/重置时返回明文) + list.forEach(this::maskSecret); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AppCredentialParam param) { + List list = baseMapper.selectListRel(param); + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + list = page.sortRecords(list); + list.forEach(this::maskSecret); + return list; + } + + @Override + public AppCredential getByIdRel(Integer id) { + AppCredentialParam param = new AppCredentialParam(); + param.setId(id.longValue()); + AppCredential credential = param.getOne(baseMapper.selectListRel(param)); + if (credential != null) { + maskSecret(credential); + } + return credential; + } + + @Override + public AppCredential createCredential(AppCredential credential) { + // 生成 OAuth Client ID:ws_ + 16位随机字符串 + String clientId = "ws_" + CommonUtil.randomUUID16(); + // 生成 OAuth Client Secret:32位随机字符串(大小写字母+数字) + String clientSecret = generateSecretValue(); + + credential.setClientId(clientId); + credential.setClientSecret(clientSecret); + // 默认状态正常 + if (credential.getStatus() == null) { + credential.setStatus(0); + } + if (StrUtil.isBlank(credential.getType())) { + credential.setType("server"); + } + + save(credential); + log.info("创建凭证成功,clientId={}, appId={}", clientId, credential.getAppId()); + // 返回含明文 secret 的对象(仅此一次) + return credential; + } + + @Override + public AppCredential resetSecret(Long id) { + AppCredential credential = getById(id); + if (credential == null) { + throw new RuntimeException("凭证不存在"); + } + String newSecret = generateSecretValue(); + credential.setClientSecret(newSecret); + updateById(credential); + log.info("重置凭证密钥成功,id={}", id); + return credential; + } + + @Override + public boolean updateStatus(Long id, Integer status) { + return update(new LambdaUpdateWrapper() + .eq(AppCredential::getId, id) + .set(AppCredential::getStatus, status)); + } + + /** + * 生成32位随机 AppSecret + */ + private String generateSecretValue() { + // 格式:8位-8位-8位-8位(类似 UUID 格式,便于复制) + return RandomUtil.randomString(8) + "-" + + RandomUtil.randomString(8) + "-" + + RandomUtil.randomString(8) + "-" + + RandomUtil.randomString(8); + } + + /** + * 脱敏处理:将 appSecret 替换为掩码 + */ + private void maskSecret(AppCredential credential) { + if (StrUtil.isNotBlank(credential.getClientSecret())) { + // 只保留前4位,其余用 * 替代 + String secret = credential.getClientSecret(); + credential.setClientSecret(secret.substring(0, Math.min(4, secret.length())) + "**********************"); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppEventServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppEventServiceImpl.java new file mode 100644 index 0000000..63e867f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppEventServiceImpl.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.mapper.AppEventMapper; +import com.gxwebsoft.app.service.AppEventService; +import com.gxwebsoft.app.entity.AppEvent; +import com.gxwebsoft.app.param.AppEventParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用操作动态Service实现 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Slf4j +@Service +public class AppEventServiceImpl extends ServiceImpl implements AppEventService { + + @Override + public PageResult pageRel(AppEventParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AppEventParam param) { + List list = baseMapper.selectListRel(param); + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public AppEvent getByIdRel(Integer id) { + AppEventParam param = new AppEventParam(); + param.setId(id.longValue()); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + @Async + public void logEvent(Long appId, String eventType, String title, String content, + Long operatorId, String operatorName, Long refId, String refType) { + try { + AppEvent event = new AppEvent(); + event.setAppId(appId); + event.setEventType(eventType); + event.setTitle(title); + event.setContent(content); + event.setOperatorId(operatorId); + event.setOperator(operatorName); + event.setRefId(refId); + event.setRefType(refType); + event.setStatus(0); + save(event); + log.debug("记录事件成功,appId={}, eventType={}, title={}", appId, eventType, title); + } catch (Exception e) { + log.warn("记录事件失败,appId={}, eventType={}: {}", appId, eventType, e.getMessage()); + } + } + + @Override + @Async + public void logEvent(Long appId, String eventType, String title, Long operatorId, String operatorName) { + logEvent(appId, eventType, title, null, operatorId, operatorName, null, null); + } + + @Override + public AppEvent getLatestEvent(Long appId) { + return getOne(new LambdaQueryWrapper() + .eq(AppEvent::getAppId, appId) + .orderByDesc(AppEvent::getCreateTime) + .last("LIMIT 1")); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppGitAccountServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppGitAccountServiceImpl.java new file mode 100644 index 0000000..f72c732 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppGitAccountServiceImpl.java @@ -0,0 +1,177 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppGitAccount; +import com.gxwebsoft.app.mapper.AppGitAccountMapper; +import com.gxwebsoft.app.service.AppGitAccountService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Git账号绑定 Service实现 + * + * @author 科技小王子 + * @since 2026-04-02 + */ +@Slf4j +@Service +public class AppGitAccountServiceImpl extends ServiceImpl implements AppGitAccountService { + + @Override + @Transactional(rollbackFor = Exception.class) + public AppGitAccount saveGitAccount(String username, String email, String remark, Integer userId, Integer tenantId) { + // 参数校验 + if (StrUtil.isBlank(username)) { + throw new RuntimeException("用户名不能为空"); + } + + // 去除空格 + username = username.trim(); + + // 检查用户名是否已被其他用户绑定(同一租户下) + AppGitAccount occupied = baseMapper.checkUsernameOccupied(username, userId, tenantId); + if (occupied != null) { + throw new RuntimeException("该用户名已被其他用户绑定"); + } + + // 查询当前用户的绑定记录(同一租户下) + AppGitAccount existing = baseMapper.selectByUserIdAndTenantId(userId, tenantId); + + LocalDateTime now = LocalDateTime.now(); + + if (existing != null) { + // 更新现有记录 + existing.setUsername(username); + if (StrUtil.isNotBlank(email)) { + existing.setEmail(email.trim()); + } else { + existing.setEmail(null); + } + if (StrUtil.isNotBlank(remark)) { + existing.setRemark(remark.trim()); + } else { + existing.setRemark(null); + } + // 重新提交审核,状态变更为 pending + existing.setStatus("pending"); + existing.setVerificationNote(null); + existing.setUpdateTime(now); + baseMapper.updateById(existing); + log.info("用户{}更新Git账号绑定信息: {}", userId, username); + return existing; + } else { + // 新增记录 + AppGitAccount account = new AppGitAccount(); + account.setUserId(userId); + account.setTenantId(tenantId); + account.setUsername(username); + if (StrUtil.isNotBlank(email)) { + account.setEmail(email.trim()); + } + if (StrUtil.isNotBlank(remark)) { + account.setRemark(remark.trim()); + } + account.setStatus("pending"); + account.setCreateTime(now); + account.setUpdateTime(now); + account.setDeleted(0); + baseMapper.insert(account); + log.info("用户{}新增Git账号绑定信息: {}", userId, username); + return account; + } + } + + @Override + public AppGitAccount getGitAccountStatus(Integer userId, Integer tenantId) { + // 使用 userId + tenantId 查询,确保数据隔离 + AppGitAccount account = baseMapper.selectByUserIdAndTenantId(userId, tenantId); + if (account == null) { + // 未绑定状态 + AppGitAccount notBound = new AppGitAccount(); + notBound.setStatus("not_bound"); + return notBound; + } + return account; + } + + @Override + public Map pageGitAccounts(String status, String keyword, int page, int size) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppGitAccount::getDeleted, 0); + + if (StrUtil.isNotBlank(status)) { + wrapper.eq(AppGitAccount::getStatus, status); + } + if (StrUtil.isNotBlank(keyword)) { + wrapper.and(w -> w + .like(AppGitAccount::getUsername, keyword) + .or() + .like(AppGitAccount::getEmail, keyword) + .or() + .like(AppGitAccount::getRemark, keyword) + ); + } + + wrapper.orderByDesc(AppGitAccount::getUpdateTime); + + Page pageResult = baseMapper.selectPage(new Page<>(page, size), wrapper); + + Map result = new HashMap<>(); + result.put("records", pageResult.getRecords()); + result.put("total", pageResult.getTotal()); + result.put("current", pageResult.getCurrent()); + result.put("size", pageResult.getSize()); + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean approveAccount(Long id, Integer reviewerId, String reviewerName, String note) { + AppGitAccount account = baseMapper.selectById(id); + if (account == null) { + throw new RuntimeException("Git账号绑定记录不存在"); + } + if (!"pending".equals(account.getStatus())) { + throw new RuntimeException("该记录不在待审核状态,无法操作"); + } + + account.setStatus("verified"); + account.setVerificationNote(note); + account.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(account); + log.info("管理员{}审核通过Git账号绑定: userId={}, username={}", reviewerId, account.getUserId(), account.getUsername()); + return true; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean rejectAccount(Long id, Integer reviewerId, String reviewerName, String reason) { + if (StrUtil.isBlank(reason)) { + throw new RuntimeException("拒绝原因不能为空"); + } + + AppGitAccount account = baseMapper.selectById(id); + if (account == null) { + throw new RuntimeException("Git账号绑定记录不存在"); + } + if (!"pending".equals(account.getStatus())) { + throw new RuntimeException("该记录不在待审核状态,无法操作"); + } + + account.setStatus("rejected"); + account.setVerificationNote(reason.trim()); + account.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(account); + log.info("管理员{}拒绝Git账号绑定: userId={}, username={}, reason={}", reviewerId, account.getUserId(), account.getUsername(), reason); + return true; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppInviteServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppInviteServiceImpl.java new file mode 100644 index 0000000..5a88655 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppInviteServiceImpl.java @@ -0,0 +1,343 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.app.entity.AppInviteToken; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.entity.AppUserCache; +import com.gxwebsoft.app.mapper.AppInviteTokenMapper; +import com.gxwebsoft.app.mapper.AppProductMapper; +import com.gxwebsoft.app.mapper.AppUserMapper; +import com.gxwebsoft.app.service.AppInviteService; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.WxMiniprogramUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 应用成员邀请 Service 实现 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AppInviteServiceImpl implements AppInviteService { + + private final AppInviteTokenMapper appInviteTokenMapper; + private final AppProductMapper appProductMapper; + private final AppUserMapper appUserMapper; + private final AppUserCacheService appUserCacheService; + + @Value("${app.invite.base-url:https://websopy.websoft.top}") + private String baseUrl; + + @Override + public Map generateQrCodeInvite(Integer appId, String role, Integer inviterId) { + // 检查权限 + checkInvitePermission(appId.longValue(), inviterId); + + // 生成token + String token = generateToken(); + + // 保存邀请记录(24小时有效) + AppInviteToken inviteToken = new AppInviteToken(); + inviteToken.setToken(token); + inviteToken.setAppId(appId); + inviteToken.setRole(role); + inviteToken.setInviterId(inviterId); + inviteToken.setExpireTime(LocalDateTime.now().plusHours(24)); + inviteToken.setCreateTime(LocalDateTime.now()); + inviteToken.setStatus(0); + appInviteTokenMapper.insert(inviteToken); + + // 生成邀请链接 + String inviteUrl = baseUrl + "/invite/accept?token=" + token + "&appId=" + appId + "&role=" + role; + + // 小程序码跳转页面(邀请成员专用) + // 注意:分包页面的完整路径需要包含分包根目录 + String miniprogramPage = "passport/invite/index"; + log.info("生成小程序码,appId={}, page={}, token={}", appId, miniprogramPage, token); + + // 检查页面路径是否在小程序 app.config.ts 中注册 + // subpackages[0].pages 中包含 "invite/index",路径为 passport/invite/index + + // 生成小程序码(通过微信工具类生成) + String miniprogramQrCode = WxMiniprogramUtil.generateMiniprogramQrCode( + token, + miniprogramPage, + 280, + "release" + ); + log.info("小程序码生成结果: {}", StrUtil.isNotBlank(miniprogramQrCode) ? "成功" : "失败"); + + Map result = new HashMap<>(); + result.put("token", token); + result.put("inviteUrl", inviteUrl); + // 返回小程序码(优先使用) + if (cn.hutool.core.util.StrUtil.isNotBlank(miniprogramQrCode)) { + result.put("miniprogramQrCode", miniprogramQrCode); + } + return result; + } + + @Override + public Map generateLinkInvite(Integer appId, String role, Integer inviterId) { + // 检查权限 + checkInvitePermission(appId.longValue(), inviterId); + + // 生成token + String token = generateToken(); + + // 保存邀请记录(7天有效) + AppInviteToken inviteToken = new AppInviteToken(); + inviteToken.setToken(token); + inviteToken.setAppId(appId); + inviteToken.setRole(role); + inviteToken.setInviterId(inviterId); + inviteToken.setExpireTime(LocalDateTime.now().plusDays(7)); + inviteToken.setCreateTime(LocalDateTime.now()); + inviteToken.setStatus(0); + appInviteTokenMapper.insert(inviteToken); + + // 生成邀请链接 + String inviteUrl = baseUrl + "/invite/accept?token=" + token + "&appId=" + appId + "&role=" + role; + + Map result = new HashMap<>(); + result.put("token", token); + result.put("inviteUrl", inviteUrl); + return result; + } + + @Override + public Map verifyInvite(String token, Integer appId) { + // 查询邀请记录 + AppInviteToken inviteToken = appInviteTokenMapper.selectByToken(token); + if (inviteToken == null) { + throw new BusinessException("邀请不存在或已失效"); + } + + // 验证应用ID + if (!inviteToken.getAppId().equals(appId)) { + throw new BusinessException("邀请与应用不匹配"); + } + + // 检查是否过期 + if (inviteToken.getExpireTime().isBefore(LocalDateTime.now())) { + throw new BusinessException("邀请已过期"); + } + + // 检查是否已使用 + if (inviteToken.getStatus() != 0) { + throw new BusinessException("邀请已被使用"); + } + + // 获取应用信息 + AppProduct app = appProductMapper.selectById(appId); + if (app == null) { + throw new BusinessException("应用不存在"); + } + + // 获取邀请人信息 + AppUserCache inviter = appUserCacheService.getByUserId(inviteToken.getInviterId()); + + Map result = new HashMap<>(); + result.put("appId", appId); + result.put("appName", app.getProductName()); + result.put("appIcon", app.getIcon()); + result.put("inviterName", inviter != null ? inviter.getNickname() : "未知"); + result.put("role", inviteToken.getRole()); + result.put("expireTime", inviteToken.getExpireTime().toString()); + return result; + } + + /** + * 通过 token 获取邀请信息(小程序专用,不需要 appId) + */ + public Map getInviteInfoByToken(String token) { + // 查询邀请记录 + AppInviteToken inviteToken = appInviteTokenMapper.selectByToken(token); + if (inviteToken == null) { + throw new BusinessException("邀请不存在或已失效"); + } + + // 检查是否过期 + if (inviteToken.getExpireTime().isBefore(LocalDateTime.now())) { + throw new BusinessException("邀请已过期"); + } + + // 检查是否已使用 + if (inviteToken.getStatus() != 0) { + throw new BusinessException("邀请已被使用"); + } + + // 获取应用信息 + AppProduct app = appProductMapper.selectById(inviteToken.getAppId()); + if (app == null) { + throw new BusinessException("应用不存在"); + } + + // 获取邀请人信息 + AppUserCache inviter = appUserCacheService.getByUserId(inviteToken.getInviterId()); + + // 获取角色名称 + String roleName = getRoleName(inviteToken.getRole()); + + Map result = new HashMap<>(); + result.put("token", token); + result.put("appId", inviteToken.getAppId()); + result.put("appName", app.getProductName()); + result.put("appLogo", app.getIcon()); + result.put("inviterName", inviter != null ? inviter.getNickname() : "某位用户"); + result.put("roleName", roleName); + result.put("role", inviteToken.getRole()); + result.put("expireTime", inviteToken.getExpireTime().toString()); + return result; + } + + /** + * 获取角色名称 + */ + private String getRoleName(String role) { + if (StrUtil.isBlank(role)) return "成员"; + switch (role) { + case "owner": return "所有者"; + case "admin": return "管理员"; + case "developer": return "开发者"; + default: return "成员"; + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void acceptInvite(String token, Integer appId, Integer userId) { + // 验证邀请 + AppInviteToken inviteToken = appInviteTokenMapper.selectByToken(token); + if (inviteToken == null) { + throw new BusinessException("邀请不存在或已失效"); + } + + if (!inviteToken.getAppId().equals(appId)) { + throw new BusinessException("邀请与应用不匹配"); + } + + if (inviteToken.getExpireTime().isBefore(LocalDateTime.now())) { + throw new BusinessException("邀请已过期"); + } + + if (inviteToken.getStatus() != 0) { + throw new BusinessException("邀请已被使用"); + } + + // 检查是否已经是成员 + AppUser existUser = appUserMapper.selectOne(new LambdaQueryWrapper() + .eq(AppUser::getAppId, appId.longValue()) + .eq(AppUser::getUserId, userId)); + if (existUser != null) { + throw new BusinessException("你已经是该应用的成员"); + } + + // 获取用户信息(从缓存获取,如果不存在则刷新缓存) + AppUserCache userCache = appUserCacheService.getByUserId(userId); + if (userCache == null) { + // 如果缓存不存在,刷新缓存 + userCache = appUserCacheService.refreshUserCache(userId); + } + + // 添加成员 + AppUser appUser = new AppUser(); + appUser.setAppId(appId.longValue()); + appUser.setUserId(userId); + appUser.setRole(inviteToken.getRole()); + appUser.setStatus(0); // 正常状态 + appUser.setCreateTime(LocalDateTime.now()); + appUser.setInviteBy(inviteToken.getInviterId().longValue()); + appUser.setInviteTime(LocalDateTime.now()); + + // 冗余存储用户信息 + if (userCache != null) { + appUser.setUsername(userCache.getUsername()); + appUser.setNickname(userCache.getNickname()); + appUser.setAvatar(userCache.getAvatar()); + appUser.setPhone(userCache.getPhone()); + } + + appUserMapper.insert(appUser); + + // 标记邀请为已使用 + inviteToken.setStatus(1); + inviteToken.setAcceptUserId(userId); + inviteToken.setAcceptTime(LocalDateTime.now()); + appInviteTokenMapper.updateById(inviteToken); + + log.info("用户 {} 通过邀请加入应用 {}", userId, appId); + } + + /** + * 检查邀请权限 + */ + private void checkInvitePermission(Long appId, Integer userId) { + // 检查用户是否是应用成员且有权限邀请 + AppUser appUser = appUserMapper.selectOne(new LambdaQueryWrapper() + .eq(AppUser::getAppId, appId) + .eq(AppUser::getUserId, userId)); + if (appUser == null) { + throw new BusinessException("你不是该应用的成员"); + } + // owner 和 admin 可以邀请 + if (!"owner".equals(appUser.getRole()) && !"admin".equals(appUser.getRole())) { + throw new BusinessException("你没有权限邀请成员"); + } + } + + /** + * 生成唯一token(16位,兼容小程序scene参数长度限制) + */ + private String generateToken() { + // 使用16位随机字符串,确保在小程序scene参数长度限制内(32字符) + return cn.hutool.core.util.RandomUtil.randomString(16); + } + + /** + * 获取小程序码页面配置(已废弃,直接返回固定值) + */ + private String getMiniprogramPageFromSetting() { + return "passport/invite/index"; + } + + @Override + public Map getInviteStatus(String token) { + Map result = new HashMap<>(); + + // 查询邀请记录 + AppInviteToken inviteToken = appInviteTokenMapper.selectByToken(token); + if (inviteToken == null) { + result.put("status", -1); // 不存在 + result.put("message", "邀请不存在"); + return result; + } + + result.put("status", inviteToken.getStatus()); // 0: 未使用, 1: 已使用 + + // 如果已使用,返回使用信息 + if (inviteToken.getStatus() == 1 && inviteToken.getAcceptUserId() != null) { + result.put("usedAt", inviteToken.getAcceptTime() != null ? inviteToken.getAcceptTime().toString() : null); + + // 获取使用者信息 + AppUserCache userCache = appUserCacheService.getByUserId(inviteToken.getAcceptUserId()); + if (userCache != null) { + result.put("usedBy", userCache.getNickname()); + } + } + + return result; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppNotificationServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppNotificationServiceImpl.java new file mode 100644 index 0000000..5f419f7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppNotificationServiceImpl.java @@ -0,0 +1,170 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppNotification; +import com.gxwebsoft.app.mapper.AppNotificationMapper; +import com.gxwebsoft.app.param.AppNotificationParam; +import com.gxwebsoft.app.service.AppNotificationService; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.*; + +/** + * 站内消息通知 Service 实现 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Service +public class AppNotificationServiceImpl extends ServiceImpl implements AppNotificationService { + + /** 支持的通知类型 */ + private static final List VALID_TYPES = Arrays.asList( + "ticket", "review", "system", "resource", "permission", "member", "payment" + ); + + // ─── 分页查询 ──────────────────────────────────────────────── + + @Override + public PageResult pageByUser(AppNotificationParam param, Integer userId) { + long pageNum = param.getPage() != null ? param.getPage() : 1; + long pageSize = param.getLimit() != null ? param.getLimit() : 15; + Page page = new Page<>(pageNum, pageSize); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppNotification::getUserId, userId) + .eq(StrUtil.isNotBlank(param.getType()), AppNotification::getType, param.getType()) + .eq(ObjectUtil.isNotNull(param.getIsRead()), AppNotification::getIsRead, param.getIsRead()) + .orderByDesc(AppNotification::getCreateTime); + + baseMapper.selectPage(page, wrapper); + return new PageResult<>(page.getRecords(), page.getTotal()); + } + + // ─── 最近通知 ──────────────────────────────────────────────── + + @Override + public List listRecent(Integer userId, String type, int limit) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppNotification::getUserId, userId) + .eq(StrUtil.isNotBlank(type), AppNotification::getType, type) + .orderByDesc(AppNotification::getCreateTime) + .last("LIMIT " + Math.min(limit, 50)); + + return baseMapper.selectList(wrapper); + } + + // ─── 未读统计 ──────────────────────────────────────────────── + + @Override + public Map getUnreadCount(Integer userId) { + LambdaQueryWrapper base = new LambdaQueryWrapper() + .eq(AppNotification::getUserId, userId) + .eq(AppNotification::getIsRead, 0); + + Map result = new HashMap<>(); + + // 总未读数 + result.put("total", (long) count(base.clone())); + + // 各类型未读数 + for (String type : VALID_TYPES) { + result.put(type, (long) count(base.clone().eq(AppNotification::getType, type))); + } + + return result; + } + + // ─── 标记已读 ──────────────────────────────────────────────── + + @Override + public void markRead(Long id, Integer userId) { + update(new LambdaUpdateWrapper() + .eq(AppNotification::getId, id) + .eq(AppNotification::getUserId, userId) + .set(AppNotification::getIsRead, 1) + .set(AppNotification::getUpdateTime, LocalDateTime.now())); + } + + @Override + public void markAllRead(Integer userId, String type) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper() + .eq(AppNotification::getUserId, userId) + .eq(AppNotification::getIsRead, 0) + .eq(StrUtil.isNotBlank(type), AppNotification::getType, type) + .set(AppNotification::getIsRead, 1) + .set(AppNotification::getUpdateTime, LocalDateTime.now()); + + update(wrapper); + } + + // ─── 删除通知 ──────────────────────────────────────────────── + + @Override + public void removeNotification(Long id, Integer userId) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper() + .eq(AppNotification::getId, id) + .eq(AppNotification::getUserId, userId); + remove(wrapper); + } + + @Override + public void clearRead(Integer userId, String type) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppNotification::getUserId, userId) + .eq(AppNotification::getIsRead, 1) + .eq(StrUtil.isNotBlank(type), AppNotification::getType, type); + + remove(wrapper); + } + + // ─── 发送通知 ──────────────────────────────────────────────── + + @Override + @Async + public void send(Integer userId, String type, String title, String content, + Long refId, String refType, String linkUrl, + Integer senderId, String senderName, String senderAvatar) { + if (userId == null || StrUtil.isBlank(title)) { + log.warn("[通知发送] 参数不完整: userId={}, title={}", userId, title); + return; + } + + // 校验类型 + if (StrUtil.isNotBlank(type) && !VALID_TYPES.contains(type)) { + type = "system"; + } + + AppNotification notification = new AppNotification(); + notification.setUserId(userId); + notification.setType(StrUtil.isNotBlank(type) ? type : "system"); + notification.setTitle(title); + notification.setContent(content); + notification.setIsRead(0); + notification.setRefId(refId); + notification.setRefType(refType); + notification.setLinkUrl(linkUrl); + notification.setSenderId(senderId != null ? senderId : 0); + notification.setSenderName(senderName); + notification.setSenderAvatar(senderAvatar); + notification.setCreateTime(LocalDateTime.now()); + notification.setUpdateTime(LocalDateTime.now()); + + try { + save(notification); + log.debug("[通知发送] userId={}, type={}, title={}", userId, type, title); + } catch (Exception e) { + log.error("[通知发送] 发送失败: userId={}, title={}", userId, title, e); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppPermissionRequestServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppPermissionRequestServiceImpl.java new file mode 100644 index 0000000..467be1f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppPermissionRequestServiceImpl.java @@ -0,0 +1,168 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppPermissionRequest; +import com.gxwebsoft.app.mapper.AppPermissionRequestMapper; +import com.gxwebsoft.app.param.AppPermissionRequestParam; +import com.gxwebsoft.app.service.AppPermissionRequestService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 权限申请Service实现 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Service +public class AppPermissionRequestServiceImpl extends ServiceImpl + implements AppPermissionRequestService { + + @Override + public IPage pageRel(AppPermissionRequestParam param) { + Page page = new Page<>(param.getPage(), param.getLimit()); + LambdaQueryWrapper wrapper = buildQueryWrapper(param); + return this.page(page, wrapper); + } + + @Override + public List listRel(AppPermissionRequestParam param) { + LambdaQueryWrapper wrapper = buildQueryWrapper(param); + return this.list(wrapper); + } + + @Override + public AppPermissionRequest getByIdRel(Long id) { + return this.getById(id); + } + + @Override + public Map getPermissionRequestStats(Integer userId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppPermissionRequest::getUserId, userId); + + List allList = this.list(wrapper); + long pending = allList.stream().filter(r -> "pending".equals(r.getStatus())).count(); + long approved = allList.stream().filter(r -> "approved".equals(r.getStatus())).count(); + long rejected = allList.stream().filter(r -> "rejected".equals(r.getStatus())).count(); + + Map stats = new HashMap<>(); + stats.put("total", allList.size()); + stats.put("pending", pending); + stats.put("approved", approved); + stats.put("rejected", rejected); + return stats; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AppPermissionRequest createPermissionRequest(Integer userId, String gitUsername, String repo, String repoName, String reason, Integer tenantId) { + // 检查是否已有待审核的申请 + LambdaQueryWrapper checkWrapper = new LambdaQueryWrapper<>(); + checkWrapper.eq(AppPermissionRequest::getUserId, userId); + checkWrapper.eq(AppPermissionRequest::getRepo, repo); + checkWrapper.eq(AppPermissionRequest::getStatus, "pending"); + AppPermissionRequest existing = this.getOne(checkWrapper); + + if (existing != null) { + throw new RuntimeException("该仓库已存在待审核的申请"); + } + + // 检查是否已通过审核 + List accessibleRepos = baseMapper.getAccessibleRepos(userId); + if (accessibleRepos != null && accessibleRepos.contains(repo)) { + throw new RuntimeException("你已拥有该仓库的访问权限"); + } + + AppPermissionRequest request = new AppPermissionRequest(); + request.setUserId(userId); + request.setGitUsername(gitUsername); + request.setRepo(repo); + request.setRepoName(repoName); + request.setReason(reason); + request.setStatus("pending"); + request.setTenantId(tenantId); + request.setCreateTime(LocalDateTime.now()); + request.setUpdateTime(LocalDateTime.now()); + + this.save(request); + return request; + } + + @Override + public List> getAvailableRepositories(Integer userId) { + return baseMapper.getAllReposWithAccessStatus(userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean approveRequest(Long requestId, Integer reviewerId, String reviewerName, String note) { + AppPermissionRequest request = this.getById(requestId); + if (request == null) { + throw new RuntimeException("申请记录不存在"); + } + if (!"pending".equals(request.getStatus())) { + throw new RuntimeException("该申请已被处理"); + } + + request.setStatus("approved"); + request.setReviewerId(reviewerId); + request.setReviewerName(reviewerName); + request.setReviewedAt(LocalDateTime.now()); + request.setUpdateTime(LocalDateTime.now()); + + return this.updateById(request); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean rejectRequest(Long requestId, Integer reviewerId, String reviewerName, String reason) { + AppPermissionRequest request = this.getById(requestId); + if (request == null) { + throw new RuntimeException("申请记录不存在"); + } + if (!"pending".equals(request.getStatus())) { + throw new RuntimeException("该申请已被处理"); + } + + request.setStatus("rejected"); + request.setReviewerId(reviewerId); + request.setReviewerName(reviewerName); + request.setRejectReason(reason); + request.setReviewedAt(LocalDateTime.now()); + request.setUpdateTime(LocalDateTime.now()); + + return this.updateById(request); + } + + /** + * 构建查询条件 + */ + private LambdaQueryWrapper buildQueryWrapper(AppPermissionRequestParam param) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (param.getUserId() != null) { + wrapper.eq(AppPermissionRequest::getUserId, param.getUserId()); + } + if (param.getStatus() != null && !param.getStatus().isEmpty()) { + wrapper.eq(AppPermissionRequest::getStatus, param.getStatus()); + } + if (param.getGitUsername() != null && !param.getGitUsername().isEmpty()) { + wrapper.like(AppPermissionRequest::getGitUsername, param.getGitUsername()); + } + if (param.getRepo() != null && !param.getRepo().isEmpty()) { + wrapper.like(AppPermissionRequest::getRepo, param.getRepo()); + } + wrapper.orderByDesc(AppPermissionRequest::getCreateTime); + return wrapper; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppPipelineServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppPipelineServiceImpl.java new file mode 100644 index 0000000..64a578a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppPipelineServiceImpl.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppPipeline; +import com.gxwebsoft.app.mapper.AppPipelineMapper; +import com.gxwebsoft.app.param.AppPipelineParam; +import com.gxwebsoft.app.service.AppPipelineService; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * CI/CD 流水线 Service 实现 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Service +public class AppPipelineServiceImpl extends ServiceImpl + implements AppPipelineService { + + @Override + public PageResult pagePipeline(AppPipelineParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPipelineList(param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public AppPipeline getPipelineDetail(Long id) { + return baseMapper.selectPipelineDetail(id); + } + + @Override + public List getByAppId(Long appId) { + return baseMapper.selectByAppId(appId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean createPipeline(AppPipeline pipeline) { + // 设置默认值 + if (pipeline.getEnabled() == null) { + pipeline.setEnabled(true); + } + if (pipeline.getAutoDeploy() == null) { + pipeline.setAutoDeploy(false); + } + if (pipeline.getTimeout() == null) { + pipeline.setTimeout(3600); // 默认1小时 + } + if (pipeline.getDefaultBranch() == null) { + pipeline.setDefaultBranch("main"); + } + + pipeline.setSuccessCount(0); + pipeline.setFailureCount(0); + pipeline.setCreateTime(LocalDateTime.now()); + pipeline.setUpdateTime(LocalDateTime.now()); + + return save(pipeline); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updatePipeline(AppPipeline pipeline) { + pipeline.setUpdateTime(LocalDateTime.now()); + return updateById(pipeline); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deletePipeline(Long id) { + return removeById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean togglePipeline(Long id, boolean enabled) { + AppPipeline pipeline = getById(id); + if (pipeline == null) { + throw new RuntimeException("流水线不存在"); + } + + pipeline.setEnabled(enabled); + pipeline.setUpdateTime(LocalDateTime.now()); + return updateById(pipeline); + } + + @Override + public String getPipelineStatus(Long id) { + AppPipeline pipeline = getById(id); + if (pipeline == null) { + return "unknown"; + } + + // 如果有最近构建,直接返回构建状态 + if (pipeline.getLastBuildStatus() != null) { + return pipeline.getLastBuildStatus(); + } + + // 否则返回启用状态 + return pipeline.getEnabled() ? "active" : "disabled"; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppProductServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppProductServiceImpl.java new file mode 100644 index 0000000..872ec85 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppProductServiceImpl.java @@ -0,0 +1,326 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.mapper.AppProductMapper; +import com.gxwebsoft.app.mapper.AppUserMapper; +import com.gxwebsoft.app.service.AppProductService; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.json.JSONUtil; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +/** + * 应用产品 服务实现 + * + * @author 科技小王子 + */ +@Service +public class AppProductServiceImpl extends ServiceImpl implements AppProductService { + + private final com.gxwebsoft.app.mapper.AppUserMapper appUserMapper; + + public AppProductServiceImpl(com.gxwebsoft.app.mapper.AppUserMapper appUserMapper) { + this.appUserMapper = appUserMapper; + } + + @Override + public IPage selectPageList(Page page, AppProduct product, Integer userId) { + return baseMapper.selectPageList(page, product, userId); + } + + @Override + public AppProduct getDetail(Integer productId) { + return baseMapper.selectById(productId); + } + + @Override + public AppProduct getByCode(String code) { + return baseMapper.selectByCode(code); + } + + @Override + public List getByUserId(Integer userId) { + return baseMapper.selectByUserId(userId); + } + + @Override + public IPage getMyApps(Page page, Integer userId) { + return baseMapper.selectPageByUserId(page, userId); + } + + @Override + public IPage getJoinedApps(Page page, Integer userId) { + return baseMapper.selectPageJoinedApps(page, userId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean create(AppProduct product) { + // 生成唯一标识 + if (product.getProductCode() == null || product.getProductCode().isEmpty()) { + product.setProductCode(generateCode()); + } + // 生成密钥 + if (product.getProductSecret() == null || product.getProductSecret().isEmpty()) { + product.setProductSecret(generateSecret()); + } + // 设置默认值 + if (product.getPublishStatus() == null) { + product.setPublishStatus(AppProduct.PUBLISH_DEVELOPING); + } + if (product.getStatus() == null) { + product.setStatus(0); // 未开通 + } + if (product.getDeleted() == null) { + product.setDeleted(0); + } + if (product.getSortNumber() == null) { + product.setSortNumber(0); + } + // 设置用户和租户信息 + Integer userId = getLoginUserId(); + Integer tenantId = getLoginTenantId(); + if (userId != null) { + product.setUserId(userId); + } + if (tenantId != null) { + product.setTenantId(tenantId); + } + + // 保存应用 + boolean saved = this.save(product); + if (saved && product.getProductId() != null && userId != null) { + // 获取当前登录用户信息 + com.gxwebsoft.common.system.entity.User loginUser = getLoginUser(); + + // 自动将创建者加入 app_user 表 + AppUser appUser = new AppUser(); + appUser.setAppId(product.getProductId().longValue()); + appUser.setUserId(userId); + appUser.setRole("owner"); // 创建者是 owner + appUser.setTenantId(tenantId); + appUser.setInviteBy(0L); // 系统创建,无邀请人 + appUser.setInviteTime(LocalDateTime.now()); + appUser.setStatus(0); + appUser.setSortNumber(0); + appUser.setCreateTime(LocalDateTime.now()); + + // 冗余存储用户信息,方便查询展示 + if (loginUser != null) { + appUser.setUsername(loginUser.getUsername()); + appUser.setNickname(loginUser.getNickname()); + appUser.setAvatar(loginUser.getAvatar()); + // 手机号脱敏存储(只存后4位或隐藏) + String phone = loginUser.getPhone(); + if (phone != null && !phone.isEmpty()) { + // 脱敏:保留后4位,其余用 * 代替 + if (phone.length() > 4) { + appUser.setPhone("****" + phone.substring(phone.length() - 4)); + } else { + appUser.setPhone(phone); + } + } + } + + appUserMapper.insert(appUser); + } + return saved; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean update(AppProduct product) { + return this.updateById(product); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delete(Integer productId) { + return this.removeById(productId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean submitReview(Integer productId) { + return baseMapper.updatePublishStatus(productId, AppProduct.PUBLISH_PENDING_REVIEW) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean approve(Integer productId) { + return baseMapper.updatePublishStatus(productId, AppProduct.PUBLISH_PUBLISHED) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean reject(Integer productId, String reason) { + AppProduct product = new AppProduct(); + product.setProductId(productId); + product.setPublishStatus(AppProduct.PUBLISH_REJECTED); + product.setRejectReason(reason); + product.setReviewerId(getLoginUserId()); + return this.updateById(product); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean publish(Integer productId) { + return baseMapper.updatePublishStatus(productId, AppProduct.PUBLISH_PUBLISHED) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean unpublish(Integer productId) { + return baseMapper.updatePublishStatus(productId, AppProduct.PUBLISH_DEPRECATED) > 0; + } + + @Override + public void incrementClicks(Integer productId) { + baseMapper.incrementClicks(productId); + } + + @Override + public void incrementInstalls(Integer productId) { + baseMapper.incrementInstalls(productId); + } + + @Override + public void incrementDownloads(Integer productId) { + baseMapper.incrementDownloads(productId); + } + + @Override + public void incrementLikes(Integer productId) { + baseMapper.incrementLikes(productId); + } + + @Override + public String regenerateSecret(Integer productId) { + String newSecret = generateSecret(); + AppProduct product = new AppProduct(); + product.setProductId(productId); + product.setProductSecret(newSecret); + this.updateById(product); + return newSecret; + } + + @Override + public IPage getMarketList(Page page, Integer appType, String keyword) { + AppProduct product = new AppProduct(); + product.setMarket(1); // 上架市场 + product.setPublishStatus(AppProduct.PUBLISH_PUBLISHED); + product.setAppType(appType); + if (keyword != null && !keyword.isEmpty()) { + product.setProductName(keyword); + } + return baseMapper.selectPageList(page, product, null); + } + + @Override + public AppProduct getConfigField(Integer tenantId, String code) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppProduct::getTenantId, tenantId); + wrapper.eq(AppProduct::getAppType, AppProduct.APP_TYPE_WEBSITE); + AppProduct product = this.getOne(wrapper); + + if (product != null && product.getConfig() != null && !product.getConfig().isEmpty()) { + // 解析 config JSON,查找对应字段 + try { + Map configMap = JSONUtil.toBean(product.getConfig(), Map.class); + if (configMap.containsKey(code)) { + // 创建一个只包含配置值的 AppProduct 用于返回 + AppProduct result = new AppProduct(); + result.setConfig(product.getConfig()); + // 可以根据 code 返回不同的值,这里返回整个 product + return result; + } + } catch (Exception e) { + // 解析失败,返回原数据 + } + } + return product; + } + + /** + * 生成应用标识 + */ + private String generateCode() { + return "APP" + IdUtil.getSnowflakeNextId(); + } + + /** + * 生成应用密钥 + */ + private String generateSecret() { + return RandomUtil.randomString(32); + } + + @Override + public List> getStatsByUserIds(List userIds) { + if (userIds == null || userIds.isEmpty()) { + return List.of(); + } + List rawList = baseMapper.selectStatsByUserIds(userIds); + // 将 List 转换为 List> + return rawList.stream() + .map(map -> (Map) map) + .toList(); + } + + @Override + public List getAccessibleApps(Integer userId) { + if (userId == null) { + return List.of(); + } + return baseMapper.selectAccessibleApps(userId); + } + + /** + * 获取登录用户 + */ + private com.gxwebsoft.common.system.entity.User getLoginUser() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.getPrincipal() instanceof com.gxwebsoft.common.system.entity.User) { + return (com.gxwebsoft.common.system.entity.User) authentication.getPrincipal(); + } + } catch (Exception e) { + // 忽略异常 + } + return null; + } + + /** + * 获取登录用户ID + */ + private Integer getLoginUserId() { + com.gxwebsoft.common.system.entity.User user = getLoginUser(); + return user != null ? user.getUserId() : null; + } + + /** + * 获取登录租户ID + */ + private Integer getLoginTenantId() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.getPrincipal() instanceof com.gxwebsoft.common.system.entity.User) { + return ((com.gxwebsoft.common.system.entity.User) authentication.getPrincipal()).getTenantId(); + } + } catch (Exception e) { + // 忽略异常 + } + return null; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppResourceServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppResourceServiceImpl.java new file mode 100644 index 0000000..64c1155 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppResourceServiceImpl.java @@ -0,0 +1,1100 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppResource; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.entity.ResourceAccessLevel; +import com.gxwebsoft.app.mapper.AppProductMapper; +import com.gxwebsoft.app.mapper.AppResourceMapper; +import com.gxwebsoft.app.mapper.AppUserMapper; +import com.gxwebsoft.app.param.AppResourceParam; +import com.gxwebsoft.app.service.AppCloudCredentialService; +import com.gxwebsoft.app.service.AppResourceService; +import com.gxwebsoft.app.service.DatabaseOperatorFactory; +import com.gxwebsoft.app.service.DatabaseOperatorService; +import com.gxwebsoft.app.service.cloud.CloudStorageProvider; +import com.gxwebsoft.app.service.cloud.CloudStorageProviderFactory; +import com.gxwebsoft.common.core.utils.DbPasswordUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * 开发者资源 Service 实现 + * + * @author 科技小王子 + * @since 2026-03-31 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AppResourceServiceImpl extends ServiceImpl + implements AppResourceService { + + private final DatabaseOperatorFactory databaseOperatorFactory; + private final AppCloudCredentialService cloudCredentialService; + private final AppUserMapper appUserMapper; + private final AppProductMapper appProductMapper; + + private static final Pattern IPV4_PATTERN = Pattern.compile( + "^(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)){3}$" + ); + + @Override + public PageResult pageRel(AppResourceParam param, Integer currentUserId) { + // 填充用户有权限的应用ID列表(创建的 + 参与的),用于资源协作权限过滤 + fillUserAppIds(param, currentUserId); + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + if (currentUserId != null) { + enrichWithPermission(list, currentUserId); + } else { + // 兼容旧调用,直接解密 + decryptPasswordList(list); + } + // 补充数据库连接端口 + enrichPort(list); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AppResourceParam param, Integer currentUserId) { + // 填充用户有权限的应用ID列表 + fillUserAppIds(param, currentUserId); + List list = baseMapper.selectListRel(param); + if (currentUserId != null) { + enrichWithPermission(list, currentUserId); + } else { + // 兼容旧调用,直接解密 + decryptPasswordList(list); + } + // 补充数据库连接端口 + enrichPort(list); + return list; + } + + @Override + public AppResource getByIdRel(Long resourceId, Integer currentUserId) { + AppResourceParam param = new AppResourceParam(); + param.setResourceId(resourceId); + List list = baseMapper.selectListRel(param); + AppResource result = list.isEmpty() ? null : list.get(0); + if (currentUserId != null) { + enrichWithPermission(List.of(result), currentUserId); + } else { + // 兼容旧调用,直接解密 + decryptPassword(result); + } + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AppResource addResource(AppResource resource, Integer userId) { + resource.setUserId(userId); + // 自动设置 ownerUserId(权限控制基准) + resource.setOwnerUserId(userId.longValue()); + + validateServerResource(resource, null); + resource.setDeleted(0); + resource.setCreateTime(LocalDateTime.now()); + resource.setUpdateTime(LocalDateTime.now()); + // 默认状态 + if (resource.getStatus() == null) { + resource.setStatus("running"); + } + // 加密数据库密码 + encryptDbPassword(resource); + // 加密管理员密码 + encryptAdminPassword(resource); + // 加密 SSH 密码 + encryptSshPassword(resource); + // 如果是云存储类型,同步调用云厂商 API 创建存储桶,成功后再入库 + if ("storage".equals(resource.getResourceType())) { + // 先获取凭证 + Map credentials; + if (resource.getCredentialId() != null) { + credentials = cloudCredentialService.getCredentialsByCredentialId(resource.getCredentialId()); + if (credentials == null || credentials.isEmpty()) { + throw new RuntimeException("云账号凭证无效"); + } + } else { + credentials = cloudCredentialService.getCredentials(resource.getProvider(), userId); + if (credentials == null || credentials.isEmpty()) { + throw new RuntimeException("请先配置云账号凭证"); + } + } + + log.info("同步创建云存储桶: provider={}, bucket={}, region={}", + resource.getProvider(), resource.getName(), resource.getRegion()); + + // 同步调用云厂商 API 创建存储桶(失败则抛异常,不入库) + CloudStorageProvider cloudProvider = CloudStorageProviderFactory.getProvider(resource.getProvider()); + try { + cloudProvider.createBucket(resource, credentials); + // 创建成功,获取 endpoint + String endpoint = cloudProvider.getBucketEndpoint(resource, credentials); + resource.setRemark("访问地址: " + endpoint); + } catch (Exception e) { + log.error("创建云存储桶失败: {}", e.getMessage()); + throw new RuntimeException("创建云存储桶失败: " + e.getMessage()); + } + } + + // 保存资源到数据库 + try { + save(resource); + } catch (DuplicateKeyException e) { + throw new RuntimeException(getDuplicateErrorMessage(resource)); + } + + return resource; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AppResource updateResource(AppResource resource, Integer currentUserId) { + if (resource.getResourceId() == null) { + throw new RuntimeException("资源ID不能为空"); + } + AppResource current = getById(resource.getResourceId()); + if (current == null || Integer.valueOf(1).equals(current.getDeleted())) { + throw new RuntimeException("资源不存在"); + } + + // 权限校验:只有资源创建者(ownerUserId)可以修改 + // 注意:ownerUserId 是 Long 类型,currentUserId 是 Integer 类型,需要类型转换后比较 + Long ownerUserId = current.getOwnerUserId(); + Integer ownerUserIdInt = ownerUserId != null ? ownerUserId.intValue() : null; + if (currentUserId != null && !currentUserId.equals(ownerUserIdInt)) { + throw new RuntimeException("只有资源创建者才能修改资源"); + } + + // 更新时保持 ownerUserId 不变(防止篡改归属) + resource.setOwnerUserId(current.getOwnerUserId()); + + validateServerResource(resource, current); + resource.setUpdateTime(LocalDateTime.now()); + // 加密数据库密码(如果有更新) + encryptDbPassword(resource); + // 加密管理员密码(如果有更新) + encryptAdminPassword(resource); + // 加密 SSH 密码(如果有更新) + encryptSshPassword(resource); + try { + // ACL 变更时同步到云端 + if ("storage".equals(current.getResourceType()) && resource.getAcl() != null + && !resource.getAcl().equals(current.getAcl())) { + syncBucketAcl(current, resource); + } + updateById(resource); + } catch (DuplicateKeyException e) { + throw new RuntimeException(getDuplicateErrorMessage(resource)); + } + // getByIdRel 内部会根据 currentUserId 注入权限字段 + return getByIdRel(resource.getResourceId(), currentUserId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void removeResource(Long resourceId, Integer userId) { + AppResource resource = getById(resourceId); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + // 权限校验:只有资源创建者(ownerUserId)可以删除(用户ID兼容旧调用) + if (!resource.getOwnerUserId().equals(userId.longValue())) { + throw new RuntimeException("只有资源创建者才能删除资源"); + } + + // 如果是存储桶类型,尝试远程删除 + if ("storage".equals(resource.getResourceType())) { + try { + deleteRemoteStorage(resource, userId); + } catch (Exception e) { + log.error("远程删除存储桶失败, resourceId={}, error={}", resourceId, e.getMessage()); + throw new RuntimeException("远程删除存储桶失败: " + e.getMessage()); + } + } + + // 如果是数据库类型且有关联的服务器,尝试远程删除 + if ("database".equals(resource.getResourceType()) && resource.getServerResourceId() != null) { + String dbType = resource.getDbType(); + if ("MySQL".equals(dbType) || "PostgreSQL".equals(dbType)) { + try { + dropRemoteDatabase(resource); + } catch (Exception e) { + log.error("远程删除数据库失败, resourceId={}, error={}", resourceId, e.getMessage()); + throw new RuntimeException("远程删除数据库失败: " + e.getMessage()); + } + } + } + + resource.setDeleted(1); + resource.setUpdateTime(LocalDateTime.now()); + updateById(resource); + log.info("删除资源成功, resourceId={}, ownerUserId={}", resourceId, resource.getOwnerUserId()); + } + + /** + * 删除远程数据库 + */ + private void dropRemoteDatabase(AppResource dbResource) { + // 获取关联的服务器信息 + AppResource server = getById(dbResource.getServerResourceId()); + if (server == null) { + log.warn("关联的服务器不存在, serverResourceId={}", dbResource.getServerResourceId()); + return; + } + if (server.getAdminUsername() == null || server.getAdminPassword() == null) { + log.warn("服务器未配置管理员凭据,跳过远程删除, serverResourceId={}", server.getResourceId()); + return; + } + + // 从关联的服务器获取端口 + String dbType = dbResource.getDbType(); + Integer port; + if ("PostgreSQL".equals(dbType)) { + port = server.getPgPort() != null ? server.getPgPort() : 5432; + } else { + // MySQL 及其他 + port = server.getMysqlPort() != null ? server.getMysqlPort() : 3306; + } + + // 解密管理员密码 + String adminPassword = DbPasswordUtil.decrypt(server.getAdminPassword()); + + log.info("开始远程删除数据库: type={}, db={}, server={}:{}", dbType, dbResource.getName(), server.getIp(), port); + + // 调用远程删除 + DatabaseOperatorService operator = databaseOperatorFactory.getOperator(dbType); + DatabaseOperatorService.DatabaseOperationResult result = operator.dropDatabaseAndUser( + server.getIp(), port, + server.getAdminUsername(), adminPassword, + dbResource.getName(), dbResource.getDbUsername() + ); + + if (!result.isSuccess()) { + throw new RuntimeException(result.getMessage()); + } + log.info("远程删除数据库成功, dbName={}", dbResource.getName()); + } + + @Override + public Map countByType(Integer userId, Integer tenantId) { + // 获取用户有权限的应用ID列表(创建的 + 参与的) + List userAppIds = getUserAppIds(userId); + + // 使用包含协作资源的统计方法 + List> raw = baseMapper.countByTypeForUser(userId, tenantId, userAppIds); + Map result = new HashMap<>(); + // 初始化所有类型为 0 + for (String type : new String[]{"server", "database", "storage", "domain", "ssl", "git"}) { + result.put(type, 0L); + } + for (Map row : raw) { + String type = (String) row.get("resourceType"); + Long cnt = ((Number) row.get("cnt")).longValue(); + result.put(type, cnt); + } + return result; + } + + /** + * 获取用户有权限的应用ID列表(包括 owner + 参与的所有应用) + * 通过 app_user 表查参与的应用,通过 app_product 表查创建的应用 + */ + private List getUserAppIds(Integer userId) { + if (userId == null) { + return List.of(); + } + // 1. 参与的应用(通过 app_user 关联) + List joinedAppIds = appUserMapper.selectList(new LambdaQueryWrapper() + .select(AppUser::getAppId) + .eq(AppUser::getUserId, userId) + .in(AppUser::getStatus, 0, 1)) + .stream() + .map(AppUser::getAppId) + .toList(); + + // 2. 创建的应用(通过 app_product 查 user_id) + List ownedAppIds = appProductMapper.selectList( + new LambdaQueryWrapper() + .select(com.gxwebsoft.app.entity.AppProduct::getProductId) + .eq(com.gxwebsoft.app.entity.AppProduct::getUserId, userId) + .eq(com.gxwebsoft.app.entity.AppProduct::getDeleted, 0)) + .stream() + .map(com.gxwebsoft.app.entity.AppProduct::getProductId) + .map(Long::valueOf) + .toList(); + + // 3. 合并去重 + return java.util.stream.Stream.concat(joinedAppIds.stream(), ownedAppIds.stream()) + .distinct() + .collect(java.util.stream.Collectors.toList()); + } + + /** + * 填充用户有权限的应用ID列表到查询参数中 + * 使 SQL 条件生效:owner_user_id = 当前用户 OR app_id IN (用户有权限的应用) + */ + private void fillUserAppIds(AppResourceParam param, Integer currentUserId) { + if (currentUserId != null && param.getUserAppIds() == null) { + param.setUserAppIds(getUserAppIds(currentUserId)); + } + } + + private void validateServerResource(AppResource resource, AppResource current) { + String resourceType = normalizeText(resource.getResourceType()); + if (resourceType == null && current != null) { + resourceType = normalizeText(current.getResourceType()); + } + if (resourceType == null) { + return; + } + resource.setResourceType(resourceType); + + Integer userId = current != null ? current.getUserId() : resource.getUserId(); + Integer tenantId = current != null ? current.getTenantId() : resource.getTenantId(); + Long excludeResourceId = current != null ? current.getResourceId() : null; + + if ("server".equals(resourceType)) { + validateAndEnsureServerUnique(resource, current, userId, tenantId, excludeResourceId); + } else if ("database".equals(resourceType)) { + validateAndEnsureDatabaseUnique(resource, current, userId, tenantId, excludeResourceId); + } + } + + private void validateAndEnsureServerUnique(AppResource resource, AppResource current, + Integer userId, Integer tenantId, Long excludeResourceId) { + String ip = normalizeText(resource.getIp()); + if (ip == null && current != null) { + ip = normalizeText(current.getIp()); + } + if (ip == null) { + throw new RuntimeException("服务器 IP 地址不能为空"); + } + if (!isValidIpAddress(ip)) { + throw new RuntimeException("IP 地址格式不正确"); + } + + long count = lambdaQuery() + .eq(AppResource::getDeleted, 0) + .eq(AppResource::getResourceType, "server") + .eq(AppResource::getIp, ip) + .eq(userId != null, AppResource::getUserId, userId) + .eq(tenantId != null, AppResource::getTenantId, tenantId) + .ne(excludeResourceId != null, AppResource::getResourceId, excludeResourceId) + .count(); + if (count > 0) { + throw new RuntimeException("该 IP 已存在,请勿重复添加"); + } + resource.setIp(ip); + } + + private void validateAndEnsureDatabaseUnique(AppResource resource, AppResource current, + Integer userId, Integer tenantId, Long excludeResourceId) { + String name = normalizeText(resource.getName()); + String host = normalizeText(resource.getHost()); + String dbType = normalizeText(resource.getDbType()); + + // 从当前记录补全缺失字段 + if (current != null) { + if (name == null) name = normalizeText(current.getName()); + if (host == null) host = normalizeText(current.getHost()); + if (dbType == null) dbType = normalizeText(current.getDbType()); + } + + if (name == null || host == null || dbType == null) { + return; // 必填校验在 controller 或前端处理 + } + + // 检查同一用户下 name + host + dbType 是否重复 + long count = lambdaQuery() + .eq(AppResource::getDeleted, 0) + .eq(AppResource::getResourceType, "database") + .eq(AppResource::getName, name) + .eq(AppResource::getHost, host) + .eq(AppResource::getDbType, dbType) + .eq(userId != null, AppResource::getUserId, userId) + .eq(tenantId != null, AppResource::getTenantId, tenantId) + .ne(excludeResourceId != null, AppResource::getResourceId, excludeResourceId) + .count(); + if (count > 0) { + throw new RuntimeException("该数据库配置已存在(名称、地址、类型相同),请勿重复添加"); + } + + resource.setName(name); + resource.setHost(host); + resource.setDbType(dbType); + } + + + + private boolean isValidIpAddress(String ip) { + if (IPV4_PATTERN.matcher(ip).matches()) { + return true; + } + if (!ip.contains(":")) { + return false; + } + try { + return InetAddress.getByName(ip) instanceof Inet6Address; + } catch (Exception e) { + return false; + } + } + + private String normalizeText(String value) { + if (value == null) { + return null; + } + String normalized = value.trim(); + return normalized.isEmpty() ? null : normalized; + } + + /** + * 获取重复数据的友好错误提示 + */ + private String getDuplicateErrorMessage(AppResource resource) { + String type = normalizeText(resource.getResourceType()); + if ("database".equals(type)) { + return "该数据库配置已存在(名称、地址、类型相同),请勿重复添加"; + } + if ("server".equals(type)) { + return "该服务器 IP 已存在,请勿重复添加"; + } + return "该资源已存在,请勿重复添加"; + } + + /** + * 加密数据库密码 + */ + private void encryptDbPassword(AppResource resource) { + if (resource.getDbPassword() != null && !resource.getDbPassword().isEmpty()) { + resource.setDbPassword(DbPasswordUtil.encrypt(resource.getDbPassword())); + } + } + + /** + * 解密数据库密码 + */ + private void decryptDbPassword(AppResource resource) { + if (resource != null && resource.getDbPassword() != null && !resource.getDbPassword().isEmpty()) { + resource.setDbPassword(DbPasswordUtil.decrypt(resource.getDbPassword())); + } + } + + /** + * 统一解密所有密码字段(数据库密码 + 管理员密码 + SSH密码) + */ + private void decryptPassword(AppResource resource) { + decryptDbPassword(resource); + decryptAdminPassword(resource); + decryptSshPassword(resource); + } + + /** + * 批量解密密码(用于列表查询,同时解密业务密码和管理员密码) + */ + private void decryptPasswordList(List list) { + if (list != null) { + for (AppResource resource : list) { + decryptPassword(resource); + } + } + } + + /** + * 加密管理员密码 + */ + private void encryptAdminPassword(AppResource resource) { + if (resource.getAdminPassword() != null && !resource.getAdminPassword().isEmpty()) { + resource.setAdminPassword(DbPasswordUtil.encrypt(resource.getAdminPassword())); + } + } + + /** + * 解密管理员密码 + */ + private void decryptAdminPassword(AppResource resource) { + if (resource != null && resource.getAdminPassword() != null && !resource.getAdminPassword().isEmpty()) { + resource.setAdminPassword(DbPasswordUtil.decrypt(resource.getAdminPassword())); + } + } + + /** + * 加密 SSH 密码 + */ + private void encryptSshPassword(AppResource resource) { + if (resource.getSshPassword() != null && !resource.getSshPassword().isEmpty()) { + resource.setSshPassword(DbPasswordUtil.encrypt(resource.getSshPassword())); + } + } + + /** + * 解密 SSH 密码 + */ + private void decryptSshPassword(AppResource resource) { + if (resource != null && resource.getSshPassword() != null && !resource.getSshPassword().isEmpty()) { + resource.setSshPassword(DbPasswordUtil.decrypt(resource.getSshPassword())); + } + } + + // ─── 协作权限核心逻辑 ────────────────────────────────────────────── + + @Override + public void enrichWithPermission(List resources, Integer currentUserId) { + if (resources == null || resources.isEmpty() || currentUserId == null) { + return; + } + + for (AppResource resource : resources) { + // 计算访问级别 + ResourceAccessLevel accessLevel = calculateAccessLevel(currentUserId, resource); + resource.setAccessLevel(accessLevel.getValue()); + resource.setIsOwner(accessLevel == ResourceAccessLevel.FULL); + + // 根据权限屏蔽敏感字段 + maskSensitiveFieldsByAccessLevel(resource, accessLevel); + } + } + + /** + * 计算当前用户对指定资源的访问级别 + */ + private ResourceAccessLevel calculateAccessLevel(Integer userId, AppResource resource) { + // Owner 拥有完全权限 + if (userId.equals(resource.getOwnerUserId())) { + return ResourceAccessLevel.FULL; + } + + // 查询用户是否是应用成员 + if (resource.getAppId() == null) { + // 无应用关联的资源,只有 Owner 能访问 + return ResourceAccessLevel.NONE; + } + + AppUser appMember = appUserMapper.selectOne(new LambdaQueryWrapper() + .eq(AppUser::getAppId, resource.getAppId()) + .eq(AppUser::getUserId, userId) + .in(AppUser::getStatus, 0, 1)); // 状态正常或冻结 + + if (appMember == null) { + return ResourceAccessLevel.NONE; + } + + // 根据角色决定访问级别 + // developer 及以上角色(owner/admin/developer)可查看连接信息(用户名、端口、1Panel、SSH) + String role = appMember.getRole(); + if ("owner".equals(role) || "admin".equals(role) || "developer".equals(role)) { + return ResourceAccessLevel.VIEW_CONNECTION; + } + + // viewer 只允许基础查看(名称/IP/端口/状态) + return ResourceAccessLevel.VIEW_BASIC; + } + + /** + * 根据访问级别屏蔽敏感字段 + */ + private void maskSensitiveFieldsByAccessLevel(AppResource resource, ResourceAccessLevel level) { + // FULL 级别(Owner)可看所有字段,不解密密码(保持前端加密状态) + if (level.atLeast(ResourceAccessLevel.FULL)) { + // Owner 能看到真实密码,但仍需要在返回前解密(因为前端需要明文) + decryptPassword(resource); + return; + } + + // VIEW_CONNECTION 级别(owner/admin/developer 角色)可看用户名、数据库密码、SSL 证书,其他密码遮罩 + if (level.atLeast(ResourceAccessLevel.VIEW_CONNECTION)) { + // 数据库密码解密返回(developer 需要连接数据库) + decryptDbPassword(resource); + // SSH 密码和管理员密码遮罩为 "******" + if (resource.getSshPassword() != null && !resource.getSshPassword().isEmpty()) { + resource.setSshPassword("******"); + } + if (resource.getAdminPassword() != null && !resource.getAdminPassword().isEmpty()) { + resource.setAdminPassword("******"); + } + // SSL 证书:developer 可查看私钥和证书内容(部署证书需要) + // privateKey、certificate、certChain 保持原值不清空 + } else { + // VIEW_BASIC 级别(基础查看)只能看名称/IP/端口/状态 + resource.setSshUsername(null); + resource.setSshPassword(null); + resource.setAdminUsername(null); + resource.setAdminPassword(null); + resource.setDbUsername(null); + resource.setDbPassword(null); + resource.setPrivateKey(null); + resource.setPublicKey(null); + resource.setCertificate(null); + resource.setCertChain(null); + } + } + + /** + * 将密码字段替换为 "******" 占位符 + */ + private void maskPasswordFields(AppResource resource) { + if (resource.getSshPassword() != null && !resource.getSshPassword().isEmpty()) { + resource.setSshPassword("******"); + } + if (resource.getAdminPassword() != null && !resource.getAdminPassword().isEmpty()) { + resource.setAdminPassword("******"); + } + if (resource.getDbPassword() != null && !resource.getDbPassword().isEmpty()) { + resource.setDbPassword("******"); + } + } + + /** + * 检查输入是否非空 + */ + private boolean hasContent(String str) { + return str != null && !str.trim().isEmpty(); + } + + /** + * 异步创建数据库 + * 在事务提交后执行,通过 resourceId 查询关联的服务器资源获取管理员凭据 + */ + @Async + public void asyncCreateDatabase(Long resourceId) { + try { + // 延迟 500ms 确保事务已提交 + Thread.sleep(500); + + // 查询数据库资源记录 + AppResource dbResource = getById(resourceId); + if (dbResource == null) { + log.warn("异步建库失败: 资源不存在, resourceId={}", resourceId); + return; + } + + // 查询关联的服务器资源 + AppResource server = getById(dbResource.getServerResourceId()); + if (server == null) { + log.warn("异步建库失败: 关联服务器不存在, serverResourceId={}", dbResource.getServerResourceId()); + updateStatus(resourceId, "failed", "关联服务器资源不存在"); + return; + } + + // 解密管理员密码 + String adminPwd = ""; + if (server.getAdminPassword() != null && !server.getAdminPassword().isEmpty()) { + adminPwd = DbPasswordUtil.decrypt(server.getAdminPassword()); + } + // 解密业务数据库密码 + String dbPass = ""; + if (dbResource.getDbPassword() != null && !dbResource.getDbPassword().isEmpty()) { + dbPass = DbPasswordUtil.decrypt(dbResource.getDbPassword()); + } + + // 根据数据库类型获取对应的端口 + String dbType = dbResource.getDbType(); + int serverPort; + if ("PostgreSQL".equals(dbType)) { + serverPort = server.getPgPort() != null ? server.getPgPort() : 5432; + } else { + // MySQL 及其他,默认 3306 + serverPort = server.getMysqlPort() != null ? server.getMysqlPort() : 3306; + } + + log.info("开始异步创建数据库: type={}, db={}, server={}:{}, adminUser={}", + dbType, dbResource.getName(), server.getIp(), serverPort, server.getAdminUsername()); + + // 更新状态为创建中 + updateStatus(resourceId, "pending", "正在创建" + dbType + "数据库..."); + + // 通过工厂获取对应数据库类型的操作服务 + DatabaseOperatorService operator = databaseOperatorFactory.getOperator(dbType); + + // 执行远程建库 + DatabaseOperatorService.DatabaseOperationResult result = operator.createDatabaseAndGrant( + server.getIp(), + serverPort, + server.getAdminUsername(), + adminPwd, + dbResource.getName(), + dbResource.getDbUsername(), + dbPass + ); + + if (result.isSuccess()) { + updateStatus(resourceId, "running", result.getMessage()); + log.info("异步创建数据库成功: type={}, db={}, resourceId={}", dbType, dbResource.getName(), resourceId); + } else { + updateStatus(resourceId, "failed", result.getMessage()); + log.error("异步创建数据库失败: type={}, db={}, resourceId={}, error={}", + dbType, dbResource.getName(), resourceId, result.getDetail()); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("异步创建数据库被中断: resourceId={}", resourceId); + } catch (Exception e) { + log.error("异步创建数据库异常: resourceId={}, error={}", resourceId, e.getMessage(), e); + updateStatus(resourceId, "failed", "创建数据库异常: " + e.getMessage()); + } + } + + /** + * 更新资源状态和备注 + */ + private void updateStatus(Long resourceId, String status, String remark) { + AppResource update = new AppResource(); + update.setResourceId(resourceId); + update.setStatus(status); + update.setRemark(remark); + update.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(update); + } + + /** + * 同步存储桶 ACL 到云端 + */ + private void syncBucketAcl(AppResource oldResource, AppResource newResource) { + String provider = oldResource.getProvider(); + if (provider == null) { + log.warn("同步 ACL 失败: 服务商未指定, resourceId={}", oldResource.getResourceId()); + return; + } + + // 获取云账号凭证 + Map credentials; + if (oldResource.getCredentialId() != null) { + credentials = cloudCredentialService.getCredentialsByCredentialId(oldResource.getCredentialId()); + } else { + credentials = cloudCredentialService.getCredentials(provider, oldResource.getOwnerUserId().intValue()); + } + + if (credentials == null || credentials.isEmpty()) { + log.warn("同步 ACL 失败: 云账号凭证不存在, resourceId={}", oldResource.getResourceId()); + return; + } + + try { + CloudStorageProvider cloudProvider = CloudStorageProviderFactory.getProvider(provider); + cloudProvider.setBucketAcl(oldResource, newResource.getAcl(), credentials); + log.info("存储桶 ACL 已同步: bucket={}, acl={}", oldResource.getName(), newResource.getAcl()); + } catch (Exception e) { + log.error("同步 ACL 失败: resourceId={}, error={}", oldResource.getResourceId(), e.getMessage(), e); + } + } + + /** + * 删除远程云存储桶 + */ + private void deleteRemoteStorage(AppResource resource, Integer userId) { + String provider = resource.getProvider(); + if (provider == null) { + throw new RuntimeException("服务商未指定"); + } + + // 获取云账号凭证 + Map credentials; + if (resource.getCredentialId() != null) { + credentials = cloudCredentialService.getCredentialsByCredentialId(resource.getCredentialId()); + } else { + credentials = cloudCredentialService.getCredentials(provider, userId); + } + + if (credentials == null || credentials.isEmpty()) { + throw new RuntimeException("云账号凭证不存在"); + } + + // 根据 region 构建 endpoint + String region = resource.getRegion(); + if (region != null && !region.isEmpty()) { + String endpoint = buildEndpoint(provider, region); + if (endpoint != null) { + credentials.put("endpoint", endpoint); + } + } + + try { + CloudStorageProvider cloudProvider = CloudStorageProviderFactory.getProvider(provider); + cloudProvider.deleteBucket(resource, credentials); + log.info("远程存储桶已删除: bucket={}, provider={}", resource.getName(), provider); + } catch (Exception e) { + throw new RuntimeException("远程删除存储桶失败: " + e.getMessage()); + } + } + + /** + * 根据服务商和 region 构建 endpoint + */ + private String buildEndpoint(String provider, String region) { + if (region == null || region.isEmpty()) { + return null; + } + + switch (provider) { + case "aliyun": + // 阿里云 OSS: https://{region}.aliyuncs.com + if (region.startsWith("oss-")) { + return "https://" + region + ".aliyuncs.com"; + } else { + return "https://oss-" + region + ".aliyuncs.com"; + } + case "tencent": + // 腾讯云 COS: https://cos.{region}.myqcloud.com + return "https://cos." + region + ".myqcloud.com"; + case "huawei": + // 华为云 OBS: https://obs.{region}.myhuaweicloud.com + return "https://obs." + region + ".myhuaweicloud.com"; + case "qiniu": + // 七牛云 Kodo: 使用区域对应的 endpoint + return "https://" + region + ".qiniuds.com"; + default: + return null; + } + } + + /** + * 根据服务器 IP 和端口查找服务器资源(用于测试连接等) + */ + public AppResource getServerByHostAndPort(String host, Integer port, Integer userId, Integer tenantId) { + return lambdaQuery() + .eq(AppResource::getDeleted, 0) + .eq(AppResource::getResourceType, "server") + .eq(AppResource::getIp, host) + .eq(port != null, AppResource::getSshPort, port) + .eq(userId != null, AppResource::getUserId, userId) + .eq(tenantId != null, AppResource::getTenantId, tenantId) + .last("LIMIT 1") + .one(); + } + + /** + * 异步创建云存储桶 + * 在事务提交后执行,调用云厂商 API 创建存储桶 + */ + @Async + public void asyncCreateStorageBucket(Long resourceId, Integer userId) { + try { + Thread.sleep(500); + + // 查询存储资源记录 + AppResource storage = getById(resourceId); + if (storage == null) { + log.warn("异步创建存储桶失败: 资源不存在, resourceId={}", resourceId); + return; + } + + String provider = storage.getProvider(); + if (provider == null || provider.isEmpty()) { + updateStatus(resourceId, "failed", "服务商未指定"); + return; + } + + // 获取云账号凭证:优先从 credentialId 获取,否则从用户默认凭证获取 + Map credentials; + if (storage.getCredentialId() != null) { + credentials = cloudCredentialService.getCredentialsByCredentialId(storage.getCredentialId()); + if (credentials == null || credentials.isEmpty()) { + updateStatus(resourceId, "failed", "云账号凭证无效"); + log.warn("credentialId {} 对应的凭证不存在", storage.getCredentialId()); + return; + } + } else { + // 兼容旧数据:从用户默认凭证获取 + credentials = cloudCredentialService.getCredentials(provider, userId); + if (credentials == null || credentials.isEmpty()) { + updateStatus(resourceId, "failed", "请先配置云账号凭证"); + log.warn("用户 {} 未配置 {} 云账号凭证", userId, provider); + return; + } + } + + log.info("开始异步创建云存储桶: provider={}, bucket={}, region={}", + provider, storage.getName(), storage.getRegion()); + + // 更新状态为创建中 + updateStatus(resourceId, "pending", "正在创建存储桶..."); + + // 调用云厂商 API 创建存储桶 + CloudStorageProvider cloudProvider = CloudStorageProviderFactory.getProvider(provider); + cloudProvider.createBucket(storage, credentials); + + // 获取存储桶访问地址 + String endpoint = cloudProvider.getBucketEndpoint(storage, credentials); + + // 更新状态和 endpoint + AppResource update = new AppResource(); + update.setResourceId(resourceId); + update.setStatus("running"); + update.setRemark("存储桶创建成功,访问地址: " + endpoint); + update.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(update); + + log.info("异步创建云存储桶成功: bucket={}, resourceId={}", storage.getName(), resourceId); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("异步创建存储桶被中断: resourceId={}", resourceId); + } catch (Exception e) { + log.error("异步创建存储桶异常: resourceId={}, error={}", resourceId, e.getMessage(), e); + updateStatus(resourceId, "failed", "创建存储桶异常: " + e.getMessage()); + } + } + + @Override + public String resetDatabasePassword(Long resourceId, Integer currentUserId) { + if (resourceId == null) { + throw new RuntimeException("资源ID不能为空"); + } + AppResource resource = getById(resourceId); + if (resource == null || Integer.valueOf(1).equals(resource.getDeleted())) { + throw new RuntimeException("资源不存在"); + } + // 权限校验:只有资源创建者可以操作 + Long ownerUserId = resource.getOwnerUserId(); + Integer ownerUserIdInt = ownerUserId != null ? ownerUserId.intValue() : null; + if (currentUserId != null && !currentUserId.equals(ownerUserIdInt)) { + throw new RuntimeException("只有资源创建者才能重置密码"); + } + if (!"database".equals(resource.getResourceType())) { + throw new RuntimeException("只有数据库资源才能重置密码"); + } + + // 生成新密码(12位,包含大小写字母、数字、特殊字符) + String newPassword = generateRandomPassword(); + + // 如果关联了服务器且支持远程操作,则远程更新数据库密码 + if (resource.getServerResourceId() != null && resource.getDbType() != null + && databaseOperatorFactory.isSupported(resource.getDbType())) { + try { + AppResource server = getById(resource.getServerResourceId()); + if (server != null) { + // 获取管理员凭据 + String adminPwd = ""; + if (server.getAdminPassword() != null && !server.getAdminPassword().isEmpty()) { + adminPwd = DbPasswordUtil.decrypt(server.getAdminPassword()); + } + // 获取当前数据库密码(解密) + String currentDbPwd = ""; + if (resource.getDbPassword() != null && !resource.getDbPassword().isEmpty()) { + currentDbPwd = DbPasswordUtil.decrypt(resource.getDbPassword()); + } + // 获取端口 + int serverPort; + if ("PostgreSQL".equals(resource.getDbType())) { + serverPort = server.getPgPort() != null ? server.getPgPort() : 5432; + } else { + serverPort = server.getMysqlPort() != null ? server.getMysqlPort() : 3306; + } + // 远程更新密码 + DatabaseOperatorService operator = databaseOperatorFactory.getOperator(resource.getDbType()); + DatabaseOperatorService.DatabaseOperationResult result = operator.changePassword( + server.getIp(), + serverPort, + server.getAdminUsername(), + adminPwd, + resource.getDbUsername(), + currentDbPwd, + newPassword + ); + if (!result.isSuccess()) { + log.warn("远程重置数据库密码失败: resourceId={}, error={}", resourceId, result.getMessage()); + // 远程失败时,依然更新本地记录,让用户可以在远程手动处理 + } else { + log.info("远程重置数据库密码成功: resourceId={}, db={}", resourceId, resource.getName()); + } + } + } catch (Exception e) { + log.error("远程重置数据库密码异常: resourceId={}, error={}", resourceId, e.getMessage()); + // 远程操作失败不影响本地密码更新 + } + } + + // 更新本地密码(加密存储) + AppResource update = new AppResource(); + update.setResourceId(resourceId); + update.setDbPassword(DbPasswordUtil.encrypt(newPassword)); + update.setUpdateTime(LocalDateTime.now()); + updateById(update); + + log.info("重置数据库密码成功: resourceId={}, dbName={}", resourceId, resource.getName()); + return newPassword; + } + + /** + * 生成随机密码(12位,包含大小写字母、数字、特殊字符) + */ + private String generateRandomPassword() { + String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*"; + StringBuilder password = new StringBuilder(); + java.util.Random random = new java.util.Random(); + for (int i = 0; i < 12; i++) { + password.append(chars.charAt(random.nextInt(chars.length()))); + } + return password.toString(); + } + + /** + * 补充数据库资源的连接端口(根据dbType从关联的服务器资源获取) + * 端口字段用于前端显示 + */ + private void enrichPort(List resources) { + if (resources == null || resources.isEmpty()) { + return; + } + for (AppResource resource : resources) { + enrichPort(resource); + } + } + + /** + * 补充单个数据库资源的连接端口 + */ + private void enrichPort(AppResource resource) { + // 只处理数据库类型 + if (!"database".equals(resource.getResourceType())) { + return; + } + // 如果已有端口,跳过 + if (resource.getPort() != null) { + return; + } + // 如果没有关联服务器,无法获取端口 + if (resource.getServerResourceId() == null) { + return; + } + // 查询关联的服务器资源 + AppResource server = getById(resource.getServerResourceId()); + if (server == null) { + return; + } + // 根据数据库类型获取对应端口 + String dbType = resource.getDbType(); + Integer port = null; + if ("PostgreSQL".equals(dbType)) { + port = server.getPgPort(); + } else if ("MySQL".equals(dbType)) { + port = server.getMysqlPort(); + } else if ("Redis".equals(dbType)) { + // Redis 默认 6379,如果有专门的 Redis 端口字段可以加 + port = 6379; + } else if ("MongoDB".equals(dbType)) { + // MongoDB 默认 27017 + port = 27017; + } + resource.setPort(port); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppSettingServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppSettingServiceImpl.java new file mode 100644 index 0000000..92d170d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppSettingServiceImpl.java @@ -0,0 +1,242 @@ +package com.gxwebsoft.app.service.impl; + +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppSetting; +import com.gxwebsoft.app.mapper.AppSettingMapper; +import com.gxwebsoft.app.param.AppSettingParam; +import com.gxwebsoft.app.service.AppSettingService; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 平台设置表 Service 实现类 + * + * @author WebSoft + */ +@Slf4j +@Service +public class AppSettingServiceImpl extends ServiceImpl implements AppSettingService { + + @Resource + private UserService userService; + + /** + * 分页查询 + */ + @Override + public List page(AppSettingParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("category asc, sort_number asc, setting_id asc"); + IPage pageResult = baseMapper.selectPageRel(page, param); + return page.sortRecords(pageResult.getRecords()); + } + + /** + * 获取设置列表 + */ + @Override + public List list(AppSettingParam param) { + List list = baseMapper.selectListRel(param); + PageParam page = new PageParam<>(); + page.setDefaultOrder("category asc, sort_number asc, setting_id asc"); + return page.sortRecords(list); + } + + /** + * 根据分类获取所有设置 + * 注意:平台配置不按租户隔离 + */ + @Override + public List getByCategory(String category) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppSetting::getCategory, category); + wrapper.eq(AppSetting::getIsEnabled, 1); + wrapper.orderByAsc(AppSetting::getSortNumber); + return list(wrapper); + } + + /** + * 根据key获取设置值 + */ + @Override + public String getValue(String settingKey) { + AppSetting setting = getByKey(settingKey); + return setting != null ? setting.getSettingValue() : null; + } + + /** + * 根据key获取设置(完整对象) + * 注意:平台配置不按租户隔离 + */ + @Override + public AppSetting getByKey(String settingKey) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppSetting::getSettingKey, settingKey); + return getOne(wrapper); + } + + /** + * 获取分类下的所有设置(以Map返回,key为settingKey) + * 注意:平台配置不按租户隔离 + */ + @Override + public Map getCategoryValues(String category) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppSetting::getCategory, category); + wrapper.eq(AppSetting::getIsEnabled, 1); + wrapper.orderByAsc(AppSetting::getSortNumber); + List settings = list(wrapper); + + Map result = new HashMap<>(); + for (AppSetting setting : settings) { + result.put(setting.getSettingKey(), setting.getSettingValue()); + } + return result; + } + + /** + * 保存或更新设置 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrUpdateSetting(AppSetting setting) { + // 设置租户ID + Long tenantId = getCurrentTenantId(); + if (tenantId != null) { + setting.setTenantId(tenantId); + } + + // 检查是否存在 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppSetting::getSettingKey, setting.getSettingKey()); + if (tenantId != null) { + wrapper.eq(AppSetting::getTenantId, tenantId); + } else { + wrapper.isNull(AppSetting::getTenantId); + } + AppSetting existSetting = getOne(wrapper); + + if (existSetting != null) { + // 更新 + existSetting.setSettingValue(setting.getSettingValue()); + existSetting.setSettingName(setting.getSettingName()); + existSetting.setDescription(setting.getDescription()); + existSetting.setValueType(setting.getValueType()); + existSetting.setIsEnabled(setting.getIsEnabled()); + existSetting.setIsPublic(setting.getIsPublic()); + existSetting.setSortNumber(setting.getSortNumber()); + updateById(existSetting); + } else { + // 新增 + save(setting); + } + } + + /** + * 批量保存分类设置 + * 使用单一key存储整个分类的JSON值 + * 注意:平台配置不按租户隔离,统一存储 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void batchSave(String category, Map values) { + log.info("batchSave - category: {}, values: {}", category, JSON.toJSONString(values)); + + // 统一使用 category 作为 settingKey + String settingKey = "platform_" + category; + + // 平台配置不按租户隔离,统一存储 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppSetting::getSettingKey, settingKey); + AppSetting existSetting = getOne(wrapper); + log.info("查询结果 - existSetting: {}", existSetting != null ? existSetting.getSettingId() : "null"); + + // 将 Map 转为 JSON 字符串存储 + String jsonValue = JSON.toJSONString(values); + + if (existSetting != null) { + log.info("执行更新 - settingId: {}, settingValue长度: {}", existSetting.getSettingId(), jsonValue.length()); + existSetting.setSettingValue(jsonValue); + boolean updated = updateById(existSetting); + log.info("更新设置 - settingKey: {}, updated: {}", settingKey, updated); + } else { + // 新增默认设置项 + AppSetting newSetting = new AppSetting(); + newSetting.setCategory(category); + newSetting.setSettingKey(settingKey); + newSetting.setSettingName(getCategoryName(category)); + newSetting.setSettingValue(jsonValue); + newSetting.setValueType("json"); + newSetting.setIsEnabled(1); + newSetting.setIsPublic(0); + newSetting.setSortNumber(getCategorySortNumber(category)); + // 平台配置不设置租户ID + boolean saved = save(newSetting); + log.info("新增设置 - settingKey: {}, saved: {}, jsonValue: {}", settingKey, saved, jsonValue); + } + } + + /** + * 获取分类名称 + */ + private String getCategoryName(String category) { + switch (category) { + case "basic": return "基础配置"; + case "review": return "审核配置"; + case "market": return "市场配置"; + case "register": return "注册登录配置"; + case "notify": return "通知配置"; + case "miniprogram": return "微信小程序配置"; + case "payment": return "支付配置"; + case "maintenance": return "系统维护"; + default: return category; + } + } + + /** + * 获取分类排序号 + */ + private Integer getCategorySortNumber(String category) { + switch (category) { + case "basic": return 1; + case "review": return 2; + case "market": return 3; + case "register": return 4; + case "notify": return 5; + case "miniprogram": return 6; + case "payment": return 7; + case "maintenance": return 8; + default: return 99; + } + } + + /** + * 获取当前登录用户的租户ID + */ + private Long getCurrentTenantId() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.getPrincipal() instanceof User) { + User user = (User) authentication.getPrincipal(); + return user.getTenantId() != null ? Long.valueOf(user.getTenantId()) : null; + } + } catch (Exception e) { + log.error("获取当前用户租户ID失败", e); + } + return null; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppSubscriptionServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppSubscriptionServiceImpl.java new file mode 100644 index 0000000..1e93437 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppSubscriptionServiceImpl.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.entity.AppSubscription; +import com.gxwebsoft.app.mapper.AppSubscriptionMapper; +import com.gxwebsoft.app.mapper.AppProductMapper; +import com.gxwebsoft.app.service.AppSubscriptionService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 应用订阅 Service 实现 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AppSubscriptionServiceImpl extends ServiceImpl + implements AppSubscriptionService { + + private final AppProductMapper productMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public AppSubscription createSubscription(Integer userId, Integer productId, String priceType, String period) { + // 1. 查询产品 + AppProduct product = productMapper.selectById(productId); + if (product == null || !"published".equals(product.getPublishStatus())) { + throw new RuntimeException("应用不存在或未上架"); + } + + // 2. 幂等检查:是否已有 active 订阅 + LambdaQueryWrapper existQuery = new LambdaQueryWrapper<>(); + existQuery.eq(AppSubscription::getUserId, userId) + .eq(AppSubscription::getProductId, productId) + .eq(AppSubscription::getStatus, "active"); + if (this.count(existQuery) > 0) { + throw new RuntimeException("您已订阅该应用,无需重复购买"); + } + + // 3. 计算价格(单位:元) + BigDecimal price = BigDecimal.ZERO; + if (!"free".equals(product.getPriceType()) && product.getPrice() != null) { + // 前端 price 字段存的是分,转为元 + price = product.getPrice().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); + if ("subscription".equals(priceType) && "year".equals(period)) { + price = price.multiply(BigDecimal.TEN); // 年付 10 个月 + } + } + + // 4. 创建记录 + AppSubscription sub = new AppSubscription(); + sub.setSubscriptionNo(generateSubscriptionNo()); + sub.setUserId(userId); + sub.setProductId(productId); + sub.setTenantId(product.getTenantId()); + sub.setStatus("pending"); + sub.setPriceType(product.getPriceType() != null ? product.getPriceType() : "free"); + sub.setOriginalPrice(price); + sub.setPayPrice(price); + sub.setPayStatus(0); + sub.setSubscriptionPeriod("subscription".equals(product.getPriceType()) ? period : null); + + // 5. 免费应用直接激活 + if (price.compareTo(BigDecimal.ZERO) == 0 || "free".equals(product.getPriceType())) { + activateImmediately(sub, product, period); + } + + this.save(sub); + return sub; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void activateSubscription(String subscriptionNo, String transactionId) { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(AppSubscription::getSubscriptionNo, subscriptionNo); + AppSubscription sub = this.getOne(query); + if (sub == null) { + log.warn("激活订阅失败:订阅不存在, subscriptionNo={}", subscriptionNo); + return; + } + + if (sub.getPayStatus() != null && sub.getPayStatus() == 1) { + log.info("订阅已支付,跳过重复激活, subscriptionNo={}", subscriptionNo); + return; + } + + // 更新支付信息 + sub.setPayStatus(1); + sub.setPayTime(LocalDateTime.now()); + sub.setTransactionId(transactionId); + sub.setStatus("active"); + sub.setStartTime(LocalDateTime.now()); + + // 计算到期时间 + if ("subscription".equals(sub.getPriceType())) { + int months = "year".equals(sub.getSubscriptionPeriod()) ? 12 : 1; + sub.setExpireTime(LocalDateTime.now().plusMonths(months)); + } + + this.updateById(sub); + + // 更新产品安装量 + AppProduct product = productMapper.selectById(sub.getProductId()); + if (product != null) { + product.setInstalls((product.getInstalls() != null ? product.getInstalls() : 0) + 1); + productMapper.updateById(product); + } + + // TODO: 发送通知给用户 + log.info("订阅激活成功: subscriptionNo={}, userId={}, productId={}", + subscriptionNo, sub.getUserId(), sub.getProductId()); + } + + @Override + public boolean isPurchased(Integer userId, Integer productId) { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(AppSubscription::getUserId, userId) + .eq(AppSubscription::getProductId, productId) + .in(AppSubscription::getStatus, "active", "pending"); + return this.count(query) > 0; + } + + /** + * 免费应用直接激活 + */ + private void activateImmediately(AppSubscription sub, AppProduct product, String period) { + sub.setStatus("active"); + sub.setPayStatus(1); + sub.setPayType(12); + sub.setPayTime(LocalDateTime.now()); + sub.setStartTime(LocalDateTime.now()); + + if ("subscription".equals(sub.getPriceType())) { + int months = "year".equals(period) ? 12 : 1; + sub.setExpireTime(LocalDateTime.now().plusMonths(months)); + } + + product.setInstalls((product.getInstalls() != null ? product.getInstalls() : 0) + 1); + productMapper.updateById(product); + } + + private String generateSubscriptionNo() { + String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + int random = ThreadLocalRandom.current().nextInt(1000, 9999); + return "SUB" + date + random; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppTicketServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppTicketServiceImpl.java new file mode 100644 index 0000000..447f195 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppTicketServiceImpl.java @@ -0,0 +1,602 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.entity.AppTicket; +import com.gxwebsoft.app.entity.AppTicketReply; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.mapper.AppTicketMapper; +import com.gxwebsoft.app.mapper.AppTicketReplyMapper; +import com.gxwebsoft.app.param.AppTicketParam; +import com.gxwebsoft.app.service.AppProductService; +import com.gxwebsoft.app.service.AppTicketService; +import com.gxwebsoft.app.service.AppUserService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 应用工单 Service 实现 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Slf4j +@Service +public class AppTicketServiceImpl extends ServiceImpl implements AppTicketService { + + /** 企业微信群机器人 Webhook,留空则不发送 */ + @Value("${notify.wecom-webhook:}") + private String wecomWebhook; + + /** 飞书群机器人 Webhook,留空则不发送 */ + @Value("${notify.feishu-webhook:}") + private String feishuWebhook; + + @Resource + private AppTicketReplyMapper replyMapper; + + @Resource + private AppUserService appUserService; + + @Resource + private UserService userService; + + @Resource + private AppProductService appProductService; + + // ─── 生成工单编号(格式:TK-260406-00001) ───────────────────── + private String generateTicketNo() { + LocalDateTime now = LocalDateTime.now(); + String datePart = now.format(DateTimeFormatter.ofPattern("yyMMdd")); + // 查询当天最大序号 + String todayStart = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00")); + String todayEnd = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59")); + Integer maxSeq = baseMapper.selectMaxSeqForDate(datePart); + int seq = (maxSeq == null ? 0 : maxSeq) + 1; + return String.format("TK-%s-%04d", datePart, seq); + } + + // ─── 客户端:查自己的工单 ───────────────────────────────────── + @Override + public PageResult myPage(AppTicketParam param, Integer userId) { + // 用 PageParam 包装分页参数(getCurrent/getSize 来自父类 Page) + Page page = new Page<>(param.getCurrent(), param.getSize() > 0 ? param.getSize() : 15); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppTicket::getDeleted, 0) + .eq(AppTicket::getSubmitUserId, userId) + .eq(ObjectUtil.isNotNull(param.getAppId()), AppTicket::getAppId, param.getAppId()) + .eq(ObjectUtil.isNotEmpty(param.getStatus()), AppTicket::getStatus, param.getStatus()) + .eq(ObjectUtil.isNotEmpty(param.getCategory()), AppTicket::getCategory, param.getCategory()) + .and(ObjectUtil.isNotEmpty(param.getKeywords()), q -> + q.like(AppTicket::getTitle, param.getKeywords()) + .or().like(AppTicket::getTicketNo, param.getKeywords())) + // 状态优先级:pending > assigned > processing > resolved > closed;同状态内最新的排前 + .last("ORDER BY FIELD(status,'pending','assigned','processing','resolved','closed','rejected'), create_time DESC"); + + baseMapper.selectPage(page, wrapper); + return new PageResult<>(page.getRecords(), page.getTotal()); + } + + // ─── 技术端:查所有工单(按应用权限过滤) ─────────────────────── + @Override + public PageResult allPage(AppTicketParam param) { + Page page = new Page<>(param.getCurrent(), param.getSize() > 0 ? param.getSize() : 20); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppTicket::getDeleted, 0) + .in(param.getAppIds() != null && !param.getAppIds().isEmpty(), AppTicket::getAppId, param.getAppIds()) + .eq(ObjectUtil.isNotNull(param.getAppId()), AppTicket::getAppId, param.getAppId()) + .eq(ObjectUtil.isNotEmpty(param.getStatus()), AppTicket::getStatus, param.getStatus()) + .eq(ObjectUtil.isNotEmpty(param.getCategory()), AppTicket::getCategory, param.getCategory()) + .eq(ObjectUtil.isNotEmpty(param.getPriority()), AppTicket::getPriority, param.getPriority()) + .and(ObjectUtil.isNotNull(param.getAssigneeId()) && param.getAssigneeId() == 0, + q -> q.isNull(AppTicket::getAssigneeId)) + .eq(ObjectUtil.isNotNull(param.getAssigneeId()) && param.getAssigneeId() > 0, + AppTicket::getAssigneeId, param.getAssigneeId()) + .and(ObjectUtil.isNotEmpty(param.getKeywords()), q -> + q.like(AppTicket::getTitle, param.getKeywords()) + .or().like(AppTicket::getTicketNo, param.getKeywords())) + // 状态优先级 > 紧急程度 > 最新提交时间 + .last("ORDER BY FIELD(status,'pending','assigned','processing','resolved','closed','rejected'), FIELD(priority,'urgent','high','normal','low'), create_time DESC"); + + baseMapper.selectPage(page, wrapper); + return new PageResult<>(page.getRecords(), page.getTotal()); + } + + // ─── 提交工单(自动分配) ───────────────────────────────────── + @Override + @Transactional(rollbackFor = Exception.class) + public AppTicket submit(AppTicket ticket, Integer userId) { + // 补充提交人信息 + ticket.setSubmitUserId(userId); + ticket.setTicketNo(generateTicketNo()); + ticket.setStatus("pending"); + ticket.setReplyCount(0); + ticket.setDeleted(0); + ticket.setCreateTime(LocalDateTime.now()); + ticket.setUpdateTime(LocalDateTime.now()); + + // 从用户服务取昵称/头像冗余存储(@InterceptorIgnore 绕过租户拦截器跨库查询) + try { + User user = userService.getByIdIgnoreTenant(userId); + if (user != null) { + ticket.setSubmitUserName(user.getNickname() != null ? user.getNickname() : user.getUsername()); + ticket.setSubmitUserAvatar(user.getAvatar()); + } + } catch (Exception e) { + log.warn("获取提交人信息失败", e); + } + + // 自动分配:查找该应用的 admin/developer 成员,随机分配 + autoAssign(ticket); + + // 补充应用名称(冗余存储) + if (ticket.getAppId() != null && ticket.getAppName() == null) { + try { + AppProduct product = appProductService.getById(ticket.getAppId()); + if (product != null) { + ticket.setAppName(product.getProductName()); + } + } catch (Exception e) { + log.warn("获取应用名称失败", e); + } + } + + save(ticket); + + // 异步推送:新工单通知(通知分配到的技术人员) + sendTicketCreatedAsync(ticket); + + return ticket; + } + + /** 自动分配工单给应用的技术成员 */ + private void autoAssign(AppTicket ticket) { + if (ticket.getAppId() == null) return; + try { + List members = appUserService.list( + new LambdaQueryWrapper() + .eq(AppUser::getAppId, ticket.getAppId()) + .eq(AppUser::getStatus, 0) + .in(AppUser::getRole, "admin", "developer", "owner")); + if (!members.isEmpty()) { + // 简单轮询:按工单数最少分配(此处随机) + AppUser assigned = members.get(new Random().nextInt(members.size())); + ticket.setAssigneeId(assigned.getUserId()); + ticket.setAssigneeName(assigned.getNickname() != null ? assigned.getNickname() : assigned.getUsername()); + ticket.setAssigneeAvatar(assigned.getAvatar()); + ticket.setStatus("assigned"); + } + } catch (Exception e) { + log.warn("自动分配工单失败,保持 pending 状态", e); + } + } + + // ─── 更新状态 ───────────────────────────────────────────────── + @Override + public void updateStatus(Long ticketId, String status, Integer operatorId) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper() + .eq(AppTicket::getTicketId, ticketId) + .set(AppTicket::getStatus, status) + .set(AppTicket::getUpdateTime, LocalDateTime.now()); + if ("resolved".equals(status)) { + wrapper.set(AppTicket::getResolvedTime, LocalDateTime.now()); + // 如果没有分配人,自动将操作人设为处理人 + AppTicket t = getById(ticketId); + if (t != null && t.getAssigneeId() == null) { + wrapper.set(AppTicket::getAssigneeId, operatorId); + } + } + update(wrapper); + + // 异步推送:状态变更通知提交人(已解决/已关闭) + if ("resolved".equals(status) || "closed".equals(status)) { + AppTicket t = getById(ticketId); + if (t != null) sendStatusChangedAsync(t, status); + } + } + + // ─── 分配处理人 ─────────────────────────────────────────────── + @Override + public void assign(Long ticketId, Integer assigneeId) { + User user = userService.getByIdIgnoreTenant(assigneeId); + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper() + .eq(AppTicket::getTicketId, ticketId) + .set(AppTicket::getAssigneeId, assigneeId) + .set(user != null, AppTicket::getAssigneeName, + user != null ? (user.getNickname() != null ? user.getNickname() : user.getUsername()) : null) + .set(user != null, AppTicket::getAssigneeAvatar, user != null ? user.getAvatar() : null) + .set(AppTicket::getStatus, "assigned") + .set(AppTicket::getUpdateTime, LocalDateTime.now()); + update(wrapper); + + // 异步推送:通知新分配到的技术人员 + AppTicket t = getById(ticketId); + if (t != null) sendTicketAssignedAsync(t); + } + + // ─── 用户关闭工单 ───────────────────────────────────────────── + @Override + public void closeByUser(Long ticketId, Integer userId) { + AppTicket ticket = getById(ticketId); + if (ticket == null || !ticket.getSubmitUserId().equals(userId)) { + throw new RuntimeException("无权操作该工单"); + } + update(new LambdaUpdateWrapper() + .eq(AppTicket::getTicketId, ticketId) + .set(AppTicket::getStatus, "closed") + .set(AppTicket::getClosedTime, LocalDateTime.now()) + .set(AppTicket::getUpdateTime, LocalDateTime.now())); + } + + // ─── 获取回复列表 ───────────────────────────────────────────── + @Override + public List getReplies(Long ticketId) { + return replyMapper.selectList( + new LambdaQueryWrapper() + .eq(AppTicketReply::getTicketId, ticketId) + .eq(AppTicketReply::getDeleted, 0) + .orderByAsc(AppTicketReply::getCreateTime)); + } + + // ─── 添加回复 ───────────────────────────────────────────────── + @Override + @Transactional(rollbackFor = Exception.class) + public AppTicketReply addReply(AppTicketReply reply, Integer userId) { + reply.setUserId(userId); + reply.setDeleted(0); + reply.setCreateTime(LocalDateTime.now()); + + // 补充用户信息(@InterceptorIgnore 绕过租户拦截器跨库查询) + try { + User user = userService.getByIdIgnoreTenant(userId); + if (user != null) { + reply.setUserName(user.getNickname() != null ? user.getNickname() : user.getUsername()); + reply.setUserAvatar(user.getAvatar()); + } + } catch (Exception e) { + log.warn("获取回复人信息失败", e); + } + + // 判断是否是技术人员(该应用的 admin/developer/owner) + AppTicket ticket = getById(reply.getTicketId()); + if (ticket != null) { + boolean isStaff = appUserService.count(new LambdaQueryWrapper() + .eq(AppUser::getAppId, ticket.getAppId()) + .eq(AppUser::getUserId, userId) + .in(AppUser::getRole, "owner", "admin", "developer") + .eq(AppUser::getStatus, 0)) > 0; + reply.setIsStaff(isStaff ? 1 : 0); + } else { + reply.setIsStaff(0); + } + + replyMapper.insert(reply); + + // 更新工单回复数 & 更新时间,若状态是 assigned 则推进为 processing + update(new LambdaUpdateWrapper() + .eq(AppTicket::getTicketId, reply.getTicketId()) + .setSql("reply_count = reply_count + 1") + .set(AppTicket::getUpdateTime, LocalDateTime.now()) + .eq(AppTicket::getStatus, "assigned") + .set(AppTicket::getStatus, "processing")); + + // 异步推送:有新回复时通知对方 + if (ticket != null) sendReplyNotifyAsync(ticket, reply); + + return reply; + } + + // ─── 统计 ───────────────────────────────────────────────────── + @Override + public Map stats(Long appId, Integer userId) { + LambdaQueryWrapper base = new LambdaQueryWrapper() + .eq(AppTicket::getDeleted, 0) + .eq(ObjectUtil.isNotNull(appId), AppTicket::getAppId, appId) + .eq(ObjectUtil.isNotNull(userId), AppTicket::getSubmitUserId, userId); + + Map result = new HashMap<>(); + result.put("total", (long) count(base.clone())); + result.put("pending", (long) count(base.clone().in(AppTicket::getStatus, "pending", "assigned"))); + result.put("processing", (long) count(base.clone().eq(AppTicket::getStatus, "processing"))); + result.put("resolved", (long) count(base.clone().eq(AppTicket::getStatus, "resolved"))); + result.put("closed", (long) count(base.clone().eq(AppTicket::getStatus, "closed"))); + return result; + } + + // ─── 获取技术人员列表 ───────────────────────────────────────── + @Override + public List> getTechStaffList() { + List members = appUserService.list( + new LambdaQueryWrapper() + .eq(AppUser::getStatus, 0) + .in(AppUser::getRole, "owner", "admin", "developer") + .select(AppUser::getUserId, AppUser::getNickname, AppUser::getAvatar)); + + // 去重(一个用户可能在多个应用里) + Map dedupMap = new LinkedHashMap<>(); + for (AppUser m : members) { + dedupMap.put(m.getUserId(), m); + } + + return dedupMap.values().stream().map(m -> { + Map map = new HashMap<>(); + map.put("userId", m.getUserId()); + map.put("nickname", m.getNickname() != null ? m.getNickname() : "用户" + m.getUserId()); + map.put("avatar", m.getAvatar()); + return map; + }).collect(Collectors.toList()); + } + + // ════════════════════════════════════════════════════════════ + // 异步消息推送 + // ════════════════════════════════════════════════════════════ + + /** + * 场景1:新工单提交 → 通知分配到的技术人员 + */ + @Async + public void sendTicketCreatedAsync(AppTicket ticket) { + String now = now(); + String title = String.format("🎫 新工单待处理(%s)", now); + + String assigneeLine = StrUtil.isNotBlank(ticket.getAssigneeName()) + ? "**处理人:** " + ticket.getAssigneeName() + : "**处理人:** 待分配"; + + String wecomContent = String.format( + "## %s\n" + + "> **工单号:** %s\n" + + "> **标题:** %s\n" + + "> **分类:** %s **优先级:** %s\n" + + "> **提交人:** %s\n" + + "> %s\n" + + "> **描述:** %s", + title, + nullSafe(ticket.getTicketNo()), + nullSafe(ticket.getTitle()), + categoryLabel(ticket.getCategory()), priorityLabel(ticket.getPriority()), + nullSafe(ticket.getSubmitUserName()), + assigneeLine, + truncate(ticket.getContent(), 120) + ); + + List feishuLines = Arrays.asList( + new String[]{"工单号:" + nullSafe(ticket.getTicketNo())}, + new String[]{"标 题:" + nullSafe(ticket.getTitle())}, + new String[]{"分 类:" + categoryLabel(ticket.getCategory()) + " 优先级:" + priorityLabel(ticket.getPriority())}, + new String[]{"提交人:" + nullSafe(ticket.getSubmitUserName())}, + new String[]{assigneeLine.replace("**", "")}, + new String[]{"描 述:" + truncate(ticket.getContent(), 120)} + ); + + doSend(title, wecomContent, feishuLines, "ticket_created"); + } + + /** + * 场景2:工单被重新分配 → 通知新处理人 + */ + @Async + public void sendTicketAssignedAsync(AppTicket ticket) { + String now = now(); + String title = String.format("📋 工单已分配给您(%s)", now); + + String wecomContent = String.format( + "## %s\n" + + "> **工单号:** %s\n" + + "> **标题:** %s\n" + + "> **分配给:** %s\n" + + "> **分类:** %s **优先级:** %s\n" + + "> **描述:** %s", + title, + nullSafe(ticket.getTicketNo()), + nullSafe(ticket.getTitle()), + nullSafe(ticket.getAssigneeName()), + categoryLabel(ticket.getCategory()), priorityLabel(ticket.getPriority()), + truncate(ticket.getContent(), 100) + ); + + List feishuLines = Arrays.asList( + new String[]{"工单号:" + nullSafe(ticket.getTicketNo())}, + new String[]{"标 题:" + nullSafe(ticket.getTitle())}, + new String[]{"分配给:" + nullSafe(ticket.getAssigneeName())}, + new String[]{"分 类:" + categoryLabel(ticket.getCategory()) + " 优先级:" + priorityLabel(ticket.getPriority())}, + new String[]{"描 述:" + truncate(ticket.getContent(), 100)} + ); + + doSend(title, wecomContent, feishuLines, "ticket_assigned"); + } + + /** + * 场景3:有新回复 → 技术人员回复则通知客户,客户回复则通知技术人员 + */ + @Async + public void sendReplyNotifyAsync(AppTicket ticket, AppTicketReply reply) { + boolean isStaff = Integer.valueOf(1).equals(reply.getIsStaff()); + String now = now(); + String who = isStaff ? "技术人员" : "用户"; + String notifyRole = isStaff ? "您的工单有新回复" : "工单有用户新回复"; + String title = String.format("💬 %s(%s)", notifyRole, now); + + String wecomContent = String.format( + "## %s\n" + + "> **工单号:** %s\n" + + "> **标题:** %s\n" + + "> **回复人:** %s(%s)\n" + + "> **回复内容:** %s", + title, + nullSafe(ticket.getTicketNo()), + nullSafe(ticket.getTitle()), + nullSafe(reply.getUserName()), who, + truncate(reply.getContent(), 200) + ); + + List feishuLines = Arrays.asList( + new String[]{"工单号:" + nullSafe(ticket.getTicketNo())}, + new String[]{"标 题:" + nullSafe(ticket.getTitle())}, + new String[]{"回复人:" + nullSafe(reply.getUserName()) + "(" + who + ")"}, + new String[]{"回复内容:" + truncate(reply.getContent(), 200)} + ); + + doSend(title, wecomContent, feishuLines, "ticket_reply"); + } + + /** + * 场景4:状态变更(已解决/已关闭)→ 通知提交人 + */ + @Async + public void sendStatusChangedAsync(AppTicket ticket, String status) { + String now = now(); + String emoji = "resolved".equals(status) ? "✅" : "🔒"; + String statusLabel = "resolved".equals(status) ? "已解决" : "已关闭"; + String title = String.format("%s 工单%s(%s)", emoji, statusLabel, now); + + String wecomContent = String.format( + "## %s\n" + + "> **工单号:** %s\n" + + "> **标题:** %s\n" + + "> **提交人:** %s\n" + + "> **处理人:** %s\n" + + "> **状态:** %s", + title, + nullSafe(ticket.getTicketNo()), + nullSafe(ticket.getTitle()), + nullSafe(ticket.getSubmitUserName()), + nullSafe(ticket.getAssigneeName()), + "resolved".equals(status) ? "info" : "comment", + statusLabel + ); + + List feishuLines = Arrays.asList( + new String[]{"工单号:" + nullSafe(ticket.getTicketNo())}, + new String[]{"标 题:" + nullSafe(ticket.getTitle())}, + new String[]{"提交人:" + nullSafe(ticket.getSubmitUserName())}, + new String[]{"处理人:" + nullSafe(ticket.getAssigneeName())}, + new String[]{"状 态:" + statusLabel} + ); + + doSend(title, wecomContent, feishuLines, "ticket_status"); + } + + /** + * 统一发送入口:企业微信 + 飞书 + */ + private void doSend(String title, String wecomContent, List feishuLines, String scene) { + if (StrUtil.isNotBlank(wecomWebhook)) { + try { + sendWecom(wecomContent); + } catch (Exception e) { + log.warn("[工单通知][{}] 企业微信发送失败: {}", scene, e.getMessage()); + } + } + if (StrUtil.isNotBlank(feishuWebhook)) { + try { + sendFeishu(title, feishuLines); + } catch (Exception e) { + log.warn("[工单通知][{}] 飞书发送失败: {}", scene, e.getMessage()); + } + } + } + + /** + * 企业微信群机器人 - markdown 消息 + * 文档:https://developer.work.weixin.qq.com/document/path/91770 + */ + private void sendWecom(String content) { + Map textMap = new HashMap<>(); + textMap.put("content", content); + Map payload = new HashMap<>(); + payload.put("msgtype", "markdown"); + payload.put("markdown", textMap); + String resp = HttpUtil.post(wecomWebhook, JSON.toJSONString(payload)); + log.info("[工单通知] 企业微信推送结果: {}", resp); + } + + /** + * 飞书群机器人 - 富文本(post)消息 + * 文档:https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot + */ + private void sendFeishu(String title, List lines) { + List>> content = new ArrayList<>(); + for (String[] line : lines) { + Map node = new HashMap<>(); + node.put("tag", "text"); + node.put("text", line[0]); + content.add(Collections.singletonList(node)); + } + + Map zhCn = new HashMap<>(); + zhCn.put("title", title); + zhCn.put("content", content); + Map postContent = new HashMap<>(); + postContent.put("zh_cn", zhCn); + Map post = new HashMap<>(); + post.put("content", postContent); + Map payload = new HashMap<>(); + payload.put("msg_type", "post"); + payload.put("content", post); + + String resp = HttpUtil.post(feishuWebhook, JSON.toJSONString(payload)); + log.info("[工单通知] 飞书推送结果: {}", resp); + } + + // ════════════════════════════════════════════════════════════ + // 工具方法 + // ════════════════════════════════════════════════════════════ + + private String now() { + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("MM-dd HH:mm")); + } + + private String nullSafe(String s) { + return StrUtil.isBlank(s) ? "—" : s; + } + + private String truncate(String s, int max) { + if (StrUtil.isBlank(s)) return "—"; + return s.length() > max ? s.substring(0, max) + "…" : s; + } + + private String categoryLabel(String category) { + if (category == null) return "其他"; + return switch (category) { + case "bug" -> "Bug反馈"; + case "feature" -> "功能需求"; + case "config" -> "配置问题"; + case "performance" -> "性能问题"; + case "security" -> "安全问题"; + default -> category; + }; + } + + private String priorityLabel(String priority) { + if (priority == null) return "普通"; + return switch (priority) { + case "urgent" -> "🔴 紧急"; + case "high" -> "🟠 高"; + case "normal" -> "🟡 普通"; + case "low" -> "🟢 低"; + default -> priority; + }; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppUserCacheServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppUserCacheServiceImpl.java new file mode 100644 index 0000000..7d2ddd1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppUserCacheServiceImpl.java @@ -0,0 +1,212 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.entity.AppUserCache; +import com.gxwebsoft.app.mapper.AppUserCacheMapper; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.system.entity.User; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 用户缓存 Service 实现 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Service +public class AppUserCacheServiceImpl extends ServiceImpl implements AppUserCacheService { + + /** Server API 地址 */ + @Value("${config.server-url:https://server.websoft.top/api}") + private String serverUrl; + + @Override + public AppUserCache getByUserId(Integer userId) { + if (userId == null) { + return null; + } + // 先查缓存 + AppUserCache cache = getById(userId); + if (cache != null) { + return cache; + } + // 缓存不存在,尝试从 server 获取并缓存 + return refreshUserCache(userId); + } + + @Override + public AppUserCache refreshUserCache(Integer userId) { + if (userId == null) { + return null; + } + User sysUser = getUserFromServer(userId); + if (sysUser == null) { + log.warn("刷新用户缓存失败,用户不存在或 API 调用失败,userId={}", userId); + return null; + } + return saveOrUpdateCache(sysUser); + } + + @Override + @Async + public void batchRefreshUserCache(List userIds) { + if (CollUtil.isEmpty(userIds)) { + return; + } + log.info("开始批量刷新用户缓存,数量={}", userIds.size()); + for (Integer userId : userIds) { + try { + refreshUserCache(userId); + } catch (Exception e) { + log.error("批量刷新用户缓存失败,userId={}", userId, e); + } + } + log.info("批量刷新用户缓存完成,数量={}", userIds.size()); + } + + /** + * 保存或更新缓存 + */ + private AppUserCache saveOrUpdateCache(User sysUser) { + AppUserCache cache = new AppUserCache(); + cache.setUserId(sysUser.getUserId()); + cache.setTenantId(sysUser.getTenantId()); + cache.setUsername(sysUser.getUsername()); + cache.setNickname(sysUser.getNickname()); + cache.setAvatar(sysUser.getAvatar()); + cache.setPhone(sysUser.getPhone()); + cache.setStatus(sysUser.getStatus()); + cache.setUpdateTime(LocalDateTime.now()); + + // 解决 MyBatis-Plus saveOrUpdate 对 IdType.INPUT 主键的兼容问题 + // 先查询再决定 insert/update,捕获并发冲突异常后回退到 update + if (getById(cache.getUserId()) != null) { + updateById(cache); + } else { + try { + save(cache); + } catch (org.springframework.dao.DuplicateKeyException e) { + // 并发场景:其他线程已插入,改为更新 + log.warn("并发插入冲突,改为更新: userId={}", cache.getUserId()); + updateById(cache); + } + } + log.debug("用户缓存更新成功,userId={}, username={}, tenantId={}", sysUser.getUserId(), sysUser.getUsername(), sysUser.getTenantId()); + return cache; + } + + /** + * 从 server API 获取用户信息 + */ + private User getUserFromServer(Integer userId) { + try { + String url = serverUrl + "/system/user/" + userId; + String response = HttpUtil.get(url); + JSONObject json = JSON.parseObject(response); + if (json.getIntValue("code") == 0 && json.get("data") != null) { + return JSON.parseObject(json.getJSONObject("data").toJSONString(), User.class); + } + log.warn("调用 server API 查询用户失败,userId={}, response={}", userId, response); + } catch (Exception e) { + log.error("调用 server API 查询用户异常,userId={}", userId, e); + } + return null; + } + + @Override + public AppUserCache refreshUserCacheByPhone(String phone) { + if (StrUtil.isBlank(phone)) { + return null; + } + + try { + // 调用 server API 根据手机号查询用户 + String url = serverUrl + "/system/user/getByPhone/" + phone; + String response = HttpUtil.get(url); + JSONObject json = JSON.parseObject(response); + + log.info("根据手机号查询用户响应: phone={}, response={}", phone, response); + + Integer code = json.getInteger("code"); + if ((code == 0 || code == 200) && json.get("data") != null) { + User sysUser = JSON.parseObject(json.getJSONObject("data").toJSONString(), User.class); + if (sysUser != null && sysUser.getUserId() != null) { + log.info("从 server 找到用户: phone={}, userId={}", phone, sysUser.getUserId()); + return saveOrUpdateCache(sysUser); + } + } + log.info("server 中未找到用户: phone={}", phone); + } catch (Exception e) { + log.error("根据手机号刷新用户缓存异常: phone={}", phone, e); + } + return null; + } + + @Override + public AppUserCache createUserByPhone(String phone) { + if (StrUtil.isBlank(phone)) { + return null; + } + + try { + // 1. 调用 server API 创建新用户 + String createUrl = serverUrl + "/system/user/"; + Map userMap = new HashMap<>(); + userMap.put("phone", phone); + userMap.put("username", "wx_" + phone); + userMap.put("nickname", "微信用户"); + userMap.put("status", 0); + userMap.put("platform", "MP-WEIXIN"); + userMap.put("tenantId", 1); // 默认租户 + + String createResult = HttpUtil.post(createUrl, JSON.toJSONString(userMap)); + JSONObject createJson = JSON.parseObject(createResult); + + log.info("创建用户响应: phone={}, response={}", phone, createResult); + + Integer createCode = createJson.getInteger("code"); + if (createCode == null || (createCode != 200 && createCode != 0)) { + log.error("创建用户失败: phone={}, code={}", phone, createCode); + return null; + } + + // 2. 创建成功,重新查询用户信息 + String queryUrl = serverUrl + "/system/user/getByPhone/" + phone; + String queryResult = HttpUtil.get(queryUrl); + JSONObject queryJson = JSON.parseObject(queryResult); + + log.info("查询用户响应: phone={}, response={}", phone, queryResult); + + Integer queryCode = queryJson.getInteger("code"); + if ((queryCode == 0 || queryCode == 200) && queryJson.get("data") != null) { + User sysUser = JSON.parseObject(queryJson.getJSONObject("data").toJSONString(), User.class); + if (sysUser != null && sysUser.getUserId() != null) { + log.info("新用户创建成功: phone={}, userId={}", phone, sysUser.getUserId()); + return saveOrUpdateCache(sysUser); + } + } + + log.error("创建用户后查询失败: phone={}", phone); + } catch (Exception e) { + log.error("创建用户异常: phone={}", phone, e); + } + return null; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppUserServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppUserServiceImpl.java new file mode 100644 index 0000000..5d84cd0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppUserServiceImpl.java @@ -0,0 +1,359 @@ +package com.gxwebsoft.app.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.mapper.AppUserMapper; +import com.gxwebsoft.app.mapper.SysUserCrossDbMapper; +import com.gxwebsoft.app.mapper.AppProductMapper; +import com.gxwebsoft.app.service.AppUserService; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.app.service.AppProductService; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.entity.AppUserCache; +import com.gxwebsoft.app.entity.AppProduct; +import com.gxwebsoft.app.param.AppUserParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.system.entity.User; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 应用成员Service实现 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Slf4j +@Service +public class AppUserServiceImpl extends ServiceImpl implements AppUserService { + + @Autowired + private SysUserCrossDbMapper sysUserCrossDbMapper; + + @Autowired(required = false) + private AppUserCacheService appUserCacheService; + + @Autowired + private AppProductService appProductService; + + @Autowired + private AppProductMapper appProductMapper; + + @Override + public PageResult pageRel(AppUserParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time asc"); + List list = baseMapper.selectPageRel(page, param); + // 补充用户信息(从缓存或远程获取) + fillUserInfo(list); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AppUserParam param) { + List list = baseMapper.selectListRel(param); + // 补充用户信息(从缓存或远程获取) + fillUserInfo(list); + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time asc"); + return page.sortRecords(list); + } + + /** + * 补充应用成员的用户信息(头像、昵称等) + * 优先从 app_user_cache 获取,缓存不存在则尝试刷新 + */ + private void fillUserInfo(List list) { + if (CollUtil.isEmpty(list) || appUserCacheService == null) { + return; + } + for (AppUser appUser : list) { + if (appUser.getUserId() == null) { + continue; + } + // 如果用户信息为空,尝试从缓存获取 + if (ObjectUtil.isEmpty(appUser.getNickname()) + || ObjectUtil.isEmpty(appUser.getAvatar()) + || ObjectUtil.isEmpty(appUser.getUsername())) { + AppUserCache cache = appUserCacheService.getByUserId(appUser.getUserId()); + if (cache != null) { + appUser.setUsername(cache.getUsername()); + appUser.setNickname(cache.getNickname()); + appUser.setAvatar(cache.getAvatar()); + appUser.setPhone(cache.getPhone()); + } + } + } + } + + @Override + public AppUser getByIdRel(Integer id) { + AppUserParam param = new AppUserParam(); + param.setId(id.longValue()); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public AppUser inviteUser(Long appId, Integer userId, String role, Integer inviteBy, Integer tenantId) { + // 检查是否已经有待处理或已确认的邀请 + AppUser existUser = getByAppIdAndUserId(appId, userId); + if (existUser != null) { + if (existUser.getInviteStatus() == 0) { + throw new RuntimeException("该用户已经是应用成员"); + } else if (existUser.getInviteStatus() == 1) { + throw new RuntimeException("该用户已有待确认的邀请"); + } + } + + // 直接从 gxwebsoft_core 库跨库查询用户信息 + User sysUser = sysUserCrossDbMapper.selectByUserId(userId); + if (sysUser == null) { + throw new RuntimeException("用户不存在,userId=" + userId); + } + + AppUser appUser = new AppUser(); + appUser.setAppId(appId); + appUser.setUserId(userId); + appUser.setRole(role != null ? role : "developer"); + appUser.setInviteBy(inviteBy.longValue()); + appUser.setInviteTime(LocalDateTime.now()); + // 邀请7天后过期 + appUser.setInviteExpireTime(LocalDateTime.now().plusDays(7)); + appUser.setStatus(0); + appUser.setInviteStatus(1); // 待确认 + appUser.setSortNumber(0); + // 设置租户ID(NOT NULL约束) + appUser.setTenantId(tenantId); + // 冗余写入用户基础信息 + appUser.setUsername(sysUser.getUsername()); + appUser.setNickname(sysUser.getNickname()); + appUser.setAvatar(sysUser.getAvatar()); + appUser.setPhone(sysUser.getPhone()); + + save(appUser); + log.info("邀请成员成功,等待对方确认,appId={}, userId={}, username={}, role={}", appId, userId, sysUser.getUsername(), role); + + // 同时更新用户缓存 + refreshUserCache(userId, sysUser); + + // TODO: 发送通知给被邀请人 + // sendInviteNotification(appUser); + + return appUser; + } + + @Override + public boolean acceptInvite(Long inviteId, Integer userId) { + AppUser invite = getById(inviteId); + if (invite == null) { + throw new RuntimeException("邀请不存在"); + } + if (!invite.getUserId().equals(userId)) { + throw new RuntimeException("无权处理该邀请"); + } + if (invite.getInviteStatus() != 1) { + throw new RuntimeException("该邀请已处理或已过期"); + } + if (invite.getInviteExpireTime() != null && invite.getInviteExpireTime().isBefore(LocalDateTime.now())) { + throw new RuntimeException("邀请已过期"); + } + + boolean success = update(new LambdaUpdateWrapper() + .eq(AppUser::getId, inviteId) + .set(AppUser::getInviteStatus, 0) // 确认加入 + .set(AppUser::getInviteTime, LocalDateTime.now()) // 更新为确认时间 + .set(AppUser::getUpdateTime, LocalDateTime.now())); + + if (success) { + log.info("用户接受邀请,inviteId={}, userId={}, appId={}", inviteId, userId, invite.getAppId()); + // TODO: 发送通知给邀请人 + } + return success; + } + + @Override + public boolean rejectInvite(Long inviteId, Integer userId) { + AppUser invite = getById(inviteId); + if (invite == null) { + throw new RuntimeException("邀请不存在"); + } + if (!invite.getUserId().equals(userId)) { + throw new RuntimeException("无权处理该邀请"); + } + if (invite.getInviteStatus() != 1) { + throw new RuntimeException("该邀请已处理或已过期"); + } + + boolean success = update(new LambdaUpdateWrapper() + .eq(AppUser::getId, inviteId) + .set(AppUser::getInviteStatus, 2) // 拒绝 + .set(AppUser::getStatus, 1) // 标记为禁用 + .set(AppUser::getUpdateTime, LocalDateTime.now())); + + if (success) { + log.info("用户拒绝邀请,inviteId={}, userId={}, appId={}", inviteId, userId, invite.getAppId()); + // TODO: 发送通知给邀请人 + } + return success; + } + + @Override + public List listPendingInvites(Integer userId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppUser::getUserId, userId) + .eq(AppUser::getInviteStatus, 1) // 待确认 + .eq(AppUser::getStatus, 0) + .gt(AppUser::getInviteExpireTime, LocalDateTime.now()) // 未过期 + .orderByDesc(AppUser::getCreateTime); + List list = list(wrapper); + // 补充应用信息和邀请人信息 + fillAppAndInviterInfo(list); + return list; + } + + @Override + public long countPendingInvites(Integer userId) { + return count(new LambdaQueryWrapper() + .eq(AppUser::getUserId, userId) + .eq(AppUser::getInviteStatus, 1) + .eq(AppUser::getStatus, 0) + .gt(AppUser::getInviteExpireTime, LocalDateTime.now())); + } + + /** + * 补充应用信息和邀请人信息 + */ + private void fillAppAndInviterInfo(List list) { + if (CollUtil.isEmpty(list)) { + return; + } + for (AppUser appUser : list) { + // 补充邀请人信息 + if (appUser.getInviteBy() != null && appUserCacheService != null) { + AppUserCache inviterCache = appUserCacheService.getByUserId(appUser.getInviteBy().intValue()); + if (inviterCache != null) { + appUser.setUsername(inviterCache.getNickname() != null ? inviterCache.getNickname() : inviterCache.getUsername()); + } + } + // 补充应用信息 + if (appUser.getAppId() != null) { + // AppProduct 主键是 productId(Integer),appId 是 Long,需要转换 + Integer productId = appUser.getAppId().intValue(); + log.info("查询应用信息: appId={}, productId={}", appUser.getAppId(), productId); + + // 直接使用 Mapper 查询,避免 Service 可能的问题 + AppProduct product = appProductMapper.selectById(productId); + + if (product != null) { + log.info("找到应用信息: productId={}, productName={}", productId, product.getProductName()); + appUser.setProductName(product.getProductName()); + appUser.setIcon(product.getLogo() != null ? product.getLogo() : product.getIcon()); + appUser.setProductCode(product.getProductCode()); + } else { + log.warn("未找到应用信息: productId={}", productId); + } + } else { + log.debug("跳过应用信息查询: appId={}", appUser.getAppId()); + } + } + } + + /** + * 根据应用ID和用户ID查询成员记录 + */ + private AppUser getByAppIdAndUserId(Long appId, Integer userId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(AppUser::getAppId, appId) + .eq(AppUser::getUserId, userId); + return getOne(wrapper); + } + + @Override + public boolean updateRole(Long id, String role) { + return update(new LambdaUpdateWrapper() + .eq(AppUser::getId, id) + .set(AppUser::getRole, role)); + } + + @Override + public boolean isMember(Long appId, Integer userId) { + long count = count(new LambdaQueryWrapper() + .eq(AppUser::getAppId, appId) + .eq(AppUser::getUserId, userId) + .eq(AppUser::getStatus, 0) + .eq(AppUser::getInviteStatus, 0)); // 只算已确认的成员 + return count > 0; + } + + @Override + public boolean hasPendingInvite(Long appId, Integer userId) { + long count = count(new LambdaQueryWrapper() + .eq(AppUser::getAppId, appId) + .eq(AppUser::getUserId, userId) + .eq(AppUser::getInviteStatus, 1) + .eq(AppUser::getStatus, 0) + .gt(AppUser::getInviteExpireTime, LocalDateTime.now())); + return count > 0; + } + + @Override + public User findUserByPhone(String phone) { + // 直接从 gxwebsoft_core 库跨库查询用户 + return sysUserCrossDbMapper.selectByPhone(phone); + } + + @Override + public List searchUsers(String keyword) { + // 从 gxwebsoft_core 库跨库搜索用户(按手机号、用户名、昵称模糊搜索) + return sysUserCrossDbMapper.searchUsers(keyword); + } + + @Override + public void recordVisit(Long appId, Integer userId) { + if (appId == null || userId == null) { + return; + } + try { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.eq(AppUser::getAppId, appId) + .eq(AppUser::getUserId, userId) + .set(AppUser::getUpdateTime, LocalDateTime.now()); + this.update(wrapper); + log.debug("记录应用访问,appId={}, userId={}", appId, userId); + } catch (Exception e) { + log.error("记录应用访问失败,appId={}, userId={}", appId, userId, e); + } + } + + /** + * 更新用户缓存 + */ + private void refreshUserCache(Integer userId, User sysUser) { + if (appUserCacheService != null && sysUser != null) { + try { + AppUserCache cache = new AppUserCache(); + cache.setUserId(sysUser.getUserId()); + cache.setUsername(sysUser.getUsername()); + cache.setNickname(sysUser.getNickname()); + cache.setAvatar(sysUser.getAvatar()); + cache.setPhone(sysUser.getPhone()); + cache.setStatus(sysUser.getStatus()); + cache.setUpdateTime(LocalDateTime.now()); + appUserCacheService.saveOrUpdate(cache); + log.debug("用户缓存已更新,userId={}", userId); + } catch (Exception e) { + log.error("更新用户缓存失败,userId={}", userId, e); + } + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppVersionServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppVersionServiceImpl.java new file mode 100644 index 0000000..b74ebf6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/AppVersionServiceImpl.java @@ -0,0 +1,112 @@ +package com.gxwebsoft.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.app.mapper.AppVersionMapper; +import com.gxwebsoft.app.service.AppVersionService; +import com.gxwebsoft.app.entity.AppVersion; +import com.gxwebsoft.app.param.AppVersionParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 应用版本发布记录Service实现 + * + * @author 科技小王子 + * @since 2026-03-28 21:29:44 + */ +@Slf4j +@Service +public class AppVersionServiceImpl extends ServiceImpl implements AppVersionService { + + @Override + public PageResult pageRel(AppVersionParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AppVersionParam param) { + List list = baseMapper.selectListRel(param); + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public AppVersion getByIdRel(Integer id) { + AppVersionParam param = new AppVersionParam(); + param.setId(id.longValue()); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean publish(Long id, Integer publishBy) { + AppVersion version = getById(id); + if (version == null) { + throw new RuntimeException("版本不存在"); + } + Long appId = version.getAppId(); + + // 1. 将该应用下所有版本的 isCurrent 设为 false + update(new LambdaUpdateWrapper() + .eq(AppVersion::getAppId, appId) + .set(AppVersion::getIsCurrent, false)); + + // 2. 将当前版本设为已发布+当前版本 + version.setStatus(1); + version.setIsCurrent(true); + version.setPublishBy(publishBy.longValue()); + version.setPublishTime(LocalDateTime.now()); + + boolean result = updateById(version); + log.info("发布版本成功,id={}, versionNo={}", id, version.getVersionNo()); + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean rollback(Long id, Integer publishBy) { + AppVersion targetVersion = getById(id); + if (targetVersion == null) { + throw new RuntimeException("目标版本不存在"); + } + Long appId = targetVersion.getAppId(); + + // 1. 将当前版本标记为已回滚 + update(new LambdaUpdateWrapper() + .eq(AppVersion::getAppId, appId) + .eq(AppVersion::getIsCurrent, true) + .set(AppVersion::getStatus, 2) // 2=已回滚 + .set(AppVersion::getIsCurrent, false)); + + // 2. 将目标版本设为当前版本 + targetVersion.setStatus(1); + targetVersion.setIsCurrent(true); + targetVersion.setPublishBy(publishBy.longValue()); + targetVersion.setPublishTime(LocalDateTime.now()); + + boolean result = updateById(targetVersion); + log.info("回滚版本成功,id={}, versionNo={}", id, targetVersion.getVersionNo()); + return result; + } + + @Override + public AppVersion getCurrentVersion(Long appId) { + return getOne(new LambdaQueryWrapper() + .eq(AppVersion::getAppId, appId) + .eq(AppVersion::getIsCurrent, true) + .last("LIMIT 1")); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/MySqlOperatorServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/MySqlOperatorServiceImpl.java new file mode 100644 index 0000000..02d7001 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/MySqlOperatorServiceImpl.java @@ -0,0 +1,344 @@ +package com.gxwebsoft.app.service.impl; + +import com.gxwebsoft.app.service.DatabaseOperatorService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.sql.*; +import java.util.regex.Pattern; + +/** + * MySQL 远程数据库操作服务实现 + * 通过 JDBC 连接远程 MySQL 服务器执行 DDL 操作 + * + * @author WebSoft + * @since 2026-04-04 + */ +@Slf4j +@Service +public class MySqlOperatorServiceImpl implements DatabaseOperatorService { + + /** + * 合法数据库名校验:小写字母、数字、下划线,小写字母开头,最长 64 字符 + */ + private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[a-z][a-z0-9_]{0,63}$"); + + /** + * 连接超时(毫秒) + */ + private static final int CONNECT_TIMEOUT_MS = 5000; + + @Override + public String getSupportedDbType() { + return "MySQL"; + } + + @Override + public DatabaseOperationResult createDatabaseAndGrant(String host, Integer port, + String username, String password, + String dbName, String dbUser, String dbPass) { + // 参数校验 + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (port == null || port < 1 || port > 65535) { + return fail("端口号无效"); + } + if (username == null || username.trim().isEmpty()) { + return fail("管理员用户名不能为空"); + } + if (dbName == null || dbName.trim().isEmpty()) { + return fail("数据库名称不能为空"); + } + if (!DB_NAME_PATTERN.matcher(dbName).matches()) { + return fail("数据库名称格式不正确(小写字母开头,仅含小写字母、数字、下划线,最长64字符)"); + } + + // 去前后空格 + host = host.trim(); + username = username.trim(); + + // 使用管理员连接(不指定数据库) + String jdbcUrl = buildJdbcUrl(host, port, null); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) { + // 1. 检查数据库是否已存在 + if (databaseExists(conn, dbName)) { + log.info("MySQL 数据库 {} 在 {}:{} 上已存在,跳过创建", dbName, host, port); + } else { + // 2. 创建数据库 + try (Statement stmt = conn.createStatement()) { + String createSql = String.format( + "CREATE DATABASE `%s` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", dbName); + stmt.execute(createSql); + log.info("MySQL 数据库 {} 在 {}:{} 上创建成功", dbName, host, port); + } + } + + // 3. 创建用户并授权(如果提供了业务用户信息) + if (dbUser != null && !dbUser.trim().isEmpty()) { + dbUser = dbUser.trim(); + createUserAndGrant(conn, dbName, dbUser, dbPass); + } + + return ok("数据库创建成功", String.format("MySQL 数据库 %s 已就绪", dbName)); + + } catch (SQLException e) { + String errorMsg = parseError(e); + log.error("MySQL 创建数据库失败: host={}, port={}, db={}, error={}", host, port, dbName, errorMsg); + return fail("创建数据库失败", errorMsg); + } + } + + @Override + public DatabaseOperationResult dropDatabaseAndUser(String host, Integer port, + String username, String password, + String dbName, String dbUser) { + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (dbName == null || dbName.trim().isEmpty()) { + return fail("数据库名称不能为空"); + } + if (!DB_NAME_PATTERN.matcher(dbName).matches()) { + return fail("数据库名称格式不正确"); + } + + host = host.trim(); + username = username.trim(); + String jdbcUrl = buildJdbcUrl(host, port, null); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) { + // 1. 删除用户权限和用户 + if (dbUser != null && !dbUser.trim().isEmpty()) { + dbUser = dbUser.trim(); + try (Statement stmt = conn.createStatement()) { + stmt.execute(String.format("DROP USER IF EXISTS `%s`@`%%`", dbUser)); + stmt.execute(String.format("DROP USER IF EXISTS `%s`@`localhost`", dbUser)); + log.info("MySQL 用户 {} 已删除", dbUser); + } catch (SQLException e) { + log.warn("删除用户 {} 失败: {}", dbUser, e.getMessage()); + } + } + + // 2. 删除数据库 + if (databaseExists(conn, dbName)) { + try (Statement stmt = conn.createStatement()) { + stmt.execute(String.format("DROP DATABASE IF EXISTS `%s`", dbName)); + log.info("MySQL 数据库 {} 在 {}:{} 上已删除", dbName, host, port); + } + } + + return ok("数据库和用户已删除", String.format("MySQL 数据库 %s 已清理", dbName)); + + } catch (SQLException e) { + String errorMsg = parseError(e); + log.error("MySQL 删除数据库失败: host={}, port={}, db={}, error={}", host, port, dbName, errorMsg); + return fail("删除数据库失败", errorMsg); + } + } + + @Override + public DatabaseOperationResult testConnection(String host, Integer port, + String username, String password, + String dbName) { + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (username == null || username.trim().isEmpty()) { + return fail("用户名不能为空"); + } + + host = host.trim(); + username = username.trim(); + String jdbcUrl = buildJdbcUrl(host, port, dbName); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) { + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT VERSION()")) { + if (rs.next()) { + String version = rs.getString(1); + String dbInfo = dbName != null ? String.format(",数据库 %s", dbName) : ""; + return ok("连接成功", String.format("MySQL %s%s", version, dbInfo)); + } + } + return ok("连接成功"); + } catch (SQLException e) { + String errorMsg = parseError(e); + log.warn("MySQL 测试连接失败: host={}, port={}, db={}, user={}, error={}", host, port, dbName, username, errorMsg); + return fail("连接失败", errorMsg); + } + } + + @Override + public DatabaseOperationResult changePassword(String host, Integer port, + String adminUsername, String adminPassword, + String dbUsername, String oldPassword, String newPassword) { + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (adminUsername == null || adminUsername.trim().isEmpty()) { + return fail("管理员用户名不能为空"); + } + if (dbUsername == null || dbUsername.trim().isEmpty()) { + return fail("数据库用户名不能为空"); + } + if (newPassword == null || newPassword.trim().isEmpty()) { + return fail("新密码不能为空"); + } + + host = host.trim(); + adminUsername = adminUsername.trim(); + dbUsername = dbUsername.trim(); + + String jdbcUrl = buildJdbcUrl(host, port, null); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, adminUsername, adminPassword)) { + try (Statement stmt = conn.createStatement()) { + // 使用 ALTER USER 修改密码(MySQL 8.x 兼容) + String alterSql = String.format( + "ALTER USER `%s`@`%%` IDENTIFIED BY '%s'", dbUsername, escapeSql(newPassword)); + stmt.execute(alterSql); + + stmt.execute("FLUSH PRIVILEGES"); + log.info("MySQL 用户 {} 密码修改成功", dbUsername); + return ok("密码修改成功", String.format("用户 %s 的密码已更新", dbUsername)); + } + } catch (SQLException e) { + String errorMsg = parseError(e); + log.error("MySQL 修改密码失败: host={}, port={}, dbUser={}, error={}", host, port, dbUsername, errorMsg); + return fail("修改密码失败", errorMsg); + } + } + + /** + * 检查数据库是否已存在 + */ + private boolean databaseExists(Connection conn, String dbName) throws SQLException { + String sql = "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?"; + try (PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, dbName); + try (ResultSet rs = ps.executeQuery()) { + return rs.next(); + } + } + } + + /** + * 创建用户并授权 + */ + private void createUserAndGrant(Connection conn, String dbName, String dbUser, String dbPass) throws SQLException { + try (Statement stmt = conn.createStatement()) { + boolean userExists = false; + try (ResultSet rs = stmt.executeQuery( + String.format("SELECT User FROM mysql.user WHERE User = '%s' AND Host = '%%'", dbUser))) { + userExists = rs.next(); + } + + if (!userExists) { + String createUserSql = String.format( + "CREATE USER `%s`@`%%` IDENTIFIED BY '%s'", dbUser, escapeSql(dbPass)); + stmt.execute(createUserSql); + log.info("MySQL 用户 {} 创建成功", dbUser); + } else { + String alterUserSql = String.format( + "ALTER USER `%s`@`%%` IDENTIFIED BY '%s'", dbUser, escapeSql(dbPass)); + stmt.execute(alterUserSql); + log.info("MySQL 用户 {} 密码已更新", dbUser); + } + + String grantSql = String.format( + "GRANT ALL PRIVILEGES ON `%s`.* TO `%s`@`%%`", dbName, dbUser); + stmt.execute(grantSql); + + stmt.execute("FLUSH PRIVILEGES"); + log.info("MySQL 用户 {} 已授权数据库 {}", dbUser, dbName); + } + } + + /** + * 构建 MySQL JDBC URL + */ + private String buildJdbcUrl(String host, int port, String dbName) { + return String.format( + "jdbc:mysql://%s:%d%s?useUnicode=true&characterEncoding=UTF-8&useSSL=false" + + "&serverTimezone=Asia/Shanghai&connectTimeout=%d&socketTimeout=%d" + + "&allowPublicKeyRetrieval=true", + host, port, + dbName != null ? "/" + dbName : "/", + CONNECT_TIMEOUT_MS, CONNECT_TIMEOUT_MS); + } + + /** + * 转义 SQL 字符串中的单引号 + */ + private String escapeSql(String value) { + if (value == null) { + return ""; + } + return value.replace("'", "''"); + } + + /** + * 解析 MySQL 错误信息,返回更友好的中文提示 + */ + private String parseError(SQLException e) { + int errorCode = e.getErrorCode(); + String state = e.getSQLState(); + String message = e.getMessage(); + + switch (errorCode) { + case 1045: + return "用户名或密码错误(Access denied)"; + case 1049: + return "数据库不存在(Unknown database)"; + case 1064: + return "SQL 语法错误"; + case 1142: + return "权限不足,当前用户无权执行此操作"; + case 1213: + return "死锁,请稍后重试"; + case 1205: + return "锁等待超时,请稍后重试"; + default: + break; + } + + if ("28000".equals(state)) { + return "认证失败,请检查用户名和密码"; + } + if ("08S01".equals(state)) { + return "连接失败,请检查服务器地址和端口是否可达,以及 MySQL 是否允许远程连接"; + } + if ("08001".equals(state)) { + return "无法建立连接,请检查网络和防火墙设置"; + } + + if (message != null) { + String[] parts = message.split("\n"); + String lastPart = parts[parts.length - 1].trim(); + if (lastPart.length() > 200) { + return lastPart.substring(0, 200); + } + return lastPart; + } + + return "未知错误: " + state + " / " + errorCode; + } + + private static DatabaseOperationResult ok(String message) { + return DatabaseOperationResult.ok(message); + } + + private static DatabaseOperationResult ok(String message, String detail) { + return DatabaseOperationResult.ok(message, detail); + } + + private static DatabaseOperationResult fail(String message) { + return DatabaseOperationResult.fail(message); + } + + private static DatabaseOperationResult fail(String message, String detail) { + return DatabaseOperationResult.fail(message, detail); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/PostgreSqlOperatorServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/PostgreSqlOperatorServiceImpl.java new file mode 100644 index 0000000..f185eb4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/PostgreSqlOperatorServiceImpl.java @@ -0,0 +1,399 @@ +package com.gxwebsoft.app.service.impl; + +import com.gxwebsoft.app.service.DatabaseOperatorService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.sql.*; +import java.util.regex.Pattern; + +/** + * PostgreSQL 远程数据库操作服务实现 + * 通过 JDBC 连接远程 PostgreSQL 服务器执行 DDL 操作 + * + * @author WebSoft + * @since 2026-04-04 + */ +@Slf4j +@Service +public class PostgreSqlOperatorServiceImpl implements DatabaseOperatorService { + + /** + * 合法数据库名校验:小写字母、数字、下划线,小写字母开头,最长 63 字符 + */ + private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[a-z][a-z0-9_]{0,62}$"); + + /** + * 合法用户名校验:小写字母、数字、下划线,小写字母开头,最长 63 字符 + */ + private static final Pattern USER_NAME_PATTERN = Pattern.compile("^[a-z][a-z0-9_]{0,62}$"); + + /** + * 连接超时(毫秒) + */ + private static final int CONNECT_TIMEOUT_MS = 5000; + + @Override + public String getSupportedDbType() { + return "PostgreSQL"; + } + + @Override + public DatabaseOperationResult createDatabaseAndGrant(String host, Integer port, + String username, String password, + String dbName, String dbUser, String dbPass) { + // 参数校验 + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (port == null || port < 1 || port > 65535) { + return fail("端口号无效"); + } + if (username == null || username.trim().isEmpty()) { + return fail("管理员用户名不能为空"); + } + if (dbName == null || dbName.trim().isEmpty()) { + return fail("数据库名称不能为空"); + } + if (!DB_NAME_PATTERN.matcher(dbName).matches()) { + return fail("数据库名称格式不正确(小写字母开头,仅含小写字母、数字、下划线,最长63字符)"); + } + + host = host.trim(); + username = username.trim(); + + // PostgreSQL 需要连接到 postgres 维护数据库来执行 DDL + String jdbcUrl = buildJdbcUrl(host, port, "postgres"); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) { + // 1. 检查数据库是否已存在 + if (databaseExists(conn, dbName)) { + log.info("PostgreSQL 数据库 {} 在 {}:{} 上已存在,跳过创建", dbName, host, port); + } else { + // 2. 创建数据库 + try (Statement stmt = conn.createStatement()) { + stmt.execute(String.format( + "CREATE DATABASE \"%s\" ENCODING 'UTF8' LC_COLLATE='zh_CN.UTF-8' LC_CTYPE='zh_CN.UTF-8' TEMPLATE=template0", + escapeDoubleQuote(dbName))); + log.info("PostgreSQL 数据库 {} 在 {}:{} 上创建成功", dbName, host, port); + } + } + + // 3. 创建用户并授权(如果提供了业务用户信息) + if (dbUser != null && !dbUser.trim().isEmpty()) { + dbUser = dbUser.trim(); + if (!USER_NAME_PATTERN.matcher(dbUser).matches()) { + return fail("用户名格式不正确(小写字母开头,仅含小写字母、数字、下划线,最长63字符)"); + } + // 需要重新连接到新创建的数据库来授权 + String newDbUrl = buildJdbcUrl(host, port, dbName); + try (Connection newConn = DriverManager.getConnection(newDbUrl, username, password)) { + createUserAndGrant(newConn, dbName, dbUser, dbPass); + } + } + + return ok("数据库创建成功", String.format("PostgreSQL 数据库 %s 已就绪", dbName)); + + } catch (SQLException e) { + String errorMsg = parseError(e); + log.error("PostgreSQL 创建数据库失败: host={}, port={}, db={}, error={}", host, port, dbName, errorMsg); + return fail("创建数据库失败", errorMsg); + } + } + + @Override + public DatabaseOperationResult dropDatabaseAndUser(String host, Integer port, + String username, String password, + String dbName, String dbUser) { + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (dbName == null || dbName.trim().isEmpty()) { + return fail("数据库名称不能为空"); + } + if (!DB_NAME_PATTERN.matcher(dbName).matches()) { + return fail("数据库名称格式不正确"); + } + + host = host.trim(); + username = username.trim(); + String jdbcUrl = buildJdbcUrl(host, port, "postgres"); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) { + // 1. 断开所有活跃连接(PostgreSQL 删除数据库前必须先断开连接) + try (Statement stmt = conn.createStatement()) { + stmt.execute(String.format( + "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()", + escapeSql(dbName))); + } catch (SQLException e) { + log.warn("断开数据库 {} 活跃连接时出错: {}", dbName, e.getMessage()); + } + + // 2. 删除数据库 + if (databaseExists(conn, dbName)) { + try (Statement stmt = conn.createStatement()) { + stmt.execute(String.format("DROP DATABASE IF EXISTS \"%s\"", escapeDoubleQuote(dbName))); + log.info("PostgreSQL 数据库 {} 在 {}:{} 上已删除", dbName, host, port); + } + } + + // 3. 删除用户(如果有提供) + if (dbUser != null && !dbUser.trim().isEmpty()) { + dbUser = dbUser.trim(); + try (Statement stmt = conn.createStatement()) { + // 先撤销所有权限 + stmt.execute(String.format("REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM \"%s\"", escapeDoubleQuote(dbUser))); + stmt.execute(String.format("REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM \"%s\"", escapeDoubleQuote(dbUser))); + stmt.execute(String.format("REVOKE USAGE ON SCHEMA public FROM \"%s\"", escapeDoubleQuote(dbUser))); + stmt.execute(String.format("REVOKE CONNECT ON DATABASE \"%s\" FROM \"%s\"", escapeDoubleQuote(dbName), escapeDoubleQuote(dbUser))); + // 删除用户 + stmt.execute(String.format("DROP USER IF EXISTS \"%s\"", escapeDoubleQuote(dbUser))); + log.info("PostgreSQL 用户 {} 已删除", dbUser); + } catch (SQLException e) { + log.warn("删除 PostgreSQL 用户 {} 失败: {}", dbUser, e.getMessage()); + } + } + + return ok("数据库和用户已删除", String.format("PostgreSQL 数据库 %s 已清理", dbName)); + + } catch (SQLException e) { + String errorMsg = parseError(e); + log.error("PostgreSQL 删除数据库失败: host={}, port={}, db={}, error={}", host, port, dbName, errorMsg); + return fail("删除数据库失败", errorMsg); + } + } + + @Override + public DatabaseOperationResult testConnection(String host, Integer port, + String username, String password, + String dbName) { + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (username == null || username.trim().isEmpty()) { + return fail("用户名不能为空"); + } + + host = host.trim(); + username = username.trim(); + + // 测试连接:如果指定了数据库名就用数据库名,否则用 postgres 维护库 + String connectDb = (dbName != null && !dbName.trim().isEmpty()) ? dbName.trim() : "postgres"; + String jdbcUrl = buildJdbcUrl(host, port, connectDb); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) { + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT version()")) { + if (rs.next()) { + String version = rs.getString(1); + String dbInfo = dbName != null ? String.format(",数据库 %s", dbName) : ""; + return ok("连接成功", String.format("PostgreSQL %s%s", version, dbInfo)); + } + } + return ok("连接成功"); + } catch (SQLException e) { + String errorMsg = parseError(e); + log.warn("PostgreSQL 测试连接失败: host={}, port={}, db={}, user={}, error={}", host, port, dbName, username, errorMsg); + return fail("连接失败", errorMsg); + } + } + + @Override + public DatabaseOperationResult changePassword(String host, Integer port, + String adminUsername, String adminPassword, + String dbUsername, String oldPassword, String newPassword) { + if (host == null || host.trim().isEmpty()) { + return fail("服务器地址不能为空"); + } + if (adminUsername == null || adminUsername.trim().isEmpty()) { + return fail("管理员用户名不能为空"); + } + if (dbUsername == null || dbUsername.trim().isEmpty()) { + return fail("数据库用户名不能为空"); + } + if (newPassword == null || newPassword.trim().isEmpty()) { + return fail("新密码不能为空"); + } + + host = host.trim(); + adminUsername = adminUsername.trim(); + dbUsername = dbUsername.trim(); + + // PostgreSQL 需要连接到 postgres 维护库来执行 ALTER USER + String jdbcUrl = buildJdbcUrl(host, port, "postgres"); + + try (Connection conn = DriverManager.getConnection(jdbcUrl, adminUsername, adminPassword)) { + try (Statement stmt = conn.createStatement()) { + // 使用 ALTER USER 修改密码(PostgreSQL 兼容) + String alterSql = String.format( + "ALTER USER \"%s\" WITH PASSWORD '%s'", + escapeDoubleQuote(dbUsername), escapeSql(newPassword)); + stmt.execute(alterSql); + log.info("PostgreSQL 用户 {} 密码修改成功", dbUsername); + return ok("密码修改成功", String.format("用户 %s 的密码已更新", dbUsername)); + } + } catch (SQLException e) { + String errorMsg = parseError(e); + log.error("PostgreSQL 修改密码失败: host={}, port={}, dbUser={}, error={}", host, port, dbUsername, errorMsg); + return fail("修改密码失败", errorMsg); + } + } + + /** + * 检查数据库是否已存在 + */ + private boolean databaseExists(Connection conn, String dbName) throws SQLException { + String sql = "SELECT datname FROM pg_database WHERE datname = ?"; + try (PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, dbName); + try (ResultSet rs = ps.executeQuery()) { + return rs.next(); + } + } + } + + /** + * 创建用户并授权 + */ + private void createUserAndGrant(Connection conn, String dbName, String dbUser, String dbPass) throws SQLException { + try (Statement stmt = conn.createStatement()) { + boolean userExists = false; + try (ResultSet rs = stmt.executeQuery( + String.format("SELECT usename FROM pg_user WHERE usename = '%s'", escapeSql(dbUser)))) { + userExists = rs.next(); + } + + if (!userExists) { + String createUserSql = String.format( + "CREATE USER \"%s\" WITH PASSWORD '%s'", + escapeDoubleQuote(dbUser), escapeSql(dbPass)); + stmt.execute(createUserSql); + log.info("PostgreSQL 用户 {} 创建成功", dbUser); + } else { + String alterUserSql = String.format( + "ALTER USER \"%s\" WITH PASSWORD '%s'", + escapeDoubleQuote(dbUser), escapeSql(dbPass)); + stmt.execute(alterUserSql); + log.info("PostgreSQL 用户 {} 密码已更新", dbUser); + } + + // 授予数据库连接权限和 schema 使用权限 + stmt.execute(String.format("GRANT CONNECT ON DATABASE \"%s\" TO \"%s\"", + escapeDoubleQuote(dbName), escapeDoubleQuote(dbUser))); + stmt.execute(String.format("GRANT USAGE ON SCHEMA public TO \"%s\"", + escapeDoubleQuote(dbUser))); + stmt.execute(String.format("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"%s\"", + escapeDoubleQuote(dbUser))); + stmt.execute(String.format("GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO \"%s\"", + escapeDoubleQuote(dbUser))); + // 设置默认权限,后续新建的表也自动授权 + stmt.execute(String.format("ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO \"%s\"", + escapeDoubleQuote(dbUser))); + stmt.execute(String.format("ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO \"%s\"", + escapeDoubleQuote(dbUser))); + + log.info("PostgreSQL 用户 {} 已授权数据库 {}", dbUser, dbName); + } + } + + /** + * 构建 PostgreSQL JDBC URL + */ + private String buildJdbcUrl(String host, int port, String dbName) { + return String.format( + "jdbc:postgresql://%s:%d/%s?connectTimeout=%d&socketTimeout=%d", + host, port, + dbName != null ? dbName : "postgres", + CONNECT_TIMEOUT_MS / 1000, CONNECT_TIMEOUT_MS / 1000); + } + + /** + * 转义 SQL 字符串中的单引号 + */ + private String escapeSql(String value) { + if (value == null) { + return ""; + } + return value.replace("'", "''"); + } + + /** + * 转义双引号标识符(PostgreSQL 用双引号包裹标识符) + */ + private String escapeDoubleQuote(String value) { + if (value == null) { + return ""; + } + return value.replace("\"", "\"\""); + } + + /** + * 解析 PostgreSQL 错误信息,返回更友好的中文提示 + */ + private String parseError(SQLException e) { + String state = e.getSQLState(); + String message = e.getMessage(); + + // PostgreSQL SQLSTATE 错误码 + if ("3D000".equals(state)) { + return "数据库不存在"; + } + if ("08001".equals(state) || "08004".equals(state)) { + return "连接失败,请检查服务器地址和端口是否可达,以及 PostgreSQL 是否允许远程连接"; + } + if ("28000".equals(state)) { + return "认证失败,请检查用户名和密码(pg_hba.conf 可能需要调整认证方式)"; + } + if ("28P01".equals(state)) { + return "密码认证失败,请检查用户名和密码"; + } + if ("3F000".equals(state)) { + return "无效的目录名(schema)"; + } + if ("42000".equals(state) || "42601".equals(state)) { + return "SQL 语法错误"; + } + if ("42501".equals(state)) { + return "权限不足,当前用户无权执行此操作"; + } + if ("42P04".equals(state)) { + return "数据库已存在"; + } + if ("42P06".equals(state)) { + return "schema 已存在"; + } + if ("42723".equals(state)) { + return "用户已存在"; + } + if ("55000".equals(state) || "55006".equals(state)) { + return "无法操作,数据库正在被其他连接使用"; + } + + if (message != null) { + // PostgreSQL 错误信息通常格式为: ERROR: xxx + String cleanMsg = message.replace("ERROR: ", "").replace("FATAL: ", "").trim(); + if (cleanMsg.length() > 200) { + return cleanMsg.substring(0, 200); + } + return cleanMsg; + } + + return "未知错误: " + state; + } + + private static DatabaseOperationResult ok(String message) { + return DatabaseOperationResult.ok(message); + } + + private static DatabaseOperationResult ok(String message, String detail) { + return DatabaseOperationResult.ok(message, detail); + } + + private static DatabaseOperationResult fail(String message) { + return DatabaseOperationResult.fail(message); + } + + private static DatabaseOperationResult fail(String message, String detail) { + return DatabaseOperationResult.fail(message, detail); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/SshServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/SshServiceImpl.java new file mode 100644 index 0000000..f99d657 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/service/impl/SshServiceImpl.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.app.service.impl; + +import com.gxwebsoft.app.service.SshService; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.Session; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Properties; + +/** + * SSH 连接测试服务实现 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +@Slf4j +@Service +public class SshServiceImpl implements SshService { + + private static final int CONNECTION_TIMEOUT = 10000; // 10秒超时 + + @Override + public ConnectionResult testConnection(String host, Integer port, String username, String password) { + if (host == null || host.trim().isEmpty()) { + return ConnectionResult.fail("服务器地址不能为空"); + } + if (username == null || username.trim().isEmpty()) { + return ConnectionResult.fail("用户名不能为空"); + } + if (password == null || password.trim().isEmpty()) { + return ConnectionResult.fail("密码不能为空"); + } + + host = host.trim(); + username = username.trim(); + int sshPort = port != null ? port : 22; + + Session session = null; + try { + JSch jsch = new JSch(); + + session = jsch.getSession(username, host, sshPort); + session.setPassword(password); + + // 设置 SSH 连接属性 + Properties config = new Properties(); + config.put("StrictHostKeyChecking", "no"); // 不验证 host key + config.put("PreferredAuthentications", "password"); + session.setConfig(config); + + // 设置超时 + session.setTimeout(CONNECTION_TIMEOUT); + + // 连接 + session.connect(); + + // 获取 SSH 版本信息 + String serverVersion = session.getServerVersion(); + log.info("SSH 连接成功: host={}, port={}, user={}, version={}", host, sshPort, username, serverVersion); + + return ConnectionResult.ok( + "连接成功", + String.format("SSH %s@%s:%d 连接成功", username, host, sshPort) + ); + + } catch (Exception e) { + String errorMsg = e.getMessage(); + log.warn("SSH 连接失败: host={}, port={}, user={}, error={}", host, sshPort, username, errorMsg); + return ConnectionResult.fail("连接失败", errorMsg); + } finally { + if (session != null && session.isConnected()) { + session.disconnect(); + } + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/CICD_CONFIG_GUIDE.md b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/CICD_CONFIG_GUIDE.md new file mode 100644 index 0000000..25790cf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/CICD_CONFIG_GUIDE.md @@ -0,0 +1,584 @@ +# CI/CD 配置指南 + +> 本文档详细说明如何配置 Jenkins / GitHub Actions / Gitea CI 与 MP 平台集成 + +--- + +## 一、Gitea CI 配置 + +### 1.1 获取 Gitea API Token + +1. 登录 Gitea,进入 **Settings** → **Applications** +2. 在 "Access Tokens" 部分,点击 **Generate Token** +3. 输入 Token 名称(如 `mp-platform`),设置过期时间 +4. 选择权限范围: + - ✅ `repo` - 仓库访问 + - ✅ `workflow` - 工作流触发 +5. 点击 **Generate Token**,复制生成的 Token + +### 1.2 在 MP 平台配置 Gitea + +**方式一:通过数据库配置** + +```sql +-- 进入数据库 +mysql -u root -p db_websopy + +-- 插入 Gitea 配置 +INSERT INTO sys_config (config_key, config_value, config_name, group_name, remark, create_time) +VALUES +('gitea-url', 'https://git.websoft.top', 'Gitea 服务器地址', 'cicd', 'Gitea CI 服务器地址', NOW()), +('gitea-token', 'your-gitea-token-here', 'Gitea API Token', 'cicd', 'Gitea API 访问令牌', NOW()); +``` + +**方式二:通过配置文件** + +```yaml +# application.yml 或 application-prod.yml +config: + gitea-url: https://git.websoft.top + gitea-token: your-gitea-token-here +``` + +### 1.3 Gitea Webhook 配置(自动更新构建状态) + +1. 登录 Gitea,进入你的**仓库** → **Settings** → **Webhooks** +2. 点击 **Add Webhook** → **Gitea** +3. 配置 Webhook: + ``` + Target URL: https://your-domain.com/api/app/cicd/webhook/gitea + HTTP Method: POST + Content Type: application/json + Secret: (可选)设置一个秘钥用于校验 + Trigger On: ✅ Push + ✅ Pull Request + ✅ Workflow Run (如果可用) + ``` +4. 点击 **Add Webhook** 保存 + +### 1.4 在仓库中添加构建工作流 + +在仓库根目录创建 `.gitea/workflows/build.yml`: + +```yaml +name: Build & Deploy + +on: + workflow_dispatch: # 手动触发 + inputs: + environment: + description: '部署环境' + required: true + default: 'staging' + type: choice + options: + - staging + - production + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Build + run: npm run build + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + # Webhook 回调(通知 MP 平台构建状态) + - name: Notify MP Platform + run: | + curl -X POST ${{ secrets.MP_WEBHOOK_URL }} \ + -H "Content-Type: application/json" \ + -d '{"run_id":"${{ github.run_id }}","status":"success","conclusion":"success"}' +``` + +--- + +## 二、Jenkins 配置 + +### 2.1 安装必要插件 + +在 Jenkins 管理界面:**Manage Jenkins** → **Manage Plugins** + +安装以下插件: +- ✅ **GitHub Integration Plugin** +- ✅ **Pipeline Plugin** +- ✅ **HTTP Request Plugin** +- ✅ **Generic Webhook Trigger Plugin** + +### 2.2 配置 Jenkins API Token + +1. 登录 Jenkins,进入 **People** → 你的用户 → **Configure** +2. 在 **API Token** 部分,点击 **Add new Token** +3. 生成并复制 Token + +### 2.3 在 MP 平台配置 Jenkins + +```sql +-- 插入 Jenkins 配置 +INSERT INTO sys_config (config_key, config_value, config_name, group_name, remark, create_time) +VALUES +('jenkins-url', 'https://jenkins.websoft.top', 'Jenkins 服务器地址', 'cicd', 'Jenkins CI 服务器地址', NOW()), +('jenkins-token', 'your-jenkins-api-token', 'Jenkins API Token', 'cicd', 'Jenkins API 访问令牌', NOW()), +('jenkins-username', 'admin', 'Jenkins 用户名', 'cicd', 'Jenkins 认证用户名', NOW()); +``` + +### 2.4 Jenkins Pipeline 配置 + +在 Jenkins 中创建 Pipeline Job,编写 Jenkinsfile: + +```groovy +pipeline { + agent any + + environment { + MP_WEBHOOK_URL = credentials('mp-webhook-url') + } + + stages { + stage('Checkout') { + steps { + echo 'Checking out source code...' + checkout scm + } + } + + stage('Build') { + steps { + echo 'Building application...' + sh ''' + npm ci + npm run build + ''' + } + } + + stage('Test') { + steps { + echo 'Running tests...' + sh 'npm test || true' + } + } + + stage('Notify MP Platform') { + steps { + script { + def buildStatus = currentBuild.result ?: 'SUCCESS' + def status = buildStatus == 'SUCCESS' ? 'success' : 'failed' + + // 通知 MP 平台构建状态 + httpRequest( + url: "${MP_WEBHOOK_URL}", + httpMode: 'POST', + contentType: 'APPLICATION_JSON', + requestBody: """ + { + "jenkins_job": "${env.JOB_NAME}", + "build_number": ${env.BUILD_NUMBER}, + "status": "${status}", + "build_url": "${env.BUILD_URL}" + } + """ + ) + } + } + } + + stage('Deploy') { + when { + branch 'main' + } + steps { + echo 'Deploying to production...' + // 添加你的部署脚本 + } + } + } + + post { + always { + echo 'Pipeline execution completed' + } + success { + echo 'Build succeeded!' + } + failure { + echo 'Build failed!' + } + } +} +``` + +### 2.5 Jenkins Webhook 配置 + +1. 进入 Job 配置 → **Build Triggers** +2. 勾选 **Trigger builds remotely**(或使用 GitHub Integration) +3. 设置认证 Token +4. 配置 GitHub Webhook 指向 Jenkins + +### 2.6 Jenkinsfile 仓库示例 + +``` +your-repo/ +├── Jenkinsfile +├── package.json +└── src/ +``` + +--- + +## 三、GitHub Actions 配置 + +### 3.1 创建 GitHub Personal Access Token + +1. 登录 GitHub → **Settings** → **Developer settings** +2. **Personal access tokens** → **Fine-grained tokens** +3. 点击 **Generate new token** +4. 配置 Token: + - **Token name**: `mp-platform-cicd` + - **Expiration**: 自定义 + - **Repository access**: 选择你的仓库 + - **Permissions**: + - ✅ `actions: read and write` + - ✅ `contents: read` + - ✅ `workflows: read and write` + +### 3.2 在 MP 平台配置 GitHub + +```sql +-- 插入 GitHub 配置 +INSERT INTO sys_config (config_key, config_value, config_name, group_name, remark, create_time) +VALUES +('github-api-url', 'https://api.github.com', 'GitHub API 地址', 'cicd', 'GitHub API 服务器地址', NOW()), +('github-token', 'your-github-pat-token', 'GitHub API Token', 'cicd', 'GitHub Personal Access Token', NOW()), +('github-owner', 'your-github-username', 'GitHub 仓库所有者', 'cicd', 'GitHub 用户名或组织名', NOW()); +``` + +### 3.3 GitHub Webhook 配置 + +1. 进入 GitHub 仓库 → **Settings** → **Webhooks** +2. 点击 **Add webhook** +3. 配置: + ``` + Payload URL: https://your-domain.com/api/app/cicd/webhook/github + Content type: application/json + Secret: (可选)设置 Webhook Secret + SSL verification: Enable + Events: ✅ Push + ✅ Pull requests + ✅ Workflow runs + ``` +4. 点击 **Add webhook** + +### 3.4 添加 GitHub Actions 工作流 + +在仓库创建 `.github/workflows/build.yml`: + +```yaml +name: CI/CD Pipeline + +on: + workflow_dispatch: # 手动触发 + inputs: + environment: + description: '部署环境' + required: true + default: 'staging' + type: choice + options: + - staging + - production + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + +env: + MP_WEBHOOK_URL: ${{ secrets.MP_WEBHOOK_URL }} + +jobs: + build: + runs-on: ubuntu-latest + outputs: + status: ${{ job.status }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Run tests + run: npm test + continue-on-error: false + + - name: Build + run: npm run build + env: + NODE_ENV: production + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: dist-${{ github.sha }} + path: dist/ + retention-days: 7 + + - name: Notify MP Platform - Started + if: always() + run: | + curl -X POST "${{ env.MP_WEBHOOK_URL }}" \ + -H "Content-Type: application/json" \ + -d '{ + "event": "workflow_run", + "action": "started", + "workflow": "${{ github.workflow }}", + "run_id": "${{ github.run_id }}", + "sha": "${{ github.sha }}", + "status": "running" + }' + + - name: Notify MP Platform - Completed + if: always() + run: | + curl -X POST "${{ env.MP_WEBHOOK_URL }}" \ + -H "Content-Type: application/json" \ + -d '{ + "event": "workflow_run", + "action": "completed", + "workflow": "${{ github.workflow }}", + "run_id": "${{ github.run_id }}", + "sha": "${{ github.sha }}", + "status": "${{ job.status }}", + "conclusion": "${{ job.status == '\''success'\'' && '\''success'\'' || '\''failure'\'' }}" + }' + + deploy-staging: + needs: build + if: github.ref == 'refs/heads/develop' + runs-on: ubuntu-latest + steps: + - name: Deploy to Staging + run: | + echo "Deploying to staging..." + # 添加你的部署脚本 + + deploy-production: + needs: build + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: dist-${{ github.sha }} + + - name: Deploy to Production + run: | + echo "Deploying to production..." + # 添加你的部署脚本 +``` + +### 3.5 配置 GitHub Secrets + +在 GitHub 仓库 **Settings** → **Secrets and variables** → **Actions** 中添加: + +| Secret Name | Value | +|-------------|-------| +| `MP_WEBHOOK_URL` | `https://your-domain.com/api/app/cicd/webhook/github` | +| `DEPLOY_TOKEN` | 部署服务器 SSH 密钥(可选) | + +--- + +## 四、流水线配置示例 + +### 4.1 Gitea CI 流水线配置 + +在 MP 平台创建流水线时: + +```json +{ + "name": "前端应用构建", + "ciType": "gitea", + "repoFullName": "owner/repository", + "defaultBranch": "main", + "workflowFile": "build.yml", + "enabled": true, + "autoTrigger": true, + "buildConfig": { + "dockerfile": "Dockerfile", + "imageName": "myapp:latest", + "registry": "registry.websoft.top" + } +} +``` + +### 4.2 Jenkins 流水线配置 + +```json +{ + "name": "Jenkins Node.js 构建", + "ciType": "jenkins", + "jenkinsJobName": "myapp-build", + "jenkinsBuildParams": { + "BRANCH": "main", + "ENVIRONMENT": "staging" + }, + "enabled": true, + "autoTrigger": false +} +``` + +### 4.3 GitHub Actions 流水线配置 + +```json +{ + "name": "GitHub Actions 构建", + "ciType": "github", + "repoFullName": "owner/repository", + "workflowFile": "build.yml", + "defaultBranch": "main", + "enabled": true, + "autoTrigger": true +} +``` + +--- + +## 五、Webhook 回调格式 + +### 5.1 Gitea Webhook 格式 + +```json +{ + "action": "run", + "仓库": { + "full_name": "owner/repo" + }, + "sender": { + "login": "username" + }, + "workflow_run": { + "id": 123456, + "run_number": 42, + "status": "completed", + "conclusion": "success" + } +} +``` + +### 5.2 Jenkins Webhook 格式 + +```json +{ + "jenkins_job": "myapp-build", + "build_number": 156, + "status": "success", + "build_url": "https://jenkins.websoft.top/job/myapp-build/156/", + "timestamp": 1712123456789 +} +``` + +### 5.3 GitHub Actions Webhook 格式 + +```json +{ + "event": "workflow_run", + "action": "completed", + "workflow": "CI/CD Pipeline", + "run_id": 12345678, + "sha": "abc123def456", + "status": "completed", + "conclusion": "success" +} +``` + +--- + +## 六、常见问题排查 + +### 6.1 构建状态不更新 + +1. 检查 Webhook 是否正确配置 +2. 验证 Webhook URL 可访问性 +3. 查看后端日志: + ```bash + tail -f logs/app.log | grep -i webhook + ``` + +### 6.2 触发构建失败 + +1. 确认 API Token 有效且有足够权限 +2. 检查 Token 是否已写入数据库配置 +3. 验证仓库名称和分支是否正确 + +### 6.3 跨域/CORS 问题 + +如果前端直接调用 CI API,确保: +- CI 服务器已配置 CORS 白名单 +- 或通过后端代理转发请求 + +--- + +## 七、安全建议 + +1. **Token 安全** + - 使用环境变量而非代码中硬编码 + - 定期轮换 Token + - 使用最小权限原则 + +2. **Webhook 安全** + - 设置 Webhook Secret + - 在后端验证签名 + +3. **访问控制** + - 限制谁可以触发构建 + - 不同环境使用不同认证 + +--- + +## 八、相关文件 + +| 文件 | 说明 | +|------|------| +| `CICDController.java` | CI/CD API 控制器 | +| `AppBuildServiceImpl.java` | 构建服务实现 | +| `AppPipelineServiceImpl.java` | 流水线服务实现 | +| `app_build.sql` | 构建记录表 | +| `app_pipeline.sql` | 流水线配置表 | + +--- + +*最后更新:2026-04-03* diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/README_CICD.md b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/README_CICD.md new file mode 100644 index 0000000..b2265ee --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/README_CICD.md @@ -0,0 +1,154 @@ +# CI/CD 功能说明 + +## 概述 + +CI/CD 模块提供完整的持续集成和持续部署功能,支持对接 Gitea CI / Jenkins / GitHub Actions。 + +## 数据库表 + +### app_pipeline - 流水线配置表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | BIGINT | 自增ID | +| app_id | BIGINT | 关联应用ID | +| name | VARCHAR(200) | 流水线名称 | +| ci_type | VARCHAR(20) | CI系统类型: gitea/jenkins/github | +| repo_full_name | VARCHAR(200) | 仓库全称(如 gxwebsoft/my-app) | +| workflow_file | VARCHAR(100) | 工作流文件名 | +| env | VARCHAR(50) | 环境: development/staging/production | +| default_branch | VARCHAR(100) | 默认触发分支 | +| enabled | TINYINT | 是否启用 | +| auto_deploy | TINYINT | 自动部署 | +| timeout | INT | 超时时间(秒) | +| success_count | INT | 成功次数 | +| failure_count | INT | 失败次数 | + +### app_build - 构建记录表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | BIGINT | 自增ID | +| app_id | BIGINT | 关联应用ID | +| build_number | VARCHAR(100) | 构建编号 | +| branch | VARCHAR(100) | 触发分支 | +| ci_type | VARCHAR(20) | CI系统类型 | +| status | VARCHAR(20) | 状态: pending/running/success/failed/cancelled | +| started_at | DATETIME | 开始时间 | +| finished_at | DATETIME | 结束时间 | +| duration | INT | 耗时(秒) | +| log_url | VARCHAR(500) | 日志URL | +| artifact_url | VARCHAR(500) | 产物URL | +| trigger_type | VARCHAR(20) | 触发方式: manual/webhook/schedule | + +## API 接口 + +### 流水线 API + +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | /api/app/cicd/pipeline/page | 分页查询流水线 | +| GET | /api/app/cicd/pipeline/app/{appId} | 查询应用的所有流水线 | +| GET | /api/app/cicd/pipeline/{id} | 查询流水线详情 | +| POST | /api/app/cicd/pipeline | 创建流水线 | +| PUT | /api/app/cicd/pipeline | 更新流水线 | +| DELETE | /api/app/cicd/pipeline/{id} | 删除流水线 | +| POST | /api/app/cicd/pipeline/{id}/toggle | 启用/禁用流水线 | +| GET | /api/app/cicd/pipeline/{id}/status | 获取流水线状态 | + +### 构建 API + +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | /api/app/cicd/build/page | 分页查询构建记录 | +| GET | /api/app/cicd/build/app/{appId} | 查询应用的所有构建 | +| GET | /api/app/cicd/build/{id} | 查询构建详情 | +| GET | /api/app/cicd/build/latest/{appId} | 获取应用最新构建 | +| POST | /api/app/cicd/build/trigger | 触发构建 | +| GET | /api/app/cicd/build/{id}/log | 获取构建日志 | +| POST | /api/app/cicd/build/{id}/cancel | 取消构建 | +| POST | /api/app/cicd/build/{id}/retry | 重试构建 | +| GET | /api/app/cicd/build/stats/{appId} | 获取构建统计 | + +### Webhook API + +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | /api/app/cicd/webhook/gitea | Gitea Webhook 回调 | + +## 前端页面 + +- `/developer/build` - 构建任务页面 +- `/developer/pipeline` - 流水线管理页面 + +## 安装步骤 + +1. 执行 SQL 创建表: + ```bash + mysql -u root -p db_websopy < app/sql/app_pipeline.sql + mysql -u root -p db_websopy < app/sql/app_build.sql + ``` + +2. 配置 Gitea API(可选): + ```properties + config.gitea-url=https://git.websoft.top + config.gitea-token=your-gitea-token + ``` + +3. 配置 Webhook(在 Gitea 中配置): + ``` + URL: https://your-domain/api/app/cicd/webhook/gitea + Content-Type: application/json + Events: Push, Pull Request + ``` + +## Gitea Actions 配置 + +在仓库中创建 `.gitea/workflows/build.yml`: + +```yaml +name: Build and Deploy + +on: + push: + branches: [ main, develop ] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + deploy: + needs: build + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + steps: + - name: Deploy to server + run: echo "Deploying..." +``` + +## 注意事项 + +1. 构建记录需要关联应用才能触发构建 +2. 触发构建前需要先配置流水线 +3. Webhook 回调需要在 CI 系统中配置才能自动更新构建状态 +4. 支持 Jenkins/GitHub Actions 的 Webhook 回调可扩展 diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/README_PERMISSION_REQUEST.md b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/README_PERMISSION_REQUEST.md new file mode 100644 index 0000000..a0b9219 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/README_PERMISSION_REQUEST.md @@ -0,0 +1,170 @@ +# 权限申请模块说明 + +## 概述 +权限申请模块(Permission Requests)允许开发者申请访问特定的 Git 仓库。 + +## 数据库表 + +### 1. app_permission_request +存储权限申请记录。 + +**字段说明:** +- `id`: 自增主键 +- `user_id`: 申请用户ID +- `git_username`: Git用户名 +- `repo`: 申请仓库路径(如:owner/repo-name) +- `repo_name`: 仓库名称 +- `reason`: 申请理由 +- `status`: 状态(pending待审核/approved已通过/rejected已拒绝) +- `reject_reason`: 拒绝原因 +- `reviewer_id`: 审核人用户ID +- `reviewer_name`: 审核人姓名 +- `reviewed_at`: 审核时间 +- `create_time`: 创建时间 +- `update_time`: 更新时间 +- `deleted`: 逻辑删除标识 + +### 2. app_repository +存储可用仓库列表。 + +**字段说明:** +- `id`: 自增主键 +- `path`: 仓库路径(唯一) +- `name`: 仓库名称 +- `description`: 仓库描述 +- `access_level`: 访问权限级别(read/write/admin) +- `status`: 状态(active/inactive) +- `create_time`: 创建时间 +- `update_time`: 更新时间 +- `deleted`: 逻辑删除标识 + +## API 接口 + +### 1. 获取权限申请列表 +``` +GET /api/app/developer/permission-requests +参数: +- page: 页码(默认1) +- size: 每页大小(默认20) +- status: 状态筛选(pending/approved/rejected) + +返回: +{ + "code": 200, + "message": "success", + "data": { + "records": [...], + "total": 10 + } +} +``` + +### 2. 获取权限申请统计 +``` +GET /api/app/developer/permission-requests/stats + +返回: +{ + "code": 200, + "message": "success", + "data": { + "total": 10, + "pending": 3, + "approved": 5, + "rejected": 2 + } +} +``` + +### 3. 提交权限申请 +``` +POST /api/app/developer/permission-requests +请求体: +{ + "repo": "owner/repo-name", + "reason": "申请理由", + "gitUsername": "git-username"(可选) +} + +返回: +{ + "code": 200, + "message": "申请提交成功,请等待审核", + "data": { + "id": 1, + "repo": "owner/repo-name", + "repoName": "repo-name", + "reason": "申请理由", + "status": "pending", + "createdAt": "2026-04-03 10:00:00" + } +} +``` + +### 4. 获取可申请的仓库列表 +``` +GET /api/app/developer/permission-requests/available-repos + +返回: +{ + "code": 200, + "message": "success", + "data": [ + { + "value": "owner/repo-name", + "label": "仓库名称", + "description": "仓库描述", + "accessLevel": "read", + "isAccessible": false + } + ] +} +``` + +### 5. 审核通过(管理员功能) +``` +PUT /api/app/developer/permission-requests/{id}/approve +请求体: +{ + "note": "审核备注"(可选) +} +``` + +### 6. 拒绝申请(管理员功能) +``` +PUT /api/app/developer/permission-requests/{id}/reject +请求体: +{ + "reason": "拒绝原因" +} +``` + +## 前端页面 + +路径:`/developer/requests` + +功能: +1. 查看权限申请记录列表 +2. 按状态筛选申请(全部/待审核/已通过/已拒绝) +3. 查看统计数据(全部/待审核/已通过/已拒绝) +4. 提交新的仓库访问申请 +5. 查看申请详情(仓库、理由、审核人、审核时间等) + +## 注意事项 + +1. 同一用户对同一仓库只能有一个待审核的申请 +2. 已拥有访问权限的仓库不能重复申请 +3. 审核人可以批准或拒绝申请 +4. 拒绝时必须填写拒绝原因 + +## 安装步骤 + +1. 执行 SQL 文件创建数据库表: + ```bash + mysql -u root -p database_name < src/main/java/com/gxwebsoft/app/sql/app_permission_request.sql + mysql -u root -p database_name < src/main/java/com/gxwebsoft/app/sql/app_repository.sql + ``` + +2. 重启后端服务 + +3. 访问前端页面 `/developer/requests` 进行测试 diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_api_key.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_api_key.sql new file mode 100644 index 0000000..c0022f1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_api_key.sql @@ -0,0 +1,28 @@ +-- ============================================= +-- 开发者 API Key 表 +-- @author 科技小王子 +-- @since 2026-04-02 +-- ============================================= + +CREATE TABLE IF NOT EXISTS `app_api_key` ( + `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `name` VARCHAR(100) NOT NULL COMMENT 'API Key名称', + `api_key` VARCHAR(255) NOT NULL COMMENT 'API Key密钥值(加密存储)', + `key_prefix` VARCHAR(20) NOT NULL COMMENT '密钥前缀(用于显示,如 sk-xxxxx)', + `status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '状态: 0正常, 1禁用', + `scopes` TEXT COMMENT '权限范围,JSON数组字符串', + `expire_time` DATETIME DEFAULT NULL COMMENT '到期时间,NULL=永不过期', + `last_used_at` DATETIME DEFAULT NULL COMMENT '最后使用时间', + `usage_count` BIGINT DEFAULT 0 COMMENT '使用次数', + `remark` VARCHAR(500) DEFAULT NULL COMMENT '备注', + `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除, 0否, 1是', + `user_id` INT NOT NULL COMMENT '用户ID', + `tenant_id` INT NOT NULL COMMENT '租户ID', + `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_tenant_id` (`tenant_id`), + KEY `idx_status` (`status`), + KEY `idx_deleted` (`deleted`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='开发者API密钥表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_article.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_article.sql new file mode 100644 index 0000000..c78dde1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_article.sql @@ -0,0 +1,38 @@ +-- ============================================= +-- 平台文章表 - SQL 建表脚本 +-- 数据库: db_websopy +-- ============================================= + +DROP TABLE IF EXISTS app_article; + +CREATE TABLE app_article ( + article_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '文章ID', + title VARCHAR(200) NOT NULL COMMENT '文章标题', + type TINYINT DEFAULT 0 COMMENT '文章类型 0常规 1视频', + model VARCHAR(40) DEFAULT 'article' COMMENT '文章模型 article 普通文章 announcement 公告', + code VARCHAR(80) DEFAULT NULL COMMENT '文章编号', + category_id INT DEFAULT NULL COMMENT '分类ID', + image VARCHAR(500) DEFAULT NULL COMMENT '封面图', + source VARCHAR(120) DEFAULT NULL COMMENT '来源', + overview VARCHAR(500) DEFAULT NULL COMMENT '摘要', + content LONGTEXT COMMENT '正文内容', + actual_views INT DEFAULT 0 COMMENT '实际阅读量', + likes INT DEFAULT 0 COMMENT '点赞数', + user_id INT DEFAULT NULL COMMENT '创建用户ID', + author VARCHAR(80) DEFAULT NULL COMMENT '作者', + recommend TINYINT DEFAULT 0 COMMENT '是否推荐 0否 1是', + sort_number INT DEFAULT 0 COMMENT '排序值', + status TINYINT DEFAULT 1 COMMENT '状态 0已发布 1草稿/待审核 2已驳回 3违规', + deleted TINYINT DEFAULT 0 COMMENT '是否删除 0否 1是', + tenant_id INT DEFAULT NULL COMMENT '租户ID', + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + UNIQUE KEY uk_code (code), + KEY idx_model (model), + KEY idx_category_id (category_id), + KEY idx_status (status), + KEY idx_recommend (recommend), + KEY idx_sort_number (sort_number), + KEY idx_tenant_id (tenant_id), + KEY idx_create_time (create_time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台文章表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_article_category.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_article_category.sql new file mode 100644 index 0000000..f4f4c9c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_article_category.sql @@ -0,0 +1,32 @@ +-- ============================================= +-- 平台文章分类表 - SQL 建表脚本 +-- 数据库: db_websopy +-- ============================================= + +DROP TABLE IF EXISTS app_article_category; + +CREATE TABLE app_article_category ( + category_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '分类ID', + category_code VARCHAR(60) DEFAULT NULL COMMENT '分类标识', + title VARCHAR(80) NOT NULL COMMENT '分类名称', + type TINYINT DEFAULT 0 COMMENT '类型 0列表 1单页 2外链', + image VARCHAR(500) DEFAULT NULL COMMENT '分类图片', + parent_id INT DEFAULT 0 COMMENT '上级分类ID', + path VARCHAR(255) DEFAULT NULL COMMENT '访问路径', + user_id INT DEFAULT NULL COMMENT '创建用户ID', + sort_number INT DEFAULT 0 COMMENT '排序值', + comments VARCHAR(255) DEFAULT NULL COMMENT '备注', + hide TINYINT DEFAULT 0 COMMENT '是否隐藏 0否 1是', + recommend TINYINT DEFAULT 0 COMMENT '是否推荐 0否 1是', + show_index TINYINT DEFAULT 0 COMMENT '是否首页显示 0否 1是', + status TINYINT DEFAULT 0 COMMENT '状态 0正常 1禁用', + deleted TINYINT DEFAULT 0 COMMENT '是否删除 0否 1是', + tenant_id INT DEFAULT NULL COMMENT '租户ID', + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + UNIQUE KEY uk_tenant_category_code (tenant_id, category_code), + KEY idx_parent_id (parent_id), + KEY idx_status (status), + KEY idx_sort_number (sort_number), + KEY idx_tenant_id (tenant_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台文章分类表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_build.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_build.sql new file mode 100644 index 0000000..24ac5f5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_build.sql @@ -0,0 +1,40 @@ +-- ============================================= +-- CI/CD 构建记录表 +-- ============================================= +CREATE TABLE IF NOT EXISTS `app_build` ( + `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `app_id` BIGINT NOT NULL COMMENT '关联应用ID', + `version_id` BIGINT DEFAULT NULL COMMENT '关联版本ID(可选)', + `build_number` VARCHAR(100) DEFAULT NULL COMMENT '构建编号(如 run-123)', + `name` VARCHAR(200) DEFAULT NULL COMMENT '构建名称', + `branch` VARCHAR(100) DEFAULT NULL COMMENT '触发分支(如 main、develop)', + `commit_sha` VARCHAR(100) DEFAULT NULL COMMENT '提交哈希', + `commit_message` TEXT DEFAULT NULL COMMENT '提交消息', + `commit_author` VARCHAR(100) DEFAULT NULL COMMENT '提交作者', + `ci_type` VARCHAR(20) DEFAULT 'gitea' COMMENT 'CI系统类型: gitea/jenkins/github', + `ci_job_id` VARCHAR(100) DEFAULT NULL COMMENT 'CI系统中的任务ID', + `ci_run_id` VARCHAR(100) DEFAULT NULL COMMENT 'CI系统中的运行ID', + `ci_api_url` VARCHAR(500) DEFAULT NULL COMMENT 'CI系统API地址', + `status` VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/running/success/failed/cancelled', + `started_at` DATETIME DEFAULT NULL COMMENT '构建开始时间', + `finished_at` DATETIME DEFAULT NULL COMMENT '构建结束时间', + `duration` INT DEFAULT NULL COMMENT '构建耗时(秒)', + `log_url` VARCHAR(500) DEFAULT NULL COMMENT '构建日志URL', + `artifact_url` VARCHAR(500) DEFAULT NULL COMMENT '构建产物URL', + `artifact_name` VARCHAR(200) DEFAULT NULL COMMENT '构建产物名称', + `artifact_size` BIGINT DEFAULT NULL COMMENT '构建产物大小(字节)', + `error_message` TEXT DEFAULT NULL COMMENT '失败原因', + `trigger_type` VARCHAR(20) DEFAULT 'manual' COMMENT '触发方式: manual/webhook/schedule', + `triggered_by` INT DEFAULT NULL COMMENT '触发人用户ID', + `config` TEXT DEFAULT NULL COMMENT '扩展配置(JSON)', + `user_id` INT DEFAULT NULL COMMENT '用户ID', + `tenant_id` INT DEFAULT NULL COMMENT '租户id', + `deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除标记', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_app_id` (`app_id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_status` (`status`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CI/CD构建记录表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_cloud_credential.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_cloud_credential.sql new file mode 100644 index 0000000..37495f6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_cloud_credential.sql @@ -0,0 +1,23 @@ +-- 云账号凭证表 +-- 用于存储用户的阿里云/腾讯云/华为云/七牛云等云账号凭证 +-- @author 科技小王子 +-- @since 2026-04-04 + +CREATE TABLE `app_cloud_credential` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `provider` varchar(20) NOT NULL COMMENT '云服务商: aliyun/tencent/huawei/qiniu', + `name` varchar(50) NOT NULL COMMENT '凭证名称', + `access_key_id` varchar(100) DEFAULT NULL COMMENT '访问密钥ID(AK)', + `access_key_secret` varchar(200) DEFAULT NULL COMMENT '访问密钥密钥(SK),AES加密存储', + `config_json` text COMMENT '额外配置,JSON格式', + `status` tinyint NOT NULL DEFAULT '0' COMMENT '状态: 0正常 1冻结', + `remark` varchar(200) DEFAULT NULL COMMENT '备注', + `user_id` int NOT NULL COMMENT '所属用户ID', + `tenant_id` int DEFAULT NULL COMMENT '租户ID', + `deleted` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除: 0否 1是', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_provider_user` (`provider`, `user_id`), + KEY `idx_tenant_id` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='云账号凭证'; \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_cloud_credential_add_test_fields.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_cloud_credential_add_test_fields.sql new file mode 100644 index 0000000..0060879 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_cloud_credential_add_test_fields.sql @@ -0,0 +1,10 @@ +-- 云账号凭证表添加测试状态字段 +-- @since 2026-04-05 + +-- 添加 test_status 字段(默认 0: 未测试) +ALTER TABLE `app_cloud_credential` +ADD COLUMN `test_status` tinyint DEFAULT 0 COMMENT '测试状态: 0未测试 1成功 2失败'; + +-- 添加 test_message 字段 +ALTER TABLE `app_cloud_credential` +ADD COLUMN `test_message` varchar(500) DEFAULT NULL COMMENT '测试消息'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_contract.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_contract.sql new file mode 100644 index 0000000..a3939cd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_contract.sql @@ -0,0 +1,34 @@ +-- ---------------------------- +-- 合同管理表 +-- 用户在控制台查看和管理合同文件 +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `app_contract` ( + `contract_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '合同ID', + `contract_no` VARCHAR(50) NOT NULL COMMENT '合同编号(HT-yyyyMMdd-XXXX)', + `title` VARCHAR(200) NOT NULL COMMENT '合同名称', + `contract_type` VARCHAR(20) NOT NULL DEFAULT 'service' COMMENT '合同类型: service/cooperation/purchase/other', + `party_a` VARCHAR(100) DEFAULT NULL COMMENT '甲方名称', + `party_b` VARCHAR(100) DEFAULT NULL COMMENT '乙方名称', + `amount` DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT '合同金额', + `start_date` DATE DEFAULT NULL COMMENT '合同开始日期', + `end_date` DATE DEFAULT NULL COMMENT '合同结束日期', + `status` VARCHAR(20) NOT NULL DEFAULT 'draft' COMMENT '状态: draft/pending/active/expired/terminated', + `file_url` VARCHAR(500) DEFAULT NULL COMMENT '合同附件URL', + `file_name` VARCHAR(200) DEFAULT NULL COMMENT '合同附件原始文件名', + `remark` VARCHAR(500) DEFAULT NULL COMMENT '备注', + `user_id` INT NOT NULL COMMENT '创建用户ID', + `user_name` VARCHAR(50) DEFAULT NULL COMMENT '创建用户名(冗余)', + `deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除: 0否 1是', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `tenant_id` INT DEFAULT NULL COMMENT '租户ID', + + PRIMARY KEY (`contract_id`), + UNIQUE KEY `uk_contract_no` (`contract_no`), + KEY `idx_user_id` (`user_id`), + KEY `idx_status` (`status`), + KEY `idx_contract_type` (`contract_type`), + KEY `idx_tenant_id` (`tenant_id`), + KEY `idx_deleted` (`deleted`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='合同管理表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_git_account.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_git_account.sql new file mode 100644 index 0000000..b22307a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_git_account.sql @@ -0,0 +1,21 @@ +-- ---------------------------- +-- Git账号绑定表(开发者Gitea账号) +-- ---------------------------- +DROP TABLE IF EXISTS `app_git_account`; +CREATE TABLE `app_git_account` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `user_id` bigint NOT NULL COMMENT '用户ID', + `tenant_id` int NOT NULL COMMENT '租户ID', + `username` varchar(50) NOT NULL COMMENT 'Gitea用户名(唯一)', + `email` varchar(100) DEFAULT NULL COMMENT '联系邮箱', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `status` varchar(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending待审核/verified已通过/rejected已拒绝', + `verification_note` varchar(500) DEFAULT NULL COMMENT '审核备注', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除, 0否, 1是', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_user_id` (`user_id`, `tenant_id`), + KEY `idx_username` (`username`), + KEY `idx_tenant_id` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Git账号绑定(开发者Gitea账号)'; \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_invite_permission.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_invite_permission.sql new file mode 100644 index 0000000..73b3464 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_invite_permission.sql @@ -0,0 +1,77 @@ +-- ============================================ +-- 应用成员邀请权限配置 +-- 在 gxwebsoft_core 数据库执行 +-- ============================================ + +-- 1. 添加菜单(如果还没有) +INSERT INTO `sys_menu` ( + `menu_name`, + `menu_type`, + `parent_id`, + `sort_number`, + `authority`, + `path`, + `component`, + `icon`, + `status`, + `create_time` +) SELECT + '邀请成员', + 3, + (SELECT menu_id FROM sys_menu WHERE authority = 'app:appUser' LIMIT 1), + 4, + 'app:appUser:invite', + NULL, + NULL, + NULL, + 0, + NOW() +WHERE NOT EXISTS ( + SELECT 1 FROM sys_menu WHERE authority = 'app:appUser:invite' +); + +-- 2. 给超级管理员角色分配权限 +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) +SELECT + 1, + menu_id +FROM `sys_menu` +WHERE `authority` = 'app:appUser:invite' + AND NOT EXISTS ( + SELECT 1 FROM `sys_role_menu` + WHERE `role_id` = 1 AND `menu_id` = ( + SELECT menu_id FROM sys_menu WHERE authority = 'app:appUser:invite' + ) + ); + +-- 3. 给开发者角色分配权限(假设角色ID为 2 或 3,根据实际情况调整) +-- 先查询开发者角色的ID +-- SELECT role_id FROM sys_role WHERE role_name LIKE '%开发者%' OR role_name LIKE '%developer%'; + +-- 如果开发者角色ID是 2: +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) +SELECT + 2, + menu_id +FROM `sys_menu` +WHERE `authority` = 'app:appUser:invite' + AND NOT EXISTS ( + SELECT 1 FROM `sys_role_menu` + WHERE `role_id` = 2 AND `menu_id` = ( + SELECT menu_id FROM sys_menu WHERE authority = 'app:appUser:invite' + ) + ); + +-- 如果开发者角色ID是 3: +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) +SELECT + 3, + menu_id +FROM `sys_menu` +WHERE `authority` = 'app:appUser:invite' + AND NOT EXISTS ( + SELECT 1 FROM `sys_role_menu` + WHERE `role_id` = 3 AND `menu_id` = ( + SELECT menu_id FROM sys_menu WHERE authority = 'app:appUser:invite' + ) + ); diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_invite_token.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_invite_token.sql new file mode 100644 index 0000000..b4b4e5f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_invite_token.sql @@ -0,0 +1,19 @@ +-- 应用邀请Token表 +CREATE TABLE IF NOT EXISTS `app_invite_token` ( + `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `token` VARCHAR(64) NOT NULL COMMENT '邀请token', + `app_id` INT NOT NULL COMMENT '应用ID', + `role` VARCHAR(20) NOT NULL COMMENT '邀请角色', + `inviter_id` INT NOT NULL COMMENT '邀请人ID', + `expire_time` DATETIME NOT NULL COMMENT '过期时间', + `status` TINYINT DEFAULT 0 COMMENT '状态:0-未使用,1-已使用', + `accept_user_id` INT DEFAULT NULL COMMENT '接受人ID', + `accept_time` DATETIME DEFAULT NULL COMMENT '接受时间', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_token` (`token`), + KEY `idx_app_id` (`app_id`), + KEY `idx_inviter_id` (`inviter_id`), + KEY `idx_expire_time` (`expire_time`), + KEY `idx_status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用邀请Token表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_notification.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_notification.sql new file mode 100644 index 0000000..89b0880 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_notification.sql @@ -0,0 +1,29 @@ +-- ---------------------------- +-- 站内消息通知表 +-- 支持工单、审核、系统、资源、权限、成员、账单等通知类型 +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `app_notification` ( + `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '通知ID', + `user_id` INT NOT NULL COMMENT '接收用户ID', + `type` VARCHAR(20) NOT NULL DEFAULT 'system' COMMENT '通知类型: ticket/review/system/resource/permission/member/payment', + `title` VARCHAR(200) NOT NULL COMMENT '通知标题', + `content` VARCHAR(500) DEFAULT NULL COMMENT '通知内容摘要', + `is_read` TINYINT NOT NULL DEFAULT 0 COMMENT '是否已读: 0未读 1已读', + `ref_id` BIGINT DEFAULT NULL COMMENT '关联业务ID(如工单ID、权限申请ID等)', + `ref_type` VARCHAR(30) DEFAULT NULL COMMENT '关联业务类型(如 ticket、permission_request 等)', + `link_url` VARCHAR(500) DEFAULT NULL COMMENT '跳转链接', + `sender_id` INT DEFAULT 0 COMMENT '发送者ID(系统通知为0)', + `sender_name` VARCHAR(50) DEFAULT NULL COMMENT '发送者名称', + `sender_avatar` VARCHAR(500) DEFAULT NULL COMMENT '发送者头像', + `tenant_id` INT DEFAULT NULL COMMENT '租户ID', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间(标记已读时间)', + + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_user_read` (`user_id`, `is_read`), + KEY `idx_type` (`type`), + KEY `idx_ref` (`ref_type`, `ref_id`), + KEY `idx_tenant_id` (`tenant_id`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站内消息通知表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_permission_request.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_permission_request.sql new file mode 100644 index 0000000..11fdca4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_permission_request.sql @@ -0,0 +1,23 @@ +-- 权限申请记录表(开发者Git仓库访问申请) +CREATE TABLE IF NOT EXISTS `app_permission_request` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `user_id` INT(11) NOT NULL COMMENT '用户ID', + `git_username` VARCHAR(100) DEFAULT NULL COMMENT 'Git用户名', + `repo` VARCHAR(255) NOT NULL COMMENT '申请仓库路径', + `repo_name` VARCHAR(255) DEFAULT NULL COMMENT '仓库名称', + `reason` TEXT COMMENT '申请理由', + `status` VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending待审核/approved已通过/rejected已拒绝', + `reject_reason` TEXT COMMENT '拒绝原因', + `reviewer_id` INT(11) DEFAULT NULL COMMENT '审核人用户ID', + `reviewer_name` VARCHAR(100) DEFAULT NULL COMMENT '审核人姓名', + `reviewed_at` DATETIME DEFAULT NULL COMMENT '审核时间', + `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除, 0否, 1是', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_repo` (`repo`), + KEY `idx_status` (`status`), + KEY `idx_create_time` (`create_time`), + KEY `idx_user_status` (`user_id`, `status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限申请记录表(开发者Git仓库访问申请)'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_pipeline.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_pipeline.sql new file mode 100644 index 0000000..0068ccc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_pipeline.sql @@ -0,0 +1,34 @@ +-- ============================================= +-- CI/CD 流水线配置表 +-- ============================================= +CREATE TABLE IF NOT EXISTS `app_pipeline` ( + `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `app_id` BIGINT NOT NULL COMMENT '关联应用ID', + `name` VARCHAR(200) NOT NULL COMMENT '流水线名称', + `description` TEXT DEFAULT NULL COMMENT '流水线描述', + `ci_type` VARCHAR(20) DEFAULT 'gitea' COMMENT 'CI系统类型: gitea/jenkins/github', + `repo_full_name` VARCHAR(200) DEFAULT NULL COMMENT 'Gitea仓库全称(如 gxwebsoft/my-app)', + `workflow_file` VARCHAR(100) DEFAULT 'build.yml' COMMENT 'Gitea工作流文件名', + `stages` VARCHAR(200) DEFAULT 'build,test,deploy' COMMENT '流水线阶段: build/test/deploy', + `env` VARCHAR(50) DEFAULT 'production' COMMENT '环境: development/staging/production', + `default_branch` VARCHAR(100) DEFAULT 'main' COMMENT '默认触发分支', + `enabled` TINYINT DEFAULT 1 COMMENT '是否启用', + `auto_deploy` TINYINT DEFAULT 0 COMMENT '自动部署', + `timeout` INT DEFAULT 3600 COMMENT '构建超时时间(秒)', + `config` TEXT DEFAULT NULL COMMENT '配置JSON(变量、环境等)', + `last_build_id` BIGINT DEFAULT NULL COMMENT '最近一次构建ID', + `last_build_status` VARCHAR(20) DEFAULT NULL COMMENT '最近构建状态', + `last_build_time` DATETIME DEFAULT NULL COMMENT '最近构建时间', + `success_count` INT DEFAULT 0 COMMENT '构建成功次数', + `failure_count` INT DEFAULT 0 COMMENT '构建失败次数', + `user_id` INT DEFAULT NULL COMMENT '用户ID', + `tenant_id` INT DEFAULT NULL COMMENT '租户id', + `deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除标记', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_app_id` (`app_id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_enabled` (`enabled`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CI/CD流水线配置表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_product.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_product.sql new file mode 100644 index 0000000..820ac4f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_product.sql @@ -0,0 +1,123 @@ +-- ============================================= +-- 应用产品主表 - SQL建表脚本 +-- 数据库: db_websopy +-- ============================================= + +-- 如果表已存在则删除 +DROP TABLE IF EXISTS app_product; + +-- 创建应用产品主表 +CREATE TABLE app_product ( + -- 核心字段 + product_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '应用ID', + product_name VARCHAR(100) NOT NULL COMMENT '应用名称', + product_code VARCHAR(50) UNIQUE COMMENT '应用标识(唯一)', + product_secret VARCHAR(100) COMMENT '应用密钥', + + -- 应用类型枚举 + app_type INT DEFAULT 10 COMMENT '应用类型: 10网站 20微信小程序 30抖音小程序 40百度小程序 50支付宝小程序 60Android 70iOS 80macOS 90Windows 100插件', + + -- 分类 + category_id INT COMMENT '分类ID', + industry_parent VARCHAR(50) COMMENT '行业类型(父级)', + industry_child VARCHAR(50) COMMENT '行业类型(子级)', + + -- 基础信息 + logo VARCHAR(500) COMMENT '应用Logo', + icon VARCHAR(500) COMMENT '应用图标', + qrcode VARCHAR(500) COMMENT '二维码', + screenshots TEXT COMMENT '应用截图(JSON数组)', + description VARCHAR(500) COMMENT '应用简介', + content TEXT COMMENT '详细说明', + keywords VARCHAR(200) COMMENT '关键词', + + -- 配置信息 + domain VARCHAR(255) COMMENT '域名', + prefix VARCHAR(50) COMMENT '域名前缀', + package_name VARCHAR(100) COMMENT '包名(AppID)', + admin_url VARCHAR(500) COMMENT '后台地址', + api_url VARCHAR(500) COMMENT 'API地址', + download_url VARCHAR(500) COMMENT '下载地址', + + -- 版本信息 + version VARCHAR(20) COMMENT '版本号', + edition VARCHAR(20) DEFAULT 'standard' COMMENT '版本: standard标准版 professional专业版 perpetual永久授权', + min_version VARCHAR(20) COMMENT '最低版本要求', + + -- 价格与交付 + price_type VARCHAR(20) DEFAULT 'free' COMMENT '定价: free免费 one_time一次性 subscription订阅', + price DECIMAL(10,2) DEFAULT 0 COMMENT '价格(元)', + line_price DECIMAL(10,2) COMMENT '划线价格', + renew_price DECIMAL(10,2) COMMENT '续费价格', + delivery_method INT COMMENT '交付方式: 1源码 2托管 3授权', + charging_method INT COMMENT '计费方式: 1按年 2按月 3一次性', + subscription_period VARCHAR(20) COMMENT '订阅周期: month/year', + + -- 发布管理 + publish_status VARCHAR(20) DEFAULT 'developing' COMMENT '发布状态: developing开发中 pending_review待审核 published已上架 rejected审核未通过 deprecated已下架', + publish_time DATETIME COMMENT '发布时间', + review_time DATETIME COMMENT '审核时间', + reviewer_id INT COMMENT '审核人ID', + reject_reason VARCHAR(500) COMMENT '拒绝原因', + + -- 统计数据 + clicks INT DEFAULT 0 COMMENT '浏览次数', + installs INT DEFAULT 0 COMMENT '安装次数', + downloads INT DEFAULT 0 COMMENT '下载次数', + rating DECIMAL(2,1) DEFAULT 0 COMMENT '评分(1-5)', + likes INT DEFAULT 0 COMMENT '点赞数', + + -- 开发者信息 + developer VARCHAR(100) COMMENT '开发者', + developer_phone VARCHAR(20) COMMENT '开发者电话', + developer_email VARCHAR(100) COMMENT '开发者邮箱', + + -- 运营配置 + recommend TINYINT DEFAULT 0 COMMENT '是否推荐: 0否 1是', + official TINYINT DEFAULT 0 COMMENT '是否官方: 0否 1是', + market TINYINT DEFAULT 1 COMMENT '是否上架市场: 0否 1是', + show_index TINYINT DEFAULT 0 COMMENT '是否显示首页: 0否 1是', + search_enabled TINYINT DEFAULT 1 COMMENT '是否可搜索: 0否 1是', + + -- 站点配置 + template_id INT COMMENT '模板ID', + style TEXT COMMENT '样式配置JSON', + config JSON COMMENT '扩展配置JSON', + theme_color VARCHAR(20) DEFAULT '#1890ff' COMMENT '主题色', + lang VARCHAR(20) DEFAULT 'zh-cn' COMMENT '语言', + + -- 备案信息 + icp_no VARCHAR(100) COMMENT 'ICP备案号', + police_no VARCHAR(100) COMMENT '公安备案号', + + -- 状态管理 + status INT DEFAULT 0 COMMENT '状态: 0未开通 1运行中 2维护中 3已关闭 4已欠费 5违规停机', + status_text VARCHAR(200) COMMENT '状态说明', + running INT DEFAULT 0 COMMENT '运行状态: 0停止 1运行中 2维护中', + expiration_time DATETIME COMMENT '到期时间', + + -- 系统字段 + sort_number INT DEFAULT 0 COMMENT '排序号', + deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0否 1是', + user_id INT COMMENT '创建用户ID', + tenant_id INT COMMENT '租户ID', + create_time DATETIME DEFAULT CURRENT_TIMESTAMP, + update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + INDEX idx_tenant (tenant_id), + INDEX idx_user (user_id), + INDEX idx_app_type (app_type), + INDEX idx_category (category_id), + INDEX idx_publish_status (publish_status), + INDEX idx_create_time (create_time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用产品主表'; + +-- ============================================= +-- 示例数据 +-- ============================================= + +-- 插入示例数据 +INSERT INTO app_product (product_name, product_code, app_type, description, developer, price_type, price, publish_status, market, user_id, tenant_id) VALUES +('示例企业官网', 'demo-website', 10, '专业的企业展示网站模板', '科技小王子', 'free', 0.00, 'published', 1, 1, 1), +('示例微信小程序', 'demo-miniprogram', 20, '微信小程序示例应用', '科技小王子', 'one_time', 299.00, 'published', 1, 1, 1), +('示例Android应用', 'demo-android', 60, 'Android原生应用', '科技小王子', 'subscription', 99.00, 'developing', 1, 1, 1); diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_repository.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_repository.sql new file mode 100644 index 0000000..2bd390b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_repository.sql @@ -0,0 +1,23 @@ +-- Git仓库表(可用仓库列表) +CREATE TABLE IF NOT EXISTS `app_repository` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `path` VARCHAR(255) NOT NULL COMMENT '仓库路径(如: owner/repo-name)', + `name` VARCHAR(255) NOT NULL COMMENT '仓库名称', + `description` TEXT COMMENT '仓库描述', + `access_level` VARCHAR(20) NOT NULL DEFAULT 'read' COMMENT '访问权限级别: read/write/admin', + `status` VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态: active/inactive', + `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否删除, 0否, 1是', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_path` (`path`), + KEY `idx_status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Git仓库表(可用仓库列表)'; + +-- 插入一些示例仓库数据 +INSERT INTO `app_repository` (`path`, `name`, `description`, `access_level`) VALUES +('websopy/core', 'Core Repository', '核心代码仓库', 'read'), +('websopy/frontend', 'Frontend Repository', '前端代码仓库', 'read'), +('websopy/backend', 'Backend Repository', '后端代码仓库', 'read'), +('websopy/docs', 'Documentation', '文档仓库', 'read'), +('websopy/tools', 'Development Tools', '开发工具仓库', 'read'); diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_credential_id.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_credential_id.sql new file mode 100644 index 0000000..760e2e8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_credential_id.sql @@ -0,0 +1,8 @@ +-- 为 app_resource 表添加云账号凭证关联字段 +-- 用于云存储关联云账号凭证 +-- @author 科技小王子 +-- @since 2026-04-04 + +ALTER TABLE `app_resource` +ADD COLUMN `credential_id` bigint DEFAULT NULL COMMENT '云账号凭证ID(云存储用,关联app_cloud_credential)' +AFTER `region`; \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_git_fields.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_git_fields.sql new file mode 100644 index 0000000..7f846f5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_git_fields.sql @@ -0,0 +1,40 @@ +-- ===================================================== +-- Git仓库资源扩展:为 app_resource 表添加 Git 相关字段 +-- resourceType = 'git' 时使用 +-- MySQL 5.7+ 兼容版本(不支持 IF NOT EXISTS,需逐列添加) +-- ===================================================== + +-- 如果字段已存在会报错,可忽略错误继续执行 +-- 建议逐条执行,或使用 DBA 工具执行 + +-- 1. git_path - Git仓库路径 +ALTER TABLE `app_resource` + ADD COLUMN `git_path` VARCHAR(255) COMMENT 'Git仓库路径(如: websopy/core)' AFTER `cert_chain`; + +-- 2. git_clone_url - Git Clone URL +ALTER TABLE `app_resource` + ADD COLUMN `git_clone_url` VARCHAR(500) COMMENT 'Git Clone URL' AFTER `git_path`; + +-- 3. git_web_url - Git Web访问URL +ALTER TABLE `app_resource` + ADD COLUMN `git_web_url` VARCHAR(500) COMMENT 'Git Web访问URL(Gitea页面地址)' AFTER `git_clone_url`; + +-- 4. git_access_level - Git权限级别 +ALTER TABLE `app_resource` + ADD COLUMN `git_access_level` VARCHAR(20) DEFAULT 'read' COMMENT 'Git权限级别: read/write/admin' AFTER `git_web_url`; + +-- ===================================================== +-- 初始化示例数据(可选,根据实际情况调整) +-- 以下示例展示如何为已有应用创建 Git 仓库资源记录 +-- ===================================================== + +-- 示例:为应用创建一个 Git 仓库资源记录 +-- INSERT INTO `app_resource` ( +-- `resource_type`, `name`, `app_id`, `git_path`, `git_clone_url`, `git_web_url`, +-- `git_access_level`, `status`, `user_id`, `owner_user_id`, `tenant_id` +-- ) VALUES ( +-- 'git', 'Core Repository', 1, 'websopy/core', +-- 'https://git.websoft.top/websopy/core.git', +-- 'https://git.websoft.top/websopy/core', +-- 'read', 'running', 1, 1, 10398 +-- ); diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_panel_fields.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_panel_fields.sql new file mode 100644 index 0000000..a809787 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_panel_fields.sql @@ -0,0 +1,17 @@ +-- 为 app_resource 表添加 1Panel 用户名字段 +-- 添加时间: 2026-04-05 + +-- 添加 panelUsername 字段(1Panel 面板用户名) +ALTER TABLE app_resource +ADD COLUMN IF NOT EXISTS panel_username VARCHAR(100) COMMENT '1Panel面板用户名(服务器用)' +AFTER panel_port; + +-- 添加 panelPassword 字段(1Panel 面板密码,AES加密存储) +ALTER TABLE app_resource +ADD COLUMN IF NOT EXISTS panel_password VARCHAR(500) COMMENT '1Panel面板密码(AES加密,服务器用)' +AFTER panel_username; + +-- 注意:如果 ALTER TABLE 不支持 IF NOT EXISTS 语法(MySQL 5.7) +-- 请手动执行以下语句: +-- ALTER TABLE app_resource ADD COLUMN panel_username VARCHAR(100) COMMENT '1Panel面板用户名(服务器用)' AFTER panel_port; +-- ALTER TABLE app_resource ADD COLUMN panel_password VARCHAR(500) COMMENT '1Panel面板密码(AES加密,服务器用)' AFTER panel_username; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_ssl_fields.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_ssl_fields.sql new file mode 100644 index 0000000..541409b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_ssl_fields.sql @@ -0,0 +1,71 @@ +-- 为 app_resource 表添加 SSL 证书相关字段 +-- @author 科技小王子 +-- @since 2026-04-05 + +/** + * SSL 证书需要的字段: + * - private_key:私钥内容(AES加密存储) + * - public_key:公钥内容(从证书提取) + * - certificate:完整的证书文件内容(包含BEGIN/END标记) + * - cert_chain:证书链/中间证书内容 + * - algorithm:加密算法(RSA/ECC) + * - key_bits:密钥长度(2048/4096/256等) + */ + +-- 检查表结构,如果字段不存在则添加 +-- 使用 IF NOT EXISTS 防止重复执行 + +-- 1. 添加私钥字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `private_key` longtext DEFAULT NULL COMMENT '私钥内容(AES加密存储,SSL用)' +AFTER `issuer`; + +-- 2. 添加公钥字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `public_key` longtext DEFAULT NULL COMMENT '公钥内容(从证书提取,SSL用)' +AFTER `private_key`; + +-- 3. 添加证书内容字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `certificate` longtext DEFAULT NULL COMMENT '证书内容/证书文件(SSL用)' +AFTER `public_key`; + +-- 4. 添加证书链字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `cert_chain` longtext DEFAULT NULL COMMENT '证书链/中间证书(SSL用)' +AFTER `certificate`; + + + +-- 如果需要,可以创建一个视图来显示 SSL 证书信息 +CREATE OR REPLACE VIEW `app_ssl_certificate_view` AS +SELECT + resource_id, + name, + domain, + cert_type, + issuer, + status, + expire_at, + app_id, + create_time, + update_time, + -- 安全考虑,不显示私钥内容 + CASE WHEN certificate IS NOT NULL THEN LENGTH(certificate) ELSE 0 END as cert_length, + CASE WHEN cert_chain IS NOT NULL THEN LENGTH(cert_chain) ELSE 0 END as chain_length, + -- 判断证书是否有效(逻辑示例,实际需要更复杂的检查) + CASE + WHEN expire_at >= CURDATE() THEN 'valid' + WHEN expire_at < CURDATE() THEN 'expired' + ELSE 'unknown' + END as validity_status, + -- 剩余天数 + DATEDIFF(expire_at, CURDATE()) as days_remaining +FROM app_resource +WHERE resource_type = 'ssl' AND deleted = 0; + +-- 说明: +-- 1. longtext 字段可以存储最多 4GB 的文本,足够存储证书和密钥 +-- 2. 私钥字段会在前端和后端进行 AES 加密处理 +-- 3. 视图提供了安全的 SSL 证书查询接口,不暴露私钥等敏感信息 +-- 4. 可以根据需要添加证书解析函数(如从证书中提取有效期、域名等) \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_used_bytes.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_used_bytes.sql new file mode 100644 index 0000000..6f23050 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_used_bytes.sql @@ -0,0 +1,8 @@ +-- 为 app_resource 表添加 used_bytes 字段 +-- 用于云存储记录已用空间(字节) +-- @author 科技小王子 +-- @since 2026-04-06 + +ALTER TABLE `app_resource` +ADD COLUMN `used_bytes` bigint DEFAULT NULL COMMENT '已用空间(字节,云存储用)' +AFTER `acl`; \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_used_count.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_used_count.sql new file mode 100644 index 0000000..28dca22 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_add_used_count.sql @@ -0,0 +1,8 @@ +-- 为 app_resource 表添加 used_count 字段 +-- 用于云存储记录对象数量 +-- @author 科技小王子 +-- @since 2026-04-06 + +ALTER TABLE `app_resource` +ADD COLUMN `used_count` int DEFAULT NULL COMMENT '对象数量(云存储用)' +AFTER `used_bytes`; \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_collab_permission.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_collab_permission.sql new file mode 100644 index 0000000..db4c096 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_resource_collab_permission.sql @@ -0,0 +1,27 @@ +-- ===================================================================== +-- 资源中心协作权限迁移脚本 +-- 版本: 2026-04-05 +-- 说明: 为 app_resource 表添加 owner_user_id 字段,支持资源协作权限分级 +-- ===================================================================== + +-- 1. 添加 owner_user_id 字段(记录资源真实创建者,区别于 user_id 代理关系) +ALTER TABLE app_resource + ADD COLUMN owner_user_id BIGINT NULL + COMMENT '资源创建者 userId(创建时自动设置,是权限控制的基准)' + AFTER user_id; + +-- 2. 历史数据修复:将现有记录的 owner_user_id 设置为 user_id +UPDATE app_resource +SET owner_user_id = user_id +WHERE owner_user_id IS NULL; + +-- 3. 创建索引 +CREATE INDEX idx_resource_owner ON app_resource (owner_user_id); + +-- ===================================================================== +-- 权限级别说明(由后端代码计算,不存储到数据库) +-- 0: 无权限 - 不是应用成员 +-- 1: 基础查看 - 可看名称、IP、端口、状态(所有团队成员默认) +-- 2: 连接查看 - 可看用户名、Host(技术负责人 admin/owner 角色) +-- 3: 完全权限 - 可看密码/私钥、可编辑删除(资源 ownerUserId 本人) +-- ===================================================================== diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_setting.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_setting.sql new file mode 100644 index 0000000..58cabfa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_setting.sql @@ -0,0 +1,53 @@ +-- ============================================ +-- 平台设置表 app_setting +-- ============================================ + +-- 创建表 +CREATE TABLE IF NOT EXISTS `app_setting` ( + `setting_id` INT NOT NULL AUTO_INCREMENT COMMENT '设置ID', + `category` VARCHAR(50) NOT NULL DEFAULT 'basic' COMMENT '设置分类:basic/review/market/register/notify/maintenance', + `setting_key` VARCHAR(100) NOT NULL COMMENT '设置项标识', + `setting_name` VARCHAR(200) DEFAULT NULL COMMENT '设置项名称', + `setting_value` TEXT COMMENT '设置值(JSON格式)', + `value_type` VARCHAR(20) NOT NULL DEFAULT 'json' COMMENT '设置类型:string/number/boolean/json', + `description` VARCHAR(500) DEFAULT NULL COMMENT '设置说明', + `sort_number` INT NOT NULL DEFAULT 0 COMMENT '排序号', + `is_enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用 0否 1是', + `is_public` TINYINT NOT NULL DEFAULT 0 COMMENT '是否公开(前端可读)0否 1是', + `tenant_id` BIGINT DEFAULT NULL COMMENT '租户id', + `created_time` BIGINT DEFAULT NULL COMMENT '创建时间', + `updated_time` BIGINT DEFAULT NULL COMMENT '更新时间', + `deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除 0否 1是', + PRIMARY KEY (`setting_id`), + UNIQUE KEY `uk_setting_key` (`setting_key`, `tenant_id`), + KEY `idx_category` (`category`), + KEY `idx_tenant_id` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='平台设置表'; + +-- ============================================ +-- 初始化默认配置数据 +-- ============================================ + +-- 基础配置 +INSERT INTO `app_setting` (`category`, `setting_key`, `setting_name`, `setting_value`, `value_type`, `description`, `sort_number`, `is_enabled`, `is_public`) VALUES +('basic', 'platform_basic', '基础配置', '{"siteName":"","domain":"","description":"","supportEmail":"","supportPhone":"","icpNo":""}', 'json', '平台基础信息配置', 1, 1, 0); + +-- 审核配置 +INSERT INTO `app_setting` (`category`, `setting_key`, `setting_name`, `setting_value`, `value_type`, `description`, `sort_number`, `is_enabled`, `is_public`) VALUES +('review', 'platform_review', '审核配置', '{"autoReview":false,"reviewEmail":"","defaultRejectReason":"","maxWaitDays":7}', 'json', '应用审核相关配置', 2, 1, 0); + +-- 市场配置 +INSERT INTO `app_setting` (`category`, `setting_key`, `setting_name`, `setting_value`, `value_type`, `description`, `sort_number`, `is_enabled`, `is_public`) VALUES +('market', 'platform_market', '市场配置', '{"enableMarket":true,"allowThirdParty":true,"commissionRate":10,"pageSize":12}', 'json', '应用市场相关配置', 3, 1, 0); + +-- 注册配置 +INSERT INTO `app_setting` (`category`, `setting_key`, `setting_name`, `setting_value`, `value_type`, `description`, `sort_number`, `is_enabled`, `is_public`) VALUES +('register', 'platform_register', '注册登录配置', '{"enableRegister":true,"emailVerify":false,"phoneVerify":true,"oauthProviders":["wechat"],"defaultRole":"user"}', 'json', '用户注册登录相关配置', 4, 1, 0); + +-- 通知配置 +INSERT INTO `app_setting` (`category`, `setting_key`, `setting_name`, `setting_value`, `value_type`, `description`, `sort_number`, `is_enabled`, `is_public`) VALUES +('notify', 'platform_notify', '通知配置', '{"ticketEmail":true,"ticketSms":false,"ticketWechat":false,"reviewEmail":true,"reviewSms":false,"announcePush":true}', 'json', '消息通知相关配置', 5, 1, 0); + +-- 维护模式配置 +INSERT INTO `app_setting` (`category`, `setting_key`, `setting_name`, `setting_value`, `value_type`, `description`, `sort_number`, `is_enabled`, `is_public`) VALUES +('maintenance', 'platform_maintenance', '维护模式', '{"enabled":false,"message":"系统维护中,请稍后再访问","allowedIps":[],"allowedUsers":[],"startTime":null,"endTime":null}', 'json', '维护模式配置', 6, 1, 0); diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_ticket.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_ticket.sql new file mode 100644 index 0000000..3ce229b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_ticket.sql @@ -0,0 +1,40 @@ +-- ---------------------------- +-- 应用工单表 +-- 以应用为维度的工单系统,客户提交 → 自动分配技术人员 → 处理 → 回复 +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `app_ticket` ( + `ticket_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '工单ID', + `ticket_no` VARCHAR(30) NOT NULL COMMENT '工单编号(TK-yyyyMMddHHmmss+4位随机)', + `title` VARCHAR(200) NOT NULL COMMENT '工单标题', + `content` TEXT DEFAULT NULL COMMENT '工单内容描述', + `app_id` BIGINT NOT NULL COMMENT '关联应用ID', + `app_name` VARCHAR(100) DEFAULT NULL COMMENT '应用名称(冗余)', + `category` VARCHAR(20) NOT NULL DEFAULT 'consultation' COMMENT '工单分类: bug/feature/consultation/complaint/other', + `priority` VARCHAR(10) NOT NULL DEFAULT 'normal' COMMENT '优先级: low/normal/high/urgent', + `status` VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/assigned/processing/resolved/closed/rejected', + `attachments` VARCHAR(2000) DEFAULT NULL COMMENT '附件JSON数组(最多5个文件URL)', + `submit_user_id` INT NOT NULL COMMENT '提交人用户ID', + `submit_user_name` VARCHAR(50) DEFAULT NULL COMMENT '提交人昵称(冗余)', + `submit_user_avatar` VARCHAR(500) DEFAULT NULL COMMENT '提交人头像(冗余)', + `assignee_id` INT DEFAULT NULL COMMENT '分配的处理人用户ID', + `assignee_name` VARCHAR(50) DEFAULT NULL COMMENT '处理人昵称(冗余)', + `assignee_avatar` VARCHAR(500) DEFAULT NULL COMMENT '处理人头像(冗余)', + `reply_count` INT DEFAULT 0 COMMENT '回复数量', + `resolved_time` DATETIME DEFAULT NULL COMMENT '解决时间', + `closed_time` DATETIME DEFAULT NULL COMMENT '关闭时间', + `deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除: 0否 1是', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `tenant_id` INT DEFAULT NULL COMMENT '租户ID', + + PRIMARY KEY (`ticket_id`), + UNIQUE KEY `uk_ticket_no` (`ticket_no`), + KEY `idx_app_id` (`app_id`), + KEY `idx_submit_user_id` (`submit_user_id`), + KEY `idx_assignee_id` (`assignee_id`), + KEY `idx_status` (`status`), + KEY `idx_category` (`category`), + KEY `idx_tenant_id` (`tenant_id`), + KEY `idx_deleted` (`deleted`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用工单表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_ticket_alter.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_ticket_alter.sql new file mode 100644 index 0000000..002c7bf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_ticket_alter.sql @@ -0,0 +1,33 @@ +-- ---------------------------- +-- 应用工单表字段补丁(如果表已存在但缺少字段) +-- ---------------------------- + +-- 添加 app_id 字段(如果不存在) +SET @exist := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = 'app_ticket' + AND column_name = 'app_id'); +SET @sql := IF(@exist = 0, 'ALTER TABLE `app_ticket` ADD COLUMN `app_id` BIGINT NOT NULL COMMENT "关联应用ID" AFTER `content`', 'SELECT "app_id already exists"'); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 添加 app_name 字段(如果不存在) +SET @exist := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = 'app_ticket' + AND column_name = 'app_name'); +SET @sql := IF(@exist = 0, 'ALTER TABLE `app_ticket` ADD COLUMN `app_name` VARCHAR(100) DEFAULT NULL COMMENT "应用名称(冗余)" AFTER `app_id`', 'SELECT "app_name already exists"'); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 添加索引(如果不存在) +SET @exist := (SELECT COUNT(*) FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'app_ticket' + AND index_name = 'idx_app_id'); +SET @sql := IF(@exist = 0, 'ALTER TABLE `app_ticket` ADD INDEX `idx_app_id` (`app_id`)', 'SELECT "idx_app_id already exists"'); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_user_add_invite_status.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_user_add_invite_status.sql new file mode 100644 index 0000000..1f2a85d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_user_add_invite_status.sql @@ -0,0 +1,17 @@ +-- 应用成员邀请状态字段添加 +-- 用于实现邀请确认机制 + +-- 添加 invite_status 字段 +ALTER TABLE `app_user` +ADD COLUMN `invite_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '邀请状态: 0-正常(直接加入), 1-待确认, 2-已拒绝' AFTER `status`; + +-- 添加邀请过期时间字段(可选,用于实现邀请有效期) +ALTER TABLE `app_user` +ADD COLUMN `invite_expire_time` datetime DEFAULT NULL COMMENT '邀请过期时间' AFTER `invite_time`; + +-- 创建索引优化查询 +CREATE INDEX `idx_invite_status` ON `app_user` (`invite_status`); +CREATE INDEX `idx_user_id_invite_status` ON `app_user` (`user_id`, `invite_status`); + +-- 数据迁移:将现有数据标记为已确认(直接加入) +-- UPDATE app_user SET invite_status = 0 WHERE invite_status IS NULL; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_user_cache.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_user_cache.sql new file mode 100644 index 0000000..7a09e30 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/app_user_cache.sql @@ -0,0 +1,15 @@ +-- 用户信息缓存表 +-- 用于缓存 sys_user 的常用字段,方便 app 模块其他表关联查询用户信息 +-- 不存储密码等敏感信息 + +CREATE TABLE `app_user_cache` ( + `user_id` int(11) NOT NULL COMMENT '用户ID(主键)', + `tenant_id` int(11) NOT NULL COMMENT '租户ID', + `username` varchar(50) DEFAULT NULL COMMENT '用户名', + `nickname` varchar(50) DEFAULT NULL COMMENT '昵称', + `avatar` varchar(255) DEFAULT NULL COMMENT '头像', + `phone` varchar(20) DEFAULT NULL COMMENT '手机号', + `status` tinyint(1) DEFAULT '0' COMMENT '状态, 0正常, 1冻结', + `update_time` datetime DEFAULT NULL COMMENT '缓存更新时间', + PRIMARY KEY (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息缓存表'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/check_cloud_credential.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/check_cloud_credential.sql new file mode 100644 index 0000000..be59d2c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/check_cloud_credential.sql @@ -0,0 +1,12 @@ +-- 检查 app_cloud_credential 表结构 +DESC app_cloud_credential; + +-- 检查是否有 test_status 和 test_message 字段 +SHOW COLUMNS FROM app_cloud_credential WHERE Field IN ('test_status', 'test_message'); + +-- 如果字段不存在,添加它们 +-- ALTER TABLE `app_cloud_credential` ADD COLUMN `test_status` tinyint DEFAULT 0 COMMENT '测试状态: 0未测试 1成功 2失败'; +-- ALTER TABLE `app_cloud_credential` ADD COLUMN `test_message` varchar(500) DEFAULT NULL COMMENT '测试消息'; + +-- 检查用户是否有数据 +SELECT id, provider, name, user_id, tenant_id, status, test_status FROM app_cloud_credential; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/fix_app_user_cache_tenant_id.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/fix_app_user_cache_tenant_id.sql new file mode 100644 index 0000000..7b1fd82 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/fix_app_user_cache_tenant_id.sql @@ -0,0 +1,40 @@ +-- ============================================ +-- 修复 app_user_cache 表 tenant_id 字段问题 +-- ============================================ + +-- 1. 检查并添加 tenant_id 字段(如果不存在) +SET @dbname = DATABASE(); +SET @tablename = 'app_user_cache'; +SET @columnname = 'tenant_id'; + +SET @sql = CONCAT( + 'SELECT COUNT(*) INTO @exists FROM information_schema.columns + WHERE table_schema = ''', @dbname, ''' + AND table_name = ''', @tablename, ''' + AND column_name = ''', @columnname, '''' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 如果字段不存在,添加它 +SET @addColumn = IF(@exists = 0, + 'ALTER TABLE app_user_cache ADD COLUMN tenant_id INT NOT NULL DEFAULT 0 COMMENT ''租户ID'' AFTER user_id', + 'SELECT ''tenant_id column already exists'' as message' +); +PREPARE stmt FROM @addColumn; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- 2. 如果字段已存在但允许 NULL,修改为 NOT NULL +-- 先为现有 NULL 值设置默认值 +UPDATE app_user_cache SET tenant_id = 0 WHERE tenant_id IS NULL; + +-- 3. 添加 NOT NULL 约束(如果还没有) +-- 注意:这需要根据实际数据情况执行 +-- ALTER TABLE app_user_cache MODIFY COLUMN tenant_id INT NOT NULL COMMENT '租户ID'; + +-- ============================================ +-- 验证表结构 +-- ============================================ +DESCRIBE app_user_cache; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/fix_tenant_id_constraint.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/fix_tenant_id_constraint.sql new file mode 100644 index 0000000..00345bf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/fix_tenant_id_constraint.sql @@ -0,0 +1,34 @@ +-- ============================================ +-- 修复 app_user 表 tenant_id 字段问题 +-- ============================================ + +-- 检查 app_user 表是否有 tenant_id 字段 +-- 如果没有,添加该字段 +-- 如果有但没有 NOT NULL 约束,添加约束 + +-- 1. 检查并添加 tenant_id 字段(如果不存在) +-- ALTER TABLE app_user ADD COLUMN tenant_id INT COMMENT '租户id' AFTER user_id; + +-- 2. 为现有数据设置 tenant_id(需要根据实际情况设置) +-- 假设通过 user_id 关联查询 sys_user 表获取 tenant_id +-- UPDATE app_user a +-- INNER JOIN sys_user u ON a.user_id = u.user_id +-- SET a.tenant_id = u.tenant_id +-- WHERE a.tenant_id IS NULL; + +-- 3. 添加 NOT NULL 约束(确保数据已填充) +-- ALTER TABLE app_user MODIFY COLUMN tenant_id INT NOT NULL COMMENT '租户id'; + +-- ============================================ +-- 修复 app_permission_request 表 tenant_id 字段问题 +-- ============================================ + +-- 检查 app_permission_request 表是否有 tenant_id 字段 +-- 如果没有,添加该字段 +-- ALTER TABLE app_permission_request ADD COLUMN tenant_id INT COMMENT '租户id' AFTER user_id; + +-- ============================================ +-- 验证表结构 +-- ============================================ +-- DESCRIBE app_user; +-- DESCRIBE app_permission_request; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/sql/sys_operation_record.sql b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/sys_operation_record.sql new file mode 100644 index 0000000..beccce2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/sql/sys_operation_record.sql @@ -0,0 +1,27 @@ +-- 操作日志表 +CREATE TABLE IF NOT EXISTS `sys_operation_record` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `user_id` int(11) DEFAULT NULL COMMENT '用户id', + `module` varchar(100) DEFAULT NULL COMMENT '操作模块', + `description` varchar(255) DEFAULT NULL COMMENT '操作功能', + `url` varchar(255) DEFAULT NULL COMMENT '请求地址', + `request_method` varchar(20) DEFAULT NULL COMMENT '请求方式', + `method` varchar(255) DEFAULT NULL COMMENT '调用方法', + `params` text COMMENT '请求参数', + `result` text COMMENT '返回结果', + `error` text COMMENT '异常信息', + `comments` varchar(500) DEFAULT NULL COMMENT '备注', + `spend_time` bigint(20) DEFAULT NULL COMMENT '消耗时间, 单位毫秒', + `os` varchar(100) DEFAULT NULL COMMENT '操作系统', + `device` varchar(100) DEFAULT NULL COMMENT '设备名称', + `browser` varchar(100) DEFAULT NULL COMMENT '浏览器类型', + `ip` varchar(50) DEFAULT NULL COMMENT 'ip地址', + `status` tinyint(1) DEFAULT '0' COMMENT '状态, 0成功, 1异常', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户id', + `create_time` datetime DEFAULT NULL COMMENT '操作时间', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_create_time` (`create_time`), + KEY `idx_module` (`module`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志'; diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/task/UserCacheRefreshTask.java b/jczxw-java/src/main/java/com/gxwebsoft/app/task/UserCacheRefreshTask.java new file mode 100644 index 0000000..18e86dc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/task/UserCacheRefreshTask.java @@ -0,0 +1,130 @@ +package com.gxwebsoft.app.task; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.app.entity.AppUser; +import com.gxwebsoft.app.entity.AppUserCache; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.app.service.AppUserService; +import com.gxwebsoft.common.system.entity.User; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 用户缓存刷新定时任务 + *

+ * 定时从 server API 获取最新用户信息并更新缓存 + * + * @author 科技小王子 + * @since 2026-04-03 + */ +@Slf4j +@Component +public class UserCacheRefreshTask { + + @Value("${config.server-url:https://server.websoft.top/api}") + private String serverUrl; + + @Autowired + private AppUserCacheService appUserCacheService; + + @Autowired + private AppUserService appUserService; + + /** + * 缓存待刷新的用户 ID 集合(去重) + */ + private final Set pendingRefreshUsers = ConcurrentHashMap.newKeySet(); + + /** + * 每天凌晨 2 点执行全量缓存刷新 + * 格式:秒 分 时 日 月 周 + */ + @Scheduled(cron = "0 0 2 * * ?") + public void fullCacheRefresh() { + log.info("【定时任务】开始全量刷新用户缓存..."); + try { + // 获取所有活跃的 app 成员用户 + List allUserIds = getAllActiveUserIds(); + if (CollUtil.isEmpty(allUserIds)) { + log.info("没有需要刷新的用户"); + return; + } + log.info("需要刷新的用户数量:{}", allUserIds.size()); + appUserCacheService.batchRefreshUserCache(allUserIds); + log.info("【定时任务】全量刷新用户缓存完成"); + } catch (Exception e) { + log.error("【定时任务】全量刷新用户缓存失败", e); + } + } + + /** + * 每小时执行一次增量刷新(刷新缓存过期的用户) + * 缓存超过 6 小时视为过期 + */ + @Scheduled(cron = "0 0 * * * ?") + public void incrementalCacheRefresh() { + log.info("【定时任务】开始增量刷新用户缓存..."); + try { + // 获取缓存中更新时间超过 6 小时的用户 + List expiredCaches = appUserCacheService.list( + new LambdaQueryWrapper() + .le(AppUserCache::getUpdateTime, LocalDateTime.now().minusHours(6)) + ); + if (CollUtil.isEmpty(expiredCaches)) { + log.info("没有过期的缓存需要刷新"); + return; + } + List userIds = expiredCaches.stream() + .map(AppUserCache::getUserId) + .toList(); + log.info("过期缓存用户数量:{}", userIds.size()); + appUserCacheService.batchRefreshUserCache(userIds); + log.info("【定时任务】增量刷新用户缓存完成"); + } catch (Exception e) { + log.error("【定时任务】增量刷新用户缓存失败", e); + } + } + + /** + * 添加待刷新的用户到队列 + * 业务层可以调用此方法标记用户需要刷新 + */ + public void markForRefresh(Integer userId) { + if (userId != null) { + pendingRefreshUsers.add(userId); + log.debug("用户已标记待刷新,userId={}", userId); + } + } + + /** + * 获取所有活跃的应用成员用户 ID + */ + private List getAllActiveUserIds() { + List members = appUserService.list( + new LambdaQueryWrapper() + .eq(AppUser::getStatus, 0) + .select(AppUser::getUserId) + ); + if (CollUtil.isEmpty(members)) { + return new ArrayList<>(); + } + return members.stream() + .map(AppUser::getUserId) + .distinct() + .toList(); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/app/utils/WxNativePayUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/app/utils/WxNativePayUtil.java new file mode 100644 index 0000000..06870e2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/app/utils/WxNativePayUtil.java @@ -0,0 +1,141 @@ +package com.gxwebsoft.app.utils; + +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAPublicKeyConfig; +import com.gxwebsoft.app.config.AppPayProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 微信支付配置工具类(按租户缓存 Config 实例) + * 参考 core 模块 WxNativeUtil,按 app 模块独立部署模式重新实现 + */ +@Slf4j +@Component +public class WxNativePayUtil { + + private static final Map TENANT_CONFIGS = new ConcurrentHashMap<>(); + + /** + * 获取/构建指定租户的微信支付 Config + */ + public Config getConfig(AppPayProperties props) { + // 暂不使用多租户配置,统一使用平台级配置 + Config cached = TENANT_CONFIGS.get(0); + if (cached != null) { + return cached; + } + + Config config = buildConfig(props); + TENANT_CONFIGS.put(0, config); + return config; + } + + private Config buildConfig(AppPayProperties props) { + String mchId; + String serialNo; + String apiV3Key; + boolean testMode = props.isTestMode(); + + if (testMode) { + // 测试模式 + mchId = props.getTestMchId() != null ? props.getTestMchId() : props.getMchId(); + serialNo = props.getTestMerchantSerialNumber() != null ? props.getTestMerchantSerialNumber() : props.getMerchantSerialNumber(); + apiV3Key = props.getTestApiV3Key() != null ? props.getTestApiV3Key() : props.getApiV3Key(); + log.info("微信支付使用测试模式 — 商户号: {}", mchId); + } else { + // 正式模式 + mchId = props.getMchId(); + serialNo = props.getMerchantSerialNumber(); + apiV3Key = props.getApiV3Key(); + log.info("微信支付使用正式模式 — 商户号: {}", mchId); + } + + String privateKeyPath = resolvePrivateKeyPath(props, testMode); + String wechatpayPublicKeyId = props.getWechatpayPublicKeyId(); + String wechatpayPublicKeyPath = resolvePublicKeyPath(props, testMode); + log.info("构建微信支付 Config — 商户号: {}, 序列号: {}, 私钥路径: {}, 公钥路径: {}, 公钥ID: {}", + mchId, serialNo, privateKeyPath, wechatpayPublicKeyPath, wechatpayPublicKeyId); + + // 使用微信支付公钥模式(RSAPublicKeyConfig) + // 必须提供本地公钥文件和公钥ID + RSAPublicKeyConfig.Builder builder = new RSAPublicKeyConfig.Builder() + .merchantId(mchId) + .privateKeyFromPath(privateKeyPath) + .merchantSerialNumber(serialNo) + .apiV3Key(apiV3Key) + .publicKeyFromPath(wechatpayPublicKeyPath) + .publicKeyId(wechatpayPublicKeyId); + + log.info("使用 RSA 公钥模式配置微信支付 — 公钥路径: {}, 公钥ID: {}", wechatpayPublicKeyPath, wechatpayPublicKeyId); + + return builder.build(); + } + + /** + * 解析私钥文件路径 + * 测试模式优先 classpath;生产模式优先挂载卷 + */ + private String resolvePrivateKeyPath(AppPayProperties props, boolean testMode) { + String certRelativePath = props.getPrivateKeyRelativePath(); + + if (testMode) { + // 测试模式:classpath + return resolveClasspathPath(certRelativePath); + } + + // 生产模式:优先挂载卷 + String certRootPath = props.getCertRootPath(); + if (certRootPath != null && !certRootPath.isEmpty()) { + Path fullPath = Paths.get(certRootPath, certRelativePath); + if (Files.exists(fullPath)) { + return fullPath.toAbsolutePath().toString(); + } + log.warn("挂载卷证书 {} 不存在,尝试 classpath 回退", fullPath); + } + + return resolveClasspathPath(certRelativePath); + } + + /** + * 解析微信支付公钥文件路径 + */ + private String resolvePublicKeyPath(AppPayProperties props, boolean testMode) { + String publicKeyRelativePath = props.getWechatpayCertRelativePath(); + + if (testMode) { + return resolveClasspathPath(publicKeyRelativePath); + } + + // 生产模式:优先挂载卷 + String certRootPath = props.getCertRootPath(); + if (certRootPath != null && !certRootPath.isEmpty()) { + Path fullPath = Paths.get(certRootPath, publicKeyRelativePath); + if (Files.exists(fullPath)) { + return fullPath.toAbsolutePath().toString(); + } + log.warn("挂载卷公钥文件 {} 不存在,尝试 classpath 回退", fullPath); + } + + return resolveClasspathPath(publicKeyRelativePath); + } + + private String resolveClasspathPath(String relativePath) { + try { + ClassPathResource resource = new ClassPathResource(relativePath); + if (resource.exists()) { + return resource.getFile().getAbsolutePath(); + } + } catch (Exception e) { + log.warn("classpath 路径解析失败: {}", e.getMessage()); + } + return "classpath:" + relativePath; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsAdController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsAdController.java new file mode 100644 index 0000000..64a979b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsAdController.java @@ -0,0 +1,119 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsAdService; +import com.gxwebsoft.cms.entity.CmsAd; +import com.gxwebsoft.cms.param.CmsAdParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 广告位控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "广告位管理") +@RestController +@RequestMapping("/api/cms/cms-ad") +public class CmsAdController extends BaseController { + @Resource + private CmsAdService cmsAdService; + + @Operation(summary = "分页查询广告位") + @GetMapping("/page") + public ApiResult> page(CmsAdParam param) { + // 使用关联查询 + return success(cmsAdService.pageRel(param)); + } + + @Operation(summary = "查询全部广告位") + @GetMapping() + public ApiResult> list(CmsAdParam param) { + // 使用关联查询 + return success(cmsAdService.listRel(param)); + } + + @Operation(summary = "根据id查询广告位") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + final CmsAd ad = cmsAdService.getByIdRel(id); + return success(ad); + } + + @Operation(summary = "根据code查询广告位") + @GetMapping("/getByCode/{code}") + public ApiResult getByCode(@PathVariable("code") String code) { + final CmsAd ad = cmsAdService.getByIdCode(code); + return success(ad); + } + + @Operation(summary = "添加广告位") + @PostMapping() + public ApiResult save(@RequestBody CmsAd cmsAd) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsAd.setUserId(loginUser.getUserId()); + } + if (cmsAdService.save(cmsAd)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改广告位") + @PutMapping() + public ApiResult update(@RequestBody CmsAd cmsAd) { + if (cmsAdService.updateById(cmsAd)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除广告位") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsAdService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加广告位") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsAdService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改广告位") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsAdService, "ad_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除广告位") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsAdService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsAdRecordController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsAdRecordController.java new file mode 100644 index 0000000..4188ead --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsAdRecordController.java @@ -0,0 +1,114 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsAdRecordService; +import com.gxwebsoft.cms.entity.CmsAdRecord; +import com.gxwebsoft.cms.param.CmsAdRecordParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 广告图片控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "广告图片管理") +@RestController +@RequestMapping("/api/cms/cms-ad-record") +public class CmsAdRecordController extends BaseController { + @Resource + private CmsAdRecordService cmsAdRecordService; + + @Operation(summary = "分页查询广告图片") + @GetMapping("/page") + public ApiResult> page(CmsAdRecordParam param) { + // 使用关联查询 + return success(cmsAdRecordService.pageRel(param)); + } + + @Operation(summary = "查询全部广告图片") + @GetMapping() + public ApiResult> list(CmsAdRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsAdRecordService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsAdRecordService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsAdRecord:list')") + @OperationLog + @Operation(summary = "根据id查询广告图片") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsAdRecordService.getById(id)); + // 使用关联查询 + //return success(cmsAdRecordService.getByIdRel(id)); + } + + @Operation(summary = "添加广告图片") + @PostMapping() + public ApiResult save(@RequestBody CmsAdRecord cmsAdRecord) { + if (cmsAdRecordService.save(cmsAdRecord)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改广告图片") + @PutMapping() + public ApiResult update(@RequestBody CmsAdRecord cmsAdRecord) { + if (cmsAdRecordService.updateById(cmsAdRecord)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除广告图片") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsAdRecordService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加广告图片") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsAdRecordService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改广告图片") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsAdRecordService, "ad_record_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除广告图片") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsAdRecordService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCategoryController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCategoryController.java new file mode 100644 index 0000000..1e540a0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCategoryController.java @@ -0,0 +1,111 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsArticleCategoryService; +import com.gxwebsoft.cms.entity.CmsArticleCategory; +import com.gxwebsoft.cms.param.CmsArticleCategoryParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 文章分类表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "文章分类表管理") +@RestController +@RequestMapping("/api/cms/cms-article-category") +public class CmsArticleCategoryController extends BaseController { + @Resource + private CmsArticleCategoryService cmsArticleCategoryService; + + @Operation(summary = "分页查询文章分类表") + @GetMapping("/page") + public ApiResult> page(CmsArticleCategoryParam param) { + // 使用关联查询 + return success(cmsArticleCategoryService.pageRel(param)); + } + + @Operation(summary = "查询全部文章分类表") + @GetMapping() + public ApiResult> list(CmsArticleCategoryParam param) { + // 使用关联查询 + return success(cmsArticleCategoryService.listRel(param)); + } + + @Operation(summary = "根据id查询文章分类表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsArticleCategoryService.getByIdRel(id)); + } + + @Operation(summary = "添加文章分类表") + @PostMapping() + public ApiResult save(@RequestBody CmsArticleCategory cmsArticleCategory) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsArticleCategory.setUserId(loginUser.getUserId()); + } + if (cmsArticleCategoryService.save(cmsArticleCategory)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改文章分类表") + @PutMapping() + public ApiResult update(@RequestBody CmsArticleCategory cmsArticleCategory) { + if (cmsArticleCategoryService.updateById(cmsArticleCategory)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除文章分类表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsArticleCategoryService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加文章分类表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsArticleCategoryService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改文章分类表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsArticleCategoryService, "category_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除文章分类表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsArticleCategoryService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCommentController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCommentController.java new file mode 100644 index 0000000..51ed99e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCommentController.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsArticleCommentService; +import com.gxwebsoft.cms.entity.CmsArticleComment; +import com.gxwebsoft.cms.param.CmsArticleCommentParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 文章评论表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "文章评论表管理") +@RestController +@RequestMapping("/api/cms/cms-article-comment") +public class CmsArticleCommentController extends BaseController { + @Resource + private CmsArticleCommentService cmsArticleCommentService; + + @Operation(summary = "分页查询文章评论表") + @GetMapping("/page") + public ApiResult> page(CmsArticleCommentParam param) { + // 使用关联查询 + return success(cmsArticleCommentService.pageRel(param)); + } + + @Operation(summary = "查询全部文章评论表") + @GetMapping() + public ApiResult> list(CmsArticleCommentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsArticleCommentService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsArticleCommentService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsArticleComment:list')") + @OperationLog + @Operation(summary = "根据id查询文章评论表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsArticleCommentService.getById(id)); + // 使用关联查询 + //return success(cmsArticleCommentService.getByIdRel(id)); + } + + @Operation(summary = "添加文章评论表") + @PostMapping() + public ApiResult save(@RequestBody CmsArticleComment cmsArticleComment) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsArticleComment.setUserId(loginUser.getUserId()); + } + if (cmsArticleCommentService.save(cmsArticleComment)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改文章评论表") + @PutMapping() + public ApiResult update(@RequestBody CmsArticleComment cmsArticleComment) { + if (cmsArticleCommentService.updateById(cmsArticleComment)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除文章评论表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsArticleCommentService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加文章评论表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsArticleCommentService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改文章评论表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsArticleCommentService, "comment_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除文章评论表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsArticleCommentService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleContentController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleContentController.java new file mode 100644 index 0000000..4f3e3d6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleContentController.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsArticleContentService; +import com.gxwebsoft.cms.entity.CmsArticleContent; +import com.gxwebsoft.cms.param.CmsArticleContentParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 文章记录表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "文章记录表管理") +@RestController +@RequestMapping("/api/cms/cms-article-content") +public class CmsArticleContentController extends BaseController { + @Resource + private CmsArticleContentService cmsArticleContentService; + + @Operation(summary = "分页查询文章记录表") + @GetMapping("/page") + public ApiResult> page(CmsArticleContentParam param) { + // 使用关联查询 + return success(cmsArticleContentService.pageRel(param)); + } + + @Operation(summary = "查询全部文章记录表") + @GetMapping() + public ApiResult> list(CmsArticleContentParam param) { +// PageParam page = new PageParam<>(param); +// page.setDefaultOrder("create_time desc"); +// return success(cmsArticleContentService.list(page.getOrderWrapper())); + // 使用关联查询 + return success(cmsArticleContentService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsArticleContent:list')") + @OperationLog + @Operation(summary = "根据id查询文章记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { +// return success(cmsArticleContentService.getById(id)); + // 使用关联查询 + return success(cmsArticleContentService.getByIdRel(id)); + } + + @Operation(summary = "添加文章记录表") + @PostMapping() + public ApiResult save(@RequestBody CmsArticleContent cmsArticleContent) { + if (cmsArticleContentService.save(cmsArticleContent)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改文章记录表") + @PutMapping() + public ApiResult update(@RequestBody CmsArticleContent cmsArticleContent) { + if (cmsArticleContentService.updateById(cmsArticleContent)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除文章记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsArticleContentService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加文章记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsArticleContentService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改文章记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsArticleContentService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除文章记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsArticleContentService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleController.java new file mode 100644 index 0000000..31be045 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleController.java @@ -0,0 +1,379 @@ +package com.gxwebsoft.cms.controller; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.gxwebsoft.cms.entity.*; +import com.gxwebsoft.cms.param.CmsArticleImportParam; +import com.gxwebsoft.cms.service.*; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.param.CmsArticleParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.*; + +import static com.gxwebsoft.common.core.constants.ArticleConstants.CACHE_KEY_ARTICLE; + +/** + * 文章控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Slf4j +@Validated +@Tag(name = "文章管理") +@RestController +@RequestMapping("/api/cms/cms-article") +public class CmsArticleController extends BaseController { + @Resource + private CmsArticleService cmsArticleService; + @Resource + private CmsArticleContentService articleContentService; + @Resource + @Lazy + private CmsNavigationService cmsNavigationService; + @Resource + private CmsModelService cmsModelService; + @Resource + private UserService userService; + @Resource + private RedisUtil redisUtil; + + private static final long CACHE_MINUTES = 30L; + + @Operation(summary = "分页查询文章") + @GetMapping("/page") + public ApiResult> page(CmsArticleParam param) { + // 使用关联查询 + return success(cmsArticleService.pageRel(param)); + } + + @Operation(summary = "查询全部文章") + @GetMapping() + public ApiResult> list(CmsArticleParam param) { + // 使用关联查询 + return success(cmsArticleService.listRel(param)); + } + + @Operation(summary = "根据id查询文章") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") @NotNull Integer id) { + final CmsArticle article = cmsArticleService.getByIdRel(id); + if (ObjectUtil.isNotEmpty(article)) { + final CmsArticleContent item = articleContentService.getByIdRel(article.getArticleId()); + if (ObjectUtil.isNotEmpty(item)) { + article.setContent(item.getContent()); + } + return success(article); + } + return fail("文章ID不存在",null); + } + + @Operation(summary = "根据code查询文章") + @GetMapping("/getByCode/{code}") + public ApiResult getByCode(@PathVariable("code") String code) { + final CmsArticle article = cmsArticleService.getByIdCode(code); + if (ObjectUtil.isNotEmpty(article)) { + final CmsArticleContent item = articleContentService.getByIdRel(article.getArticleId()); + if (ObjectUtil.isNotEmpty(item)) { + article.setContent(item.getContent()); + } + } + return success(article); + } + + @PreAuthorize("hasAuthority('cms:cmsArticle:save')") + @Operation(summary = "添加文章") + @PostMapping() + public ApiResult save(@RequestBody @Valid CmsArticle article) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + article.setUserId(loginUser.getUserId()); + article.setAuthor(loginUser.getNickname()); + article.setMerchantId(loginUser.getMerchantId()); + if (cmsArticleService.saveRel(article)) { + return success("添加成功"); + } + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsArticle:update')") + @Operation(summary = "修改文章") + @PutMapping() + public ApiResult update(@RequestBody CmsArticle article) { + if (cmsArticleService.updateByIdRel(article)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsArticle:remove')") + @Operation(summary = "删除文章") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsArticleService.removeById(id)) { + redisUtil.delete(CACHE_KEY_ARTICLE + id); + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsArticle:save')") + @Operation(summary = "批量添加文章") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsArticleService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsArticle:update')") + @Operation(summary = "批量修改文章") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsArticleService, "article_id")) { + // 删除缓存 + final List ids = batchParam.getIds(); + ids.forEach(id -> { + redisUtil.delete(CACHE_KEY_ARTICLE + id); + }); + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsArticle:remove')") + @Operation(summary = "批量删除文章") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsArticleService.removeByIds(ids)) { + // 删除缓存 + ids.forEach(id -> { + redisUtil.delete(CACHE_KEY_ARTICLE + id); + }); + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "读取上一篇") + @GetMapping("/getPrevious/{id}") + public ApiResult getPrevious(@PathVariable("id") Integer id) { + final CmsArticle item = cmsArticleService.getById(id); + if (ObjectUtil.isEmpty(item)) { + return success("没有找到上一篇文章",null); + } + CmsArticle article; + // TODO 按排序号规则 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.lt(CmsArticle::getSortNumber, item.getSortNumber()); + wrapper.eq(CmsArticle::getStatus, 0); + wrapper.eq(CmsArticle::getType, 0); + wrapper.eq(CmsArticle::getCategoryId, item.getCategoryId()); + wrapper.orderByDesc(CmsArticle::getSortNumber); + wrapper.last("limit 1"); + article = cmsArticleService.getOne(wrapper); + if (ObjectUtil.isNotEmpty(article)) { + return success(article); + } + // TODO 按ID排序 + LambdaQueryWrapper wrapper2 = new LambdaQueryWrapper<>(); + wrapper2.lt(CmsArticle::getArticleId, item.getArticleId()); + wrapper2.eq(CmsArticle::getStatus, 0); + wrapper2.eq(CmsArticle::getCategoryId, item.getCategoryId()); + wrapper2.last("limit 1"); + wrapper2.orderByDesc(CmsArticle::getArticleId); + article = cmsArticleService.getOne(wrapper2); + return success(article); + } + + @Operation(summary = "读取下一篇") + @GetMapping("/getNext/{id}") + public ApiResult getNext(@PathVariable("id") Integer id) { + CmsArticle item = cmsArticleService.getById(id); + if (ObjectUtil.isEmpty(item)) { + return success("没有找到下一篇文章",null); + } + CmsArticle article; + // TODO 按排序号规则 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.gt(CmsArticle::getSortNumber, item.getSortNumber()); + wrapper.eq(CmsArticle::getStatus, 0); + wrapper.eq(CmsArticle::getType, 0); + wrapper.eq(CmsArticle::getCategoryId, item.getCategoryId()); + wrapper.orderByAsc(CmsArticle::getSortNumber); + wrapper.last("limit 1"); + article = cmsArticleService.getOne(wrapper); + if (ObjectUtil.isNotEmpty(article)) { + return success(article); + } + // TODO 按ID排序 + LambdaQueryWrapper wrapper2 = new LambdaQueryWrapper<>(); + wrapper2.gt(CmsArticle::getArticleId, item.getArticleId()); + wrapper2.eq(CmsArticle::getStatus, 0); + wrapper2.eq(CmsArticle::getCategoryId, item.getCategoryId()); + wrapper2.last("limit 1"); + wrapper2.orderByAsc(CmsArticle::getArticleId); + article = cmsArticleService.getOne(wrapper2); + return success(article); + } + + @Operation(summary = "统计信息") + @GetMapping("/data") + public ApiResult> data(CmsArticleParam param) { + Map data = new HashMap<>(); + final LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + if (param.getMerchantId() != null) { + wrapper.eq(CmsArticle::getMerchantId, param.getMerchantId()); + } + + long totalNum = cmsArticleService.count( + wrapper.eq(CmsArticle::getDeleted, 0).eq(CmsArticle::getStatus, 0) + ); + data.put("totalNum", Math.toIntExact(totalNum)); + + long totalNum2 = cmsArticleService.count( + wrapper.eq(CmsArticle::getStatus, 1) + ); + data.put("totalNum2", Math.toIntExact(totalNum2)); + + long totalNum3 = cmsArticleService.count( + wrapper.gt(CmsArticle::getStatus, 1) + ); + data.put("totalNum3", Math.toIntExact(totalNum3)); + + return success(data); + } + + @Operation(summary = "密码校验") + @GetMapping("/checkArticlePassword") + public ApiResult checkArticlePassword(CmsArticle param) { + if (!userService.comparePassword(param.getPassword(), param.getPassword2())) { + return fail("密码不正确"); + } + return success("密码正确"); + } + + /** + * excel批量导入文章 + */ + @PreAuthorize("hasAuthority('cms:cmsArticle:save')") + @Operation(summary = "批量导入文章") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/import") + public ApiResult> importBatch(MultipartFile file) { + ImportParams importParams = new ImportParams(); + try { + List list = ExcelImportUtil.importExcel(file.getInputStream(), CmsArticleImportParam.class, importParams); + list.forEach(d -> { + CmsArticle item = JSONUtil.parseObject(JSONUtil.toJSONString(d), CmsArticle.class); + assert item != null; + if (ObjectUtil.isNotEmpty(item)) { + if (item.getStatus() == null) { + item.setStatus(1); + } + if (cmsArticleService.save(item)) { + CmsArticleContent content = new CmsArticleContent(); + content.setArticleId(item.getArticleId()); + content.setContent(item.getContent()); + articleContentService.save(content); + } + } + }); + return success("成功导入" + list.size() + "条", null); + } catch (Exception e) { + e.printStackTrace(); + } + return fail("导入失败", null); + } + + @Operation(summary = "按标签分页查询") + @GetMapping("/findTags") + public ApiResult> findTags(CmsArticleParam param) { + final String tags = param.getTags(); + if (StringUtils.isNotBlank(tags)) { + final String[] split = tags.split(","); + final List list = Arrays.asList(split); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); + if (StrUtil.isNotBlank(tags)) { + for (String s : list) { + queryWrapper.or().like(CmsArticle::getTags, s); +// queryWrapper.or().apply("LOCATE(" + "'" + s + "'," + "tags" + ") > 0"); + } + } + if (param.getCategoryId() != null) { + queryWrapper.eq(CmsArticle::getCategoryId, param.getCategoryId()); + } + if (param.getDetail() != null) { + queryWrapper.eq(CmsArticle::getDetail, param.getDetail()); + } + queryWrapper.last("limit 8"); + List articles = cmsArticleService.list(queryWrapper); + return success(articles); + } + return success("", null); + } + + @Operation(summary = "按标签分页查询") + @GetMapping("/pageTags") + public ApiResult> pageTags(CmsArticleParam param) { + final String tags = param.getTags(); + if (StringUtils.isNotBlank(tags)) { + final String[] split = tags.split(","); + final List list = Arrays.asList(split); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + for (String s : list) { + queryWrapper.or().like(CmsArticle::getTags, s); + } + queryWrapper.orderByDesc(CmsArticle::getCreateTime); + queryWrapper.last("limit 100"); + List articles = cmsArticleService.list(queryWrapper); + if (!articles.isEmpty()) { + List navigationList = cmsNavigationService.listByIds(articles.stream().map(CmsArticle::getCategoryId).toList()); + for (CmsArticle article : articles) { + for (CmsNavigation navigation : navigationList) { + if (article.getCategoryId().equals(navigation.getNavigationId())) { + article.setCategoryName(navigation.getTitle()); + } + } + } + } + return success(articles); + } + return success("", null); + } + + @Operation(summary = "按IDS查询") + @GetMapping("/getByIds") + public ApiResult> getByIds(CmsArticleParam param) { + // 使用关联查询 + return success(cmsArticleService.list(new LambdaQueryWrapper().in(CmsArticle::getArticleId, param.getArticleIds()))); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCountController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCountController.java new file mode 100644 index 0000000..f80a684 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleCountController.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsArticleCountService; +import com.gxwebsoft.cms.entity.CmsArticleCount; +import com.gxwebsoft.cms.param.CmsArticleCountParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 点赞文章控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "点赞文章管理") +@RestController +@RequestMapping("/api/cms/cms-article-count") +public class CmsArticleCountController extends BaseController { + @Resource + private CmsArticleCountService cmsArticleCountService; + + @Operation(summary = "分页查询点赞文章") + @GetMapping("/page") + public ApiResult> page(CmsArticleCountParam param) { + // 使用关联查询 + return success(cmsArticleCountService.pageRel(param)); + } + + @Operation(summary = "查询全部点赞文章") + @GetMapping() + public ApiResult> list(CmsArticleCountParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsArticleCountService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsArticleCountService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsArticleCount:list')") + @OperationLog + @Operation(summary = "根据id查询点赞文章") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsArticleCountService.getById(id)); + // 使用关联查询 + //return success(cmsArticleCountService.getByIdRel(id)); + } + + @Operation(summary = "添加点赞文章") + @PostMapping() + public ApiResult save(@RequestBody CmsArticleCount cmsArticleCount) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsArticleCount.setUserId(loginUser.getUserId()); + } + if (cmsArticleCountService.save(cmsArticleCount)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改点赞文章") + @PutMapping() + public ApiResult update(@RequestBody CmsArticleCount cmsArticleCount) { + if (cmsArticleCountService.updateById(cmsArticleCount)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除点赞文章") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsArticleCountService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加点赞文章") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsArticleCountService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改点赞文章") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsArticleCountService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除点赞文章") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsArticleCountService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleLikeController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleLikeController.java new file mode 100644 index 0000000..2b9d2ef --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsArticleLikeController.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsArticleLikeService; +import com.gxwebsoft.cms.entity.CmsArticleLike; +import com.gxwebsoft.cms.param.CmsArticleLikeParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 点赞文章控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "点赞文章管理") +@RestController +@RequestMapping("/api/cms/cms-article-like") +public class CmsArticleLikeController extends BaseController { + @Resource + private CmsArticleLikeService cmsArticleLikeService; + + @Operation(summary = "分页查询点赞文章") + @GetMapping("/page") + public ApiResult> page(CmsArticleLikeParam param) { + // 使用关联查询 + return success(cmsArticleLikeService.pageRel(param)); + } + + @Operation(summary = "查询全部点赞文章") + @GetMapping() + public ApiResult> list(CmsArticleLikeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsArticleLikeService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsArticleLikeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsArticleLike:list')") + @OperationLog + @Operation(summary = "根据id查询点赞文章") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsArticleLikeService.getById(id)); + // 使用关联查询 + //return success(cmsArticleLikeService.getByIdRel(id)); + } + + @Operation(summary = "添加点赞文章") + @PostMapping() + public ApiResult save(@RequestBody CmsArticleLike cmsArticleLike) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsArticleLike.setUserId(loginUser.getUserId()); + } + if (cmsArticleLikeService.save(cmsArticleLike)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改点赞文章") + @PutMapping() + public ApiResult update(@RequestBody CmsArticleLike cmsArticleLike) { + if (cmsArticleLikeService.updateById(cmsArticleLike)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除点赞文章") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsArticleLikeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加点赞文章") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsArticleLikeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改点赞文章") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsArticleLikeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除点赞文章") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsArticleLikeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDesignController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDesignController.java new file mode 100644 index 0000000..e69d81b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDesignController.java @@ -0,0 +1,127 @@ +package com.gxwebsoft.cms.controller; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.cms.entity.CmsNavigation; +import com.gxwebsoft.cms.service.CmsNavigationService; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsDesignService; +import com.gxwebsoft.cms.entity.CmsDesign; +import com.gxwebsoft.cms.param.CmsDesignParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 页面管理记录表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "页面管理记录表管理") +@RestController +@RequestMapping("/api/cms/cms-design") +public class CmsDesignController extends BaseController { + @Resource + private CmsDesignService cmsDesignService; + @Resource + private CmsNavigationService cmsNavigationService; + + @Operation(summary = "分页查询页面管理记录表") + @GetMapping("/page") + public ApiResult> page(CmsDesignParam param) { + // 使用关联查询 + return success(cmsDesignService.pageRel(param)); + } + + @Operation(summary = "查询全部页面管理记录表") + @GetMapping() + public ApiResult> list(CmsDesignParam param) { + // 使用关联查询 + return success(cmsDesignService.listRel(param)); + } + + @Operation(summary = "根据id查询页面管理记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsDesignService.getByIdRel(id)); + } + + @Operation(summary = "添加页面管理记录表") + @PostMapping() + public ApiResult save(@RequestBody CmsDesign cmsDesign) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsDesign.setUserId(loginUser.getUserId()); + } + if (cmsDesignService.save(cmsDesign)) { + try { + cmsNavigationService.update(new LambdaUpdateWrapper().set(CmsNavigation::getBanner, cmsDesign.getPhoto()).eq(CmsNavigation::getNavigationId,cmsDesign.getCategoryId())); + // 同步翻译英文版 + cmsDesignService.translate(cmsDesign); + return success("添加成功"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return fail("添加失败"); + } + + @Operation(summary = "修改页面管理记录表") + @PutMapping() + public ApiResult update(@RequestBody CmsDesign cmsDesign) { + if (cmsDesignService.updateById(cmsDesign)) { + // 同步翻译英文版 + cmsDesignService.translate(cmsDesign); + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除页面管理记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsDesignService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加页面管理记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsDesignService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改页面管理记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsDesignService, "page_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除页面管理记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsDesignService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDesignRecordController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDesignRecordController.java new file mode 100644 index 0000000..d921d01 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDesignRecordController.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsDesignRecordService; +import com.gxwebsoft.cms.entity.CmsDesignRecord; +import com.gxwebsoft.cms.param.CmsDesignRecordParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 页面组件表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "页面组件表管理") +@RestController +@RequestMapping("/api/cms/cms-design-record") +public class CmsDesignRecordController extends BaseController { + @Resource + private CmsDesignRecordService cmsDesignRecordService; + + @Operation(summary = "分页查询页面组件表") + @GetMapping("/page") + public ApiResult> page(CmsDesignRecordParam param) { + // 使用关联查询 + return success(cmsDesignRecordService.pageRel(param)); + } + + @Operation(summary = "查询全部页面组件表") + @GetMapping() + public ApiResult> list(CmsDesignRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsDesignRecordService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsDesignRecordService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsDesignRecord:list')") + @OperationLog + @Operation(summary = "根据id查询页面组件表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsDesignRecordService.getById(id)); + // 使用关联查询 + //return success(cmsDesignRecordService.getByIdRel(id)); + } + + @Operation(summary = "添加页面组件表") + @PostMapping() + public ApiResult save(@RequestBody CmsDesignRecord cmsDesignRecord) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsDesignRecord.setUserId(loginUser.getUserId()); + } + if (cmsDesignRecordService.save(cmsDesignRecord)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改页面组件表") + @PutMapping() + public ApiResult update(@RequestBody CmsDesignRecord cmsDesignRecord) { + if (cmsDesignRecordService.updateById(cmsDesignRecord)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除页面组件表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsDesignRecordService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加页面组件表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsDesignRecordService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改页面组件表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsDesignRecordService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除页面组件表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsDesignRecordService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDomainController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDomainController.java new file mode 100644 index 0000000..5487036 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsDomainController.java @@ -0,0 +1,166 @@ +package com.gxwebsoft.cms.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.cms.mapper.CmsDomainMapper; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsDomainService; +import com.gxwebsoft.cms.entity.CmsDomain; +import com.gxwebsoft.cms.param.CmsDomainParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 网站域名记录表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Tag(name = "网站域名记录表管理") +@RestController +@RequestMapping("/api/cms/cms-domain") +public class CmsDomainController extends BaseController { + @Resource + private CmsDomainService cmsDomainService; + @Resource + private CmsDomainMapper cmsDomainMapper; + @Resource + private RedisUtil redisUtil; + + @Operation(summary = "分页查询网站域名记录表") + @GetMapping("/page") + public ApiResult> page(CmsDomainParam param) { + // 使用关联查询 + return success(cmsDomainService.pageRel(param)); + } + + @Operation(summary = "查询全部网站域名记录表") + @GetMapping() + public ApiResult> list(CmsDomainParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsDomainService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsDomainService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsDomain:list')") + @OperationLog + @Operation(summary = "根据id查询网站域名记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsDomainService.getById(id)); + // 使用关联查询 + //return success(cmsDomainService.getByIdRel(id)); + } + + @Operation(summary = "添加网站域名记录表") + @PostMapping() + public ApiResult save(@RequestBody CmsDomain cmsDomain) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsDomain.setUserId(loginUser.getUserId()); + } + if (cmsDomainService.save(cmsDomain)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改网站域名记录表") + @PutMapping() + public ApiResult update(@RequestBody CmsDomain cmsDomain) { + if (cmsDomainService.updateById(cmsDomain)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除网站域名记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsDomainService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加网站域名记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsDomainService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改网站域名记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsDomainService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除网站域名记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsDomainService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "查询授权域名信息") + @GetMapping("/getTenantIdByDomain") + public ApiResult getTenantIdByDomain(CmsDomainParam param) { + final CmsDomain domain = cmsDomainService.getOne(new LambdaQueryWrapper().eq(CmsDomain::getDomain, param.getDomain()).last("limit 1")); + return success(domain); + } + + @Operation(summary = "授权二级域名") + @PostMapping("/domain") + public ApiResult domain(@RequestBody CmsDomain cmsDomain) { + final User loginUser = getLoginUser(); + String key = "Domain:" + cmsDomain.getDomain(); + final Integer tenantId = loginUser.getTenantId(); + final CmsDomain domain = cmsDomainService.getOne(new LambdaQueryWrapper() + .eq(CmsDomain::getWebsiteId, cmsDomain.getWebsiteId()).last("limit 1")); + if (ObjectUtil.isNotEmpty(domain)) { + // 重写缓存 + redisUtil.set(key,tenantId); + domain.setDomain(cmsDomain.getDomain()); + cmsDomainService.updateById(domain); + return success("授权成功"); + } + if(ObjectUtil.isEmpty(domain)){ + cmsDomain.setUserId(loginUser.getUserId()); + cmsDomain.setSortNumber(100); + cmsDomain.setStatus(1); + cmsDomain.setHostName("@"); + cmsDomain.setWebsiteId(cmsDomain.getWebsiteId()); + cmsDomain.setTenantId(tenantId); + if(cmsDomainService.save(cmsDomain)){ + // 重写缓存 + redisUtil.set(key,tenantId); + return success("授权成功"); + } + } + return fail("授权失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsFormController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsFormController.java new file mode 100644 index 0000000..ce9ab34 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsFormController.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsFormService; +import com.gxwebsoft.cms.entity.CmsForm; +import com.gxwebsoft.cms.param.CmsFormParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 表单设计表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "表单设计表管理") +@RestController +@RequestMapping("/api/cms/cms-form") +public class CmsFormController extends BaseController { + @Resource + private CmsFormService cmsFormService; + + @Operation(summary = "分页查询表单设计表") + @GetMapping("/page") + public ApiResult> page(CmsFormParam param) { + // 使用关联查询 + return success(cmsFormService.pageRel(param)); + } + + @Operation(summary = "查询全部表单设计表") + @GetMapping() + public ApiResult> list(CmsFormParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsFormService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsFormService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsForm:list')") + @OperationLog + @Operation(summary = "根据id查询表单设计表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsFormService.getById(id)); + // 使用关联查询 + //return success(cmsFormService.getByIdRel(id)); + } + + @Operation(summary = "添加表单设计表") + @PostMapping() + public ApiResult save(@RequestBody CmsForm cmsForm) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsForm.setUserId(loginUser.getUserId()); + } + if (cmsFormService.save(cmsForm)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改表单设计表") + @PutMapping() + public ApiResult update(@RequestBody CmsForm cmsForm) { + if (cmsFormService.updateById(cmsForm)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除表单设计表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsFormService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加表单设计表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsFormService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改表单设计表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsFormService, "form_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除表单设计表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsFormService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsFormRecordController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsFormRecordController.java new file mode 100644 index 0000000..0aedacc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsFormRecordController.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsFormRecordService; +import com.gxwebsoft.cms.entity.CmsFormRecord; +import com.gxwebsoft.cms.param.CmsFormRecordParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 表单数据记录表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "表单数据记录表管理") +@RestController +@RequestMapping("/api/cms/cms-form-record") +public class CmsFormRecordController extends BaseController { + @Resource + private CmsFormRecordService cmsFormRecordService; + + @Operation(summary = "分页查询表单数据记录表") + @GetMapping("/page") + public ApiResult> page(CmsFormRecordParam param) { + // 使用关联查询 + return success(cmsFormRecordService.pageRel(param)); + } + + @Operation(summary = "查询全部表单数据记录表") + @GetMapping() + public ApiResult> list(CmsFormRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(cmsFormRecordService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(cmsFormRecordService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsFormRecord:list')") + @OperationLog + @Operation(summary = "根据id查询表单数据记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsFormRecordService.getById(id)); + // 使用关联查询 + //return success(cmsFormRecordService.getByIdRel(id)); + } + + @Operation(summary = "添加表单数据记录表") + @PostMapping() + public ApiResult save(@RequestBody CmsFormRecord cmsFormRecord) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsFormRecord.setUserId(loginUser.getUserId()); + } + if (cmsFormRecordService.save(cmsFormRecord)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改表单数据记录表") + @PutMapping() + public ApiResult update(@RequestBody CmsFormRecord cmsFormRecord) { + if (cmsFormRecordService.updateById(cmsFormRecord)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除表单数据记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsFormRecordService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加表单数据记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsFormRecordService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改表单数据记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsFormRecordService, "form_record_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除表单数据记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsFormRecordService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLangController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLangController.java new file mode 100644 index 0000000..475e9cd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLangController.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsLangService; +import com.gxwebsoft.cms.entity.CmsLang; +import com.gxwebsoft.cms.param.CmsLangParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 国际化控制器 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Tag(name = "国际化管理") +@RestController +@RequestMapping("/api/cms/cms-lang") +public class CmsLangController extends BaseController { + @Resource + private CmsLangService cmsLangService; + + @Operation(summary = "分页查询国际化") + @GetMapping("/page") + public ApiResult> page(CmsLangParam param) { + // 使用关联查询 + return success(cmsLangService.pageRel(param)); + } + + @Operation(summary = "查询全部国际化") + @GetMapping() + public ApiResult> list(CmsLangParam param) { + // 使用关联查询 + return success(cmsLangService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsLang:list')") + @Operation(summary = "根据id查询国际化") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsLangService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('cms:cmsLang:save')") + @Operation(summary = "添加国际化") + @PostMapping() + public ApiResult save(@RequestBody CmsLang cmsLang) { + if (cmsLangService.save(cmsLang)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLang:update')") + @Operation(summary = "修改国际化") + @PutMapping() + public ApiResult update(@RequestBody CmsLang cmsLang) { + if (cmsLangService.updateById(cmsLang)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLang:remove')") + @Operation(summary = "删除国际化") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsLangService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLang:save')") + @Operation(summary = "批量添加国际化") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsLangService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLang:update')") + @Operation(summary = "批量修改国际化") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsLangService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLang:reomve')") + @Operation(summary = "批量删除国际化") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsLangService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLangLogController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLangLogController.java new file mode 100644 index 0000000..a881156 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLangLogController.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsLangLogService; +import com.gxwebsoft.cms.entity.CmsLangLog; +import com.gxwebsoft.cms.param.CmsLangLogParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 国际化记录启用控制器 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Tag(name = "国际化记录启用管理") +@RestController +@RequestMapping("/api/cms/cms-lang-log") +public class CmsLangLogController extends BaseController { + @Resource + private CmsLangLogService cmsLangLogService; + + @Operation(summary = "分页查询国际化记录启用") + @GetMapping("/page") + public ApiResult> page(CmsLangLogParam param) { + // 使用关联查询 + return success(cmsLangLogService.pageRel(param)); + } + + @Operation(summary = "查询全部国际化记录启用") + @GetMapping() + public ApiResult> list(CmsLangLogParam param) { + // 使用关联查询 + return success(cmsLangLogService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsLangLog:list')") + @Operation(summary = "根据id查询国际化记录启用") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsLangLogService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('cms:cmsLangLog:save')") + @Operation(summary = "添加国际化记录启用") + @PostMapping() + public ApiResult save(@RequestBody CmsLangLog cmsLangLog) { + if (cmsLangLogService.save(cmsLangLog)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLangLog:update')") + @Operation(summary = "修改国际化记录启用") + @PutMapping() + public ApiResult update(@RequestBody CmsLangLog cmsLangLog) { + if (cmsLangLogService.updateById(cmsLangLog)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLangLog:remove')") + @Operation(summary = "删除国际化记录启用") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsLangLogService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLangLog:save')") + @Operation(summary = "批量添加国际化记录启用") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsLangLogService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLangLog:update')") + @Operation(summary = "批量修改国际化记录启用") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsLangLogService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsLangLog:remove')") + @Operation(summary = "批量删除国际化记录启用") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsLangLogService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLinkController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLinkController.java new file mode 100644 index 0000000..03f798c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsLinkController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsLinkService; +import com.gxwebsoft.cms.entity.CmsLink; +import com.gxwebsoft.cms.param.CmsLinkParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 常用链接控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "常用链接管理") +@RestController +@RequestMapping("/api/cms/cms-link") +public class CmsLinkController extends BaseController { + @Resource + private CmsLinkService cmsLinkService; + + @Operation(summary = "分页查询常用链接") + @GetMapping("/page") + public ApiResult> page(CmsLinkParam param) { + // 使用关联查询 + return success(cmsLinkService.pageRel(param)); + } + + @Operation(summary = "查询全部常用链接") + @GetMapping() + public ApiResult> list(CmsLinkParam param) { + // 使用关联查询 + return success(cmsLinkService.listRel(param)); + } + + @PreAuthorize("hasAuthority('cms:cmsLink:list')") + @OperationLog + @Operation(summary = "根据id查询常用链接") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsLinkService.getByIdRel(id)); + } + + @Operation(summary = "添加常用链接") + @PostMapping() + public ApiResult save(@RequestBody CmsLink cmsLink) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsLink.setUserId(loginUser.getUserId()); + } + if (cmsLinkService.save(cmsLink)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改常用链接") + @PutMapping() + public ApiResult update(@RequestBody CmsLink cmsLink) { + if (cmsLinkService.updateById(cmsLink)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除常用链接") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsLinkService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加常用链接") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsLinkService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改常用链接") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsLinkService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除常用链接") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsLinkService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsMainController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsMainController.java new file mode 100644 index 0000000..4242c80 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsMainController.java @@ -0,0 +1,25 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.cms.service.CmsWebsiteService; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * 网站应用主入口 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Slf4j +@Tag(name = "网站应用") +@RestController +@RequestMapping("/api/cms") +public class CmsMainController extends BaseController { + @Resource + private CmsWebsiteService cmsWebsiteService; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsModelController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsModelController.java new file mode 100644 index 0000000..c139eaa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsModelController.java @@ -0,0 +1,118 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsModelService; +import com.gxwebsoft.cms.entity.CmsModel; +import com.gxwebsoft.cms.param.CmsModelParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 模型控制器 + * + * @author 科技小王子 + * @since 2024-11-26 15:44:53 + */ +@Tag(name = "模型管理") +@RestController +@RequestMapping("/api/cms/cms-model") +public class CmsModelController extends BaseController { + @Resource + private CmsModelService cmsModelService; + + @Operation(summary = "分页查询模型") + @GetMapping("/page") + public ApiResult> page(CmsModelParam param) { + // 使用关联查询 + return success(cmsModelService.pageRel(param)); + } + + @Operation(summary = "查询全部模型") + @GetMapping() + public ApiResult> list(CmsModelParam param) { + // 使用关联查询 + return success(cmsModelService.listRel(param)); + } + + @Operation(summary = "根据id查询模型") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsModelService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('cms:cmsModel:save')") + @Operation(summary = "添加模型") + @PostMapping() + public ApiResult save(@RequestBody CmsModel cmsModel) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsModel.setUserId(loginUser.getUserId()); + } + if (cmsModelService.save(cmsModel)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsModel:update')") + @Operation(summary = "修改模型") + @PutMapping() + public ApiResult update(@RequestBody CmsModel cmsModel) { + if (cmsModelService.updateById(cmsModel)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsModel:remove')") + @Operation(summary = "删除模型") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsModelService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsModel:save')") + @Operation(summary = "批量添加模型") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsModelService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsModel:update')") + @Operation(summary = "批量修改模型") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsModelService, "model_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsModel:remvoe')") + @Operation(summary = "批量删除模型") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsModelService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsNavigationController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsNavigationController.java new file mode 100644 index 0000000..2c067ca --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsNavigationController.java @@ -0,0 +1,197 @@ +package com.gxwebsoft.cms.controller; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.cms.entity.CmsDesign; +import com.gxwebsoft.cms.entity.CmsModel; +import com.gxwebsoft.cms.service.CmsDesignService; +import com.gxwebsoft.cms.service.CmsModelService; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsNavigationService; +import com.gxwebsoft.cms.entity.CmsNavigation; +import com.gxwebsoft.cms.param.CmsNavigationParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.*; + + +import javax.annotation.Resource; +import java.util.List; + +/** + * 网站导航记录表控制器 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Tag(name = "网站导航记录表管理") +@RestController +@RequestMapping("/api/cms/cms-navigation") +public class CmsNavigationController extends BaseController { + @Resource + private CmsNavigationService cmsNavigationService; + @Resource + private CmsModelService cmsModelService; + @Resource + private CmsDesignService cmsDesignService; + @Resource + private UserService userService; + @Resource + private RedisUtil redisUtil; + + + private static final String SITE_INFO_KEY_PREFIX = "SiteInfo:"; + + @Operation(summary = "分页查询网站导航记录表") + @GetMapping("/page") + public ApiResult> page(CmsNavigationParam param) { + // 使用关联查询 + return success(cmsNavigationService.pageRel(param)); + } + + @Operation(summary = "查询全部网站导航记录表") + @GetMapping() + public ApiResult> list(CmsNavigationParam param) { + // 使用关联查询 + return success(cmsNavigationService.listRel(param)); + } + + @Operation(summary = "根据id查询网站导航记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsNavigationService.getByIdRel(id)); + } + + @Operation(summary = "根据code查询网站导航记录表") + @GetMapping("/getByCode/{code}") + public ApiResult getByCode(@PathVariable("code") String code) { + // 使用关联查询 + return success(cmsNavigationService.getByIdRelByCodeRel(code)); + } + + @Operation(summary = "添加网站导航记录表") + @PostMapping() + public ApiResult save(@RequestBody CmsNavigation cmsNavigation) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsNavigation.setUserId(loginUser.getUserId()); + cmsNavigation.setTenantId(loginUser.getTenantId()); + } + // 去除前面空格 + cmsNavigation.setTitle(StrUtil.trimStart(cmsNavigation.getTitle())); + if (cmsNavigationService.save(cmsNavigation)) { + // 添加成功事务处理 + cmsNavigationService.saveAsync(cmsNavigation); + redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改网站导航记录表") + @PutMapping() + public ApiResult update(@RequestBody CmsNavigation cmsNavigation) { + if (cmsNavigationService.updateById(cmsNavigation)) { + // 修改成功事务处理 + cmsNavigationService.saveAsync(cmsNavigation); + redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除网站导航记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsNavigationService.removeById(id)) { + redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加网站导航记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsNavigationService.saveBatch(list)) { + redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改网站导航记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsNavigationService, "navigation_id")) { + redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除网站导航记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsNavigationService.removeByIds(ids)) { + redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "获取树形结构的网站导航数据") + @GetMapping("/tree") + public ApiResult> tree(CmsNavigationParam param) { + param.setHide(0); + final List navigations = cmsNavigationService.listRel(param); + return success(CommonUtil.toTreeData(navigations, 0, CmsNavigation::getParentId, CmsNavigation::getNavigationId, CmsNavigation::setChildren)); + } + + @Operation(summary = "根据path获取导航") + @GetMapping("/getNavigationByPath") + public ApiResult getNavigationByPath(CmsNavigationParam param) { + final CmsNavigation navigation = cmsNavigationService.getOne(new LambdaUpdateWrapper().eq(CmsNavigation::getModel, param.getModel()).last("limit 1")); + if (ObjectUtil.isNotEmpty(navigation)) { + // 页面元素 + final CmsDesign design = cmsDesignService.getOne(new LambdaUpdateWrapper().eq(CmsDesign::getCategoryId, navigation.getNavigationId()).last("limit 1")); + // 模型信息 + final CmsModel model = cmsModelService.getOne(new LambdaQueryWrapper().eq(CmsModel::getModel, navigation.getModel()).last("limit 1")); + navigation.setBanner(model.getBanner()); + // 上级导航 + if (!navigation.getParentId().equals(0)) { + final CmsNavigation parent = cmsNavigationService.getById(navigation.getParentId()); + navigation.setParentPath(parent.getPath()); + navigation.setParentName(parent.getTitle()); + } + // 页面信息 + navigation.setDesign(design); + // 页面布局 + if (ObjectUtil.isNotEmpty(design)) { + navigation.setLayout(design.getLayout()); + } + } + return success(navigation); + } + + @Operation(summary = "密码校验") + @GetMapping("/checkNavigationPassword") + public ApiResult checkNavigationPassword(CmsNavigationParam param) { + if (!userService.comparePassword(param.getPassword(), param.getPassword2())) { + return fail("密码不正确"); + } + return success("密码正确"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsStatisticsController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsStatisticsController.java new file mode 100644 index 0000000..0e89ff3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsStatisticsController.java @@ -0,0 +1,126 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsStatisticsService; +import com.gxwebsoft.cms.entity.CmsStatistics; +import com.gxwebsoft.cms.param.CmsStatisticsParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 站点统计信息表控制器 + * + * @author 科技小王子 + * @since 2025-07-25 12:32:06 + */ +@Tag(name = "站点统计信息表管理") +@RestController +@RequestMapping("/api/cms/cms-statistics") +public class CmsStatisticsController extends BaseController { + @Resource + private CmsStatisticsService cmsStatisticsService; + + @Operation(summary = "分页查询站点统计信息表") + @GetMapping("/page") + public ApiResult> page(CmsStatisticsParam param) { + // 使用关联查询 + return success(cmsStatisticsService.pageRel(param)); + } + + @Operation(summary = "查询全部站点统计信息表") + @GetMapping() + public ApiResult> list(CmsStatisticsParam param) { + // 使用关联查询 + return success(cmsStatisticsService.listRel(param)); + } + + @Operation(summary = "根据id查询站点统计信息表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsStatisticsService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('cms:cmsStatistics:save')") + @OperationLog + @Operation(summary = "添加站点统计信息表") + @PostMapping() + public ApiResult save(@RequestBody CmsStatistics cmsStatistics) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsStatistics.setUserId(loginUser.getUserId()); + } + if (cmsStatisticsService.save(cmsStatistics)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsStatistics:update')") + @OperationLog + @Operation(summary = "修改站点统计信息表") + @PutMapping() + public ApiResult update(@RequestBody CmsStatistics cmsStatistics) { + if (cmsStatisticsService.updateById(cmsStatistics)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsStatistics:remove')") + @OperationLog + @Operation(summary = "删除站点统计信息表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsStatisticsService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsStatistics:save')") + @OperationLog + @Operation(summary = "批量添加站点统计信息表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsStatisticsService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsStatistics:update')") + @OperationLog + @Operation(summary = "批量修改站点统计信息表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsStatisticsService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsStatistics:remove')") + @OperationLog + @Operation(summary = "批量删除站点统计信息表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsStatisticsService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsTemplateController.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsTemplateController.java new file mode 100644 index 0000000..1b3fe9e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/controller/CmsTemplateController.java @@ -0,0 +1,118 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.cms.service.CmsTemplateService; +import com.gxwebsoft.cms.entity.CmsTemplate; +import com.gxwebsoft.cms.param.CmsTemplateParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 网站模版控制器 + * + * @author 科技小王子 + * @since 2025-01-21 14:21:16 + */ +@Tag(name = "网站模版管理") +@RestController +@RequestMapping("/api/cms/cms-template") +public class CmsTemplateController extends BaseController { + @Resource + private CmsTemplateService cmsTemplateService; + + @Operation(summary = "分页查询网站模版") + @GetMapping("/page") + public ApiResult> page(CmsTemplateParam param) { + // 使用关联查询 + return success(cmsTemplateService.pageRel(param)); + } + + @Operation(summary = "查询全部网站模版") + @GetMapping() + public ApiResult> list(CmsTemplateParam param) { + // 使用关联查询 + return success(cmsTemplateService.listRel(param)); + } + + @Operation(summary = "根据id查询网站模版") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(cmsTemplateService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('cms:cmsTemplate:save')") + @Operation(summary = "添加网站模版") + @PostMapping() + public ApiResult save(@RequestBody CmsTemplate cmsTemplate) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cmsTemplate.setUserId(loginUser.getUserId()); + } + if (cmsTemplateService.save(cmsTemplate)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsTemplate:update')") + @Operation(summary = "修改网站模版") + @PutMapping() + public ApiResult update(@RequestBody CmsTemplate cmsTemplate) { + if (cmsTemplateService.updateById(cmsTemplate)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsTemplate:remove')") + @Operation(summary = "删除网站模版") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsTemplateService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsTemplate:save')") + @Operation(summary = "批量添加网站模版") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cmsTemplateService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsTemplate:update')") + @Operation(summary = "批量修改网站模版") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsTemplateService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('cms:cmsTemplate:remove')") + @Operation(summary = "批量删除网站模版") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsTemplateService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAd.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAd.java new file mode 100644 index 0000000..307e443 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAd.java @@ -0,0 +1,105 @@ +package com.gxwebsoft.cms.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.gxwebsoft.common.core.utils.JSONUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 广告位 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsAd对象", description = "广告位") +public class CmsAd implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "ad_id", type = IdType.AUTO) + private Integer adId; + + @Schema(description = "类型") + private Integer type; + + @Schema(description = "唯一标识") + private String code; + + @Schema(description = "栏目ID") + private Integer categoryId; + + @Schema(description = "栏目名称") + @TableField(exist = false) + private String categoryName; + + @Schema(description = "广告位名称") + private String name; + + @Schema(description = "宽") + private String width; + + @Schema(description = "高") + private String height; + + @Schema(description = "边框") + private String border; + + @Schema(description = "CSS样式") + private String style; + + @Schema(description = "广告图片") + private String images; + + @Schema(description = "广告图片") + @TableField(exist = false) + private JSONArray imageList; + + @Schema(description = "路由/链接地址") + private String path; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "国际化语言") + private String lang; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + public JSONArray getImageList() { + return JSON.parseArray(this.images); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAdRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAdRecord.java new file mode 100644 index 0000000..70c1fc3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAdRecord.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 广告图片 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsAdRecord对象", description = "广告图片") +public class CmsAdRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "ad_record_id", type = IdType.AUTO) + private Integer adRecordId; + + @Schema(description = "广告标题") + private String title; + + @Schema(description = "图片地址") + private String path; + + @Schema(description = "链接地址") + private String url; + + @Schema(description = "广告位ID") + private Integer adId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAdVo.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAdVo.java new file mode 100644 index 0000000..0a13e77 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsAdVo.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "图片DTO", description = "图片DTO") +public class CmsAdVo implements Serializable { + + @Schema(description = "ID") + @TableField(exist = false) + private Integer uid; + + @Schema(description = "名称") + @TableField(exist = false) + private String title; + + @Schema(description = "图片路径") + @TableField(exist = false) + private String url; + + @Schema(description = "视频地址") + @TableField(exist = false) + private String video; + + @Schema(description = "状态") + @TableField(exist = false) + private String status; + + @Schema(description = "图片宽") + @TableField(exist = false) + private Integer width; + + @Schema(description = "图片高") + @TableField(exist = false) + private Integer height; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticle.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticle.java new file mode 100644 index 0000000..32eb9b0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticle.java @@ -0,0 +1,266 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文章 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsArticle对象", description = "文章") +public class CmsArticle implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章ID") + @TableId(value = "article_id", type = IdType.AUTO) + private Integer articleId; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章类型 0常规 1视频") + private Integer type; + + @Schema(description = "文章模型") + private String model; + + @Schema(description = "文章编号") + private String code; + + @Schema(description = "内容模板页面") + private String detail; + + @Schema(description = "banner") + @TableField(exist = false) + private String banner; + + @Schema(description = "访问路径") + @TableField(exist = false) + private String path; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + private Integer showType; + + @Schema(description = "话题") + private String topic; + + @Schema(description = "标签") + private String tags; + + @Schema(description = "文章分类ID") + private Integer categoryId; + + @Schema(description = "当前分类") + @TableField(exist = false) + private String categoryName; + + @Schema(description = "父级分类ID") + private Integer parentId; + + @Schema(description = "父级分类") + @TableField(exist = false) + private String parentName; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "封面图宽度") + private Integer imageWidth; + + @Schema(description = "封面图高度") + private Integer imageHeight; + + @Schema(description = "价格") + private BigDecimal price; + + @Schema(description = "开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime startTime; + + @Schema(description = "到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime endTime; + + @Schema(description = "来源") + private String source; + + @Schema(description = "产品概述") + private String overview; + + @Schema(description = "虚拟阅读量(仅用作展示)") + private Integer virtualViews; + + @Schema(description = "实际阅读量") + private Integer actualViews; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + private Integer permission; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "验证密码(前端回传)") + @TableField(exist = false) + private String password2; + + @Schema(description = "发布来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "文章附件") + private String files; + + @Schema(description = "视频地址") + private String video; + + @Schema(description = "接受的文件类型") + private String accept; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "点赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "提醒谁看") + private String toUsers; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "作者") + private String author; + + @Schema(description = "国际化语言") + private String lang; + + @Schema(description = "关联默认语言的文章ID,用于同步翻译更新") + private Integer langArticleId; + + @Schema(description = "是否启用自动翻译") + private Boolean translation; + + @Schema(description = "编辑器类型 1 富文本编辑器 2 Markdown编辑器") + private Integer editor; + + @Schema(description = "PDF地址") + private String pdfUrl; + + @Schema(description = "版本号") + private Integer version; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "项目ID") + private Long projectId; + + @Schema(description = "商户名称") + @TableField(exist = false) + private String merchantName; + + @Schema(description = "商户名称") + @TableField(exist = false) + private String merchantAvatar; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + private Integer status; + + @Schema(description = "状态文本") + @TableField(exist = false) + private String statusText; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "是否更新") + @TableField(exist = false) + private Boolean isUpdate; + + @Schema(description = "文章内容") + @TableField(exist = false) + private String content; + + @Schema(description = "已报名人数") + private Integer bmUsers; + + public String getStatusText() { + if (this.status == 0) { + return "已发布"; + } + if (this.status == 1) { + return "待审核"; + } + if (this.status == 2) { + return "已驳回"; + } + if (this.status == 3) { + return "违规内容"; + } + return ""; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleCategory.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleCategory.java new file mode 100644 index 0000000..94de0d5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleCategory.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文章分类表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsArticleCategory对象", description = "文章分类表") +public class CmsArticleCategory implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章分类ID") + @TableId(value = "category_id", type = IdType.AUTO) + private Integer categoryId; + + @Schema(description = "分类标识") + private String categoryCode; + + @Schema(description = "分类名称") + private String title; + + @Schema(description = "类型 0列表 1单页 2外链") + private Integer type; + + @Schema(description = "分类图片") + private String image; + + @Schema(description = "上级分类ID") + private Integer parentId; + + @Schema(description = "路由/链接地址") + private String path; + + @Schema(description = "组件路径") + private String component; + + @Schema(description = "绑定的页面") + private Integer pageId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "文章数量") + private Integer count; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + private Integer hide; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否显示在首页") + private Integer showIndex; + + @Schema(description = "状态, 0正常, 1禁用") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleComment.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleComment.java new file mode 100644 index 0000000..9c20894 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleComment.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文章评论表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsArticleComment对象", description = "文章评论表") +public class CmsArticleComment implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "评价ID") + @TableId(value = "comment_id", type = IdType.AUTO) + private Integer commentId; + + @Schema(description = "文章ID") + private Integer articleId; + + @Schema(description = "评分 (10好评 20中评 30差评)") + private Integer score; + + @Schema(description = "评价内容") + private String content; + + @Schema(description = "是否为图片评价") + private Integer isPicture; + + @Schema(description = "评论者ID") + private Integer userId; + + @Schema(description = "被评价者ID") + private Integer toUserId; + + @Schema(description = "回复的评论ID") + private Integer replyCommentId; + + @Schema(description = "回复者ID") + private Integer replyUserId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0未读, 1已读") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleContent.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleContent.java new file mode 100644 index 0000000..a06b349 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleContent.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文章记录表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsArticleContent对象", description = "文章记录表") +public class CmsArticleContent implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "文章ID") + private Integer articleId; + + @Schema(description = "文章内容") + private String content; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleCount.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleCount.java new file mode 100644 index 0000000..87c7108 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleCount.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 点赞文章 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsArticleCount对象", description = "点赞文章") +public class CmsArticleCount implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "文章ID") + private Integer articleId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleLike.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleLike.java new file mode 100644 index 0000000..5c0dfb8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsArticleLike.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 点赞文章 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsArticleLike对象", description = "点赞文章") +public class CmsArticleLike implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "文章ID") + private Integer articleId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDesign.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDesign.java new file mode 100644 index 0000000..9218b0a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDesign.java @@ -0,0 +1,122 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 页面管理记录表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsDesign对象", description = "页面管理记录表") +public class CmsDesign implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "page_id", type = IdType.AUTO) + private Integer pageId; + + @Schema(description = "页面") + private String name; + + @Schema(description = "所属栏目ID") + private Integer categoryId; + + @Schema(description = "所属栏目") + @TableField(exist = false) + private String categoryName; + + @Schema(description = "页面模型") + private String model; + + @Schema(description = "页面关键词") + private String keywords; + + @Schema(description = "页面描述") + private String description; + + @Schema(description = "路由地址") + @TableField(exist = false) + private String path; + + @Schema(description = "组件路径") + @TableField(exist = false) + private String component; + + @Schema(description = "缩列图") + private String photo; + + @Schema(description = "购买链接") + private String buyUrl; + + @Schema(description = "页面样式") + private String style; + + @Schema(description = "页面内容") + private String content; + + @Schema(description = "是否开启布局") + private Boolean showLayout; + + @Schema(description = "页面布局") + @TableField(exist = false) + private String layout; + + @Schema(description = "是否显示banner") + private Boolean showBanner; + + @Schema(description = "是否显示Button") + private Boolean showButton; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "国际化语言") + private String lang; + + @Schema(description = "用于同步翻译内容") + @TableField(exist = false) + private Integer langCategoryId; + + @Schema(description = "是否启用自动翻译") + private Boolean translation; + + @Schema(description = "设为首页") + private Integer home; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDesignRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDesignRecord.java new file mode 100644 index 0000000..292f1ef --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDesignRecord.java @@ -0,0 +1,75 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 页面组件表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsDesignRecord对象", description = "页面组件表") +public class CmsDesignRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "关联导航ID") + private Integer navigationId; + + @Schema(description = "组件") + private String title; + + @Schema(description = "组件标识") + private String dictCode; + + @Schema(description = "组件样式") + private String styles; + + @Schema(description = "卡片阴影显示时机") + private String shadow; + + @Schema(description = "页面关键词") + private String keywords; + + @Schema(description = "页面描述") + private String description; + + @Schema(description = "页面路由地址") + private String path; + + @Schema(description = "缩列图") + private String photo; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDomain.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDomain.java new file mode 100644 index 0000000..fc4f445 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsDomain.java @@ -0,0 +1,72 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 网站域名记录表 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsDomain对象", description = "网站域名记录表") +public class CmsDomain implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "类型 0赠送域名 1绑定域名 ") + private Integer type; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "主机记录") + private String hostName; + + @Schema(description = "记录值") + private String hostValue; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "网站ID") + private Integer websiteId; + + @Schema(description = "租户ID") + private Integer appId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsForm.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsForm.java new file mode 100644 index 0000000..4f0f0f5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsForm.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.cms.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 表单设计表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsForm对象", description = "表单设计表") +public class CmsForm implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "form_id", type = IdType.AUTO) + private Integer formId; + + @Schema(description = "表单标题") + private String name; + + @Schema(description = "顶部图片") + private String photo; + + @Schema(description = "背景图片") + private String background; + + @Schema(description = "视频文件") + private String video; + + @Schema(description = "提交次数") + private Integer submitNumber; + + @Schema(description = "页面布局") + private String layout; + + @Schema(description = "是否隐藏顶部图片") + private Integer hidePhoto; + + @Schema(description = "是否隐藏背景图片") + private Integer hideBackground; + + @Schema(description = "是否隐藏视频") + private Integer hideVideo; + + @Schema(description = "背景图片透明度") + private BigDecimal opacity; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "国际化语言") + private String lang; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsFormRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsFormRecord.java new file mode 100644 index 0000000..4e22a42 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsFormRecord.java @@ -0,0 +1,68 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 表单数据记录表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsFormRecord对象", description = "表单数据记录表") +public class CmsFormRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "form_record_id", type = IdType.AUTO) + private Integer formRecordId; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "表单数据") + private String formData; + + @Schema(description = "表单ID") + private Integer formId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLang.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLang.java new file mode 100644 index 0000000..b25db1c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLang.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 国际化 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsLang对象", description = "国际化") +public class CmsLang implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "名称") + private String name; + + @Schema(description = "编码") + private String code; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLangLog.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLangLog.java new file mode 100644 index 0000000..ea2948f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLangLog.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 国际化记录启用 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsLangLog对象", description = "国际化记录启用") +public class CmsLangLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "名称") + private String lang; + + @Schema(description = "关联ID") + private Integer langId; + + @Schema(description = "编码") + private String code; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLink.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLink.java new file mode 100644 index 0000000..690f4c9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsLink.java @@ -0,0 +1,79 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 常用链接 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsLink对象", description = "常用链接") +public class CmsLink implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "链接名称") + private String name; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "链接地址") + private String url; + + @Schema(description = "栏目ID") + private Integer categoryId; + + @Schema(description = "应用ID") + private Integer appId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "国际化语言") + private String lang; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "状态, 0正常, 1待确认") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "栏目名称") + @TableField(exist = false) + private String categoryName; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsModel.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsModel.java new file mode 100644 index 0000000..97c5943 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsModel.java @@ -0,0 +1,97 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 模型 + * + * @author 科技小王子 + * @since 2024-11-26 15:44:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsModel对象", description = "模型") +public class CmsModel implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "model_id", type = IdType.AUTO) + private Integer modelId; + + @Schema(description = "模型名称") + private String name; + + @Schema(description = "唯一标识") + private String model; + + @Schema(description = "列表页路径") + private String component; + + @Schema(description = "详情页路径") + private String componentDetail; + + @Schema(description = "模型banner图片") + private String banner; + + @Schema(description = "文章后缀") + private String suffix; + + @Schema(description = "拇指图片") + private String thumb; + + @Schema(description = "封面图宽") + private String imageWidth; + + @Schema(description = "封面图高") + private String imageHeight; + + @Schema(description = "css样式") + private String style; + + @Schema(description = "Banner上的标题") + private String title; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + private Integer showType; + + @Schema(description = "是否禁用") + private Boolean disabled; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsNavigation.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsNavigation.java new file mode 100644 index 0000000..bc60ca3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsNavigation.java @@ -0,0 +1,240 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 网站导航记录表 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsNavigation对象", description = "网站导航记录表") +public class CmsNavigation implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "navigation_id", type = IdType.AUTO) + private Integer navigationId; + + @Schema(description = "类型, 0列表 1图文") + private Integer type; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "模型") + private String model; + + @Schema(description = "标识") + private String code; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址, 目录可为空") + private String component; + + @Schema(description = "文件后缀") + @TableField(exist = false) + private String suffix; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "banner") + @TableField(exist = false) + private String banner; + + @Schema(description = "移动端banner") + @TableField(exist = false) + private String mpBanner; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + private Integer hide; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + private Integer permission; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "验证密码(前端回传)") + @TableField(exist = false) + private String password2; + + @Schema(description = "位置 0不限 1顶部 2底部") + private Integer position; + + @Schema(description = "仅在顶部显示") + private Integer top; + + @Schema(description = "仅在底部显示") + private Integer bottom; + + @Schema(description = "菜单侧栏选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "css样式") + private String style; + + @Schema(description = "父级栏目路由") + private String parentPath; + + @Schema(description = "父级栏目名称") + private String parentName; + + @Schema(description = "父级栏目位置") + @TableField(exist = false) + private Integer parentPosition; + + @Schema(description = "模型名称") + private String modelName; + + @Schema(description = "绑定的页面(已废弃)") + private Integer pageId; + + @Schema(description = "详情页ID") + private Integer itemId; + + @Schema(description = "是否微信小程序菜单") + private Boolean isMpWeixin; + + @Schema(description = "菜单间距") + private Integer gutter; + + @Schema(description = "菜单宽度") + private Integer span; + + @Schema(description = "阅读量") + private Integer readNum; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "国际化语言") + private String lang; + + @Schema(description = "用于同步翻译内容") + private Integer langCategoryId; + + @Schema(description = "设为首页") + private Integer home; + + @Schema(description = "是否推荐") + private Boolean recommend; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonIgnore // 导航的创建时间前端不需要 + private LocalDateTime createTime; + + + @Schema(description = "页面名称") + @TableField(exist = false) + private String pageName; + + @Schema(description = "子菜单") + @TableField(exist = false) + private List children; + + @Schema(description = "页面布局") + @TableField(exist = false) + private String layout; + + @Schema(description = "关联的页面") + @TableField(exist = false) + private CmsDesign design; + + @Schema(description = "所属模型") + @TableField(exist = false) + private CmsModel modelInfo; + + @Schema(description = "父级栏目") + @TableField(exist = false) + private CmsNavigation parent; + + @Schema(description = "当前栏目名称") + @TableField(exist = false) + private String categoryName; + + @Schema(description = "当前栏目链接") + @TableField(exist = false) + private String categoryPath; + + @Schema(description = "栏目图片") + @TableField(exist = false) + private String photo; + + @Schema(description = "是否开启布局") + @TableField(exist = false) + private Boolean showLayout; + + @Schema(description = "单页内容") + @TableField(exist = false) + private String content; + + @Schema(description = "是否显示banner") + @TableField(exist = false) + private Boolean showBanner; + + @Schema(description = "菜单标题") + @TableField(exist = false) + private String text; + + public String getCategoryName() { + return this.title; + } + + public String getCategoryPath() { + return this.path; + } + + public String getText() { + return this.title; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsStatistics.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsStatistics.java new file mode 100644 index 0000000..de7c8ad --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsStatistics.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.cms.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDate; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 站点统计信息表 + * + * @author 科技小王子 + * @since 2025-07-25 12:32:06 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsStatistics对象", description = "站点统计信息表") +public class CmsStatistics implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "站点ID") + private Integer websiteId; + + @Schema(description = "用户总数") + private Integer userCount; + + @Schema(description = "订单总数") + private Integer orderCount; + + @Schema(description = "商品总数") + private Integer productCount; + + @Schema(description = "总销售额") + private BigDecimal totalSales; + + @Schema(description = "本月销售额") + private BigDecimal monthSales; + + @Schema(description = "今日销售额") + private BigDecimal todaySales; + + @Schema(description = "昨日销售额") + private BigDecimal yesterdaySales; + + @Schema(description = "本周销售额") + private BigDecimal weekSales; + + @Schema(description = "本年销售额") + private BigDecimal yearSales; + + @Schema(description = "今日订单数") + private Integer todayOrders; + + @Schema(description = "本月订单数") + private Integer monthOrders; + + @Schema(description = "今日新增用户") + private Integer todayUsers; + + @Schema(description = "本月新增用户") + private Integer monthUsers; + + @Schema(description = "今日访问量") + private Integer todayVisits; + + @Schema(description = "总访问量") + private Integer totalVisits; + + @Schema(description = "商户总数") + private Integer merchantCount; + + @Schema(description = "活跃用户数") + private Integer activeUsers; + + @Schema(description = "转化率(%)") + private BigDecimal conversionRate; + + @Schema(description = "平均订单金额") + private BigDecimal avgOrderAmount; + + @Schema(description = "统计日期") + private LocalDate statisticsDate; + + @Schema(description = "统计类型: 1日统计, 2月统计, 3年统计") + private Integer statisticsType; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "操作用户ID") + private Integer userId; + + @Schema(description = "商户ID") + private Integer merchantId; + + @Schema(description = "状态: 0禁用, 1启用") + private Boolean status; + + @Schema(description = "是否删除: 0否, 1是") + @TableLogic + private Boolean deleted; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsTemplate.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsTemplate.java new file mode 100644 index 0000000..7e10240 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsTemplate.java @@ -0,0 +1,97 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 网站模版 + * + * @author 科技小王子 + * @since 2025-01-21 14:21:16 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsTemplate对象", description = "网站模版") +public class CmsTemplate implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "模版名称") + private String name; + + @Schema(description = "模版标识") + private String code; + + @Schema(description = "缩列图") + private String image; + + @Schema(description = "类型 1企业官网 2其他") + private Integer type; + + @Schema(description = "网站关键词") + private String keywords; + + @Schema(description = "域名前缀") + private String prefix; + + @Schema(description = "预览地址") + private String domain; + + @Schema(description = "模版下载地址") + private String downUrl; + + @Schema(description = "色系") + private String color; + + @Schema(description = "应用版本 10免费版 20授权版 30永久授权") + private Integer version; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否推荐") + private Boolean recommend; + + @Schema(description = "是否共享模板") + private Boolean share; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsite.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsite.java new file mode 100644 index 0000000..b0f3d6c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsite.java @@ -0,0 +1,326 @@ +package com.gxwebsoft.cms.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 网站信息记录表 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsWebsite对象", description = "网站信息记录表") +public class CmsWebsite implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "站点ID") + @TableId(value = "website_id", type = IdType.AUTO) + private Integer websiteId; + + @Schema(description = "网站名称") + private String websiteName; + + @Schema(description = "网站标识") + private String websiteCode; + + @Schema(description = "网站密钥") + private String websiteSecret; + + @Schema(description = "网站LOGO") + private String websiteIcon; + + @Schema(description = "网站LOGO") + private String websiteLogo; + + @Schema(description = "网站LOGO(深色模式)") + private String websiteDarkLogo; + + @Schema(description = "网站类型") + private String websiteType; + + @Schema(description = "栏目ID") + private Integer categoryId; + + @Schema(description = "应用ID") + @TableField(exist = false) + private Integer appId; + + @Schema(description = "网站截图") + private String files; + + @Schema(description = "网站类型 10企业官网 20微信小程序 30APP 40其他") + private Integer type; + + @Schema(description = "网站关键词") + private String keywords; + + @Schema(description = "域名前缀") + private String prefix; + + @Schema(description = "绑定域名") + private String domain; + + @Schema(description = "全局样式") + private String style; + + @Schema(description = "后台管理地址") + private String adminUrl; + + @Schema(description = "自定义API接口") + private String apiUrl; + + @Schema(description = "应用版本 10免费版 20授权版 30永久授权") + private Integer version; + + @Schema(description = "服务到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date expirationTime; + + @Schema(description = "是否到期") + @TableField(exist = false) + private Integer expired; + + @Schema(description = "剩余天数") + @TableField(exist = false) + private Long expiredDays; + + @Schema(description = "服务器ID") + private Integer assetsId; + + @Schema(description = "服务器ID") + private String assetsName; + + @Schema(description = "模版ID(存克隆的租户UID)") + private Integer templateId; + + @Schema(description = "模版名称") + @TableField(exist = false) + private String templateName; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "开发者名称") + private String developer; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "电子邮箱") + private String email; + + @Schema(description = "ICP备案号") + private String icpNo; + + @Schema(description = "公安备案") + private String policeNo; + + @Schema(description = "网站描述") + private String content; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "管理员备注") + private String remarks; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否官方产品") + private Boolean official; + + @Schema(description = "允许展示到插件市场") + private Boolean market; + + @Schema(description = "是否插件类型 0应用 1插件") + private Boolean plugin; + + @Schema(description = "允许被搜索") + private Boolean search; + + @Schema(description = "主题色") + private String color; + + @Schema(description = "运行状态 0运行中 1已关闭 2维护中") + private Integer running; + + @Schema(description = "即将过期") + private Integer soon; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "点赞数量") + private Integer likes; + + @Schema(description = "点击数量") + private Integer clicks; + + @Schema(description = "购买数量") + private Integer buys; + + @Schema(description = "下载数量") + private Integer downloads; + + @Schema(description = "销售价格") + private BigDecimal price; + + @Schema(description = "交付方式") + private Integer deliveryMethod; + + @Schema(description = "计费方式") + private Integer chargingMethod; + + @Schema(description = "状态 0未开通 1运行中 2维护中 3已关闭 4已欠费停机 5违规关停") + private Integer status; + + @Schema(description = "状态图标") + @TableField(exist = false) + private String statusIcon; + + @Schema(description = "维护说明") + private String statusText; + + @Schema(description = "关闭说明") + private String statusClose; + + @Schema(description = "全局样式") + private String styles; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @Schema(description = "预设字段") + @TableField(exist = false) + private List fields; + + @Schema(description = "小程序导航图标") + @TableField(exist = false) + private Map> mpMenus; + + @Schema(description = "网站导航栏") + @TableField(exist = false) + private List navigations; + + @Schema(description = "顶部菜单") + @TableField(exist = false) + private List topNavs; + + @Schema(description = "底部菜单") + @TableField(exist = false) + private List bottomNavs; + + @Schema(description = "幻灯片广告") + @TableField(exist = false) + private CmsAd slide; + + @Schema(description = "站点广告") + @TableField(exist = false) + private List ads; + + @Schema(description = "首页布局") + @TableField(exist = false) + private String layout; + + @Schema(description = "友情链接") + @TableField(exist = false) + private List links; + + @Schema(description = "配置信息") + @TableField(exist = false) + private Object config; + + @Schema(description = "服务器时间") + @TableField(exist = false) + private HashMap serverTime; + + @Schema(description = "当前登录用户") + @TableField(exist = false) + private User loginUser; + + @Schema(description = "超管账号") + @TableField(exist = false) + private String superAdminPhone; + + @Schema(description = "是否登录") + @TableField(exist = false) + private Boolean isLogin; + + @Schema(description = "网站设置") + @TableField(exist = false) + private CmsWebsiteSetting setting; + + public String getPhone(){ + return DesensitizedUtil.mobilePhone(this.phone); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsiteField.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsiteField.java new file mode 100644 index 0000000..afa7e29 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsiteField.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsWebsiteField对象", description = "应用参数") +public class CmsWebsiteField implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "类型,0文本 1图片 2其他") + private Integer type; + + @Schema(description = "名称") + private String name; + + @Schema(description = "默认值") + private String defaultValue; + + @Schema(description = "可修改的值 [on|off]") + private String modifyRange; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "css样式") + private String style; + + @Schema(description = "名称") + private String value; + + @Schema(description = "国际化语言") + private String lang; + + @Schema(description = "是否加密") + private Boolean encrypted; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsiteSetting.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsiteSetting.java new file mode 100644 index 0000000..5adb085 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/CmsWebsiteSetting.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 网站设置 + * + * @author 科技小王子 + * @since 2025-02-19 01:35:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsWebsiteSetting对象", description = "网站设置") +public class CmsWebsiteSetting implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "关联网站ID") + private Integer websiteId; + + @Schema(description = "是否官方插件") + private Boolean official; + + @Schema(description = "是否展示在插件市场") + private Boolean market; + + @Schema(description = "是否允许被搜索") + private Boolean search; + + @Schema(description = "是否共享") + private Boolean share; + + @Schema(description = "文章是否需要审核") + private Boolean articleReview; + + @Schema(description = "是否插件 0应用1 插件 ") + private Boolean plugin; + + @Schema(description = "编辑器类型 1 富文本编辑器 2 Markdown编辑器") + private Integer editor; + + @Schema(description = "显示站内搜索") + private Boolean searchBtn; + + @Schema(description = "显示登录注册功能") + private Boolean loginBtn; + + @Schema(description = "显示悬浮客服工具") + private Boolean floatTool; + + @Schema(description = "显示版权链接") + private Boolean copyrightLink; + + @Schema(description = "导航栏最多显示数量") + private Boolean maxMenuNum; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/TranslateDataVo.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/TranslateDataVo.java new file mode 100644 index 0000000..b858289 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/TranslateDataVo.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "翻译结果", description = "翻译结果") +public class TranslateDataVo implements Serializable { + + @Schema(description = "文本格式") + private String FormatType; + + @Schema(description = "原文语言") + private String SourceLanguage; + + @Schema(description = "译文语言") + private String TargetLanguage; + + @Schema(description = "待翻译内容") + private String SourceText; + + @Schema(description = "场景可选取值:商品标题(title),商品描述(description),商品沟通(communication),医疗(medical),社交(social),金融(finance)") + private String Scene; + + @Schema(description = "上下文信息") + private String Context; + + @Schema(description = "翻译结果") + private String translated; + + @Schema(description = "总单词数") + private String wordCount; + + @Schema(description = "源语言传入 auto 时,语种识别后的源语言代码") + private String detectedLanguage; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/TranslateVo.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/TranslateVo.java new file mode 100644 index 0000000..e7e0662 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/entity/TranslateVo.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "阿里云机器翻译", description = "阿里云机器翻译") +public class TranslateVo implements Serializable { + + @Schema(description = "错误码") + private String Code; + + @Schema(description = "错误信息") + @JsonIgnoreProperties(ignoreUnknown = true) + private String Message; + + @Schema(description = "请求ID") + private String RequestId; + + @Schema(description = "返回数据") + private TranslateDataVo Data; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsAdMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsAdMapper.java new file mode 100644 index 0000000..836fa83 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsAdMapper.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsAd; +import com.gxwebsoft.cms.entity.CmsLangLog; +import com.gxwebsoft.cms.param.CmsAdParam; +import com.gxwebsoft.cms.param.CmsLangLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 广告位Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsAdMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsAdParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsAdParam param); + + @InterceptorIgnore(tenantLine = "true") + List selectListAllRel(@Param("param") CmsAdParam param); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsAdRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsAdRecordMapper.java new file mode 100644 index 0000000..329956e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsAdRecordMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsAdRecord; +import com.gxwebsoft.cms.param.CmsAdRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 广告图片Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsAdRecordMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsAdRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsAdRecordParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCategoryMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCategoryMapper.java new file mode 100644 index 0000000..d540f29 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCategoryMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsArticleCategory; +import com.gxwebsoft.cms.param.CmsArticleCategoryParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文章分类表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleCategoryMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsArticleCategoryParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsArticleCategoryParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCommentMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCommentMapper.java new file mode 100644 index 0000000..ed20748 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCommentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsArticleComment; +import com.gxwebsoft.cms.param.CmsArticleCommentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文章评论表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleCommentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsArticleCommentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsArticleCommentParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleContentMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleContentMapper.java new file mode 100644 index 0000000..2a39ca9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleContentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsArticleContent; +import com.gxwebsoft.cms.param.CmsArticleContentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文章记录表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleContentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsArticleContentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsArticleContentParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCountMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCountMapper.java new file mode 100644 index 0000000..596a640 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleCountMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsArticleCount; +import com.gxwebsoft.cms.param.CmsArticleCountParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 点赞文章Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleCountMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsArticleCountParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsArticleCountParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleLikeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleLikeMapper.java new file mode 100644 index 0000000..f6eba4b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleLikeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsArticleLike; +import com.gxwebsoft.cms.param.CmsArticleLikeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 点赞文章Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleLikeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsArticleLikeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsArticleLikeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleMapper.java new file mode 100644 index 0000000..18c2506 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsArticleMapper.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsArticle; +import com.gxwebsoft.cms.entity.CmsLangLog; +import com.gxwebsoft.cms.param.CmsArticleParam; +import com.gxwebsoft.cms.param.CmsLangLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文章Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsArticleParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsArticleParam param); + + + @InterceptorIgnore(tenantLine = "true") + List selectListAllRel(@Param("param") CmsArticleParam param); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDesignMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDesignMapper.java new file mode 100644 index 0000000..5542ff7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDesignMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsDesign; +import com.gxwebsoft.cms.param.CmsDesignParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 页面管理记录表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsDesignMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsDesignParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsDesignParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDesignRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDesignRecordMapper.java new file mode 100644 index 0000000..dd25171 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDesignRecordMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsDesignRecord; +import com.gxwebsoft.cms.param.CmsDesignRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 页面组件表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsDesignRecordMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsDesignRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsDesignRecordParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDomainMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDomainMapper.java new file mode 100644 index 0000000..e561b20 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsDomainMapper.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsDomain; +import com.gxwebsoft.cms.param.CmsDomainParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 网站域名记录表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +public interface CmsDomainMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsDomainParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsDomainParam param); + + @InterceptorIgnore(tenantLine = "true") + CmsDomain getDomain(@Param("domain") String domain); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsFormMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsFormMapper.java new file mode 100644 index 0000000..ab12d1a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsFormMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsForm; +import com.gxwebsoft.cms.param.CmsFormParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 表单设计表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsFormMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsFormParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsFormParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsFormRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsFormRecordMapper.java new file mode 100644 index 0000000..b766f7b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsFormRecordMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsFormRecord; +import com.gxwebsoft.cms.param.CmsFormRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 表单数据记录表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsFormRecordMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsFormRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsFormRecordParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLangLogMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLangLogMapper.java new file mode 100644 index 0000000..70c8678 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLangLogMapper.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsLangLog; +import com.gxwebsoft.cms.param.CmsLangLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 国际化记录启用Mapper + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +public interface CmsLangLogMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsLangLogParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsLangLogParam param); + + @InterceptorIgnore(tenantLine = "true") + List selectListAllRel(@Param("param") CmsLangLogParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLangMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLangMapper.java new file mode 100644 index 0000000..b8705df --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLangMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsLang; +import com.gxwebsoft.cms.param.CmsLangParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 国际化Mapper + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +public interface CmsLangMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsLangParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsLangParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLinkMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLinkMapper.java new file mode 100644 index 0000000..915b1f1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsLinkMapper.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsLangLog; +import com.gxwebsoft.cms.entity.CmsLink; +import com.gxwebsoft.cms.param.CmsLangLogParam; +import com.gxwebsoft.cms.param.CmsLinkParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 常用链接Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsLinkMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsLinkParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsLinkParam param); + + + @InterceptorIgnore(tenantLine = "true") + List selectListAllRel(@Param("param") CmsLinkParam param); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsModelMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsModelMapper.java new file mode 100644 index 0000000..6fe0a36 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsModelMapper.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsModel; +import com.gxwebsoft.cms.param.CmsModelParam; +import com.gxwebsoft.cms.param.CmsWebsiteFieldParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 模型Mapper + * + * @author 科技小王子 + * @since 2024-11-26 15:44:53 + */ +public interface CmsModelMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsModelParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsModelParam param); + + @InterceptorIgnore(tenantLine = "true") + List selectListAllRel(@Param("param") CmsModelParam param); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsNavigationMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsNavigationMapper.java new file mode 100644 index 0000000..e0fcfac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsNavigationMapper.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsModel; +import com.gxwebsoft.cms.entity.CmsNavigation; +import com.gxwebsoft.cms.param.CmsModelParam; +import com.gxwebsoft.cms.param.CmsNavigationParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 网站导航记录表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsNavigationMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsNavigationParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsNavigationParam param); + + + @InterceptorIgnore(tenantLine = "true") + List selectListAllRel(@Param("param") CmsNavigationParam param); + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsStatisticsMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsStatisticsMapper.java new file mode 100644 index 0000000..160d5be --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsStatisticsMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsStatistics; +import com.gxwebsoft.cms.param.CmsStatisticsParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 站点统计信息表Mapper + * + * @author 科技小王子 + * @since 2025-07-25 12:32:06 + */ +public interface CmsStatisticsMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsStatisticsParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsStatisticsParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsTemplateMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsTemplateMapper.java new file mode 100644 index 0000000..7cd4485 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsTemplateMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsTemplate; +import com.gxwebsoft.cms.param.CmsTemplateParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 网站模版Mapper + * + * @author 科技小王子 + * @since 2025-01-21 14:21:16 + */ +public interface CmsTemplateMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsTemplateParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsTemplateParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteFieldMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteFieldMapper.java new file mode 100644 index 0000000..b92614d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteFieldMapper.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsWebsiteField; +import com.gxwebsoft.cms.param.CmsWebsiteFieldParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用参数Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +public interface CmsWebsiteFieldMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsWebsiteFieldParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsWebsiteFieldParam param); + + + @InterceptorIgnore(tenantLine = "true") + List selectListAllRel(@Param("param") CmsWebsiteFieldParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteMapper.java new file mode 100644 index 0000000..c24e345 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteMapper.java @@ -0,0 +1,53 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsWebsite; +import com.gxwebsoft.cms.param.CmsWebsiteParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 网站信息记录表Mapper + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +public interface CmsWebsiteMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsWebsiteParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsWebsiteParam param); + + @InterceptorIgnore(tenantLine = "true") + List selectPageRelAll(@Param("page") IPage page, + @Param("param") CmsWebsiteParam param); + + @InterceptorIgnore(tenantLine = "true") + CmsWebsite getByIdRelAll(@Param("websiteId") Integer id); + + @InterceptorIgnore(tenantLine = "true") + boolean updateByIdAll(@Param("param") CmsWebsite cmsWebsite); + + @InterceptorIgnore(tenantLine = "true") + boolean removeByIdAll(@Param("websiteId") Integer id); + + @InterceptorIgnore(tenantLine = "true") + CmsWebsite getByTenantId(@Param("tenantId") Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteSettingMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteSettingMapper.java new file mode 100644 index 0000000..dc468fd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/CmsWebsiteSettingMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsWebsiteSetting; +import com.gxwebsoft.cms.param.CmsWebsiteSettingParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 网站设置Mapper + * + * @author 科技小王子 + * @since 2025-02-19 01:35:44 + */ +public interface CmsWebsiteSettingMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsWebsiteSettingParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsWebsiteSettingParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsAdMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsAdMapper.xml new file mode 100644 index 0000000..6ee7cbf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsAdMapper.xml @@ -0,0 +1,92 @@ + + + + + + + SELECT a.*, b.user_id as websiteUserId, c.title as categoryName + FROM cms_ad a + LEFT JOIN cms_website b ON a.tenant_id = b.tenant_id + LEFT JOIN cms_navigation c ON a.category_id = c.navigation_id + + + AND a.ad_id = #{param.adId} + + + AND a.type = #{param.type} + + + AND a.code = #{param.code} + + + AND a.category_id = #{param.categoryId} + + + AND a.lang = #{param.lang} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.width LIKE CONCAT('%', #{param.width}, '%') + + + AND a.height LIKE CONCAT('%', #{param.height}, '%') + + + AND a.images LIKE CONCAT('%', #{param.images}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.user_id = #{param.userId} + + + AND b.user_id = #{param.websiteUserId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.ad_id = #{param.keywords} + ) + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsAdRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsAdRecordMapper.xml new file mode 100644 index 0000000..959667a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsAdRecordMapper.xml @@ -0,0 +1,53 @@ + + + + + + + SELECT a.* + FROM cms_ad_record a + + + AND a.ad_record_id = #{param.adRecordId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.url LIKE CONCAT('%', #{param.url}, '%') + + + AND a.ad_id = #{param.adId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCategoryMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCategoryMapper.xml new file mode 100644 index 0000000..f548eb4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCategoryMapper.xml @@ -0,0 +1,86 @@ + + + + + + + SELECT a.* + FROM cms_article_category a + + + AND a.category_id = #{param.categoryId} + + + AND a.category_code LIKE CONCAT('%', #{param.categoryCode}, '%') + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.type = #{param.type} + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.parent_id = #{param.parentId} + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.component LIKE CONCAT('%', #{param.component}, '%') + + + AND a.page_id = #{param.pageId} + + + AND a.user_id = #{param.userId} + + + AND a.count = #{param.count} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.hide = #{param.hide} + + + AND a.recommend = #{param.recommend} + + + AND a.show_index = #{param.showIndex} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCommentMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCommentMapper.xml new file mode 100644 index 0000000..8d82a95 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCommentMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.* + FROM cms_article_comment a + + + AND a.comment_id = #{param.commentId} + + + AND a.article_id = #{param.articleId} + + + AND a.score = #{param.score} + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.is_picture = #{param.isPicture} + + + AND a.user_id = #{param.userId} + + + AND a.to_user_id = #{param.toUserId} + + + AND a.reply_comment_id = #{param.replyCommentId} + + + AND a.reply_user_id = #{param.replyUserId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleContentMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleContentMapper.xml new file mode 100644 index 0000000..de251b4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleContentMapper.xml @@ -0,0 +1,38 @@ + + + + + + + SELECT a.* + FROM cms_article_content a + + + AND a.id = #{param.id} + + + AND a.article_id = #{param.articleId} + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCountMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCountMapper.xml new file mode 100644 index 0000000..d714ed3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleCountMapper.xml @@ -0,0 +1,38 @@ + + + + + + + SELECT a.* + FROM cms_article_count a + + + AND a.id = #{param.id} + + + AND a.article_id = #{param.articleId} + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleLikeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleLikeMapper.xml new file mode 100644 index 0000000..b33ff0c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleLikeMapper.xml @@ -0,0 +1,38 @@ + + + + + + + SELECT a.* + FROM cms_article_like a + + + AND a.id = #{param.id} + + + AND a.article_id = #{param.articleId} + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleMapper.xml new file mode 100644 index 0000000..d46baf8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsArticleMapper.xml @@ -0,0 +1,187 @@ + + + + + + + SELECT a.*,b.title as categoryName,b.parent_Id as parentId, b.model,c.title as parentName,u.nickname,u.avatar + FROM cms_article a + LEFT JOIN cms_navigation b ON a.category_id = b.navigation_id + LEFT JOIN cms_navigation c ON b.parent_id = c.navigation_id + LEFT JOIN gxwebsoft_core.sys_user u ON a.user_id = u.user_id + + + AND a.article_id = #{param.articleId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.type = #{param.type} + + + AND a.lang = #{param.lang} + + + AND a.model = #{param.model} + + + AND a.code = #{param.code} + + + AND a.detail = #{param.detail} + + + AND a.show_type = #{param.showType} + + + AND a.topic LIKE CONCAT('%', #{param.topic}, '%') + + + AND a.category_id = #{param.categoryId} + + + AND a.category_id IN + + #{item} + + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.image != '' + + + AND a.source LIKE CONCAT('%', #{param.source}, '%') + + + AND a.virtual_views = #{param.virtualViews} + + + AND a.actual_views = #{param.actualViews} + + + AND a.platform LIKE CONCAT('%', #{param.platform}, '%') + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.video LIKE CONCAT('%', #{param.video}, '%') + + + AND a.accept LIKE CONCAT('%', #{param.accept}, '%') + + + AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%') + + + AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.likes = #{param.likes} + + + AND a.comment_numbers = #{param.commentNumbers} + + + AND a.to_users LIKE CONCAT('%', #{param.toUsers}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.project_id = #{param.projectId} + + + AND a.tags LIKE CONCAT('%', #{param.tags}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.recommend = #{param.recommend} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.article_id IN + + #{item} + + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.article_id = #{param.keywords} + OR a.detail = #{param.keywords} + OR a.title LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignMapper.xml new file mode 100644 index 0000000..def6547 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignMapper.xml @@ -0,0 +1,93 @@ + + + + + + + SELECT a.*,b.lang_category_id, b.title as categoryName + FROM cms_design a + LEFT JOIN cms_navigation b ON a.category_id = b.navigation_id + + + AND a.page_id = #{param.pageId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.lang = #{param.lang} + + + AND a.category_id = #{param.categoryId} + + + AND a.model = #{param.model} + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.photo LIKE CONCAT('%', #{param.photo}, '%') + + + AND a.buy_url LIKE CONCAT('%', #{param.buyUrl}, '%') + + + AND a.style LIKE CONCAT('%', #{param.style}, '%') + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.show_layout = #{param.showLayout} + + + AND a.layout LIKE CONCAT('%', #{param.layout}, '%') + + + AND a.parent_id = #{param.parentId} + + + AND a.user_id = #{param.userId} + + + AND a.home = #{param.home} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignRecordMapper.xml new file mode 100644 index 0000000..0ff62ef --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDesignRecordMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.* + FROM cms_design_record a + + + AND a.id = #{param.id} + + + AND a.navigation_id = #{param.navigationId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.dict_code LIKE CONCAT('%', #{param.dictCode}, '%') + + + AND a.styles LIKE CONCAT('%', #{param.styles}, '%') + + + AND a.shadow LIKE CONCAT('%', #{param.shadow}, '%') + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.photo LIKE CONCAT('%', #{param.photo}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDomainMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDomainMapper.xml new file mode 100644 index 0000000..dc39215 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsDomainMapper.xml @@ -0,0 +1,65 @@ + + + + + + + SELECT a.* + FROM cms_domain a + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.host_name LIKE CONCAT('%', #{param.hostName}, '%') + + + AND a.host_value LIKE CONCAT('%', #{param.hostValue}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.website_id = #{param.websiteId} + + + AND a.app_id = #{param.appId} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsFormMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsFormMapper.xml new file mode 100644 index 0000000..5b2d2b1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsFormMapper.xml @@ -0,0 +1,83 @@ + + + + + + + SELECT a.* + FROM cms_form a + + + AND a.form_id = #{param.formId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.photo LIKE CONCAT('%', #{param.photo}, '%') + + + AND a.background LIKE CONCAT('%', #{param.background}, '%') + + + AND a.video LIKE CONCAT('%', #{param.video}, '%') + + + AND a.submit_number = #{param.submitNumber} + + + AND a.layout LIKE CONCAT('%', #{param.layout}, '%') + + + AND a.hide_photo = #{param.hidePhoto} + + + AND a.hide_background = #{param.hideBackground} + + + AND a.hide_video = #{param.hideVideo} + + + AND a.opacity = #{param.opacity} + + + AND a.user_id = #{param.userId} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsFormRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsFormRecordMapper.xml new file mode 100644 index 0000000..f646c1e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsFormRecordMapper.xml @@ -0,0 +1,65 @@ + + + + + + + SELECT a.* + FROM cms_form_record a + + + AND a.form_record_id = #{param.formRecordId} + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.form_data LIKE CONCAT('%', #{param.formData}, '%') + + + AND a.form_id = #{param.formId} + + + AND a.user_id = #{param.userId} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLangLogMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLangLogMapper.xml new file mode 100644 index 0000000..97d9bcb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLangLogMapper.xml @@ -0,0 +1,54 @@ + + + + + + + SELECT a.*, b.user_id as websiteUserId + FROM cms_lang_log a + LEFT JOIN cms_website b ON a.tenant_id = b.tenant_id + + + AND a.id = #{param.id} + + + AND a.lang LIKE CONCAT('%', #{param.lang}, '%') + + + AND a.lang_id = #{param.langId} + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND b.user_id = #{param.websiteUserId} + + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLangMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLangMapper.xml new file mode 100644 index 0000000..0dc0bed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLangMapper.xml @@ -0,0 +1,57 @@ + + + + + + + SELECT a.* + FROM cms_lang a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLinkMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLinkMapper.xml new file mode 100644 index 0000000..6102242 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsLinkMapper.xml @@ -0,0 +1,86 @@ + + + + + + + SELECT a.*, b.user_id as websiteUserId,c.title as categoryName + FROM cms_link a + LEFT JOIN cms_website b ON a.tenant_id = b.tenant_id + LEFT JOIN cms_navigation c ON a.category_id = c.navigation_id + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.lang = #{param.lang} + + + AND a.icon LIKE CONCAT('%', #{param.icon}, '%') + + + AND a.url LIKE CONCAT('%', #{param.url}, '%') + + + AND a.category_id LIKE CONCAT('%', #{param.categoryId}, '%') + + + AND a.app_id = #{param.appId} + + + AND a.user_id = #{param.userId} + + + AND b.user_id = #{param.websiteUserId} + + + AND a.recommend = #{param.recommend} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.id = #{param.keywords} + OR a.name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsModelMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsModelMapper.xml new file mode 100644 index 0000000..a948d9c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsModelMapper.xml @@ -0,0 +1,89 @@ + + + + + + + SELECT a.*, b.user_id as websiteUserId + FROM cms_model a + LEFT JOIN cms_website b ON a.tenant_id = b.tenant_id + + + AND a.model_id = #{param.modelId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.model LIKE CONCAT('%', #{param.model}, '%') + + + AND a.component_detail LIKE CONCAT('%', #{param.componentDetail}, '%') + + + AND a.component LIKE CONCAT('%', #{param.component}, '%') + + + AND a.banner LIKE CONCAT('%', #{param.banner}, '%') + + + AND a.image_width = #{param.imageWidth} + + + AND a.image_height = #{param.imageHeight} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.show_type = #{param.showType} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.user_id = #{param.userId} + + + AND b.user_id = #{param.websiteUserId} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsNavigationMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsNavigationMapper.xml new file mode 100644 index 0000000..837a948 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsNavigationMapper.xml @@ -0,0 +1,161 @@ + + + + + + + SELECT a.*, b.title as parentName, b.position as parentPosition + FROM cms_navigation a + LEFT JOIN cms_navigation b ON a.parent_id = b.navigation_id + + + AND a.navigation_id = #{param.navigationId} + + + AND a.parent_id = #{param.parentId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.model LIKE CONCAT('%', #{param.model}, '%') + + + AND a.lang = #{param.lang} + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.component LIKE CONCAT('%', #{param.component}, '%') + + + AND a.target LIKE CONCAT('%', #{param.target}, '%') + + + AND a.icon LIKE CONCAT('%', #{param.icon}, '%') + + + AND a.color LIKE CONCAT('%', #{param.color}, '%') + + + AND a.hide = #{param.hide} + + + AND a.permission = #{param.permission} + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.position = #{param.position} + + + AND a.top = #{param.top} + + + AND a.bottom = #{param.bottom} + + + AND a.active LIKE CONCAT('%', #{param.active}, '%') + + + AND a.meta LIKE CONCAT('%', #{param.meta}, '%') + + + AND a.style LIKE CONCAT('%', #{param.style}, '%') + + + AND a.parent_path LIKE CONCAT('%', #{param.parentPath}, '%') + + + AND a.parent_name LIKE CONCAT('%', #{param.parentName}, '%') + + + AND a.model_name LIKE CONCAT('%', #{param.modelName}, '%') + + + AND a.type = #{param.type} + + + AND a.page_id = #{param.pageId} + + + AND a.is_mp_weixin = #{param.isMpWeixin} + + + AND a.user_id = #{param.userId} + + + AND a.home = #{param.home} + + + AND a.recommend = #{param.recommend} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.path LIKE CONCAT('%', #{param.keywords}, '%') + OR a.title LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsStatisticsMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsStatisticsMapper.xml new file mode 100644 index 0000000..6662a86 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsStatisticsMapper.xml @@ -0,0 +1,120 @@ + + + + + + + SELECT a.* + FROM cms_statistics a + + + AND a.id = #{param.id} + + + AND a.website_id = #{param.websiteId} + + + AND a.user_count = #{param.userCount} + + + AND a.order_count = #{param.orderCount} + + + AND a.product_count = #{param.productCount} + + + AND a.total_sales = #{param.totalSales} + + + AND a.month_sales = #{param.monthSales} + + + AND a.today_sales = #{param.todaySales} + + + AND a.yesterday_sales = #{param.yesterdaySales} + + + AND a.week_sales = #{param.weekSales} + + + AND a.year_sales = #{param.yearSales} + + + AND a.today_orders = #{param.todayOrders} + + + AND a.month_orders = #{param.monthOrders} + + + AND a.today_users = #{param.todayUsers} + + + AND a.month_users = #{param.monthUsers} + + + AND a.today_visits = #{param.todayVisits} + + + AND a.total_visits = #{param.totalVisits} + + + AND a.merchant_count = #{param.merchantCount} + + + AND a.active_users = #{param.activeUsers} + + + AND a.conversion_rate = #{param.conversionRate} + + + AND a.avg_order_amount = #{param.avgOrderAmount} + + + AND a.statistics_date LIKE CONCAT('%', #{param.statisticsDate}, '%') + + + AND a.statistics_type = #{param.statisticsType} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsTemplateMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsTemplateMapper.xml new file mode 100644 index 0000000..c7319c0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsTemplateMapper.xml @@ -0,0 +1,93 @@ + + + + + + + SELECT a.* + FROM cms_template a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.type = #{param.type} + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.prefix LIKE CONCAT('%', #{param.prefix}, '%') + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.down_url LIKE CONCAT('%', #{param.downUrl}, '%') + + + AND a.color LIKE CONCAT('%', #{param.color}, '%') + + + AND a.version = #{param.version} + + + AND a.industry_parent LIKE CONCAT('%', #{param.industryParent}, '%') + + + AND a.industry_child LIKE CONCAT('%', #{param.industryChild}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.recommend = #{param.recommend} + + + AND a.share = #{param.share} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsWebsiteFieldMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsWebsiteFieldMapper.xml new file mode 100644 index 0000000..dc903bc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsWebsiteFieldMapper.xml @@ -0,0 +1,82 @@ + + + + + + + SELECT a.*, b.user_id + FROM cms_website_field a + LEFT JOIN cms_website b ON a.tenant_id = b.tenant_id + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.lang = #{param.lang} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.default_value LIKE CONCAT('%', #{param.defaultValue}, '%') + + + AND a.modify_range LIKE CONCAT('%', #{param.modifyRange}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.style LIKE CONCAT('%', #{param.style}, '%') + + + AND a.value LIKE CONCAT('%', #{param.value}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND b.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.value LIKE CONCAT('%', #{param.keywords}, '%') + OR a.name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsWebsiteSettingMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsWebsiteSettingMapper.xml new file mode 100644 index 0000000..2164b44 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsWebsiteSettingMapper.xml @@ -0,0 +1,81 @@ + + + + + + + SELECT a.* + FROM cms_website_setting a + + + AND a.id = #{param.id} + + + AND a.website_id = #{param.websiteId} + + + AND a.official = #{param.official} + + + AND a.market = #{param.market} + + + AND a.search = #{param.search} + + + AND a.share = #{param.share} + + + AND a.plugin = #{param.plugin} + + + AND a.editor = #{param.editor} + + + AND a.search_btn = #{param.searchBtn} + + + AND a.login_btn = #{param.loginBtn} + + + AND a.float_tool = #{param.floatTool} + + + AND a.copyright_link = #{param.copyrightLink} + + + AND a.max_menu_num = #{param.maxMenuNum} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsAdParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsAdParam.java new file mode 100644 index 0000000..315df9e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsAdParam.java @@ -0,0 +1,91 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 广告位查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsAdParam对象", description = "广告位查询参数") +public class CmsAdParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer adId; + + @Schema(description = "类型") + private Integer type; + + @Schema(description = "唯一标识") + @QueryField(type = QueryType.EQ) + private String code; + + @Schema(description = "栏目ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "页面ID") + @QueryField(type = QueryType.EQ) + private Integer designId; + + @Schema(description = "广告类型(废弃)") + private String adType; + + @Schema(description = "广告位名称") + private String name; + + @Schema(description = "宽") + private String width; + + @Schema(description = "高") + private String height; + + @Schema(description = "广告图片") + private String images; + + @Schema(description = "路由/链接地址") + private String path; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "页面ID") + @QueryField(type = QueryType.EQ) + private Integer pageId; + + @Schema(description = "页面名称") + private String pageName; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "网站创建者ID") + @QueryField(type = QueryType.EQ) + private Integer websiteUserId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsAdRecordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsAdRecordParam.java new file mode 100644 index 0000000..ad3daaf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsAdRecordParam.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 广告图片查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsAdRecordParam对象", description = "广告图片查询参数") +public class CmsAdRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer adRecordId; + + @Schema(description = "广告标题") + private String title; + + @Schema(description = "图片地址") + private String path; + + @Schema(description = "链接地址") + private String url; + + @Schema(description = "广告位ID") + @QueryField(type = QueryType.EQ) + private Integer adId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCategoryParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCategoryParam.java new file mode 100644 index 0000000..e13ec5d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCategoryParam.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文章分类表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsArticleCategoryParam对象", description = "文章分类表查询参数") +public class CmsArticleCategoryParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "分类标识") + private String categoryCode; + + @Schema(description = "分类名称") + private String title; + + @Schema(description = "类型 0列表 1单页 2外链") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "分类图片") + private String image; + + @Schema(description = "上级分类ID") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "路由/链接地址") + private String path; + + @Schema(description = "组件路径") + private String component; + + @Schema(description = "绑定的页面") + @QueryField(type = QueryType.EQ) + private Integer pageId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "文章数量") + @QueryField(type = QueryType.EQ) + private Integer count; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否显示在首页") + @QueryField(type = QueryType.EQ) + private Integer showIndex; + + @Schema(description = "状态, 0正常, 1禁用") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCommentParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCommentParam.java new file mode 100644 index 0000000..23761af --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCommentParam.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文章评论表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsArticleCommentParam对象", description = "文章评论表查询参数") +public class CmsArticleCommentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "评价ID") + @QueryField(type = QueryType.EQ) + private Integer commentId; + + @Schema(description = "文章ID") + @QueryField(type = QueryType.EQ) + private Integer articleId; + + @Schema(description = "评分 (10好评 20中评 30差评)") + @QueryField(type = QueryType.EQ) + private Integer score; + + @Schema(description = "评价内容") + private String content; + + @Schema(description = "是否为图片评价") + @QueryField(type = QueryType.EQ) + private Integer isPicture; + + @Schema(description = "评论者ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "被评价者ID") + @QueryField(type = QueryType.EQ) + private Integer toUserId; + + @Schema(description = "回复的评论ID") + @QueryField(type = QueryType.EQ) + private Integer replyCommentId; + + @Schema(description = "回复者ID") + @QueryField(type = QueryType.EQ) + private Integer replyUserId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0未读, 1已读") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleContentParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleContentParam.java new file mode 100644 index 0000000..ed325ec --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleContentParam.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文章记录表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsArticleContentParam对象", description = "文章记录表查询参数") +public class CmsArticleContentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "文章ID") + @QueryField(type = QueryType.EQ) + private Integer articleId; + + @Schema(description = "文章内容") + private String content; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCountParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCountParam.java new file mode 100644 index 0000000..eee9f12 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleCountParam.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 点赞文章查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsArticleCountParam对象", description = "点赞文章查询参数") +public class CmsArticleCountParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "文章ID") + @QueryField(type = QueryType.EQ) + private Integer articleId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleImportParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleImportParam.java new file mode 100644 index 0000000..d39650f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleImportParam.java @@ -0,0 +1,122 @@ +package com.gxwebsoft.cms.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 用户导入参数 + * + * @author WebSoft + * @since 2011-10-15 17:33:34 + */ +@Data +public class CmsArticleImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "文章ID") + private Integer articleId; + + @Excel(name = "文章标题") + private String title; + + @Excel(name = "封面图片") + private String image; + + @Excel(name = "所属栏目") + @TableField(exist = false) + private String categoryName; + + @Excel(name = "栏目ID") + private String categoryId; + + @Excel(name = "父级栏目名称") + private String parentName; + + @Excel(name = "父级栏目ID") + private Integer parentId; + + @Excel(name = "文章内容") + private String content; + + @Excel(name = "摘要") + private String comments; + + @Excel(name = "文章来源") + private String source; + + @Excel(name = "实际阅读量") + private String actualViews; + + @Excel(name = "作者") + private String author; + + @Excel(name = "发布时间") + private LocalDateTime createTime; + + @Excel(name = "类型") + private Integer type; + + @Excel(name = "模型") + private String model; + + @Excel(name = "详情页模板") + private String detail; + + @Excel(name = "话题") + private String topic; + + @Excel(name = "关键词") + private String tags; + + @Excel(name = "产品概述") + private String overview; + + @Excel(name = "显示方式") + private Integer showType; + + @Excel(name = "客户端") + private String platform; + + @Excel(name = "文件列表") + private String files; + + @Excel(name = "视频地址") + private String video; + + @Excel(name = "点赞数") + private Integer likes; + + @Excel(name = "评论数") + private Integer commentNumbers; + + @Excel(name = "推荐") + private Integer recommend; + + @Excel(name = "查看密码") + private String password; + + @Excel(name = "权限") + private Integer permission; + + @Excel(name = "用户ID") + private Integer userId; + + @Excel(name = "商户ID") + private Long merchantId; + + @Excel(name = "语言") + private String lang; + + @Excel(name = "排序") + private Integer sortNumber; + + @Excel(name = "状态") + private Integer status; + + @Excel(name = "租户ID") + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleLikeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleLikeParam.java new file mode 100644 index 0000000..8900c94 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleLikeParam.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 点赞文章查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsArticleLikeParam对象", description = "点赞文章查询参数") +public class CmsArticleLikeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "文章ID") + @QueryField(type = QueryType.EQ) + private Integer articleId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleParam.java new file mode 100644 index 0000000..cdd08bb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsArticleParam.java @@ -0,0 +1,188 @@ +package com.gxwebsoft.cms.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.Set; + +/** + * 文章查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsArticleParam对象", description = "文章查询参数") +public class CmsArticleParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章ID") + @QueryField(type = QueryType.EQ) + private Integer articleId; + + @Schema(description = "父级栏目ID") + @TableField(exist = false) + private Set categoryIds; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章类型 0常规 1视频") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "文章模型") + @QueryField(type = QueryType.EQ) + private String model; + + @Schema(description = "文章编号") + @QueryField(type = QueryType.EQ) + private String code; + + @Schema(description = "详情页标识") + @QueryField(type = QueryType.EQ) + private String detail; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + @QueryField(type = QueryType.EQ) + private Integer showType; + + @Schema(description = "话题") + @QueryField(type = QueryType.LIKE) + private String topic; + + @Schema(description = "标签") + @QueryField(type = QueryType.EQ) + private String tags; + + @Schema(description = "栏目ID") + @QueryField(type = QueryType.EQ) + private Integer navigationId; + + @Schema(description = "文章分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "父级栏目ID") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "是否包含封面图") + @QueryField(type = QueryType.EQ) + private Boolean hasImage; + + @Schema(description = "价格") + private BigDecimal price; + + @Schema(description = "来源") + private String source; + + @Schema(description = "虚拟阅读量(仅用作展示)") + @QueryField(type = QueryType.EQ) + private Integer virtualViews; + + @Schema(description = "实际阅读量") + @QueryField(type = QueryType.EQ) + private Integer actualViews; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + @QueryField(type = QueryType.EQ) + private Integer permission; + + @Schema(description = "访问密码") + @QueryField(type = QueryType.EQ) + private String password; + + @Schema(description = "访问密码") + @QueryField(type = QueryType.EQ) + private String password2; + + @Schema(description = "发布来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "文章附件") + private String files; + + @Schema(description = "视频地址") + private String video; + + @Schema(description = "接受的文件类型") + private String accept; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "点赞数") + @QueryField(type = QueryType.EQ) + private Integer likes; + + @Schema(description = "评论数") + @QueryField(type = QueryType.EQ) + private Integer commentNumbers; + + @Schema(description = "提醒谁看") + private String toUsers; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "项目ID") + @QueryField(type = QueryType.EQ) + private Long projectId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "文章ID集查询") + @TableField(exist = false) + private Set articleIds; + + @Schema(description = "网站创建者ID") + @QueryField(type = QueryType.EQ) + private Integer websiteUserId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDesignParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDesignParam.java new file mode 100644 index 0000000..8268f8e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDesignParam.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 页面管理记录表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsDesignParam对象", description = "页面管理记录表查询参数") +public class CmsDesignParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer pageId; + + @Schema(description = "页面标题") + private String name; + + @Schema(description = "所属栏目ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "页面模型") + private String model; + + @Schema(description = "页面关键词") + private String keywords; + + @Schema(description = "页面描述") + private String description; + + @Schema(description = "缩列图") + private String photo; + + @Schema(description = "购买链接") + private String buyUrl; + + @Schema(description = "页面样式") + private String style; + + @Schema(description = "页面内容") + private String content; + + @Schema(description = "是否开启布局") + @QueryField(type = QueryType.EQ) + private Integer showLayout; + + @Schema(description = "页面布局") + private String layout; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "设为首页") + @QueryField(type = QueryType.EQ) + private Integer home; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDesignRecordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDesignRecordParam.java new file mode 100644 index 0000000..daa8549 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDesignRecordParam.java @@ -0,0 +1,71 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 页面组件表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsDesignRecordParam对象", description = "页面组件表查询参数") +public class CmsDesignRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "关联导航ID") + @QueryField(type = QueryType.EQ) + private Integer navigationId; + + @Schema(description = "组件") + private String title; + + @Schema(description = "组件标识") + private String dictCode; + + @Schema(description = "组件样式") + private String styles; + + @Schema(description = "卡片阴影显示时机") + private String shadow; + + @Schema(description = "页面关键词") + private String keywords; + + @Schema(description = "页面描述") + private String description; + + @Schema(description = "页面路由地址") + private String path; + + @Schema(description = "缩列图") + private String photo; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDomainParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDomainParam.java new file mode 100644 index 0000000..998634d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsDomainParam.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 网站域名记录表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsDomainParam对象", description = "网站域名记录表查询参数") +public class CmsDomainParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "类型 0赠送域名 1绑定域名 ") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "主机记录") + private String hostName; + + @Schema(description = "记录值") + private String hostValue; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "网站ID") + @QueryField(type = QueryType.EQ) + private Integer websiteId; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer appId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsFormParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsFormParam.java new file mode 100644 index 0000000..f54e6b0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsFormParam.java @@ -0,0 +1,88 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 表单设计表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsFormParam对象", description = "表单设计表查询参数") +public class CmsFormParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer formId; + + @Schema(description = "表单标题") + private String name; + + @Schema(description = "顶部图片") + private String photo; + + @Schema(description = "背景图片") + private String background; + + @Schema(description = "视频文件") + private String video; + + @Schema(description = "提交次数") + @QueryField(type = QueryType.EQ) + private Integer submitNumber; + + @Schema(description = "页面布局") + private String layout; + + @Schema(description = "是否隐藏顶部图片") + @QueryField(type = QueryType.EQ) + private Integer hidePhoto; + + @Schema(description = "是否隐藏背景图片") + @QueryField(type = QueryType.EQ) + private Integer hideBackground; + + @Schema(description = "是否隐藏视频") + @QueryField(type = QueryType.EQ) + private Integer hideVideo; + + @Schema(description = "背景图片透明度") + @QueryField(type = QueryType.EQ) + private BigDecimal opacity; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsFormRecordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsFormRecordParam.java new file mode 100644 index 0000000..f0bc29a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsFormRecordParam.java @@ -0,0 +1,64 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 表单数据记录表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsFormRecordParam对象", description = "表单数据记录表查询参数") +public class CmsFormRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer formRecordId; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "表单数据") + private String formData; + + @Schema(description = "表单ID") + @QueryField(type = QueryType.EQ) + private Integer formId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLangLogParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLangLogParam.java new file mode 100644 index 0000000..a4a4997 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLangLogParam.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.param; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 国际化记录启用查询参数 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsLangLogParam对象", description = "国际化记录启用查询参数") +public class CmsLangLogParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "名称") + private String lang; + + @Schema(description = "关联ID") + @QueryField(type = QueryType.EQ) + private Integer langId; + + @Schema(description = "编码") + private String code; + + @Schema(description = "名称") + private String name; + + @Schema(description = "创建者UID") + @TableField(exist = false) + private Integer websiteUserId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLangParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLangParam.java new file mode 100644 index 0000000..f3311d8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLangParam.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.cms.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 国际化查询参数 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsLangParam对象", description = "国际化查询参数") +public class CmsLangParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "名称") + private String name; + + @Schema(description = "编码") + private String code; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLinkParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLinkParam.java new file mode 100644 index 0000000..9e97466 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsLinkParam.java @@ -0,0 +1,71 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 常用链接查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsLinkParam对象", description = "常用链接查询参数") +public class CmsLinkParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "链接名称") + private String name; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "链接地址") + private String url; + + @Schema(description = "栏目ID") + private Integer categoryId; + + @Schema(description = "应用ID") + @QueryField(type = QueryType.EQ) + private Integer appId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "状态, 0正常, 1待确认") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "网站创建者ID") + @QueryField(type = QueryType.EQ) + private Integer websiteUserId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsModelParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsModelParam.java new file mode 100644 index 0000000..6de4529 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsModelParam.java @@ -0,0 +1,82 @@ +package com.gxwebsoft.cms.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 模型查询参数 + * + * @author 科技小王子 + * @since 2024-11-26 15:44:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsModelParam对象", description = "模型查询参数") +public class CmsModelParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer modelId; + + @Schema(description = "模型名称") + private String name; + + @Schema(description = "唯一标识") + private String model; + + @Schema(description = "菜单路由地址") + private String componentDetail; + + @Schema(description = "菜单组件地址, 目录可为空") + private String component; + + @Schema(description = "模型banner图片") + private String banner; + + @Schema(description = "封面图宽") + @QueryField(type = QueryType.EQ) + private String imageWidth; + + @Schema(description = "封面图高") + @QueryField(type = QueryType.EQ) + private String imageHeight; + + @Schema(description = "Banner上的标题") + private String title; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + @QueryField(type = QueryType.EQ) + private Integer showType; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "创建者用户ID") + @QueryField(type = QueryType.EQ) + private Integer websiteUserId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsNavigationParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsNavigationParam.java new file mode 100644 index 0000000..39989c5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsNavigationParam.java @@ -0,0 +1,153 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 网站导航记录表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsNavigationParam对象", description = "网站导航记录表查询参数") +public class CmsNavigationParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer navigationId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "模型") + private String model; + + @Schema(description = "标识") + private String code; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址, 目录可为空") + private String component; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + @QueryField(type = QueryType.EQ) + private Integer permission; + + @Schema(description = "访问密码") + @QueryField(type = QueryType.EQ) + private String password; + + @Schema(description = "访问密码") + @QueryField(type = QueryType.EQ) + private String password2; + + @Schema(description = "位置 0不限 1顶部 2底部") + @QueryField(type = QueryType.EQ) + private Integer position; + + @Schema(description = "仅在顶部显示") + @QueryField(type = QueryType.EQ) + private Integer top; + + @Schema(description = "仅在底部显示") + @QueryField(type = QueryType.EQ) + private Integer bottom; + + @Schema(description = "菜单侧栏选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "css样式") + private String style; + + @Schema(description = "父级栏目路由") + private String parentPath; + + @Schema(description = "父级栏目名称") + private String parentName; + + @Schema(description = "模型名称") + private String modelName; + + @Schema(description = "类型(已废弃)") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "绑定的页面(已废弃)") + @QueryField(type = QueryType.EQ) + private Integer pageId; + + @Schema(description = "是否微信小程序菜单") + @QueryField(type = QueryType.EQ) + private Boolean isMpWeixin; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "设为首页") + @QueryField(type = QueryType.EQ) + private Integer home; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Boolean recommend; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否开启布局") + @QueryField(type = QueryType.EQ) + private Boolean showLayout; + + @Schema(description = "是否查询单页内容") + @QueryField(type = QueryType.EQ) + private Boolean queryContent; + + @Schema(description = "网站创建者用户ID") + @QueryField(type = QueryType.EQ) + private Integer websiteUserId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsStatisticsParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsStatisticsParam.java new file mode 100644 index 0000000..cc8c37e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsStatisticsParam.java @@ -0,0 +1,136 @@ +package com.gxwebsoft.cms.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 站点统计信息表查询参数 + * + * @author 科技小王子 + * @since 2025-07-25 12:32:06 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsStatisticsParam对象", description = "站点统计信息表查询参数") +public class CmsStatisticsParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "站点ID") + @QueryField(type = QueryType.EQ) + private Integer websiteId; + + @Schema(description = "用户总数") + @QueryField(type = QueryType.EQ) + private Integer userCount; + + @Schema(description = "订单总数") + @QueryField(type = QueryType.EQ) + private Integer orderCount; + + @Schema(description = "商品总数") + @QueryField(type = QueryType.EQ) + private Integer productCount; + + @Schema(description = "总销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal totalSales; + + @Schema(description = "本月销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal monthSales; + + @Schema(description = "今日销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal todaySales; + + @Schema(description = "昨日销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal yesterdaySales; + + @Schema(description = "本周销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal weekSales; + + @Schema(description = "本年销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal yearSales; + + @Schema(description = "今日订单数") + @QueryField(type = QueryType.EQ) + private Integer todayOrders; + + @Schema(description = "本月订单数") + @QueryField(type = QueryType.EQ) + private Integer monthOrders; + + @Schema(description = "今日新增用户") + @QueryField(type = QueryType.EQ) + private Integer todayUsers; + + @Schema(description = "本月新增用户") + @QueryField(type = QueryType.EQ) + private Integer monthUsers; + + @Schema(description = "今日访问量") + @QueryField(type = QueryType.EQ) + private Integer todayVisits; + + @Schema(description = "总访问量") + @QueryField(type = QueryType.EQ) + private Integer totalVisits; + + @Schema(description = "商户总数") + @QueryField(type = QueryType.EQ) + private Integer merchantCount; + + @Schema(description = "活跃用户数") + @QueryField(type = QueryType.EQ) + private Integer activeUsers; + + @Schema(description = "转化率(%)") + @QueryField(type = QueryType.EQ) + private BigDecimal conversionRate; + + @Schema(description = "平均订单金额") + @QueryField(type = QueryType.EQ) + private BigDecimal avgOrderAmount; + + @Schema(description = "统计日期") + private String statisticsDate; + + @Schema(description = "统计类型: 1日统计, 2月统计, 3年统计") + @QueryField(type = QueryType.EQ) + private Integer statisticsType; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "操作用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "状态: 0禁用, 1启用") + @QueryField(type = QueryType.EQ) + private Boolean status; + + @Schema(description = "是否删除: 0否, 1是") + @QueryField(type = QueryType.EQ) + private Boolean deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsTemplateParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsTemplateParam.java new file mode 100644 index 0000000..ca2ebf1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsTemplateParam.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.cms.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 网站模版查询参数 + * + * @author 科技小王子 + * @since 2025-01-21 14:21:16 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsTemplateParam对象", description = "网站模版查询参数") +public class CmsTemplateParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "模版名称") + private String name; + + @Schema(description = "模版标识") + private String code; + + @Schema(description = "缩列图") + private String image; + + @Schema(description = "类型 1企业官网 2其他") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "网站关键词") + private String keywords; + + @Schema(description = "域名前缀") + private String prefix; + + @Schema(description = "预览地址") + private String domain; + + @Schema(description = "模版下载地址") + private String downUrl; + + @Schema(description = "色系") + private String color; + + @Schema(description = "应用版本 10免费版 20授权版 30永久授权") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Boolean recommend; + + @Schema(description = "是否共享模板") + @QueryField(type = QueryType.EQ) + private Boolean share; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteFieldImportParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteFieldImportParam.java new file mode 100644 index 0000000..5bf56d3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteFieldImportParam.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.cms.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; + +/** + * 应用参数导入参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Data +public class CmsWebsiteFieldImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "自增ID") + private Integer id; + + @Excel(name = "类型") + private Integer type; + + @Excel(name = "名称") + private String name; + + @Excel(name = "默认值") + private String defaultValue; + + @Excel(name = "可修改的值") + private String modifyRange; + + @Excel(name = "备注") + private String comments; + + @Excel(name = "css样式") + private String style; + + @Excel(name = "值") + private String value; + + @Excel(name = "国际化语言") + private String lang; + + @Excel(name = "加密") + private Boolean encrypted; + + @Excel(name = "商户ID") + private Long merchantId; + + @Excel(name = "排序") + private Integer sortNumber; + + @Excel(name = "租户ID") + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteFieldParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteFieldParam.java new file mode 100644 index 0000000..c152a31 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteFieldParam.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用参数查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsWebsiteFieldParam对象", description = "应用参数查询参数") +public class CmsWebsiteFieldParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "类型,0文本 1图片 2其他") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "名称") + private String name; + + @Schema(description = "默认值") + private String defaultValue; + + @Schema(description = "可修改的值 [on|off]") + private String modifyRange; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "css样式") + private String style; + + @Schema(description = "名称") + private String value; + + @Schema(description = "是否加密") + private Boolean encrypted; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "创建者") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteParam.java new file mode 100644 index 0000000..7488ead --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteParam.java @@ -0,0 +1,224 @@ +package com.gxwebsoft.cms.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.util.Set; + +/** + * 网站信息记录表查询参数 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsWebsiteParam对象", description = "网站信息记录表查询参数") +public class CmsWebsiteParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "站点ID") + @QueryField(type = QueryType.EQ) + private Integer websiteId; + + @Schema(description = "站点类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "网站名称") + private String websiteName; + + @Schema(description = "网站标识") + private String websiteCode; + + @Schema(description = "网站密钥") + private String websiteSecret; + + @Schema(description = "网站LOGO") + private String websiteIcon; + + @Schema(description = "网站LOGO") + private String websiteLogo; + + @Schema(description = "网站LOGO(深色模式)") + private String websiteDarkLogo; + + @Schema(description = "网站类型") + private String websiteType; + + @Schema(description = "栏目ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "网站截图") + private String files; + + @Schema(description = "网站关键词") + private String keywords; + + @Schema(description = "域名前缀") + private String prefix; + + @Schema(description = "绑定域名") + private String domain; + + @Schema(description = "全局样式") + private String style; + + @Schema(description = "后台管理地址") + private String adminUrl; + + @Schema(description = "应用版本 10免费版 20授权版 30永久授权") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "服务到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private String expirationTime; + + @Schema(description = "模版ID") + @QueryField(type = QueryType.EQ) + private Integer templateId; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "开发者名称") + private String developer; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "电子邮箱") + private String email; + + @Schema(description = "ICP备案号") + private String icpNo; + + @Schema(description = "公安备案") + private String policeNo; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否官方产品") + @QueryField(type = QueryType.EQ) + private Boolean official; + + @Schema(description = "是否查询超管账号") + @QueryField(type = QueryType.EQ) + private Boolean showAdminPhone; + + @Schema(description = "允许展示到插件市场") + @QueryField(type = QueryType.EQ) + private Boolean market; + + @Schema(description = "是否插件类型 0应用 1插件") + @QueryField(type = QueryType.EQ) + private Boolean plugin; + + @Schema(description = "允许被搜索") + @QueryField(type = QueryType.EQ) + private Boolean search; + + @Schema(description = "主题色") + private String color; + + @Schema(description = "点赞数量") + private Integer likes; + + @Schema(description = "点击数量") + private Integer clicks; + + @Schema(description = "购买数量") + private Integer buys; + + @Schema(description = "下载数量") + private Integer downloads; + + @Schema(description = "状态 0未开通 1运行中 2维护中 3已关闭 4已欠费停机 5违规关停") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "维护说明") + private String statusText; + + @Schema(description = "关闭说明") + private String statusClose; + + @Schema(description = "全局样式") + private String styles; + + @Schema(description = "运行状态") + @QueryField(type = QueryType.EQ) + private Integer running; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "按userId集搜索") + @QueryField(type = QueryType.EQ) + private Set userIds; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "按WebsiteIds集搜索") + private Set websiteIds; + + @Schema(description = "当前登录用户ID") + @QueryField(type = QueryType.EQ) + private Integer loginUserId; + + @Schema(description = "管理员手机号") + @QueryField(type = QueryType.EQ) + private String adminPhone; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteSettingParam.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteSettingParam.java new file mode 100644 index 0000000..947f00e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/param/CmsWebsiteSettingParam.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.cms.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 网站设置查询参数 + * + * @author 科技小王子 + * @since 2025-02-19 01:35:44 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsWebsiteSettingParam对象", description = "网站设置查询参数") +public class CmsWebsiteSettingParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "关联网站ID") + @QueryField(type = QueryType.EQ) + private Integer websiteId; + + @Schema(description = "是否官方插件") + @QueryField(type = QueryType.EQ) + private Boolean official; + + @Schema(description = "是否展示在插件市场") + @QueryField(type = QueryType.EQ) + private Boolean market; + + @Schema(description = "是否允许被搜索") + @QueryField(type = QueryType.EQ) + private Boolean search; + + @Schema(description = "是否共享") + @QueryField(type = QueryType.EQ) + private Boolean share; + + @Schema(description = "是否插件 0应用1 插件 ") + @QueryField(type = QueryType.EQ) + private Boolean plugin; + + @Schema(description = "编辑器类型 1 md-editor-v3, 2 tinymce-editor") + @QueryField(type = QueryType.EQ) + private Boolean editor; + + @Schema(description = "显示站内搜索") + @QueryField(type = QueryType.EQ) + private Boolean searchBtn; + + @Schema(description = "显示登录注册功能") + @QueryField(type = QueryType.EQ) + private Boolean loginBtn; + + @Schema(description = "显示悬浮客服工具") + @QueryField(type = QueryType.EQ) + private Boolean floatTool; + + @Schema(description = "显示版权链接") + @QueryField(type = QueryType.EQ) + private Boolean copyrightLink; + + @Schema(description = "导航栏最多显示数量") + @QueryField(type = QueryType.EQ) + private Boolean maxMenuNum; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsAdRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsAdRecordService.java new file mode 100644 index 0000000..5610204 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsAdRecordService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsAdRecord; +import com.gxwebsoft.cms.param.CmsAdRecordParam; + +import java.util.List; + +/** + * 广告图片Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsAdRecordService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsAdRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsAdRecordParam param); + + /** + * 根据id查询 + * + * @param adRecordId ID + * @return CmsAdRecord + */ + CmsAdRecord getByIdRel(Integer adRecordId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsAdService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsAdService.java new file mode 100644 index 0000000..9cef726 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsAdService.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsAd; +import com.gxwebsoft.cms.param.CmsAdParam; + +import java.util.List; + +/** + * 广告位Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsAdService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsAdParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsAdParam param); + + /** + * 根据id查询 + * + * @param adId ID + * @return CmsAd + */ + CmsAd getByIdRel(Integer adId); + + /** + * 根据code查询 + * + * @return CmsAd + */ + CmsAd getByIdCode(String code); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCategoryService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCategoryService.java new file mode 100644 index 0000000..38d55be --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCategoryService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsArticleCategory; +import com.gxwebsoft.cms.param.CmsArticleCategoryParam; + +import java.util.List; + +/** + * 文章分类表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleCategoryService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsArticleCategoryParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsArticleCategoryParam param); + + /** + * 根据id查询 + * + * @param categoryId 文章分类ID + * @return CmsArticleCategory + */ + CmsArticleCategory getByIdRel(Integer categoryId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCommentService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCommentService.java new file mode 100644 index 0000000..68b4fd8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCommentService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsArticleComment; +import com.gxwebsoft.cms.param.CmsArticleCommentParam; + +import java.util.List; + +/** + * 文章评论表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleCommentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsArticleCommentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsArticleCommentParam param); + + /** + * 根据id查询 + * + * @param commentId 评价ID + * @return CmsArticleComment + */ + CmsArticleComment getByIdRel(Integer commentId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleContentService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleContentService.java new file mode 100644 index 0000000..640ad80 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleContentService.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.cms.entity.CmsArticle; +import com.gxwebsoft.cms.entity.TranslateDataVo; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsArticleContent; +import com.gxwebsoft.cms.param.CmsArticleContentParam; + +import java.util.List; + +/** + * 文章记录表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleContentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsArticleContentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsArticleContentParam param); + + + CmsArticleContent getByIdRel(Integer id); + + void translate(CmsArticle article); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCountService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCountService.java new file mode 100644 index 0000000..c9cd3b1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleCountService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsArticleCount; +import com.gxwebsoft.cms.param.CmsArticleCountParam; + +import java.util.List; + +/** + * 点赞文章Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleCountService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsArticleCountParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsArticleCountParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return CmsArticleCount + */ + CmsArticleCount getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleLikeService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleLikeService.java new file mode 100644 index 0000000..08cd5a3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleLikeService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsArticleLike; +import com.gxwebsoft.cms.param.CmsArticleLikeParam; + +import java.util.List; + +/** + * 点赞文章Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleLikeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsArticleLikeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsArticleLikeParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return CmsArticleLike + */ + CmsArticleLike getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleService.java new file mode 100644 index 0000000..1d13e3c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsArticleService.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsArticle; +import com.gxwebsoft.cms.param.CmsArticleParam; + +import javax.validation.Valid; +import java.util.List; + +/** + * 文章Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsArticleService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsArticleParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsArticleParam param); + + /** + * 根据id查询 + * + * @param articleId 文章ID + * @return CmsArticle + */ + CmsArticle getByIdRel(Integer articleId); + + void saveInc(Integer formId); + + boolean saveRel(@Valid CmsArticle article); + + boolean updateByIdRel(CmsArticle article); + + CmsArticle getByIdCode(String code); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDesignRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDesignRecordService.java new file mode 100644 index 0000000..e9e3465 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDesignRecordService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsDesignRecord; +import com.gxwebsoft.cms.param.CmsDesignRecordParam; + +import java.util.List; + +/** + * 页面组件表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsDesignRecordService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsDesignRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsDesignRecordParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return CmsDesignRecord + */ + CmsDesignRecord getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDesignService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDesignService.java new file mode 100644 index 0000000..6a895d3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDesignService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsDesign; +import com.gxwebsoft.cms.param.CmsDesignParam; + +import java.util.List; + +/** + * 页面管理记录表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsDesignService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsDesignParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsDesignParam param); + + /** + * 根据id查询 + * + * @param pageId ID + * @return CmsDesign + */ + CmsDesign getByIdRel(Integer pageId); + + void translate(CmsDesign cmsDesign); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDomainService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDomainService.java new file mode 100644 index 0000000..bdb1944 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsDomainService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsDomain; +import com.gxwebsoft.cms.param.CmsDomainParam; + +import java.util.List; + +/** + * 网站域名记录表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +public interface CmsDomainService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsDomainParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsDomainParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return CmsDomain + */ + CmsDomain getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsFormRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsFormRecordService.java new file mode 100644 index 0000000..86b1b2f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsFormRecordService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsFormRecord; +import com.gxwebsoft.cms.param.CmsFormRecordParam; + +import java.util.List; + +/** + * 表单数据记录表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsFormRecordService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsFormRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsFormRecordParam param); + + /** + * 根据id查询 + * + * @param formRecordId ID + * @return CmsFormRecord + */ + CmsFormRecord getByIdRel(Integer formRecordId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsFormService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsFormService.java new file mode 100644 index 0000000..a6c98fd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsFormService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsForm; +import com.gxwebsoft.cms.param.CmsFormParam; + +import java.util.List; + +/** + * 表单设计表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsFormService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsFormParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsFormParam param); + + /** + * 根据id查询 + * + * @param formId ID + * @return CmsForm + */ + CmsForm getByIdRel(Integer formId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLangLogService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLangLogService.java new file mode 100644 index 0000000..d3e59ff --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLangLogService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsLangLog; +import com.gxwebsoft.cms.param.CmsLangLogParam; + +import java.util.List; + +/** + * 国际化记录启用Service + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +public interface CmsLangLogService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsLangLogParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsLangLogParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return CmsLangLog + */ + CmsLangLog getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLangService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLangService.java new file mode 100644 index 0000000..d1c1fa3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLangService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsLang; +import com.gxwebsoft.cms.param.CmsLangParam; + +import java.util.List; + +/** + * 国际化Service + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +public interface CmsLangService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsLangParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsLangParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return CmsLang + */ + CmsLang getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLinkService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLinkService.java new file mode 100644 index 0000000..e65eee7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsLinkService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsLink; +import com.gxwebsoft.cms.param.CmsLinkParam; + +import java.util.List; + +/** + * 常用链接Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsLinkService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsLinkParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsLinkParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CmsLink + */ + CmsLink getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsModelService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsModelService.java new file mode 100644 index 0000000..1fe9778 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsModelService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsModel; +import com.gxwebsoft.cms.param.CmsModelParam; + +import java.util.List; + +/** + * 模型Service + * + * @author 科技小王子 + * @since 2024-11-26 15:44:53 + */ +public interface CmsModelService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsModelParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsModelParam param); + + /** + * 根据id查询 + * + * @param modelId ID + * @return CmsModel + */ + CmsModel getByIdRel(Integer modelId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsNavigationService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsNavigationService.java new file mode 100644 index 0000000..cb867f6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsNavigationService.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsNavigation; +import com.gxwebsoft.cms.param.CmsNavigationParam; + +import java.util.List; + +/** + * 网站导航记录表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +public interface CmsNavigationService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsNavigationParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsNavigationParam param); + + /** + * 根据id查询 + * + * @param navigationId ID + * @return CmsNavigation + */ + CmsNavigation getByIdRel(Integer navigationId); + + void saveAsync(CmsNavigation cmsNavigation); + + CmsNavigation getByIdRelByCodeRel(String code); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsStatisticsService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsStatisticsService.java new file mode 100644 index 0000000..948d780 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsStatisticsService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsStatistics; +import com.gxwebsoft.cms.param.CmsStatisticsParam; + +import java.util.List; + +/** + * 站点统计信息表Service + * + * @author 科技小王子 + * @since 2025-07-25 12:32:06 + */ +public interface CmsStatisticsService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsStatisticsParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsStatisticsParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CmsStatistics + */ + CmsStatistics getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsTemplateService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsTemplateService.java new file mode 100644 index 0000000..979fa0c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsTemplateService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.cms.entity.CmsTemplate; +import com.gxwebsoft.cms.param.CmsTemplateParam; + +import java.util.List; + +/** + * 网站模版Service + * + * @author 科技小王子 + * @since 2025-01-21 14:21:16 + */ +public interface CmsTemplateService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsTemplateParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsTemplateParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return CmsTemplate + */ + CmsTemplate getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteFieldService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteFieldService.java new file mode 100644 index 0000000..05adebe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteFieldService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.cms.entity.CmsWebsiteField; +import com.gxwebsoft.cms.param.CmsWebsiteFieldParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; + +/** + * 应用参数Service + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +public interface CmsWebsiteFieldService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsWebsiteFieldParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsWebsiteFieldParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CmsWebsiteField + */ + CmsWebsiteField getByIdRel(Integer id); + + CmsWebsiteField getByCodeRel(String code); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteService.java new file mode 100644 index 0000000..6700567 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteService.java @@ -0,0 +1,70 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.cms.entity.CmsWebsite; +import com.gxwebsoft.cms.param.CmsWebsiteParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.vo.ShopVo; + +import java.util.List; + +/** + * 网站信息记录表Service + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +public interface CmsWebsiteService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsWebsiteParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsWebsiteParam param); + + /** + * 根据id查询 + * + * @param websiteId 站点ID + * @return CmsWebsite + */ + CmsWebsite getByIdRel(Integer websiteId); + + PageResult pageRelAll(CmsWebsiteParam param); + + // 创建站点 + CmsWebsite create(CmsWebsite cmsWebsite); + + CmsWebsite getByIdRelAll(Integer id); + + boolean updateByIdAll(CmsWebsite cmsWebsite); + + boolean removeByIdAll(Integer id); + + CmsWebsite getByTenantId(Integer tenantId); + + /** + * 获取网站基本信息(VO格式) + * + * @param tenantId 租户ID + * @return 网站信息VO + */ + ShopVo getSiteInfo(Integer tenantId); + + /** + * 清除网站信息缓存 + * + * @param tenantId 租户ID + */ + void clearSiteInfoCache(Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteSettingService.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteSettingService.java new file mode 100644 index 0000000..17d6420 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/CmsWebsiteSettingService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.cms.entity.CmsWebsiteSetting; +import com.gxwebsoft.cms.param.CmsWebsiteSettingParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; + +/** + * 网站设置Service + * + * @author 科技小王子 + * @since 2025-02-19 01:35:44 + */ +public interface CmsWebsiteSettingService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsWebsiteSettingParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsWebsiteSettingParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CmsWebsiteSetting + */ + CmsWebsiteSetting getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsAdRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsAdRecordServiceImpl.java new file mode 100644 index 0000000..d82d016 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsAdRecordServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsAdRecordMapper; +import com.gxwebsoft.cms.service.CmsAdRecordService; +import com.gxwebsoft.cms.entity.CmsAdRecord; +import com.gxwebsoft.cms.param.CmsAdRecordParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 广告图片Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsAdRecordServiceImpl extends ServiceImpl implements CmsAdRecordService { + + @Override + public PageResult pageRel(CmsAdRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsAdRecordParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsAdRecord getByIdRel(Integer adRecordId) { + CmsAdRecordParam param = new CmsAdRecordParam(); + param.setAdRecordId(adRecordId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsAdServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsAdServiceImpl.java new file mode 100644 index 0000000..370d48d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsAdServiceImpl.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.cms.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsAdMapper; +import com.gxwebsoft.cms.service.CmsAdService; +import com.gxwebsoft.cms.entity.CmsAd; +import com.gxwebsoft.cms.param.CmsAdParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 广告位Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsAdServiceImpl extends ServiceImpl implements CmsAdService { + + @Override + public PageResult pageRel(CmsAdParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsAdParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time asc"); + return page.sortRecords(list); + } + + @Override + public CmsAd getByIdRel(Integer adId) { + CmsAdParam param = new CmsAdParam(); + param.setAdId(adId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public CmsAd getByIdCode(String code) { + CmsAdParam param = new CmsAdParam(); + param.setCode(code); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCategoryServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCategoryServiceImpl.java new file mode 100644 index 0000000..e52e243 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCategoryServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsArticleCategoryMapper; +import com.gxwebsoft.cms.service.CmsArticleCategoryService; +import com.gxwebsoft.cms.entity.CmsArticleCategory; +import com.gxwebsoft.cms.param.CmsArticleCategoryParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 文章分类表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsArticleCategoryServiceImpl extends ServiceImpl implements CmsArticleCategoryService { + + @Override + public PageResult pageRel(CmsArticleCategoryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsArticleCategoryParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsArticleCategory getByIdRel(Integer categoryId) { + CmsArticleCategoryParam param = new CmsArticleCategoryParam(); + param.setCategoryId(categoryId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCommentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCommentServiceImpl.java new file mode 100644 index 0000000..cc41aed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCommentServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsArticleCommentMapper; +import com.gxwebsoft.cms.service.CmsArticleCommentService; +import com.gxwebsoft.cms.entity.CmsArticleComment; +import com.gxwebsoft.cms.param.CmsArticleCommentParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 文章评论表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsArticleCommentServiceImpl extends ServiceImpl implements CmsArticleCommentService { + + @Override + public PageResult pageRel(CmsArticleCommentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsArticleCommentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsArticleComment getByIdRel(Integer commentId) { + CmsArticleCommentParam param = new CmsArticleCommentParam(); + param.setCommentId(commentId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleContentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleContentServiceImpl.java new file mode 100644 index 0000000..36f47c6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleContentServiceImpl.java @@ -0,0 +1,189 @@ +package com.gxwebsoft.cms.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.*; +import com.gxwebsoft.cms.mapper.CmsArticleContentMapper; +import com.gxwebsoft.cms.service.CmsArticleContentService; +import com.gxwebsoft.cms.param.CmsArticleContentParam; +import com.gxwebsoft.cms.service.CmsArticleService; +import com.gxwebsoft.cms.service.CmsLangLogService; +import com.gxwebsoft.cms.service.CmsNavigationService; +import com.gxwebsoft.common.core.utils.AliYunSender; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 文章记录表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsArticleContentServiceImpl extends ServiceImpl implements CmsArticleContentService { + @Resource + @Lazy + private CmsNavigationService cmsNavigationService; + @Resource + @Lazy + private CmsArticleService cmsArticleService; + @Resource + private CmsLangLogService cmsLangLogService; + @Override + public PageResult pageRel(CmsArticleContentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsArticleContentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsArticleContent getByIdRel(Integer id) { + CmsArticleContentParam param = new CmsArticleContentParam(); + param.setArticleId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public void translate(CmsArticle article) { + // 未开启多语言 + if(cmsLangLogService.count() == 0){ + return; + } + // 仅限定新增简体中文才会同步翻译其他目标语言 + if(!article.getLang().equals("zh_CN")){ + return; + } + // 是否启用自动翻译 + if(!article.getTranslation()){ + return; + } + // 查询关联的默认语言栏目ID + CmsNavigation navigation = cmsNavigationService.getOne(new LambdaQueryWrapper().eq(CmsNavigation::getLangCategoryId, article.getCategoryId()).last("limit 1")); + if (ObjectUtil.isNotEmpty(navigation)) { + TranslateDataVo vo = new TranslateDataVo(); + vo.setFormatType("text"); + vo.setSourceLanguage("auto"); + vo.setTargetLanguage("en"); + + // 翻译标题 + vo.setScene("title"); + vo.setSourceText(article.getTitle()); + article.setTitle(getTranslateApi(vo)); + + // 翻译摘要 + vo.setSourceText(article.getComments()); + vo.setScene("description"); + article.setComments(getTranslateApi(vo)); + + // 翻译产品概述 + vo.setSourceText(article.getOverview()); + article.setOverview(getTranslateApi(vo)); + + // 翻译关键词 + vo.setScene("title"); + vo.setSourceText(article.getTags()); + article.setTags(getTranslateApi(vo)); + + // 翻译话题 + vo.setScene("title"); + vo.setSourceText(article.getTopic()); + article.setTopic(getTranslateApi(vo)); + + // 翻译来源 + vo.setScene("title"); + vo.setSourceText(article.getSource()); + article.setSource(getTranslateApi(vo)); + + // 翻译内容 + vo.setScene(null); + vo.setSourceText(article.getContent()); + article.setContent(getTranslateApi(vo)); + + // 其他参数 + article.setLang("en"); + article.setCategoryId(navigation.getNavigationId()); + + + CmsArticle target = cmsArticleService.getOne(new LambdaQueryWrapper().eq(CmsArticle::getLangArticleId,article.getArticleId()).last("limit 1")); + if(article.getIsUpdate() != null && target != null){ + // 更新操作 + if (ObjectUtil.isNotEmpty(target)) { + target.setTitle(article.getTitle()); + target.setImage(article.getImage()); + target.setFiles(article.getFiles()); + target.setComments(article.getComments()); + target.setTags(article.getTags()); + target.setRecommend(article.getRecommend()); + target.setOverview(article.getOverview()); + target.setContent(article.getContent()); + cmsArticleService.updateById(target); + this.update(new LambdaUpdateWrapper().eq(CmsArticleContent::getArticleId, target.getArticleId()).set(CmsArticleContent::getContent,target.getContent())); + } + }else { + // 新增操作 + article.setLangArticleId(article.getArticleId()); + cmsArticleService.save(article); + final CmsArticleContent content = new CmsArticleContent(); + content.setArticleId(article.getArticleId()); + content.setContent(article.getContent()); + content.setTenantId(article.getTenantId()); + this.save(content); + } + } + + } + + /** + * 机器翻译 + * 阿里云接口 + * ... + */ + public String getTranslateApi(TranslateDataVo item){ + String serviceURL = "http://mt.cn-hangzhou.aliyuncs.com/api/translate/web/ecommerce"; + String accessKeyId = "LTAI5tEsyhW4GCKbds1qsopg";// 使用您的阿里云访问密钥 AccessKeyId + String accessKeySecret = "zltFlQrYVAoq2KMFDWgLa3GhkMNeyO"; // 使用您的阿里云访问密钥 + + final Map map = new HashMap<>(); + map.put("FormatType","text"); + map.put("SourceLanguage","auto"); + map.put("TargetLanguage","en"); + map.put("SourceText",item.getSourceText()); + map.put("Scene","description"); + map.put("Context","产品介绍"); + // Sender代码请参考帮助文档“签名方法” + String result = AliYunSender.sendPost(serviceURL, JSONUtil.toJSONString(map), accessKeyId, accessKeySecret); + JSONObject jsonObject = JSON.parseObject(result); + final Object code = jsonObject.get("Code"); + if (code.equals("200")) { + final Object data = jsonObject.get("Data"); + JSONObject data1 = JSON.parseObject(data.toString()); + final Object translated = data1.get("Translated"); + final Object wordCount = data1.get("WordCount"); + return translated.toString(); + } + return ""; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCountServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCountServiceImpl.java new file mode 100644 index 0000000..f5804d4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleCountServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsArticleCountMapper; +import com.gxwebsoft.cms.service.CmsArticleCountService; +import com.gxwebsoft.cms.entity.CmsArticleCount; +import com.gxwebsoft.cms.param.CmsArticleCountParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 点赞文章Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsArticleCountServiceImpl extends ServiceImpl implements CmsArticleCountService { + + @Override + public PageResult pageRel(CmsArticleCountParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsArticleCountParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsArticleCount getByIdRel(Integer id) { + CmsArticleCountParam param = new CmsArticleCountParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleLikeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleLikeServiceImpl.java new file mode 100644 index 0000000..26d7521 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleLikeServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsArticleLikeMapper; +import com.gxwebsoft.cms.service.CmsArticleLikeService; +import com.gxwebsoft.cms.entity.CmsArticleLike; +import com.gxwebsoft.cms.param.CmsArticleLikeParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 点赞文章Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsArticleLikeServiceImpl extends ServiceImpl implements CmsArticleLikeService { + + @Override + public PageResult pageRel(CmsArticleLikeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsArticleLikeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsArticleLike getByIdRel(Integer id) { + CmsArticleLikeParam param = new CmsArticleLikeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleServiceImpl.java new file mode 100644 index 0000000..46b128b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleServiceImpl.java @@ -0,0 +1,250 @@ +package com.gxwebsoft.cms.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.*; +import com.gxwebsoft.cms.mapper.CmsArticleMapper; +import com.gxwebsoft.cms.param.CmsAdParam; +import com.gxwebsoft.cms.service.CmsArticleContentService; +import com.gxwebsoft.cms.service.CmsArticleService; +import com.gxwebsoft.cms.param.CmsArticleParam; +import com.gxwebsoft.cms.service.CmsModelService; +import com.gxwebsoft.cms.service.CmsNavigationService; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.service.UserService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static com.gxwebsoft.common.core.constants.ArticleConstants.CACHE_KEY_ARTICLE; + +/** + * 文章Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsArticleServiceImpl extends ServiceImpl implements CmsArticleService { + @Resource + @Lazy + private CmsNavigationService cmsNavigationService; + @Resource + private CmsArticleContentService cmsArticleContentService; + @Resource + private UserService userService; + @Resource + private CmsModelService cmsModelService; + @Resource + private RedisUtil redisUtil; + + private static final int PERMISSION_PASSWORD = 2; + private static final long CACHE_MINUTES = 30L; + + @Override + public PageResult pageRel(CmsArticleParam param) { + if (param.getParentId() != null && !param.getParentId().equals(0)) { + final List cmsNavigations = cmsNavigationService.list(new LambdaQueryWrapper().eq(CmsNavigation::getParentId, param.getParentId())); + if (!CollectionUtils.isEmpty(cmsNavigations)) { + param.setCategoryIds(cmsNavigations.stream().map(CmsNavigation::getNavigationId).collect(Collectors.toSet())); + } + } + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc,create_time desc"); + List list = baseMapper.selectPageRel(page, param); + + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsArticleParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc,create_time desc"); + + if (StrUtil.isNotBlank(param.getSceneType())) { + // 导出数据 + if (param.getSceneType().equals("Content")) { + final Set collectIds = list.stream().map(CmsArticle::getArticleId).collect(Collectors.toSet()); + final List contents = cmsArticleContentService.list(new LambdaQueryWrapper().in(CmsArticleContent::getArticleId, collectIds)); + final Map> collect = contents.stream().collect(Collectors.groupingBy(CmsArticleContent::getArticleId)); + list.forEach(d -> { + final List cmsArticleContents = collect.get(d.getArticleId()); + final CmsArticleContent content = cmsArticleContents.get(0); + if (ObjectUtil.isNotEmpty(content)) { + d.setContent(content.getContent()); + } + }); + } + } + return page.sortRecords(list); + } + + @Override + public CmsArticle getByIdRel(Integer articleId) { +// String key = CACHE_KEY_ARTICLE + articleId; +// final String cacheInfo = redisUtil.get(key); +// if (StrUtil.isNotBlank(cacheInfo)) { +// final CmsArticle article = JSONUtil.parseObject(cacheInfo, CmsArticle.class); +// // 更新阅读数量 +// assert article != null; +// article.setActualViews(article.getActualViews() + 1); +// updateById(article); +// return article; +// } + // 缓存不存在 + CmsArticleParam param = new CmsArticleParam(); + param.setArticleId(articleId); + final CmsArticle article = param.getOne(baseMapper.selectListRel(param)); + if (ObjectUtil.isNotEmpty(article)) { + // 更新阅读数量 + article.setActualViews(article.getActualViews() + 1); + updateById(article); + // 读取Banner +// final CmsModel model = cmsModelService.getOne(new LambdaQueryWrapper().eq(CmsModel::getModel, article.getModel()).last("limit 1")); +// if (ObjectUtil.isNotEmpty(model)) { +// article.setBanner(model.getBanner()); +// } + // 附加文字内容 + CmsArticleContent content = cmsArticleContentService.getOne(new LambdaQueryWrapper().eq(CmsArticleContent::getArticleId, article.getArticleId()).last("limit 1")); + if (content != null) { + article.setContent(content.getContent()); + } +// redisUtil.set(key, article, CACHE_MINUTES, TimeUnit.MINUTES); + return article; + } + return null; + } + + @Override + public void saveInc(Integer formId) { + final CmsArticle article = getById(formId); + if (ObjectUtil.isNull(article)) { + return; + } + article.setBmUsers(article.getBmUsers() + 1); + updateById(article); + } + + @Override + public boolean saveRel(CmsArticle article) { + try { + // 保存文章模型 + final CmsNavigation cmsNavigation = cmsNavigationService.getByIdRel(article.getCategoryId()); + final CmsModel modelInfo = cmsNavigation.getModelInfo(); + final String componentDetail = modelInfo.getComponentDetail(); + if (ObjectUtil.isNotEmpty(componentDetail)) { + final String[] split = componentDetail.split("/"); + article.setModel(modelInfo.getModel()); + if (split[2].equals(modelInfo.getModel())) { + article.setDetail(split[2].concat("/").concat(split[3])); + } else { + article.setDetail(split[2]); + } + } + // 是否密码可见 + if (article.getPermission() != null && article.getPermission() == PERMISSION_PASSWORD) { + article.setPassword(userService.encodePassword(article.getPassword())); + } + // 保存文章内容 + final boolean save = save(article); + if(StrUtil.isBlank(article.getContent())){ + return true; + } + if (save) { + final CmsArticleContent content = new CmsArticleContent(); + content.setArticleId(article.getArticleId()); + content.setContent(article.getContent()); + content.setTenantId(article.getTenantId()); + cmsArticleContentService.save(content); + // 同步翻译并保存 + cmsArticleContentService.translate(article); + return true; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return false; + } + + @Override + public boolean updateByIdRel(CmsArticle article) { + // 是否密码可见 + if (article.getPermission() == PERMISSION_PASSWORD) { + article.setPassword(userService.encodePassword(article.getPassword())); + } + try { + // 保存文章模型 + final CmsNavigation cmsNavigation = cmsNavigationService.getByIdRel(article.getCategoryId()); + // 模型信息 + if (ObjectUtil.isNotEmpty(cmsNavigation)) { + final CmsModel modelInfo = cmsNavigation.getModelInfo(); + final String componentDetail = modelInfo.getComponentDetail(); + if (ObjectUtil.isNotEmpty(componentDetail)) { + final String[] split = componentDetail.split("/"); + article.setModel(modelInfo.getModel()); + if (split[2].equals(modelInfo.getModel())) { + article.setDetail(split[2].concat("/").concat(split[3])); + } else { + article.setDetail(split[2]); + } + } + } + // 修正父级栏目ID + if (article.getParentId().equals(0)) { + final CmsNavigation current = cmsNavigationService.getById(article.getCategoryId()); + if (ObjectUtil.isNotEmpty(current)) { + article.setParentId(current.getParentId()); + } + } + if (updateById(article)) { + if (StrUtil.isBlank(article.getContent())) { + return true; + } + // 删除缓存 + String key = CACHE_KEY_ARTICLE + article.getArticleId(); + redisUtil.delete(key); + // 更新内容 + final boolean update = cmsArticleContentService.update(new LambdaUpdateWrapper().eq(CmsArticleContent::getArticleId, article.getArticleId()).set(CmsArticleContent::getContent, article.getContent())); + if (update) { + // 同步翻译并保存 + article.setIsUpdate(true); + cmsArticleContentService.translate(article); + return true; + } else { + // 添加内容 + final CmsArticleContent content = new CmsArticleContent(); + content.setArticleId(article.getArticleId()); + content.setContent(article.getContent()); + content.setTenantId(article.getTenantId()); + cmsArticleContentService.save(content); + } + return true; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return false; + } + + @Override + public CmsArticle getByIdCode(String code) { + CmsArticleParam param = new CmsArticleParam(); + param.setCode(code); + return param.getOne(baseMapper.selectListRel(param)); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDesignRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDesignRecordServiceImpl.java new file mode 100644 index 0000000..f1810c4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDesignRecordServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsDesignRecordMapper; +import com.gxwebsoft.cms.service.CmsDesignRecordService; +import com.gxwebsoft.cms.entity.CmsDesignRecord; +import com.gxwebsoft.cms.param.CmsDesignRecordParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 页面组件表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsDesignRecordServiceImpl extends ServiceImpl implements CmsDesignRecordService { + + @Override + public PageResult pageRel(CmsDesignRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsDesignRecordParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsDesignRecord getByIdRel(Integer id) { + CmsDesignRecordParam param = new CmsDesignRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDesignServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDesignServiceImpl.java new file mode 100644 index 0000000..ed53a12 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDesignServiceImpl.java @@ -0,0 +1,157 @@ +package com.gxwebsoft.cms.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.CmsNavigation; +import com.gxwebsoft.cms.entity.TranslateDataVo; +import com.gxwebsoft.cms.mapper.CmsDesignMapper; +import com.gxwebsoft.cms.service.CmsArticleContentService; +import com.gxwebsoft.cms.service.CmsDesignService; +import com.gxwebsoft.cms.entity.CmsDesign; +import com.gxwebsoft.cms.param.CmsDesignParam; +import com.gxwebsoft.cms.service.CmsLangLogService; +import com.gxwebsoft.cms.service.CmsNavigationService; +import com.gxwebsoft.common.core.utils.AliYunSender; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 页面管理记录表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsDesignServiceImpl extends ServiceImpl implements CmsDesignService { + @Resource + private CmsLangLogService cmsLangLogService; + @Resource + @Lazy + private CmsNavigationService cmsNavigationService; + @Resource + @Lazy + private CmsArticleContentService cmsArticleContentService; + + @Override + public PageResult pageRel(CmsDesignParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsDesignParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time asc"); + return page.sortRecords(list); + } + + @Override + public CmsDesign getByIdRel(Integer pageId) { + CmsDesignParam param = new CmsDesignParam(); + param.setPageId(pageId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public void translate(CmsDesign cmsDesign) { + // 是否启用自动翻译 + if (!cmsDesign.getTranslation()) { + return; + } + // 未开启多语言 + if (cmsLangLogService.count() == 0) { + return; + } + // 查询关联的默认语言栏目ID + CmsNavigation navigation = cmsNavigationService.getOne(new LambdaQueryWrapper().eq(CmsNavigation::getLangCategoryId, cmsDesign.getCategoryId()).last("limit 1")); + if (ObjectUtil.isEmpty(navigation)) { + return; + } + // 仅限定新增简体中文才会同步翻译其他目标语言 + if (!navigation.getLang().equals("en")) { + return; + } + // 查找要翻译的单页面信息 + final CmsDesign design = getOne(new LambdaQueryWrapper().eq(CmsDesign::getCategoryId, navigation.getNavigationId()).last("limit 1")); + if (ObjectUtil.isNotEmpty(design)) { + + TranslateDataVo vo = new TranslateDataVo(); + vo.setFormatType("text"); + vo.setSourceLanguage("auto"); + vo.setTargetLanguage("en"); + + // 翻译标题 + vo.setScene("title"); + vo.setSourceText(cmsDesign.getName()); + design.setName(getTranslateApi(vo)); + + // 翻译关键词 + vo.setSourceText(cmsDesign.getKeywords()); + design.setKeywords(getTranslateApi(vo)); + + // 翻译描述 + vo.setSourceText(cmsDesign.getDescription()); + design.setDescription(getTranslateApi(vo)); + + // 翻译页面内容 + vo.setScene(null); + vo.setSourceText(cmsDesign.getContent()); + design.setContent(getTranslateApi(vo)); + design.setShowBanner(cmsDesign.getShowBanner()); + design.setStyle(cmsDesign.getStyle()); + design.setShowButton(cmsDesign.getShowButton()); + design.setBuyUrl(cmsDesign.getBuyUrl()); + updateById(design); + } + } + + /** + * 机器翻译 + * 阿里云接口 + * ... + */ + public String getTranslateApi(TranslateDataVo item) { + String serviceURL = "http://mt.cn-hangzhou.aliyuncs.com/api/translate/web/ecommerce"; + String accessKeyId = "LTAI5tEsyhW4GCKbds1qsopg";// 使用您的阿里云访问密钥 AccessKeyId + String accessKeySecret = "zltFlQrYVAoq2KMFDWgLa3GhkMNeyO"; // 使用您的阿里云访问密钥 + + final Map map = new HashMap<>(); + map.put("FormatType", "text"); + map.put("SourceLanguage", "auto"); + map.put("TargetLanguage", "en"); + map.put("SourceText", item.getSourceText()); + map.put("Scene", "description"); + map.put("Context", "产品介绍"); + // Sender代码请参考帮助文档“签名方法” + String result = AliYunSender.sendPost(serviceURL, JSONUtil.toJSONString(map), accessKeyId, accessKeySecret); + JSONObject jsonObject = JSON.parseObject(result); + final Object code = jsonObject.get("Code"); + if (code.equals("200")) { + final Object data = jsonObject.get("Data"); + JSONObject data1 = JSON.parseObject(data.toString()); + final Object translated = data1.get("Translated"); + final Object wordCount = data1.get("WordCount"); + return translated.toString(); + } + return ""; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDomainServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDomainServiceImpl.java new file mode 100644 index 0000000..dea153f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsDomainServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsDomainMapper; +import com.gxwebsoft.cms.service.CmsDomainService; +import com.gxwebsoft.cms.entity.CmsDomain; +import com.gxwebsoft.cms.param.CmsDomainParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 网站域名记录表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Service +public class CmsDomainServiceImpl extends ServiceImpl implements CmsDomainService { + + @Override + public PageResult pageRel(CmsDomainParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsDomainParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsDomain getByIdRel(Integer id) { + CmsDomainParam param = new CmsDomainParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsFormRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsFormRecordServiceImpl.java new file mode 100644 index 0000000..4156faf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsFormRecordServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsFormRecordMapper; +import com.gxwebsoft.cms.service.CmsFormRecordService; +import com.gxwebsoft.cms.entity.CmsFormRecord; +import com.gxwebsoft.cms.param.CmsFormRecordParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 表单数据记录表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsFormRecordServiceImpl extends ServiceImpl implements CmsFormRecordService { + + @Override + public PageResult pageRel(CmsFormRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsFormRecordParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsFormRecord getByIdRel(Integer formRecordId) { + CmsFormRecordParam param = new CmsFormRecordParam(); + param.setFormRecordId(formRecordId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsFormServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsFormServiceImpl.java new file mode 100644 index 0000000..b42ffb1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsFormServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsFormMapper; +import com.gxwebsoft.cms.service.CmsFormService; +import com.gxwebsoft.cms.entity.CmsForm; +import com.gxwebsoft.cms.param.CmsFormParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 表单设计表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsFormServiceImpl extends ServiceImpl implements CmsFormService { + + @Override + public PageResult pageRel(CmsFormParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsFormParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsForm getByIdRel(Integer formId) { + CmsFormParam param = new CmsFormParam(); + param.setFormId(formId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLangLogServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLangLogServiceImpl.java new file mode 100644 index 0000000..f8627cb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLangLogServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsLangLogMapper; +import com.gxwebsoft.cms.service.CmsLangLogService; +import com.gxwebsoft.cms.entity.CmsLangLog; +import com.gxwebsoft.cms.param.CmsLangLogParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 国际化记录启用Service实现 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Service +public class CmsLangLogServiceImpl extends ServiceImpl implements CmsLangLogService { + + @Override + public PageResult pageRel(CmsLangLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsLangLogParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsLangLog getByIdRel(Integer id) { + CmsLangLogParam param = new CmsLangLogParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLangServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLangServiceImpl.java new file mode 100644 index 0000000..4e27908 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLangServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsLangMapper; +import com.gxwebsoft.cms.service.CmsLangService; +import com.gxwebsoft.cms.entity.CmsLang; +import com.gxwebsoft.cms.param.CmsLangParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 国际化Service实现 + * + * @author 科技小王子 + * @since 2025-01-06 19:29:26 + */ +@Service +public class CmsLangServiceImpl extends ServiceImpl implements CmsLangService { + + @Override + public PageResult pageRel(CmsLangParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsLangParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsLang getByIdRel(Integer id) { + CmsLangParam param = new CmsLangParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLinkServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLinkServiceImpl.java new file mode 100644 index 0000000..b85d845 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsLinkServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsLinkMapper; +import com.gxwebsoft.cms.service.CmsLinkService; +import com.gxwebsoft.cms.entity.CmsLink; +import com.gxwebsoft.cms.param.CmsLinkParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 常用链接Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsLinkServiceImpl extends ServiceImpl implements CmsLinkService { + + @Override + public PageResult pageRel(CmsLinkParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc,create_time asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsLinkParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time asc"); + return page.sortRecords(list); + } + + @Override + public CmsLink getByIdRel(Integer id) { + CmsLinkParam param = new CmsLinkParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsModelServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsModelServiceImpl.java new file mode 100644 index 0000000..071f7fa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsModelServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsModelMapper; +import com.gxwebsoft.cms.service.CmsModelService; +import com.gxwebsoft.cms.entity.CmsModel; +import com.gxwebsoft.cms.param.CmsModelParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 模型Service实现 + * + * @author 科技小王子 + * @since 2024-11-26 15:44:53 + */ +@Service +public class CmsModelServiceImpl extends ServiceImpl implements CmsModelService { + + @Override + public PageResult pageRel(CmsModelParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsModelParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time asc"); + return page.sortRecords(list); + } + + @Override + public CmsModel getByIdRel(Integer modelId) { + CmsModelParam param = new CmsModelParam(); + param.setModelId(modelId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsNavigationServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsNavigationServiceImpl.java new file mode 100644 index 0000000..7a541ba --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsNavigationServiceImpl.java @@ -0,0 +1,190 @@ +package com.gxwebsoft.cms.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.CmsDesign; +import com.gxwebsoft.cms.entity.CmsModel; +import com.gxwebsoft.cms.mapper.CmsNavigationMapper; +import com.gxwebsoft.cms.service.CmsDesignService; +import com.gxwebsoft.cms.service.CmsModelService; +import com.gxwebsoft.cms.service.CmsNavigationService; +import com.gxwebsoft.cms.entity.CmsNavigation; +import com.gxwebsoft.cms.param.CmsNavigationParam; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.service.UserService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.text.MessageFormat; +import java.util.List; + +/** + * 网站导航记录表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:47:57 + */ +@Service +public class CmsNavigationServiceImpl extends ServiceImpl implements CmsNavigationService { + @Resource + @Lazy + private CmsDesignService cmsDesignService; + @Resource + private CmsModelService cmsModelService; + @Resource + private UserService userService; + + @Override + public PageResult pageRel(CmsNavigationParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, position asc, navigation_id asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsNavigationParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, position asc,navigation_id asc"); + return page.sortRecords(list); + } + + @Override + public CmsNavigation getByIdRel(Integer navigationId) { + CmsNavigationParam param = new CmsNavigationParam(); + param.setNavigationId(navigationId); + CmsNavigation navigation; + navigation = param.getOne(baseMapper.selectListRel(param)); + if (ObjectUtil.isEmpty(navigation)) { + return null; + } + // 父级栏目并且是page模型则读取子项目第一条 + if (navigation.getParentId().equals(0) && navigation.getModel().equals("page")) { + final CmsNavigation parent = this.getOne(new LambdaQueryWrapper().eq(CmsNavigation::getParentId, navigation.getNavigationId()).last("limit 1")); + if (ObjectUtil.isNotEmpty(parent)) { + navigation = parent; + } + } + // 所属页面 + navigation.setDesign(cmsDesignService.getOne(new LambdaQueryWrapper().eq(CmsDesign::getCategoryId, navigation.getNavigationId()).last("limit 1"))); + // 所属模型 + if (StrUtil.isNotBlank(navigation.getModel())) { + navigation.setModelInfo(cmsModelService.getOne(new LambdaQueryWrapper().eq(CmsModel::getModel, navigation.getModel()).last("limit 1"))); + if (StrUtil.isBlank(navigation.getBanner())) { + navigation.setBanner(navigation.getModelInfo().getBanner()); + navigation.setMpBanner(navigation.getModelInfo().getThumb()); + } + } + return navigation; + } + + /** + * 配置路由生成规则 + * path:/模型/导航ID + * component: /pages/模型/index.vue + */ + @Override + public void saveAsync(CmsNavigation navigation) { + // TODO 1.设计path和component生产规则 + final String path = navigation.getPath(); + final CmsModel model = cmsModelService.getOne(new LambdaQueryWrapper().eq(CmsModel::getModel, navigation.getModel()).last("limit 1")); + // 1.自动配置 + navigation.setPath("/" + navigation.getModel() + "/" + navigation.getNavigationId()); + navigation.setTarget("_self"); + navigation.setComponent(MessageFormat.format("/pages/{0}/{1}", navigation.getModel(), "[id].vue")); + + // 1.2自定义文件后缀 + if(!navigation.getModel().equals("index") && model.getSuffix() != null){ + navigation.setPath(navigation.getPath() + model.getSuffix()); + } + + // 2.特例:默认首页 + if (navigation.getPath().equals("/") || navigation.getModel().equals("index")) { + final long count = count(new LambdaQueryWrapper().eq(CmsNavigation::getPath, "/").eq(CmsNavigation::getLang,navigation.getLang())); + if(count > 1){ + throw new BusinessException("路由地址已存在!"); + } + navigation.setPath("/"); + navigation.setComponent("/pages/index.vue"); + navigation.setModel("index"); + navigation.setHome(1); + } + // 3.外链模型 + if (navigation.getModel().equals("links")) { + navigation.setPath(path); + navigation.setTarget("_blank"); + navigation.setComponent(null); + } + + // 4.密码可见 + if(StrUtil.isNotBlank(navigation.getPassword())){ + navigation.setPassword(userService.encodePassword(navigation.getPassword())); + } + + // 更新操作 + updateById(navigation); + + // TODO 2.同步添加页面 + final CmsDesign one = cmsDesignService.getOne(new LambdaQueryWrapper().eq(CmsDesign::getCategoryId, navigation.getNavigationId()).eq(CmsDesign::getDeleted, 0).last("limit 1")); + if (ObjectUtil.isEmpty(one)) { + final CmsDesign design = new CmsDesign(); + design.setName(navigation.getTitle()); + design.setCategoryId(navigation.getNavigationId()); + design.setKeywords(navigation.getTitle()); + design.setDescription(navigation.getComments()); + design.setPath(navigation.getPath()); + design.setComponent(navigation.getComponent()); + design.setTenantId(navigation.getTenantId()); + if (StrUtil.isNotBlank(navigation.getContent())) { + design.setContent(navigation.getContent()); + } + cmsDesignService.save(design); + } + + // 面包屑 +// final CmsNavigation parent = getById(navigation.getParentId()); +// if (ObjectUtil.isNotEmpty(parent) && navigation.getParentId() > 0) { +// navigation.setParentName(parent.getTitle()); +// navigation.setParentPath(parent.getPath()); +// navigation.setParentId(parent.getNavigationId()); +// updateById(parent); +// } + } + + @Override + public CmsNavigation getByIdRelByCodeRel(String code) { + CmsNavigationParam param = new CmsNavigationParam(); + param.setCode(code); + CmsNavigation navigation; + navigation = param.getOne(baseMapper.selectListRel(param)); + if (ObjectUtil.isEmpty(navigation)) { + return null; + } + // 父级栏目并且是page模型则读取子项目第一条 + if (navigation.getParentId().equals(0) && navigation.getModel().equals("page")) { + final CmsNavigation parent = this.getOne(new LambdaQueryWrapper().eq(CmsNavigation::getParentId, navigation.getNavigationId()).last("limit 1")); + if (ObjectUtil.isNotEmpty(parent)) { + navigation = parent; + } + } + // 所属页面 + navigation.setDesign(cmsDesignService.getOne(new LambdaQueryWrapper().eq(CmsDesign::getCategoryId, navigation.getNavigationId()).last("limit 1"))); + // 所属模型 + if (StrUtil.isNotBlank(navigation.getModel())) { + navigation.setModelInfo(cmsModelService.getOne(new LambdaQueryWrapper().eq(CmsModel::getModel, navigation.getModel()).last("limit 1"))); + if (StrUtil.isBlank(navigation.getBanner())) { + navigation.setBanner(navigation.getModelInfo().getBanner()); + navigation.setMpBanner(navigation.getModelInfo().getThumb()); + } + } + return navigation; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsStatisticsServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsStatisticsServiceImpl.java new file mode 100644 index 0000000..b965b41 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsStatisticsServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsStatisticsMapper; +import com.gxwebsoft.cms.service.CmsStatisticsService; +import com.gxwebsoft.cms.entity.CmsStatistics; +import com.gxwebsoft.cms.param.CmsStatisticsParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 站点统计信息表Service实现 + * + * @author 科技小王子 + * @since 2025-07-25 12:32:06 + */ +@Service +public class CmsStatisticsServiceImpl extends ServiceImpl implements CmsStatisticsService { + + @Override + public PageResult pageRel(CmsStatisticsParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsStatisticsParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsStatistics getByIdRel(Integer id) { + CmsStatisticsParam param = new CmsStatisticsParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsTemplateServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsTemplateServiceImpl.java new file mode 100644 index 0000000..3be39e4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsTemplateServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.mapper.CmsTemplateMapper; +import com.gxwebsoft.cms.service.CmsTemplateService; +import com.gxwebsoft.cms.entity.CmsTemplate; +import com.gxwebsoft.cms.param.CmsTemplateParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 网站模版Service实现 + * + * @author 科技小王子 + * @since 2025-01-21 14:21:16 + */ +@Service +public class CmsTemplateServiceImpl extends ServiceImpl implements CmsTemplateService { + + @Override + public PageResult pageRel(CmsTemplateParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsTemplateParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsTemplate getByIdRel(Integer id) { + CmsTemplateParam param = new CmsTemplateParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteFieldServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteFieldServiceImpl.java new file mode 100644 index 0000000..a1ec98f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteFieldServiceImpl.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.CmsWebsiteField; +import com.gxwebsoft.cms.mapper.CmsWebsiteFieldMapper; +import com.gxwebsoft.cms.param.CmsWebsiteFieldParam; +import com.gxwebsoft.cms.service.CmsWebsiteFieldService; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用参数Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Service +public class CmsWebsiteFieldServiceImpl extends ServiceImpl implements CmsWebsiteFieldService { + + @Override + public PageResult pageRel(CmsWebsiteFieldParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsWebsiteFieldParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time asc"); + return page.sortRecords(list); + } + + @Override + public CmsWebsiteField getByIdRel(Integer id) { + CmsWebsiteFieldParam param = new CmsWebsiteFieldParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public CmsWebsiteField getByCodeRel(String code) { + CmsWebsiteFieldParam param = new CmsWebsiteFieldParam(); + param.setName(code); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImpl.java new file mode 100644 index 0000000..b6bdf7d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImpl.java @@ -0,0 +1,407 @@ +package com.gxwebsoft.cms.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.*; +import com.gxwebsoft.cms.mapper.*; +import com.gxwebsoft.cms.param.*; +import com.gxwebsoft.cms.service.*; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.CompanyService; +import com.gxwebsoft.common.system.service.UserService; +import com.gxwebsoft.shop.vo.ShopVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * 网站信息记录表Service实现 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Slf4j +@Service +public class CmsWebsiteServiceImpl extends ServiceImpl implements CmsWebsiteService { + + private static final String SITE_INFO_KEY_PREFIX = "SiteInfo:"; + @Resource + private CmsWebsiteFieldMapper cmsWebsiteFieldMapper; + @Resource + private CmsModelMapper cmsModelMapper; + @Resource + private CmsNavigationMapper cmsNavigationMapper; + @Resource + private CmsLangLogMapper cmsLangLogMapper; + @Resource + private CmsAdMapper cmsAdMapper; + @Resource + private CmsLinkMapper cmsLinkMapper; + @Resource + private CmsArticleMapper cmsArticleMapper; + @Resource + private CmsWebsiteFieldService cmsWebsiteFieldService; + @Resource + private CmsModelService cmsModelService; + @Resource + private CmsNavigationService cmsNavigationService; + @Resource + private CmsLangLogService cmsLangLogService; + @Resource + private CmsAdService cmsAdService; + @Resource + private CmsLinkService cmsLinkService; + @Resource + private CmsArticleService cmsArticleService; + @Resource + private CmsArticleContentService cmsArticleContentService; + @Resource + private CmsWebsiteMapper cmsWebsiteMapper; + @Resource + private RedisUtil redisUtil; + @Resource + private UserService userService; + @Resource + private CompanyService companyService; + + @Override + public PageResult pageRel(CmsWebsiteParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + list.forEach(d -> { + LocalDateTime now = LocalDateTime.now(); + if (d.getExpirationTime() != null) { + // 将Date转换为LocalDateTime进行计算 + LocalDateTime expirationTime = d.getExpirationTime().toInstant() + .atZone(java.time.ZoneId.systemDefault()) + .toLocalDateTime(); + // 即将过期(30天内过期的) + d.setSoon(expirationTime.minusDays(30).compareTo(now)); + // 是否过期 -1已过期 大于0 未过期 + d.setStatus(expirationTime.compareTo(now)); + } else { + d.setSoon(0); + d.setStatus(1); + } + }); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsWebsiteParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsWebsite getByIdRel(Integer websiteId) { + CmsWebsiteParam param = new CmsWebsiteParam(); + param.setWebsiteId(websiteId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public PageResult pageRelAll(CmsWebsiteParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRelAll(page, param); + list.forEach(d -> { + LocalDateTime now = LocalDateTime.now(); + if (d.getExpirationTime() != null) { + // 将Date转换为LocalDateTime进行计算 + LocalDateTime expirationTime = d.getExpirationTime().toInstant() + .atZone(java.time.ZoneId.systemDefault()) + .toLocalDateTime(); + // 即将过期(30天内过期的) + d.setSoon(expirationTime.minusDays(30).compareTo(now)); + // 是否过期 -1已过期 大于0 未过期 + d.setStatus(expirationTime.compareTo(now)); + } else { + d.setSoon(0); + d.setStatus(1); + } + }); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public CmsWebsite create(CmsWebsite website) { + final User loginUser = website.getLoginUser(); + // 创建站点 +// website.setWebsiteName("网站名称"); + website.setWebsiteCode("site-".concat(loginUser.getTenantId().toString())); +// if (StrUtil.isBlank(website.getWebsiteLogo())) { +// website.setWebsiteLogo("https://oss.wsdns.cn/20240822/0252ad4ed46449cdafe12f8d3d96c2ea.svg"); +// } + website.setWebsiteIcon("/favicon.ico"); + website.setWebsiteType("云·企业官网"); + website.setAdminUrl("site.websoft.top"); + website.setVersion(10); + website.setExpirationTime(java.util.Date.from(LocalDateTime.now().plusMonths(1) + .atZone(java.time.ZoneId.systemDefault()).toInstant())); + website.setUserId(loginUser.getUserId()); + website.setDeveloper(loginUser.getNickname()); + website.setTenantId(loginUser.getTenantId()); + website.setTemplateId(loginUser.getTemplateId()); + website.setCompanyId(loginUser.getCompanyId()); + + // 初始化数据 + if(save(website)){ + // 插入网站设置记录 +// final CmsWebsiteSetting setting = new CmsWebsiteSetting(); +// setting.setWebsiteId(website.getWebsiteId()); +// setting.setCreateTime(DateUtil.date()); +// setting.setUpdateTime(DateUtil.date()); +// cmsWebsiteSettingService.save(setting); + + // 将网站创建者的userId做为查询条件 10257(4716),10324(6978),10398(26564) + Integer websiteUserId = website.getTemplateId(); + + // 只有当templateId存在时才执行复制操作 + if (websiteUserId != null && websiteUserId > 0) { + // TODO 国际化 + final CmsLangLogParam cmsLangLogParam = new CmsLangLogParam(); + cmsLangLogParam.setWebsiteUserId(websiteUserId); + final List logs = cmsLangLogMapper.selectListAllRel(cmsLangLogParam); + logs.forEach(d->{ + d.setTenantId(loginUser.getTenantId()); + }); + cmsLangLogService.saveBatch(logs); + + // TODO 复制参数 + final CmsWebsiteFieldParam param = new CmsWebsiteFieldParam(); + param.setUserId(websiteUserId); + final List fields = cmsWebsiteFieldMapper.selectListAllRel(param); + fields.forEach(d->{ + d.setTenantId(loginUser.getTenantId()); + }); + cmsWebsiteFieldService.saveBatch(fields); + + // TODO 复制模型 + final CmsModelParam modelParam = new CmsModelParam(); + modelParam.setWebsiteUserId(websiteUserId); + final List models = cmsModelMapper.selectListAllRel(modelParam); + models.forEach(d->{ + d.setUserId(loginUser.getUserId()); + d.setTenantId(loginUser.getTenantId()); + }); + cmsModelService.saveBatch(models); + + // TODO 复制广告 + final CmsAdParam cmsAdParam = new CmsAdParam(); + cmsAdParam.setWebsiteUserId(websiteUserId); + final List ads = cmsAdMapper.selectListAllRel(cmsAdParam); + ads.forEach(d -> { + d.setUserId(loginUser.getUserId()); + d.setTenantId(loginUser.getTenantId()); + }); + cmsAdService.saveBatch(ads); + + // TODO 复制链接 + CmsLinkParam cmsLinkParam = new CmsLinkParam(); + cmsLinkParam.setWebsiteUserId(websiteUserId); + final List links = cmsLinkMapper.selectListAllRel(cmsLinkParam); + links.forEach(d -> { + d.setUserId(loginUser.getUserId()); + d.setTenantId(loginUser.getTenantId()); + }); + cmsLinkService.saveBatch(links); + + // TODO 复制栏目和文章、文章内容 + CmsNavigationParam cmsNavigationParam = new CmsNavigationParam(); + cmsNavigationParam.setWebsiteUserId(websiteUserId); + cmsNavigationParam.setParentId(0); + final List parents = cmsNavigationMapper.selectListAllRel(cmsNavigationParam); + parents.forEach(d -> { + Integer navigationId = d.getNavigationId(); + // 复制顶级栏目 + d.setTenantId(loginUser.getTenantId()); + d.setUserId(loginUser.getUserId()); + if (cmsNavigationService.save(d)) { + cmsNavigationService.saveAsync(d); + // 复制栏目文章 + CmsArticleParam cmsArticleParam = new CmsArticleParam(); + cmsArticleParam.setWebsiteUserId(websiteUserId); + cmsArticleParam.setCategoryId(navigationId); + final List articles = cmsArticleMapper.selectListAllRel(cmsArticleParam); + articles.forEach(a -> { + a.setCategoryId(d.getNavigationId()); + a.setUserId(loginUser.getUserId()); + a.setTenantId(loginUser.getTenantId()); + if (cmsArticleService.save(a)) { + final CmsArticleContent content = new CmsArticleContent(); + content.setArticleId(a.getArticleId()); + content.setContent(a.getContent()); + cmsArticleContentService.save(content); + } + }); + // 复制子栏目 + cmsNavigationParam.setParentId(navigationId); + final List navigations = cmsNavigationMapper.selectListAllRel(cmsNavigationParam); + navigations.forEach(c -> { + cmsArticleParam.setCategoryId(c.getNavigationId()); + c.setParentId(d.getNavigationId()); + c.setTenantId(loginUser.getTenantId()); + c.setUserId(loginUser.getUserId()); + cmsNavigationService.save(c); + cmsNavigationService.saveAsync(c); + // 复制子栏目文章 + final List articles2 = cmsArticleMapper.selectListAllRel(cmsArticleParam); + articles2.forEach(a2 -> { + a2.setCategoryId(c.getNavigationId()); + a2.setParentId(c.getParentId()); + a2.setUserId(loginUser.getUserId()); + a2.setTenantId(loginUser.getTenantId()); + if (cmsArticleService.save(a2)) { + final CmsArticleContent content = new CmsArticleContent(); + content.setArticleId(a2.getArticleId()); + content.setContent(a2.getContent()); + cmsArticleContentService.save(content); + } + }); + }); + } + }); + } else { + log.warn("没有有效的模板ID,跳过复制操作"); + } + + } + return website; + } + + @Override + public CmsWebsite getByIdRelAll(Integer id) { + return cmsWebsiteMapper.getByIdRelAll(id); + } + + @Override + public boolean updateByIdAll(CmsWebsite cmsWebsite) { + return baseMapper.updateByIdAll(cmsWebsite); + } + + @Override + public boolean removeByIdAll(Integer id) { + return baseMapper.removeByIdAll(id); + } + + @Override + public CmsWebsite getByTenantId(Integer tenantId) { + return baseMapper.getByTenantId(tenantId); + } + + @Override + public ShopVo getSiteInfo(Integer tenantId) { + // 参数验证 + if (ObjectUtil.isEmpty(tenantId)) { + throw new IllegalArgumentException("租户ID不能为空"); + } + + // 尝试从缓存获取 + String cacheKey = SITE_INFO_KEY_PREFIX + tenantId; + String siteInfo = redisUtil.get(cacheKey); + if (StrUtil.isNotBlank(siteInfo)) { + log.info("从缓存获取网站信息,租户ID: {}", tenantId); + try { + return JSONUtil.parseObject(siteInfo, ShopVo.class); + } catch (Exception e) { + log.warn("缓存解析失败,从数据库重新获取: {}", e.getMessage()); + } + } + + // 从数据库获取站点信息 + CmsWebsite website = getWebsiteFromDatabase(tenantId); + + + if (website == null) { + throw new RuntimeException("请先创建站点"); + } + + // 构建完整的网站信息 + buildCompleteWebsiteInfo(website); + + // 处理过期时间 + CmsWebsiteServiceImplHelper.processExpirationTime(website); + + // 转换为VO对象 + ShopVo websiteVO = CmsWebsiteServiceImplHelper.convertToVO(website); + + // 缓存结果 + try { + redisUtil.set(cacheKey, websiteVO, 1L, TimeUnit.DAYS); + } catch (Exception e) { + log.warn("缓存网站信息失败: {}", e.getMessage()); + } + + log.info("获取网站信息成功,网站ID: {}, 租户ID: {}", website.getWebsiteId(), tenantId); + return websiteVO; + } + + @Override + public void clearSiteInfoCache(Integer tenantId) { + if (tenantId != null) { + String cacheKey = SITE_INFO_KEY_PREFIX + tenantId; + redisUtil.delete(cacheKey); + log.info("清除网站信息缓存成功,租户ID: {}", tenantId); + } + } + + /** + * 从数据库获取网站信息 + */ + private CmsWebsite getWebsiteFromDatabase(Integer tenantId) { + return getByTenantId(tenantId); + } + + /** + * 构建完整的网站信息 + */ + private void buildCompleteWebsiteInfo(CmsWebsite website) { + // 设置网站状态 + CmsWebsiteServiceImplHelper.setWebsiteStatus(website); + + // 设置网站配置 + CmsWebsiteServiceImplHelper.setWebsiteConfig(website); + + // 设置网站导航 + setWebsiteNavigation(website); + + // 设置网站设置信息 + CmsWebsiteServiceImplHelper.setWebsiteSetting(website); + + // 设置服务器时间信息 + CmsWebsiteServiceImplHelper.setServerTimeInfo(website); + } + + /** + * 设置网站导航 + */ + private void setWebsiteNavigation(CmsWebsite website) { + // 获取顶部导航 + CmsNavigationParam navigationParam = new CmsNavigationParam(); + navigationParam.setHide(0); + navigationParam.setTop(0); + navigationParam.setBottom(null); + List topNavs = cmsNavigationService.listRel(navigationParam); + website.setTopNavs(topNavs); + + // 获取底部导航 + navigationParam.setTop(null); + navigationParam.setBottom(0); + List bottomNavs = cmsNavigationService.listRel(navigationParam); + website.setBottomNavs(bottomNavs); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImplHelper.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImplHelper.java new file mode 100644 index 0000000..85647df --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImplHelper.java @@ -0,0 +1,239 @@ +package com.gxwebsoft.cms.service.impl; + +import com.gxwebsoft.cms.entity.CmsNavigation; +import com.gxwebsoft.cms.entity.CmsWebsite; +import com.gxwebsoft.shop.vo.MenuVo; +import com.gxwebsoft.shop.vo.ShopVo; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +/** + * CmsWebsiteServiceImpl 辅助方法 + * 包含转换和处理逻辑 + */ +public class CmsWebsiteServiceImplHelper { + + /** + * 处理过期时间,只处理真正需要的字段 + */ + public static void processExpirationTime(CmsWebsite website) { + if (website.getExpirationTime() != null) { + LocalDateTime now = LocalDateTime.now(); + Date expirationTimeDate = website.getExpirationTime(); + + // 将Date转换为LocalDateTime进行计算 + LocalDateTime expirationTime = expirationTimeDate.toInstant() + .atZone(java.time.ZoneId.systemDefault()) + .toLocalDateTime(); + + // 计算是否即将过期(30天内过期) + LocalDateTime thirtyDaysLater = now.plusDays(30); + website.setSoon(expirationTime.isBefore(thirtyDaysLater) ? 1 : 0); + + // 计算是否已过期 + website.setExpired(expirationTime.isBefore(now) ? -1 : 1); + + // 计算剩余天数 + long daysBetween = ChronoUnit.DAYS.between(now, expirationTime); + website.setExpiredDays(daysBetween); + } else { + // 没有过期时间的默认值 + website.setSoon(0); + website.setExpired(1); + website.setExpiredDays(0L); + } + } + + /** + * 将实体对象转换为VO对象 + */ + public static ShopVo convertToVO(CmsWebsite website) { + ShopVo vo = new ShopVo(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + // 基本信息 + vo.setAppId(website.getTenantId()); + vo.setAppName(website.getTenantName()); + vo.setTitle(website.getWebsiteName()); + vo.setKeywords(website.getKeywords()); + vo.setDescription(website.getComments()); + vo.setLogo(website.getWebsiteLogo()); + vo.setMpQrCode(website.getWebsiteDarkLogo()); + vo.setDomain(website.getDomain()); + vo.setAdminUrl(website.getAdminUrl()); + vo.setApiUrl(website.getApiUrl()); + vo.setRunning(website.getRunning()); + vo.setVersion(website.getVersion()); + if (website.getCreateTime() != null) { + // 将Date转换为LocalDateTime后格式化 + LocalDateTime createTime = website.getCreateTime().toInstant() + .atZone(java.time.ZoneId.systemDefault()) + .toLocalDateTime(); + vo.setCreateTime(createTime.format(formatter)); + } + + // 时间字段 - 格式化为字符串 + if (website.getExpirationTime() != null) { + // 将Date转换为LocalDateTime后格式化 + LocalDateTime expirationTime = website.getExpirationTime().toInstant() + .atZone(java.time.ZoneId.systemDefault()) + .toLocalDateTime(); + vo.setExpirationTime(expirationTime.format(formatter)); + } + + // 过期相关信息 + vo.setExpired(website.getExpired()); + vo.setExpiredDays(website.getExpiredDays()); + vo.setSoon(website.getSoon()); + + // 状态信息 + vo.setStatusIcon(website.getStatusIcon()); + vo.setStatusText(website.getStatusText()); + + // 复杂对象 + vo.setConfig(website.getConfig()); + vo.setServerTime(website.getServerTime()); + vo.setSetting(website.getSetting()); // CmsWebsiteSetting对象可以直接设置给Object类型 + + // 导航信息 + vo.setTopNavs(convertNavigationToVO(website.getTopNavs())); + vo.setBottomNavs(convertNavigationToVO(website.getBottomNavs())); + + return vo; + } + + /** + * 安全转换 target 字段为整数 + * + * @param target 字符串类型的 target 值 + * @return 对应的整数值 + */ + private static Integer convertTargetToInteger(String target) { + if (target == null) { + return 0; // 默认值:当前窗口 + } + + switch (target.toLowerCase()) { + case "_self": + return 0; // 当前窗口 + case "_blank": + return 1; // 新窗口 + default: + // 如果是数字字符串,尝试直接转换 + try { + return Integer.valueOf(target); + } catch (NumberFormatException e) { + // 转换失败时返回默认值 + return 0; + } + } + } + + /** + * 转换导航列表为VO + * 整理导航栏目录结构(ShopInfo) + */ + public static List convertNavigationToVO(List navigations) { + if (navigations == null) { + return null; + } + + return navigations.stream().map(nav -> { + MenuVo navVO = new MenuVo(); + navVO.setNavigationId(nav.getNavigationId()); + navVO.setTitle(nav.getTitle()); + navVO.setPath(nav.getPath()); + navVO.setIcon(nav.getIcon()); + navVO.setColor(nav.getColor()); + navVO.setParentId(nav.getParentId()); + navVO.setSort(nav.getSortNumber()); + navVO.setHide(nav.getHide()); + navVO.setTop(nav.getTop()); + navVO.setPath(nav.getPath()); + navVO.setTarget(convertTargetToInteger(nav.getTarget())); + navVO.setModel(nav.getModel()); + + // 递归处理子导航 + if (nav.getChildren() != null) { + navVO.setChildren(convertNavigationToVO(nav.getChildren())); + } + + return navVO; + }).collect(Collectors.toList()); + } + + /** + * 设置网站状态 + */ + public static void setWebsiteStatus(CmsWebsite website) { + if (website.getRunning() != null) { + switch (website.getRunning()) { + case 0: + website.setStatusIcon("🔴"); + website.setStatusText("未开通"); + break; + case 1: + website.setStatusIcon("🟢"); + website.setStatusText("正常运行"); + break; + case 2: + website.setStatusIcon("🟡"); + website.setStatusText("维护中"); + break; + case 3: + website.setStatusIcon("🔴"); + website.setStatusText("违规关停"); + break; + default: + website.setStatusIcon("❓"); + website.setStatusText("未知状态"); + } + } + } + + /** + * 设置网站配置 + */ + public static void setWebsiteConfig(CmsWebsite website) { + HashMap config = new HashMap<>(); + config.put("websiteName", website.getWebsiteName()); + config.put("websiteComments", website.getComments()); + config.put("websiteTitle", website.getWebsiteName()); + config.put("websiteKeywords", website.getKeywords()); + config.put("websiteDescription", website.getContent()); // 使用 content 字段作为描述 + config.put("websiteLogo", website.getWebsiteLogo()); + config.put("websiteIcon", website.getWebsiteIcon()); + config.put("domain", website.getDomain()); + website.setConfig(config); + } + + /** + * 设置服务器时间信息 + */ + public static void setServerTimeInfo(CmsWebsite website) { + HashMap serverTime = new HashMap<>(); + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + serverTime.put("currentTime", now.format(formatter)); + serverTime.put("timestamp", System.currentTimeMillis()); + serverTime.put("timezone", "Asia/Shanghai"); + + website.setServerTime(serverTime); + } + + /** + * 设置网站设置信息 + */ + public static void setWebsiteSetting(CmsWebsite website) { + // 这里可以根据需要设置网站的其他设置信息 + // 暂时设置为null,因为setting字段类型是CmsWebsiteSetting而不是HashMap + website.setSetting(null); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteSettingServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteSettingServiceImpl.java new file mode 100644 index 0000000..1238f31 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteSettingServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.cms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.CmsWebsiteSetting; +import com.gxwebsoft.cms.mapper.CmsWebsiteSettingMapper; +import com.gxwebsoft.cms.param.CmsWebsiteSettingParam; +import com.gxwebsoft.cms.service.CmsWebsiteSettingService; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 网站设置Service实现 + * + * @author 科技小王子 + * @since 2025-02-19 01:35:44 + */ +@Service +public class CmsWebsiteSettingServiceImpl extends ServiceImpl implements CmsWebsiteSettingService { + + @Override + public PageResult pageRel(CmsWebsiteSettingParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsWebsiteSettingParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public CmsWebsiteSetting getByIdRel(Integer id) { + CmsWebsiteSettingParam param = new CmsWebsiteSettingParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/Constants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/Constants.java new file mode 100644 index 0000000..be48387 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/Constants.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.common.core; + +/** + * 系统常量 + * Created by WebSoft on 2019-10-29 15:55 + */ +public class Constants { + /** + * 默认成功码 + */ + public static final int RESULT_OK_CODE = 0; + + /** + * 默认失败码 + */ + public static final int RESULT_ERROR_CODE = 1; + + /** + * 默认成功信息 + */ + public static final String RESULT_OK_MSG = "操作成功"; + + /** + * 默认失败信息 + */ + public static final String RESULT_ERROR_MSG = "操作失败"; + + /** + * 无权限错误码 + */ + public static final int UNAUTHORIZED_CODE = 403; + + /** + * 无权限提示信息 + */ + public static final String UNAUTHORIZED_MSG = "没有访问权限"; + + /** + * 未认证错误码 + */ + public static final int UNAUTHENTICATED_CODE = 401; + + /** + * 未认证提示信息 + */ + public static final String UNAUTHENTICATED_MSG = "请先登录"; + + /** + * 登录过期错误码 + */ + public static final int TOKEN_EXPIRED_CODE = 401; + + /** + * 登录过期提示信息 + */ + public static final String TOKEN_EXPIRED_MSG = "登录已过期"; + + /** + * 非法token错误码 + */ + public static final int BAD_CREDENTIALS_CODE = 401; + + /** + * 非法token提示信息 + */ + public static final String BAD_CREDENTIALS_MSG = "请退出重新登录"; + + /** + * 表示升序的值 + */ + public static final String ORDER_ASC_VALUE = "asc"; + + /** + * 表示降序的值 + */ + public static final String ORDER_DESC_VALUE = "desc"; + + /** + * token通过header传递的名称 + */ + public static final String TOKEN_HEADER_NAME = "Authorization"; + + /** + * token通过参数传递的名称 + */ + public static final String TOKEN_PARAM_NAME = "access_token"; + + /** + * token认证类型 + */ + public static final String TOKEN_TYPE = "Bearer"; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/IgnoreTenant.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/IgnoreTenant.java new file mode 100644 index 0000000..ace48fa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/IgnoreTenant.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.core.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 忽略租户隔离注解 + * + * 用于标记需要跨租户操作的方法,如定时任务、系统管理等场景 + * + * @author WebSoft + * @since 2025-01-26 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface IgnoreTenant { + + /** + * 说明信息,用于记录为什么需要忽略租户隔离 + */ + String value() default ""; + + /** + * 是否记录日志 + */ + boolean logAccess() default true; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/OperationLog.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/OperationLog.java new file mode 100644 index 0000000..87bdf2c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/OperationLog.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 操作日志记录注解 + * + * @author WebSoft + * @since 2020-03-21 17:03:08 + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface OperationLog { + + /** + * 操作功能 + */ + String value() default ""; + + /** + * 操作模块 + */ + String module() default ""; + + /** + * 备注 + */ + String comments() default ""; + + /** + * 是否记录请求参数 + */ + boolean param() default true; + + /** + * 是否记录返回结果 + */ + boolean result() default true; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/OperationModule.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/OperationModule.java new file mode 100644 index 0000000..60ab018 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/OperationModule.java @@ -0,0 +1,21 @@ +package com.gxwebsoft.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 操作日志模块注解 + * + * @author WebSoft + * @since 2021-09-01 20:48:16 + */ +@Documented +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface OperationModule { + + /** + * 模块名称 + */ + String value(); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/QueryField.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/QueryField.java new file mode 100644 index 0000000..9377b9b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/QueryField.java @@ -0,0 +1,22 @@ +package com.gxwebsoft.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 查询条件注解 + * + * @author WebSoft + * @since 2021-09-01 20:48:16 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) +public @interface QueryField { + + // 字段名称 + String value() default ""; + + // 查询方式 + QueryType type() default QueryType.LIKE; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/QueryType.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/QueryType.java new file mode 100644 index 0000000..3eb540e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/annotation/QueryType.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.core.annotation; + +/** + * 查询方式 + * + * @author WebSoft + * @since 2021-09-01 20:48:16 + */ +public enum QueryType { + // 等于 + EQ, + // 不等于 + NE, + // 大于 + GT, + // 大于等于 + GE, + // 小于 + LT, + // 小于等于 + LE, + // 包含 + LIKE, + // 不包含 + NOT_LIKE, + // 结尾等于 + LIKE_LEFT, + // 开头等于 + LIKE_RIGHT, + // 为NULL + IS_NULL, + // 不为空 + IS_NOT_NULL, + // IN + IN, + // NOT IN + NOT_IN, + // IN条件解析逗号分割 + IN_STR, + // NOT IN条件解析逗号分割 + NOT_IN_STR +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/aspect/IgnoreTenantAspect.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/aspect/IgnoreTenantAspect.java new file mode 100644 index 0000000..da58a3b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/aspect/IgnoreTenantAspect.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.common.core.aspect; + +import com.gxwebsoft.common.core.annotation.IgnoreTenant; +import com.gxwebsoft.common.core.context.TenantContext; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + +/** + * 忽略租户隔离切面 + * + * 自动处理 @IgnoreTenant 注解标记的方法,临时禁用租户隔离 + * + * @author WebSoft + * @since 2025-01-26 + */ +@Slf4j +@Aspect +@Component +@Order(1) // 确保在其他切面之前执行 +public class IgnoreTenantAspect { + + @Around("@annotation(com.gxwebsoft.common.core.annotation.IgnoreTenant)") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + IgnoreTenant ignoreTenant = method.getAnnotation(IgnoreTenant.class); + + // 记录原始状态 + boolean originalIgnore = TenantContext.isIgnoreTenant(); + + try { + // 设置忽略租户隔离 + TenantContext.setIgnoreTenant(true); + + // 记录日志 + if (ignoreTenant.logAccess()) { + String className = joinPoint.getTarget().getClass().getSimpleName(); + String methodName = method.getName(); + String reason = ignoreTenant.value(); + + if (reason.isEmpty()) { + log.debug("执行跨租户操作: {}.{}", className, methodName); + } else { + log.debug("执行跨租户操作: {}.{} - {}", className, methodName, reason); + } + } + + // 执行目标方法 + return joinPoint.proceed(); + + } finally { + // 恢复原始状态 + TenantContext.setIgnoreTenant(originalIgnore); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/aspect/OperationLogAspect.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/aspect/OperationLogAspect.java new file mode 100644 index 0000000..4b15358 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/aspect/OperationLogAspect.java @@ -0,0 +1,227 @@ +package com.gxwebsoft.common.core.aspect; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.annotation.OperationModule; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.OperationRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; +import java.util.Map; + +/** + * 操作日志记录 + * + * @author WebSoft + * @since 2020-03-21 16:58:16:05 + */ +@Aspect +@Component +public class OperationLogAspect { + @Resource + private OperationRecordService operationRecordService; + + // 参数、返回结果、错误信息等最大保存长度 + private static final int MAX_LENGTH = 1000; + // 用于记录请求耗时 + private final ThreadLocal startTime = new ThreadLocal<>(); + + @Pointcut("@annotation(com.gxwebsoft.common.core.annotation.OperationLog)") + public void operationLog() { + } + + @Before("operationLog()") + public void doBefore(JoinPoint joinPoint) throws Throwable { + startTime.set(System.currentTimeMillis()); + } + + @AfterReturning(pointcut = "operationLog()", returning = "result") + public void doAfterReturning(JoinPoint joinPoint, Object result) { + saveLog(joinPoint, result, null); + } + + @AfterThrowing(value = "operationLog()", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Exception e) { + saveLog(joinPoint, null, e); + } + + /** + * 保存操作记录 + */ + private void saveLog(JoinPoint joinPoint, Object result, Exception e) { + OperationRecord record = new OperationRecord(); + // 记录操作耗时 + if (startTime.get() != null) { + record.setSpendTime(System.currentTimeMillis() - startTime.get()); + } + // 记录当前登录用户id、租户id + User user = getLoginUser(); + if (user != null) { + record.setUserId(user.getUserId()); + record.setTenantId(user.getTenantId()); + } + // 记录请求地址、请求方式、ip + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + HttpServletRequest request = (attributes == null ? null : attributes.getRequest()); + if (request != null) { + record.setUrl(request.getRequestURI()); + record.setRequestMethod(request.getMethod()); + UserAgent ua = UserAgentUtil.parse(ServletUtil.getHeaderIgnoreCase(request, "User-Agent")); + record.setOs(ua.getPlatform().toString()); + record.setDevice(ua.getOs().toString()); + record.setBrowser(ua.getBrowser().toString()); + record.setIp(ServletUtil.getClientIP(request)); + } + // 记录异常信息 + if (e != null) { + record.setStatus(1); + record.setError(StrUtil.sub(e.toString(), 0, MAX_LENGTH)); + } + // 记录模块名、操作功能、请求方法、请求参数、返回结果 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + record.setMethod(joinPoint.getTarget().getClass().getName() + "." + signature.getName()); + Method method = signature.getMethod(); + if (method != null) { + OperationLog ol = method.getAnnotation(OperationLog.class); + if (ol != null) { + // 记录操作功能 + record.setDescription(getDescription(method, ol)); + // 记录操作模块 + record.setModule(getModule(joinPoint, ol)); + // 记录备注 + if (StrUtil.isNotEmpty(ol.comments())) { + record.setComments(ol.comments()); + } + // 记录请求参数 + if (ol.param() && request != null) { + record.setParams(StrUtil.sub(getParams(joinPoint, request), 0, MAX_LENGTH)); + } + // 记录请求结果 + if (ol.result() && result != null) { + record.setResult(StrUtil.sub(JSONUtil.toJSONString(result), 0, MAX_LENGTH)); + } + } + } + + // 记录访客日志 +// System.out.println("record = " + record); +// if (record.getMethod().equals("com.gxwebsoft.love.controller.UserProfileController.detail")) { +// final Integer toUserId = Integer.valueOf(StrUtil.removeSuffix(record.getParams()," ")); +// if (userLookService.count(new LambdaQueryWrapper().eq(UserLook::getUserId,record.getUserId()).eq(UserLook::getToUserId,toUserId)) == 0) { +// final UserLook userLook = new UserLook(); +// userLook.setUserId(record.getUserId()); +// userLook.setToUserId(toUserId); +// userLookService.save(userLook); +// } +// } + + operationRecordService.saveAsync(record); + } + + /** + * 获取当前登录用户 + */ + private User getLoginUser() { + Authentication subject = SecurityContextHolder.getContext().getAuthentication(); + if (subject != null) { + Object object = subject.getPrincipal(); + if (object instanceof User) { + return (User) object; + } + } + return null; + } + + /** + * 获取请求参数 + * + * @param joinPoint JoinPoint + * @param request HttpServletRequest + * @return String + */ + private String getParams(JoinPoint joinPoint, HttpServletRequest request) { + String params; + Map paramsMap = ServletUtil.getParamMap(request); + if (paramsMap.keySet().size() > 0) { + params = JSONUtil.toJSONString(paramsMap); + } else { + StringBuilder sb = new StringBuilder(); + for (Object arg : joinPoint.getArgs()) { + if (ObjectUtil.isNull(arg) + || arg instanceof MultipartFile + || arg instanceof HttpServletRequest + || arg instanceof HttpServletResponse) { + continue; + } + sb.append(JSONUtil.toJSONString(arg)).append(" "); + } + params = sb.toString(); + } + return params; + } + + /** + * 获取操作模块 + * + * @param joinPoint JoinPoint + * @param ol OperationLog + * @return String + */ + private String getModule(JoinPoint joinPoint, OperationLog ol) { + if (StrUtil.isNotEmpty(ol.module())) { + return ol.module(); + } + OperationModule om = joinPoint.getTarget().getClass().getAnnotation(OperationModule.class); + if (om != null && StrUtil.isNotEmpty(om.value())) { + return om.value(); + } + // 尝试获取 SpringDoc 的 @Tag 注解 + io.swagger.v3.oas.annotations.tags.Tag tag = joinPoint.getTarget().getClass().getAnnotation(io.swagger.v3.oas.annotations.tags.Tag.class); + if (tag != null && StrUtil.isNotEmpty(tag.name())) { + return tag.name(); + } + return null; + } + + /** + * 获取操作功能 + * + * @param method Method + * @param ol OperationLog + * @return String + */ + private String getDescription(Method method, OperationLog ol) { + if (StrUtil.isNotEmpty(ol.value())) { + return ol.value(); + } + // 尝试获取 SpringDoc 的 @Operation 注解 + io.swagger.v3.oas.annotations.Operation operation = method.getAnnotation(io.swagger.v3.oas.annotations.Operation.class); + if (operation != null && StrUtil.isNotEmpty(operation.summary())) { + return operation.summary(); + } + return null; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/BigDecimalDeserializer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/BigDecimalDeserializer.java new file mode 100644 index 0000000..ed76d34 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/BigDecimalDeserializer.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.math.BigDecimal; + +/** + * BigDecimal 自定义反序列化器 + * 处理null值和空字符串,避免反序列化异常 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +public class BigDecimalDeserializer extends JsonDeserializer { + + @Override + public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getValueAsString(); + + if (value == null || value.trim().isEmpty() || "null".equals(value)) { + return null; + } + + try { + return new BigDecimal(value); + } catch (NumberFormatException e) { + log.warn("无法解析BigDecimal值: {}, 返回null", value); + return null; + } + } + + @Override + public BigDecimal getNullValue(DeserializationContext ctxt) { + return null; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/CertificateProperties.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/CertificateProperties.java new file mode 100644 index 0000000..a13c9d3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/CertificateProperties.java @@ -0,0 +1,217 @@ +package com.gxwebsoft.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 证书配置属性类 + * 支持开发环境从classpath加载证书,生产环境从Docker挂载卷加载证书 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Data +@Component +@ConfigurationProperties(prefix = "certificate") +public class CertificateProperties { + + /** + * 证书加载模式 + * CLASSPATH: 从classpath加载(开发环境) + * FILESYSTEM: 从文件系统加载(生产环境) + * VOLUME: 从Docker挂载卷加载(容器环境) + */ + private LoadMode loadMode = LoadMode.CLASSPATH; + + /** + * Docker挂载卷证书根路径 + */ + private String certRootPath = "/www/wwwroot/file.ws"; + + /** + * 开发环境证书路径前缀 + */ + private String devCertPath = "dev"; + + /** + * 微信支付证书配置 + */ + private WechatPayConfig wechatPay = new WechatPayConfig(); + + /** + * 支付宝证书配置 + */ + private AlipayConfig alipay = new AlipayConfig(); + + /** + * 证书加载模式枚举 + */ + public enum LoadMode { + CLASSPATH, // 从classpath加载 + FILESYSTEM, // 从文件系统加载 + VOLUME // 从Docker挂载卷加载 + } + + /** + * 微信支付证书配置 + */ + @Data + public static class WechatPayConfig { + /** + * 开发环境配置 + */ + private DevConfig dev = new DevConfig(); + + /** + * 生产环境基础路径 + */ + private String prodBasePath = "/"; + + /** + * 微信支付证书目录名 + */ + private String certDir = "wechat"; + + @Data + public static class DevConfig { + /** + * APIv3密钥 + */ + private String apiV3Key; + + /** + * 商户私钥证书文件名 + */ + private String privateKeyFile = "apiclient_key.pem"; + + /** + * 商户证书文件名 + */ + private String apiclientCertFile = "apiclient_cert.pem"; + + /** + * 微信支付平台证书文件名 + */ + private String wechatpayCertFile = "wechatpay_cert.pem"; + } + } + + /** + * 支付宝证书配置 + */ + @Data + public static class AlipayConfig { + /** + * 支付宝证书目录名 + */ + private String certDir = "alipay"; + + /** + * 应用私钥文件名 + */ + private String appPrivateKeyFile = "app_private_key.pem"; + + /** + * 应用公钥证书文件名 + */ + private String appCertPublicKeyFile = "appCertPublicKey.crt"; + + /** + * 支付宝公钥证书文件名 + */ + private String alipayCertPublicKeyFile = "alipayCertPublicKey.crt"; + + /** + * 支付宝根证书文件名 + */ + private String alipayRootCertFile = "alipayRootCert.crt"; + } + + /** + * 获取证书文件的完整路径 + * + * @param certType 证书类型(wechat/alipay) + * @param fileName 文件名 + * @return 完整路径 + */ + public String getCertificatePath(String certType, String fileName) { + switch (loadMode) { + case CLASSPATH: + return devCertPath + "/" + certType + "/" + fileName; + case FILESYSTEM: + return System.getProperty("user.dir") + "/certs/" + certType + "/" + fileName; + case VOLUME: + return certRootPath + "/" + certType + "/" + fileName; + default: + throw new IllegalArgumentException("不支持的证书加载模式: " + loadMode); + } + } + + /** + * 获取微信支付证书路径 + * + * @param fileName 文件名 + * @return 完整路径 + */ + public String getWechatPayCertPath(String fileName) { + // 生产环境特殊处理:数据库中存储的路径直接拼接到根路径 + if (loadMode == LoadMode.VOLUME) { + // 生产环境已经没有/file目录,所有路径都直接拼接到根路径 + // 处理数据库中可能存在的历史路径格式 + String cleanFileName = fileName; + if (fileName.startsWith("/file/")) { + // 去掉历史的 /file/ 前缀 + cleanFileName = fileName.substring(6); + } else if (fileName.startsWith("file/")) { + // 去掉历史的 file/ 前缀 + cleanFileName = fileName.substring(5); + } + // 确保路径以 / 开头 + if (!cleanFileName.startsWith("/")) { + cleanFileName = "/" + cleanFileName; + } + return certRootPath + cleanFileName; + } else { + // 开发环境和文件系统模式使用原有逻辑 + return getCertificatePath(wechatPay.getCertDir(), fileName); + } + } + + /** + * 获取支付宝证书路径 + * + * @param fileName 文件名 + * @return 完整路径 + */ + public String getAlipayCertPath(String fileName) { + return getCertificatePath(alipay.getCertDir(), fileName); + } + + /** + * 检查证书加载模式是否为classpath模式 + * + * @return true if classpath mode + */ + public boolean isClasspathMode() { + return LoadMode.CLASSPATH.equals(loadMode); + } + + /** + * 检查证书加载模式是否为文件系统模式 + * + * @return true if filesystem mode + */ + public boolean isFilesystemMode() { + return LoadMode.FILESYSTEM.equals(loadMode); + } + + /** + * 检查证书加载模式是否为挂载卷模式 + * + * @return true if volume mode + */ + public boolean isVolumeMode() { + return LoadMode.VOLUME.equals(loadMode); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/CloudAuthProperties.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/CloudAuthProperties.java new file mode 100644 index 0000000..5ee4cc2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/CloudAuthProperties.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 阿里云实人认证配置 + * + * @author WebSoft + */ +@Data +@Component +@ConfigurationProperties(prefix = "cloudauth") +public class CloudAuthProperties { + + /** + * 阿里云 AccessKey ID + */ + private String accessKeyId; + + /** + * 阿里云 AccessKey Secret + */ + private String accessKeySecret; + + /** + * 地域ID + */ + private String regionId = "cn-shenzhen"; + + /** + * 接入点 + */ + private String endpoint = "cloudauth.aliyuncs.com"; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/ConfigProperties.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/ConfigProperties.java new file mode 100644 index 0000000..d500177 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/ConfigProperties.java @@ -0,0 +1,105 @@ +package com.gxwebsoft.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 系统配置属性 + * + * @author WebSoft + * @since 2021-08-30 17:58:16 + */ +@Data +@ConfigurationProperties(prefix = "config") +public class ConfigProperties { + /** + * 文件上传磁盘位置 + */ + private Integer uploadLocation = 0; + + /** + * 文件上传是否使用uuid命名 + */ + private Boolean uploadUuidName = true; + + /** + * 文件上传生成缩略图的大小(kb) + */ + private Integer thumbnailSize = 60; + + /** + * OpenOffice的安装目录 + */ + private String openOfficeHome; + + /** + * swagger扫描包 + */ + private String swaggerBasePackage; + + /** + * swagger文档标题 + */ + private String swaggerTitle; + + /** + * swagger文档描述 + */ + private String swaggerDescription; + + /** + * swagger文档版本号 + */ + private String swaggerVersion; + + /** + * swagger地址 + */ + private String swaggerHost; + + /** + * token过期时间, 单位秒 + */ + private Long tokenExpireTime = 60 * 60 * 365 * 24L; + + /** + * token快要过期自动刷新时间, 单位分钟 + */ + private int tokenRefreshTime = 30; + + /** + * 生成token的密钥Key的base64字符 + */ + private String tokenKey; + + /** + * 文件上传目录 + */ + private String uploadPath; + + /** + * 本地文件上传目录(开发环境) + */ + private String localUploadPath; + + /** + * 文件服务器 + */ + private String fileServer; + + /** + * 网关地址 + */ + private String serverUrl; + + /** + * 阿里云存储 OSS + * Endpoint + */ + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; + private String bucketDomain; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/HttpMessageConverter.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/HttpMessageConverter.java new file mode 100644 index 0000000..6bae59d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/HttpMessageConverter.java @@ -0,0 +1,15 @@ +package com.gxwebsoft.common.core.config; + +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import java.util.ArrayList; +import java.util.List; + +public class HttpMessageConverter extends MappingJackson2HttpMessageConverter { + public HttpMessageConverter(){ + List mediaTypes = new ArrayList<>(); + mediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); + setSupportedMediaTypes(mediaTypes); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java new file mode 100644 index 0000000..40bc90c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java @@ -0,0 +1,133 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.DeserializationFeature; +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.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * Jackson配置类 - 强制配置版本 + * 确保JavaTimeModule被正确注册并覆盖Spring Boot的自动配置 + * + * @author WebSoft + * @since 2025-09-08 + */ +@Configuration +public class JacksonConfig { + + /** + * 日期时间格式(序列化输出格式) + */ + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + /** + * 自定义 LocalDateTime 反序列化器 - 兼容多种格式 + * 支持: yyyy-MM-dd HH:mm:ss, yyyy-MM-ddTHH:mm:ss, yyyy-MM-ddTHH:mm:ss.SSS, yyyy-MM-ddTHH:mm:ss.SSSSSS, yyyy-MM-ddTHH:mm:ss.SSSSSSSSS + */ + public static class FlexibleLocalDateTimeDeserializer extends LocalDateTimeDeserializer { + + private static final long serialVersionUID = 1L; + + private static final DateTimeFormatter[] SUPPORTED_FORMATS = { + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"), + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"), + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"), + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS"), + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS"), + }; + + public FlexibleLocalDateTimeDeserializer() { + super(); + } + + public FlexibleLocalDateTimeDeserializer(DateTimeFormatter dtf) { + super(dtf); + } + + @Override + public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + String value = parser.getValueAsString(); + if (value == null || value.isEmpty()) { + return null; + } + + // 清理字符串:去掉可能的尾随 Z 或时区信息 + String cleanValue = value.trim(); + if (cleanValue.endsWith("Z")) { + cleanValue = cleanValue.substring(0, cleanValue.length() - 1); + } + + // 尝试解析所有支持的格式 + for (DateTimeFormatter formatter : SUPPORTED_FORMATS) { + try { + java.time.temporal.TemporalAccessor ta = formatter.parse(cleanValue); + return LocalDateTime.from(ta); + } catch (java.time.format.DateTimeParseException ignored) { + // 尝试下一个格式 + } + } + + // 如果都不匹配,使用默认反序列化 + return super.deserialize(parser, context); + } + } + + @Bean + @Primary + public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { + ObjectMapper mapper = builder.build(); + + // 创建并配置JavaTimeModule + JavaTimeModule javaTimeModule = new JavaTimeModule(); + + // 配置LocalDateTime的序列化格式(输出格式) + DateTimeFormatter serializerFormatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(serializerFormatter)); + + // 使用灵活的 LocalDateTime 反序列化器(兼容纳秒精度) + javaTimeModule.addDeserializer(LocalDateTime.class, new FlexibleLocalDateTimeDeserializer()); + + // 注册JavaTimeModule - 这是关键 + mapper.registerModule(javaTimeModule); + + // 禁用将日期写为时间戳 + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + // 忽略未知属性 + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + // 设置时区 + mapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); + + return mapper; + } + + /** + * 备用JavaTimeModule Bean + */ + @Bean + public JavaTimeModule javaTimeModule() { + JavaTimeModule module = new JavaTimeModule(); + + // 配置LocalDateTime的序列化格式(输出格式) + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); + module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + // 使用灵活的 LocalDateTime 反序列化器(兼容纳秒精度) + module.addDeserializer(LocalDateTime.class, new FlexibleLocalDateTimeDeserializer()); + + return module; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JacksonConfigChecker.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JacksonConfigChecker.java new file mode 100644 index 0000000..6af29f2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JacksonConfigChecker.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * Jackson配置检查器 + * 在应用启动时检查Jackson配置是否正确 + * + * @author WebSoft + * @since 2025-09-08 + */ +@Component +public class JacksonConfigChecker implements CommandLineRunner { + + private static final Logger logger = LoggerFactory.getLogger(JacksonConfigChecker.class); + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void run(String... args) throws Exception { + logger.info("=== Jackson配置检查开始 ==="); + + try { + // 检查JavaTimeModule是否注册 + boolean hasJavaTimeModule = objectMapper.getRegisteredModuleIds() + .contains(JavaTimeModule.class.getName()); + logger.info("JavaTimeModule是否注册: {}", hasJavaTimeModule); + + // 测试LocalDateTime序列化 + Map testData = new HashMap<>(); + testData.put("currentTime", LocalDateTime.now()); + testData.put("message", "Jackson配置测试"); + + String json = objectMapper.writeValueAsString(testData); + logger.info("LocalDateTime序列化测试成功: {}", json); + + // 测试反序列化 + Map result = objectMapper.readValue(json, Map.class); + logger.info("反序列化测试成功: {}", result); + + logger.info("=== Jackson配置检查完成 - 配置正常 ==="); + + } catch (Exception e) { + logger.error("=== Jackson配置检查失败 ===", e); + logger.error("请检查Jackson配置是否正确"); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JsonArrayToStringDeserializer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JsonArrayToStringDeserializer.java new file mode 100644 index 0000000..16815b5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JsonArrayToStringDeserializer.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; + +/** + * JSON数组转String反序列化器 + * 直接返回 JSON 字符串,不做转换 + * + * @author 科技小王子 + * @since 2026-04-01 + */ +@Slf4j +public class JsonArrayToStringDeserializer extends JsonDeserializer { + + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + // 直接返回 JSON 数组字符串,不做转换 + return p.getValueAsString(); + } + + @Override + public String getNullValue(DeserializationContext ctxt) { + return null; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JsonStringToArraySerializer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JsonStringToArraySerializer.java new file mode 100644 index 0000000..8f553a9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/JsonStringToArraySerializer.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.io.IOException; +import java.util.List; + +/** + * String转JSON数组序列化器 + * 将JSON数组字符串序列化为JSON数组输出 + * + * @author 科技小王子 + * @since 2026-04-01 + */ +public class JsonStringToArraySerializer extends JsonSerializer { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value == null || value.trim().isEmpty()) { + gen.writeStartArray(); + gen.writeEndArray(); + return; + } + + try { + // 解析 JSON 字符串为 List + List list = objectMapper.readValue(value, new TypeReference>() {}); + gen.writeStartArray(); + for (String item : list) { + gen.writeString(item); + } + gen.writeEndArray(); + } catch (Exception e) { + // 解析失败,作为单元素数组处理 + gen.writeStartArray(); + gen.writeString(value); + gen.writeEndArray(); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeDeserializer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeDeserializer.java new file mode 100644 index 0000000..52ddd0a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeDeserializer.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * LocalDateTime自定义反序列化器 + * + * @author WebSoft + * @since 2025-01-12 + */ +public class LocalDateTimeDeserializer extends JsonDeserializer { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Override + public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getValueAsString(); + if (value != null && !value.isEmpty()) { + return LocalDateTime.parse(value, FORMATTER); + } + return null; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeSerializer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeSerializer.java new file mode 100644 index 0000000..d3849e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/LocalDateTimeSerializer.java @@ -0,0 +1,27 @@ +package com.gxwebsoft.common.core.config; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * LocalDateTime自定义序列化器 + * + * @author WebSoft + * @since 2025-01-12 + */ +public class LocalDateTimeSerializer extends JsonSerializer { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Override + public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value != null) { + gen.writeString(value.format(FORMATTER)); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/MqttProperties.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/MqttProperties.java new file mode 100644 index 0000000..cfc882d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/MqttProperties.java @@ -0,0 +1,72 @@ +package com.gxwebsoft.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * MQTT配置属性 + * + * @author 科技小王子 + * @since 2025-07-02 + */ +@Data +@Component +@ConfigurationProperties(prefix = "mqtt") +public class MqttProperties { + + /** + * 是否启用MQTT服务 + */ + private boolean enabled = false; + + /** + * MQTT服务器地址 + */ + private String host = "tcp://127.0.0.1:1883"; + + /** + * 用户名 + */ + private String username = ""; + + /** + * 密码 + */ + private String password = ""; + + /** + * 客户端ID前缀 + */ + private String clientIdPrefix = "mqtt_client_"; + + /** + * 订阅主题 + */ + private String topic = "/SW_GPS/#"; + + /** + * QoS等级 + */ + private int qos = 2; + + /** + * 连接超时时间(秒) + */ + private int connectionTimeout = 10; + + /** + * 心跳间隔(秒) + */ + private int keepAliveInterval = 20; + + /** + * 是否自动重连 + */ + private boolean autoReconnect = true; + + /** + * 是否清除会话 + */ + private boolean cleanSession = false; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/MybatisPlusConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/MybatisPlusConfig.java new file mode 100644 index 0000000..0e3fd79 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/MybatisPlusConfig.java @@ -0,0 +1,160 @@ +package com.gxwebsoft.common.core.config; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.context.TenantContext; +import com.gxwebsoft.common.system.entity.User; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.NullValue; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * MybatisPlus配置 + * + * @author WebSoft + * @since 2018-02-22 11:29:28 + */ +@Configuration +public class MybatisPlusConfig { + @Resource + private RedisUtil redisUtil; + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + + // 多租户插件配置 + TenantLineHandler tenantLineHandler = new TenantLineHandler() { + @Override + public Expression getTenantId() { + String tenantId = null; + try { + // 从Spring上下文获取当前请求 + HttpServletRequest request = getCurrentRequest(); + if (request != null) { + // 从请求头拿ID + tenantId = request.getHeader("tenantId"); + if(tenantId != null && !tenantId.trim().isEmpty()){ + return new LongValue(tenantId); + } + // 从域名拿ID + String Domain = request.getHeader("Domain"); + if (StrUtil.isNotBlank(Domain)) { + String key = "Domain:" + Domain; + tenantId = redisUtil.get(key); + if(tenantId != null && !tenantId.trim().isEmpty()){ + System.out.println("从域名拿TID = " + tenantId); + return new LongValue(tenantId); + } + } + } + } catch (Exception e) { + // 忽略异常,使用默认逻辑 + System.err.println("获取租户ID异常: " + e.getMessage()); + } + + // 最后尝试从登录用户获取 + Expression loginUserTenantId = getLoginUserTenantId(); + if (loginUserTenantId instanceof LongValue) { + return loginUserTenantId; + } + + // 如果都获取不到,返回null而不是undefined + return new NullValue(); + } + + @Override + public boolean ignoreTable(String tableName) { + // 如果当前上下文设置了忽略租户隔离,则忽略所有表的租户隔离 + if (TenantContext.isIgnoreTenant()) { + return true; + } + + // 系统级别的表始终忽略租户隔离 + return Arrays.asList( + "sys_tenant", + "sys_user", + "sys_dictionary", + "sys_dictionary_data", + "apps_test_data", + "cms_lang", + "app_invite_token", + "app_repository", + "app_permission_request", + "app_product" +// "hjm_car", +// "hjm_fence" +// "cms_website" +// "sys_user" +// "cms_domain" +// "shop_order_goods", +// "shop_goods" +// "shop_users", +// "shop_order" // 移除shop_order,改为通过注解控制 +// "shop_order_info", +// "booking_user_invoice" + ).contains(tableName); + } + }; + TenantLineInnerInterceptor tenantLineInnerInterceptor = new TenantLineInnerInterceptor(tenantLineHandler); + interceptor.addInnerInterceptor(tenantLineInnerInterceptor); + + // 分页插件配置 + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + paginationInnerInterceptor.setMaxLimit(2000L); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + + return interceptor; + } + + /** + * 获取当前登录用户的租户id + * + * @return Integer + */ + public Expression getLoginUserTenantId() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + Integer tenantId = ((User) object).getTenantId(); + if (tenantId != null) { + return new LongValue(tenantId); + } + } + } + } catch (Exception e) { + System.err.println("获取登录用户租户ID异常: " + e.getMessage()); + } + return new NullValue(); + } + + /** + * 获取当前HTTP请求 + */ + private HttpServletRequest getCurrentRequest() { + try { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + return attributes != null ? attributes.getRequest() : null; + } catch (Exception e) { + return null; + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/RestTemplateConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/RestTemplateConfig.java new file mode 100644 index 0000000..786798f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/RestTemplateConfig.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.core.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate(ClientHttpRequestFactory factory) { + RestTemplate restTemplate = new RestTemplate(factory); + restTemplate.getMessageConverters().add(new HttpMessageConverter()); + return restTemplate; + } + @Bean + public ClientHttpRequestFactory simpleClientHttpRequestFactory() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + // ms + factory.setReadTimeout(60000); + // ms + factory.setConnectTimeout(60000); + + return factory; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/SpringContextUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/SpringContextUtil.java new file mode 100644 index 0000000..4e6d883 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/SpringContextUtil.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.common.core.config; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * @Author ds + * @Date 2022-05-05 + */ +@Component +public class SpringContextUtil implements ApplicationContextAware { + /** + * spring的应用上下文 + */ + private static ApplicationContext applicationContext; + + /** + * 初始化时将应用上下文设置进applicationContext + * @param applicationContext + * @throws BeansException + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringContextUtil.applicationContext=applicationContext; + } + + public static ApplicationContext getApplicationContext(){ + return applicationContext; + } + + /** + * 根据bean名称获取某个bean对象 + * + * @param name bean名称 + * @return Object + * @throws BeansException + */ + public static Object getBean(String name) throws BeansException { + return applicationContext.getBean(name); + } + + /** + * 根据bean的class获取某个bean对象 + * @param beanClass + * @param + * @return + * @throws BeansException + */ + public static T getBean(Class beanClass) throws BeansException { + return applicationContext.getBean(beanClass); + } + + /** + * 获取spring.profiles.active + * @return + */ + public static String getProfile(){ + return getApplicationContext().getEnvironment().getActiveProfiles()[0]; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java new file mode 100644 index 0000000..c63c2c7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java @@ -0,0 +1,111 @@ +package com.gxwebsoft.common.core.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.Components; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; + +/** + * SpringDoc OpenAPI 配置 + * + * @author WebSoft + * @since 2018-02-22 11:29:05 + */ +@Configuration +public class SwaggerConfig { + @Resource + private ConfigProperties config; + + /** + * 全局 OpenAPI 配置 + */ + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title(config.getSwaggerTitle()) + .description(config.getSwaggerDescription()) + .version(config.getSwaggerVersion()) + .contact(new Contact() + .name("科技小王子") + .url("https://www.gxwebsoft.com") + .email("170083662@qq.com")) + .termsOfService(config.getServerUrl() + "/system")) + .components(new Components() + .addSecuritySchemes("Authorization", + new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .name("Authorization") + .description("JWT Authorization header using the Bearer scheme"))) + .addSecurityItem(new SecurityRequirement().addList("Authorization")); + } + + /** + * Common 模块分组 + */ + @Bean + public GroupedOpenApi commonApi() { + return GroupedOpenApi.builder() + .group("common") + .pathsToMatch("/api/common/**", "/api/system/**", "/api/user/**", "/api/role/**", "/api/menu/**") + .packagesToScan("com.gxwebsoft.common") + .build(); + } + + /** + * CMS 模块分组 + */ + @Bean + public GroupedOpenApi cmsApi() { + return GroupedOpenApi.builder() + .group("cms") + .pathsToMatch("/api/cms/**") + .packagesToScan("com.gxwebsoft.cms") + .build(); + } + + /** + * Shop 模块分组 + */ + @Bean + public GroupedOpenApi shopApi() { + return GroupedOpenApi.builder() + .group("shop") + .pathsToMatch("/api/shop/**") + .packagesToScan("com.gxwebsoft.shop") + .build(); + } + + /** + * OA 模块分组 + */ + @Bean + public GroupedOpenApi oaApi() { + return GroupedOpenApi.builder() + .group("oa") + .pathsToMatch("/api/oa/**") + .packagesToScan("com.gxwebsoft.oa") + .build(); + } + + /** + * 其他模块分组 + */ + @Bean + public GroupedOpenApi otherApi() { + return GroupedOpenApi.builder() + .group("other") + .pathsToMatch("/api/docs/**", "/api/project/**", "/api/pwl/**", "/api/bszx/**", "/api/hjm/**") + .packagesToScan("com.gxwebsoft.docs", "com.gxwebsoft.project", "com.gxwebsoft.pwl", "com.gxwebsoft.bszx", "com.gxwebsoft.hjm") + .build(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/WebMvcConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/WebMvcConfig.java new file mode 100644 index 0000000..2ed9d8b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/config/WebMvcConfig.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.core.config; + +import com.gxwebsoft.common.core.Constants; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * WebMvc配置, 拦截器、资源映射等都在此配置 + * + * @author WebSoft + * @since 2019-06-12 10:11:16 + */ +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + /** + * 支持跨域访问 + */ + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOriginPatterns("*") + .allowedHeaders("*") + .exposedHeaders(Constants.TOKEN_HEADER_NAME) + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH") + .allowCredentials(true) + .maxAge(3600); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/AppUserConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/AppUserConstants.java new file mode 100644 index 0000000..538e295 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/AppUserConstants.java @@ -0,0 +1,8 @@ +package com.gxwebsoft.common.core.constants; + +public class AppUserConstants { + // 成员角色 + public static final Integer TRIAL = 10; // 体验成员 + public static final Integer DEVELOPER = 20; // 开发者 + public static final Integer ADMINISTRATOR = 30; // 管理员 +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/ArticleConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/ArticleConstants.java new file mode 100644 index 0000000..62a38cc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/ArticleConstants.java @@ -0,0 +1,6 @@ +package com.gxwebsoft.common.core.constants; + +public class ArticleConstants extends BaseConstants { + public static final String[] ARTICLE_STATUS = {"已发布","待审核","已驳回","违规内容"}; + public static final String CACHE_KEY_ARTICLE = "Article:"; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/BalanceConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/BalanceConstants.java new file mode 100644 index 0000000..6857250 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/BalanceConstants.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.common.core.constants; + +public class BalanceConstants { + // 余额变动场景 + public static final Integer BALANCE_RECHARGE = 10; // 用户充值 + public static final Integer BALANCE_USE = 20; // 用户消费 + public static final Integer BALANCE_RE_LET = 21; // 续租 + public static final Integer BALANCE_ADMIN = 30; // 管理员操作 + public static final Integer BALANCE_REFUND = 40; // 订单退款 +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/BaseConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/BaseConstants.java new file mode 100644 index 0000000..66cf4c0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/BaseConstants.java @@ -0,0 +1,5 @@ +package com.gxwebsoft.common.core.constants; + +public class BaseConstants { + public static final String[] STATUS = {"未定义","显示","隐藏"}; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/OrderConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/OrderConstants.java new file mode 100644 index 0000000..e866654 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/OrderConstants.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.core.constants; + +public class OrderConstants { + // 支付方式 + public static final String PAY_METHOD_BALANCE = "10"; // 余额支付 + public static final String PAY_METHOD_WX = "20"; // 微信支付 + public static final String PAY_METHOD_ALIPAY = "30"; // 支付宝支付 + public static final String PAY_METHOD_OTHER = "40"; // 其他支付 + + // 付款状态 + public static final Integer PAY_STATUS_NO_PAY = 10; // 未付款 + public static final Integer PAY_STATUS_SUCCESS = 20; // 已付款 + + // 发货状态 + public static final Integer DELIVERY_STATUS_NO = 10; // 未发货 + public static final Integer DELIVERY_STATUS_YES = 20; // 已发货 + public static final Integer DELIVERY_STATUS_30 = 30; // 部分发货 + + // 收货状态 + public static final Integer RECEIPT_STATUS_NO = 10; // 未收货 + public static final Integer RECEIPT_STATUS_YES = 20; // 已收货 + public static final Integer RECEIPT_STATUS_RETURN = 30; // 已退货 + + // 订单状态 + public static final Integer ORDER_STATUS_DOING = 10; // 进行中 + public static final Integer ORDER_STATUS_CANCEL = 20; // 已取消 + public static final Integer ORDER_STATUS_TO_CANCEL = 21; // 待取消 + public static final Integer ORDER_STATUS_COMPLETED = 30; // 已完成 + + // 订单结算状态 + public static final Integer ORDER_SETTLED_YES = 1; // 已结算 + public static final Integer ORDER_SETTLED_NO = 0; // 未结算 + + + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/PlatformConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/PlatformConstants.java new file mode 100644 index 0000000..896f8e3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/PlatformConstants.java @@ -0,0 +1,12 @@ +package com.gxwebsoft.common.core.constants; + +public class PlatformConstants { + public static final String MP_OFFICIAL = "MP-OFFICIAL"; // 微信公众号 + public static final String MP_WEIXIN = "MP-WEIXIN"; // 微信小程序 + public static final String MP_ALIPAY = "MP-ALIPAY"; // 支付宝小程序 + public static final String WEB = "WEB"; // web(同H5) + public static final String H5 = "H5"; // H5(推荐使用 WEB) + public static final String APP = "APP"; // App + public static final String MP_BAIDU = "MP-BAIDU"; // 百度小程序 + public static final String MP_TOUTIAO = "MP-TOUTIAO"; // 百度小程序 +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/ProfitConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/ProfitConstants.java new file mode 100644 index 0000000..2cb60fd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/ProfitConstants.java @@ -0,0 +1,9 @@ +package com.gxwebsoft.common.core.constants; + +public class ProfitConstants { + // 收益类型 + public static final Integer PROFIT_TYPE10 = 10; // 推广收益 + public static final Integer PROFIT_TYPE20 = 20; // 团队收益 + public static final Integer PROFIT_TYPE30 = 30; // 门店收益 + public static final Integer PROFIT_TYPE40 = 30; // 区域收益 +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/QRCodeConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/QRCodeConstants.java new file mode 100644 index 0000000..1b30868 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/QRCodeConstants.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.common.core.constants; + +public class QRCodeConstants { + // 二维码类型 + public static final String USER_QRCODE = "user"; // 用户二维码 + public static final String TASK_QRCODE = "task"; // 工单二维码 + public static final String ARTICLE_QRCODE = "article"; // 文章二维码 + public static final String GOODS_QRCODE = "goods"; // 商品二维码 + public static final String DIY_QRCODE = "diy"; // 工单二维码 +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/RedisConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/RedisConstants.java new file mode 100644 index 0000000..0d04947 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/RedisConstants.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.common.core.constants; + +public class RedisConstants { + // 短信验证码Key + public static final String SMS_CODE_KEY = "sms"; + // 验证码过期时间 + public static final Long SMS_CODE_TTL = 5L; + // 微信凭证access-token + public static final String ACCESS_TOKEN_KEY = "access-token"; + // 空值防止击穿数据库 + public static final Long CACHE_NULL_TTL = 2L; + // 商户信息 + public static final String MERCHANT_KEY = "merchant"; + // 添加商户定位点 + public static final String MERCHANT_GEO_KEY = "merchant-geo"; + + // token + public static final String TOKEN_USER_ID = "cache:token:"; + // 排行榜 + public static final String USER_RANKING_BY_APPS = "userRankingByApps"; + // 搜索历史 + public static final String SEARCH_HISTORY = "searchHistory"; + // 租户系统设置信息 + public static final String TEN_ANT_SETTING_KEY = "setting"; + // 排行榜Key + public static final String USER_RANKING_BY_APPS_5 = "cache5:userRankingByApps"; + // 微信小程序Key + public static final String MP_WX_KEY = "mp-weixin:"; + + + + // 扫码登录相关key + public static final String QR_LOGIN_TOKEN_KEY = "qr-login:token:"; // 扫码登录token前缀 + public static final Long QR_LOGIN_TOKEN_TTL = 300L; // 扫码登录token过期时间(5分钟) + public static final String QR_LOGIN_STATUS_PENDING = "pending"; // 等待扫码 + public static final String QR_LOGIN_STATUS_SCANNED = "scanned"; // 已扫码 + public static final String QR_LOGIN_STATUS_BIND_PHONE = "bind_phone"; // 新用户待绑定手机号 + public static final String QR_LOGIN_STATUS_CONFIRMED = "confirmed"; // 已确认 + public static final String QR_LOGIN_STATUS_EXPIRED = "expired"; // 已过期 + + // 哗啦啦key + public static final String getAllShop = "allShop"; + public static final String getBaseInfo = "baseInfo"; + public static final String getFoodClassCategory = "foodCategory"; + public static final String getOpenFood = "openFood"; + public static final String haulalaGeoKey = "cache10:hualala-geo"; + public static final String HLL_CART_KEY = "hll-cart"; // hll-cart[shopId]:[userId] + public static final String HLL_CART_FOOD_KEY = "hll-cart-list"; // hll-cart-list[shopId]:[userId] + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/TaskConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/TaskConstants.java new file mode 100644 index 0000000..42cec5e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/TaskConstants.java @@ -0,0 +1,22 @@ +package com.gxwebsoft.common.core.constants; + +public class TaskConstants { + // 工单进度 + public static final Integer TOBEARRANGED = 0; // 待安排 + public static final Integer PENDING = 1; // 待处理 + public static final Integer PROCESSING = 2; // 处理中 + public static final Integer TOBECONFIRMED = 3; // 待评价 + public static final Integer COMPLETED = 4; // 已完成 + public static final Integer CLOSED = 5; // 已关闭 + + // 工单状态 + public static final Integer TASK_STATUS_0 = 0; // 待处理 + public static final Integer TASK_STATUS_1 = 1; // 已完成 + + // 操作类型 + public static final String ACTION_1 = "派单"; + public static final String ACTION_2 = "已解决"; + public static final String ACTION_3 = "关单"; + public static final String ACTION_4 = "分享"; + public static final String ACTION_5 = "编辑"; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/WebsiteConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/WebsiteConstants.java new file mode 100644 index 0000000..77cc849 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/WebsiteConstants.java @@ -0,0 +1,16 @@ +package com.gxwebsoft.common.core.constants; + +public class WebsiteConstants extends BaseConstants { + // 运行状态 0未开通 1运行中 2维护中 3已关闭 4已欠费停机 5违规关停 + public static final String[] WEBSITE_STATUS_NAME = {"未开通","运行中","维护中","已关闭","已欠费停机","违规关停"}; + // 状态图标 + public static final String[] WEBSITE_STATUS_ICON = {"error","success","warning","error","error","error"}; + // 关闭原因 + public static final String[] WEBSITE_STATUS_TEXT = {"产品未开通","","系统升级维护","","已欠费停机","违规关停"}; + // 跳转地址 + public static final String[] WEBSITE_STATUS_URL = {"https://websoft.top","","","","https://websoft.top/user","https://websoft.top/user"}; + // 跳转按钮文字 + public static final String[] WEBSITE_STATUS_BTN_TEXT = {"立即开通","","","","立即续费","申请解封"}; + // 开发者短信验证码万能码(Redis Key) + public static final String CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS = "devSmsCode:universal"; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/WxOfficialConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/WxOfficialConstants.java new file mode 100644 index 0000000..a025610 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/constants/WxOfficialConstants.java @@ -0,0 +1,6 @@ +package com.gxwebsoft.common.core.constants; + +public class WxOfficialConstants { + // 获取 Access token + public static final String GET_ACCESS_TOKEN_API = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/context/TenantContext.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/context/TenantContext.java new file mode 100644 index 0000000..42adb46 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/context/TenantContext.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.common.core.context; + +/** + * 租户上下文管理器 + * + * 用于在特定场景下临时禁用租户隔离 + * + * @author WebSoft + * @since 2025-01-26 + */ +public class TenantContext { + + private static final ThreadLocal IGNORE_TENANT = new ThreadLocal<>(); + + /** + * 设置忽略租户隔离 + */ + public static void setIgnoreTenant(boolean ignore) { + IGNORE_TENANT.set(ignore); + } + + /** + * 是否忽略租户隔离 + */ + public static boolean isIgnoreTenant() { + Boolean ignore = IGNORE_TENANT.get(); + return ignore != null && ignore; + } + + /** + * 清除租户上下文 + */ + public static void clear() { + IGNORE_TENANT.remove(); + } + + /** + * 在忽略租户隔离的上下文中执行操作 + * + * @param runnable 要执行的操作 + */ + public static void runIgnoreTenant(Runnable runnable) { + boolean originalIgnore = isIgnoreTenant(); + try { + setIgnoreTenant(true); + runnable.run(); + } finally { + setIgnoreTenant(originalIgnore); + } + } + + /** + * 在忽略租户隔离的上下文中执行操作并返回结果 + * + * @param supplier 要执行的操作 + * @return 操作结果 + */ + public static T callIgnoreTenant(java.util.function.Supplier supplier) { + boolean originalIgnore = isIgnoreTenant(); + try { + setIgnoreTenant(true); + return supplier.get(); + } finally { + setIgnoreTenant(originalIgnore); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/CertificateController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/CertificateController.java new file mode 100644 index 0000000..d3dee92 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/CertificateController.java @@ -0,0 +1,187 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.service.CertificateHealthService; +import com.gxwebsoft.common.core.service.CertificateService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 证书管理控制器 + * 提供证书状态查询、健康检查等功能 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@Tag(name = "证书管理") +@RestController +@RequestMapping("/api/system/certificate") +public class CertificateController extends BaseController { + + @Resource + private CertificateService certificateService; + + @Resource + private CertificateHealthService certificateHealthService; + + @Operation(summary = "获取所有证书状态") + @GetMapping("/status") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult> getCertificateStatus() { + try { + Map status = certificateService.getAllCertificateStatus(); + return success("获取证书状态成功", status); + } catch (Exception e) { + log.error("获取证书状态失败", e); + return new ApiResult<>(1, "获取证书状态失败: " + e.getMessage()); + } + } + + @Operation(summary = "证书健康检查") + @GetMapping("/health") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult> healthCheck() { + try { + CertificateHealthService.HealthResult health = certificateHealthService.health(); + Map result = Map.of( + "status", health.getStatus(), + "details", health.getDetails() + ); + return success("证书健康检查完成", result); + } catch (Exception e) { + log.error("证书健康检查失败", e); + return new ApiResult<>(1, "证书健康检查失败: " + e.getMessage()); + } + } + + @Operation(summary = "获取证书诊断信息") + @GetMapping("/diagnostic") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult> getDiagnosticInfo() { + try { + Map diagnostic = certificateHealthService.getDiagnosticInfo(); + return success("获取证书诊断信息成功", diagnostic); + } catch (Exception e) { + log.error("获取证书诊断信息失败", e); + return new ApiResult<>(1, "获取证书诊断信息失败: " + e.getMessage()); + } + } + + @Operation(summary = "检查特定证书") + @GetMapping("/check/{certType}/{fileName}") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult> checkSpecificCertificate( + @Parameter(description = "证书类型", example = "wechat") @PathVariable String certType, + @Parameter(description = "文件名", example = "apiclient_key.pem") @PathVariable String fileName) { + try { + Map result = certificateHealthService.checkSpecificCertificate(certType, fileName); + return success("检查证书完成", result); + } catch (Exception e) { + log.error("检查证书失败: {}/{}", certType, fileName, e); + return new ApiResult<>(1, "检查证书失败: " + e.getMessage()); + } + } + + @Operation(summary = "验证证书文件") + @GetMapping("/validate/{certType}/{fileName}") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult validateCertificate( + @Parameter(description = "证书类型", example = "wechat") @PathVariable String certType, + @Parameter(description = "文件名", example = "apiclient_cert.pem") @PathVariable String fileName) { + try { + CertificateService.CertificateInfo certInfo = + certificateService.validateX509Certificate(certType, fileName); + + if (certInfo != null) { + return success("证书验证成功", certInfo); + } else { + return new ApiResult<>(1, "证书验证失败,可能不是有效的X509证书"); + } + } catch (Exception e) { + log.error("验证证书失败: {}/{}", certType, fileName, e); + return new ApiResult<>(1, "验证证书失败: " + e.getMessage()); + } + } + + @Operation(summary = "检查证书文件是否存在") + @GetMapping("/exists/{certType}/{fileName}") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult checkCertificateExists( + @Parameter(description = "证书类型", example = "alipay") @PathVariable String certType, + @Parameter(description = "文件名", example = "appCertPublicKey.crt") @PathVariable String fileName) { + try { + boolean exists = certificateService.certificateExists(certType, fileName); + String message = exists ? "证书文件存在" : "证书文件不存在"; + return success(message, exists); + } catch (Exception e) { + log.error("检查证书文件存在性失败: {}/{}", certType, fileName, e); + return new ApiResult<>(1, "检查证书文件存在性失败: " + e.getMessage()); + } + } + + @Operation(summary = "获取证书文件路径") + @GetMapping("/path/{certType}/{fileName}") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult getCertificatePath( + @Parameter(description = "证书类型", example = "wechat") @PathVariable String certType, + @Parameter(description = "文件名", example = "wechatpay_cert.pem") @PathVariable String fileName) { + try { + String path = certificateService.getCertificateFilePath(certType, fileName); + return success("获取证书路径成功", path); + } catch (Exception e) { + log.error("获取证书路径失败: {}/{}", certType, fileName, e); + return new ApiResult<>(1, "获取证书路径失败: " + e.getMessage()); + } + } + + @Operation(summary = "获取微信支付证书路径") + @GetMapping("/wechat-path/{fileName}") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult getWechatPayCertPath( + @Parameter(description = "文件名", example = "apiclient_key.pem") @PathVariable String fileName) { + try { + String path = certificateService.getWechatPayCertPath(fileName); + return success("获取微信支付证书路径成功", path); + } catch (Exception e) { + log.error("获取微信支付证书路径失败: {}", fileName, e); + return new ApiResult<>(1, "获取微信支付证书路径失败: " + e.getMessage()); + } + } + + @Operation(summary = "获取支付宝证书路径") + @GetMapping("/alipay-path/{fileName}") + @PreAuthorize("hasAuthority('system:certificate:view')") + public ApiResult getAlipayCertPath( + @Parameter(description = "文件名", example = "appCertPublicKey.crt") @PathVariable String fileName) { + try { + String path = certificateService.getAlipayCertPath(fileName); + return success("获取支付宝证书路径成功", path); + } catch (Exception e) { + log.error("获取支付宝证书路径失败: {}", fileName, e); + return new ApiResult<>(1, "获取支付宝证书路径失败: " + e.getMessage()); + } + } + + @Operation(summary = "刷新证书缓存") + @PostMapping("/refresh") + @PreAuthorize("hasAuthority('system:certificate:manage')") + public ApiResult refreshCertificateCache() { + try { + // 这里可以添加刷新证书缓存的逻辑 + log.info("证书缓存刷新请求,操作用户: {}", getLoginUser().getUsername()); + return new ApiResult<>(0, "证书缓存刷新成功", "success"); + } catch (Exception e) { + log.error("刷新证书缓存失败", e); + return new ApiResult<>(1, "刷新证书缓存失败: " + e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/DatabaseFixController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/DatabaseFixController.java new file mode 100644 index 0000000..166e9cd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/DatabaseFixController.java @@ -0,0 +1,204 @@ +package com.gxwebsoft.common.core.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 数据库修复工具控制器 + * 仅在开发环境启用,用于修复数据库问题 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +@Tag(name = "数据库修复工具") +@RestController +@RequestMapping("/api/database-fix") +// @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev") +public class DatabaseFixController extends BaseController { + + @Autowired + private ShopUserCouponService shopUserCouponService; + + @Autowired + private ShopCouponService shopCouponService; + + @Operation(summary = "检查BigDecimal null值问题") + @GetMapping("/check-bigdecimal-nulls") + public ApiResult> checkBigDecimalNulls() { + try { + Map result = new HashMap<>(); + + // 检查用户优惠券表 + List userCoupons = shopUserCouponService.list(); + long userCouponNullReducePrice = userCoupons.stream() + .mapToLong(c -> c.getReducePrice() == null ? 1 : 0) + .sum(); + long userCouponNullMinPrice = userCoupons.stream() + .mapToLong(c -> c.getMinPrice() == null ? 1 : 0) + .sum(); + + // 检查优惠券模板表 + List coupons = shopCouponService.list(); + long couponNullReducePrice = coupons.stream() + .mapToLong(c -> c.getReducePrice() == null ? 1 : 0) + .sum(); + long couponNullMinPrice = coupons.stream() + .mapToLong(c -> c.getMinPrice() == null ? 1 : 0) + .sum(); + + Map userCouponStats = new HashMap<>(); + userCouponStats.put("totalRecords", userCoupons.size()); + userCouponStats.put("nullReducePrice", userCouponNullReducePrice); + userCouponStats.put("nullMinPrice", userCouponNullMinPrice); + + Map couponStats = new HashMap<>(); + couponStats.put("totalRecords", coupons.size()); + couponStats.put("nullReducePrice", couponNullReducePrice); + couponStats.put("nullMinPrice", couponNullMinPrice); + + result.put("shopUserCoupon", userCouponStats); + result.put("shopCoupon", couponStats); + result.put("needsFix", userCouponNullReducePrice > 0 || userCouponNullMinPrice > 0 || + couponNullReducePrice > 0 || couponNullMinPrice > 0); + + return success("检查完成", result); + + } catch (Exception e) { + log.error("检查BigDecimal null值失败", e); + return fail("检查失败: " + e.getMessage(),null); + } + } + + @Operation(summary = "修复BigDecimal null值问题") + @PostMapping("/fix-bigdecimal-nulls") + public ApiResult> fixBigDecimalNulls() { + try { + Map result = new HashMap<>(); + int userCouponFixed = 0; + int couponFixed = 0; + + // 修复用户优惠券表 + List userCoupons = shopUserCouponService.list(); + for (ShopUserCoupon userCoupon : userCoupons) { + boolean needUpdate = false; + + if (userCoupon.getReducePrice() == null) { + userCoupon.setReducePrice(BigDecimal.ZERO); + needUpdate = true; + } + + if (userCoupon.getMinPrice() == null) { + userCoupon.setMinPrice(BigDecimal.ZERO); + needUpdate = true; + } + + if (needUpdate) { + shopUserCouponService.updateById(userCoupon); + userCouponFixed++; + } + } + + // 修复优惠券模板表 + List coupons = shopCouponService.list(); + for (ShopCoupon coupon : coupons) { + boolean needUpdate = false; + + if (coupon.getReducePrice() == null) { + coupon.setReducePrice(BigDecimal.ZERO); + needUpdate = true; + } + + if (coupon.getMinPrice() == null) { + coupon.setMinPrice(BigDecimal.ZERO); + needUpdate = true; + } + + if (needUpdate) { + shopCouponService.updateById(coupon); + couponFixed++; + } + } + + result.put("userCouponFixed", userCouponFixed); + result.put("couponFixed", couponFixed); + result.put("totalFixed", userCouponFixed + couponFixed); + + log.info("BigDecimal null值修复完成: 用户优惠券{}条, 优惠券模板{}条", userCouponFixed, couponFixed); + + return success("修复完成", result); + + } catch (Exception e) { + log.error("修复BigDecimal null值失败", e); + return fail("修复失败: " + e.getMessage(), null); + } + } + + @Operation(summary = "测试优惠券接口") + @GetMapping("/test-coupon-api") + public ApiResult> testCouponApi() { + try { + Map result = new HashMap<>(); + + // 测试查询用户优惠券 + List userCoupons = shopUserCouponService.list( + new QueryWrapper().last("LIMIT 5") + ); + + // 测试查询优惠券模板 + List coupons = shopCouponService.list( + new QueryWrapper().last("LIMIT 5") + ); + + result.put("userCouponsCount", userCoupons.size()); + result.put("couponsCount", coupons.size()); + result.put("userCouponsSample", userCoupons); + result.put("couponsSample", coupons); + result.put("testStatus", "SUCCESS"); + + return success("测试成功", result); + + } catch (Exception e) { + log.error("测试优惠券接口失败", e); + Map errorResult = new HashMap<>(); + errorResult.put("testStatus", "FAILED"); + errorResult.put("errorMessage", e.getMessage()); + errorResult.put("errorType", e.getClass().getSimpleName()); + + return fail("测试失败: " + e.getMessage(), errorResult); + } + } + + @Operation(summary = "获取修复指南") + @GetMapping("/guide") + public ApiResult> getFixGuide() { + Map guide = new HashMap<>(); + + guide.put("step1", "GET /api/database-fix/check-bigdecimal-nulls - 检查null值问题"); + guide.put("step2", "POST /api/database-fix/fix-bigdecimal-nulls - 修复null值问题"); + guide.put("step3", "GET /api/database-fix/test-coupon-api - 测试修复效果"); + guide.put("step4", "重启应用,验证优惠券功能正常"); + + guide.put("note1", "此工具仅在开发环境可用"); + guide.put("note2", "修复前建议备份数据库"); + guide.put("note3", "修复完成后可以删除此控制器"); + + return success("获取成功", guide); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/DevEnvironmentController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/DevEnvironmentController.java new file mode 100644 index 0000000..8e30a34 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/DevEnvironmentController.java @@ -0,0 +1,236 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.service.EnvironmentAwarePaymentService; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.service.PaymentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 开发环境管理控制器 + * 仅在开发环境启用,用于管理开发调试配置 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +@Tag(name = "开发环境管理") +@RestController +@RequestMapping("/api/dev") +// @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev") +public class DevEnvironmentController extends BaseController { + + @Autowired + private EnvironmentAwarePaymentService environmentAwarePaymentService; + + @Autowired + private PaymentCacheService paymentCacheService; + + @Autowired + private PaymentService paymentService; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + @Operation(summary = "获取当前环境信息") + @GetMapping("/environment/info") + public ApiResult> getEnvironmentInfo() { + Map info = new HashMap<>(); + info.put("activeProfile", activeProfile); + info.put("isDevelopment", environmentAwarePaymentService.isDevelopmentEnvironment()); + info.put("isProduction", environmentAwarePaymentService.isProductionEnvironment()); + info.put("currentEnvironment", environmentAwarePaymentService.getCurrentEnvironment()); + + return success("获取成功", info); + } + + @Operation(summary = "获取环境感知的支付配置") + @GetMapping("/payment/config/{payType}") + public ApiResult> getPaymentConfig(@PathVariable Integer payType) { + try { + Integer tenantId = getTenantId(); + + // 获取原始配置 + Payment originalConfig = paymentCacheService.getPaymentConfig(payType, tenantId); + + // 获取环境感知配置 + Payment envConfig = environmentAwarePaymentService.getEnvironmentAwarePaymentConfig(payType, tenantId); + + Map result = new HashMap<>(); + result.put("tenantId", tenantId); + result.put("payType", payType); + result.put("environment", activeProfile); + result.put("originalConfig", originalConfig); + result.put("environmentAwareConfig", envConfig); + + if (originalConfig != null && envConfig != null) { + result.put("notifyUrlChanged", !originalConfig.getNotifyUrl().equals(envConfig.getNotifyUrl())); + result.put("originalNotifyUrl", originalConfig.getNotifyUrl()); + result.put("environmentNotifyUrl", envConfig.getNotifyUrl()); + } + + return success("获取成功", result); + + } catch (Exception e) { + log.error("获取支付配置失败", e); + return fail("获取失败: " + e.getMessage(),null); + } + } + + @Operation(summary = "切换开发环境回调地址") + @PostMapping("/payment/switch-notify-url") + public ApiResult switchNotifyUrl(@RequestBody Map request) { + try { + String newNotifyUrl = request.get("notifyUrl"); + Integer payType = Integer.valueOf(request.getOrDefault("payType", "0")); + + if (newNotifyUrl == null || newNotifyUrl.trim().isEmpty()) { + return fail("回调地址不能为空"); + } + + Integer tenantId = getTenantId(); + + // 获取当前配置 + Payment payment = paymentCacheService.getPaymentConfig(payType, tenantId); + if (payment == null) { + return fail("未找到支付配置"); + } + + // 更新回调地址 + payment.setNotifyUrl(newNotifyUrl); + + // 更新数据库 + boolean updated = paymentService.updateById(payment); + + if (updated) { + // 清除缓存,强制重新加载 + paymentCacheService.removePaymentConfig(payType.toString(), tenantId); + + log.info("开发环境回调地址已更新: {} -> {}", payment.getNotifyUrl(), newNotifyUrl); + + Map result = new HashMap<>(); + result.put("oldNotifyUrl", payment.getNotifyUrl()); + result.put("newNotifyUrl", newNotifyUrl); + result.put("payType", payType); + result.put("tenantId", tenantId); + + return success("回调地址更新成功", result); + } else { + return fail("更新失败"); + } + + } catch (Exception e) { + log.error("切换回调地址失败", e); + return fail("切换失败: " + e.getMessage()); + } + } + + @Operation(summary = "重置为生产环境回调地址") + @PostMapping("/payment/reset-to-prod") + public ApiResult resetToProdNotifyUrl(@RequestParam(defaultValue = "0") Integer payType) { + try { + Integer tenantId = getTenantId(); + + // 获取当前配置 + Payment payment = paymentCacheService.getPaymentConfig(payType, tenantId); + if (payment == null) { + return fail("未找到支付配置"); + } + + // 设置为生产环境回调地址 + String prodNotifyUrl = "https://cms-api.websoft.top/api/shop/shop-order/notify"; + String oldNotifyUrl = payment.getNotifyUrl(); + + payment.setNotifyUrl(prodNotifyUrl); + + // 更新数据库 + boolean updated = paymentService.updateById(payment); + + if (updated) { + // 清除缓存 + paymentCacheService.removePaymentConfig(payType.toString(), tenantId); + + log.info("回调地址已重置为生产环境: {} -> {}", oldNotifyUrl, prodNotifyUrl); + + Map result = new HashMap<>(); + result.put("oldNotifyUrl", oldNotifyUrl); + result.put("newNotifyUrl", prodNotifyUrl); + result.put("payType", payType); + result.put("tenantId", tenantId); + + return success("已重置为生产环境回调地址", result); + } else { + return fail("重置失败"); + } + + } catch (Exception e) { + log.error("重置回调地址失败", e); + return fail("重置失败: " + e.getMessage()); + } + } + + @Operation(summary = "清除支付配置缓存") + @PostMapping("/payment/clear-cache") + public ApiResult clearPaymentCache(@RequestParam(defaultValue = "0") Integer payType) { + try { + Integer tenantId = getTenantId(); + + paymentCacheService.removePaymentConfig(payType.toString(), tenantId); + + log.info("支付配置缓存已清除: payType={}, tenantId={}", payType, tenantId); + + return success("缓存清除成功"); + + } catch (Exception e) { + log.error("清除缓存失败", e); + return fail("清除失败: " + e.getMessage()); + } + } + + @Operation(summary = "获取开发环境使用指南") + @GetMapping("/guide") + public ApiResult> getDevGuide() { + Map guide = new HashMap<>(); + + guide.put("title", "开发环境支付调试指南"); + guide.put("environment", activeProfile); + + Map steps = new HashMap<>(); + steps.put("step1", "使用 /api/dev/payment/switch-notify-url 切换到本地回调地址"); + steps.put("step2", "进行支付功能调试和测试"); + steps.put("step3", "调试完成后使用 /api/dev/payment/reset-to-prod 恢复生产环境配置"); + steps.put("step4", "或者直接在后台管理界面修改回调地址"); + + guide.put("steps", steps); + + Map apis = new HashMap<>(); + apis.put("环境信息", "GET /api/dev/environment/info"); + apis.put("查看配置", "GET /api/dev/payment/config/{payType}"); + apis.put("切换回调", "POST /api/dev/payment/switch-notify-url"); + apis.put("重置生产", "POST /api/dev/payment/reset-to-prod"); + apis.put("清除缓存", "POST /api/dev/payment/clear-cache"); + + guide.put("apis", apis); + + Map tips = new HashMap<>(); + tips.put("tip1", "此控制器仅在开发环境启用"); + tips.put("tip2", "生产环境不会加载这些接口"); + tips.put("tip3", "建议使用环境感知服务自动切换"); + tips.put("tip4", "记得在调试完成后恢复生产配置"); + + guide.put("tips", tips); + + return success("获取成功", guide); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/JacksonTestController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/JacksonTestController.java new file mode 100644 index 0000000..2a58aea --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/JacksonTestController.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * Jackson序列化测试控制器 + * 用于测试LocalDateTime序列化是否正常工作 + * + * @author WebSoft + * @since 2025-09-08 + */ +@Tag(name = "Jackson测试") +@RestController +@RequestMapping("/api/test/jackson") +public class JacksonTestController extends BaseController { + + @Operation(summary = "测试LocalDateTime序列化") + @GetMapping("/datetime") + public ApiResult> testDateTime() { + Map result = new HashMap<>(); + result.put("currentTime", LocalDateTime.now()); + result.put("message", "如果您能看到格式化的时间,说明Jackson配置正常"); + result.put("timestamp", System.currentTimeMillis()); + return success(result); + } + + @Operation(summary = "测试实体类序列化") + @GetMapping("/entity") + public ApiResult testEntity() { + TestEntity entity = new TestEntity(); + entity.setId(1); + entity.setName("测试实体"); + entity.setCreateTime(LocalDateTime.now()); + entity.setUpdateTime(LocalDateTime.now()); + return success(entity); + } + + /** + * 测试实体类 + */ + public static class TestEntity { + private Integer id; + private String name; + private LocalDateTime createTime; + private LocalDateTime updateTime; + + // Getters and Setters + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/PaymentConfigController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/PaymentConfigController.java new file mode 100644 index 0000000..37706fd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/PaymentConfigController.java @@ -0,0 +1,149 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.service.PaymentService; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 支付配置管理控制器 + * 用于检查和管理支付配置 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Tag(name = "支付配置管理") +@RestController +@RequestMapping("/api/system/payment-config") +public class PaymentConfigController extends BaseController { + + @Autowired + private PaymentService paymentService; + + @Autowired + private PaymentCacheService paymentCacheService; + + @Operation(summary = "检查支付配置") + @GetMapping("/check/{payType}") + @PreAuthorize("hasAuthority('sys:payment:list')") + public ApiResult> checkPaymentConfig(@PathVariable Integer payType) { + try { + Map result = new HashMap<>(); + + // 获取支付配置 + Payment payment = paymentCacheService.getPaymentConfig(payType, getTenantId()); + + if (payment == null) { + result.put("status", "error"); + result.put("message", "未找到支付配置"); + return success("检查完成", result); + } + + // 检查配置完整性 + Map configCheck = new HashMap<>(); + configCheck.put("id", payment.getId()); + configCheck.put("name", payment.getName()); + configCheck.put("type", payment.getType()); + configCheck.put("code", payment.getCode()); + configCheck.put("appId", payment.getAppId()); + configCheck.put("mchId", payment.getMchId()); + configCheck.put("apiKeyConfigured", payment.getApiKey() != null && !payment.getApiKey().trim().isEmpty()); + configCheck.put("apiKeyLength", payment.getApiKey() != null ? payment.getApiKey().length() : 0); + configCheck.put("merchantSerialNumber", payment.getMerchantSerialNumber()); + configCheck.put("status", payment.getStatus()); + configCheck.put("tenantId", payment.getTenantId()); + + // 检查必要字段 + boolean isValid = true; + StringBuilder errors = new StringBuilder(); + + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + isValid = false; + errors.append("商户号(mchId)未配置; "); + } + + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + isValid = false; + errors.append("API密钥(apiKey)未配置; "); + } + + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + isValid = false; + errors.append("商户证书序列号(merchantSerialNumber)未配置; "); + } + + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + isValid = false; + errors.append("应用ID(appId)未配置; "); + } + + result.put("status", isValid ? "success" : "error"); + result.put("valid", isValid); + result.put("errors", errors.toString()); + result.put("config", configCheck); + + return success("检查完成", result); + + } catch (Exception e) { + log.error("检查支付配置失败", e); + Map result = new HashMap<>(); + result.put("status", "error"); + result.put("message", "检查失败: " + e.getMessage()); + return success("检查完成", result); + } + } + + @Operation(summary = "初始化微信支付配置") + @PostMapping("/init-wechat") + @PreAuthorize("hasAuthority('sys:payment:save')") + public ApiResult initWechatPayConfig(@RequestBody Map config) { + try { + Payment payment = new Payment(); + payment.setName("微信支付"); + payment.setType(0); // 微信支付类型为0 + payment.setCode("0"); + payment.setAppId(config.get("appId")); + payment.setMchId(config.get("mchId")); + payment.setApiKey(config.get("apiKey")); + payment.setMerchantSerialNumber(config.get("merchantSerialNumber")); + payment.setStatus(true); + payment.setTenantId(getTenantId()); + + if (paymentService.save(payment)) { + // 缓存配置 + paymentCacheService.cachePaymentConfig(payment, getTenantId()); + return success("微信支付配置初始化成功"); + } else { + return fail("微信支付配置初始化失败"); + } + + } catch (Exception e) { + log.error("初始化微信支付配置失败", e); + return fail("初始化失败: " + e.getMessage()); + } + } + + @Operation(summary = "清除支付配置缓存") + @DeleteMapping("/cache/{payType}") + @PreAuthorize("hasAuthority('sys:payment:update')") + public ApiResult clearPaymentCache(@PathVariable Integer payType) { + try { + paymentCacheService.removePaymentConfig(payType.toString(), getTenantId()); + return success("缓存清除成功"); + } catch (Exception e) { + log.error("清除支付配置缓存失败", e); + return fail("清除缓存失败: " + e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/QrCodeController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/QrCodeController.java new file mode 100644 index 0000000..b589901 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/QrCodeController.java @@ -0,0 +1,258 @@ +package com.gxwebsoft.common.core.controller; + +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import com.gxwebsoft.common.core.dto.qr.*; +import com.gxwebsoft.common.core.utils.EncryptedQrCodeUtil; +import com.gxwebsoft.common.core.utils.QrCodeDecryptResult; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.awt.*; +import java.io.IOException; +import java.util.Base64; +import java.util.Map; + +/** + * 二维码生成控制器 + * + * @author WebSoft + * @since 2025-08-18 + */ +@RestController +@RequestMapping("/api/qr-code") +@Tag(name = "二维码生成API") +@Validated +public class QrCodeController extends BaseController { + + @Autowired + private EncryptedQrCodeUtil encryptedQrCodeUtil; + + @Operation(summary = "生成普通二维码") + @GetMapping("/create-qr-code") + public void createQrCode( + @Parameter(description = "要编码的数据") @RequestParam("data") String data, + @Parameter(description = "二维码尺寸,格式:宽x高 或 单个数字") @RequestParam(value = "size", defaultValue = "200x200") String size, + HttpServletResponse response) throws IOException { + + try { + // 解析尺寸 + String[] dimensions = size.split("x"); + int width = Integer.parseInt(dimensions[0]); + int height = dimensions.length > 1 ? Integer.parseInt(dimensions[1]) : width; + + // 验证尺寸范围,防止过大的图片 + if (width < 50 || width > 1000 || height < 50 || height > 1000) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("尺寸必须在50-1000像素之间"); + return; + } + + // 配置二维码 + QrConfig config = new QrConfig(width, height); + config.setMargin(1); + config.setForeColor(Color.BLACK); + config.setBackColor(Color.WHITE); + + // 设置响应头 + response.setContentType("image/png"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Content-Disposition", "inline; filename=qrcode.png"); + + // 生成二维码并直接输出到响应流 + QrCodeUtil.generate(data, config, "png", response.getOutputStream()); + + } catch (NumberFormatException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("尺寸格式错误,请使用如:200x200 的格式"); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("生成二维码失败:" + e.getMessage()); + } + } + + @Operation(summary = "生成加密二维码") + @PostMapping("/create-encrypted-qr-code") + public ApiResult createEncryptedQrCode(@Valid @RequestBody CreateEncryptedQrCodeRequest request) { + + try { + // 生成加密二维码 + Map result = encryptedQrCodeUtil.generateEncryptedQrCode( + request.getData(), + request.getWidth(), + request.getHeight(), + request.getExpireMinutes(), + request.getBusinessType()); + + return success("生成加密二维码成功", result); + + } catch (Exception e) { + return fail("生成加密二维码失败:" + e.getMessage()); + } + } + + @Operation(summary = "生成加密二维码图片流") + @GetMapping("/create-encrypted-qr-image") + public void createEncryptedQrImage( + @Parameter(description = "要加密的数据") @RequestParam("data") String data, + @Parameter(description = "二维码尺寸") @RequestParam(value = "size", defaultValue = "200x200") String size, + @Parameter(description = "过期时间(分钟)") @RequestParam(value = "expireMinutes", defaultValue = "30") Long expireMinutes, + @Parameter(description = "业务类型(可选)") @RequestParam(value = "businessType", required = false) String businessType, + HttpServletResponse response) throws IOException { + + try { + // 解析尺寸 + String[] dimensions = size.split("x"); + int width = Integer.parseInt(dimensions[0]); + int height = dimensions.length > 1 ? Integer.parseInt(dimensions[1]) : width; + + // 验证尺寸范围 + if (width < 50 || width > 1000 || height < 50 || height > 1000) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("尺寸必须在50-1000像素之间"); + return; + } + + // 验证过期时间 + if (expireMinutes <= 0 || expireMinutes > 1440) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("过期时间必须在1-1440分钟之间"); + return; + } + + // 生成加密二维码 + Map result = encryptedQrCodeUtil.generateEncryptedQrCode(data, width, height, expireMinutes, businessType); + String base64Image = (String) result.get("qrCodeBase64"); + + // 解码Base64图片 + byte[] imageBytes = Base64.getDecoder().decode(base64Image); + + // 设置响应头 + response.setContentType("image/png"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Content-Disposition", "inline; filename=encrypted_qrcode.png"); + response.setHeader("X-QR-Token", (String) result.get("token")); + response.setHeader("X-QR-Expire-Minutes", result.get("expireMinutes").toString()); + + // 输出图片 + response.getOutputStream().write(imageBytes); + + } catch (NumberFormatException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("尺寸格式错误,请使用如:200x200 的格式"); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("生成加密二维码失败:" + e.getMessage()); + } + } + + @Operation(summary = "解密二维码数据") + @PostMapping("/decrypt-qr-data") + public ApiResult decryptQrData(@Valid @RequestBody DecryptQrDataRequest request) { + + try { + String decryptedData = encryptedQrCodeUtil.decryptData(request.getToken(), request.getEncryptedData()); + return success("解密成功", decryptedData); + + } catch (Exception e) { + return fail("解密失败:" + e.getMessage()); + } + } + + @Operation(summary = "验证并解密二维码内容(自包含模式)") + @PostMapping("/verify-and-decrypt-qr") + public ApiResult verifyAndDecryptQr(@Valid @RequestBody VerifyQrContentRequest request) { + + try { + String originalData = encryptedQrCodeUtil.verifyAndDecryptQrCode(request.getQrContent()); + return success("验证和解密成功", originalData); + + } catch (Exception e) { + return fail("验证和解密失败:" + e.getMessage()); + } + } + + @Operation(summary = "验证并解密二维码内容(返回完整结果,包含业务类型)") + @PostMapping("/verify-and-decrypt-qr-with-type") + public ApiResult verifyAndDecryptQrWithType(@Valid @RequestBody VerifyQrContentRequest request) { + + try { + QrCodeDecryptResult result = encryptedQrCodeUtil.verifyAndDecryptQrCodeWithResult(request.getQrContent()); + return success("验证和解密成功", result); + + } catch (Exception e) { + return fail("验证和解密失败:" + e.getMessage(),null); + } + } + + @Operation(summary = "生成业务加密二维码(门店核销模式)") + @PostMapping("/create-business-encrypted-qr-code") + public ApiResult createBusinessEncryptedQrCode(@Valid @RequestBody CreateBusinessEncryptedQrCodeRequest request) { + + try { + // 生成业务加密二维码 + Map result = encryptedQrCodeUtil.generateBusinessEncryptedQrCode( + request.getData(), + request.getWidth(), + request.getHeight(), + request.getBusinessKey(), + request.getExpireMinutes(), + request.getBusinessType()); + + return success("生成业务加密二维码成功", result); + + } catch (Exception e) { + return fail("生成业务加密二维码失败:" + e.getMessage()); + } + } + + @Operation(summary = "门店核销二维码(业务模式)") + @PostMapping("/verify-business-qr") + public ApiResult verifyBusinessQr(@Valid @RequestBody VerifyBusinessQrRequest request) { + + try { + String originalData = encryptedQrCodeUtil.verifyAndDecryptQrCodeWithBusinessKey( + request.getQrContent(), request.getBusinessKey()); + return success("核销成功", originalData); + + } catch (Exception e) { + return fail("核销失败:" + e.getMessage()); + } + } + + @Operation(summary = "检查token是否有效") + @GetMapping("/check-token") + public ApiResult checkToken( + @Parameter(description = "要检查的token") @RequestParam("token") String token) { + + try { + boolean isValid = encryptedQrCodeUtil.isTokenValid(token); + return success("检查完成", isValid); + + } catch (Exception e) { + return fail("检查token失败:" + e.getMessage()); + } + } + + @Operation(summary = "使token失效") + @PostMapping("/invalidate-token") + public ApiResult invalidateToken(@Valid @RequestBody InvalidateTokenRequest request) { + + try { + encryptedQrCodeUtil.invalidateToken(request.getToken()); + return success("token已失效"); + + } catch (Exception e) { + return fail("使token失效失败:" + e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/TestController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/TestController.java new file mode 100644 index 0000000..05c4246 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/TestController.java @@ -0,0 +1,302 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.service.PaymentService; +import com.gxwebsoft.common.system.param.PaymentParam; +import com.gxwebsoft.common.core.web.ApiResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 测试控制器 + * 用于测试LocalDateTime序列化 + * + * @author WebSoft + * @since 2025-01-12 + */ +@Tag(name = "测试接口") +@RestController +@RequestMapping("/api/test") +public class TestController extends BaseController { + + @Autowired + private PaymentCacheService paymentCacheService; + + @Autowired + private PaymentService paymentService; + + @Operation(summary = "测试LocalDateTime序列化") + @GetMapping("/datetime") + public ApiResult> testDateTime() { + Map result = new HashMap<>(); + // 使用字符串格式避免序列化问题 + result.put("currentTime", LocalDateTime.now().toString()); + result.put("currentTimeFormatted", LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + result.put("message", "LocalDateTime序列化测试"); + result.put("timestamp", System.currentTimeMillis()); + return success(result); + } + + @Operation(summary = "基础诊断 - 不依赖支付服务") + @GetMapping("/basic-debug/{tenantId}") + public ApiResult basicDebug(@PathVariable Integer tenantId) { + try { + System.out.println("=== 基础诊断开始 ==="); + System.out.println("接收到的租户ID: " + tenantId); + + if (tenantId == null) { + return fail("租户ID为null",null); + } + + return success("基础诊断通过,租户ID: " + tenantId,null); + + } catch (Exception e) { + System.err.println("基础诊断异常: " + e.getMessage()); + e.printStackTrace(); + return fail("基础诊断异常: " + e.getMessage(),null); + } + } + + @Operation(summary = "快速诊断支付配置") + @GetMapping("/payment-debug/{tenantId}") + public ApiResult debugPaymentConfig(@PathVariable Integer tenantId) { + try { + System.out.println("=== 开始诊断租户 " + tenantId + " 的支付配置 ==="); + + // 检查基础参数 + if (tenantId == null) { + return fail("租户ID为null",null); + } + + // 检查服务是否可用 + if (paymentCacheService == null) { + return fail("PaymentCacheService未注入",null); + } + + System.out.println("准备调用 paymentCacheService.getWechatPayConfig(" + tenantId + ")"); + + // 获取支付配置 + Payment payment = null; + try { + payment = paymentCacheService.getWechatPayConfig(tenantId); + System.out.println("成功调用 getWechatPayConfig,结果: " + (payment != null ? "非null" : "null")); + } catch (Exception e) { + System.err.println("调用 getWechatPayConfig 异常: " + e.getMessage()); + e.printStackTrace(); + return fail("获取支付配置异常: " + e.getMessage() + " (类型: " + e.getClass().getName() + ")",null); + } + + if (payment == null) { + System.out.println("❌ 支付配置不存在"); + return fail("支付配置不存在,租户ID: " + tenantId,null); + } + + // 构建诊断信息字符串,避免序列化问题 + StringBuilder diagnosis = new StringBuilder(); + diagnosis.append("=== 支付配置诊断结果 ===\n"); + diagnosis.append("租户ID: ").append(tenantId).append("\n"); + diagnosis.append("商户号: ").append(payment.getMchId()).append("\n"); + diagnosis.append("应用ID: ").append(payment.getAppId()).append("\n"); + diagnosis.append("证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); + diagnosis.append("API密钥: ").append(payment.getApiKey() != null ? "已配置(长度:" + payment.getApiKey().length() + ")" : "未配置").append("\n"); + diagnosis.append("状态: ").append(payment.getStatus()).append("\n"); + diagnosis.append("私钥文件: ").append(payment.getApiclientKey()).append("\n"); + diagnosis.append("证书文件: ").append(payment.getApiclientCert()).append("\n"); + diagnosis.append("公钥文件: ").append(payment.getPubKey()).append("\n"); + diagnosis.append("公钥ID: ").append(payment.getPubKeyId()).append("\n"); + + // 检查问题 + StringBuilder issues = new StringBuilder(); + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + issues.append("❌ 商户号为空\n"); + } + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + issues.append("❌ 应用ID为空\n"); + } + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + issues.append("❌ 证书序列号为空\n"); + } + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + issues.append("❌ API密钥为空\n"); + } else if (payment.getApiKey().length() != 32) { + issues.append("❌ API密钥长度错误(").append(payment.getApiKey().length()).append("位)\n"); + } + if (payment.getStatus() == null || !payment.getStatus()) { + issues.append("❌ 支付配置未启用\n"); + } + + if (issues.length() > 0) { + diagnosis.append("\n=== 发现的问题 ===\n"); + diagnosis.append(issues.toString()); + } else { + diagnosis.append("\n✅ 配置检查通过,无问题发现"); + } + + // 打印到控制台 + System.out.println(diagnosis.toString()); + + if (issues.length() > 0) { + return fail(diagnosis.toString(),null); + } else { + return success(diagnosis.toString(),null); + } + + } catch (Exception e) { + String errorMsg = "诊断失败: " + e.getMessage() + " (类型: " + e.getClass().getName() + ")"; + System.err.println(errorMsg); + e.printStackTrace(); + return fail(errorMsg,null); + } + } + + @Operation(summary = "直接数据库查询支付配置") + @GetMapping("/db-payment-check/{tenantId}") + public ApiResult checkPaymentFromDB(@PathVariable Integer tenantId) { + try { + System.out.println("=== 直接数据库查询支付配置 ==="); + System.out.println("租户ID: " + tenantId); + + if (tenantId == null) { + return fail("租户ID为null",null); + } + + if (paymentService == null) { + return fail("PaymentService未注入",null); + } + + // 直接查询数据库,不使用缓存 + PaymentParam param = new PaymentParam(); + param.setType(0); // 微信支付 + param.setTenantId(tenantId); + + System.out.println("准备查询数据库,参数: type=0, tenantId=" + tenantId); + + java.util.List payments = paymentService.listRel(param); + + System.out.println("查询结果数量: " + (payments != null ? payments.size() : "null")); + + if (payments == null || payments.isEmpty()) { + return fail("数据库中没有找到租户 " + tenantId + " 的微信支付配置",null); + } + + Payment payment = payments.get(0); + + StringBuilder result = new StringBuilder(); + result.append("=== 数据库查询结果 ===\n"); + result.append("租户ID: ").append(payment.getTenantId()).append("\n"); + result.append("支付方式: ").append(payment.getName()).append("\n"); + result.append("类型: ").append(payment.getType()).append("\n"); + result.append("商户号: ").append(payment.getMchId()).append("\n"); + result.append("应用ID: ").append(payment.getAppId()).append("\n"); + result.append("证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); + result.append("API密钥状态: ").append(payment.getApiKey() != null ? "已配置(长度:" + payment.getApiKey().length() + ")" : "未配置").append("\n"); + result.append("状态: ").append(payment.getStatus()).append("\n"); + result.append("是否删除: ").append(payment.getDeleted()).append("\n"); + + System.out.println(result.toString()); + + return success(result.toString(),null); + + } catch (Exception e) { + String errorMsg = "数据库查询异常: " + e.getMessage() + " (类型: " + e.getClass().getName() + ")"; + System.err.println(errorMsg); + e.printStackTrace(); + return fail(errorMsg,null); + } + } + + @Operation(summary = "清理支付配置缓存") + @GetMapping("/clear-payment-cache/{tenantId}") + public String clearPaymentCache(@PathVariable Integer tenantId) { + try { + System.out.println("=== 清理支付配置缓存 ==="); + System.out.println("租户ID: " + tenantId); + + if (tenantId == null) { + return "错误: 租户ID为null"; + } + + // 清理可能的缓存键 + paymentCacheService.removePaymentConfig("0", tenantId); // 微信支付 + paymentCacheService.removePaymentConfig("wechat", tenantId); // 可能的其他格式 + + String result = "✅ 缓存已清理,租户ID: " + tenantId; + System.out.println(result); + return result; + + } catch (Exception e) { + String errorMsg = "❌ 清理缓存异常: " + e.getMessage(); + System.err.println(errorMsg); + e.printStackTrace(); + return errorMsg; + } + } + + @Operation(summary = "最简单的测试接口") + @GetMapping("/simple-test") + public String simpleTest() { + return "✅ 测试接口正常工作,时间: " + System.currentTimeMillis(); + } + + @Operation(summary = "测试支付配置是否存在") + @GetMapping("/check-payment-exists/{tenantId}") + public String checkPaymentExists(@PathVariable Integer tenantId) { + try { + System.out.println("=== 检查支付配置是否存在 ==="); + System.out.println("租户ID: " + tenantId); + + if (tenantId == null) { + return "❌ 租户ID为null"; + } + + if (paymentService == null) { + return "❌ PaymentService未注入"; + } + + // 使用最简单的查询 + PaymentParam param = new PaymentParam(); + param.setType(0); + param.setTenantId(tenantId); + + java.util.List payments = paymentService.listRel(param); + + if (payments == null) { + return "❌ 查询结果为null"; + } + + if (payments.isEmpty()) { + return "❌ 没有找到支付配置,租户ID: " + tenantId; + } + + Payment payment = payments.get(0); + StringBuilder result = new StringBuilder(); + result.append("✅ 找到支付配置\n"); + result.append("租户ID: ").append(payment.getTenantId()).append("\n"); + result.append("商户号: ").append(payment.getMchId() != null ? payment.getMchId() : "NULL").append("\n"); + result.append("应用ID: ").append(payment.getAppId() != null ? payment.getAppId() : "NULL").append("\n"); + result.append("状态: ").append(payment.getStatus()).append("\n"); + + return result.toString(); + + } catch (Exception e) { + String error = "❌ 检查异常: " + e.getMessage(); + System.err.println(error); + e.printStackTrace(); + return error; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/TranslateController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/TranslateController.java new file mode 100644 index 0000000..7fe1400 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/TranslateController.java @@ -0,0 +1,160 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.utils.AliyunTranslateUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/** + * 翻译控制器 + * 提供文本翻译和批量翻译功能 + */ +@Slf4j +@Tag(name = "翻译管理") +@RestController +@RequestMapping("/api/translate") +public class TranslateController extends BaseController { + + @Resource + private AliyunTranslateUtil translateUtil; + + @Operation(summary = "单文本翻译") + @PostMapping("/text") + public ApiResult translateText(@RequestBody TranslateRequest request) { + try { + String translated = translateUtil.translate( + request.getText(), + request.getTargetLang(), + request.getSourceLang() != null ? request.getSourceLang() : "auto" + ); + + TranslateResponse response = new TranslateResponse(); + response.setSourceText(request.getText()); + response.setTranslatedText(translated); + response.setSourceLang(request.getSourceLang()); + response.setTargetLang(request.getTargetLang()); + + return success("翻译成功", response); + } catch (Exception e) { + log.error("翻译失败", e); + return new ApiResult<>(1, "翻译失败: " + e.getMessage()); + } + } + + @Operation(summary = "批量翻译") + @PostMapping("/batch") + public ApiResult batchTranslate(@RequestBody BatchTranslateRequest request) { + try { + log.info("收到批量翻译请求: {}", request); + + // 参数校验 + if (request.getTexts() == null || request.getTexts().isEmpty()) { + return new ApiResult<>(1, "待翻译文本列表不能为空"); + } + + if (request.getTargetLang() == null || request.getTargetLang().isEmpty()) { + return new ApiResult<>(1, "目标语言不能为空"); + } + + List results = new ArrayList<>(); + + for (String text : request.getTexts()) { + if (text == null || text.trim().isEmpty()) { + continue; // 跳过空文本 + } + + String translated = translateUtil.translate( + text, + request.getTargetLang(), + request.getSourceLang() != null ? request.getSourceLang() : "auto" + ); + + TranslateResponse response = new TranslateResponse(); + response.setSourceText(text); + response.setTranslatedText(translated); + response.setSourceLang(request.getSourceLang()); + response.setTargetLang(request.getTargetLang()); + + results.add(response); + } + + BatchTranslateResponse batchResponse = new BatchTranslateResponse(); + batchResponse.setResults(results); + batchResponse.setTotal(results.size()); + + return success("批量翻译成功", batchResponse); + } catch (Exception e) { + log.error("批量翻译失败,请求参数: {}", request, e); + return new ApiResult<>(1, "批量翻译失败: " + e.getMessage()); + } + } + + /** + * 单文本翻译请求 + */ + @Data + public static class TranslateRequest { + @Parameter(description = "待翻译文本") + private String text; + + @Parameter(description = "目标语言(如:en, zh, ja, ko)") + private String targetLang; + + @Parameter(description = "源语言(如:zh, en, auto)默认auto自动检测") + private String sourceLang; + } + + /** + * 批量翻译请求 + */ + @Data + public static class BatchTranslateRequest { + @Parameter(description = "待翻译文本列表") + private List texts; + + @Parameter(description = "目标语言(如:en, zh, ja, ko)") + private String targetLang; + + @Parameter(description = "源语言(如:zh, en, auto)默认auto自动检测") + private String sourceLang; + } + + /** + * 翻译响应 + */ + @Data + public static class TranslateResponse { + @Parameter(description = "原文") + private String sourceText; + + @Parameter(description = "译文") + private String translatedText; + + @Parameter(description = "源语言") + private String sourceLang; + + @Parameter(description = "目标语言") + private String targetLang; + } + + /** + * 批量翻译响应 + */ + @Data + public static class BatchTranslateResponse { + @Parameter(description = "翻译结果列表") + private List results; + + @Parameter(description = "总数") + private Integer total; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/WechatCertTestController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/WechatCertTestController.java new file mode 100644 index 0000000..148ece5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/WechatCertTestController.java @@ -0,0 +1,211 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.utils.WechatCertAutoConfig; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.wechat.pay.java.core.Config; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 微信支付证书自动配置测试控制器 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@RestController +@RequestMapping("/api/wechat-cert-test") +@Tag(name = "微信支付证书自动配置测试") +public class WechatCertTestController extends BaseController { + + @Autowired + private WechatCertAutoConfig wechatCertAutoConfig; + + @Operation(summary = "测试默认开发环境证书配置") + @PostMapping("/test-default") + public ApiResult> testDefaultConfig() { + Map result = new HashMap<>(); + + try { + log.info("开始测试默认开发环境证书配置..."); + + // 创建自动证书配置 + Config config = wechatCertAutoConfig.createDefaultDevConfig(); + + // 测试配置 + boolean testResult = wechatCertAutoConfig.testConfig(config); + + result.put("success", true); + result.put("configCreated", config != null); + result.put("testPassed", testResult); + result.put("message", "默认证书配置测试完成"); + result.put("instructions", wechatCertAutoConfig.getUsageInstructions()); + + log.info("✅ 默认证书配置测试成功"); + return success("测试成功", result); + + } catch (Exception e) { + log.error("❌ 默认证书配置测试失败: {}", e.getMessage(), e); + + result.put("success", false); + result.put("error", e.getMessage()); + result.put("message", "证书配置测试失败"); + result.put("troubleshooting", getTroubleshootingInfo()); + + return fail("测试失败: " + e.getMessage(), result); + } + } + + @Operation(summary = "测试自定义证书配置") + @PostMapping("/test-custom") + public ApiResult> testCustomConfig( + @Parameter(description = "商户号") @RequestParam String merchantId, + @Parameter(description = "私钥文件路径") @RequestParam String privateKeyPath, + @Parameter(description = "证书序列号") @RequestParam String merchantSerialNumber, + @Parameter(description = "APIv3密钥") @RequestParam String apiV3Key) { + + Map result = new HashMap<>(); + + try { + log.info("开始测试自定义证书配置..."); + log.info("商户号: {}", merchantId); + log.info("私钥路径: {}", privateKeyPath); + + // 创建自动证书配置 + Config config = wechatCertAutoConfig.createAutoConfig( + merchantId, privateKeyPath, merchantSerialNumber, apiV3Key); + + // 测试配置 + boolean testResult = wechatCertAutoConfig.testConfig(config); + + result.put("success", true); + result.put("configCreated", config != null); + result.put("testPassed", testResult); + result.put("message", "自定义证书配置测试完成"); + result.put("merchantId", merchantId); + result.put("privateKeyPath", privateKeyPath); + + log.info("✅ 自定义证书配置测试成功"); + return success("测试成功", result); + + } catch (Exception e) { + log.error("❌ 自定义证书配置测试失败: {}", e.getMessage(), e); + + result.put("success", false); + result.put("error", e.getMessage()); + result.put("message", "证书配置测试失败"); + result.put("troubleshooting", getTroubleshootingInfo()); + + return fail("测试失败: " + e.getMessage(), result); + } + } + + @Operation(summary = "获取使用说明") + @GetMapping("/instructions") + public ApiResult getInstructions() { + String instructions = wechatCertAutoConfig.getUsageInstructions(); + return success("获取使用说明成功", instructions); + } + + @Operation(summary = "获取故障排除信息") + @GetMapping("/troubleshooting") + public ApiResult> getTroubleshooting() { + Map troubleshooting = getTroubleshootingInfo(); + return success("获取故障排除信息成功", troubleshooting); + } + + /** + * 获取故障排除信息 + */ + private Map getTroubleshootingInfo() { + Map info = new HashMap<>(); + + info.put("commonIssues", Map.of( + "404错误", "商户平台未开启API安全功能或未申请使用微信支付公钥", + "证书序列号错误", "请检查商户平台中的证书序列号是否正确", + "APIv3密钥错误", "请确认APIv3密钥是否正确设置", + "私钥文件不存在", "请检查私钥文件路径是否正确", + "网络连接问题", "请检查网络连接是否正常" + )); + + info.put("solutions", Map.of( + "开启API安全", "登录微信商户平台 -> 账户中心 -> API安全 -> 申请使用微信支付公钥", + "获取证书序列号", "在API安全页面查看或重新下载证书", + "设置APIv3密钥", "在API安全页面设置APIv3密钥", + "检查私钥文件", "确保apiclient_key.pem文件存在且路径正确" + )); + + info.put("advantages", Map.of( + "自动下载", "RSAAutoCertificateConfig会自动下载平台证书", + "自动更新", "证书过期时会自动更新", + "简化管理", "无需手动管理wechatpay_cert.pem文件", + "官方推荐", "微信支付官方推荐的证书管理方式" + )); + + info.put("documentation", "https://pay.weixin.qq.com/doc/v3/merchant/4012153196"); + + return info; + } + + @Operation(summary = "检查商户平台配置状态") + @PostMapping("/check-merchant-config") + public ApiResult> checkMerchantConfig( + @RequestParam String merchantId, + @RequestParam String privateKeyPath, + @RequestParam String merchantSerialNumber, + @RequestParam String apiV3Key) { + + Map result = new HashMap<>(); + + try { + log.info("开始检查商户平台配置状态..."); + log.info("商户号: {}", merchantId); + + // 尝试创建自动证书配置 + Config config = wechatCertAutoConfig.createAutoConfig( + merchantId, privateKeyPath, merchantSerialNumber, apiV3Key); + + result.put("success", true); + result.put("configCreated", true); + result.put("message", "商户平台配置正常,自动证书配置创建成功"); + result.put("merchantId", merchantId); + result.put("recommendation", "配置正常,可以正常使用微信支付功能"); + + log.info("✅ 商户平台配置检查成功"); + return success("配置检查成功", result); + + } catch (Exception e) { + log.error("❌ 商户平台配置检查失败: {}", e.getMessage(), e); + + result.put("success", false); + result.put("configCreated", false); + result.put("error", e.getMessage()); + result.put("merchantId", merchantId); + + // 分析错误类型并提供解决方案 + if (e.getMessage().contains("404") || e.getMessage().contains("RESOURCE_NOT_EXISTS")) { + result.put("errorType", "商户平台配置问题"); + result.put("solution", "请在微信支付商户平台完成以下配置:\n" + + "1. 登录商户平台:https://pay.weixin.qq.com/\n" + + "2. 进入:产品中心 → 开发配置 → API安全\n" + + "3. 申请API证书\n" + + "4. 申请使用微信支付公钥\n" + + "5. 确保API证书和微信支付公钥状态为\"已生效\""); + result.put("documentUrl", "https://pay.weixin.qq.com/doc/v3/merchant/4012153196"); + } else { + result.put("errorType", "其他配置问题"); + result.put("solution", "请检查商户号、证书序列号、API密钥等配置是否正确"); + } + + return success("配置检查完成(发现问题)", result); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/WechatPayDiagnosticController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/WechatPayDiagnosticController.java new file mode 100644 index 0000000..d621ad1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/controller/WechatPayDiagnosticController.java @@ -0,0 +1,318 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.utils.WechatPayCertificateDiagnostic; +import com.gxwebsoft.common.core.utils.WechatPayConfigChecker; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.system.entity.Payment; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 微信支付诊断控制器 + * 用于诊断和解决微信支付证书相关问题 + * + * @author 科技小王子 + * @since 2025-07-29 + */ +@Slf4j +@RestController +@RequestMapping("/system/wechat-pay-diagnostic") +@Tag(name = "微信支付诊断", description = "微信支付证书诊断和问题排查") +public class WechatPayDiagnosticController extends com.gxwebsoft.common.core.web.BaseController { + + @Autowired + private WechatPayCertificateDiagnostic certificateDiagnostic; + + @Autowired + private com.gxwebsoft.common.core.service.PaymentCacheService paymentCacheService; + + @Autowired + private WechatPayConfigChecker configChecker; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + @Operation(summary = "诊断租户微信支付证书配置") + @GetMapping("/diagnose/{tenantId}") + @PreAuthorize("hasAuthority('system:payment:view')") + public ApiResult> diagnoseTenantCertificate( + @Parameter(description = "租户ID", example = "5") @PathVariable Integer tenantId) { + + try { + log.info("开始诊断租户 {} 的微信支付证书配置", tenantId); + + // 获取支付配置 (微信支付类型为0) + Payment payment = paymentCacheService.getWechatPayConfig(tenantId); + if (payment == null) { + Map errorResponse = new HashMap<>(); + errorResponse.put("tenantId", tenantId); + errorResponse.put("error", "支付配置不存在"); + return fail("租户 " + tenantId + " 的微信支付配置不存在", errorResponse); + } + + // 执行诊断 + WechatPayCertificateDiagnostic.DiagnosticResult result = + certificateDiagnostic.diagnoseCertificateConfig(payment, tenantId, activeProfile); + + Map response = new HashMap<>(); + response.put("tenantId", tenantId); + response.put("environment", activeProfile); + response.put("hasErrors", result.hasErrors()); + response.put("errors", result.getErrors()); + response.put("warnings", result.getWarnings()); + response.put("info", result.getInfo()); + response.put("recommendations", result.getRecommendations()); + response.put("fullReport", result.getFullReport()); + + if (result.hasErrors()) { + return fail("诊断发现问题", response); + } else { + return success("诊断完成", response); + } + + } catch (Exception e) { + log.error("诊断租户 {} 证书配置时发生异常", tenantId, e); + Map errorResponse = new HashMap<>(); + errorResponse.put("tenantId", tenantId); + errorResponse.put("exception", e.getMessage()); + return fail("诊断过程中发生异常: " + e.getMessage(), errorResponse); + } + } + + @Operation(summary = "获取证书问题解决方案") + @GetMapping("/solutions") + @PreAuthorize("hasAuthority('system:payment:view')") + public ApiResult> getCertificateSolutions() { + Map solutions = new HashMap<>(); + + solutions.put("commonIssues", Map.of( + "X509Certificate.getSerialNumber() null", "证书对象为空,通常是自动证书配置失败导致", + "404错误", "商户平台未开启API安全功能或未申请使用微信支付公钥", + "证书序列号错误", "请检查商户平台中的证书序列号是否正确", + "APIv3密钥错误", "请确认APIv3密钥是否正确设置", + "私钥文件不存在", "请检查私钥文件路径是否正确", + "网络连接问题", "请检查网络连接是否正常" + )); + + solutions.put("stepByStepSolutions", Map.of( + "开启API安全", "登录微信商户平台 -> 账户中心 -> API安全 -> 申请使用微信支付公钥", + "获取证书序列号", "在API安全页面查看或重新下载证书", + "设置APIv3密钥", "在API安全页面设置APIv3密钥(32位字符串)", + "检查私钥文件", "确保apiclient_key.pem文件存在且路径正确", + "使用自动证书配置", "推荐使用RSAAutoCertificateConfig,可自动管理平台证书" + )); + + solutions.put("configurationAdvice", Map.of( + "开发环境", "证书文件放在 src/main/resources/dev/wechat/{tenantId}/ 目录下", + "生产环境", "证书文件放在 Docker 挂载卷或指定的文件系统路径", + "证书文件要求", "需要 apiclient_key.pem(私钥)和 apiclient_cert.pem(商户证书)", + "自动配置优势", "无需手动管理微信支付平台证书,自动下载和更新" + )); + + solutions.put("troubleshootingSteps", new String[]{ + "1. 检查商户平台是否已开启API安全功能", + "2. 确认已申请使用微信支付公钥", + "3. 验证商户证书序列号是否正确", + "4. 检查APIv3密钥是否为32位字符串", + "5. 确认私钥文件路径正确且文件存在", + "6. 测试网络连接是否正常", + "7. 查看详细错误日志进行进一步诊断" + }); + + return success("获取解决方案成功", solutions); + } + + @Operation(summary = "测试证书配置") + @PostMapping("/test/{tenantId}") + @PreAuthorize("hasAuthority('system:payment:edit')") + public ApiResult> testCertificateConfig( + @Parameter(description = "租户ID", example = "5") @PathVariable Integer tenantId) { + + try { + log.info("开始测试租户 {} 的证书配置", tenantId); + + // 获取支付配置 (微信支付类型为0) + Payment payment = paymentCacheService.getWechatPayConfig(tenantId); + if (payment == null) { + Map errorResponse = new HashMap<>(); + errorResponse.put("tenantId", tenantId); + errorResponse.put("error", "支付配置不存在"); + return fail("租户 " + tenantId + " 的微信支付配置不存在", errorResponse); + } + + // 执行诊断 + WechatPayCertificateDiagnostic.DiagnosticResult result = + certificateDiagnostic.diagnoseCertificateConfig(payment, tenantId, activeProfile); + + Map testResult = new HashMap<>(); + testResult.put("tenantId", tenantId); + testResult.put("configurationValid", !result.hasErrors()); + testResult.put("testTime", System.currentTimeMillis()); + testResult.put("environment", activeProfile); + + if (result.hasErrors()) { + testResult.put("status", "FAILED"); + testResult.put("errors", result.getErrors()); + testResult.put("recommendations", result.getRecommendations()); + return fail("证书配置测试失败", testResult); + } else { + testResult.put("status", "SUCCESS"); + testResult.put("message", "证书配置正常"); + return success("证书配置测试通过", testResult); + } + + } catch (Exception e) { + log.error("测试租户 {} 证书配置时发生异常", tenantId, e); + Map errorResponse = new HashMap<>(); + errorResponse.put("tenantId", tenantId); + errorResponse.put("exception", e.getMessage()); + return fail("测试过程中发生异常: " + e.getMessage(), errorResponse); + } + } + + @Operation(summary = "获取环境信息") + @GetMapping("/environment") + @PreAuthorize("hasAuthority('system:payment:view')") + public ApiResult> getEnvironmentInfo() { + Map envInfo = new HashMap<>(); + envInfo.put("activeProfile", activeProfile); + envInfo.put("javaVersion", System.getProperty("java.version")); + envInfo.put("osName", System.getProperty("os.name")); + envInfo.put("userDir", System.getProperty("user.dir")); + envInfo.put("timestamp", System.currentTimeMillis()); + + return success("获取环境信息成功", envInfo); + } + + @Operation(summary = "获取证书配置指南") + @GetMapping("/guide") + public ApiResult> getCertificateGuide() { + Map guide = new HashMap<>(); + + guide.put("overview", "微信支付证书配置完整指南"); + + guide.put("prerequisites", new String[]{ + "1. 拥有微信支付商户账号", + "2. 已完成商户入驻和资质审核", + "3. 具备开发者权限" + }); + + guide.put("merchantPlatformSteps", new String[]{ + "1. 登录微信商户平台 (pay.weixin.qq.com)", + "2. 进入【账户中心】->【API安全】", + "3. 点击【申请使用微信支付公钥】", + "4. 下载商户证书(apiclient_cert.pem 和 apiclient_key.pem)", + "5. 设置APIv3密钥(32位字符串)", + "6. 记录商户证书序列号" + }); + + guide.put("developmentSetup", new String[]{ + "1. 在项目中创建证书目录:src/main/resources/dev/wechat/{tenantId}/", + "2. 将 apiclient_key.pem 放入该目录", + "3. 将 apiclient_cert.pem 放入该目录(可选,自动配置不需要)", + "4. 在数据库中配置支付信息:商户号、应用ID、证书序列号、APIv3密钥" + }); + + guide.put("productionSetup", new String[]{ + "1. 将证书文件上传到服务器指定目录", + "2. 确保应用有读取证书文件的权限", + "3. 在数据库中配置正确的证书文件路径", + "4. 测试证书配置是否正常" + }); + + guide.put("bestPractices", new String[]{ + "1. 使用RSAAutoCertificateConfig自动证书配置", + "2. 定期检查证书有效期", + "3. 妥善保管私钥文件", + "4. 使用HTTPS传输敏感信息", + "5. 定期更新微信支付SDK版本" + }); + + return success("获取配置指南成功", guide); + } + + @Operation(summary = "快速检查租户配置状态") + @GetMapping("/check/{tenantId}") + @PreAuthorize("hasAuthority('system:payment:view')") + public ApiResult> quickCheckConfig( + @Parameter(description = "租户ID", example = "10547") @PathVariable Integer tenantId) { + + try { + log.info("快速检查租户 {} 的配置状态", tenantId); + + WechatPayConfigChecker.ConfigStatus status = configChecker.checkTenantConfig(tenantId); + + Map response = new HashMap<>(); + response.put("tenantId", status.tenantId); + response.put("environment", status.environment); + response.put("configMode", status.configMode); + response.put("configComplete", status.configComplete); + response.put("hasError", status.hasError); + response.put("errorMessage", status.errorMessage); + response.put("recommendation", status.recommendation); + response.put("issues", status.issues); + + // 详细配置信息 + Map configDetails = new HashMap<>(); + configDetails.put("merchantId", status.merchantId); + configDetails.put("appId", status.appId); + configDetails.put("serialNumber", status.serialNumber); + configDetails.put("hasApiKey", status.hasApiKey); + configDetails.put("apiKeyLength", status.apiKeyLength); + configDetails.put("hasPublicKey", status.hasPublicKey); + configDetails.put("publicKeyFile", status.publicKeyFile); + configDetails.put("publicKeyId", status.publicKeyId); + configDetails.put("publicKeyExists", status.publicKeyExists); + configDetails.put("privateKeyExists", status.privateKeyExists); + configDetails.put("merchantCertExists", status.merchantCertExists); + response.put("configDetails", configDetails); + + if (status.hasError || !status.configComplete) { + return fail("配置检查发现问题", response); + } else { + return success("配置检查通过", response); + } + + } catch (Exception e) { + log.error("检查租户 {} 配置状态时发生异常", tenantId, e); + Map errorResponse = new HashMap<>(); + errorResponse.put("tenantId", tenantId); + errorResponse.put("exception", e.getMessage()); + return fail("检查过程中发生异常: " + e.getMessage(), errorResponse); + } + } + + @Operation(summary = "获取配置建议") + @GetMapping("/advice/{tenantId}") + @PreAuthorize("hasAuthority('system:payment:view')") + public ApiResult> getConfigAdvice( + @Parameter(description = "租户ID", example = "10547") @PathVariable Integer tenantId) { + + try { + String advice = configChecker.generateConfigAdvice(tenantId); + + Map response = new HashMap<>(); + response.put("tenantId", tenantId); + response.put("advice", advice); + response.put("timestamp", System.currentTimeMillis()); + + return success("获取配置建议成功", response); + + } catch (Exception e) { + log.error("获取租户 {} 配置建议时发生异常", tenantId, e); + Map errorResponse = new HashMap<>(); + errorResponse.put("tenantId", tenantId); + errorResponse.put("exception", e.getMessage()); + return fail("获取建议过程中发生异常: " + e.getMessage(), errorResponse); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/CreateBusinessEncryptedQrCodeRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/CreateBusinessEncryptedQrCodeRequest.java new file mode 100644 index 0000000..bae53d8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/CreateBusinessEncryptedQrCodeRequest.java @@ -0,0 +1,114 @@ +package com.gxwebsoft.common.core.dto.qr; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.*; + +/** + * 创建业务加密二维码请求DTO + * + * @author WebSoft + * @since 2025-08-18 + */ +@Schema(description = "创建业务加密二维码请求") +public class CreateBusinessEncryptedQrCodeRequest { + + @Schema(description = "要加密的数据", required = true, example = "订单ID:ORDER123") + @NotBlank(message = "数据不能为空") + private String data; + + @Schema(description = "业务密钥(如门店密钥)", required = true, example = "store_key_123") + @NotBlank(message = "业务密钥不能为空") + private String businessKey; + + @Schema(description = "二维码宽度", example = "200") + @Min(value = 50, message = "宽度不能小于50像素") + @Max(value = 1000, message = "宽度不能大于1000像素") + private Integer width = 200; + + @Schema(description = "二维码高度", example = "200") + @Min(value = 50, message = "高度不能小于50像素") + @Max(value = 1000, message = "高度不能大于1000像素") + private Integer height = 200; + + @Schema(description = "过期时间(分钟)", example = "30") + @Min(value = 1, message = "过期时间不能小于1分钟") + @Max(value = 1440, message = "过期时间不能大于1440分钟") + private Long expireMinutes = 30L; + + @Schema(description = "业务类型(可选)", example = "ORDER") + private String businessType; + + // 构造函数 + public CreateBusinessEncryptedQrCodeRequest() {} + + public CreateBusinessEncryptedQrCodeRequest(String data, String businessKey, Integer width, Integer height, Long expireMinutes, String businessType) { + this.data = data; + this.businessKey = businessKey; + this.width = width; + this.height = height; + this.expireMinutes = expireMinutes; + this.businessType = businessType; + } + + // Getter和Setter方法 + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getBusinessKey() { + return businessKey; + } + + public void setBusinessKey(String businessKey) { + this.businessKey = businessKey; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + + public Integer getHeight() { + return height; + } + + public void setHeight(Integer height) { + this.height = height; + } + + public Long getExpireMinutes() { + return expireMinutes; + } + + public void setExpireMinutes(Long expireMinutes) { + this.expireMinutes = expireMinutes; + } + + public String getBusinessType() { + return businessType; + } + + public void setBusinessType(String businessType) { + this.businessType = businessType; + } + + @Override + public String toString() { + return "CreateBusinessEncryptedQrCodeRequest{" + + "data='" + data + '\'' + + ", businessKey='" + businessKey + '\'' + + ", width=" + width + + ", height=" + height + + ", expireMinutes=" + expireMinutes + + ", businessType='" + businessType + '\'' + + '}'; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/CreateEncryptedQrCodeRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/CreateEncryptedQrCodeRequest.java new file mode 100644 index 0000000..f81c9d1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/CreateEncryptedQrCodeRequest.java @@ -0,0 +1,100 @@ +package com.gxwebsoft.common.core.dto.qr; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.*; + +/** + * 创建加密二维码请求DTO + * + * @author WebSoft + * @since 2025-08-18 + */ +@Schema(description = "创建加密二维码请求") +public class CreateEncryptedQrCodeRequest { + + @Schema(description = "要加密的数据", required = true, example = "用户ID:12345") + @NotBlank(message = "数据不能为空") + private String data; + + @Schema(description = "二维码宽度", example = "200") + @Min(value = 50, message = "宽度不能小于50像素") + @Max(value = 1000, message = "宽度不能大于1000像素") + private Integer width = 200; + + @Schema(description = "二维码高度", example = "200") + @Min(value = 50, message = "高度不能小于50像素") + @Max(value = 1000, message = "高度不能大于1000像素") + private Integer height = 200; + + @Schema(description = "过期时间(分钟)", example = "30") + @Min(value = 1, message = "过期时间不能小于1分钟") + @Max(value = 1440, message = "过期时间不能大于1440分钟") + private Long expireMinutes = 30L; + + @Schema(description = "业务类型(可选)", example = "LOGIN") + private String businessType; + + // 构造函数 + public CreateEncryptedQrCodeRequest() {} + + public CreateEncryptedQrCodeRequest(String data, Integer width, Integer height, Long expireMinutes, String businessType) { + this.data = data; + this.width = width; + this.height = height; + this.expireMinutes = expireMinutes; + this.businessType = businessType; + } + + // Getter和Setter方法 + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + + public Integer getHeight() { + return height; + } + + public void setHeight(Integer height) { + this.height = height; + } + + public Long getExpireMinutes() { + return expireMinutes; + } + + public void setExpireMinutes(Long expireMinutes) { + this.expireMinutes = expireMinutes; + } + + public String getBusinessType() { + return businessType; + } + + public void setBusinessType(String businessType) { + this.businessType = businessType; + } + + @Override + public String toString() { + return "CreateEncryptedQrCodeRequest{" + + "data='" + data + '\'' + + ", width=" + width + + ", height=" + height + + ", expireMinutes=" + expireMinutes + + ", businessType='" + businessType + '\'' + + '}'; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/DecryptQrDataRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/DecryptQrDataRequest.java new file mode 100644 index 0000000..3d35550 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/DecryptQrDataRequest.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.core.dto.qr; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.NotBlank; + +/** + * 解密二维码数据请求DTO + * + * @author WebSoft + * @since 2025-08-18 + */ +@Schema(description = "解密二维码数据请求") +public class DecryptQrDataRequest { + + @Schema(description = "token密钥", required = true, example = "abc123def456") + @NotBlank(message = "token不能为空") + private String token; + + @Schema(description = "加密的数据", required = true, example = "encrypted_data_string") + @NotBlank(message = "加密数据不能为空") + private String encryptedData; + + // 构造函数 + public DecryptQrDataRequest() {} + + public DecryptQrDataRequest(String token, String encryptedData) { + this.token = token; + this.encryptedData = encryptedData; + } + + // Getter和Setter方法 + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getEncryptedData() { + return encryptedData; + } + + public void setEncryptedData(String encryptedData) { + this.encryptedData = encryptedData; + } + + @Override + public String toString() { + return "DecryptQrDataRequest{" + + "token='" + token + '\'' + + ", encryptedData='" + encryptedData + '\'' + + '}'; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/InvalidateTokenRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/InvalidateTokenRequest.java new file mode 100644 index 0000000..1e8aa67 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/InvalidateTokenRequest.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.core.dto.qr; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.NotBlank; + +/** + * 使token失效请求DTO + * + * @author WebSoft + * @since 2025-08-18 + */ +@Schema(description = "使token失效请求") +public class InvalidateTokenRequest { + + @Schema(description = "要使失效的token", required = true, example = "abc123def456") + @NotBlank(message = "token不能为空") + private String token; + + // 构造函数 + public InvalidateTokenRequest() {} + + public InvalidateTokenRequest(String token) { + this.token = token; + } + + // Getter和Setter方法 + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public String toString() { + return "InvalidateTokenRequest{" + + "token='" + token + '\'' + + '}'; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/VerifyBusinessQrRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/VerifyBusinessQrRequest.java new file mode 100644 index 0000000..fbdfe3a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/VerifyBusinessQrRequest.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.core.dto.qr; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.NotBlank; + +/** + * 门店核销二维码请求DTO + * + * @author WebSoft + * @since 2025-08-18 + */ +@Schema(description = "门店核销二维码请求") +public class VerifyBusinessQrRequest { + + @Schema(description = "二维码扫描得到的完整内容", required = true, example = "qr_content_string") + @NotBlank(message = "二维码内容不能为空") + private String qrContent; + + @Schema(description = "门店业务密钥", required = true, example = "store_key_123") + @NotBlank(message = "业务密钥不能为空") + private String businessKey; + + // 构造函数 + public VerifyBusinessQrRequest() {} + + public VerifyBusinessQrRequest(String qrContent, String businessKey) { + this.qrContent = qrContent; + this.businessKey = businessKey; + } + + // Getter和Setter方法 + public String getQrContent() { + return qrContent; + } + + public void setQrContent(String qrContent) { + this.qrContent = qrContent; + } + + public String getBusinessKey() { + return businessKey; + } + + public void setBusinessKey(String businessKey) { + this.businessKey = businessKey; + } + + @Override + public String toString() { + return "VerifyBusinessQrRequest{" + + "qrContent='" + qrContent + '\'' + + ", businessKey='" + businessKey + '\'' + + '}'; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/VerifyQrContentRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/VerifyQrContentRequest.java new file mode 100644 index 0000000..eb60b09 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/dto/qr/VerifyQrContentRequest.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.core.dto.qr; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.NotBlank; + +/** + * 验证二维码内容请求DTO + * + * @author WebSoft + * @since 2025-08-18 + */ +@Schema(description = "验证二维码内容请求") +public class VerifyQrContentRequest { + + @Schema(description = "二维码扫描得到的完整内容", required = true, example = "qr_content_string") + @NotBlank(message = "二维码内容不能为空") + private String qrContent; + + // 构造函数 + public VerifyQrContentRequest() {} + + public VerifyQrContentRequest(String qrContent) { + this.qrContent = qrContent; + } + + // Getter和Setter方法 + public String getQrContent() { + return qrContent; + } + + public void setQrContent(String qrContent) { + this.qrContent = qrContent; + } + + @Override + public String toString() { + return "VerifyQrContentRequest{" + + "qrContent='" + qrContent + '\'' + + '}'; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/enums/ChatMessageType.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/enums/ChatMessageType.java new file mode 100644 index 0000000..9ebb38e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/enums/ChatMessageType.java @@ -0,0 +1,25 @@ +package com.gxwebsoft.common.core.enums; + +public enum ChatMessageType { + TEXT( 1, "text"), + IMAGE(2, "image"), + VOICE(3, "voice"), + CARD(4, "card"), + ; + + private int index; + + private String name; + ChatMessageType(int i, String text) { + this.name = text; + this.index = i; + } + + public String getName() { + return name; + } + + public int getIndex() { + return index; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/enums/GreenWebType.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/enums/GreenWebType.java new file mode 100644 index 0000000..d9a0a5f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/enums/GreenWebType.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.core.enums; + +public enum GreenWebType { + /** + * 用户昵称 + */ + nickname_detection, + /** + * 聊天互动 + */ + chat_detection, + /** + * 动态评论 + */ + comment_detection, + /** + * 教学无聊 + */ + pgc_detection, + /** + * 图片检测service: baselineCheck通用基线检测 + */ + baselineCheck, + /** + * 视频检测 + */ + videoDetection; + + public enum ChatMessageType { + TEXT( 1, "text"), + IMAGE(2, "image"), + VOICE(3, "voice"), + CARD(4, "card"), + ; + + private int index; + + private String name; + ChatMessageType(int i, String text) { + this.name = text; + this.index = i; + } + + public String getName() { + return name; + } + + public int getIndex() { + return index; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/exception/BusinessException.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/exception/BusinessException.java new file mode 100644 index 0000000..8e10e82 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/exception/BusinessException.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.core.exception; + +import com.gxwebsoft.common.core.Constants; + +/** + * 自定义业务异常 + * + * @author WebSoft + * @since 2018-02-22 11:29:28 + */ +public class BusinessException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private Integer code; + + public BusinessException() { + this(Constants.RESULT_ERROR_MSG); + } + + public BusinessException(String message) { + this(Constants.RESULT_ERROR_CODE, message); + } + + public BusinessException(Integer code, String message) { + super(message); + this.code = code; + } + + public BusinessException(Integer code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public BusinessException(Integer code, String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + this.code = code; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/exception/GlobalExceptionHandler.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..7fb4c8c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/exception/GlobalExceptionHandler.java @@ -0,0 +1,89 @@ +package com.gxwebsoft.common.core.exception; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.Set; + +/** + * 全局异常处理器 + * + * @author WebSoft + * @since 2018-02-22 11:29:30 + */ +@ControllerAdvice +public class GlobalExceptionHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @ResponseBody + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ApiResult methodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e, + HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(Constants.RESULT_ERROR_CODE, "请求方式不正确").setError(e.toString()); + } + + @ResponseBody + @ExceptionHandler(AccessDeniedException.class) + public ApiResult accessDeniedExceptionHandler(AccessDeniedException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(Constants.UNAUTHORIZED_CODE, Constants.UNAUTHORIZED_MSG).setError(e.toString()); + } + + @ResponseBody + @ExceptionHandler(BusinessException.class) + public ApiResult businessExceptionHandler(BusinessException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(e.getCode(), e.getMessage()); + } + + @ResponseBody + @ExceptionHandler(MethodArgumentNotValidException.class) + public ApiResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + FieldError fieldError = e.getBindingResult().getFieldError(); + String message = fieldError != null ? fieldError.getDefaultMessage() : "参数验证失败"; + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message); + } + + @ResponseBody + @ExceptionHandler(BindException.class) + public ApiResult bindExceptionHandler(BindException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + FieldError fieldError = e.getBindingResult().getFieldError(); + String message = fieldError != null ? fieldError.getDefaultMessage() : "参数绑定失败"; + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message); + } + + @ResponseBody + @ExceptionHandler(ConstraintViolationException.class) + public ApiResult constraintViolationExceptionHandler(ConstraintViolationException e, HttpServletResponse response) { + CommonUtil.addCrossHeaders(response); + Set> violations = e.getConstraintViolations(); + String message = violations.isEmpty() ? "参数验证失败" : violations.iterator().next().getMessage(); + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message); + } + + @ResponseBody + @ExceptionHandler(Throwable.class) + public ApiResult exceptionHandler(Throwable e, HttpServletResponse response) { + logger.error(e.getMessage(), e); + CommonUtil.addCrossHeaders(response); + return new ApiResult<>(Constants.RESULT_ERROR_CODE, Constants.RESULT_ERROR_MSG).setError(e.toString()); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAccessDeniedHandler.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..66acb5c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAccessDeniedHandler.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.core.security; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.CommonUtil; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 没有访问权限异常处理 + * + * @author WebSoft + * @since 2020-03-25 00:35:03 + */ +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) + throws IOException, ServletException { + CommonUtil.responseError(response, Constants.UNAUTHORIZED_CODE, Constants.UNAUTHORIZED_MSG, e.getMessage()); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationEntryPoint.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..3be2908 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.core.security; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.CommonUtil; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 没有登录异常处理 + * + * @author WebSoft + * @since 2020-03-25 00:35:03 + */ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) + throws IOException, ServletException { +// CommonUtil.responseError(response, Constants.UNAUTHENTICATED_CODE, Constants.UNAUTHENTICATED_MSG, +// e.getMessage()); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..e910c6d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java @@ -0,0 +1,118 @@ +package com.gxwebsoft.common.core.security; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.SignCheckUtil; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.User; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.Resource; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 处理携带token的请求过滤器 + * + * @author WebSoft + * @since 2020-03-30 20:48:05 + */ +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + @Resource + private ConfigProperties configProperties; + @Value("${spring.profiles.active}") + String active; + @Resource + private RedisUtil redisUtil; + // 是否读取用户信息 + public static Boolean isReadUserInfo = true; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + String access_token = JwtUtil.getAccessToken(request); + if (StrUtil.isNotBlank(access_token)) { + try { + // 解析token + Claims claims = JwtUtil.parseToken(access_token, configProperties.getTokenKey()); + JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims); + + // 请求主服务器获取用户信息 + if (isReadUserInfo) { + HashMap map = new HashMap<>(); + map.put("username", jwtSubject.getUsername()); + map.put("tenantId", jwtSubject.getTenantId()); + // 链式构建请求 + String result = HttpRequest.post(configProperties.getServerUrl() + "/auth/user") + .header("Authorization", access_token) + .header("Tenantid", jwtSubject.getTenantId().toString()) + .body(JSONUtil.toJSONString(map))//表单内容 + .timeout(20000)//超时,毫秒 + .execute().body(); + + // 校验服务器域名白名单 + final SignCheckUtil checkUtil = new SignCheckUtil(); + String key = "WhiteDomain:" + jwtSubject.getTenantId(); + List whiteDomains = redisUtil.get(key, List.class); + // 生产环境 + if (active.equals("prod") && !checkUtil.checkWhiteDomains(whiteDomains, request.getServerName())) { + throw new UsernameNotFoundException("The requested domain name is not on the whitelist"); + } + + JSONObject jsonObject = JSONObject.parseObject(result); + if(jsonObject.getString("code").equals("401")){ + throw new UsernameNotFoundException("Username not found"); + } + final String data = jsonObject.getString("data"); + final User user = JSONObject.parseObject(data, User.class); + List

authorities = user.getAuthorities().stream() + .filter(m -> StrUtil.isNotBlank(m.getAuthority())).collect(Collectors.toList()); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + user, null, authorities); + SecurityContextHolder.getContext().setAuthentication(authentication); + + // token将要过期签发新token, 防止突然退出登录 +// long expiration = (claims.getExpiration().getTime() - new Date().getTime()) / 1000 / 60; +// if (expiration < configProperties.getTokenRefreshTime()) { +// String token = JwtUtil.buildToken(jwtSubject, configProperties.getTokenExpireTime(), +// configProperties.getTokenKey()); +// response.addHeader(Constants.TOKEN_HEADER_NAME, token); +// loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_REFRESH, null, +// user.getTenantId(), request); +// } + + } + } catch (ExpiredJwtException e) { + CommonUtil.responseError(response, Constants.TOKEN_EXPIRED_CODE, Constants.TOKEN_EXPIRED_MSG, + e.getMessage()); + return; + } catch (Exception e) { + CommonUtil.responseError(response, Constants.BAD_CREDENTIALS_CODE, Constants.BAD_CREDENTIALS_MSG, + e.toString()); + return; + } + } + chain.doFilter(request, response); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtSubject.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtSubject.java new file mode 100644 index 0000000..1a0ff7d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtSubject.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.core.security; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * Jwt载体 + * + * @author WebSoft + * @since 2021-09-03 00:11:12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class JwtSubject implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 账号 + */ + private String username; + + /** + * 租户id + */ + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtUtil.java new file mode 100644 index 0000000..2f05d23 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/JwtUtil.java @@ -0,0 +1,141 @@ +package com.gxwebsoft.common.core.security; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.ServletUtil; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.utils.JSONUtil; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.io.Encoders; +import io.jsonwebtoken.security.Keys; + +import javax.servlet.http.HttpServletRequest; +import java.security.Key; +import java.util.Date; + +/** + * JWT工具类 + * + * @author WebSoft + * @since 2018-01-21 16:30:59 + */ +public class JwtUtil { + + /** + * 获取请求中的access_token + * + * @param request HttpServletRequest + * @return String + */ + public static String getAccessToken(HttpServletRequest request) { + String access_token = ServletUtil.getHeaderIgnoreCase(request, Constants.TOKEN_HEADER_NAME); + if (StrUtil.isNotBlank(access_token)) { + if (access_token.startsWith(Constants.TOKEN_TYPE)) { + access_token = StrUtil.removePrefix(access_token, Constants.TOKEN_TYPE).trim(); + } + } else { + access_token = request.getParameter(Constants.TOKEN_PARAM_NAME); + } + return access_token; + } + + /** + * 生成token + * + * @param subject 载体 + * @param expire 过期时间 + * @param base64EncodedKey base64编码的Key + * @return token + */ + public static String buildToken(JwtSubject subject, Long expire, String base64EncodedKey) { + return buildToken(JSONUtil.toJSONString(subject), expire, decodeKey(base64EncodedKey)); + } + + /** + * 生成token + * + * @param subject 载体 + * @param expire 过期时间 + * @param key 密钥 + * @return token + */ + public static String buildToken(String subject, Long expire, Key key) { + Date expireDate = new Date(new Date().getTime() + 1000 * expire); + return Jwts.builder() + .setSubject(subject) + .setExpiration(expireDate) + .setIssuedAt(new Date()) + .signWith(key) + .compact(); + } + + /** + * 解析token + * + * @param token token + * @param base64EncodedKey base64编码的Key + * @return Claims + */ + public static Claims parseToken(String token, String base64EncodedKey) { + return parseToken(token, decodeKey(base64EncodedKey)); + } + + /** + * 解析token + * + * @param token token + * @param key 密钥 + * @return Claims + */ + public static Claims parseToken(String token, Key key) { + return Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + } + + /** + * 获取JwtSubject + * + * @param claims Claims + * @return JwtSubject + */ + public static JwtSubject getJwtSubject(Claims claims) { + return JSONUtil.parseObject(claims.getSubject(), JwtSubject.class); + } + + /** + * 生成Key + * + * @return Key + */ + public static Key randomKey() { + return Keys.secretKeyFor(SignatureAlgorithm.HS256); + } + + /** + * base64编码key + * + * @return String + */ + public static String encodeKey(Key key) { + return Encoders.BASE64.encode(key.getEncoded()); + } + + /** + * base64编码Key + * + * @param base64EncodedKey base64编码的key + * @return Key + */ + public static Key decodeKey(String base64EncodedKey) { + if (StrUtil.isBlank(base64EncodedKey)) { + return null; + } + return Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64EncodedKey)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java new file mode 100644 index 0000000..f2b1143 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java @@ -0,0 +1,116 @@ +package com.gxwebsoft.common.core.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import javax.annotation.Resource; + +/** + * Spring Security配置 + * + * @author WebSoft + * @since 2020-03-23 18:04:52 + */ +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig { + @Resource + private JwtAccessDeniedHandler jwtAccessDeniedHandler; + @Resource + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + @Resource + private JwtAuthenticationFilter jwtAuthenticationFilter; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http.authorizeRequests() + .antMatchers(HttpMethod.OPTIONS, "/**") + .permitAll() + .antMatchers(HttpMethod.GET, "/api/file/**", "/**", "/api/captcha", "/") + .permitAll() + .antMatchers( + "/api/login", + "/api/login-without-tenant", + "/api/register", + "/api/cms/website/createWebsite", + "/druid/**", + "/swagger-ui.html", + "/swagger-resources/**", + "/webjars/**", + "/v2/api-docs", + "/v3/api-docs", + "/swagger-ui/**", + "/doc.html", + "/api/open/**", + "/hxz/v1/**", + "/api/sendSmsCaptcha", + "/api/login-alipay/*", + "/api/wx-login/loginByMpWxPhone", + "/api/shop/payment/mp-alipay/notify", + "/api/shop/payment/mp-alipay/test/**", + "/api/shop/payment/mp-alipay/getPhoneNumber", + "/api/cms/cms-order/**", + "/api/shop/shop-order/notify/**", + "/api/mp/mp/component_verify_ticket", + "/api/mp/mp/callback", + "/api/shop/test/**", + "/api/test/payment-debug/**", + "/api/shop/wx-login/**", + "/api/shop/wx-native-pay/**", + "/api/shop/wx-pay/**", + "/api/bszx/bszx-pay/notify/**", + "/api/wxWorkQrConnect", + "/WW_verify_QMv7HoblYU6z63bb.txt", + "/5zbYEPkyV4.txt", + "/api/love/user-plan-log/wx-pay/**", + "/api/cms/form-record", + "/api/shop/merchant-account/getMerchantAccountByPhone", + "/api/hjm/hjm-car/**", + "/api/chat/**", + "/api/shop/getShopInfo", + "/api/shop/shop-order/test", + "/api/qr-code/**", + "/api/shop/order-delivery/notify", + "/api/_app/developer/invite/**", + "/api/app/user-sync/**" + ) + .permitAll() + .anyRequest() + .authenticated() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .csrf() + .disable() + .cors() + .and() + .logout() + .disable() + .headers() + .frameOptions() + .disable() + .and() + .exceptionHandling() + .accessDeniedHandler(jwtAccessDeniedHandler) + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + .and() + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) + .build(); + } + + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + return new BCryptPasswordEncoder(); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/CertificateHealthService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/CertificateHealthService.java new file mode 100644 index 0000000..e37bb05 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/CertificateHealthService.java @@ -0,0 +1,253 @@ +package com.gxwebsoft.common.core.service; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 证书健康检查服务 + * 提供证书状态检查和健康监控功能 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@Service +public class CertificateHealthService { + + private final CertificateService certificateService; + private final CertificateProperties certificateProperties; + + public CertificateHealthService(CertificateService certificateService, + CertificateProperties certificateProperties) { + this.certificateService = certificateService; + this.certificateProperties = certificateProperties; + } + + /** + * 自定义健康检查结果类 + */ + public static class HealthResult { + private final String status; + private final Map details; + + public HealthResult(String status, Map details) { + this.status = status; + this.details = details; + } + + public String getStatus() { + return status; + } + + public Map getDetails() { + return details; + } + + public static HealthResult up(Map details) { + return new HealthResult("UP", details); + } + + public static HealthResult down(Map details) { + return new HealthResult("DOWN", details); + } + } + + public HealthResult health() { + try { + Map details = new HashMap<>(); + boolean allHealthy = true; + + // 检查微信支付证书 + Map wechatHealth = checkWechatPayCertificates(); + details.put("wechatPay", wechatHealth); + if (!(Boolean) wechatHealth.get("healthy")) { + allHealthy = false; + } + + // 检查支付宝证书 + Map alipayHealth = checkAlipayCertificates(); + details.put("alipay", alipayHealth); + if (!(Boolean) alipayHealth.get("healthy")) { + allHealthy = false; + } + + // 添加系统信息 + details.put("loadMode", certificateProperties.getLoadMode()); + details.put("certRootPath", certificateProperties.getCertRootPath()); + + if (allHealthy) { + return HealthResult.up(details); + } else { + return HealthResult.down(details); + } + + } catch (Exception e) { + log.error("证书健康检查失败", e); + Map errorDetails = new HashMap<>(); + errorDetails.put("error", e.getMessage()); + return HealthResult.down(errorDetails); + } + } + + /** + * 检查微信支付证书健康状态 + */ + private Map checkWechatPayCertificates() { + Map health = new HashMap<>(); + boolean healthy = true; + Map certificates = new HashMap<>(); + + CertificateProperties.WechatPayConfig wechatConfig = certificateProperties.getWechatPay(); + + // 检查私钥证书 + String privateKeyFile = wechatConfig.getDev().getPrivateKeyFile(); + boolean privateKeyExists = certificateService.certificateExists("wechat", privateKeyFile); + certificates.put("privateKey", Map.of( + "file", privateKeyFile, + "exists", privateKeyExists, + "path", certificateService.getWechatPayCertPath(privateKeyFile) + )); + if (!privateKeyExists) healthy = false; + + // 检查商户证书 + String apiclientCertFile = wechatConfig.getDev().getApiclientCertFile(); + boolean apiclientCertExists = certificateService.certificateExists("wechat", apiclientCertFile); + certificates.put("apiclientCert", Map.of( + "file", apiclientCertFile, + "exists", apiclientCertExists, + "path", certificateService.getWechatPayCertPath(apiclientCertFile) + )); + if (!apiclientCertExists) healthy = false; + + // 检查微信支付平台证书 + String wechatpayCertFile = wechatConfig.getDev().getWechatpayCertFile(); + boolean wechatpayCertExists = certificateService.certificateExists("wechat", wechatpayCertFile); + certificates.put("wechatpayCert", Map.of( + "file", wechatpayCertFile, + "exists", wechatpayCertExists, + "path", certificateService.getWechatPayCertPath(wechatpayCertFile) + )); + if (!wechatpayCertExists) healthy = false; + + health.put("healthy", healthy); + health.put("certificates", certificates); + return health; + } + + /** + * 检查支付宝证书健康状态 + */ + private Map checkAlipayCertificates() { + Map health = new HashMap<>(); + boolean healthy = true; + Map certificates = new HashMap<>(); + + CertificateProperties.AlipayConfig alipayConfig = certificateProperties.getAlipay(); + + // 检查应用私钥 + String appPrivateKeyFile = alipayConfig.getAppPrivateKeyFile(); + boolean appPrivateKeyExists = certificateService.certificateExists("alipay", appPrivateKeyFile); + certificates.put("appPrivateKey", Map.of( + "file", appPrivateKeyFile, + "exists", appPrivateKeyExists, + "path", certificateService.getAlipayCertPath(appPrivateKeyFile) + )); + if (!appPrivateKeyExists) healthy = false; + + // 检查应用公钥证书 + String appCertPublicKeyFile = alipayConfig.getAppCertPublicKeyFile(); + boolean appCertExists = certificateService.certificateExists("alipay", appCertPublicKeyFile); + certificates.put("appCertPublicKey", Map.of( + "file", appCertPublicKeyFile, + "exists", appCertExists, + "path", certificateService.getAlipayCertPath(appCertPublicKeyFile) + )); + if (!appCertExists) healthy = false; + + // 检查支付宝公钥证书 + String alipayCertPublicKeyFile = alipayConfig.getAlipayCertPublicKeyFile(); + boolean alipayCertExists = certificateService.certificateExists("alipay", alipayCertPublicKeyFile); + certificates.put("alipayCertPublicKey", Map.of( + "file", alipayCertPublicKeyFile, + "exists", alipayCertExists, + "path", certificateService.getAlipayCertPath(alipayCertPublicKeyFile) + )); + if (!alipayCertExists) healthy = false; + + // 检查支付宝根证书 + String alipayRootCertFile = alipayConfig.getAlipayRootCertFile(); + boolean rootCertExists = certificateService.certificateExists("alipay", alipayRootCertFile); + certificates.put("alipayRootCert", Map.of( + "file", alipayRootCertFile, + "exists", rootCertExists, + "path", certificateService.getAlipayCertPath(alipayRootCertFile) + )); + if (!rootCertExists) healthy = false; + + health.put("healthy", healthy); + health.put("certificates", certificates); + return health; + } + + /** + * 获取详细的证书诊断信息 + */ + public Map getDiagnosticInfo() { + Map diagnostic = new HashMap<>(); + + try { + // 基本系统信息 + diagnostic.put("loadMode", certificateProperties.getLoadMode()); + diagnostic.put("certRootPath", certificateProperties.getCertRootPath()); + diagnostic.put("devCertPath", certificateProperties.getDevCertPath()); + + // 获取所有证书状态 + diagnostic.put("certificateStatus", certificateService.getAllCertificateStatus()); + + // 健康检查结果 + HealthResult health = health(); + diagnostic.put("healthStatus", health.getStatus()); + diagnostic.put("healthDetails", health.getDetails()); + + } catch (Exception e) { + log.error("获取证书诊断信息失败", e); + diagnostic.put("error", e.getMessage()); + } + + return diagnostic; + } + + /** + * 检查特定证书的详细信息 + */ + public Map checkSpecificCertificate(String certType, String fileName) { + Map result = new HashMap<>(); + + try { + boolean exists = certificateService.certificateExists(certType, fileName); + String path = certificateService.getCertificateFilePath(certType, fileName); + + result.put("certType", certType); + result.put("fileName", fileName); + result.put("exists", exists); + result.put("path", path); + + if (exists && (fileName.endsWith(".crt") || fileName.endsWith(".pem"))) { + // 尝试验证证书 + CertificateService.CertificateInfo certInfo = + certificateService.validateX509Certificate(certType, fileName); + result.put("certificateInfo", certInfo); + } + + } catch (Exception e) { + log.error("检查证书失败: {}/{}", certType, fileName, e); + result.put("error", e.getMessage()); + } + + return result; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/CertificateService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/CertificateService.java new file mode 100644 index 0000000..e12854a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/CertificateService.java @@ -0,0 +1,281 @@ +package com.gxwebsoft.common.core.service; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 证书管理服务 + * 负责处理不同环境下的证书加载、验证和管理 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@Service +public class CertificateService { + + private final CertificateProperties certificateProperties; + + public CertificateService(CertificateProperties certificateProperties) { + this.certificateProperties = certificateProperties; + } + + @PostConstruct + public void init() { + log.info("证书服务初始化,当前加载模式: {}", certificateProperties.getLoadMode()); + log.info("证书根路径: {}", certificateProperties.getCertRootPath()); + + // 检查证书目录和文件 + checkCertificateDirectories(); + } + + /** + * 获取证书文件的输入流 + * + * @param certType 证书类型(wechat/alipay) + * @param fileName 文件名 + * @return 输入流 + * @throws IOException 文件读取异常 + */ + public InputStream getCertificateInputStream(String certType, String fileName) throws IOException { + String certPath = certificateProperties.getCertificatePath(certType, fileName); + + if (certificateProperties.isClasspathMode()) { + // 从classpath加载 + Resource resource = new ClassPathResource(certPath); + if (!resource.exists()) { + throw new IOException("证书文件不存在: " + certPath); + } + log.debug("从classpath加载证书: {}", certPath); + return resource.getInputStream(); + } else { + // 从文件系统加载 + File file = new File(certPath); + if (!file.exists()) { + throw new IOException("证书文件不存在: " + certPath); + } + log.debug("从文件系统加载证书: {}", certPath); + return Files.newInputStream(file.toPath()); + } + } + + /** + * 获取证书文件路径 + * + * @param certType 证书类型 + * @param fileName 文件名 + * @return 文件路径 + */ + public String getCertificateFilePath(String certType, String fileName) { + return certificateProperties.getCertificatePath(certType, fileName); + } + + /** + * 检查证书文件是否存在 + * + * @param certType 证书类型 + * @param fileName 文件名 + * @return 是否存在 + */ + public boolean certificateExists(String certType, String fileName) { + try { + String certPath = certificateProperties.getCertificatePath(certType, fileName); + + if (certificateProperties.isClasspathMode()) { + Resource resource = new ClassPathResource(certPath); + return resource.exists(); + } else { + File file = new File(certPath); + return file.exists() && file.isFile(); + } + } catch (Exception e) { + log.error("检查证书文件存在性时出错: {}", e.getMessage()); + return false; + } + } + + /** + * 获取微信支付证书路径 + * + * @param fileName 文件名 + * @return 证书路径 + */ + public String getWechatPayCertPath(String fileName) { + return certificateProperties.getWechatPayCertPath(fileName); + } + + /** + * 获取支付宝证书路径 + * + * @param fileName 文件名 + * @return 证书路径 + */ + public String getAlipayCertPath(String fileName) { + return certificateProperties.getAlipayCertPath(fileName); + } + + /** + * 验证X509证书 + * + * @param certType 证书类型 + * @param fileName 文件名 + * @return 证书信息 + */ + public CertificateInfo validateX509Certificate(String certType, String fileName) { + try (InputStream inputStream = getCertificateInputStream(certType, fileName)) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); + + CertificateInfo info = new CertificateInfo(); + info.setSubject(cert.getSubjectX500Principal().toString()); + info.setIssuer(cert.getIssuerX500Principal().toString()); + info.setNotBefore(convertToLocalDateTime(cert.getNotBefore())); + info.setNotAfter(convertToLocalDateTime(cert.getNotAfter())); + info.setSerialNumber(cert.getSerialNumber().toString()); + info.setValid(isValidDate(cert.getNotBefore(), cert.getNotAfter())); + + return info; + } catch (Exception e) { + log.error("验证证书失败: {}/{}, 错误: {}", certType, fileName, e.getMessage()); + return null; + } + } + + /** + * 检查证书目录结构 + */ + private void checkCertificateDirectories() { + String[] certTypes = {"wechat", "alipay"}; + + for (String certType : certTypes) { + if (!certificateProperties.isClasspathMode()) { + // 检查文件系统目录 + String dirPath = certificateProperties.getCertificatePath(certType, ""); + File dir = new File(dirPath); + if (!dir.exists()) { + log.warn("证书目录不存在: {}", dirPath); + } else { + log.info("证书目录存在: {}", dirPath); + } + } + } + } + + /** + * 获取所有证书状态 + * + * @return 证书状态映射 + */ + public Map getAllCertificateStatus() { + Map status = new HashMap<>(); + + // 微信支付证书状态 + Map wechatStatus = new HashMap<>(); + CertificateProperties.WechatPayConfig wechatConfig = certificateProperties.getWechatPay(); + wechatStatus.put("privateKey", getCertStatus("wechat", wechatConfig.getDev().getPrivateKeyFile())); + wechatStatus.put("apiclientCert", getCertStatus("wechat", wechatConfig.getDev().getApiclientCertFile())); + wechatStatus.put("wechatpayCert", getCertStatus("wechat", wechatConfig.getDev().getWechatpayCertFile())); + status.put("wechat", wechatStatus); + + // 支付宝证书状态 + Map alipayStatus = new HashMap<>(); + CertificateProperties.AlipayConfig alipayConfig = certificateProperties.getAlipay(); + alipayStatus.put("appPrivateKey", getCertStatus("alipay", alipayConfig.getAppPrivateKeyFile())); + alipayStatus.put("appCertPublicKey", getCertStatus("alipay", alipayConfig.getAppCertPublicKeyFile())); + alipayStatus.put("alipayCertPublicKey", getCertStatus("alipay", alipayConfig.getAlipayCertPublicKeyFile())); + alipayStatus.put("alipayRootCert", getCertStatus("alipay", alipayConfig.getAlipayRootCertFile())); + status.put("alipay", alipayStatus); + + // 系统信息 + Map systemInfo = new HashMap<>(); + systemInfo.put("loadMode", certificateProperties.getLoadMode()); + systemInfo.put("certRootPath", certificateProperties.getCertRootPath()); + systemInfo.put("devCertPath", certificateProperties.getDevCertPath()); + status.put("system", systemInfo); + + return status; + } + + /** + * 获取单个证书状态 + */ + private Map getCertStatus(String certType, String fileName) { + Map status = new HashMap<>(); + status.put("fileName", fileName); + status.put("exists", certificateExists(certType, fileName)); + status.put("path", getCertificateFilePath(certType, fileName)); + + // 如果是.crt或.pem文件,尝试验证证书 + if (fileName.endsWith(".crt") || fileName.endsWith(".pem")) { + CertificateInfo certInfo = validateX509Certificate(certType, fileName); + status.put("certificateInfo", certInfo); + } + + return status; + } + + /** + * 检查日期是否有效 + */ + private boolean isValidDate(Date notBefore, Date notAfter) { + Date now = new Date(); + return now.after(notBefore) && now.before(notAfter); + } + + /** + * 将Date转换为LocalDateTime + */ + private LocalDateTime convertToLocalDateTime(Date date) { + if (date == null) { + return null; + } + return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + } + + /** + * 证书信息类 + */ + public static class CertificateInfo { + private String subject; + private String issuer; + private LocalDateTime notBefore; + private LocalDateTime notAfter; + private String serialNumber; + private boolean valid; + + // Getters and Setters + public String getSubject() { return subject; } + public void setSubject(String subject) { this.subject = subject; } + + public String getIssuer() { return issuer; } + public void setIssuer(String issuer) { this.issuer = issuer; } + + public LocalDateTime getNotBefore() { return notBefore; } + public void setNotBefore(LocalDateTime notBefore) { this.notBefore = notBefore; } + + public LocalDateTime getNotAfter() { return notAfter; } + public void setNotAfter(LocalDateTime notAfter) { this.notAfter = notAfter; } + + public String getSerialNumber() { return serialNumber; } + public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; } + + public boolean isValid() { return valid; } + public void setValid(boolean valid) { this.valid = valid; } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/EnvironmentAwarePaymentService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/EnvironmentAwarePaymentService.java new file mode 100644 index 0000000..2155cc9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/EnvironmentAwarePaymentService.java @@ -0,0 +1,143 @@ +package com.gxwebsoft.common.core.service; + +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * 环境感知的支付配置服务 + * 根据不同环境自动切换支付回调地址 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +@Service +public class EnvironmentAwarePaymentService { + + @Autowired + private PaymentCacheService paymentCacheService; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + @Value("${config.server-url:}") + private String serverUrl; + + // 开发环境回调地址配置 + @Value("${payment.dev.notify-url:http://frps-10550.s209.websoft.top/api/shop/shop-order/notify}") + private String devNotifyUrl; + + // 生产环境回调地址配置 + @Value("${payment.prod.notify-url:https://cms-api.websoft.top/api/shop/shop-order/notify}") + private String prodNotifyUrl; + + /** + * 获取环境感知的支付配置 + * 根据当前环境自动调整回调地址 + * + * @param payType 支付类型 + * @param tenantId 租户ID + * @return 支付配置 + */ + public Payment getEnvironmentAwarePaymentConfig(Integer payType, Integer tenantId) { + // 获取原始支付配置 + Payment payment = paymentCacheService.getPaymentConfig(payType, tenantId); + + if (payment == null) { + return null; + } + + // 根据环境调整回调地址 + Payment envPayment = clonePayment(payment); + String notifyUrl = getEnvironmentNotifyUrl(); + + log.info("环境感知支付配置 - 环境: {}, 原始回调: {}, 调整后回调: {}", + activeProfile, payment.getNotifyUrl(), notifyUrl); + + envPayment.setNotifyUrl(notifyUrl); + + return envPayment; + } + + /** + * 根据当前环境获取回调地址 + */ + private String getEnvironmentNotifyUrl() { + if ("dev".equals(activeProfile) || "test".equals(activeProfile)) { + // 开发/测试环境使用本地回调地址 + return devNotifyUrl; + } else if ("prod".equals(activeProfile)) { + // 生产环境使用生产回调地址 + return prodNotifyUrl; + } else { + // 默认使用配置的服务器地址 + return serverUrl + "/shop/shop-order/notify"; + } + } + + /** + * 克隆支付配置对象 + */ + private Payment clonePayment(Payment original) { + Payment cloned = new Payment(); + cloned.setId(original.getId()); + cloned.setName(original.getName()); + cloned.setType(original.getType()); + cloned.setCode(original.getCode()); + cloned.setImage(original.getImage()); + cloned.setWechatType(original.getWechatType()); + cloned.setAppId(original.getAppId()); + cloned.setMchId(original.getMchId()); + cloned.setApiKey(original.getApiKey()); + cloned.setApiclientCert(original.getApiclientCert()); + cloned.setApiclientKey(original.getApiclientKey()); + cloned.setPubKey(original.getPubKey()); + cloned.setPubKeyId(original.getPubKeyId()); + cloned.setMerchantSerialNumber(original.getMerchantSerialNumber()); + cloned.setNotifyUrl(original.getNotifyUrl()); // 这个会被后续覆盖 + cloned.setComments(original.getComments()); + cloned.setSortNumber(original.getSortNumber()); + cloned.setStatus(original.getStatus()); + cloned.setDeleted(original.getDeleted()); + cloned.setTenantId(original.getTenantId()); + return cloned; + } + + /** + * 获取微信支付配置(环境感知) + */ + public Payment getWechatPayConfig(Integer tenantId) { + return getEnvironmentAwarePaymentConfig(0, tenantId); + } + + /** + * 获取支付宝配置(环境感知) + */ + public Payment getAlipayConfig(Integer tenantId) { + return getEnvironmentAwarePaymentConfig(1, tenantId); + } + + /** + * 检查当前环境 + */ + public String getCurrentEnvironment() { + return activeProfile; + } + + /** + * 是否为开发环境 + */ + public boolean isDevelopmentEnvironment() { + return "dev".equals(activeProfile) || "test".equals(activeProfile); + } + + /** + * 是否为生产环境 + */ + public boolean isProductionEnvironment() { + return "prod".equals(activeProfile); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/IdVerificationService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/IdVerificationService.java new file mode 100644 index 0000000..5923546 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/IdVerificationService.java @@ -0,0 +1,84 @@ +package com.gxwebsoft.common.core.service; + +import com.aliyun.cloudauth20190307.Client; +import com.aliyun.cloudauth20190307.models.Id2MetaVerifyRequest; +import com.aliyun.cloudauth20190307.models.Id2MetaVerifyResponse; +import com.aliyun.teaopenapi.models.Config; +import com.gxwebsoft.common.core.config.CloudAuthProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 阿里云实人认证服务 + * + * @author WebSoft + */ +@Slf4j +@Service +public class IdVerificationService { + + @Autowired + private CloudAuthProperties cloudAuthProperties; + + /** + * 身份证二要素核验 + * + * @param name 姓名 + * @param idCard 身份证号 + * @return true=一致,false=不一致 + */ + public boolean verifyIdCard(String name, String idCard) { + try { + Client client = createClient(); + + Id2MetaVerifyRequest request = new Id2MetaVerifyRequest(); + // 明文传输(生产环境建议使用 md5 加密) + request.setParamType("normal"); + request.setUserName(name); + request.setIdentifyNum(idCard); + + Id2MetaVerifyResponse response = client.id2MetaVerify(request); + + // 3.x SDK API 变化:通过 getBody() 获取响应体 + if (response.getBody() == null) { + log.error("阿里云实人认证响应体为空"); + return false; + } + + var body = response.getBody(); + log.info("阿里云实人认证响应: code={}, message={}", + body.getCode(), body.getMessage()); + + // 接口调用成功 + if ("200".equals(body.getCode())) { + // 通过 getResultObject().getBizCode() 获取验证结果 + // BizCode: 1=一致,2=不一致,3=未查到记录 + if (body.getResultObject() != null) { + String bizCode = body.getResultObject().getBizCode(); + log.info("验证结果 bizCode={}", bizCode); + return "1".equals(bizCode); + } + } + + log.error("阿里云实人认证接口调用失败: code={}, message={}", body.getCode(), body.getMessage()); + return false; + + } catch (Exception e) { + log.error("阿里云实人认证异常", e); + return false; + } + } + + /** + * 创建阿里云实人认证客户端 + */ + private Client createClient() throws Exception { + Config config = new Config(); + config.setAccessKeyId(cloudAuthProperties.getAccessKeyId()); + config.setAccessKeySecret(cloudAuthProperties.getAccessKeySecret()); + config.setRegionId(cloudAuthProperties.getRegionId()); + config.setEndpoint(cloudAuthProperties.getEndpoint()); + return new Client(config); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java new file mode 100644 index 0000000..17a8e32 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java @@ -0,0 +1,174 @@ +package com.gxwebsoft.common.core.service; + +import cn.hutool.core.util.ObjectUtil; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.param.PaymentParam; +import com.gxwebsoft.common.system.service.PaymentService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 支付配置缓存服务 + * 统一管理支付配置的缓存读取,支持 Payment:1* 格式 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Service +public class PaymentCacheService { + + @Autowired + private RedisUtil redisUtil; + + @Autowired + private PaymentService paymentService; + + /** + * 根据支付类型获取支付配置 + * 优先从 Payment:1{payType} 格式的缓存读取 + * + * @param payType 支付类型 (0=微信支付, 1=支付宝, 2=其他) + * @param tenantId 租户ID (用于兜底查询) + * @return Payment 支付配置 + */ + public Payment getPaymentConfig(Integer payType, Integer tenantId) { + // 1. 优先使用 Payment:1{payType} 格式的缓存键 + String primaryKey = "Payment:1:" + tenantId; + Payment payment = redisUtil.get(primaryKey, Payment.class); + + if (ObjectUtil.isNotEmpty(payment)) { + log.debug("从缓存获取支付配置成功: {}", primaryKey); + return payment; + } + + // 2. 如果 Payment:1* 格式不存在,尝试原有格式 + String fallbackKey = "Payment:" + payType + ":" + tenantId; + payment = redisUtil.get(fallbackKey, Payment.class); + + if (ObjectUtil.isNotEmpty(payment)) { + log.debug("从兜底缓存获取支付配置成功: {}", fallbackKey); + // 将查询结果缓存到 Payment:1* 格式 + redisUtil.set(primaryKey, payment); + return payment; + } + + // 3. 最后从数据库查询 + log.debug("从数据库查询支付配置, payType: {}, tenantId: {}", payType, tenantId); + PaymentParam paymentParam = new PaymentParam(); + paymentParam.setType(payType); + paymentParam.setTenantId(tenantId); // 设置租户ID进行过滤 + List payments = paymentService.listRel(paymentParam); + + if (payments.isEmpty()) { + throw new BusinessException("请完成支付配置,支付类型: " + payType); + } + + Payment dbPayment = payments.get(0); + + // 清理时间字段,避免序列化问题 + Payment cachePayment = cleanPaymentForCache(dbPayment); + + // 将查询结果缓存到 Payment:1* 格式 + redisUtil.set(primaryKey, cachePayment); + log.debug("支付配置已缓存到: {}", primaryKey); + + return dbPayment; // 返回原始对象,不影响业务逻辑 + } + + /** + * 缓存支付配置 + * 同时缓存到 Payment:1{payType} 和原有格式 + * + * @param payment 支付配置 + * @param tenantId 租户ID + */ + public void cachePaymentConfig(Payment payment, Integer tenantId) { + // 缓存到 Payment:1* 格式 + String primaryKey = "Payment:1" + payment.getCode(); + redisUtil.set(primaryKey, payment); + log.debug("支付配置已缓存到: {}", primaryKey); + + // 兼容原有格式 + String legacyKey = "Payment:" + payment.getCode() + ":" + tenantId; + redisUtil.set(legacyKey, payment); + log.debug("支付配置已缓存到兼容格式: {}", legacyKey); + } + + /** + * 删除支付配置缓存 + * 同时删除 Payment:1{payType} 和原有格式 + * + * @param paymentCode 支付代码 (可以是String或Integer) + * @param tenantId 租户ID + */ + public void removePaymentConfig(String paymentCode, Integer tenantId) { + // 删除 Payment:1* 格式缓存 + String primaryKey = "Payment:1" + paymentCode; + redisUtil.delete(primaryKey); + log.debug("已删除支付配置缓存: {}", primaryKey); + + // 删除原有格式缓存 + String legacyKey = "Payment:" + paymentCode + ":" + tenantId; + redisUtil.delete(legacyKey); + log.debug("已删除兼容格式缓存: {}", legacyKey); + } + + /** + * 获取微信支付配置 (payType = 0) + */ + public Payment getWechatPayConfig(Integer tenantId) { + return getPaymentConfig(0, tenantId); + } + + /** + * 获取支付宝配置 (payType = 1) + */ + public Payment getAlipayConfig(Integer tenantId) { + return getPaymentConfig(1, tenantId); + } + + /** + * 清理Payment对象用于缓存 + * 移除可能导致序列化问题的时间字段 + */ + private Payment cleanPaymentForCache(Payment original) { + if (original == null) { + return null; + } + + Payment cleaned = new Payment(); + // 复制所有业务相关字段 + cleaned.setId(original.getId()); + cleaned.setName(original.getName()); + cleaned.setType(original.getType()); + cleaned.setCode(original.getCode()); + cleaned.setImage(original.getImage()); + cleaned.setWechatType(original.getWechatType()); + cleaned.setAppId(original.getAppId()); + cleaned.setMchId(original.getMchId()); + cleaned.setApiKey(original.getApiKey()); + cleaned.setApiclientCert(original.getApiclientCert()); + cleaned.setApiclientKey(original.getApiclientKey()); + cleaned.setPubKey(original.getPubKey()); + cleaned.setPubKeyId(original.getPubKeyId()); + cleaned.setMerchantSerialNumber(original.getMerchantSerialNumber()); + cleaned.setNotifyUrl(original.getNotifyUrl()); + cleaned.setComments(original.getComments()); + cleaned.setSortNumber(original.getSortNumber()); + cleaned.setStatus(original.getStatus()); + cleaned.setDeleted(original.getDeleted()); + cleaned.setTenantId(original.getTenantId()); + + // 不设置时间字段,避免序列化问题 + // cleaned.setCreateTime(null); + // cleaned.setUpdateTime(null); + + return cleaned; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AesUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AesUtil.java new file mode 100644 index 0000000..61dd2cd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AesUtil.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.common.core.utils; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * AES 加密解密工具类 + * 用于云凭证等敏感信息的加密存储 + * + * @author 科技小王子 + * @since 2026-04-04 + */ +public class AesUtil { + + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; + + /** + * AES 加密 + * + * @param plaintext 明文 + * @param key 密钥(16字符) + * @return Base64 编码的密文 + */ + public static String encrypt(String plaintext, String key) { + if (plaintext == null || plaintext.isEmpty()) { + return plaintext; + } + try { + String actualKey = formatKey(key); + SecretKeySpec secretKey = new SecretKeySpec(actualKey.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(encrypted); + } catch (Exception e) { + throw new RuntimeException("AES加密失败", e); + } + } + + /** + * AES 解密 + * + * @param ciphertext Base64 编码的密文 + * @param key 密钥(16字符) + * @return 明文 + */ + public static String decrypt(String ciphertext, String key) { + if (ciphertext == null || ciphertext.isEmpty()) { + return ciphertext; + } + try { + String actualKey = formatKey(key); + SecretKeySpec secretKey = new SecretKeySpec(actualKey.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + byte[] decoded = Base64.getDecoder().decode(ciphertext); + byte[] decrypted = cipher.doFinal(decoded); + return new String(decrypted, StandardCharsets.UTF_8); + } catch (Exception e) { + throw new RuntimeException("AES解密失败", e); + } + } + + /** + * 格式化密钥为16字节 + */ + private static String formatKey(String key) { + if (key == null) { + key = ""; + } + if (key.length() < 16) { + return String.format("%-16s", key).replace(' ', '0'); + } else if (key.length() > 16) { + return key.substring(0, 16); + } + return key; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AliYunSender.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AliYunSender.java new file mode 100644 index 0000000..80fe4b1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AliYunSender.java @@ -0,0 +1,145 @@ +package com.gxwebsoft.common.core.utils; +import cn.hutool.core.codec.Base64; +import org.springframework.stereotype.Component; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.security.MessageDigest; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.UUID; + +@Component +public class AliYunSender { + /* + * 计算MD5+BASE64 + */ + public static String MD5Base64(String s) { + if (s == null) + return null; + String encodeStr = ""; + byte[] utfBytes = s.getBytes(); + MessageDigest mdTemp; + try { + mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(utfBytes); + byte[] md5Bytes = mdTemp.digest(); + encodeStr = Base64.encode(md5Bytes); + } catch (Exception e) { + throw new Error("Failed to generate MD5 : " + e.getMessage()); + } + return encodeStr; + } + /* + * 计算 HMAC-SHA1 + */ + public static String HMACSha1(String data, String key) { + String result; + try { + SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1"); + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(signingKey); + byte[] rawHmac = mac.doFinal(data.getBytes()); + result = Base64.encode(rawHmac); + } catch (Exception e) { + throw new Error("Failed to generate HMAC : " + e.getMessage()); + } + return result; + } + /* + * 获取时间 + */ + public static String toGMTString(Date date) { + SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK); + df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT")); + return df.format(date); + } + /* + * 发送POST请求 + */ + public static String sendPost(String url, String body, String ak_id, String ak_secret) { + PrintWriter out = null; + BufferedReader in = null; + String result = ""; + try { + URL realUrl = new URL(url); + /* + * http header 参数 + */ + String method = "POST"; + String accept = "application/json"; + String content_type = "application/json;chrset=utf-8"; + String path = realUrl.getFile(); + String date = toGMTString(new Date()); + String host = realUrl.getHost(); + // 1.对body做MD5+BASE64加密 + String bodyMd5 = MD5Base64(body); + String uuid = UUID.randomUUID().toString(); + String stringToSign = method + "\n" + accept + "\n" + bodyMd5 + "\n" + content_type + "\n" + date + "\n" + + "x-acs-signature-method:HMAC-SHA1\n" + + "x-acs-signature-nonce:" + uuid + "\n" + + "x-acs-version:2019-01-02\n" + + path; + // 2.计算 HMAC-SHA1 + String signature = HMACSha1(stringToSign, ak_secret); + // 3.得到 authorization header + String authHeader = "acs " + ak_id + ":" + signature; + // 打开和URL之间的连接 + URLConnection conn = realUrl.openConnection(); + // 设置通用的请求属性 + conn.setRequestProperty("Accept", accept); + conn.setRequestProperty("Content-Type", content_type); + conn.setRequestProperty("Content-MD5", bodyMd5); + conn.setRequestProperty("Date", date); + conn.setRequestProperty("Host", host); + conn.setRequestProperty("Authorization", authHeader); + conn.setRequestProperty("x-acs-signature-nonce", uuid); + conn.setRequestProperty("x-acs-signature-method", "HMAC-SHA1"); + conn.setRequestProperty("x-acs-version", "2019-01-02"); // 版本可选 + // 发送POST请求必须设置如下两行 + conn.setDoOutput(true); + conn.setDoInput(true); + // 获取URLConnection对象对应的输出流 + out = new PrintWriter(conn.getOutputStream()); + // 发送请求参数 + out.print(body); + // flush输出流的缓冲 + out.flush(); + // 定义BufferedReader输入流来读取URL的响应 + InputStream is; + HttpURLConnection httpconn = (HttpURLConnection) conn; + if (httpconn.getResponseCode() == 200) { + is = httpconn.getInputStream(); + } else { + is = httpconn.getErrorStream(); + } + in = new BufferedReader(new InputStreamReader(is)); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + } catch (Exception e) { + System.out.println("发送 POST 请求出现异常!" + e); + e.printStackTrace(); + } + // 使用finally块来关闭输出流、输入流 + finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + return result; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AlipayConfigUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AlipayConfigUtil.java new file mode 100644 index 0000000..42975ef --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AlipayConfigUtil.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.common.core.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayConstants; +import com.alipay.api.CertAlipayRequest; +import com.alipay.api.DefaultAlipayClient; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.exception.BusinessException; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 支付宝工具类 + * @author leng + * + */ +@Component +public class AlipayConfigUtil { + private final StringRedisTemplate stringRedisTemplate; + public Integer tenantId; + public String gateway; + public JSONObject config; + public String appId; + public String privateKey; + public String appCertPublicKey; + public String alipayCertPublicKey; + public String alipayRootCert; + + @Resource + private ConfigProperties pathConfig; + + public AlipayConfigUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + // 实例化客户端 + public DefaultAlipayClient alipayClient(Integer tenantId) throws AlipayApiException { + this.gateway = "https://openapi.alipay.com/gateway.do"; + this.tenantId = tenantId; + this.payment(tenantId); + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + certAlipayRequest.setServerUrl(this.gateway); + certAlipayRequest.setAppId(this.appId); + certAlipayRequest.setPrivateKey(this.privateKey); + certAlipayRequest.setFormat(AlipayConstants.FORMAT_JSON); + certAlipayRequest.setCharset(AlipayConstants.CHARSET_UTF8); + certAlipayRequest.setSignType(AlipayConstants.SIGN_TYPE_RSA2); + certAlipayRequest.setCertPath(this.appCertPublicKey); + certAlipayRequest.setAlipayPublicCertPath(this.alipayCertPublicKey); + certAlipayRequest.setRootCertPath(this.alipayRootCert); +// System.out.println("this.appId = " + this.appId); +// System.out.println("this.appId = " + this.gateway); +// System.out.println("this.appId = " + this.privateKey); +// System.out.println("this.appId = " + this.appCertPublicKey); +// System.out.println("this.appId = " + this.alipayCertPublicKey); +// System.out.println("this.appId = " + this.alipayRootCert); +// System.out.println("this.config = " + this.config); + return new DefaultAlipayClient(certAlipayRequest); + } + + /** + * 获取支付宝秘钥 + */ + public JSONObject payment(Integer tenantId) { + System.out.println("tenantId = " + tenantId); + String key = "cache".concat(tenantId.toString()).concat(":setting:payment"); + System.out.println("key = " + key); + String cache = stringRedisTemplate.opsForValue().get(key); + if (cache == null) { + throw new BusinessException("支付方式未配置"); + } + // 解析json数据 + JSONObject payment = JSON.parseObject(cache.getBytes()); + this.config = payment; + this.appId = payment.getString("alipayAppId"); + this.privateKey = payment.getString("privateKey"); + this.appCertPublicKey = pathConfig.getUploadPath() + "file" + payment.getString("appCertPublicKey"); + this.alipayCertPublicKey = pathConfig.getUploadPath() + "file" + payment.getString("alipayCertPublicKey"); + this.alipayRootCert = pathConfig.getUploadPath() + "file" + payment.getString("alipayRootCert"); + return payment; + } + + public String appId(){ + return this.appId; + } + + public String privateKey(){ + return this.privateKey; + } + + public String appCertPublicKey(){ + return this.appCertPublicKey; + } + + public String alipayCertPublicKey(){ + return this.alipayCertPublicKey; + } + + public String alipayRootCert(){ + return this.alipayRootCert; + } + + + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AliyunTranslateUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AliyunTranslateUtil.java new file mode 100644 index 0000000..8ba568f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/AliyunTranslateUtil.java @@ -0,0 +1,72 @@ +package com.gxwebsoft.common.core.utils; + +import com.aliyun.alimt20181012.Client; +import com.aliyun.alimt20181012.models.TranslateGeneralRequest; +import com.aliyun.alimt20181012.models.TranslateGeneralResponse; +import com.aliyun.teaopenapi.models.Config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * 阿里云机器翻译工具类 + */ +@Component +public class AliyunTranslateUtil { + + @Value("${aliyun.translate.access-key-id:}") + private String accessKeyId; + + @Value("${aliyun.translate.access-key-secret:}") + private String accessKeySecret; + + @Value("${aliyun.translate.endpoint:mt.cn-hangzhou.aliyuncs.com}") + private String endpoint; + + /** + * 创建客户端 + */ + private Client createClient() throws Exception { + Config config = new Config() + .setAccessKeyId(accessKeyId) + .setAccessKeySecret(accessKeySecret) + .setEndpoint(endpoint); + return new Client(config); + } + + /** + * 翻译文本 + * + * @param text 待翻译文本 + * @param targetLang 目标语言(如:en, zh, ja, ko等) + * @param sourceLang 源语言(如:zh, en, auto等,auto表示自动检测) + * @return 翻译后的文本 + */ + public String translate(String text, String targetLang, String sourceLang) { + try { + Client client = createClient(); + TranslateGeneralRequest request = new TranslateGeneralRequest() + .setFormatType("text") + .setSourceLanguage(sourceLang) + .setTargetLanguage(targetLang) + .setSourceText(text) + .setScene("general"); + + TranslateGeneralResponse response = client.translateGeneral(request); + return response.getBody().getData().getTranslated(); + } catch (Exception e) { + e.printStackTrace(); + return text; + } + } + + /** + * 翻译文本(自动检测源语言) + * + * @param text 待翻译文本 + * @param targetLang 目标语言 + * @return 翻译后的文本 + */ + public String translate(String text, String targetLang) { + return translate(text, targetLang, "auto"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CacheClient.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CacheClient.java new file mode 100644 index 0000000..62f063e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CacheClient.java @@ -0,0 +1,265 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.result.RedisResult; +import org.springframework.data.geo.Point; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import static com.gxwebsoft.common.core.constants.RedisConstants.CACHE_NULL_TTL; + +@Component +public class CacheClient { + private final StringRedisTemplate stringRedisTemplate; + public static Integer tenantId; + + public CacheClient(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant) + */ + public void set(String key, T entity){ + stringRedisTemplate.opsForValue().set(prefix(key), JSONUtil.toJSONString(entity)); + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant,1L,TimeUnit.DAYS) + */ + public void set(String key, T entity, Long time, TimeUnit unit){ + stringRedisTemplate.opsForValue().set(prefix(key), JSONUtil.toJSONString(entity),time,unit); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * 示例 cacheClient.get(key) + * @return merchant + */ + public String get(String key) { + return stringRedisTemplate.opsForValue().get(prefix(key)); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * @param clazz Merchant.class + * @param + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @return merchant + */ + public T get(String key, Class clazz) { + String json = stringRedisTemplate.opsForValue().get(prefix(key)); + if(StrUtil.isNotBlank(json)){ + return JSONUtil.parseObject(json, clazz); + } + return null; + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param field 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPut(String key, String field, T entity) { + stringRedisTemplate.opsForHash().put(prefix(key),field,JSONUtil.toJSONString(entity)); + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param map 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPutAll(String key, Map map) { + stringRedisTemplate.opsForHash().putAll(prefix(key),map); + } + + /** + * 读取redis缓存(哈希类型) + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @param key [表名]:id + * @param field 字段 + * @return merchant + */ + public T hGet(String key, String field, Class clazz) { + Object obj = stringRedisTemplate.opsForHash().get(prefix(key), field); + return JSONUtil.parseObject(JSONUtil.toJSONString(obj),clazz); + } + + public List hValues(String key){ + return stringRedisTemplate.opsForHash().values(prefix(key)); + } + + public Long hSize(String key){ + return stringRedisTemplate.opsForHash().size(prefix(key)); + } + + // 逻辑过期方式写入redis + public void setWithLogicalExpire(String key, T value, Long time, TimeUnit unit){ + // 设置逻辑过期时间 + final RedisResult redisResult = new RedisResult<>(); + redisResult.setData(value); + redisResult.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time))); + stringRedisTemplate.opsForValue().set(prefix(key),JSONUtil.toJSONString(redisResult)); + } + + // 读取redis + public R query(String keyPrefix, ID id, Class clazz, Function dbFallback, Long time, TimeUnit unit){ + String key = keyPrefix + id; + // 1.从redis查询缓存 + final String json = stringRedisTemplate.opsForValue().get(prefix(key)); + // 2.判断是否存在 + if (StrUtil.isNotBlank(json)) { + // 3.存在,直接返回 + return JSONUtil.parseObject(json,clazz); + } + // 判断命中的是否为空值 + if (json != null) { + return null; + } + // 4. 不存在,跟进ID查询数据库 + R r = dbFallback.apply(id); + // 5. 数据库不存在,返回错误 + if(r == null){ + // 空值写入数据库 + this.set(prefix(key),"",CACHE_NULL_TTL,TimeUnit.MINUTES); + return null; + } + // 写入redis + this.set(prefix(key),r,time,unit); + return r; + } + + /** + * 添加商户定位点 + * @param key geo + * @param id + * 示例 cacheClient.geoAdd("merchant-geo",merchant) + */ + public void geoAdd(String key, Double x, Double y, String id){ + stringRedisTemplate.opsForGeo().add(prefix(key),new Point(x,y),id); + } + + /** + * 删除定位 + * @param key geo + * @param id + * 示例 cacheClient.geoRemove("merchant-geo",id) + */ + public void geoRemove(String key, Integer id){ + stringRedisTemplate.opsForGeo().remove(prefix(key),id.toString()); + } + + + + public void sAdd(String key, T entity){ + stringRedisTemplate.opsForSet().add(prefix(key),JSONUtil.toJSONString(entity)); + } + + public Set sMembers(String key){ + return stringRedisTemplate.opsForSet().members(prefix(key)); + } + + // 更新排行榜 + public void zAdd(String key, Integer userId, Double value) { + stringRedisTemplate.opsForZSet().add(prefix(key),userId.toString(),value); + } + // 增加元素的score值,并返回增加后的值 + public Double zIncrementScore(String key,Integer userId, Double delta){ + return stringRedisTemplate.opsForZSet().incrementScore(key, userId.toString(), delta); + } + // 获取排名榜 + public Set range(String key, Integer start, Integer end) { + return stringRedisTemplate.opsForZSet().range(prefix(key), start, end); + } + // 获取排名榜 + public Set reverseRange(String key, Integer start, Integer end){ + return stringRedisTemplate.opsForZSet().reverseRange(prefix(key), start, end); + } + // 获取分数 + public Double score(String key, Object value){ + return stringRedisTemplate.opsForZSet().score(prefix(key), value); + } + + public void delete(String key){ + stringRedisTemplate.delete(prefix(key)); + } + + // 存储在list头部 + public void leftPush(String key, String keyword){ + stringRedisTemplate.opsForList().leftPush(prefix(key),keyword); + } + + // 获取列表指定范围内的元素 + public List listRange(String key,Long start, Long end){ + return stringRedisTemplate.opsForList().range(prefix(key), start, end); + } + + // 获取列表长度 + public Long listSize(String key){ + return stringRedisTemplate.opsForList().size(prefix(key)); + } + + // 裁剪list + public void listTrim(String key){ + stringRedisTemplate.opsForList().trim(prefix(key), 0L, 100L); + } + + /** + * 读取后台系统设置信息 + * @param keyName 键名wx-word + * @param tenantId 租户ID + * @return + * key示例 cache10048:setting:wx-work + */ + public JSONObject getSettingInfo(String keyName,Integer tenantId){ + String key = "cache" + tenantId + ":setting:" + keyName; + final String cache = stringRedisTemplate.opsForValue().get(key); + assert cache != null; + return JSON.parseObject(cache); + } + + /** + * KEY前缀 + * cache[tenantId]:[key+id] + */ + public static String prefix(String key){ + String prefix = "cache"; + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + final Integer tenantId = ((User) object).getTenantId(); + prefix = prefix.concat(tenantId.toString()).concat(":"); + } + } + return prefix.concat(key); + } + + // 组装key + public String key(String name,Integer id){ + return name.concat(":").concat(id.toString()); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CertificateLoader.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CertificateLoader.java new file mode 100644 index 0000000..a256e49 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CertificateLoader.java @@ -0,0 +1,230 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.config.CertificateProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * 证书加载工具类 + * 支持多种证书加载方式,适配Docker容器化部署 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Component +public class CertificateLoader { + + private final CertificateProperties certConfig; + + public CertificateLoader(CertificateProperties certConfig) { + this.certConfig = certConfig; + } + + @PostConstruct + public void init() { + log.info("证书加载器初始化,加载模式:{}", certConfig.getLoadMode()); + if (certConfig.getLoadMode() == CertificateProperties.LoadMode.VOLUME) { + log.info("Docker挂载卷证书路径:{}", certConfig.getCertRootPath()); + validateCertDirectory(); + } + } + + /** + * 验证证书目录是否存在 + */ + private void validateCertDirectory() { + File certDir = new File(certConfig.getCertRootPath()); + if (!certDir.exists()) { + log.warn("证书目录不存在:{},将尝试创建", certConfig.getCertRootPath()); + if (!certDir.mkdirs()) { + log.error("无法创建证书目录:{}", certConfig.getCertRootPath()); + } + } else { + log.info("证书目录验证成功:{}", certConfig.getCertRootPath()); + } + } + + /** + * 加载证书文件路径 + * + * @param certPath 证书路径(可能是相对路径、绝对路径或classpath路径) + * @return 实际的证书文件路径 + */ + public String loadCertificatePath(String certPath) { + if (!StringUtils.hasText(certPath)) { + throw new IllegalArgumentException("证书路径不能为空"); + } + + try { + switch (certConfig.getLoadMode()) { + case CLASSPATH: + return loadFromClasspath(certPath); + case VOLUME: + return loadFromVolume(certPath); + case FILESYSTEM: + default: + return loadFromFileSystem(certPath); + } + } catch (Exception e) { + log.error("加载证书失败,路径:{}", certPath, e); + throw new RuntimeException("证书加载失败:" + certPath, e); + } + } + + /** + * 从classpath加载证书 + */ + private String loadFromClasspath(String certPath) throws IOException { + String resourcePath = certPath.startsWith("classpath:") ? + certPath.substring("classpath:".length()) : certPath; + + ClassPathResource resource = new ClassPathResource(resourcePath); + if (!resource.exists()) { + throw new IOException("Classpath中找不到证书文件:" + resourcePath); + } + + // 将classpath中的文件复制到临时目录 + Path tempFile = Files.createTempFile("cert_", ".pem"); + try (InputStream inputStream = resource.getInputStream()) { + Files.copy(inputStream, tempFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } + + String tempPath = tempFile.toAbsolutePath().toString(); + log.debug("从classpath加载证书:{} -> {}", resourcePath, tempPath); + return tempPath; + } + + /** + * 从Docker挂载卷加载证书 + */ + private String loadFromVolume(String certPath) { + log.debug("尝试从Docker挂载卷加载证书:{}", certPath); + + // 如果是完整路径,直接使用 + if (certPath.startsWith("/") || certPath.contains(":")) { + File file = new File(certPath); + log.debug("检查完整路径文件是否存在:{}", certPath); + if (file.exists()) { + log.debug("使用完整路径加载证书:{}", certPath); + return certPath; + } else { + log.error("完整路径文件不存在:{}", certPath); + } + } + + // 否则拼接挂载卷路径 + String fullPath = Paths.get(certConfig.getCertRootPath(), certPath).toString(); + File file = new File(fullPath); + if (!file.exists()) { + throw new RuntimeException("Docker挂载卷中找不到证书文件:" + fullPath); + } + + log.debug("从Docker挂载卷加载证书:{}", fullPath); + return fullPath; + } + + /** + * 从文件系统加载证书 + */ + private String loadFromFileSystem(String certPath) { + File file = new File(certPath); + if (!file.exists()) { + throw new RuntimeException("文件系统中找不到证书文件:" + certPath); + } + + log.debug("从文件系统加载证书:{}", certPath); + return certPath; + } + + /** + * 检查证书文件是否存在 + * + * @param certPath 证书路径 + * @return 是否存在 + */ + public boolean certificateExists(String certPath) { + try { + switch (certConfig.getLoadMode()) { + case CLASSPATH: + String resourcePath = certPath.startsWith("classpath:") ? + certPath.substring("classpath:".length()) : certPath; + ClassPathResource resource = new ClassPathResource(resourcePath); + return resource.exists(); + case VOLUME: + String fullPath = certPath.startsWith("/") ? certPath : + Paths.get(certConfig.getCertRootPath(), certPath).toString(); + return new File(fullPath).exists(); + case FILESYSTEM: + default: + return new File(certPath).exists(); + } + } catch (Exception e) { + log.warn("检查证书文件存在性时出错:{}", certPath, e); + return false; + } + } + + /** + * 获取证书文件的输入流 + * + * @param certPath 证书路径 + * @return 输入流 + */ + public InputStream getCertificateInputStream(String certPath) throws IOException { + switch (certConfig.getLoadMode()) { + case CLASSPATH: + String resourcePath = certPath.startsWith("classpath:") ? + certPath.substring("classpath:".length()) : certPath; + ClassPathResource resource = new ClassPathResource(resourcePath); + return resource.getInputStream(); + case VOLUME: + case FILESYSTEM: + default: + String actualPath = loadCertificatePath(certPath); + return Files.newInputStream(Paths.get(actualPath)); + } + } + + /** + * 列出证书目录中的所有文件 + * + * @return 证书文件列表 + */ + public String[] listCertificateFiles() { + try { + switch (certConfig.getLoadMode()) { + case VOLUME: + File certDir = new File(certConfig.getCertRootPath()); + if (certDir.exists() && certDir.isDirectory()) { + return certDir.list(); + } + break; + case CLASSPATH: + // classpath模式下不支持列出文件 + log.warn("Classpath模式下不支持列出证书文件"); + break; + case FILESYSTEM: + default: + // 文件系统模式下证书可能分散在不同目录,不支持统一列出 + log.warn("文件系统模式下不支持列出证书文件"); + break; + } + } catch (Exception e) { + log.error("列出证书文件时出错", e); + } + return new String[0]; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CommonUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CommonUtil.java new file mode 100644 index 0000000..6435db6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/CommonUtil.java @@ -0,0 +1,321 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import cn.hutool.crypto.symmetric.SymmetricAlgorithm; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.system.entity.Role; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * 常用工具方法 + * + * @author WebSoft + * @since 2017-06-10 10:10:22 + */ +public class CommonUtil { + + // 生成uuid的字符 + private static final String[] chars = new String[]{ + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" + }; + + /** + * 生成8位uuid + * + * @return String + */ + public static String randomUUID8() { + StringBuilder sb = new StringBuilder(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + for (int i = 0; i < 8; i++) { + String str = uuid.substring(i * 4, i * 4 + 4); + int x = Integer.parseInt(str, 16); + sb.append(chars[x % 0x3E]); + } + return sb.toString(); + } + + /** + * 生成16位uuid + * + * @return String + */ + public static String randomUUID16() { + StringBuilder sb = new StringBuilder(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + for (int i = 0; i < 16; i++) { + String str = uuid.substring(i * 2, i * 2 + 2); + int x = Integer.parseInt(str, 16); + sb.append(chars[x % 0x3E]); + } + return sb.toString(); + } + + /** + * 获取当前时间 + * + * @return String + */ + public static String currentTime() { + Date date = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss"); + return sdf.format(date); + } + + /** + * 生成10位随机用户名 + * + * @return String + */ + public static String randomUsername(String prefix) { + Date date = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss"); + String currentTime = sdf.format(date); + return prefix + currentTime; + } + + /** + * 生成订单号 + * 20233191166110426 + * 20230419135802391412 + * @return + */ + public static String createOrderNo() { + String prefix = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN); + return prefix + RandomUtil.randomNumbers(2); + } + + /** + * 生成订单号 + * @param tenantId + * 20233191166110426 + * 20230419135802391412 + * @return + */ + public static String createOrderNo(String tenantId) { + String prefix = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN); + return prefix + tenantId + RandomUtil.randomNumbers(2); + } + + /** + * 生成订单水流号 + * @param tenantId + * @return + */ + public static String serialNo(int tenantId) { + String prefix = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN); + return prefix + tenantId + RandomUtil.randomNumbers(2); + } + + /** + * 生成会员卡号 + * @return + */ + public static String createCardNo() { + String prefix = DateTime.now().toString(DatePattern.PURE_TIME_PATTERN); + return "00" + prefix + RandomUtil.randomNumbers(2); + } + + /** + * 检查List是否有重复元素 + * + * @param list List + * @param mapper 获取需要检查的字段的Function + * @param 数据的类型 + * @param 需要检查的字段的类型 + * @return boolean + */ + public static boolean checkRepeat(List list, Function mapper) { + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < list.size(); j++) { + if (i != j && mapper.apply(list.get(i)).equals(mapper.apply(list.get(j)))) { + return true; + } + } + } + return false; + } + + /** + * List转为树形结构 + * + * @param data List + * @param parentId 顶级的parentId + * @param parentIdMapper 获取parentId的Function + * @param idMapper 获取id的Function + * @param consumer 赋值children的Consumer + * @param 数据的类型 + * @param parentId的类型 + * @return List + */ + public static List toTreeData(List data, R parentId, + Function parentIdMapper, + Function idMapper, + BiConsumer> consumer) { + List result = new ArrayList<>(); + for (T d : data) { + R dParentId = parentIdMapper.apply(d); + if (ObjectUtil.equals(parentId, dParentId)) { + R dId = idMapper.apply(d); + List children = toTreeData(data, dId, parentIdMapper, idMapper, consumer); + consumer.accept(d, children); + result.add(d); + } + } + return result; + } + + /** + * 遍历树形结构数据 + * + * @param data List + * @param consumer 回调 + * @param mapper 获取children的Function + * @param 数据的类型 + */ + public static void eachTreeData(List data, Consumer consumer, Function> mapper) { + for (T d : data) { + consumer.accept(d); + List children = mapper.apply(d); + if (children != null && children.size() > 0) { + eachTreeData(children, consumer, mapper); + } + } + } + + /** + * 获取集合中的第一条数据 + * + * @param records 集合 + * @return 第一条数据 + */ + public static T listGetOne(List records) { + return records == null || records.size() == 0 ? null : records.get(0); + } + + /** + * 支持跨域 + * + * @param response HttpServletResponse + */ + public static void addCrossHeaders(HttpServletResponse response) { + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods", "*"); + response.setHeader("Access-Control-Allow-Headers", "*"); + response.setHeader("Access-Control-Expose-Headers", Constants.TOKEN_HEADER_NAME); + } + + /** + * 输出错误信息 + * + * @param response HttpServletResponse + * @param code 错误码 + * @param message 提示信息 + * @param error 错误信息 + */ + public static void responseError(HttpServletResponse response, Integer code, String message, String error) { + response.setContentType("application/json;charset=UTF-8"); + try { + PrintWriter out = response.getWriter(); + out.write(JSONUtil.toJSONString(new ApiResult<>(code, message, null, error))); + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static boolean hasRole(List array,String value){ + System.out.println("value = " + value); + if (value == null) { + return true; + } + if (array == null) { + return false; + } + if (!array.isEmpty()) { + final List collect = array.stream().map(Role::getRoleCode) + .collect(Collectors.toList()); + final boolean contains = collect.contains(value); + if (contains) { + return true; + } + } + return false; + } + + public static boolean hasRole(List array,List value){ + System.out.println("value = " + value); + if (value == null) { + return true; + } + if (array == null) { + return false; + } + if (!array.isEmpty()) { + final List collect = array.stream().map(Role::getRoleCode) + .collect(Collectors.toList()); + final boolean disjoint = Collections.disjoint(collect, value); + if (!disjoint) { + return true; + } + } + return false; + } + + public static AES aes(){ + // 随机生成密钥 + byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded(); + return SecureUtil.aes(key); + } + + // 机密文本 + public static String encrypt(String text){ + final AES aes = aes(); + return aes.encryptHex(text); + } + + // 解密 + public static String decrypt(String encrypt){ + final AES aes = aes(); + return aes.decryptStr(encrypt, CharsetUtil.CHARSET_UTF_8); + } + + /** + * 验证给定的字符串是否为有效的中国大陆手机号码。 + * + * @param phoneNumber 要验证的电话号码字符串 + * @return 如果字符串是有效的手机号码,则返回true;否则返回false + */ + public static boolean isValidPhoneNumber(String phoneNumber) { + // 定义手机号码的正则表达式 + String regex = "^1[3-9]\\d{9}$"; + + // 创建Pattern对象 + Pattern pattern = Pattern.compile(regex); + + // 使用matcher方法创建Matcher对象并进行匹配 + return pattern.matcher(phoneNumber).matches(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DateTimeUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DateTimeUtil.java new file mode 100644 index 0000000..bde0280 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DateTimeUtil.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.common.core.utils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 时间格式化工具类 + * 用于统一处理LocalDateTime的格式化 + * + * @author WebSoft + * @since 2025-08-23 + */ +public class DateTimeUtil { + + /** + * 默认的日期时间格式 + */ + public static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + /** + * 默认的日期格式 + */ + public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; + + /** + * 默认的时间格式 + */ + public static final String DEFAULT_TIME_PATTERN = "HH:mm:ss"; + + /** + * 默认的日期时间格式化器 + */ + private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = + DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN); + + /** + * 格式化LocalDateTime为字符串 + * 使用默认格式:yyyy-MM-dd HH:mm:ss + * + * @param dateTime 要格式化的时间 + * @return 格式化后的字符串,如果输入为null则返回null + */ + public static String formatDateTime(LocalDateTime dateTime) { + if (dateTime == null) { + return null; + } + return dateTime.format(DEFAULT_DATETIME_FORMATTER); + } + + /** + * 格式化LocalDateTime为字符串 + * 使用指定格式 + * + * @param dateTime 要格式化的时间 + * @param pattern 格式模式 + * @return 格式化后的字符串,如果输入为null则返回null + */ + public static String formatDateTime(LocalDateTime dateTime, String pattern) { + if (dateTime == null) { + return null; + } + return dateTime.format(DateTimeFormatter.ofPattern(pattern)); + } + + /** + * 解析字符串为LocalDateTime + * 使用默认格式:yyyy-MM-dd HH:mm:ss + * + * @param dateTimeStr 时间字符串 + * @return LocalDateTime对象,如果输入为null或空字符串则返回null + */ + public static LocalDateTime parseDateTime(String dateTimeStr) { + if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) { + return null; + } + return LocalDateTime.parse(dateTimeStr, DEFAULT_DATETIME_FORMATTER); + } + + /** + * 解析字符串为LocalDateTime + * 使用指定格式 + * + * @param dateTimeStr 时间字符串 + * @param pattern 格式模式 + * @return LocalDateTime对象,如果输入为null或空字符串则返回null + */ + public static LocalDateTime parseDateTime(String dateTimeStr, String pattern) { + if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) { + return null; + } + return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern)); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DbPasswordUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DbPasswordUtil.java new file mode 100644 index 0000000..40a40e5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DbPasswordUtil.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.crypto.symmetric.AES; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * 数据库密码加密工具类 + * 使用 AES 加密存储数据库密码 + * + * @author WebSoft + * @since 2026-04-04 + */ +@Slf4j +@Component +public class DbPasswordUtil { + + @Value("${db.password.aes-key:websopyDbPasswordKey2026}") + private String aesKey; + + private static AES aes; + + @PostConstruct + public void init() { + // 使用 16 字节密钥(AES-128) + String key = aesKey; + if (key.length() < 16) { + key = String.format("%-16s", key).replace(' ', '0'); + } else if (key.length() > 16) { + key = key.substring(0, 16); + } + aes = new AES(key.getBytes(StandardCharsets.UTF_8)); + log.info("数据库密码加密工具初始化完成"); + } + + /** + * 加密密码 + * + * @param plainPassword 明文密码 + * @return 加密后的 Base64 字符串 + */ + public static String encrypt(String plainPassword) { + if (plainPassword == null || plainPassword.isEmpty()) { + return plainPassword; + } + try { + byte[] encrypted = aes.encrypt(plainPassword); + return Base64.getEncoder().encodeToString(encrypted); + } catch (Exception e) { + log.error("密码加密失败", e); + throw new RuntimeException("密码加密失败"); + } + } + + /** + * 解密密码 + * + * @param encryptedPassword 加密后的 Base64 字符串 + * @return 明文密码 + */ + public static String decrypt(String encryptedPassword) { + if (encryptedPassword == null || encryptedPassword.isEmpty()) { + return encryptedPassword; + } + try { + byte[] decoded = Base64.getDecoder().decode(encryptedPassword); + return aes.decryptStr(decoded); + } catch (Exception e) { + log.error("密码解密失败", e); + throw new RuntimeException("密码解密失败"); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DomainUtils.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DomainUtils.java new file mode 100644 index 0000000..64f4ad2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/DomainUtils.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.cms.entity.CmsDomain; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class DomainUtils { + public static boolean isDomainResolvable(String domain) { + try { + InetAddress.getByName(domain); + return true; + } catch (UnknownHostException e) { + return false; + } + } + + public static boolean DNSLookup(CmsDomain domain){ + try { + // 获取域名对应的InetAddress对象 + InetAddress inetAddress = InetAddress.getByName(domain.getDomain()); + final String hostAddress = inetAddress.getHostAddress(); + InetAddress inetAddress2 = InetAddress.getByName(domain.getHostValue()); + final String hostAddress2 = inetAddress2.getHostAddress(); + if(hostAddress.equals(hostAddress2)){ + return true; + } + return false; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtil.java new file mode 100644 index 0000000..ff66ddc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtil.java @@ -0,0 +1,433 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import cn.hutool.crypto.symmetric.SymmetricAlgorithm; +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.crypto.spec.SecretKeySpec; +import java.awt.*; +import java.io.ByteArrayOutputStream; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * 加密二维码工具类 + * 使用token作为密钥对二维码数据进行AES加密 + * + * @author WebSoft + * @since 2025-08-18 + */ +@Component +public class EncryptedQrCodeUtil { + + @Autowired + private RedisUtil redisUtil; + + private static final String QR_TOKEN_PREFIX = "qr_token:"; + private static final long DEFAULT_EXPIRE_MINUTES = 30; // 默认30分钟过期 + + /** + * 生成加密的二维码数据 + * + * @param originalData 原始数据 + * @param expireMinutes 过期时间(分钟) + * @return 包含token和加密数据的Map + */ + public Map generateEncryptedData(String originalData, Long expireMinutes) { + if (StrUtil.isBlank(originalData)) { + throw new IllegalArgumentException("原始数据不能为空"); + } + + if (expireMinutes == null || expireMinutes <= 0) { + expireMinutes = DEFAULT_EXPIRE_MINUTES; + } + + // 生成随机token作为密钥 + String token = RandomUtil.randomString(32); + + try { + // 使用token生成AES密钥 + AES aes = createAESFromToken(token); + + // 加密原始数据 + String encryptedData = aes.encryptHex(originalData); + + // 将token和原始数据存储到Redis中,设置过期时间 + String redisKey = QR_TOKEN_PREFIX + token; + redisUtil.set(redisKey, originalData, expireMinutes, TimeUnit.MINUTES); + + Map result = new HashMap<>(); + result.put("token", token); + result.put("encryptedData", encryptedData); + result.put("expireMinutes", expireMinutes.toString()); + + return result; + + } catch (Exception e) { + throw new RuntimeException("生成加密数据失败: " + e.getMessage(), e); + } + } + + /** + * 解密二维码数据 + * + * @param token 密钥token + * @param encryptedData 加密的数据 + * @return 解密后的原始数据 + */ + public String decryptData(String token, String encryptedData) { + if (StrUtil.isBlank(token) || StrUtil.isBlank(encryptedData)) { + throw new IllegalArgumentException("token和加密数据不能为空"); + } + + try { + // 从Redis验证token是否有效 + String redisKey = QR_TOKEN_PREFIX + token; + String originalData = redisUtil.get(redisKey); + + if (StrUtil.isBlank(originalData)) { + throw new RuntimeException("token已过期或无效"); + } + + // 使用token生成AES密钥 + AES aes = createAESFromToken(token); + + // 解密数据 + String decryptedData = aes.decryptStr(encryptedData, CharsetUtil.CHARSET_UTF_8); + + // 验证解密结果与Redis中存储的数据是否一致 + if (!originalData.equals(decryptedData)) { + throw new RuntimeException("数据验证失败"); + } + + return decryptedData; + + } catch (Exception e) { + throw new RuntimeException("解密数据失败: " + e.getMessage(), e); + } + } + + /** + * 生成加密的二维码图片(自包含模式) + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param expireMinutes 过期时间(分钟) + * @param businessType 业务类型(可选,如:order、user、coupon等) + * @return 包含二维码图片Base64和token的Map + */ + public Map generateEncryptedQrCode(String originalData, int width, int height, Long expireMinutes, String businessType) { + try { + // 生成加密数据 + Map encryptedInfo = generateEncryptedData(originalData, expireMinutes); + + // 创建二维码内容(包含token、加密数据和业务类型) + Map qrContent = new HashMap<>(); + qrContent.put("token", encryptedInfo.get("token")); + qrContent.put("data", encryptedInfo.get("encryptedData")); + qrContent.put("type", "encrypted"); + + // 添加业务类型(如果提供) + if (StrUtil.isNotBlank(businessType)) { + qrContent.put("businessType", businessType); + } + + String qrDataJson = JSONObject.toJSONString(qrContent); + + // 配置二维码 + QrConfig config = new QrConfig(width, height); + config.setMargin(1); + config.setForeColor(Color.BLACK); + config.setBackColor(Color.WHITE); + + // 生成二维码图片 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + QrCodeUtil.generate(qrDataJson, config, "png", outputStream); + + // 转换为Base64 + String base64Image = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + + Map result = new HashMap<>(); + result.put("qrCodeBase64", base64Image); + result.put("token", encryptedInfo.get("token")); + result.put("originalData", originalData); + result.put("expireMinutes", encryptedInfo.get("expireMinutes")); + result.put("businessType", businessType); + + return result; + + } catch (Exception e) { + throw new RuntimeException("生成加密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 生成加密的二维码图片(自包含模式,无业务类型) + * 向后兼容的重载方法 + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param expireMinutes 过期时间(分钟) + * @return 包含二维码图片Base64和token的Map + */ + public Map generateEncryptedQrCode(String originalData, int width, int height, Long expireMinutes) { + return generateEncryptedQrCode(originalData, width, height, expireMinutes, null); + } + + /** + * 生成业务加密二维码(门店核销模式) + * 使用统一的业务密钥,门店可以直接解密 + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param businessKey 业务密钥(如门店密钥) + * @param expireMinutes 过期时间(分钟) + * @param businessType 业务类型(如:order、coupon、ticket等) + * @return 包含二维码图片Base64的Map + */ + public Map generateBusinessEncryptedQrCode(String originalData, int width, int height, + String businessKey, Long expireMinutes, String businessType) { + try { + if (StrUtil.isBlank(businessKey)) { + throw new IllegalArgumentException("业务密钥不能为空"); + } + + if (expireMinutes == null || expireMinutes <= 0) { + expireMinutes = DEFAULT_EXPIRE_MINUTES; + } + + // 生成唯一的二维码ID + String qrId = RandomUtil.randomString(16); + + // 使用业务密钥加密数据 + AES aes = createAESFromToken(businessKey); + String encryptedData = aes.encryptHex(originalData); + + // 将二维码信息存储到Redis(用于验证和防重复使用) + String qrInfoKey = "qr_info:" + qrId; + Map qrInfo = new HashMap<>(); + qrInfo.put("originalData", originalData); + qrInfo.put("createTime", String.valueOf(System.currentTimeMillis())); + qrInfo.put("businessKey", businessKey); + redisUtil.set(qrInfoKey, JSONObject.toJSONString(qrInfo), expireMinutes, TimeUnit.MINUTES); + + // 创建二维码内容 + Map qrContent = new HashMap<>(); + qrContent.put("qrId", qrId); + qrContent.put("data", encryptedData); + qrContent.put("type", "business_encrypted"); + qrContent.put("expire", String.valueOf(System.currentTimeMillis() + expireMinutes * 60 * 1000)); + + // 添加业务类型(如果提供) + if (StrUtil.isNotBlank(businessType)) { + qrContent.put("businessType", businessType); + } + + String qrDataJson = JSONObject.toJSONString(qrContent); + + // 配置二维码 + QrConfig config = new QrConfig(width, height); + config.setMargin(1); + config.setForeColor(Color.BLACK); + config.setBackColor(Color.WHITE); + + // 生成二维码图片 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + QrCodeUtil.generate(qrDataJson, config, "png", outputStream); + + // 转换为Base64 + String base64Image = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + + Map result = new HashMap<>(); + result.put("qrCodeBase64", base64Image); + result.put("qrId", qrId); + result.put("originalData", originalData); + result.put("expireMinutes", expireMinutes.toString()); + result.put("businessType", businessType); + // 注意:出于安全考虑,不返回businessKey + + return result; + + } catch (Exception e) { + throw new RuntimeException("生成业务加密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 生成业务加密二维码(门店核销模式,无业务类型) + * 向后兼容的重载方法 + * + * @param originalData 原始数据 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param businessKey 业务密钥(如门店密钥) + * @param expireMinutes 过期时间(分钟) + * @return 包含二维码图片Base64的Map + */ + public Map generateBusinessEncryptedQrCode(String originalData, int width, int height, + String businessKey, Long expireMinutes) { + return generateBusinessEncryptedQrCode(originalData, width, height, businessKey, expireMinutes, null); + } + + /** + * 验证并解密二维码内容(自包含模式) + * 二维码包含token和加密数据,扫码方无需额外信息 + * + * @param qrContent 二维码扫描得到的内容 + * @return 解密后的原始数据 + */ + public String verifyAndDecryptQrCode(String qrContent) { + QrCodeDecryptResult result = verifyAndDecryptQrCodeWithResult(qrContent); + return result.getOriginalData(); + } + + /** + * 验证并解密二维码内容(自包含模式,返回完整结果) + * 包含业务类型等详细信息 + * + * @param qrContent 二维码扫描得到的内容 + * @return 包含解密数据和业务类型的完整结果 + */ + public QrCodeDecryptResult verifyAndDecryptQrCodeWithResult(String qrContent) { + try { + // 解析二维码内容 + @SuppressWarnings("unchecked") + Map contentMap = JSONObject.parseObject(qrContent, Map.class); + + String type = contentMap.get("type"); + + // 严格验证二维码类型,防止前端伪造 + if (!isValidQrCodeType(type, "encrypted")) { + throw new RuntimeException("无效的二维码类型或二维码已被篡改"); + } + + String token = contentMap.get("token"); + String encryptedData = contentMap.get("data"); + + // 验证必要字段 + if (StrUtil.isBlank(token) || StrUtil.isBlank(encryptedData)) { + throw new RuntimeException("二维码数据不完整"); + } + + String businessType = contentMap.get("businessType"); // 获取业务类型 + + // 解密数据(自包含模式:token就在二维码中) + String originalData = decryptData(token, encryptedData); + + // 返回包含业务类型的完整结果 + return QrCodeDecryptResult.createEncryptedResult(originalData, businessType); + + } catch (Exception e) { + throw new RuntimeException("验证和解密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 验证并解密二维码内容(业务模式) + * 适用于门店核销场景:门店有统一的解密密钥 + * + * @param qrContent 二维码扫描得到的内容 + * @param businessKey 业务密钥(如门店密钥) + * @return 解密后的原始数据 + */ + public String verifyAndDecryptQrCodeWithBusinessKey(String qrContent, String businessKey) { + try { + // 解析二维码内容 + @SuppressWarnings("unchecked") + Map contentMap = JSONObject.parseObject(qrContent, Map.class); + + String type = contentMap.get("type"); + if (!"business_encrypted".equals(type)) { + throw new RuntimeException("不是业务加密类型的二维码"); + } + + String encryptedData = contentMap.get("data"); + String qrId = contentMap.get("qrId"); // 二维码唯一ID + + // 验证二维码是否已被使用(防止重复核销) + String usedKey = "qr_used:" + qrId; + if (StrUtil.isNotBlank(redisUtil.get(usedKey))) { + throw new RuntimeException("二维码已被使用"); + } + + // 使用业务密钥解密 + AES aes = createAESFromToken(businessKey); + String decryptedData = aes.decryptStr(encryptedData, CharsetUtil.CHARSET_UTF_8); + + // 标记二维码为已使用(24小时过期,防止重复使用) + redisUtil.set(usedKey, "used", 24L, TimeUnit.HOURS); + + return decryptedData; + + } catch (Exception e) { + throw new RuntimeException("业务验证和解密二维码失败: " + e.getMessage(), e); + } + } + + /** + * 删除token(使二维码失效) + * + * @param token 要删除的token + */ + public void invalidateToken(String token) { + if (StrUtil.isNotBlank(token)) { + String redisKey = QR_TOKEN_PREFIX + token; + redisUtil.delete(redisKey); + } + } + + /** + * 检查token是否有效 + * + * @param token 要检查的token + * @return true表示有效,false表示无效或过期 + */ + public boolean isTokenValid(String token) { + if (StrUtil.isBlank(token)) { + return false; + } + + String redisKey = QR_TOKEN_PREFIX + token; + String data = redisUtil.get(redisKey); + return StrUtil.isNotBlank(data); + } + + /** + * 验证二维码类型是否有效 + * + * @param actualType 实际的类型 + * @param expectedType 期望的类型 + * @return true表示有效,false表示无效 + */ + private boolean isValidQrCodeType(String actualType, String expectedType) { + return expectedType.equals(actualType); + } + + /** + * 根据token创建AES加密器 + * + * @param token 密钥token + * @return AES加密器 + */ + private AES createAESFromToken(String token) { + // 使用token生成固定长度的密钥 + String keyString = SecureUtil.md5(token); + // 取前16字节作为AES密钥 + byte[] keyBytes = keyString.substring(0, 16).getBytes(CharsetUtil.CHARSET_UTF_8); + SecretKeySpec secretKey = new SecretKeySpec(keyBytes, SymmetricAlgorithm.AES.getValue()); + return SecureUtil.aes(secretKey.getEncoded()); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/FileServerUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/FileServerUtil.java new file mode 100644 index 0000000..45201d2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/FileServerUtil.java @@ -0,0 +1,401 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import org.apache.tika.Tika; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.MalformedURLException; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 文件上传下载工具类 + * + * @author WebSoft + * @since 2018-12-14 08:38:53 + */ +public class FileServerUtil { + // 除 text/* 外也需要设置输出编码的 content-type + private final static List SET_CHARSET_CONTENT_TYPES = Arrays.asList( + "application/json", + "application/javascript" + ); + + /** + * 上传文件 + * + * @param file MultipartFile + * @param directory 文件保存的目录 + * @param uuidName 是否用uuid命名 + * @return File + */ + public static File upload(MultipartFile file, String directory, boolean uuidName) + throws IOException, IllegalStateException { + File outFile = getUploadFile(file.getOriginalFilename(), directory, uuidName); + if (!outFile.getParentFile().exists()) { + if (!outFile.getParentFile().mkdirs()) { + throw new RuntimeException("make directory fail"); + } + } + file.transferTo(outFile); + return outFile; + } + + /** + * 上传base64格式文件 + * + * @param base64 base64编码字符 + * @param fileName 文件名称, 为空使用uuid命名 + * @param directory 文件保存的目录 + * @return File + */ + public static File upload(String base64, String fileName, String directory) + throws FileNotFoundException, IORuntimeException { + if (StrUtil.isBlank(base64) || !base64.startsWith("data:image/") || !base64.contains(";base64,")) { + throw new RuntimeException("base64 data error"); + } + String suffix = "." + base64.substring(11, base64.indexOf(";")); // 获取文件后缀 + boolean uuidName = StrUtil.isBlank(fileName); + File outFile = getUploadFile(uuidName ? suffix : fileName, directory, uuidName); + byte[] bytes = Base64.getDecoder().decode(base64.substring(base64.indexOf(";") + 8).getBytes()); + IoUtil.write(new FileOutputStream(outFile), true, bytes); + return outFile; + } + + /** + * 获取上传文件位置 + * + * @param name 文件名称 + * @param directory 上传目录 + * @param uuidName 是否使用uuid命名 + * @return File + */ + public static File getUploadFile(String name, String directory, boolean uuidName) { + // 当前日期作为上传子目录 + String dir = new SimpleDateFormat("yyyyMMdd/").format(new Date()); + // 获取文件后缀 + String suffix = (name == null || !name.contains(".")) ? "" : name.substring(name.lastIndexOf(".")); + // 使用uuid命名 + if (uuidName || name == null) { + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + return new File(directory, dir + uuid + suffix); + } + // 使用原名称, 存在相同则加(1) + File file = new File(directory, dir + name); + String prefix = StrUtil.removeSuffix(name, suffix); + int sameSize = 2; + while (file.exists()) { + file = new File(directory, dir + prefix + "(" + sameSize + ")" + suffix); + sameSize++; + } + return file; + } + + /** + * 查看文件, 支持断点续传 + * + * @param file 文件 + * @param pdfDir office转pdf输出目录 + * @param officeHome openOffice安装目录 + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void preview(File file, String pdfDir, String officeHome, + HttpServletResponse response, HttpServletRequest request) { + preview(file, false, null, pdfDir, officeHome, response, request); + } + + /** + * 查看文件, 支持断点续传 + * + * @param file 文件 + * @param forceDownload 是否强制下载 + * @param fileName 强制下载的文件名称 + * @param pdfDir office转pdf输出目录 + * @param officeHome openOffice安装目录 + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void preview(File file, boolean forceDownload, String fileName, String pdfDir, String officeHome, + HttpServletResponse response, HttpServletRequest request) { + CommonUtil.addCrossHeaders(response); + if (file == null || !file.exists()) { + outNotFund(response); + return; + } + if (forceDownload) { + setDownloadHeader(response, StrUtil.isBlank(fileName) ? file.getName() : fileName); + } else { + // office转pdf预览 + if (OpenOfficeUtil.canConverter(file.getName())) { + File pdfFile = OpenOfficeUtil.converterToPDF(file.getAbsolutePath(), pdfDir, officeHome); + if (pdfFile != null) { + file = pdfFile; + } + } + // 获取文件类型 + String contentType = getContentType(file); + if (contentType != null) { + response.setContentType(contentType); + // 设置编码 + if (contentType.startsWith("text/") || SET_CHARSET_CONTENT_TYPES.contains(contentType)) { + try { + String charset = JChardetFacadeUtil.detectCodepage(file.toURI().toURL()); + if (charset != null) { + response.setCharacterEncoding(charset); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + } else { + setDownloadHeader(response, file.getName()); + } + } + response.setHeader("Cache-Control", "public"); + output(file, response, request); + } + + /** + * 查看缩略图 + * + * @param file 原文件 + * @param thumbnail 缩略图文件 + * @param size 缩略图文件的最大值(kb) + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void previewThumbnail(File file, File thumbnail, Integer size, + HttpServletResponse response, HttpServletRequest request) { + // 如果是图片并且缩略图不存在则生成 + if (!thumbnail.exists() && isImage(file)) { + long fileSize = file.length(); + if ((fileSize / 1024) > size) { + try { + if (thumbnail.getParentFile().mkdirs()) { + System.out.println("生成缩略图1>>>>>>>>>>>>>>>> = " + thumbnail); + ImgUtil.scale(file, thumbnail, size / (fileSize / 1024f)); + if (thumbnail.exists() && thumbnail.length() > file.length()) { + FileUtil.copy(file, thumbnail, true); + } + }else{ + System.out.println("生成缩略图2>>>>>>>>>>>>>>>> = " + thumbnail); + ImgUtil.scale(file, thumbnail, size / (fileSize / 1024f)); + if (thumbnail.exists() && thumbnail.length() > file.length()) { + FileUtil.copy(file, thumbnail, true); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + preview(file, null, null, response, request); + return; + } + } + preview(thumbnail.exists() ? thumbnail : file, null, null, response, request); + } + + /** + * 输出文件流, 支持断点续传 + * + * @param file 文件 + * @param response HttpServletResponse + * @param request HttpServletRequest + */ + public static void output(File file, HttpServletResponse response, HttpServletRequest request) { + long length = file.length(); // 文件总大小 + long start = 0, to = length - 1; // 开始读取位置, 结束读取位置 + long lastModified = file.lastModified(); // 文件修改时间 + response.setHeader("Accept-Ranges", "bytes"); + response.setHeader("ETag", "\"" + length + "-" + lastModified + "\""); + response.setHeader("Last-Modified", new Date(lastModified).toString()); + String range = request.getHeader("Range"); + if (range != null) { + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); + String[] ranges = range.replace("bytes=", "").split("-"); + start = Long.parseLong(ranges[0].trim()); + if (ranges.length > 1) { + to = Long.parseLong(ranges[1].trim()); + } + response.setHeader("Content-Range", "bytes " + start + "-" + to + "/" + length); + } + response.setHeader("Content-Length", String.valueOf(to - start + 1)); + try { + output(file, response.getOutputStream(), 2048, start, to); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 输出文件流 + * + * @param file 文件 + * @param os 输出流 + */ + public static void output(File file, OutputStream os) { + output(file, os, null); + } + + /** + * 输出文件流 + * + * @param file 文件 + * @param os 输出流 + * @param size 读取缓冲区大小 + */ + public static void output(File file, OutputStream os, Integer size) { + output(file, os, size, null, null); + } + + /** + * 输出文件流, 支持分片 + * + * @param file 文件 + * @param os 输出流 + * @param size 读取缓冲区大小 + * @param start 开始位置 + * @param to 结束位置 + */ + public static void output(File file, OutputStream os, Integer size, Long start, Long to) { + BufferedInputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + if (start != null) { + long skip = is.skip(start); + if (skip < start) { + System.out.println("ERROR: skip fail[ skipped=" + skip + ", start= " + start + " ]"); + } + to = to - start + 1; + } + byte[] bytes = new byte[size == null ? 2048 : size]; + int len; + if (to == null) { + while ((len = is.read(bytes)) != -1) { + os.write(bytes, 0, len); + } + } else { + while (to > 0 && (len = is.read(bytes)) != -1) { + os.write(bytes, 0, to < len ? (int) ((long) to) : len); + to -= len; + } + } + os.flush(); + } catch (IOException ignored) { + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (os != null) { + try { + os.close(); + } catch (IOException ignored) { + } + } + if (is != null) { + try { + is.close(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + } + } + + /** + * 获取文件类型 + * + * @param file 文件 + * @return String + */ + public static String getContentType(File file) { + String contentType = null; + if (file.exists()) { + try { + contentType = new Tika().detect(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + return contentType; + } + + /** + * 判断文件是否是图片类型 + * + * @param file 文件 + * @return boolean + */ + public static boolean isImage(File file) { + return isImage(getContentType(file)); + } + + /** + * 判断文件是否是图片类型 + * + * @param contentType 文件类型 + * @return boolean + */ + public static boolean isImage(String contentType) { + return contentType != null && contentType.startsWith("image/"); + } + + /** + * 设置下载文件的header + * + * @param response HttpServletResponse + * @param fileName 文件名称 + */ + public static void setDownloadHeader(HttpServletResponse response, String fileName) { + response.setContentType("application/force-download"); + try { + fileName = URLEncoder.encode(fileName, "utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); + } + + /** + * 输出404错误页面 + * + * @param response HttpServletResponse + */ + public static void outNotFund(HttpServletResponse response) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + outMessage("404 Not Found", null, response); + } + + /** + * 输出错误页面 + * + * @param title 标题 + * @param message 内容 + * @param response HttpServletResponse + */ + public static void outMessage(String title, String message, HttpServletResponse response) { + response.setContentType("text/html;charset=UTF-8"); + try { + PrintWriter writer = response.getWriter(); + writer.write(""); + writer.write("" + title + ""); + writer.write("

" + title + "

"); + if (message != null) { + writer.write(message); + } + writer.write("

WebSoft File Server

"); + writer.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/HttpUtils.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/HttpUtils.java new file mode 100644 index 0000000..888acc2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/HttpUtils.java @@ -0,0 +1,311 @@ +package com.gxwebsoft.common.core.utils; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HttpUtils { + + /** + * get + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @return + * @throws Exception + */ + public static HttpResponse doGet(String host, String path, String method, + Map headers, + Map querys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpGet request = new HttpGet(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + return httpClient.execute(request); + } + + /** + * post form + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param bodys + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + Map bodys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (bodys != null) { + List nameValuePairList = new ArrayList(); + + for (String key : bodys.keySet()) { + nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key))); + } + UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8"); + formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); + request.setEntity(formEntity); + } + + return httpClient.execute(request); + } + + /** + * Post String + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + String body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (StringUtils.isNotBlank(body)) { + request.setEntity(new StringEntity(body, "utf-8")); + } + + return httpClient.execute(request); + } + + /** + * Post stream + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + byte[] body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (body != null) { + request.setEntity(new ByteArrayEntity(body)); + } + + return httpClient.execute(request); + } + + /** + * Put String + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPut(String host, String path, String method, + Map headers, + Map querys, + String body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPut request = new HttpPut(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (StringUtils.isNotBlank(body)) { + request.setEntity(new StringEntity(body, "utf-8")); + } + + return httpClient.execute(request); + } + + /** + * Put stream + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPut(String host, String path, String method, + Map headers, + Map querys, + byte[] body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPut request = new HttpPut(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (body != null) { + request.setEntity(new ByteArrayEntity(body)); + } + + return httpClient.execute(request); + } + + /** + * Delete + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @return + * @throws Exception + */ + public static HttpResponse doDelete(String host, String path, String method, + Map headers, + Map querys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpDelete request = new HttpDelete(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + return httpClient.execute(request); + } + + private static String buildUrl(String host, String path, Map querys) throws UnsupportedEncodingException { + StringBuilder sbUrl = new StringBuilder(); + sbUrl.append(host); + if (!StringUtils.isBlank(path)) { + sbUrl.append(path); + } + if (null != querys) { + StringBuilder sbQuery = new StringBuilder(); + for (Map.Entry query : querys.entrySet()) { + if (0 < sbQuery.length()) { + sbQuery.append("&"); + } + if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) { + sbQuery.append(query.getValue()); + } + if (!StringUtils.isBlank(query.getKey())) { + sbQuery.append(query.getKey()); + if (!StringUtils.isBlank(query.getValue())) { + sbQuery.append("="); + sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8")); + } + } + } + if (0 < sbQuery.length()) { + sbUrl.append("?").append(sbQuery); + } + } + + return sbUrl.toString(); + } + + private static HttpClient wrapClient(String host) { + HttpClient httpClient = new DefaultHttpClient(); + if (host.startsWith("https://")) { + sslClient(httpClient); + } + + return httpClient; + } + + private static void sslClient(HttpClient httpClient) { + try { + SSLContext ctx = SSLContext.getInstance("TLS"); + X509TrustManager tm = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted(X509Certificate[] xcs, String str) { + + } + public void checkServerTrusted(X509Certificate[] xcs, String str) { + + } + }; + ctx.init(null, new TrustManager[] { tm }, null); + SSLSocketFactory ssf = new SSLSocketFactory(ctx); + ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + ClientConnectionManager ccm = httpClient.getConnectionManager(); + SchemeRegistry registry = ccm.getSchemeRegistry(); + registry.register(new Scheme("https", 443, ssf)); + } catch (KeyManagementException ex) { + throw new RuntimeException(ex); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/ImageUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/ImageUtil.java new file mode 100644 index 0000000..b345923 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/ImageUtil.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.codec.Base64Encoder; + +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Iterator; +import java.io.File; + +public class ImageUtil { + public static String ImageBase64(String imgUrl) { + URL url = null; + InputStream is = null; + ByteArrayOutputStream outStream = null; + HttpURLConnection httpUrl = null; + try{ + url = new URL(imgUrl); + httpUrl = (HttpURLConnection) url.openConnection(); + httpUrl.connect(); + httpUrl.getInputStream(); + is = httpUrl.getInputStream(); + + outStream = new ByteArrayOutputStream(); + //创建一个Buffer字符串 + byte[] buffer = new byte[1024]; + //每次读取的字符串长度,如果为-1,代表全部读取完毕 + int len = 0; + //使用一个输入流从buffer里把数据读取出来 + while( (len=is.read(buffer)) != -1 ){ + //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 + outStream.write(buffer, 0, len); + } + // 对字节数组Base64编码 + return new Base64Encoder().encode(outStream.toByteArray()); + }catch (Exception e) { + e.printStackTrace(); + } + finally{ + if(is != null) { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(outStream != null) { + try { + outStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if(httpUrl != null) { + httpUrl.disconnect(); + } + } + return null; + } + + + public static void adjustQuality(File inputFile, File outputFile, float quality) throws IOException { + // 读取图片文件 + BufferedImage image = ImageIO.read(inputFile); + + // 获取JPEG ImageWriters的迭代器 + Iterator iter = ImageIO.getImageWritersByFormatName("jpeg"); + ImageWriter writer = iter.next(); + + // 创建输出文件 + ImageOutputStream ios = ImageIO.createImageOutputStream(outputFile); + writer.setOutput(ios); + + // 创建ImageWriteParam并设置压缩质量 + ImageWriteParam iwp = writer.getDefaultWriteParam(); + if (iwp.canWriteCompressed()) { + iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + iwp.setCompressionQuality(quality); // 设置质量,1.0为最好,0.0最差 + } + + // 写入图片 + writer.write(null, new IIOImage(image, null, null), iwp); + writer.dispose(); + ios.close(); + } + +} + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/JChardetFacadeUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/JChardetFacadeUtil.java new file mode 100644 index 0000000..1b49fb7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/JChardetFacadeUtil.java @@ -0,0 +1,2025 @@ +package com.gxwebsoft.common.core.utils; + +import java.io.*; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; + +/** + * 文件编码检测工具, 核心代码来自 cpDetector 和 jChardet, 可以检测大多数文件的编码 + * + * @author WebSoft + * @since 2020-09-15 09:24:20 + */ +public class JChardetFacadeUtil { + + public static String detectCodepage(URL url) { + try { + Charset ret = JChardetFacade.getInstance().detectCodepage(url); + return ret == null ? null : ret.name(); + } catch (Exception ignored) { + } + return null; + } + + /** + * 下面代码来自: https://github.com/r91987/cpdetector + */ + public static class JChardetFacade extends AbstractCodepageDetector implements nsICharsetDetectionObserver { + private static JChardetFacade instance = null; + private static nsDetector det; + private byte[] buf = new byte[4096]; + private Charset codpage = null; + private boolean m_guessing = true; + private int amountOfVerifiers = 0; + + private JChardetFacade() { + det = new nsDetector(0); + det.Init(this); + this.amountOfVerifiers = det.getProbableCharsets().length; + } + + public static JChardetFacade getInstance() { + if (instance == null) { + instance = new JChardetFacade(); + } + + return instance; + } + + public synchronized Charset detectCodepage(InputStream in, int length) throws IOException { + this.Reset(); + int read = 0; + boolean done = false; + boolean isAscii = true; + Charset ret = null; + + int len; + do { + len = in.read(this.buf, 0, Math.min(this.buf.length, length - read)); + if (len > 0) { + read += len; + } + + if (!done) { + done = det.DoIt(this.buf, len, false); + } + } while (len > 0 && !done); + + det.DataEnd(); + if (this.codpage == null) { + if (this.m_guessing) { + ret = this.guess(); + } + } else { + ret = this.codpage; + } + return ret; + } + + private Charset guess() { + Charset ret = null; + String[] possibilities = det.getProbableCharsets(); + if (possibilities.length == this.amountOfVerifiers) { + ret = Charset.forName("US-ASCII"); + } else { + String check = possibilities[0]; + if (!check.equalsIgnoreCase("nomatch")) { + for (int i = 0; ret == null && i < possibilities.length; ++i) { + try { + ret = Charset.forName(possibilities[i]); + } catch (UnsupportedCharsetException ignored) { + } + } + } + } + return ret; + } + + public void Notify(String charset) { + this.codpage = Charset.forName(charset); + } + + public void Reset() { + det.Reset(); + this.codpage = null; + } + + public boolean isGuessing() { + return this.m_guessing; + } + + public synchronized void setGuessing(boolean guessing) { + this.m_guessing = guessing; + } + } + + /** + * + */ + public static abstract class AbstractCodepageDetector implements ICodepageDetector { + public AbstractCodepageDetector() { + } + + public Charset detectCodepage(URL url) throws IOException { + BufferedInputStream in = new BufferedInputStream(url.openStream()); + Charset result = this.detectCodepage(in, 2147483647); + in.close(); + return result; + } + + public final Reader open(URL url) throws IOException { + Reader ret = null; + Charset cs = this.detectCodepage(url); + if (cs != null) { + ret = new InputStreamReader(new BufferedInputStream(url.openStream()), cs); + } + + return ret; + } + + public int compareTo(Object o) { + String other = o.getClass().getName(); + String mine = this.getClass().getName(); + return mine.compareTo(other); + } + } + + /** + * + */ + interface ICodepageDetector extends Serializable, Comparable { + Reader open(URL var1) throws IOException; + + Charset detectCodepage(URL var1) throws IOException; + + Charset detectCodepage(InputStream var1, int var2) throws IOException; + } + + /** + * 以下代码开始是由Mozilla组织提供的JChardet, 它可以检测大多数文件的编码 + * http://jchardet.sourceforge.net/ + */ + public static class nsDetector extends nsPSMDetector implements nsICharsetDetector { + nsICharsetDetectionObserver mObserver = null; + + public nsDetector() { + } + + public nsDetector(int var1) { + super(var1); + } + + public void Init(nsICharsetDetectionObserver var1) { + this.mObserver = var1; + } + + public boolean DoIt(byte[] var1, int var2, boolean var3) { + if (var1 != null && !var3) { + this.HandleData(var1, var2); + return this.mDone; + } else { + return false; + } + } + + public void Done() { + this.DataEnd(); + } + + public void Report(String var1) { + if (this.mObserver != null) { + this.mObserver.Notify(var1); + } + + } + + public boolean isAscii(byte[] var1, int var2) { + for (int var3 = 0; var3 < var2; ++var3) { + if ((128 & var1[var3]) != 0) { + return false; + } + } + + return true; + } + } + + /** + * + */ + public static abstract class nsPSMDetector { + public static final int ALL = 0; + public static final int JAPANESE = 1; + public static final int CHINESE = 2; + public static final int SIMPLIFIED_CHINESE = 3; + public static final int TRADITIONAL_CHINESE = 4; + public static final int KOREAN = 5; + public static final int NO_OF_LANGUAGES = 6; + public static final int MAX_VERIFIERS = 16; + nsVerifier[] mVerifier; + nsEUCStatistics[] mStatisticsData; + nsEUCSampler mSampler = new nsEUCSampler(); + byte[] mState = new byte[16]; + int[] mItemIdx = new int[16]; + int mItems; + int mClassItems; + boolean mDone; + boolean mRunSampler; + boolean mClassRunSampler; + + public nsPSMDetector() { + this.initVerifiers(0); + this.Reset(); + } + + public nsPSMDetector(int var1) { + this.initVerifiers(var1); + this.Reset(); + } + + public nsPSMDetector(int var1, nsVerifier[] var2, nsEUCStatistics[] var3) { + this.mClassRunSampler = var3 != null; + this.mStatisticsData = var3; + this.mVerifier = var2; + this.mClassItems = var1; + this.Reset(); + } + + public void Reset() { + this.mRunSampler = this.mClassRunSampler; + this.mDone = false; + this.mItems = this.mClassItems; + + for (int var1 = 0; var1 < this.mItems; this.mItemIdx[var1] = var1++) { + this.mState[var1] = 0; + } + + this.mSampler.Reset(); + } + + protected void initVerifiers(int var1) { + boolean var2 = false; + int var3; + if (var1 >= 0 && var1 < 6) { + var3 = var1; + } else { + var3 = 0; + } + + this.mVerifier = null; + this.mStatisticsData = null; + if (var3 == 4) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsBIG5Verifier(), new nsISO2022CNVerifier(), new nsEUCTWVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + this.mStatisticsData = new nsEUCStatistics[]{null, new Big5Statistics(), null, new EUCTWStatistics(), null, null, null}; + } else if (var3 == 5) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsEUCKRVerifier(), new nsISO2022KRVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + } else if (var3 == 3) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsGB2312Verifier(), new nsGB18030Verifier(), new nsISO2022CNVerifier(), new nsHZVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + } else if (var3 == 1) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsSJISVerifier(), new nsEUCJPVerifier(), new nsISO2022JPVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + } else if (var3 == 2) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsGB2312Verifier(), new nsGB18030Verifier(), new nsBIG5Verifier(), new nsISO2022CNVerifier(), new nsHZVerifier(), new nsEUCTWVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + this.mStatisticsData = new nsEUCStatistics[]{null, new GB2312Statistics(), null, new Big5Statistics(), null, null, new EUCTWStatistics(), null, null, null}; + } else if (var3 == 0) { + this.mVerifier = new nsVerifier[]{new nsUTF8Verifier(), new nsSJISVerifier(), new nsEUCJPVerifier(), new nsISO2022JPVerifier(), new nsEUCKRVerifier(), new nsISO2022KRVerifier(), new nsBIG5Verifier(), new nsEUCTWVerifier(), new nsGB2312Verifier(), new nsGB18030Verifier(), new nsISO2022CNVerifier(), new nsHZVerifier(), new nsCP1252Verifier(), new nsUCS2BEVerifier(), new nsUCS2LEVerifier()}; + this.mStatisticsData = new nsEUCStatistics[]{null, null, new EUCJPStatistics(), null, new EUCKRStatistics(), null, new Big5Statistics(), new EUCTWStatistics(), new GB2312Statistics(), null, null, null, null, null, null}; + } + + this.mClassRunSampler = this.mStatisticsData != null; + this.mClassItems = this.mVerifier.length; + } + + public abstract void Report(String var1); + + public boolean HandleData(byte[] var1, int var2) { + for (int var3 = 0; var3 < var2; ++var3) { + byte var5 = var1[var3]; + int var4 = 0; + + while (var4 < this.mItems) { + byte var6 = nsVerifier.getNextState(this.mVerifier[this.mItemIdx[var4]], var5, this.mState[var4]); + if (var6 == 2) { + this.Report(this.mVerifier[this.mItemIdx[var4]].charset()); + this.mDone = true; + return this.mDone; + } + + if (var6 == 1) { + --this.mItems; + if (var4 < this.mItems) { + this.mItemIdx[var4] = this.mItemIdx[this.mItems]; + this.mState[var4] = this.mState[this.mItems]; + } + } else { + this.mState[var4++] = var6; + } + } + + if (this.mItems <= 1) { + if (1 == this.mItems) { + this.Report(this.mVerifier[this.mItemIdx[0]].charset()); + } + + this.mDone = true; + return this.mDone; + } + + int var7 = 0; + int var8 = 0; + + for (var4 = 0; var4 < this.mItems; ++var4) { + if (!this.mVerifier[this.mItemIdx[var4]].isUCS2() && !this.mVerifier[this.mItemIdx[var4]].isUCS2()) { + ++var7; + var8 = var4; + } + } + + if (1 == var7) { + this.Report(this.mVerifier[this.mItemIdx[var8]].charset()); + this.mDone = true; + return this.mDone; + } + } + + if (this.mRunSampler) { + this.Sample(var1, var2); + } + + return this.mDone; + } + + public void DataEnd() { + if (!this.mDone) { + if (this.mItems == 2) { + if (this.mVerifier[this.mItemIdx[0]].charset().equals("GB18030")) { + this.Report(this.mVerifier[this.mItemIdx[1]].charset()); + this.mDone = true; + } else if (this.mVerifier[this.mItemIdx[1]].charset().equals("GB18030")) { + this.Report(this.mVerifier[this.mItemIdx[0]].charset()); + this.mDone = true; + } + } + + if (this.mRunSampler) { + this.Sample((byte[]) null, 0, true); + } + + } + } + + public void Sample(byte[] var1, int var2) { + this.Sample(var1, var2, false); + } + + public void Sample(byte[] var1, int var2, boolean var3) { + int var4 = 0; + int var6 = 0; + + int var5; + for (var5 = 0; var5 < this.mItems; ++var5) { + if (null != this.mStatisticsData[this.mItemIdx[var5]]) { + ++var6; + } + + if (!this.mVerifier[this.mItemIdx[var5]].isUCS2() && !this.mVerifier[this.mItemIdx[var5]].charset().equals("GB18030")) { + ++var4; + } + } + + this.mRunSampler = var6 > 1; + if (this.mRunSampler) { + this.mRunSampler = this.mSampler.Sample(var1, var2); + if ((var3 && this.mSampler.GetSomeData() || this.mSampler.EnoughData()) && var6 == var4) { + this.mSampler.CalFreq(); + int var7 = -1; + int var8 = 0; + float var9 = 0.0F; + + for (var5 = 0; var5 < this.mItems; ++var5) { + if (null != this.mStatisticsData[this.mItemIdx[var5]] && !this.mVerifier[this.mItemIdx[var5]].charset().equals("Big5")) { + float var10 = this.mSampler.GetScore(this.mStatisticsData[this.mItemIdx[var5]].mFirstByteFreq(), this.mStatisticsData[this.mItemIdx[var5]].mFirstByteWeight(), this.mStatisticsData[this.mItemIdx[var5]].mSecondByteFreq(), this.mStatisticsData[this.mItemIdx[var5]].mSecondByteWeight()); + if (0 == var8++ || var9 > var10) { + var9 = var10; + var7 = var5; + } + } + } + + if (var7 >= 0) { + this.Report(this.mVerifier[this.mItemIdx[var7]].charset()); + this.mDone = true; + } + } + } + + } + + public String[] getProbableCharsets() { + String[] var1; + if (this.mItems <= 0) { + var1 = new String[]{"nomatch"}; + return var1; + } else { + var1 = new String[this.mItems]; + + for (int var2 = 0; var2 < this.mItems; ++var2) { + var1[var2] = this.mVerifier[this.mItemIdx[var2]].charset(); + } + + return var1; + } + } + } + + /** + * + */ + public static interface nsICharsetDetectionObserver { + void Notify(String var1); + } + + /** + * + */ + public static interface nsICharsetDetector { + void Init(nsICharsetDetectionObserver var1); + + boolean DoIt(byte[] var1, int var2, boolean var3); + + void Done(); + } + + /** + * + */ + public static abstract class nsVerifier { + static final byte eStart = 0; + static final byte eError = 1; + static final byte eItsMe = 2; + static final int eidxSft4bits = 3; + static final int eSftMsk4bits = 7; + static final int eBitSft4bits = 2; + static final int eUnitMsk4bits = 15; + + nsVerifier() { + } + + public abstract String charset(); + + public abstract int stFactor(); + + public abstract int[] cclass(); + + public abstract int[] states(); + + public abstract boolean isUCS2(); + + public static byte getNextState(nsVerifier var0, byte var1, byte var2) { + return (byte) (255 & var0.states()[(var2 * var0.stFactor() + (var0.cclass()[(var1 & 255) >> 3] >> ((var1 & 7) << 2) & 15) & 255) >> 3] >> ((var2 * var0.stFactor() + (var0.cclass()[(var1 & 255) >> 3] >> ((var1 & 7) << 2) & 15) & 255 & 7) << 2) & 15); + } + } + + /** + * + */ + public static class nsEUCSampler { + int mTotal = 0; + int mThreshold = 200; + int mState = 0; + public int[] mFirstByteCnt = new int[94]; + public int[] mSecondByteCnt = new int[94]; + public float[] mFirstByteFreq = new float[94]; + public float[] mSecondByteFreq = new float[94]; + + public nsEUCSampler() { + this.Reset(); + } + + public void Reset() { + this.mTotal = 0; + this.mState = 0; + + for (int var1 = 0; var1 < 94; ++var1) { + this.mFirstByteCnt[var1] = this.mSecondByteCnt[var1] = 0; + } + + } + + boolean EnoughData() { + return this.mTotal > this.mThreshold; + } + + boolean GetSomeData() { + return this.mTotal > 1; + } + + boolean Sample(byte[] var1, int var2) { + if (this.mState == 1) { + return false; + } else { + int var3 = 0; + + for (int var4 = 0; var4 < var2 && 1 != this.mState; ++var3) { + int var10002; + switch (this.mState) { + case 0: + if ((var1[var3] & 128) != 0) { + if (255 != (255 & var1[var3]) && 161 <= (255 & var1[var3])) { + ++this.mTotal; + var10002 = this.mFirstByteCnt[(255 & var1[var3]) - 161]++; + this.mState = 2; + } else { + this.mState = 1; + } + } + case 1: + break; + case 2: + if ((var1[var3] & 128) != 0) { + if (255 != (255 & var1[var3]) && 161 <= (255 & var1[var3])) { + ++this.mTotal; + var10002 = this.mSecondByteCnt[(255 & var1[var3]) - 161]++; + this.mState = 0; + } else { + this.mState = 1; + } + } else { + this.mState = 1; + } + break; + default: + this.mState = 1; + } + + ++var4; + } + + return 1 != this.mState; + } + } + + void CalFreq() { + for (int var1 = 0; var1 < 94; ++var1) { + this.mFirstByteFreq[var1] = (float) this.mFirstByteCnt[var1] / (float) this.mTotal; + this.mSecondByteFreq[var1] = (float) this.mSecondByteCnt[var1] / (float) this.mTotal; + } + + } + + float GetScore(float[] var1, float var2, float[] var3, float var4) { + return var2 * this.GetScore(var1, this.mFirstByteFreq) + var4 * this.GetScore(var3, this.mSecondByteFreq); + } + + float GetScore(float[] var1, float[] var2) { + float var4 = 0.0F; + + for (int var5 = 0; var5 < 94; ++var5) { + float var3 = var1[var5] - var2[var5]; + var4 += var3 * var3; + } + + return (float) Math.sqrt((double) var4) / 94.0F; + } + } + + /** + * + */ + public static abstract class nsEUCStatistics { + public abstract float[] mFirstByteFreq(); + + public abstract float mFirstByteStdDev(); + + public abstract float mFirstByteMean(); + + public abstract float mFirstByteWeight(); + + public abstract float[] mSecondByteFreq(); + + public abstract float mSecondByteStdDev(); + + public abstract float mSecondByteMean(); + + public abstract float mSecondByteWeight(); + + public nsEUCStatistics() { + } + } + + /** + * + */ + public static class EUCJPStatistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public EUCJPStatistics() { + mFirstByteFreq = new float[]{0.364808F, 0.0F, 0.0F, 0.145325F, 0.304891F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.001835F, 0.010771F, 0.006462F, 0.001157F, 0.002114F, 0.003231F, 0.001356F, 0.00742F, 0.004189F, 0.003231F, 0.003032F, 0.03319F, 0.006303F, 0.006064F, 0.009973F, 0.002354F, 0.00367F, 0.009135F, 0.001675F, 0.002792F, 0.002194F, 0.01472F, 0.011928F, 8.78E-4F, 0.013124F, 0.001077F, 0.009295F, 0.003471F, 0.002872F, 0.002433F, 9.57E-4F, 0.001636F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 8.0E-5F, 2.79E-4F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 8.0E-5F, 0.0F}; + mFirstByteStdDev = 0.050407F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.640871F; + mSecondByteFreq = new float[]{0.002473F, 0.039134F, 0.152745F, 0.009694F, 3.59E-4F, 0.02218F, 7.58E-4F, 0.004308F, 1.6E-4F, 0.002513F, 0.003072F, 0.001316F, 0.00383F, 0.001037F, 0.00359F, 9.57E-4F, 1.6E-4F, 2.39E-4F, 0.006462F, 0.001596F, 0.031554F, 0.001316F, 0.002194F, 0.016555F, 0.003271F, 6.78E-4F, 5.98E-4F, 0.206438F, 7.18E-4F, 0.001077F, 0.00371F, 0.001356F, 0.001356F, 4.39E-4F, 0.004388F, 0.005704F, 8.78E-4F, 0.010172F, 0.007061F, 0.01468F, 6.38E-4F, 0.02573F, 0.002792F, 7.18E-4F, 0.001795F, 0.091551F, 7.58E-4F, 0.003909F, 5.58E-4F, 0.031195F, 0.007061F, 0.001316F, 0.022579F, 0.006981F, 0.00726F, 0.001117F, 2.39E-4F, 0.012127F, 8.78E-4F, 0.00379F, 0.001077F, 7.58E-4F, 0.002114F, 0.002234F, 6.78E-4F, 0.002992F, 0.003311F, 0.023416F, 0.001237F, 0.002753F, 0.005146F, 0.002194F, 0.007021F, 0.008497F, 0.013763F, 0.011768F, 0.006303F, 0.001915F, 6.38E-4F, 0.008776F, 9.18E-4F, 0.003431F, 0.057603F, 4.39E-4F, 4.39E-4F, 7.58E-4F, 0.002872F, 0.001675F, 0.01105F, 0.0F, 2.79E-4F, 0.012127F, 7.18E-4F, 0.00738F}; + mSecondByteStdDev = 0.028247F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.359129F; + } + } + + /** + * + */ + public static class nsEUCJPVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsEUCJPVerifier() { + cclass = new int[32]; + cclass[0] = 1145324612; + cclass[1] = 1430537284; + cclass[2] = 1145324612; + cclass[3] = 1145328708; + cclass[4] = 1145324612; + cclass[5] = 1145324612; + cclass[6] = 1145324612; + cclass[7] = 1145324612; + cclass[8] = 1145324612; + cclass[9] = 1145324612; + cclass[10] = 1145324612; + cclass[11] = 1145324612; + cclass[12] = 1145324612; + cclass[13] = 1145324612; + cclass[14] = 1145324612; + cclass[15] = 1145324612; + cclass[16] = 1431655765; + cclass[17] = 827675989; + cclass[18] = 1431655765; + cclass[19] = 1431655765; + cclass[20] = 572662309; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 0; + cclass[29] = 0; + cclass[30] = 0; + cclass[31] = 1342177280; + states = new int[5]; + states[0] = 286282563; + states[1] = 572657937; + states[2] = 286265378; + states[3] = 319885329; + states[4] = 4371; + charset = "EUC-JP"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class EUCKRStatistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public EUCKRStatistics() { + mFirstByteFreq = new float[]{0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 4.12E-4F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.057502F, 0.033182F, 0.002267F, 0.016076F, 0.014633F, 0.032976F, 0.004122F, 0.011336F, 0.058533F, 0.024526F, 0.025969F, 0.054411F, 0.01958F, 0.063273F, 0.113974F, 0.029885F, 0.150041F, 0.059151F, 0.002679F, 0.009893F, 0.014839F, 0.026381F, 0.015045F, 0.069456F, 0.08986F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}; + mFirstByteStdDev = 0.025593F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.647437F; + mSecondByteFreq = new float[]{0.016694F, 0.0F, 0.012778F, 0.030091F, 0.002679F, 0.006595F, 0.001855F, 8.24E-4F, 0.005977F, 0.00474F, 0.003092F, 8.24E-4F, 0.01958F, 0.037304F, 0.008244F, 0.014633F, 0.001031F, 0.0F, 0.003298F, 0.002061F, 0.006183F, 0.005977F, 8.24E-4F, 0.021847F, 0.014839F, 0.052968F, 0.017312F, 0.007626F, 4.12E-4F, 8.24E-4F, 0.011129F, 0.0F, 4.12E-4F, 0.001649F, 0.005977F, 0.065746F, 0.020198F, 0.021434F, 0.014633F, 0.004122F, 0.001649F, 8.24E-4F, 8.24E-4F, 0.051937F, 0.01958F, 0.023289F, 0.026381F, 0.040396F, 0.009068F, 0.001443F, 0.00371F, 0.00742F, 0.001443F, 0.01319F, 0.002885F, 4.12E-4F, 0.003298F, 0.025969F, 4.12E-4F, 4.12E-4F, 0.006183F, 0.003298F, 0.066983F, 0.002679F, 0.002267F, 0.011129F, 4.12E-4F, 0.010099F, 0.015251F, 0.007626F, 0.043899F, 0.00371F, 0.002679F, 0.001443F, 0.010923F, 0.002885F, 0.009068F, 0.019992F, 4.12E-4F, 0.00845F, 0.005153F, 0.0F, 0.010099F, 0.0F, 0.001649F, 0.01216F, 0.011542F, 0.006595F, 0.001855F, 0.010923F, 4.12E-4F, 0.023702F, 0.00371F, 0.001855F}; + mSecondByteStdDev = 0.013937F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.352563F; + } + } + + /** + * + */ + public static class nsEUCKRVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsEUCKRVerifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 286331153; + cclass[9] = 286331153; + cclass[10] = 286331153; + cclass[11] = 286331153; + cclass[12] = 286331153; + cclass[13] = 286331153; + cclass[14] = 286331153; + cclass[15] = 286331153; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 572662304; + cclass[21] = 858923554; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662322; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 35791394; + states = new int[2]; + states[0] = 286331649; + states[1] = 1122850; + charset = "EUC-KR"; + stFactor = 4; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class EUCTWStatistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public EUCTWStatistics() { + mFirstByteFreq = new float[]{0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.119286F, 0.052233F, 0.044126F, 0.052494F, 0.045906F, 0.019038F, 0.032465F, 0.026252F, 0.025502F, 0.015963F, 0.052493F, 0.019256F, 0.015137F, 0.031782F, 0.01737F, 0.018494F, 0.015575F, 0.016621F, 0.007444F, 0.011642F, 0.013916F, 0.019159F, 0.016445F, 0.007851F, 0.011079F, 0.022842F, 0.015513F, 0.010033F, 0.00995F, 0.010347F, 0.013103F, 0.015371F, 0.012502F, 0.007436F, 0.018253F, 0.014134F, 0.008907F, 0.005411F, 0.00957F, 0.013598F, 0.006092F, 0.007409F, 0.008432F, 0.005816F, 0.009349F, 0.005472F, 0.00717F, 0.00742F, 0.003681F, 0.007523F, 0.00461F, 0.006154F, 0.003348F, 0.005074F, 0.005922F, 0.005254F, 0.004682F, 0.002093F, 0.0F}; + mFirstByteStdDev = 0.016681F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.715599F; + mSecondByteFreq = new float[]{0.028933F, 0.011371F, 0.011053F, 0.007232F, 0.010192F, 0.004093F, 0.015043F, 0.011752F, 0.022387F, 0.00841F, 0.012448F, 0.007473F, 0.003594F, 0.007139F, 0.018912F, 0.006083F, 0.003302F, 0.010215F, 0.008791F, 0.024236F, 0.014107F, 0.014108F, 0.010303F, 0.009728F, 0.007877F, 0.009719F, 0.007952F, 0.021028F, 0.005764F, 0.009341F, 0.006591F, 0.012517F, 0.005921F, 0.008982F, 0.008771F, 0.012802F, 0.005926F, 0.008342F, 0.003086F, 0.006843F, 0.007576F, 0.004734F, 0.016404F, 0.008803F, 0.008071F, 0.005349F, 0.008566F, 0.01084F, 0.015401F, 0.031904F, 0.00867F, 0.011479F, 0.010936F, 0.007617F, 0.008995F, 0.008114F, 0.008658F, 0.005934F, 0.010452F, 0.009142F, 0.004519F, 0.008339F, 0.007476F, 0.007027F, 0.006025F, 0.021804F, 0.024248F, 0.015895F, 0.003768F, 0.010171F, 0.010007F, 0.010178F, 0.008316F, 0.006832F, 0.006364F, 0.009141F, 0.009148F, 0.012081F, 0.011914F, 0.004464F, 0.014257F, 0.006907F, 0.011292F, 0.018622F, 0.008149F, 0.004636F, 0.006612F, 0.013478F, 0.012614F, 0.005186F, 0.048285F, 0.006816F, 0.006743F, 0.008671F}; + mSecondByteStdDev = 0.00663F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.284401F; + } + } + + /** + * + */ + public static class nsEUCTWVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsEUCTWVerifier() { + cclass = new int[32]; + cclass[0] = 572662306; + cclass[1] = 2236962; + cclass[2] = 572662306; + cclass[3] = 572654114; + cclass[4] = 572662306; + cclass[5] = 572662306; + cclass[6] = 572662306; + cclass[7] = 572662306; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 572662306; + cclass[16] = 0; + cclass[17] = 100663296; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 1145324592; + cclass[21] = 286331221; + cclass[22] = 286331153; + cclass[23] = 286331153; + cclass[24] = 858985233; + cclass[25] = 858993459; + cclass[26] = 858993459; + cclass[27] = 858993459; + cclass[28] = 858993459; + cclass[29] = 858993459; + cclass[30] = 858993459; + cclass[31] = 53687091; + states = new int[6]; + states[0] = 338898961; + states[1] = 571543825; + states[2] = 269623842; + states[3] = 286330880; + states[4] = 1052949; + states[5] = 16; + charset = "x-euc-tw"; + stFactor = 7; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class Big5Statistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public Big5Statistics() { + mFirstByteFreq = new float[]{0.0F, 0.0F, 0.0F, 0.114427F, 0.061058F, 0.075598F, 0.048386F, 0.063966F, 0.027094F, 0.095787F, 0.029525F, 0.031331F, 0.036915F, 0.021805F, 0.019349F, 0.037496F, 0.018068F, 0.01276F, 0.030053F, 0.017339F, 0.016731F, 0.019501F, 0.01124F, 0.032973F, 0.016658F, 0.015872F, 0.021458F, 0.012378F, 0.017003F, 0.020802F, 0.012454F, 0.009239F, 0.012829F, 0.007922F, 0.010079F, 0.009815F, 0.010104F, 0.0F, 0.0F, 0.0F, 5.3E-5F, 3.5E-5F, 1.05E-4F, 3.1E-5F, 8.8E-5F, 2.7E-5F, 2.7E-5F, 2.6E-5F, 3.5E-5F, 2.4E-5F, 3.4E-5F, 3.75E-4F, 2.5E-5F, 2.8E-5F, 2.0E-5F, 2.4E-5F, 2.8E-5F, 3.1E-5F, 5.9E-5F, 4.0E-5F, 3.0E-5F, 7.9E-5F, 3.7E-5F, 4.0E-5F, 2.3E-5F, 3.0E-5F, 2.7E-5F, 6.4E-5F, 2.0E-5F, 2.7E-5F, 2.5E-5F, 7.4E-5F, 1.9E-5F, 2.3E-5F, 2.1E-5F, 1.8E-5F, 1.7E-5F, 3.5E-5F, 2.1E-5F, 1.9E-5F, 2.5E-5F, 1.7E-5F, 3.7E-5F, 1.8E-5F, 1.8E-5F, 1.9E-5F, 2.2E-5F, 3.3E-5F, 3.2E-5F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}; + mFirstByteStdDev = 0.020606F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.675261F; + mSecondByteFreq = new float[]{0.020256F, 0.003293F, 0.045811F, 0.01665F, 0.007066F, 0.004146F, 0.009229F, 0.007333F, 0.003296F, 0.005239F, 0.008282F, 0.003791F, 0.006116F, 0.003536F, 0.004024F, 0.016654F, 0.009334F, 0.005429F, 0.033392F, 0.006121F, 0.008983F, 0.002801F, 0.004221F, 0.010357F, 0.014695F, 0.077937F, 0.006314F, 0.00402F, 0.007331F, 0.00715F, 0.005341F, 0.009195F, 0.00535F, 0.005698F, 0.004472F, 0.007242F, 0.004039F, 0.011154F, 0.016184F, 0.004741F, 0.012814F, 0.007679F, 0.008045F, 0.016631F, 0.009451F, 0.016487F, 0.007287F, 0.012688F, 0.017421F, 0.013205F, 0.03148F, 0.003404F, 0.009149F, 0.008921F, 0.007514F, 0.008683F, 0.008203F, 0.031403F, 0.011733F, 0.015617F, 0.015306F, 0.004004F, 0.010899F, 0.009961F, 0.008388F, 0.01092F, 0.003925F, 0.008585F, 0.009108F, 0.015546F, 0.004659F, 0.006934F, 0.007023F, 0.020252F, 0.005387F, 0.024704F, 0.006963F, 0.002625F, 0.009512F, 0.002971F, 0.008233F, 0.01F, 0.011973F, 0.010553F, 0.005945F, 0.006349F, 0.009401F, 0.008577F, 0.008186F, 0.008159F, 0.005033F, 0.008714F, 0.010614F, 0.006554F}; + mSecondByteStdDev = 0.009909F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.324739F; + } + } + + /** + * + */ + public static class nsBIG5Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsBIG5Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 304226850; + cclass[16] = 1145324612; + cclass[17] = 1145324612; + cclass[18] = 1145324612; + cclass[19] = 1145324612; + cclass[20] = 858993460; + cclass[21] = 858993459; + cclass[22] = 858993459; + cclass[23] = 858993459; + cclass[24] = 858993459; + cclass[25] = 858993459; + cclass[26] = 858993459; + cclass[27] = 858993459; + cclass[28] = 858993459; + cclass[29] = 858993459; + cclass[30] = 858993459; + cclass[31] = 53687091; + states = new int[3]; + states[0] = 286339073; + states[1] = 304226833; + states[2] = 1; + charset = "Big5"; + stFactor = 5; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class GB2312Statistics extends nsEUCStatistics { + static float[] mFirstByteFreq; + static float mFirstByteStdDev; + static float mFirstByteMean; + static float mFirstByteWeight; + static float[] mSecondByteFreq; + static float mSecondByteStdDev; + static float mSecondByteMean; + static float mSecondByteWeight; + + public float[] mFirstByteFreq() { + return mFirstByteFreq; + } + + public float mFirstByteStdDev() { + return mFirstByteStdDev; + } + + public float mFirstByteMean() { + return mFirstByteMean; + } + + public float mFirstByteWeight() { + return mFirstByteWeight; + } + + public float[] mSecondByteFreq() { + return mSecondByteFreq; + } + + public float mSecondByteStdDev() { + return mSecondByteStdDev; + } + + public float mSecondByteMean() { + return mSecondByteMean; + } + + public float mSecondByteWeight() { + return mSecondByteWeight; + } + + public GB2312Statistics() { + mFirstByteFreq = new float[]{0.011628F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.011628F, 0.012403F, 0.009302F, 0.003876F, 0.017829F, 0.037209F, 0.008527F, 0.010078F, 0.01938F, 0.054264F, 0.010078F, 0.041085F, 0.02093F, 0.018605F, 0.010078F, 0.013178F, 0.016279F, 0.006202F, 0.009302F, 0.017054F, 0.011628F, 0.008527F, 0.004651F, 0.006202F, 0.017829F, 0.024806F, 0.020155F, 0.013953F, 0.032558F, 0.035659F, 0.068217F, 0.010853F, 0.036434F, 0.117054F, 0.027907F, 0.100775F, 0.010078F, 0.017829F, 0.062016F, 0.012403F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.00155F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}; + mFirstByteStdDev = 0.020081F; + mFirstByteMean = 0.010638F; + mFirstByteWeight = 0.586533F; + mSecondByteFreq = new float[]{0.006202F, 0.031008F, 0.005426F, 0.003101F, 0.00155F, 0.003101F, 0.082171F, 0.014729F, 0.006977F, 0.00155F, 0.013953F, 0.0F, 0.013953F, 0.010078F, 0.008527F, 0.006977F, 0.004651F, 0.003101F, 0.003101F, 0.003101F, 0.008527F, 0.003101F, 0.005426F, 0.005426F, 0.005426F, 0.003101F, 0.00155F, 0.006202F, 0.014729F, 0.010853F, 0.0F, 0.011628F, 0.0F, 0.031783F, 0.013953F, 0.030233F, 0.039535F, 0.008527F, 0.015504F, 0.0F, 0.003101F, 0.008527F, 0.016279F, 0.005426F, 0.00155F, 0.013953F, 0.013953F, 0.044961F, 0.003101F, 0.004651F, 0.006977F, 0.00155F, 0.005426F, 0.012403F, 0.00155F, 0.015504F, 0.0F, 0.006202F, 0.00155F, 0.0F, 0.007752F, 0.006977F, 0.00155F, 0.009302F, 0.011628F, 0.004651F, 0.010853F, 0.012403F, 0.017829F, 0.005426F, 0.024806F, 0.0F, 0.006202F, 0.0F, 0.082171F, 0.015504F, 0.004651F, 0.0F, 0.006977F, 0.004651F, 0.0F, 0.008527F, 0.012403F, 0.004651F, 0.003876F, 0.003101F, 0.022481F, 0.024031F, 0.00155F, 0.047287F, 0.009302F, 0.00155F, 0.005426F, 0.017054F}; + mSecondByteStdDev = 0.014156F; + mSecondByteMean = 0.010638F; + mSecondByteWeight = 0.413467F; + } + } + + /** + * + */ + public static class nsGB2312Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsGB2312Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 286331153; + cclass[9] = 286331153; + cclass[10] = 286331153; + cclass[11] = 286331153; + cclass[12] = 286331153; + cclass[13] = 286331153; + cclass[14] = 286331153; + cclass[15] = 286331153; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 572662304; + cclass[21] = 858993442; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 35791394; + states = new int[2]; + states[0] = 286331649; + states[1] = 1122850; + charset = "GB2312"; + stFactor = 4; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsGB18030Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsGB18030Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 858993459; + cclass[7] = 286331187; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 1109533218; + cclass[16] = 1717986917; + cclass[17] = 1717986918; + cclass[18] = 1717986918; + cclass[19] = 1717986918; + cclass[20] = 1717986918; + cclass[21] = 1717986918; + cclass[22] = 1717986918; + cclass[23] = 1717986918; + cclass[24] = 1717986918; + cclass[25] = 1717986918; + cclass[26] = 1717986918; + cclass[27] = 1717986918; + cclass[28] = 1717986918; + cclass[29] = 1717986918; + cclass[30] = 1717986918; + cclass[31] = 107374182; + states = new int[6]; + states[0] = 318767105; + states[1] = 571543825; + states[2] = 17965602; + states[3] = 286326804; + states[4] = 303109393; + states[5] = 17; + charset = "GB18030"; + stFactor = 7; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsISO2022CNVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsISO2022CNVerifier() { + cclass = new int[32]; + cclass[0] = 2; + cclass[1] = 0; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 0; + cclass[5] = 48; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 16384; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 572662306; + cclass[17] = 572662306; + cclass[18] = 572662306; + cclass[19] = 572662306; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 572662306; + states = new int[8]; + states[0] = 304; + states[1] = 286331152; + states[2] = 572662289; + states[3] = 336663074; + states[4] = 286335249; + states[5] = 286331237; + states[6] = 286335249; + states[7] = 18944273; + charset = "ISO-2022-CN"; + stFactor = 9; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsISO2022JPVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsISO2022JPVerifier() { + cclass = new int[32]; + cclass[0] = 2; + cclass[1] = 570425344; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 458752; + cclass[5] = 3; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 1030; + cclass[9] = 1280; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 572662306; + cclass[17] = 572662306; + cclass[18] = 572662306; + cclass[19] = 572662306; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 572662306; + states = new int[6]; + states[0] = 304; + states[1] = 286331153; + states[2] = 572662306; + states[3] = 1091653905; + states[4] = 303173905; + states[5] = 287445265; + charset = "ISO-2022-JP"; + stFactor = 8; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsISO2022KRVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsISO2022KRVerifier() { + cclass = new int[32]; + cclass[0] = 2; + cclass[1] = 0; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 196608; + cclass[5] = 64; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 20480; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 572662306; + cclass[17] = 572662306; + cclass[18] = 572662306; + cclass[19] = 572662306; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 572662306; + cclass[29] = 572662306; + cclass[30] = 572662306; + cclass[31] = 572662306; + states = new int[5]; + states[0] = 285212976; + states[1] = 572657937; + states[2] = 289476898; + states[3] = 286593297; + states[4] = 8465; + charset = "ISO-2022-KR"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsUCS2BEVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsUCS2BEVerifier() { + cclass = new int[32]; + cclass[0] = 0; + cclass[1] = 2097408; + cclass[2] = 0; + cclass[3] = 12288; + cclass[4] = 0; + cclass[5] = 3355440; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 0; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 0; + cclass[21] = 0; + cclass[22] = 0; + cclass[23] = 0; + cclass[24] = 0; + cclass[25] = 0; + cclass[26] = 0; + cclass[27] = 0; + cclass[28] = 0; + cclass[29] = 0; + cclass[30] = 0; + cclass[31] = 1409286144; + states = new int[7]; + states[0] = 288626549; + states[1] = 572657937; + states[2] = 291923490; + states[3] = 1713792614; + states[4] = 393569894; + states[5] = 1717659269; + states[6] = 1140326; + charset = "UTF-16BE"; + stFactor = 6; + } + + public boolean isUCS2() { + return true; + } + } + + /** + * + */ + public static class nsUCS2LEVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsUCS2LEVerifier() { + cclass = new int[32]; + cclass[0] = 0; + cclass[1] = 2097408; + cclass[2] = 0; + cclass[3] = 12288; + cclass[4] = 0; + cclass[5] = 3355440; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 0; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 0; + cclass[16] = 0; + cclass[17] = 0; + cclass[18] = 0; + cclass[19] = 0; + cclass[20] = 0; + cclass[21] = 0; + cclass[22] = 0; + cclass[23] = 0; + cclass[24] = 0; + cclass[25] = 0; + cclass[26] = 0; + cclass[27] = 0; + cclass[28] = 0; + cclass[29] = 0; + cclass[30] = 0; + cclass[31] = 1409286144; + states = new int[7]; + states[0] = 288647014; + states[1] = 572657937; + states[2] = 303387938; + states[3] = 1712657749; + states[4] = 357927015; + states[5] = 1427182933; + states[6] = 1381717; + charset = "UTF-16LE"; + stFactor = 6; + } + + public boolean isUCS2() { + return true; + } + } + + /** + * + */ + public static class nsCP1252Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsCP1252Verifier() { + cclass = new int[32]; + cclass[0] = 572662305; + cclass[1] = 2236962; + cclass[2] = 572662306; + cclass[3] = 572654114; + cclass[4] = 572662306; + cclass[5] = 572662306; + cclass[6] = 572662306; + cclass[7] = 572662306; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 572662306; + cclass[16] = 572662274; + cclass[17] = 16851234; + cclass[18] = 572662304; + cclass[19] = 285286690; + cclass[20] = 572662306; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 286331153; + cclass[25] = 286331153; + cclass[26] = 554766609; + cclass[27] = 286331153; + cclass[28] = 286331153; + cclass[29] = 286331153; + cclass[30] = 554766609; + cclass[31] = 286331153; + states = new int[3]; + states[0] = 571543601; + states[1] = 340853778; + states[2] = 65; + charset = "windows-1252"; + stFactor = 3; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsHZVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsHZVerifier() { + cclass = new int[32]; + cclass[0] = 1; + cclass[1] = 0; + cclass[2] = 0; + cclass[3] = 4096; + cclass[4] = 0; + cclass[5] = 0; + cclass[6] = 0; + cclass[7] = 0; + cclass[8] = 0; + cclass[9] = 0; + cclass[10] = 0; + cclass[11] = 0; + cclass[12] = 0; + cclass[13] = 0; + cclass[14] = 0; + cclass[15] = 38813696; + cclass[16] = 286331153; + cclass[17] = 286331153; + cclass[18] = 286331153; + cclass[19] = 286331153; + cclass[20] = 286331153; + cclass[21] = 286331153; + cclass[22] = 286331153; + cclass[23] = 286331153; + cclass[24] = 286331153; + cclass[25] = 286331153; + cclass[26] = 286331153; + cclass[27] = 286331153; + cclass[28] = 286331153; + cclass[29] = 286331153; + cclass[30] = 286331153; + cclass[31] = 286331153; + states = new int[6]; + states[0] = 285213456; + states[1] = 572657937; + states[2] = 335548706; + states[3] = 341120533; + states[4] = 336872468; + states[5] = 36; + charset = "HZ-GB-2312"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsSJISVerifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsSJISVerifier() { + cclass = new int[32]; + cclass[0] = 286331152; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 572662306; + cclass[9] = 572662306; + cclass[10] = 572662306; + cclass[11] = 572662306; + cclass[12] = 572662306; + cclass[13] = 572662306; + cclass[14] = 572662306; + cclass[15] = 304226850; + cclass[16] = 858993459; + cclass[17] = 858993459; + cclass[18] = 858993459; + cclass[19] = 858993459; + cclass[20] = 572662308; + cclass[21] = 572662306; + cclass[22] = 572662306; + cclass[23] = 572662306; + cclass[24] = 572662306; + cclass[25] = 572662306; + cclass[26] = 572662306; + cclass[27] = 572662306; + cclass[28] = 858993459; + cclass[29] = 1145393971; + cclass[30] = 1145324612; + cclass[31] = 279620; + states = new int[3]; + states[0] = 286339073; + states[1] = 572657937; + states[2] = 4386; + charset = "Shift_JIS"; + stFactor = 6; + } + + public boolean isUCS2() { + return false; + } + } + + /** + * + */ + public static class nsUTF8Verifier extends nsVerifier { + static int[] cclass; + static int[] states; + static int stFactor; + static String charset; + + public int[] cclass() { + return cclass; + } + + public int[] states() { + return states; + } + + public int stFactor() { + return stFactor; + } + + public String charset() { + return charset; + } + + public nsUTF8Verifier() { + cclass = new int[32]; + cclass[0] = 286331153; + cclass[1] = 1118481; + cclass[2] = 286331153; + cclass[3] = 286327057; + cclass[4] = 286331153; + cclass[5] = 286331153; + cclass[6] = 286331153; + cclass[7] = 286331153; + cclass[8] = 286331153; + cclass[9] = 286331153; + cclass[10] = 286331153; + cclass[11] = 286331153; + cclass[12] = 286331153; + cclass[13] = 286331153; + cclass[14] = 286331153; + cclass[15] = 286331153; + cclass[16] = 858989090; + cclass[17] = 1145324612; + cclass[18] = 1145324612; + cclass[19] = 1145324612; + cclass[20] = 1431655765; + cclass[21] = 1431655765; + cclass[22] = 1431655765; + cclass[23] = 1431655765; + cclass[24] = 1717986816; + cclass[25] = 1717986918; + cclass[26] = 1717986918; + cclass[27] = 1717986918; + cclass[28] = -2004318073; + cclass[29] = -2003269496; + cclass[30] = -1145324614; + cclass[31] = 16702940; + states = new int[26]; + states[0] = -1408167679; + states[1] = 878082233; + states[2] = 286331153; + states[3] = 286331153; + states[4] = 572662306; + states[5] = 572662306; + states[6] = 290805009; + states[7] = 286331153; + states[8] = 290803985; + states[9] = 286331153; + states[10] = 293041937; + states[11] = 286331153; + states[12] = 293015825; + states[13] = 286331153; + states[14] = 295278865; + states[15] = 286331153; + states[16] = 294719761; + states[17] = 286331153; + states[18] = 298634257; + states[19] = 286331153; + states[20] = 297865489; + states[21] = 286331153; + states[22] = 287099921; + states[23] = 286331153; + states[24] = 285212689; + states[25] = 286331153; + charset = "UTF-8"; + stFactor = 16; + } + + public boolean isUCS2() { + return false; + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/JSONUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/JSONUtil.java new file mode 100644 index 0000000..9fa7b33 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/JSONUtil.java @@ -0,0 +1,91 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; + +import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; + +/** + * JSON解析工具类 + * + * @author WebSoft + * @since 2017-06-10 10:10:39 + */ +public class JSONUtil { + private static final ObjectMapper objectMapper; + private static final ObjectWriter objectWriter; + + static { + objectMapper = new ObjectMapper(); + // 注册 JavaTimeModule 支持 Java 8 日期时间 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(java.time.LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(java.time.LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + objectMapper.registerModule(javaTimeModule); + // 设置日期格式 + objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + // 禁用将日期写为时间戳 + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectWriter = objectMapper.writerWithDefaultPrettyPrinter(); + } + + /** + * 对象转json字符串 + * + * @param value 对象 + * @return String + */ + public static String toJSONString(Object value) { + return toJSONString(value, false); + } + + /** + * 对象转json字符串 + * + * @param value 对象 + * @param pretty 是否格式化输出 + * @return String + */ + public static String toJSONString(Object value, boolean pretty) { + if (value != null) { + if (value instanceof String) { + return (String) value; + } + try { + if (pretty) { + return objectWriter.writeValueAsString(value); + } + return objectMapper.writeValueAsString(value); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * json字符串转对象 + * + * @param json String + * @param clazz Class + * @return T + */ + public static T parseObject(String json, Class clazz) { + if (StrUtil.isNotBlank(json) && clazz != null) { + try { + return objectMapper.readValue(json, clazz); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java new file mode 100644 index 0000000..87d95b9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/MyQrCodeUtil.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import org.springframework.beans.factory.annotation.Value; + +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URL; +import java.util.HashMap; + +import static com.gxwebsoft.common.core.constants.QRCodeConstants.*; + +/** + * 常用工具方法 + * + * @author WebSoft + * @since 2017-06-10 10:10:22 + */ +public class MyQrCodeUtil { + + @Value("${config.upload-path}") + private static String uploadPath; + + private static final String logoUrl = "https://file.wsdns.cn/20230430/6fa31aca3b0d47af98a149cf2dd26a4f.jpeg"; + + /** + * 生成用户二维码 + */ + public static String getUserCode(Integer userId, String content) throws IOException { + return createQrCode(USER_QRCODE,userId,content); + } + + /** + * 生成工单二维码 + */ + public static String getTaskCode(Integer taskId, String content) throws IOException { + return createQrCode(TASK_QRCODE,taskId,content); + } + + /** + * 生成商品二维码 + */ + public static String getGoodsCode(Integer goodsId, String content) throws IOException { + return createQrCode(GOODS_QRCODE,goodsId,content); + } + + /** + * 生成自定义二维码 + */ + public static String getCodeMap(HashMap map) throws IOException { + return ""; + } + + /** + * 生成带水印的二维码 + * @param type 类型 + * @param id 实体ID + * @param content 二维码内容 + * @return 二维码图片地址 + */ + public static String createQrCode(String type,Integer id, String content) throws IOException { + String filePath = uploadPath + "/qrcode/".concat(type).concat("/"); + String qrcodeUrl = "https://file.websoft.top/qrcode/".concat(type).concat("/"); + // 将URL转为BufferedImage + BufferedImage bufferedImage = ImageIO.read(new URL(logoUrl)); + // 生成二维码 + QrConfig config = new QrConfig(300, 300); + // 设置边距,既二维码和背景之间的边距 + config.setMargin(1); + // 附带小logo + config.setImg(bufferedImage); + // 保存路径 + filePath = filePath.concat(id + ".jpg"); + qrcodeUrl = qrcodeUrl.concat(id + ".jpg") + "?v=" + DateUtil.current(); + + // 生成二维码 + QrCodeUtil.generate(content, config, FileUtil.file(filePath)); + return qrcodeUrl; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/OpenOfficeUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/OpenOfficeUtil.java new file mode 100644 index 0000000..cca3990 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/OpenOfficeUtil.java @@ -0,0 +1,124 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import org.artofsolving.jodconverter.OfficeDocumentConverter; +import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration; +import org.artofsolving.jodconverter.office.OfficeManager; + +import java.io.File; +import java.util.Arrays; +import java.util.Base64; + +/** + * OpenOfficeUtil + * + * @author WebSoft + * @since 2018-12-14 08:38:19 + */ +public class OpenOfficeUtil { + // 支持转换pdf的文件后缀列表 + private static final String[] CAN_CONVERTER_FILES = new String[]{ + "doc", "docx", "xls", "xlsx", "ppt", "pptx" + }; + + /** + * 文件转pdf + * + * @param filePath 源文件路径 + * @param outDir 输出目录 + * @param officeHome OpenOffice安装路径 + * @return File + */ + public static File converterToPDF(String filePath, String outDir, String officeHome) { + return converterToPDF(filePath, outDir, officeHome, true); + } + + /** + * 文件转pdf + * + * @param filePath 源文件路径 + * @param outDir 输出目录 + * @param officeHome OpenOffice安装路径 + * @param cache 是否使用上次转换过的文件 + * @return File + */ + public static File converterToPDF(String filePath, String outDir, String officeHome, boolean cache) { + if (StrUtil.isBlank(filePath)) { + return null; + } + File srcFile = new File(filePath); + if (!srcFile.exists()) { + return null; + } + // 是否转换过 + String outPath = Base64.getEncoder().encodeToString(filePath.getBytes()) + .replace("/", "-").replace("+", "-"); + File outFile = new File(outDir, outPath + ".pdf"); + if (cache && outFile.exists()) { + return outFile; + } + // 转换 + OfficeManager officeManager = null; + try { + officeManager = getOfficeManager(officeHome); + OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager); + return converterFile(srcFile, outFile, converter); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (officeManager != null) { + officeManager.stop(); + } + } + return null; + } + + /** + * 转换文件 + * + * @param inFile 源文件 + * @param outFile 输出文件 + * @param converter OfficeDocumentConverter + * @return File + */ + public static File converterFile(File inFile, File outFile, OfficeDocumentConverter converter) { + if (!outFile.getParentFile().exists()) { + if (!outFile.getParentFile().mkdirs()) { + return outFile; + } + } + converter.convert(inFile, outFile); + return outFile; + } + + /** + * 判断文件后缀是否可以转换pdf + * + * @param path 文件路径 + * @return boolean + */ + public static boolean canConverter(String path) { + try { + String suffix = path.substring(path.lastIndexOf(".") + 1); + return Arrays.asList(CAN_CONVERTER_FILES).contains(suffix); + } catch (Exception e) { + return false; + } + } + + /** + * 连接并启动OpenOffice + * + * @param officeHome OpenOffice安装路径 + * @return OfficeManager + */ + public static OfficeManager getOfficeManager(String officeHome) { + if (officeHome == null || officeHome.trim().isEmpty()) return null; + DefaultOfficeManagerConfiguration config = new DefaultOfficeManagerConfiguration(); + config.setOfficeHome(officeHome); // 设置OpenOffice安装目录 + OfficeManager officeManager = config.buildOfficeManager(); + officeManager.start(); // 启动OpenOffice服务 + return officeManager; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/QrCodeDecryptResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/QrCodeDecryptResult.java new file mode 100644 index 0000000..bbfe3b6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/QrCodeDecryptResult.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.common.core.utils; + +import lombok.Data; + +/** + * 二维码解密结果类 + * 包含解密后的数据和业务类型信息 + * + * @author WebSoft + * @since 2025-08-18 + */ +@Data +public class QrCodeDecryptResult { + + /** + * 解密后的原始数据 + */ + private String originalData; + + /** + * 业务类型(如:order、user、coupon、ticket等) + */ + private String businessType; + + /** + * 二维码类型(encrypted 或 business_encrypted) + */ + private String qrType; + + /** + * 二维码ID(仅业务模式有) + */ + private String qrId; + + /** + * 过期时间戳(仅业务模式有) + */ + private Long expireTime; + + /** + * 是否已过期 + */ + private Boolean expired; + + public QrCodeDecryptResult() {} + + public QrCodeDecryptResult(String originalData, String businessType, String qrType) { + this.originalData = originalData; + this.businessType = businessType; + this.qrType = qrType; + this.expired = false; + } + + /** + * 创建自包含模式的解密结果 + */ + public static QrCodeDecryptResult createEncryptedResult(String originalData, String businessType) { + return new QrCodeDecryptResult(originalData, businessType, "encrypted"); + } + + /** + * 创建业务模式的解密结果 + */ + public static QrCodeDecryptResult createBusinessResult(String originalData, String businessType, + String qrId, Long expireTime) { + QrCodeDecryptResult result = new QrCodeDecryptResult(originalData, businessType, "business_encrypted"); + result.setQrId(qrId); + result.setExpireTime(expireTime); + result.setExpired(expireTime != null && System.currentTimeMillis() > expireTime); + return result; + } + + /** + * 检查是否有业务类型 + */ + public boolean hasBusinessType() { + return businessType != null && !businessType.trim().isEmpty(); + } + + /** + * 检查是否为业务模式 + */ + public boolean isBusinessMode() { + return "business_encrypted".equals(qrType); + } + + /** + * 检查是否为自包含模式 + */ + public boolean isEncryptedMode() { + return "encrypted".equals(qrType); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/RedisUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/RedisUtil.java new file mode 100644 index 0000000..5a900c4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/RedisUtil.java @@ -0,0 +1,287 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.result.RedisResult; +import org.springframework.data.geo.Point; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import static com.gxwebsoft.common.core.constants.RedisConstants.CACHE_NULL_TTL; + +@Component +public class RedisUtil { + private final StringRedisTemplate stringRedisTemplate; + public static Integer tenantId; + + public RedisUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant) + */ + public void set(String key, T entity){ + stringRedisTemplate.opsForValue().set(key, JSONUtil.toJSONString(entity)); + } + + /** + * 写入redis缓存 + * @param key [表名]:id + * @param entity 实体类对象 + * 示例 cacheClient.set("merchant:"+id,merchant,1L,TimeUnit.DAYS) + */ + public void set(String key, T entity, Long time, TimeUnit unit){ + stringRedisTemplate.opsForValue().set(key, JSONUtil.toJSONString(entity),time,unit); + } + + /** + * 写入redis缓存(支持 Duration) + * 示例 cacheClient.set("key", "value", Duration.ofHours(24)) + */ + public void set(String key, String value, java.time.Duration duration) { + stringRedisTemplate.opsForValue().set(key, value, duration); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * 示例 cacheClient.get(key) + * @return merchant + */ + public String get(String key) { + return stringRedisTemplate.opsForValue().get(key); + } + + /** + * 读取redis缓存 + * @param key [表名]:id + * @param clazz Merchant.class + * @param + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @return merchant + */ + public T get(String key, Class clazz) { + String json = stringRedisTemplate.opsForValue().get(key); + if(StrUtil.isNotBlank(json)){ + return JSONUtil.parseObject(json, clazz); + } + return null; + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param field 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPut(String key, String field, T entity) { + stringRedisTemplate.opsForHash().put(key,field,JSONUtil.toJSONString(entity)); + } + + /** + * 写redis缓存(哈希类型) + * @param key [表名]:id + * @param map 字段 + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + */ + public void hPutAll(String key, Map map) { + stringRedisTemplate.opsForHash().putAll(key,map); + } + + /** + * 读取redis缓存(哈希类型) + * 示例 cacheClient.get("merchant:"+id,Merchant.class) + * @param key [表名]:id + * @param field 字段 + * @return merchant + */ + public T hGet(String key, String field, Class clazz) { + Object obj = stringRedisTemplate.opsForHash().get(key, field); + return JSONUtil.parseObject(JSONUtil.toJSONString(obj),clazz); + } + + public List hValues(String key){ + return stringRedisTemplate.opsForHash().values(key); + } + + public Long hSize(String key){ + return stringRedisTemplate.opsForHash().size(key); + } + + // 逻辑过期方式写入redis + public void setWithLogicalExpire(String key, T value, Long time, TimeUnit unit){ + // 设置逻辑过期时间 + final RedisResult redisResult = new RedisResult<>(); + redisResult.setData(value); + redisResult.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time))); + stringRedisTemplate.opsForValue().set(key,JSONUtil.toJSONString(redisResult)); + } + + // 读取redis + public R query(String keyPrefix, ID id, Class clazz, Function dbFallback, Long time, TimeUnit unit){ + String key = keyPrefix + id; + // 1.从redis查询缓存 + final String json = stringRedisTemplate.opsForValue().get(key); + // 2.判断是否存在 + if (StrUtil.isNotBlank(json)) { + // 3.存在,直接返回 + return JSONUtil.parseObject(json,clazz); + } + // 判断命中的是否为空值 + if (json != null) { + return null; + } + // 4. 不存在,跟进ID查询数据库 + R r = dbFallback.apply(id); + // 5. 数据库不存在,返回错误 + if(r == null){ + // 空值写入数据库 + this.set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES); + return null; + } + // 写入redis + this.set(key,r,time,unit); + return r; + } + + /** + * 添加商户定位点 + * @param key geo + * @param id + * 示例 cacheClient.geoAdd("merchant-geo",merchant) + */ + public void geoAdd(String key, Double x, Double y, String id){ + stringRedisTemplate.opsForGeo().add(key,new Point(x,y),id); + } + + /** + * 删除定位 + * @param key geo + * @param id + * 示例 cacheClient.geoRemove("merchant-geo",id) + */ + public void geoRemove(String key, Integer id){ + stringRedisTemplate.opsForGeo().remove(key,id.toString()); + } + + + + public void sAdd(String key, T entity){ + stringRedisTemplate.opsForSet().add(key,JSONUtil.toJSONString(entity)); + } + + public Set sMembers(String key){ + return stringRedisTemplate.opsForSet().members(key); + } + + // 更新排行榜 + public void zAdd(String key, Integer userId, Double value) { + stringRedisTemplate.opsForZSet().add(key,userId.toString(),value); + } + // 增加元素的score值,并返回增加后的值 + public Double zIncrementScore(String key,Integer userId, Double delta){ + return stringRedisTemplate.opsForZSet().incrementScore(key, userId.toString(), delta); + } + // 获取排名榜 + public Set range(String key, Integer start, Integer end) { + return stringRedisTemplate.opsForZSet().range(key, start, end); + } + // 获取排名榜 + public Set reverseRange(String key, Integer start, Integer end){ + return stringRedisTemplate.opsForZSet().reverseRange(key, start, end); + } + // 获取分数 + public Double score(String key, Object value){ + return stringRedisTemplate.opsForZSet().score(key, value); + } + + public void delete(String key){ + stringRedisTemplate.delete(key); + } + + // 存储在list头部 + public void leftPush(String key, String keyword){ + stringRedisTemplate.opsForList().leftPush(key,keyword); + } + + // 获取列表指定范围内的元素 + public List listRange(String key,Long start, Long end){ + return stringRedisTemplate.opsForList().range(key, start, end); + } + + // 获取列表长度 + public Long listSize(String key){ + return stringRedisTemplate.opsForList().size(key); + } + + // 裁剪list + public void listTrim(String key){ + stringRedisTemplate.opsForList().trim(key, 0L, 100L); + } + + /** + * 读取后台系统设置信息 + * @param keyName 键名wx-word + * @param tenantId 租户ID + * @return + * key示例 cache10048:setting:wx-work + */ + public JSONObject getSettingInfo(String keyName,Integer tenantId){ + String key = "cache" + tenantId + ":setting:" + keyName; + final String cache = stringRedisTemplate.opsForValue().get(key); + assert cache != null; + return JSON.parseObject(cache); + } + + /** + * KEY前缀 + * cache[tenantId]:[key+id] + */ + public static String prefix(String key){ + String prefix = "cache"; + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + final Integer tenantId = ((User) object).getTenantId(); + prefix = prefix.concat(tenantId.toString()).concat(":"); + } + } + return prefix.concat(key); + } + + // 组装key + public String key(String name,Integer id){ + return name.concat(":").concat(id.toString()); + } + + // 获取上传配置 + public HashMap getUploadConfig(Integer tenantId){ + String key = "setting:upload:" + tenantId; + final String s = get(key); + final JSONObject jsonObject = JSONObject.parseObject(s); + final String uploadMethod = jsonObject.getString("uploadMethod"); + final String bucketDomain = jsonObject.getString("bucketDomain"); + + final HashMap map = new HashMap<>(); + map.put("uploadMethod",uploadMethod); + map.put("bucketDomain",bucketDomain); + return map; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java new file mode 100644 index 0000000..cdda4da --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java @@ -0,0 +1,343 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserRole; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.entity.ShopMerchantAccount; +import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; + +@Component +public class RequestUtil { + + @Autowired + private ConfigProperties configProperties; + + private static String ACCESS_TOKEN; + private static String TENANT_ID; + + public void setTenantId(String tenantId) { + TENANT_ID = tenantId; + } + + public void setAccessToken(String token) { + ACCESS_TOKEN = token; + } + + private String getServerUrl() { + return configProperties.getServerUrl(); + } + + // 预付请求付款(余额支付) + public Object balancePay(ShopOrder order) { + // 设置租户ID + setTenantId(order.getTenantId().toString()); + // 设置token + setAccessToken(order.getAddress()); + // 余额支付接口 + String path = "/system/payment/balancePay"; + try { + // 链式构建请求 + final String body = HttpRequest.post(getServerUrl().concat(path)) + .header("Tenantid", TENANT_ID) + .header("Authorization", ACCESS_TOKEN) + .body(JSONUtil.toJSONString(order))//表单内容 + .timeout(20000)//超时,毫秒 + .execute().body(); + return JSONUtil.parseObject(body, ApiResult.class).getData(); + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + // 微信支付通知 + public String pushWxPayNotify(Transaction transaction, Payment payment) { + // 设置租户ID + setTenantId(payment.getTenantId().toString()); + // 推送支付通知地址 + String path = payment.getNotifyUrl(); + try { + // 链式构建请求 + return HttpRequest.post(path) + .header("Tenantid", TENANT_ID) + .body(JSONUtil.toJSONString(transaction))//表单内容 + .timeout(20000)//超时,毫秒 + .execute().body(); + + } catch (Exception e) { + e.printStackTrace(); + } + return "支付失败"; + } + + + public User getUserByPhone(String phone) { + String path = "/system/user/getByPhone/" + phone; + try { + // 链式构建请求 + String result = HttpRequest.get(getServerUrl().concat(path)) + .header("Authorization", ACCESS_TOKEN) + .header("Tenantid", TENANT_ID) + .timeout(20000)//超时,毫秒 + .execute().body(); + + JSONObject jsonObject = JSONObject.parseObject(result); + final String data = jsonObject.getString("data"); + return JSONObject.parseObject(data, User.class); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public User getByUserId(Integer userId) { + String path = "/system/user/" + userId; + try { + // 链式构建请求 + String result = HttpRequest.get(getServerUrl().concat(path)) + .header("Authorization", ACCESS_TOKEN) + .header("Tenantid", TENANT_ID) + .timeout(20000)//超时,毫秒 + .execute().body(); + + JSONObject jsonObject = JSONObject.parseObject(result); + System.out.println("jsonObject1111111111 = " + jsonObject); + final String data = jsonObject.getString("data"); + return JSONObject.parseObject(data, User.class); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public User getByUserIdWithoutLogin(Integer userId) { + String path = "/system/user/getByUserId/" + userId; + try { + // 链式构建请求 + String result = HttpRequest.get(getServerUrl().concat(path)) + .header("Tenantid", TENANT_ID) + .timeout(20000)//超时,毫秒 + .execute().body(); + JSONObject jsonObject = JSONObject.parseObject(result); + System.out.println("jsonObject1111 = " + jsonObject); + final String data = jsonObject.getString("data"); + return JSONObject.parseObject(data, User.class); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + // 新增用户 + public boolean saveUserByPhone(ShopMerchantAccount merchantAccount) { + String path = "/system/user/"; + try { + HashMap map = new HashMap<>(); + map.put("nickname", merchantAccount.getRealName()); + map.put("username", merchantAccount.getPhone()); + map.put("realName", merchantAccount.getRealName()); + map.put("phone", merchantAccount.getPhone()); + map.put("merchantId", merchantAccount.getMerchantId()); + final ArrayList roles = new ArrayList<>(); + final UserRole userRole = new UserRole(); + userRole.setUserId(merchantAccount.getUserId()); + userRole.setRoleId(merchantAccount.getRoleId()); + userRole.setTenantId(merchantAccount.getTenantId()); + roles.add(userRole); + map.put("roles", roles); + map.put("tenantId", TENANT_ID); + // 链式构建请求 + String result = HttpRequest.post(getServerUrl().concat(path)) + .header("Authorization", ACCESS_TOKEN) + .header("Tenantid", TENANT_ID) + .body(JSONUtil.toJSONString(map))//表单内容 + .timeout(20000)//超时,毫秒 + .execute().body(); + + } catch (Exception e) { + e.printStackTrace(); + } + return true; + } + + public ApiResult updateUserBalance(String path, User user) { + try { + // 链式构建请求 + final String body = HttpRequest.put(getServerUrl().concat(path)) + .header("Authorization", ACCESS_TOKEN) + .header("Tenantid", TENANT_ID) + .body(JSONUtil.toJSONString(user)) + .timeout(20000) + .execute().body(); + return JSONUtil.parseObject(body, ApiResult.class); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public User getParent(Integer userId) { + try { + // 链式构建请求 + final String result = HttpRequest.get(getServerUrl().concat("/system/user-referee/getReferee/" + userId)) + .header("Tenantid", TENANT_ID) + .timeout(20000) + .execute().body(); + JSONObject jsonObject = JSONObject.parseObject(result); + final String data = jsonObject.getString("data"); + return JSONObject.parseObject(data, User.class); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + // 更新用户信息 + public void updateUser(User user) { + String path = "/system/user/"; + try { + // 链式构建请求 + final String body = HttpRequest.put(getServerUrl().concat(path)) + .header("Authorization", ACCESS_TOKEN) + .header("Tenantid", TENANT_ID) + .body(JSONUtil.toJSONString(user)) + .timeout(20000) + .execute().body(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // 更新用户信息 + public void updateWithoutLogin(User user) { + String path = "/system/user/updateWithoutLogin"; + try { + // 链式构建请求 + final String body = HttpRequest.put(getServerUrl().concat(path)) + .header("Tenantid", TENANT_ID) + .body(JSONUtil.toJSONString(user)) + .timeout(20000) + .execute().body(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String getMpOrderQrCode(String orderNo) { + String path = "/wx-login/getOrderQRCode/"; + try { + // 链式构建请求 + final String body = HttpRequest.get(getServerUrl().concat(path).concat(orderNo)) + .header("Authorization", ACCESS_TOKEN) + .header("tenantId", TENANT_ID) + .timeout(20000) + .execute().body(); + final JSONObject jsonObject = JSONObject.parseObject(body); + final String qrCode = jsonObject.getString("message"); + return qrCode; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public String getOrderQRCodeUnlimited(String orderNo) { + String path = "/wx-login/getOrderQRCodeUnlimited/"; + try { + // 链式构建请求 + final String body = HttpRequest.get(getServerUrl().concat(path).concat(orderNo)) + .header("Authorization", ACCESS_TOKEN) + .header("tenantId", TENANT_ID) + .timeout(20000) + .execute().body(); + System.out.println("body = " + body); + final JSONObject jsonObject = JSONObject.parseObject(body); + final String qrCode = jsonObject.getString("message"); + System.out.println("qrCode = " + qrCode); + return qrCode; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public void updateUserMerchantId(User user) { + String path = "/system/user/updateUserMerchantId"; + try { + // 链式构建请求 + final String body = HttpRequest.put(getServerUrl().concat(path)) + .header("Authorization", ACCESS_TOKEN) + .header("tenantId", TENANT_ID) + .body(JSONUtil.toJSONString(user)) + .timeout(20000) + .execute().body(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public ApiResult getWxConfig() { + String path = "/system/setting?settingKey=mp-weixin"; + try { + // 链式构建请求 + final String body = HttpRequest.get(getServerUrl().concat(path)) + .header("Authorization", ACCESS_TOKEN) + .header("tenantId", TENANT_ID) + .timeout(20000) + .execute().body(); + return JSONUtil.parseObject(body, ApiResult.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public ApiResult pageDictData(Integer dictId) { + String path = "/system/dict-data/page"; + try { + // 链式构建请求 + final String body = HttpRequest.get(getServerUrl().concat(path).concat("?dictId=" + dictId)) + .header("tenantId", TENANT_ID) + .timeout(20000) + .execute().body(); + return JSONUtil.parseObject(body, ApiResult.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + // 余额支付通知 + public void pushBalancePayNotify(Transaction transaction, Payment payment) { + System.out.println("payment = " + payment); + System.out.println("transaction = " + transaction); + // 设置租户ID + setTenantId(payment.getTenantId().toString()); + // 推送支付通知地址 + String path = payment.getNotifyUrl(); + try { + // 链式构建请求 + HttpRequest.post(path) + .header("Tenantid", TENANT_ID) + .body(JSONUtil.toJSONString(transaction))//表单内容 + .timeout(20000)//超时,毫秒 + .execute().body(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java new file mode 100644 index 0000000..b09cd9a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/SignCheckUtil.java @@ -0,0 +1,197 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.crypto.SecureUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.system.entity.KVEntity; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; + +/** + * 签名检查和获取签名 + * https://blog.csdn.net/u011628753/article/details/110251445 + * @author leng + * + */ +public class SignCheckUtil { + // 签名字段 + public final static String SIGN = "sign"; + + /** + * 签名检查,签名参数中,sign是用于校验的加密值,其他参数按照字母顺序排序,加密,并将其内容链接起来 + * + * @param params + * @param key + * @return + */ + public static boolean signCheck(JSONObject params, String key) { + if (null != params) { + Map map = new HashMap<>(); + + params.forEach((k, v) -> { + map.put(k, v.toString()); + }); + return signCheck(map, key); + } + + return false; + } + + /** + * 签名检查,签名参数中,sign是用于校验的加密值,其他参数按照字母顺序排序,加密,并将其内容链接起来 + * + * @param params + * @param key + * 签名key不允许为空 + * @return + */ + public static boolean signCheck(Map params, String key) { + String sign = params.get(SIGN);// 签名 + if (null == sign) { + return false; + } + String signTemp = getSignString(params,key); + if (null == signTemp) { + return false; + } + return signTemp.equals(sign); + } + + /** + * 获取签名的字符串 + * + * @param params + * @param key + * @return + */ + public static String getSignString(JSONObject params, String key) { + if (null != params) { + Map map = new HashMap<>(); + + params.forEach((k, v) -> { + map.put(k, v.toString()); + }); + return getSignString(map, key); + } + + return null; + } + + /** + * 获取签名的字符串 + * + * @param params + * @param key + * @return + */ + public static String getSignString(Map params, String key) { + // 签名 + if (null == params || params.size() == 0) { + return null; + } + key = (null == key) ? "" : key; + List> list = new ArrayList<>(params.size() - 1); + + params.forEach((k, v) -> { + if (!SIGN.equals(k)) { + list.add(KVEntity.build(k, v)); + } + }); + + Collections.sort(list, (obj1, obj2) -> { + return obj1.getK().compareTo(obj2.getK()); + }); + + StringBuffer sb = new StringBuffer(); + for (KVEntity kv : list) { + String value = kv.getV(); + if (!StringUtils.isEmpty(value)) { + sb.append(kv.getV()).append("-"); + } + } + sb.append(key); + System.out.println("md5加密前的字符串 = " + sb + key); + String signTemp = SecureUtil.md5(sb.toString()).toLowerCase(); + return signTemp; + } + + /** + * 获取微信签名的字符串 + * + * 注意签名(sign)的生成方式,具体见官方文档(传参都要参与生成签名,且参数名按照字典序排序,最后接上APP_KEY,转化成大写) + * + * @param params + * @param key + * @return + */ + public static String getWXSignString(Map params, String key) { + // 签名 + if (null == params || params.size() == 0 || StringUtils.isEmpty(key)) { + return null; + } + + List> list = new ArrayList<>(params.size() - 1); + + params.forEach((k, v) -> { + if (!SIGN.equals(k)) { + list.add(KVEntity.build(k, v)); + } + }); + + Collections.sort(list, (obj1, obj2) -> { + return obj1.getK().compareTo(obj2.getK()); + }); + + StringBuffer sb = new StringBuffer(); + for (KVEntity kv : list) { + String value = kv.getV(); + if (!StringUtils.isEmpty(value)) { + sb.append(kv.getK() + "=" + value + "&"); + } + } + + sb.append("key=" + key); + String signTemp = SecureUtil.md5(sb.toString()).toLowerCase(); + return signTemp; + } + + /** + * 微信签名验证 + * @param params + * @param key + * @return + */ + public static boolean WXsignCheck(Map params, String key) { + String sign = params.get(SIGN); + if (StringUtils.isEmpty(sign)) { + return false; + } + return sign.equals(getWXSignString(params, key)); + } + + + /** + * 白名单校验 + * @param domainName abc.com + * @return true + */ + public boolean checkWhiteDomains(List whiteDomains, String domainName) { + if(whiteDomains == null){ + return true; + } + if (whiteDomains.isEmpty()) { + return true; + } + // 服务器域名白名单列表 + whiteDomains.add("server.websoft.top"); + System.out.println("whiteDomains = " + whiteDomains); + System.out.println(">>> domainName = " + domainName); + for(String item: whiteDomains){ + if(Objects.equals(item, domainName)){ + return true; + } + } + return false; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/SpmUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/SpmUtil.java new file mode 100644 index 0000000..091ef20 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/SpmUtil.java @@ -0,0 +1,23 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.cms.entity.CmsNavigation; + +public class SpmUtil { + + // 生成spmUrl + public static String getSpmUrl(String path){ + return path.concat("?spm=c."); + } + + // 生成spmUrl + public static String getSpmUrl(String path, CmsNavigation navigation){ + return path.concat("?spm=c.".concat(navigation.getNavigationId().toString())); + } + + // 生成spmUrl +// public static String getSpmUrl(String path, T data){ +// System.out.println("json = " + data); +// return "?spm=".concat(path).concat(); +// } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatCertAutoConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatCertAutoConfig.java new file mode 100644 index 0000000..c8fa68a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatCertAutoConfig.java @@ -0,0 +1,173 @@ +package com.gxwebsoft.common.core.utils; + +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import com.gxwebsoft.common.core.config.ConfigProperties; + +import javax.annotation.Resource; + +/** + * 微信支付证书自动配置工具类 + * 使用RSAAutoCertificateConfig实现证书自动管理 + * + * @author 科技小王子 + * @since 2024-07-26 + */ +@Slf4j +@Component +public class WechatCertAutoConfig { + + @Value("${spring.profiles.active:prod}") + private String activeProfile; + + @Resource + private ConfigProperties configProperties; + + /** + * 创建微信支付自动证书配置 + * + * @param merchantId 商户号 + * @param privateKeyPath 私钥文件路径 + * @param merchantSerialNumber 商户证书序列号 + * @param apiV3Key APIv3密钥 + * @return 微信支付配置对象 + */ + public Config createAutoConfig(String merchantId, String privateKeyPath, + String merchantSerialNumber, String apiV3Key) { + try { + log.info("创建微信支付自动证书配置..."); + log.info("商户号: {}", merchantId); + log.info("私钥路径: {}", privateKeyPath); + log.info("证书序列号: {}", merchantSerialNumber); + + Config config = new RSAAutoCertificateConfig.Builder() + .merchantId(merchantId) + .privateKeyFromPath(privateKeyPath) + .merchantSerialNumber(merchantSerialNumber) + .apiV3Key(apiV3Key) + .build(); + + log.info("✅ 微信支付自动证书配置创建成功"); + log.info("🔄 系统将自动管理平台证书的下载和更新"); + + return config; + + } catch (Exception e) { + log.error("❌ 创建微信支付自动证书配置失败: {}", e.getMessage(), e); + + // 提供详细的错误诊断信息 + log.error("🔍 错误诊断:"); + log.error("1. 请检查商户平台是否已开启API安全功能"); + log.error("2. 请确认已申请使用微信支付公钥"); + log.error("3. 请验证APIv3密钥和证书序列号是否正确"); + log.error("4. 请检查网络连接是否正常"); + log.error("5. 请确认私钥文件路径是否正确: {}", privateKeyPath); + + throw new RuntimeException("微信支付自动证书配置失败: " + e.getMessage(), e); + } + } + + /** + * 使用默认开发环境配置创建自动证书配置 + * 根据当前环境自动选择证书路径 + * 开发环境拼接规则:配置文件upload-path + dev/wechat/ + 租户ID + * + * @return 微信支付配置对象 + */ + public Config createDefaultDevConfig() { + String merchantId = "1246610101"; + String privateKeyPath; + String merchantSerialNumber = "754B973F56C0CF9E3B21D950ECAB5ED99063057D"; + String apiV3Key = "zGufUcqa7ovgxRL0kF5OlPr482EZwtn8"; + + // 根据环境选择证书路径 + if ("dev".equals(activeProfile)) { + // 开发环境:使用配置文件upload-path拼接证书路径 + String uploadPath = configProperties.getUploadPath(); // 配置文件路径 + String tenantId = "5"; // 租户ID + String certPath = uploadPath + "dev/wechat/" + tenantId + "/"; + privateKeyPath = certPath + "apiclient_key.pem"; + + log.info("开发环境:使用配置文件upload-path拼接证书路径"); + log.info("配置文件upload-path: {}", uploadPath); + log.info("证书基础路径: {}", certPath); + log.info("私钥文件路径: {}", privateKeyPath); + } else { + // 生产环境:使用 Docker 挂载路径 + // 容器挂载路径:/www/wwwroot/file.ws + String certRootPath = "/www/wwwroot/file.ws"; + privateKeyPath = certRootPath + "/wechat/apiclient_key.pem"; + log.info("生产环境:使用容器挂载路径 - {}", privateKeyPath); + } + + return createAutoConfig(merchantId, privateKeyPath, merchantSerialNumber, apiV3Key); + } + + /** + * 测试证书配置是否正常 + * + * @param config 微信支付配置 + * @return 是否配置成功 + */ + public boolean testConfig(Config config) { + try { + // 这里可以添加一些基本的配置验证逻辑 + log.info("🧪 测试微信支付证书配置..."); + + if (config == null) { + log.error("配置对象为空"); + return false; + } + + log.info("✅ 证书配置测试通过"); + return true; + + } catch (Exception e) { + log.error("❌ 证书配置测试失败: {}", e.getMessage(), e); + return false; + } + } + + /** + * 获取配置使用说明 + * + * @return 使用说明 + */ + public String getUsageInstructions() { + return """ + 🚀 微信支付自动证书配置使用说明 + ================================ + + ✅ 优势: + 1. 自动下载微信支付平台证书 + 2. 证书过期时自动更新 + 3. 无需手动管理 wechatpay_cert.pem 文件 + 4. 符合微信支付官方最佳实践 + + 📝 使用方法: + + // 方法1: 使用默认开发环境配置 + Config config = wechatCertAutoConfig.createDefaultDevConfig(); + + // 方法2: 自定义配置 + Config config = wechatCertAutoConfig.createAutoConfig( + "商户号", + "私钥路径", + "证书序列号", + "APIv3密钥" + ); + + 🔧 前置条件: + 1. 微信商户平台已开启API安全功能 + 2. 已申请使用微信支付公钥 + 3. 私钥文件存在且路径正确 + 4. 网络连接正常 + + 📚 更多信息: + https://pay.weixin.qq.com/doc/v3/merchant/4012153196 + """; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateDiagnostic.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateDiagnostic.java new file mode 100644 index 0000000..ebe8189 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateDiagnostic.java @@ -0,0 +1,314 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + + +/** + * 微信支付证书诊断工具 + * 专门用于诊断和解决证书相关问题 + * + * @author 科技小王子 + * @since 2025-07-29 + */ +@Slf4j +@Component +public class WechatPayCertificateDiagnostic { + + private final CertificateProperties certConfig; + private final CertificateLoader certificateLoader; + + public WechatPayCertificateDiagnostic(CertificateProperties certConfig, CertificateLoader certificateLoader) { + this.certConfig = certConfig; + this.certificateLoader = certificateLoader; + } + + /** + * 全面诊断微信支付证书配置 + * + * @param payment 支付配置 + * @param tenantId 租户ID + * @param environment 环境(dev/prod) + * @return 诊断结果 + */ + public DiagnosticResult diagnoseCertificateConfig(Payment payment, Integer tenantId, String environment) { + DiagnosticResult result = new DiagnosticResult(); + + log.info("=== 开始微信支付证书诊断 ==="); + log.info("租户ID: {}, 环境: {}", tenantId, environment); + + try { + // 1. 检查基本配置 + checkBasicConfig(payment, result); + + // 2. 检查证书文件 + checkCertificateFiles(payment, tenantId, environment, result); + + // 3. 检查证书内容 + validateCertificateContent(payment, tenantId, environment, result); + + // 4. 生成建议 + generateRecommendations(result); + + } catch (Exception e) { + result.addError("诊断过程中发生异常: " + e.getMessage()); + log.error("证书诊断异常", e); + } + + log.info("=== 证书诊断完成 ==="); + return result; + } + + /** + * 检查基本配置 + */ + private void checkBasicConfig(Payment payment, DiagnosticResult result) { + if (payment == null) { + result.addError("支付配置为空"); + return; + } + + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + result.addError("商户号未配置"); + } else { + result.addInfo("商户号: " + payment.getMchId()); + } + + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + result.addError("应用ID未配置"); + } else { + result.addInfo("应用ID: " + payment.getAppId()); + } + + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + result.addError("商户证书序列号未配置"); + } else { + result.addInfo("商户证书序列号: " + payment.getMerchantSerialNumber()); + } + + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + result.addWarning("数据库中APIv3密钥未配置,将使用配置文件默认值"); + } else { + result.addInfo("APIv3密钥: 已配置(" + payment.getApiKey().length() + "位)"); + } + } + + /** + * 检查证书文件 + */ + private void checkCertificateFiles(Payment payment, Integer tenantId, String environment, DiagnosticResult result) { + if ("dev".equals(environment)) { + // 开发环境证书检查 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + // 检查私钥文件 + if (certificateLoader.certificateExists(privateKeyPath)) { + result.addInfo("✅ 私钥文件存在: " + privateKeyPath); + try { + String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath); + result.addInfo("私钥文件路径: " + privateKeyFile); + } catch (Exception e) { + result.addError("私钥文件加载失败: " + e.getMessage()); + } + } else { + result.addError("❌ 私钥文件不存在: " + privateKeyPath); + } + + // 检查商户证书文件 + if (certificateLoader.certificateExists(apiclientCertPath)) { + result.addInfo("✅ 商户证书文件存在: " + apiclientCertPath); + } else { + result.addWarning("⚠️ 商户证书文件不存在: " + apiclientCertPath + " (自动证书配置不需要此文件)"); + } + + } else { + // 生产环境证书检查 + if (payment.getApiclientKey() != null) { + result.addInfo("私钥文件配置: " + payment.getApiclientKey()); + } else { + result.addError("生产环境私钥文件路径未配置"); + } + + if (payment.getApiclientCert() != null) { + result.addInfo("商户证书文件配置: " + payment.getApiclientCert()); + } else { + result.addWarning("生产环境商户证书文件路径未配置 (自动证书配置不需要此文件)"); + } + } + } + + /** + * 验证证书内容 + */ + private void validateCertificateContent(Payment payment, Integer tenantId, String environment, DiagnosticResult result) { + try { + if ("dev".equals(environment)) { + String tenantCertPath = "dev/wechat/" + tenantId; + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + if (certificateLoader.certificateExists(apiclientCertPath)) { + validateX509Certificate(apiclientCertPath, payment.getMerchantSerialNumber(), result); + } + } + } catch (Exception e) { + result.addWarning("证书内容验证失败: " + e.getMessage()); + } + } + + /** + * 验证X509证书 + */ + private void validateX509Certificate(String certPath, String expectedSerialNumber, DiagnosticResult result) { + try { + String actualCertPath = certificateLoader.loadCertificatePath(certPath); + + try (InputStream inputStream = new FileInputStream(new File(actualCertPath))) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); + + if (cert != null) { + String actualSerialNumber = cert.getSerialNumber().toString(16).toUpperCase(); + result.addInfo("证书序列号: " + actualSerialNumber); + result.addInfo("证书有效期: " + cert.getNotBefore() + " 至 " + cert.getNotAfter()); + result.addInfo("证书主体: " + cert.getSubjectX500Principal().toString()); + + // 检查序列号是否匹配 + if (expectedSerialNumber != null && !expectedSerialNumber.equalsIgnoreCase(actualSerialNumber)) { + result.addError("证书序列号不匹配! 配置: " + expectedSerialNumber + ", 实际: " + actualSerialNumber); + } else { + result.addInfo("✅ 证书序列号匹配"); + } + + // 检查证书是否过期 + long now = System.currentTimeMillis(); + if (now < cert.getNotBefore().getTime()) { + result.addError("证书尚未生效"); + } else if (now > cert.getNotAfter().getTime()) { + result.addError("证书已过期"); + } else { + result.addInfo("✅ 证书在有效期内"); + } + } else { + result.addError("无法解析证书文件"); + } + } + } catch (Exception e) { + result.addError("证书验证失败: " + e.getMessage()); + } + } + + /** + * 生成建议 + */ + private void generateRecommendations(DiagnosticResult result) { + if (result.hasErrors()) { + result.addRecommendation("🔧 修复建议:"); + + String errorText = result.getErrors(); + if (errorText.contains("商户号")) { + result.addRecommendation("1. 请在支付配置中设置正确的商户号"); + } + + if (errorText.contains("序列号")) { + result.addRecommendation("2. 请检查商户证书序列号是否正确,可在微信商户平台查看"); + } + + if (errorText.contains("证书文件")) { + result.addRecommendation("3. 请确保证书文件已正确放置在指定目录"); + } + + if (errorText.contains("过期")) { + result.addRecommendation("4. 请更新过期的证书文件"); + } + + result.addRecommendation("5. 建议使用RSAAutoCertificateConfig自动证书配置,可避免手动管理证书"); + result.addRecommendation("6. 确保在微信商户平台开启API安全功能并申请使用微信支付公钥"); + } else { + result.addRecommendation("✅ 证书配置正常,建议使用自动证书配置以获得最佳体验"); + } + } + + /** + * 诊断结果类 + */ + public static class DiagnosticResult { + private final StringBuilder errors = new StringBuilder(); + private final StringBuilder warnings = new StringBuilder(); + private final StringBuilder info = new StringBuilder(); + private final StringBuilder recommendations = new StringBuilder(); + + public void addError(String error) { + if (errors.length() > 0) errors.append("\n"); + errors.append(error); + } + + public void addWarning(String warning) { + if (warnings.length() > 0) warnings.append("\n"); + warnings.append(warning); + } + + public void addInfo(String information) { + if (info.length() > 0) info.append("\n"); + info.append(information); + } + + public void addRecommendation(String recommendation) { + if (recommendations.length() > 0) recommendations.append("\n"); + recommendations.append(recommendation); + } + + public boolean hasErrors() { + return errors.length() > 0; + } + + public String getErrors() { + return errors.toString(); + } + + public String getWarnings() { + return warnings.toString(); + } + + public String getInfo() { + return info.toString(); + } + + public String getRecommendations() { + return recommendations.toString(); + } + + public String getFullReport() { + StringBuilder report = new StringBuilder(); + report.append("=== 微信支付证书诊断报告 ===\n\n"); + + if (info.length() > 0) { + report.append("📋 基本信息:\n").append(info).append("\n\n"); + } + + if (warnings.length() > 0) { + report.append("⚠️ 警告:\n").append(warnings).append("\n\n"); + } + + if (errors.length() > 0) { + report.append("❌ 错误:\n").append(errors).append("\n\n"); + } + + if (recommendations.length() > 0) { + report.append("💡 建议:\n").append(recommendations).append("\n\n"); + } + + report.append("=== 诊断报告结束 ==="); + return report.toString(); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateFixer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateFixer.java new file mode 100644 index 0000000..af6e357 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayCertificateFixer.java @@ -0,0 +1,312 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +/** + * 微信支付证书修复工具 + * 自动检测和修复常见的证书配置问题 + * + * @author 科技小王子 + * @since 2025-07-29 + */ +@Slf4j +@Component +public class WechatPayCertificateFixer { + + private final CertificateProperties certConfig; + private final CertificateLoader certificateLoader; + + public WechatPayCertificateFixer(CertificateProperties certConfig, CertificateLoader certificateLoader) { + this.certConfig = certConfig; + this.certificateLoader = certificateLoader; + } + + /** + * 自动修复证书配置问题 + * + * @param payment 支付配置 + * @param tenantId 租户ID + * @param environment 环境 + * @return 修复结果 + */ + public FixResult autoFixCertificateIssues(Payment payment, Integer tenantId, String environment) { + FixResult result = new FixResult(); + + log.info("开始自动修复租户 {} 的证书配置问题", tenantId); + + try { + // 1. 检查并修复基本配置 + fixBasicConfiguration(payment, result); + + // 2. 检查并修复证书文件问题 + fixCertificateFiles(payment, tenantId, environment, result); + + // 3. 检查并修复序列号问题 + fixSerialNumberIssues(payment, tenantId, environment, result); + + // 4. 生成修复建议 + generateFixRecommendations(result); + + } catch (Exception e) { + result.addError("修复过程中发生异常: " + e.getMessage()); + log.error("证书修复异常", e); + } + + log.info("证书配置修复完成,成功修复 {} 个问题", result.getFixedIssues().size()); + return result; + } + + /** + * 修复基本配置问题 + */ + private void fixBasicConfiguration(Payment payment, FixResult result) { + if (payment == null) { + result.addError("支付配置为空,无法修复"); + return; + } + + // 检查商户号 + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + result.addError("商户号未配置,需要手动设置"); + } + + // 检查应用ID + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + result.addError("应用ID未配置,需要手动设置"); + } + + // 检查APIv3密钥 + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + result.addWarning("APIv3密钥未配置,将使用配置文件默认值"); + } else if (payment.getApiKey().length() != 32) { + result.addError("APIv3密钥长度错误,应为32位,实际为: " + payment.getApiKey().length()); + } + + // 检查商户证书序列号 + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + result.addError("商户证书序列号未配置,需要手动设置"); + } + } + + /** + * 修复证书文件问题 + */ + private void fixCertificateFiles(Payment payment, Integer tenantId, String environment, FixResult result) { + if ("dev".equals(environment)) { + fixDevCertificateFiles(tenantId, result); + } else { + fixProdCertificateFiles(payment, result); + } + } + + /** + * 修复开发环境证书文件问题 + */ + private void fixDevCertificateFiles(Integer tenantId, FixResult result) { + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + // 检查私钥文件 + if (!certificateLoader.certificateExists(privateKeyPath)) { + result.addError("私钥文件不存在: " + privateKeyPath); + result.addRecommendation("请将 apiclient_key.pem 文件放置到 src/main/resources/" + privateKeyPath); + } else { + result.addFixed("私钥文件存在: " + privateKeyPath); + + // 尝试加载私钥文件 + try { + String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath); + result.addFixed("私钥文件加载成功: " + privateKeyFile); + } catch (Exception e) { + result.addError("私钥文件加载失败: " + e.getMessage()); + } + } + + // 检查商户证书文件(可选) + if (!certificateLoader.certificateExists(apiclientCertPath)) { + result.addWarning("商户证书文件不存在: " + apiclientCertPath + " (自动证书配置不需要此文件)"); + } else { + result.addFixed("商户证书文件存在: " + apiclientCertPath); + } + } + + /** + * 修复生产环境证书文件问题 + */ + private void fixProdCertificateFiles(Payment payment, FixResult result) { + if (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) { + result.addError("生产环境私钥文件路径未配置"); + } else { + result.addFixed("生产环境私钥文件路径已配置: " + payment.getApiclientKey()); + } + + if (payment.getApiclientCert() == null || payment.getApiclientCert().trim().isEmpty()) { + result.addWarning("生产环境商户证书文件路径未配置 (自动证书配置不需要此文件)"); + } else { + result.addFixed("生产环境商户证书文件路径已配置: " + payment.getApiclientCert()); + } + } + + /** + * 修复序列号问题 + */ + private void fixSerialNumberIssues(Payment payment, Integer tenantId, String environment, FixResult result) { + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + result.addError("商户证书序列号未配置"); + return; + } + + // 在开发环境中,尝试从证书文件中提取序列号进行验证 + if ("dev".equals(environment)) { + try { + String tenantCertPath = "dev/wechat/" + tenantId; + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + if (certificateLoader.certificateExists(apiclientCertPath)) { + String actualCertPath = certificateLoader.loadCertificatePath(apiclientCertPath); + + try (InputStream inputStream = new FileInputStream(new File(actualCertPath))) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); + + if (cert != null) { + String actualSerialNumber = cert.getSerialNumber().toString(16).toUpperCase(); + String configuredSerialNumber = payment.getMerchantSerialNumber(); + + if (!configuredSerialNumber.equalsIgnoreCase(actualSerialNumber)) { + result.addError("证书序列号不匹配! 配置: " + configuredSerialNumber + ", 实际: " + actualSerialNumber); + result.addRecommendation("建议将商户证书序列号更新为: " + actualSerialNumber); + } else { + result.addFixed("证书序列号匹配: " + actualSerialNumber); + } + } + } + } + } catch (Exception e) { + result.addWarning("无法验证证书序列号: " + e.getMessage()); + } + } + } + + /** + * 生成修复建议 + */ + private void generateFixRecommendations(FixResult result) { + if (result.hasErrors()) { + result.addRecommendation("=== 修复建议 ==="); + + if (result.getErrors().stream().anyMatch(e -> e.contains("商户号"))) { + result.addRecommendation("1. 请在微信商户平台获取商户号并在系统中配置"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("应用ID"))) { + result.addRecommendation("2. 请在微信开放平台获取应用ID并在系统中配置"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("APIv3密钥"))) { + result.addRecommendation("3. 请在微信商户平台设置32位APIv3密钥"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("证书序列号"))) { + result.addRecommendation("4. 请在微信商户平台查看正确的商户证书序列号"); + } + + if (result.getErrors().stream().anyMatch(e -> e.contains("私钥文件"))) { + result.addRecommendation("5. 请从微信商户平台下载私钥文件并放置到正确位置"); + } + + result.addRecommendation("6. 建议使用RSAAutoCertificateConfig自动证书配置"); + result.addRecommendation("7. 确保在微信商户平台开启API安全功能"); + } + } + + /** + * 修复结果类 + */ + public static class FixResult { + private final List errors = new ArrayList<>(); + private final List warnings = new ArrayList<>(); + private final List fixedIssues = new ArrayList<>(); + private final List recommendations = new ArrayList<>(); + + public void addError(String error) { + errors.add(error); + } + + public void addWarning(String warning) { + warnings.add(warning); + } + + public void addFixed(String fixed) { + fixedIssues.add(fixed); + } + + public void addRecommendation(String recommendation) { + recommendations.add(recommendation); + } + + public boolean hasErrors() { + return !errors.isEmpty(); + } + + public List getErrors() { + return errors; + } + + public List getWarnings() { + return warnings; + } + + public List getFixedIssues() { + return fixedIssues; + } + + public List getRecommendations() { + return recommendations; + } + + public String getFullReport() { + StringBuilder report = new StringBuilder(); + report.append("=== 微信支付证书修复报告 ===\n\n"); + + if (!fixedIssues.isEmpty()) { + report.append("✅ 已修复的问题:\n"); + fixedIssues.forEach(issue -> report.append(" - ").append(issue).append("\n")); + report.append("\n"); + } + + if (!warnings.isEmpty()) { + report.append("⚠️ 警告:\n"); + warnings.forEach(warning -> report.append(" - ").append(warning).append("\n")); + report.append("\n"); + } + + if (!errors.isEmpty()) { + report.append("❌ 需要手动修复的问题:\n"); + errors.forEach(error -> report.append(" - ").append(error).append("\n")); + report.append("\n"); + } + + if (!recommendations.isEmpty()) { + report.append("💡 修复建议:\n"); + recommendations.forEach(rec -> report.append(" ").append(rec).append("\n")); + report.append("\n"); + } + + report.append("=== 修复报告结束 ==="); + return report.toString(); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigChecker.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigChecker.java new file mode 100644 index 0000000..74a6fa4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigChecker.java @@ -0,0 +1,243 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * 微信支付配置检查器 + * 用于快速检查和验证微信支付配置状态 + * + * @author 科技小王子 + * @since 2025-07-29 + */ +@Slf4j +@Component +public class WechatPayConfigChecker { + + @Autowired + private PaymentCacheService paymentCacheService; + + @Autowired + private CertificateLoader certificateLoader; + + @Autowired + private CertificateProperties certConfig; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + /** + * 检查租户的微信支付配置状态 + * + * @param tenantId 租户ID + * @return 配置状态报告 + */ + public ConfigStatus checkTenantConfig(Integer tenantId) { + ConfigStatus status = new ConfigStatus(); + status.tenantId = tenantId; + status.environment = activeProfile; + + try { + // 获取支付配置 + Payment payment = paymentCacheService.getWechatPayConfig(tenantId); + if (payment == null) { + status.hasError = true; + status.errorMessage = "支付配置不存在"; + return status; + } + + status.merchantId = payment.getMchId(); + status.appId = payment.getAppId(); + status.serialNumber = payment.getMerchantSerialNumber(); + status.hasApiKey = payment.getApiKey() != null && !payment.getApiKey().isEmpty(); + status.apiKeyLength = payment.getApiKey() != null ? payment.getApiKey().length() : 0; + + // 检查公钥配置 + if (payment.getPubKey() != null && !payment.getPubKey().isEmpty() && + payment.getPubKeyId() != null && !payment.getPubKeyId().isEmpty()) { + + status.hasPublicKey = true; + status.publicKeyFile = payment.getPubKey(); + status.publicKeyId = payment.getPubKeyId(); + status.configMode = "公钥模式"; + + // 检查公钥文件是否存在 + String tenantCertPath = "dev/wechat/" + tenantId; + String pubKeyPath = tenantCertPath + "/" + payment.getPubKey(); + status.publicKeyExists = certificateLoader.certificateExists(pubKeyPath); + + } else { + status.hasPublicKey = false; + status.configMode = "自动证书模式"; + } + + // 检查私钥文件 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + status.privateKeyExists = certificateLoader.certificateExists(privateKeyPath); + + // 检查商户证书文件 + String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + status.merchantCertExists = certificateLoader.certificateExists(apiclientCertPath); + + // 评估配置完整性 + evaluateConfigCompleteness(status); + + } catch (Exception e) { + status.hasError = true; + status.errorMessage = "检查配置时发生异常: " + e.getMessage(); + log.error("检查租户 {} 配置时发生异常", tenantId, e); + } + + return status; + } + + /** + * 评估配置完整性 + */ + private void evaluateConfigCompleteness(ConfigStatus status) { + if (status.hasError) { + return; + } + + // 基本配置检查 + if (status.merchantId == null || status.merchantId.isEmpty()) { + status.addIssue("商户号未配置"); + } + + if (status.appId == null || status.appId.isEmpty()) { + status.addIssue("应用ID未配置"); + } + + if (status.serialNumber == null || status.serialNumber.isEmpty()) { + status.addIssue("商户证书序列号未配置"); + } + + if (!status.hasApiKey) { + status.addIssue("APIv3密钥未配置"); + } else if (status.apiKeyLength != 32) { + status.addIssue("APIv3密钥长度错误,应为32位,实际为" + status.apiKeyLength + "位"); + } + + if (!status.privateKeyExists) { + status.addIssue("私钥文件不存在"); + } + + // 公钥模式特定检查 + if (status.hasPublicKey) { + if (!status.publicKeyExists) { + status.addIssue("公钥文件不存在"); + } + } + + // 设置配置状态 + if (status.issues.isEmpty()) { + status.configComplete = true; + status.recommendation = "✅ 配置完整,建议使用当前配置"; + } else { + status.configComplete = false; + if (status.hasPublicKey) { + status.recommendation = "⚠️ 公钥配置不完整,建议修复问题或回退到自动证书模式"; + } else { + status.recommendation = "⚠️ 自动证书配置不完整,建议配置公钥模式或修复当前问题"; + } + } + } + + /** + * 生成配置建议 + */ + public String generateConfigAdvice(Integer tenantId) { + ConfigStatus status = checkTenantConfig(tenantId); + + StringBuilder advice = new StringBuilder(); + advice.append("=== 租户 ").append(tenantId).append(" 微信支付配置建议 ===\n\n"); + + advice.append("当前配置模式: ").append(status.configMode).append("\n"); + advice.append("配置完整性: ").append(status.configComplete ? "完整" : "不完整").append("\n\n"); + + if (status.hasError) { + advice.append("❌ 错误: ").append(status.errorMessage).append("\n\n"); + return advice.toString(); + } + + // 基本信息 + advice.append("📋 基本信息:\n"); + advice.append(" 商户号: ").append(status.merchantId).append("\n"); + advice.append(" 应用ID: ").append(status.appId).append("\n"); + advice.append(" 序列号: ").append(status.serialNumber).append("\n"); + advice.append(" API密钥: ").append(status.hasApiKey ? "已配置(" + status.apiKeyLength + "位)" : "未配置").append("\n\n"); + + // 证书文件状态 + advice.append("📁 证书文件状态:\n"); + advice.append(" 私钥文件: ").append(status.privateKeyExists ? "✅ 存在" : "❌ 不存在").append("\n"); + advice.append(" 商户证书: ").append(status.merchantCertExists ? "✅ 存在" : "⚠️ 不存在").append("\n"); + + if (status.hasPublicKey) { + advice.append(" 公钥文件: ").append(status.publicKeyExists ? "✅ 存在" : "❌ 不存在").append("\n"); + advice.append(" 公钥ID: ").append(status.publicKeyId).append("\n"); + } + advice.append("\n"); + + // 问题列表 + if (!status.issues.isEmpty()) { + advice.append("⚠️ 发现的问题:\n"); + for (String issue : status.issues) { + advice.append(" - ").append(issue).append("\n"); + } + advice.append("\n"); + } + + // 建议 + advice.append("💡 建议:\n"); + advice.append(" ").append(status.recommendation).append("\n\n"); + + if (!status.hasPublicKey) { + advice.append("🔧 配置公钥模式的步骤:\n"); + advice.append(" 1. 获取微信支付平台公钥文件和公钥ID\n"); + advice.append(" 2. 将公钥文件放置到: src/main/resources/dev/wechat/").append(tenantId).append("/\n"); + advice.append(" 3. 执行SQL更新数据库配置:\n"); + advice.append(" UPDATE sys_payment SET \n"); + advice.append(" pub_key = 'wechatpay_public_key.pem',\n"); + advice.append(" pub_key_id = 'YOUR_PUBLIC_KEY_ID'\n"); + advice.append(" WHERE tenant_id = ").append(tenantId).append(" AND type = 0;\n\n"); + } + + advice.append("=== 配置建议结束 ==="); + return advice.toString(); + } + + /** + * 配置状态类 + */ + public static class ConfigStatus { + public Integer tenantId; + public String environment; + public String merchantId; + public String appId; + public String serialNumber; + public boolean hasApiKey; + public int apiKeyLength; + public boolean hasPublicKey; + public String publicKeyFile; + public String publicKeyId; + public boolean publicKeyExists; + public boolean privateKeyExists; + public boolean merchantCertExists; + public String configMode; + public boolean configComplete; + public boolean hasError; + public String errorMessage; + public String recommendation; + public java.util.List issues = new java.util.ArrayList<>(); + + public void addIssue(String issue) { + issues.add(issue); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java new file mode 100644 index 0000000..23326d2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayConfigValidator.java @@ -0,0 +1,223 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +/** + * 微信支付配置验证工具 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Component +public class WechatPayConfigValidator { + + private final CertificateProperties certConfig; + private final CertificateLoader certificateLoader; + + @Value("${spring.profiles.active}") + private String activeProfile; + + public WechatPayConfigValidator(CertificateProperties certConfig, CertificateLoader certificateLoader) { + this.certConfig = certConfig; + this.certificateLoader = certificateLoader; + } + + /** + * 验证微信支付配置 + * + * @param payment 支付配置 + * @param tenantId 租户ID + * @return 验证结果 + */ + public ValidationResult validateWechatPayConfig(Payment payment, Integer tenantId) { + ValidationResult result = new ValidationResult(); + + log.info("开始验证微信支付配置 - 租户ID: {}", tenantId); + + // 1. 验证基本配置 + if (payment == null) { + result.addError("支付配置为空"); + return result; + } + + if (!StringUtils.hasText(payment.getMchId())) { + result.addError("商户号未配置"); + } + + if (!StringUtils.hasText(payment.getAppId())) { + result.addError("应用ID未配置"); + } + + if (!StringUtils.hasText(payment.getMerchantSerialNumber())) { + result.addError("商户证书序列号未配置"); + } + + // 2. 验证 APIv3 密钥 + String apiV3Key = getValidApiV3Key(payment); + if (!StringUtils.hasText(apiV3Key)) { + result.addError("APIv3密钥未配置"); + } else { + validateApiV3Key(apiV3Key, result); + } + + // 3. 验证证书文件 + validateCertificateFiles(tenantId, result); + + // 4. 记录验证结果 + if (result.isValid()) { + log.info("✅ 微信支付配置验证通过 - 租户ID: {}", tenantId); + } else { + log.error("❌ 微信支付配置验证失败 - 租户ID: {}, 错误: {}", tenantId, result.getErrors()); + } + + return result; + } + + /** + * 获取有效的 APIv3 密钥 + * 优先使用数据库配置,如果为空则使用配置文件默认值 + */ + public String getValidApiV3Key(Payment payment) { + String apiV3Key = payment.getApiKey(); + + if (!StringUtils.hasText(apiV3Key)) { + apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key(); + log.warn("数据库中APIv3密钥为空,使用配置文件默认值"); + } + + return apiV3Key; + } + + /** + * 验证 APIv3 密钥格式 + */ + private void validateApiV3Key(String apiV3Key, ValidationResult result) { + if (apiV3Key.length() != 32) { + result.addError("APIv3密钥长度错误,应为32位,实际为: " + apiV3Key.length()); + } + + if (!apiV3Key.matches("^[a-zA-Z0-9]+$")) { + result.addError("APIv3密钥格式错误,应仅包含字母和数字"); + } + + log.info("APIv3密钥验证 - 长度: {}, 格式: {}", + apiV3Key.length(), + apiV3Key.matches("^[a-zA-Z0-9]+$") ? "正确" : "错误"); + } + + /** + * 验证证书文件 + */ + private void validateCertificateFiles(Integer tenantId, ValidationResult result) { + if ("dev".equals(activeProfile)) { + // 开发环境证书验证 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + + if (!certificateLoader.certificateExists(privateKeyPath)) { + result.addError("证书文件不存在: " + privateKeyPath); + return; + } + + try { + certificateLoader.loadCertificatePath(privateKeyPath); + log.info("✅ 开发环境证书文件验证通过: {}", privateKeyPath); + } catch (Exception e) { + result.addError("证书文件加载失败: " + e.getMessage()); + } + } else { + // 生产环境证书验证 - 跳过文件存在性检查,因为证书路径来自数据库 + log.info("✅ 生产环境跳过证书文件存在性验证,使用数据库配置的证书路径"); + } + } + + /** + * 验证结果类 + */ + public static class ValidationResult { + private boolean valid = true; + private StringBuilder errors = new StringBuilder(); + + public void addError(String error) { + this.valid = false; + if (errors.length() > 0) { + errors.append("; "); + } + errors.append(error); + } + + public boolean isValid() { + return valid; + } + + public String getErrors() { + return errors.toString(); + } + + public void logErrors() { + if (!valid) { + log.error("配置验证失败: {}", errors.toString()); + } + } + } + + /** + * 生成配置诊断报告 + */ + public String generateDiagnosticReport(Payment payment, Integer tenantId) { + StringBuilder report = new StringBuilder(); + report.append("=== 微信支付配置诊断报告 ===\n"); + report.append("租户ID: ").append(tenantId).append("\n"); + + if (payment != null) { + report.append("商户号: ").append(payment.getMchId()).append("\n"); + report.append("应用ID: ").append(payment.getAppId()).append("\n"); + report.append("商户证书序列号: ").append(payment.getMerchantSerialNumber()).append("\n"); + + String dbApiKey = payment.getApiKey(); + String configApiKey = certConfig.getWechatPay().getDev().getApiV3Key(); + + report.append("数据库APIv3密钥: ").append(dbApiKey != null ? "已配置(" + dbApiKey.length() + "位)" : "未配置").append("\n"); + report.append("配置文件APIv3密钥: ").append(configApiKey != null ? "已配置(" + configApiKey.length() + "位)" : "未配置").append("\n"); + + String finalApiKey = getValidApiV3Key(payment); + report.append("最终使用APIv3密钥: ").append(finalApiKey != null ? "已配置(" + finalApiKey.length() + "位)" : "未配置").append("\n"); + + } else { + report.append("❌ 支付配置为空\n"); + } + + // 证书文件检查 + report.append("当前环境: ").append(activeProfile).append("\n"); + if ("dev".equals(activeProfile)) { + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + boolean certExists = certificateLoader.certificateExists(privateKeyPath); + + report.append("开发环境证书文件路径: ").append(privateKeyPath).append("\n"); + report.append("证书文件存在: ").append(certExists ? "是" : "否").append("\n"); + } else { + report.append("生产环境证书路径: 从数据库配置获取\n"); + if (payment != null) { + report.append("私钥文件: ").append(payment.getApiclientKey()).append("\n"); + report.append("证书文件: ").append(payment.getApiclientCert()).append("\n"); + } + } + + ValidationResult validation = validateWechatPayConfig(payment, tenantId); + report.append("配置验证结果: ").append(validation.isValid() ? "通过" : "失败").append("\n"); + if (!validation.isValid()) { + report.append("验证错误: ").append(validation.getErrors()).append("\n"); + } + + report.append("=== 诊断报告结束 ==="); + + return report.toString(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java new file mode 100644 index 0000000..620d506 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayDiagnostic.java @@ -0,0 +1,222 @@ +package com.gxwebsoft.common.core.utils; + +import com.gxwebsoft.common.system.entity.Payment; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * 微信支付配置诊断工具 + * 用于排查微信支付签名验证失败等问题 + * + * @author 科技小王子 + * @since 2025-07-27 + */ +@Slf4j +@Component +public class WechatPayDiagnostic { + + /** + * 诊断微信支付配置 + * + * @param payment 支付配置 + * @param privateKeyPath 私钥路径 + * @param environment 环境标识 + */ + public void diagnosePaymentConfig(Payment payment, String privateKeyPath, String environment) { + log.info("=== 微信支付配置诊断开始 ==="); + log.info("环境: {}", environment); + + // 1. 检查支付配置基本信息 + checkBasicConfig(payment); + + // 2. 检查证书文件 + checkCertificateFiles(payment, privateKeyPath, environment); + + // 3. 检查配置完整性 + checkConfigCompleteness(payment); + + log.info("=== 微信支付配置诊断结束 ==="); + } + + /** + * 检查基本配置信息 + */ + private void checkBasicConfig(Payment payment) { + log.info("--- 基本配置检查 ---"); + + if (payment == null) { + log.error("❌ 支付配置为空"); + return; + } + + log.info("支付配置ID: {}", payment.getId()); + log.info("支付方式名称: {}", payment.getName()); + log.info("支付类型: {}", payment.getType()); + log.info("支付代码: {}", payment.getCode()); + log.info("状态: {}", payment.getStatus()); + + // 检查关键字段 + checkField("应用ID", payment.getAppId()); + checkField("商户号", payment.getMchId()); + checkField("商户证书序列号", payment.getMerchantSerialNumber()); + checkField("API密钥", payment.getApiKey(), true); + } + + /** + * 检查证书文件 + */ + private void checkCertificateFiles(Payment payment, String privateKeyPath, String environment) { + log.info("--- 证书文件检查 ---"); + + // 检查私钥文件 + if (privateKeyPath != null) { + checkFileExists("私钥文件", privateKeyPath); + } + + // 生产环境检查证书文件 + if (!"dev".equals(environment)) { + if (payment.getApiclientCert() != null) { + log.info("商户证书文件配置: {}", payment.getApiclientCert()); + } + + if (payment.getPubKey() != null) { + log.info("公钥文件配置: {}", payment.getPubKey()); + log.info("公钥ID: {}", payment.getPubKeyId()); + } + } + } + + /** + * 检查配置完整性 + */ + private void checkConfigCompleteness(Payment payment) { + log.info("--- 配置完整性检查 ---"); + + boolean isComplete = true; + + if (isEmpty(payment.getMchId())) { + log.error("❌ 商户号未配置"); + isComplete = false; + } + + if (isEmpty(payment.getMerchantSerialNumber())) { + log.error("❌ 商户证书序列号未配置"); + isComplete = false; + } + + if (isEmpty(payment.getApiKey())) { + log.error("❌ API密钥未配置"); + isComplete = false; + } + + if (isEmpty(payment.getAppId())) { + log.error("❌ 应用ID未配置"); + isComplete = false; + } + + if (isComplete) { + log.info("✅ 配置完整性检查通过"); + } else { + log.error("❌ 配置不完整,请补充缺失的配置项"); + } + } + + /** + * 检查字段是否为空 + */ + private void checkField(String fieldName, String value) { + checkField(fieldName, value, false); + } + + /** + * 检查字段是否为空 + */ + private void checkField(String fieldName, String value, boolean isSensitive) { + if (isEmpty(value)) { + log.warn("⚠️ {}: 未配置", fieldName); + } else { + if (isSensitive) { + log.info("✅ {}: 已配置(长度:{})", fieldName, value.length()); + } else { + log.info("✅ {}: {}", fieldName, value); + } + } + } + + /** + * 检查文件是否存在 + */ + private void checkFileExists(String fileName, String filePath) { + try { + File file = new File(filePath); + if (file.exists() && file.isFile()) { + log.info("✅ {}: 文件存在 - {}", fileName, filePath); + log.info(" 文件大小: {} bytes", file.length()); + + // 检查文件内容格式 + if (filePath.endsWith(".pem")) { + checkPemFileFormat(fileName, filePath); + } + } else { + log.error("❌ {}: 文件不存在 - {}", fileName, filePath); + } + } catch (Exception e) { + log.error("❌ {}: 检查文件时出错 - {} ({})", fileName, filePath, e.getMessage()); + } + } + + /** + * 检查PEM文件格式 + */ + private void checkPemFileFormat(String fileName, String filePath) { + try { + String content = Files.readString(Paths.get(filePath)); + if (content.contains("-----BEGIN") && content.contains("-----END")) { + log.info("✅ {}: PEM格式正确", fileName); + } else { + log.warn("⚠️ {}: PEM格式可能有问题", fileName); + } + } catch (Exception e) { + log.warn("⚠️ {}: 无法读取文件内容进行格式检查 ({})", fileName, e.getMessage()); + } + } + + /** + * 检查字符串是否为空 + */ + private boolean isEmpty(String str) { + return str == null || str.trim().isEmpty(); + } + + /** + * 生成诊断报告 + */ + public String generateDiagnosticReport(Payment payment, String environment) { + StringBuilder report = new StringBuilder(); + report.append("🔍 微信支付配置诊断报告\n"); + report.append("========================\n\n"); + + report.append("环境: ").append(environment).append("\n"); + report.append("租户ID: ").append(payment != null ? payment.getTenantId() : "未知").append("\n"); + report.append("商户号: ").append(payment != null ? payment.getMchId() : "未配置").append("\n"); + report.append("应用ID: ").append(payment != null ? payment.getAppId() : "未配置").append("\n\n"); + + report.append("🚨 常见问题排查:\n"); + report.append("1. 商户证书序列号是否正确\n"); + report.append("2. APIv3密钥是否正确\n"); + report.append("3. 私钥文件是否正确\n"); + report.append("4. 微信支付平台证书是否过期\n"); + report.append("5. 网络连接是否正常\n\n"); + + report.append("💡 建议解决方案:\n"); + report.append("1. 使用自动证书配置(RSAAutoCertificateConfig)\n"); + report.append("2. 在微信商户平台重新下载证书\n"); + report.append("3. 检查商户平台API安全设置\n"); + + return report.toString(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayUtils.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayUtils.java new file mode 100644 index 0000000..14a31e9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WechatPayUtils.java @@ -0,0 +1,111 @@ +package com.gxwebsoft.common.core.utils; + +import java.nio.charset.StandardCharsets; + +/** + * 微信支付工具类 + * 处理微信支付API的字段限制和格式要求 + * + * @author 科技小王子 + * @since 2025-01-11 + */ +public class WechatPayUtils { + + /** + * 微信支付description字段的最大字节数限制 + */ + public static final int DESCRIPTION_MAX_BYTES = 127; + + /** + * 微信支付attach字段的最大字节数限制 + */ + public static final int ATTACH_MAX_BYTES = 127; + + /** + * 截断字符串以确保字节数不超过指定限制 + * 主要用于微信支付API的字段限制处理 + * + * @param text 原始文本 + * @param maxBytes 最大字节数 + * @return 截断后的文本,确保UTF-8字符完整性 + */ + public static String truncateToByteLimit(String text, int maxBytes) { + if (text == null || text.isEmpty()) { + return text; + } + + byte[] bytes = text.getBytes(StandardCharsets.UTF_8); + if (bytes.length <= maxBytes) { + return text; + } + + // 截断字节数组,但要确保不会截断UTF-8字符的中间 + int truncateLength = maxBytes; + while (truncateLength > 0) { + byte[] truncated = new byte[truncateLength]; + System.arraycopy(bytes, 0, truncated, 0, truncateLength); + + try { + String result = new String(truncated, StandardCharsets.UTF_8); + // 检查是否有无效字符(被截断的UTF-8字符) + if (!result.contains("\uFFFD")) { + return result; + } + } catch (Exception e) { + // 继续尝试更短的长度 + } + truncateLength--; + } + + return ""; // 如果无法安全截断,返回空字符串 + } + + /** + * 处理微信支付商品描述字段 + * 确保字节数不超过127字节 + * + * @param description 商品描述 + * @return 处理后的描述,符合微信支付要求 + */ + public static String processDescription(String description) { + return truncateToByteLimit(description, DESCRIPTION_MAX_BYTES); + } + + /** + * 处理微信支付附加数据字段 + * 确保字节数不超过127字节 + * + * @param attach 附加数据 + * @return 处理后的附加数据,符合微信支付要求 + */ + public static String processAttach(String attach) { + return truncateToByteLimit(attach, ATTACH_MAX_BYTES); + } + + /** + * 验证字符串是否符合微信支付字段的字节限制 + * + * @param text 待验证的文本 + * @param maxBytes 最大字节数限制 + * @return true如果符合限制,false如果超出限制 + */ + public static boolean isWithinByteLimit(String text, int maxBytes) { + if (text == null) { + return true; + } + return text.getBytes(StandardCharsets.UTF_8).length <= maxBytes; + } + + /** + * 获取字符串的UTF-8字节数 + * + * @param text 文本 + * @return 字节数 + */ + public static int getByteLength(String text) { + if (text == null) { + return 0; + } + return text.getBytes(StandardCharsets.UTF_8).length; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxMiniprogramUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxMiniprogramUtil.java new file mode 100644 index 0000000..acd65e2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxMiniprogramUtil.java @@ -0,0 +1,197 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.app.entity.AppSetting; +import com.gxwebsoft.app.service.AppSettingService; +import com.gxwebsoft.common.core.config.SpringContextUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * 微信小程序码工具类 + * 用于生成小程序码(无限制二维码) + * + * @author 科技小王子 + */ +@Slf4j +public class WxMiniprogramUtil { + + private static final String ACCESS_TOKEN_KEY = "WX_ACCESS_TOKEN:"; + private static final String SETTING_KEY = "platform_miniprogram"; + private static final Integer DEFAULT_TENANT_ID = 5; + + /** + * 生成小程序码(Base64格式) + * + * @param token 邀请/登录token + * @param page 小程序页面路径(如:pages/passport/qr-confirm/index) + * @param width 二维码宽度(默认280) + * @param envVersion 环境版本:release/trial/develop + * @return 小程序码 Base64 字符串(带 data:image/png;base64, 前缀),失败返回 null + */ + public static String generateMiniprogramQrCode(String token, String page, Integer width, String envVersion) { + try { + String accessToken = getAccessToken(); + if (StrUtil.isBlank(accessToken)) { + log.warn("获取小程序access_token失败,跳过生成小程序码"); + return null; + } + + String apiUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken; + + JSONObject params = new JSONObject(); + params.put("scene", token); + params.put("page", page); + params.put("env_version", envVersion != null ? envVersion : "release"); + params.put("width", width != null ? width : 280); + params.put("auto_color", false); + + byte[] imageBytes = HttpRequest.post(apiUrl) + .body(params.toJSONString()) + .timeout(15000) + .execute().bodyBytes(); + + if (imageBytes == null || imageBytes.length == 0) { + log.error("生成小程序码API返回空数据"); + return null; + } + + // 检查是否返回JSON错误 + if (imageBytes.length < 100 && new String(imageBytes).startsWith("{")) { + JSONObject errorResult = JSON.parseObject(new String(imageBytes)); + Integer errCode = errorResult.getInteger("errcode"); + String errMsg = errorResult.getString("errmsg"); + log.error("生成小程序码API返回错误[{}:{}]", errCode, errMsg); + return null; + } + + // 转换为Base64 + String base64Image = cn.hutool.core.codec.Base64.encode(imageBytes); + return "data:image/png;base64," + base64Image; + } catch (Exception e) { + log.error("生成小程序码异常: {}", e.getMessage(), e); + return null; + } + } + + /** + * 获取小程序access_token + */ + public static String getAccessToken() { + Integer tenantId = DEFAULT_TENANT_ID; + String key = ACCESS_TOKEN_KEY + tenantId; + + try { + // 通过 SpringContextUtil 获取 StringRedisTemplate,避免循环依赖 + StringRedisTemplate redisTemplate = getRedisTemplate(); + if (redisTemplate == null) { + log.warn("无法获取StringRedisTemplate"); + return null; + } + + // 从缓存获取 + String cachedToken = redisTemplate.opsForValue().get(key); + if (StrUtil.isNotBlank(cachedToken)) { + try { + JSONObject tokenData = JSON.parseObject(cachedToken); + String accessToken = tokenData.getString("access_token"); + if (StrUtil.isNotBlank(accessToken)) { + return accessToken; + } + } catch (Exception e) { + redisTemplate.delete(key); + } + } + + // 获取微信小程序配置 + JSONObject settingJson = getMiniprogramSetting(); + if (settingJson == null) { + log.warn("微信小程序配置不存在或解析失败"); + return null; + } + + String appId = settingJson.getString("appId"); + String appSecret = settingJson.getString("appSecret"); + if (StrUtil.isBlank(appId) || StrUtil.isBlank(appSecret)) { + log.warn("微信小程序配置不完整"); + return null; + } + + // 调用微信API获取AccessToken + String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + + appId + "&secret=" + appSecret; + String response = HttpRequest.get(apiUrl).execute().body(); + + JSONObject result = JSON.parseObject(response); + String accessToken = result.getString("access_token"); + if (StrUtil.isNotBlank(accessToken)) { + // 存入缓存 + JSONObject tokenData = new JSONObject(); + tokenData.put("access_token", accessToken); + tokenData.put("expires_in", result.get("expires_in")); + redisTemplate.opsForValue().set(key, tokenData.toJSONString(), 7000L, TimeUnit.SECONDS); + return accessToken; + } else { + log.error("获取AccessToken失败: {}", response); + return null; + } + } catch (Exception e) { + log.error("获取微信AccessToken失败: {}", e.getMessage(), e); + return null; + } + } + + /** + * 获取微信小程序配置(从 app_setting 表读取) + */ + private static JSONObject getMiniprogramSetting() { + try { + // 通过 SpringContextUtil 获取 AppSettingService + AppSettingService appSettingService = SpringContextUtil.getBean(AppSettingService.class); + if (appSettingService == null) { + log.warn("无法获取 AppSettingService"); + return null; + } + + // 从 app_setting 表获取小程序配置 + AppSetting appSetting = appSettingService.getByKey(SETTING_KEY); + if (appSetting == null || StrUtil.isBlank(appSetting.getSettingValue())) { + log.warn("微信小程序配置不存在或为空,settingKey={}", SETTING_KEY); + return null; + } + + // 解析 setting_value(JSON格式) + String settingValue = appSetting.getSettingValue(); + return JSON.parseObject(settingValue); + } catch (Exception e) { + log.warn("获取微信小程序配置失败: {}", e.getMessage()); + return null; + } + } + + /** + * 获取StringRedisTemplate + */ + private static StringRedisTemplate getRedisTemplate() { + try { + return SpringContextUtil.getBean(StringRedisTemplate.class); + } catch (Exception e) { + log.warn("通过类型获取StringRedisTemplate失败: {}", e.getMessage()); + } + // 尝试通过名称获取 + try { + Object bean = SpringContextUtil.getBean("stringRedisTemplate"); + if (bean instanceof StringRedisTemplate) { + return (StringRedisTemplate) bean; + } + } catch (Exception ex) { + log.warn("通过名称获取StringRedisTemplate失败: {}", ex.getMessage()); + } + return null; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxNativeUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxNativeUtil.java new file mode 100644 index 0000000..52a8d2c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxNativeUtil.java @@ -0,0 +1,20 @@ +package com.gxwebsoft.common.core.utils; + +import com.wechat.pay.java.core.Config; + +import java.util.HashMap; +import java.util.Map; + + +public class WxNativeUtil { + + private static final Map tenantConfigs = new HashMap<>(); + + public static void addConfig(Integer tenantId, Config config) { + tenantConfigs.put(tenantId, config); + } + + public static Config getConfig(Integer tenantId) { + return tenantConfigs.get(tenantId); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java new file mode 100644 index 0000000..4f10747 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java @@ -0,0 +1,106 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.service.SettingService; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +/** + * 微信公众号工具类 + * @author 科技小王子 + * + */ +@Component +public class WxOfficialUtil { + private final StringRedisTemplate stringRedisTemplate; + private Integer tenantId; + public String appId; + public String appSecret; + public String openid; + public String unionid; + public String access_token; + public String expires_in; + public String nickname; + + + @Resource + private SettingService settingService; + @Resource + private ConfigProperties pathConfig; + @Resource + private CacheClient cacheClient; + + public WxOfficialUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + // 实例化客户端 + public WxOfficialUtil client(Integer tenantId) { + if(tenantId > 0){ + throw new BusinessException(tenantId + "123123"); + } + this.tenantId = tenantId; + this.config(); + System.out.println("this.tenantId = " + this.tenantId); + return this; + } + + // 开发者ID和秘钥 + private void config() { + String key = "cache"+ this.tenantId +":setting:wx-official"; + String wxOfficial = stringRedisTemplate.opsForValue().get(key); + JSONObject data = JSONObject.parseObject(wxOfficial); + if(data != null){ + this.appId = data.getString("appId"); + this.appSecret = data.getString("appSecret"); + } + System.out.println("this.appId = " + this.appId); + System.out.println("this.appSecret = " + this.appSecret); + } + + // 获取appId + public String getAppSecret(){ + return this.appSecret; + } + + public String getCodeUrl() throws UnsupportedEncodingException { + String encodedReturnUrl = URLEncoder.encode(pathConfig.getServerUrl() + "/open/wx-official/accessToken","UTF-8"); + return "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+ this.appId +"&redirect_uri=" + encodedReturnUrl + "&response_type=code&scope=snsapi_userinfo&state="+ this.tenantId +"#wechat_redirect"; + } + + // 获取access_token + public String getAccessToken(String code) { + String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ this.appId +"&secret="+ this.appSecret +"&code="+ code +"&grant_type=authorization_code"; + System.out.println("url = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + final JSONObject jsonObject = JSONObject.parseObject(response); + access_token = jsonObject.getString("access_token"); + if(access_token == null){ + throw new BusinessException("获取access_token失败"); + } + this.openid = jsonObject.getString("openid"); + this.unionid = jsonObject.getString("unionid"); + this.expires_in = jsonObject.getString("expires_in"); + return access_token; + } + + // 获取userinfo + public JSONObject getUserInfo(String access_token) { + String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+ access_token +"&openid="+ this.openid +"&lang=zh_CN"; + System.out.println("url2 = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response = " + response); + if(response == null){ + throw new BusinessException("获取userinfo失败"); + } + return JSONObject.parseObject(response); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxUtil.java new file mode 100644 index 0000000..ad45abe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxUtil.java @@ -0,0 +1,152 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.exception.BusinessException; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +/** + * 微信小程序工具类 + * @author 科技小王子 + * + */ +@Component +public class WxUtil { + private final StringRedisTemplate stringRedisTemplate; + private Integer tenantId; + public String appId; + public String appSecret; + public String access_token; + public String expires_in; + public String nickname; + public String userid; + public String user_ticket; + public String openid; + public String external_userid; + public String name; + public String position; + public String mobile; + public String gender; + public String email; + public String avatar; + public String thumb_avatar; + public String telephone; + public String address; + public String alias; + public String qr_code; + public String open_userid; + + @Resource + private CacheClient cacheClient; + + + public WxUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + + // 实例化客户端 + public WxUtil client(Integer tenantId) { + this.tenantId = tenantId; + this.config(); + return this; + } + + // 开发者ID和秘钥 + private void config() { + JSONObject settingInfo = cacheClient.getSettingInfo("wx-work", this.tenantId); + if(settingInfo == null){ + throw new BusinessException("微信小程序未配置"); + } + this.appId = settingInfo.getString("corpId"); + this.appSecret = settingInfo.getString("secret"); + System.out.println("this.appId = " + this.appId); + System.out.println("this.appSecret = " + this.appSecret); + } + + // 获取access_token + public void getAccessToken(String code) { + String key = "cache"+ this.tenantId +":ww:access_token"; + final String cachedValue = stringRedisTemplate.opsForValue().get(key); + + if(cachedValue != null){ + try { + // 尝试解析JSON格式的缓存 + JSONObject cachedJson = JSONObject.parseObject(cachedValue); + String accessToken = cachedJson.getString("access_token"); + if (accessToken != null) { + this.access_token = accessToken; + this.getUserInfo(code, accessToken); + return; + } + } catch (Exception e) { + // 如果解析失败,可能是旧格式的纯字符串token + System.out.println("企业微信缓存token格式异常,使用原值: " + e.getMessage()); + this.access_token = cachedValue; + this.getUserInfo(code, cachedValue); + return; + } + } + + // 缓存中没有,重新获取 + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" +this.appId+ "&corpsecret="+ this.appSecret; + System.out.println("调用企业微信API获取token - URL: " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("企业微信API响应: " + response); + final JSONObject jsonObject = JSONObject.parseObject(response); + + // 获取成功 + if(jsonObject.getString("access_token") != null){ + this.access_token = jsonObject.getString("access_token"); + this.expires_in = jsonObject.getString("expires_in"); + + // 缓存完整的JSON响应,与其他方法保持一致 + stringRedisTemplate.opsForValue().set(key, response, 7000, TimeUnit.SECONDS); + System.out.println("获取企业微信access_token成功 = " + this.access_token); + this.getUserInfo(code, this.access_token); + } + } + + // 获取userinfo + public void getUserInfo(String code, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=" +access_token+ "&code=" + code; + System.out.println("url2 = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + JSONObject jsonObject = JSONObject.parseObject(response); + final String errcode = jsonObject.getString("errcode"); + final String errmsg = jsonObject.getString("errmsg"); + if(!StrUtil.equals(errcode,"0")){ + throw new BusinessException(errmsg); + } + this.userid = jsonObject.getString("userid"); + this.user_ticket = jsonObject.getString("user_ticket"); + this.openid = jsonObject.getString("openid"); + this.external_userid = jsonObject.getString("external_userid"); + } + + public void getUserProfile(String userid, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token="+ access_token +"&userid=" + userid; + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + JSONObject jsonObject = JSONObject.parseObject(response); + + this.name = jsonObject.getString("name"); + this.position = jsonObject.getString("position"); + this.gender = jsonObject.getString("gender"); + this.email = jsonObject.getString("email"); + this.avatar = jsonObject.getString("avatar"); + this.thumb_avatar = jsonObject.getString("thumb_avatar"); + this.telephone = jsonObject.getString("telephone"); + this.address = jsonObject.getString("address"); + this.alias = jsonObject.getString("alias"); + this.qr_code = jsonObject.getString("qr_code"); + this.open_userid = jsonObject.getString("open_userid"); + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxWorkUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxWorkUtil.java new file mode 100644 index 0000000..70635ed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/utils/WxWorkUtil.java @@ -0,0 +1,154 @@ +package com.gxwebsoft.common.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.exception.BusinessException; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +/** + * 企业微信工具类 + * @author 科技小王子 + * + */ +@Component +public class WxWorkUtil { + private final StringRedisTemplate stringRedisTemplate; + private Integer tenantId; + public String appId; + public String appSecret; + public String access_token; + public String expires_in; + public String nickname; + public String userid; + public String user_ticket; + public String openid; + public String external_userid; + public String name; + public String position; + public String mobile; + public String gender; + public String email; + public String avatar; + public String thumb_avatar; + public String telephone; + public String address; + public String alias; + public String qr_code; + public String open_userid; + + @Resource + private CacheClient cacheClient; + + + public WxWorkUtil(StringRedisTemplate stringRedisTemplate){ + this.stringRedisTemplate = stringRedisTemplate; + } + + + // 实例化客户端 + public WxWorkUtil client(Integer tenantId) { + this.tenantId = tenantId; + this.config(); + return this; + } + + // 开发者ID和秘钥 + private void config() { + JSONObject settingInfo = cacheClient.getSettingInfo("wx-work", this.tenantId); + if(settingInfo == null){ + throw new BusinessException("企业微信未配置"); + } + this.appId = settingInfo.getString("corpId"); + this.appSecret = settingInfo.getString("secret"); + System.out.println("this.appId = " + this.appId); + System.out.println("this.appSecret = " + this.appSecret); + } + + // 获取access_token + public void getAccessToken(String code) { + String key = "cache"+ this.tenantId +":ww:access_token"; + final String cachedValue = stringRedisTemplate.opsForValue().get(key); + + if(cachedValue != null){ + try { + // 尝试解析JSON格式的缓存 + JSONObject cachedJson = JSONObject.parseObject(cachedValue); + String accessToken = cachedJson.getString("access_token"); + if (accessToken != null) { + this.access_token = accessToken; + this.getUserInfo(code, accessToken); + return; + } + } catch (Exception e) { + // 如果解析失败,可能是旧格式的纯字符串token + System.out.println("企业微信Work缓存token格式异常,使用原值: " + e.getMessage()); + this.access_token = cachedValue; + this.getUserInfo(code, cachedValue); + return; + } + } + + // 缓存中没有,重新获取 + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" +this.appId+ "&corpsecret="+ this.appSecret; + System.out.println("调用企业微信Work API获取token - URL: " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("企业微信Work API响应: " + response); + final JSONObject jsonObject = JSONObject.parseObject(response); + + // 获取成功 + if(jsonObject.getString("access_token") != null){ + this.access_token = jsonObject.getString("access_token"); + this.expires_in = jsonObject.getString("expires_in"); + + // 缓存完整的JSON响应,与其他方法保持一致 + stringRedisTemplate.opsForValue().set(key, response, 7000, TimeUnit.SECONDS); + System.out.println("获取企业微信Work access_token成功 = " + this.access_token); + this.getUserInfo(code, this.access_token); + } + } + + // 获取userinfo + public void getUserInfo(String code, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=" +access_token+ "&code=" + code; + System.out.println("url2 = " + url); + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response = " + response); + JSONObject jsonObject = JSONObject.parseObject(response); + final String errcode = jsonObject.getString("errcode"); + final String errmsg = jsonObject.getString("errmsg"); + if(!StrUtil.equals(errcode,"0")){ + throw new BusinessException(errmsg); + } + this.userid = jsonObject.getString("userid"); + this.user_ticket = jsonObject.getString("user_ticket"); + this.openid = jsonObject.getString("openid"); + this.external_userid = jsonObject.getString("external_userid"); + System.out.println("获取用户信息成功 = " + jsonObject); + } + + public void getUserProfile(String userid, String access_token) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token="+ access_token +"&userid=" + userid; + String response = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8); + System.out.println("response3 = " + response); + JSONObject jsonObject = JSONObject.parseObject(response); + System.out.println("读取用户详细信息 = " + jsonObject); + + this.name = jsonObject.getString("name"); + this.position = jsonObject.getString("position"); + this.gender = jsonObject.getString("gender"); + this.email = jsonObject.getString("email"); + this.avatar = jsonObject.getString("avatar"); + this.thumb_avatar = jsonObject.getString("thumb_avatar"); + this.telephone = jsonObject.getString("telephone"); + this.address = jsonObject.getString("address"); + this.alias = jsonObject.getString("alias"); + this.qr_code = jsonObject.getString("qr_code"); + this.open_userid = jsonObject.getString("open_userid"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/ApiResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/ApiResult.java new file mode 100644 index 0000000..0313839 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/ApiResult.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.common.core.web; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serializable; + +/** + * 返回结果 + * + * @author WebSoft + * @since 2017-06-10 10:10:50 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ApiResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "状态码") + private Integer code; + + @Schema(description = "状态信息") + private String message; + + @Schema(description = "返回数据") + private T data; + + @Schema(description = "错误信息") + private String error; + + public ApiResult() {} + + public ApiResult(Integer code) { + this(code, null); + } + + public ApiResult(Integer code, String message) { + this(code, message, null); + } + + public ApiResult(Integer code, String message, T data) { + this(code, message, data, null); + } + + public ApiResult(Integer code, String message, T data, String error) { + setCode(code); + setMessage(message); + setData(data); + setError(error); + } + + public Integer getCode() { + return this.code; + } + + public ApiResult setCode(Integer code) { + this.code = code; + return this; + } + + public String getMessage() { + return this.message; + } + + public ApiResult setMessage(String message) { + this.message = message; + return this; + } + + public T getData() { + return this.data; + } + + public ApiResult setData(T data) { + this.data = data; + return this; + } + + public String getError() { + return this.error; + } + + public ApiResult setError(String error) { + this.error = error; + return this; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BaseController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BaseController.java new file mode 100644 index 0000000..556c1ac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BaseController.java @@ -0,0 +1,333 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.SignCheckUtil; +import com.gxwebsoft.common.system.entity.User; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Controller基类 + * + * @author WebSoft + * @since 2017-06-10 10:10:19 + */ +public class BaseController { + @Resource + private HttpServletRequest request; + @Resource + private RedisUtil redisUtil; + + /** + * 获取当前登录的user + * + * @return User + */ + public User getLoginUser() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + Object object = authentication.getPrincipal(); + if (object instanceof User) { + return (User) object; + } + } + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return null; + } + + /** + * 获取当前登录的userId + * + * @return userId + */ + public Integer getLoginUserId() { + User loginUser = getLoginUser(); + return loginUser == null ? null : loginUser.getUserId(); + } + + /** + * 获取当前登录的tenantId + * + * @return tenantId + */ + public Integer getTenantId() { + String tenantId; + // 2 从请求头拿ID + tenantId = request.getHeader("tenantId"); + if(StrUtil.isNotBlank(tenantId)){ + return Integer.valueOf(tenantId); + } + // 3 从登录用户拿tenantId + User loginUser = getLoginUser(); + if (loginUser != null) { + return loginUser.getTenantId(); + } + // 1 从域名拿ID + String Domain = request.getHeader("Domain"); + if (StrUtil.isNotBlank(Domain)) { + String key = "Domain:" + Domain; + tenantId = redisUtil.get(key); + if(tenantId != null){ + System.out.println("从域名拿ID = " + tenantId); + return Integer.valueOf(tenantId); + } + } + return null; + } + + /** + * 返回成功 + * + * @return ApiResult + */ + public ApiResult success() { + return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG); + } + + /** + * 返回成功 + * + * @param message 状态信息 + * @return ApiResult + */ + public ApiResult success(String message) { + return new ApiResult<>(Constants.RESULT_OK_CODE, message); + } + + /** + * 返回成功 + * + * @param data 返回数据 + * @return ApiResult + */ + public ApiResult success(T data) { + return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG, data); + } + + /** + * 返回成功 + * + * @param message 状态信息 + * @return ApiResult + */ + public ApiResult success(String message, T data) { + return success(data).setMessage(message); + } + + /** + * 返回分页查询数据 + * + * @param list 当前页数据 + * @param count 总数量 + * @return ApiResult + */ + public ApiResult> success(List list, Long count) { + return success(new PageResult<>(list, count)); + } + + /** + * 返回分页查询数据 + * + * @param iPage IPage + * @return ApiResult + */ + public ApiResult> success(IPage iPage) { + return success(iPage.getRecords(), iPage.getTotal()); + } + + /** + * 返回失败 + * + * @return ApiResult + */ + public ApiResult fail() { + return new ApiResult<>(Constants.RESULT_ERROR_CODE, Constants.RESULT_ERROR_MSG); + } + + /** + * 返回失败 + * + * @param message 状态信息 + * @return ApiResult + */ + public ApiResult fail(String message) { + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message); + } + + /** + * 返回失败 + * + * @param data 返回数据 + * @return ApiResult + */ + public ApiResult fail(T data) { + return fail(Constants.RESULT_ERROR_MSG, data); + } + + /** + * 返回失败 + * + * @param message 状态信息 + * @param data 返回数据 + * @return ApiResult + */ + public ApiResult fail(String message, T data) { + return new ApiResult<>(Constants.RESULT_ERROR_CODE, message, data); + } + + /** + * 请求参数的空字符串转为null + */ + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); + } + + // 自定义函数 + public String getAuthorization(){ + return request.getHeader("Authorization"); + } + + public String getAppId() { + // 兼容小写 + if(request.getHeader("appid") != null){ + return request.getHeader("appid"); + } + return request.getHeader("AppId"); + } + + public String getSign() { + return request.getParameter("sign"); + } + + /** + * 是否校验签名信息 + * 存在签名信息则需要验证 + */ + public void isCheckSign() { + if (StrUtil.isNotBlank(getSign())) { + if(getTenantId() == null){ + throw new BusinessException("签名失败:TenantId不能为空"); + } + + String timestamp1 = request.getParameter("timestamp"); + long timestamp2 = System.currentTimeMillis(); + long time = timestamp2 - Long.parseLong(timestamp1); + if(time > 600000L){ + throw new BusinessException("签名失败:请求超时"); + } + + Enumeration names = request.getParameterNames(); + //2.遍历正文名称的枚举获得请求参数 + Map params = new HashMap<>(); + while(names.hasMoreElements()){ + String name = names.nextElement(); + String value = request.getParameter(name); + params.put(name,value); + } + String signString = SignCheckUtil.getSignString(params, getAppSecret()); + System.out.println("请求的参数 = " + params); + System.out.println("正确的签名 = " + signString); + System.out.println("签名是否正确 = " + SignCheckUtil.signCheck(params, getAppSecret())); + + if (!SignCheckUtil.signCheck(params, getAppSecret())) { + throw new BusinessException("签名失败"); + } + } + + // 模拟提交参数 + // String key = "FRbMx1FkG4Qz6GZxY"; + // Map param0 = new HashMap<>(); + // param0.put("orderId", "D2018062976332656413"); + // param0.put("MainAccountID", "DC3NHPJ73S"); + // param0.put("MainAccountSN", "320"); + // param0.put("payStatus", "2"); + // param0.put("title","测试"); + // System.out.println("请求的参数 = " + param0); + // String signString0 = SignCheckUtil.getSignString(param0, key); + // System.out.println("signString0 = " + signString0); + + // return SignCheckUtil.signCheck(params, getAppSecret()); + } + + /** + * 获取当前请求租户的AppSecret + * + * @return AppSecret + */ + public String getAppSecret() { + String key = "cache5:AppSecret:" + Integer.valueOf(getAppId()); + return redisUtil.get(key); + } + + /** + * 根据账号|手机号码|邮箱查找用户ID + * @return userId + */ +// public Integer getUserIdByUsername(String username, Integer tenantId){ +// // 按账号搜素 +// User user = userService.getOne(new LambdaQueryWrapper().eq(User::getUsername, username).eq(User::getTenantId,tenantId)); +// if (user != null && user.getUserId() > 0) { +// return user.getUserId(); +// } +// // 按手机号码搜索 +// User userByPhone = userService.getOne(new LambdaQueryWrapper().eq(User::getPhone, username).eq(User::getTenantId, tenantId)); +// if (userByPhone != null && userByPhone.getUserId() > 0) { +// return userByPhone.getUserId(); +// } +// // 按邮箱搜索 +// User userByEmail = userService.getOne(new LambdaQueryWrapper().eq(User::getEmail, username).eq(User::getTenantId, tenantId)); +// if (userByEmail != null && userByEmail.getUserId() > 0) { +// return userByEmail.getUserId(); +// } +// throw new BusinessException("找不到该用户"); +// } + + /** + * 处理方法参数类型转换异常 + * 主要处理URL路径参数中传入"NaN"等无法转换为Integer的情况 + * + * @param ex 方法参数类型不匹配异常 + * @return ApiResult + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public ApiResult handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex) { + String parameterName = ex.getName(); + Object value = ex.getValue(); + Class requiredType = ex.getRequiredType(); + + // 记录错误日志 + System.err.println("参数类型转换异常: 参数名=" + parameterName + + ", 传入值=" + value + + ", 期望类型=" + (requiredType != null ? requiredType.getSimpleName() : "unknown")); + + // 如果是ID参数且传入的是"NaN",返回友好的错误信息 + if ("id".equals(parameterName) && "NaN".equals(String.valueOf(value))) { + return fail("无效的ID参数,请检查传入的ID值"); + } + + // 其他类型转换错误的通用处理 + return fail("参数格式错误: " + parameterName + " 的值 '" + value + "' 无法转换为 " + + (requiredType != null ? requiredType.getSimpleName() : "目标类型")); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BaseParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BaseParam.java new file mode 100644 index 0000000..9661fd8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BaseParam.java @@ -0,0 +1,98 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.utils.CommonUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 查询参数基本字段 + * + * @author WebSoft + * @since 2021-08-26 22:14:43 + */ +@Data +public class BaseParam implements Serializable { + private static final long serialVersionUID = 1L; + + @TableField(exist = false) + @Schema(description = "分页查询页码") + private Long page; + + @TableField(exist = false) + @Schema(description = "分页查询每页数量") + private Long limit; + + @TableField(exist = false) + @Schema(description = "国际化") + private String lang; + + @TableField(exist = false) + @Schema(description = "排序字段", example = "id asc, name desc") + private String sort; + + @TableField(exist = false) + @Schema(description = "排序方式", example = "asc或desc") + private String order; + + @QueryField(value = "create_time", type = QueryType.GE) + @TableField(exist = false) + @Schema(description = "创建时间起始值") + private String createTimeStart; + + @QueryField(value = "create_time", type = QueryType.LE) + @TableField(exist = false) + @Schema(description = "创建时间结束值") + private String createTimeEnd; + + @QueryField(value = "create_time", type = QueryType.GE) + @Schema(description = "搜索场景") + @TableField(exist = false) + private String sceneType; + + @Schema(description = "模糊搜素") + @TableField(exist = false) + private String keywords; + + @Schema(description = "token") + @TableField(exist = false) + private String token; + + @Schema(description = "租户ID") + @TableField(exist = false) + private Integer tenantId; + + @Schema(description = "商户ID") + @TableField(exist = false) + private Long merchantId; + + /** + * 获取集合中的第一条数据 + * + * @param records 集合 + * @return 第一条数据 + */ + public T getOne(List records) { + return CommonUtil.listGetOne(records); + } + + /** + * 国际化参数 + */ + public String getLang(){ + if(StrUtil.isBlank(this.lang)){ + return null; + } + if(this.lang.equals("zh")){ + return "zh_CN"; + } + return this.lang; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BatchParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BatchParam.java new file mode 100644 index 0000000..cc69572 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/BatchParam.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.common.core.web; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.service.IService; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 批量修改通用参数 + * + * @author WebSoft + * @since 2020-03-13 00:11:06 + */ +@Data +public class BatchParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "需要修改的数据id集合") + private List ids; + + @Schema(description = "需要修改的字段和值") + private T data; + + /** + * 通用批量修改方法 + * + * @param service IService + * @param idField id字段名称 + * @return boolean + */ + public boolean update(IService service, String idField) { + if (this.data == null) { + return false; + } + return service.update(this.data, new UpdateWrapper().in(idField, this.ids)); + } + + /** + * 通用批量修改方法 + * + * @param service IService + * @param idField id字段名称 + * @return boolean + */ + public boolean update(IService service, SFunction idField) { + if (this.data == null) { + return false; + } + return service.update(this.data, new LambdaUpdateWrapper().in(idField, this.ids)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/ExistenceParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/ExistenceParam.java new file mode 100644 index 0000000..8c51268 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/ExistenceParam.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.service.IService; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 检查是否存在通用参数 + * + * @author WebSoft + * @since 2021-09-07 22:24:39 + */ +@Data +public class ExistenceParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "检查的字段") + private String field; + + @Schema(description = "字段的值") + private String value; + + @Schema(description = "修改时的主键") + private Integer id; + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @return boolean + */ + public boolean isExistence(IService service, String idField) { + return isExistence(service, idField, true); + } + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @param isToUnderlineCase 是否需要把field转为下划线格式 + * @return boolean + */ + public boolean isExistence(IService service, String idField, boolean isToUnderlineCase) { + if (StrUtil.hasBlank(this.field, this.value)) { + return false; + } + String fieldName = isToUnderlineCase ? StrUtil.toUnderlineCase(field) : field; + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq(fieldName, value); + if (id != null) { + wrapper.ne(idField, id); + } + return service.count(wrapper) > 0; + } + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @return boolean + */ + public boolean isExistence(IService service, SFunction idField) { + return isExistence(service, idField, true); + } + + /** + * 检查是否存在 + * + * @param service IService + * @param idField 修改时的主键字段 + * @param isToUnderlineCase 是否需要把field转为下划线格式 + * @return boolean + */ + public boolean isExistence(IService service, SFunction idField, boolean isToUnderlineCase) { + if (StrUtil.hasBlank(this.field, this.value)) { + return false; + } + String fieldName = isToUnderlineCase ? StrUtil.toUnderlineCase(field) : field; + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.apply(fieldName + " = {0}", value); + if (id != null) { + wrapper.ne(idField, id); + } + return service.count(wrapper) > 0; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/PageParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/PageParam.java new file mode 100644 index 0000000..596ea58 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/PageParam.java @@ -0,0 +1,343 @@ +package com.gxwebsoft.common.core.web; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.utils.CommonUtil; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 分页、排序、搜索参数封装 + * + * @author WebSoft + * @since 2019-04-26 10:34:35 + */ +public class PageParam extends Page { + private static final long serialVersionUID = 1L; + + /** + * 租户id字段名称 + */ + private static final String TENANT_ID_FIELD = "tenantId"; + + /** + * 查询条件 + */ + private final U where; + + /** + * 是否把字段名称驼峰转下划线 + */ + private final boolean isToUnderlineCase; + + public PageParam() { + this(null); + } + + public PageParam(U where) { + this(where, true); + } + + public PageParam(U where, boolean isToUnderlineCase) { + super(); + this.where = where; + this.isToUnderlineCase = isToUnderlineCase; + if (where != null) { + // 获取分页页码 + if (where.getPage() != null) { + setCurrent(where.getPage()); + } + // 获取分页每页数量 + if (where.getLimit() != null) { + setSize(where.getLimit()); + } + // 获取排序方式 + if (where.getSort() != null) { + if (sortIsSQL(where.getSort())) { + setOrders(parseOrderSQL(where.getSort())); + } else { + List orderItems = new ArrayList<>(); + String column = this.isToUnderlineCase ? StrUtil.toUnderlineCase(where.getSort()) : where.getSort(); + boolean asc = !Constants.ORDER_DESC_VALUE.equals(where.getOrder()); + orderItems.add(new OrderItem(column, asc)); + setOrders(orderItems); + } + } + } + } + + /** + * 排序字段是否是sql + */ + private boolean sortIsSQL(String sort) { + return sort != null && (sort.contains(",") || sort.trim().contains(" ")); + } + + /** + * 解析排序sql + */ + private List parseOrderSQL(String orderSQL) { + List orders = new ArrayList<>(); + if (StrUtil.isNotBlank(orderSQL)) { + for (String item : orderSQL.split(",")) { + String[] temp = item.trim().split(" "); + if (!temp[0].isEmpty()) { + String column = this.isToUnderlineCase ? StrUtil.toUnderlineCase(temp[0]) : temp[0]; + boolean asc = temp.length == 1 || !temp[temp.length - 1].equals(Constants.ORDER_DESC_VALUE); + orders.add(new OrderItem(column, asc)); + } + } + } + return orders; + } + + /** + * 设置默认排序方式 + * + * @param orderItems 排序方式 + * @return PageParam + */ + public PageParam setDefaultOrder(List orderItems) { + if (orders() == null || orders().size() == 0) { + setOrders(orderItems); + } + return this; + } + + /** + * 设置默认排序方式 + * + * @param orderSQL 排序方式 + * @return PageParam + */ + public PageParam setDefaultOrder(String orderSQL) { + setDefaultOrder(parseOrderSQL(orderSQL)); + return this; + } + + /** + * 获取查询条件 + * + * @param excludes 不包含的字段 + * @return QueryWrapper + */ + public QueryWrapper getWrapper(String... excludes) { + return buildWrapper(null, Arrays.asList(excludes)); + } + + /** + * 获取查询条件 + * + * @param columns 只包含的字段 + * @return QueryWrapper + */ + public QueryWrapper getWrapperWith(String... columns) { + return buildWrapper(Arrays.asList(columns), null); + } + + /** + * 构建QueryWrapper + * + * @param columns 包含的字段 + * @param excludes 排除的字段 + * @return QueryWrapper + */ + private QueryWrapper buildWrapper(List columns, List excludes) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + Map map = BeanUtil.beanToMap(where, false, true); + for (String fieldName : map.keySet()) { + Object fieldValue = map.get(fieldName); + Field field = ReflectUtil.getField(where.getClass(), fieldName); + + // 过滤不包含的字段 + if (columns != null && !columns.contains(fieldName)) { + continue; + } + + // 过滤排除的字段 + if (excludes != null && excludes.contains(fieldName)) { + continue; + } + + // 过滤逻辑删除字段 + if (field.getAnnotation(TableLogic.class) != null) { + continue; + } + + // 过滤租户id字段 + if (fieldName.equals(TENANT_ID_FIELD)) { + continue; + } + + // 获取注解指定的查询字段及查询方式 + QueryType queryType = QueryType.LIKE; + QueryField queryField = field.getAnnotation(QueryField.class); + if (queryField != null) { + if (StrUtil.isNotEmpty(queryField.value())) { + fieldName = queryField.value(); + } + if (queryField.type() != null) { + queryType = queryField.type(); + } + } else { + // 过滤非本表的字段 + TableField tableField = field.getAnnotation(TableField.class); + if (tableField != null && !tableField.exist()) { + continue; + } + } + + // 字段名驼峰转下划线 + if (this.isToUnderlineCase) { + fieldName = StrUtil.toUnderlineCase(fieldName); + } + + // + switch (queryType) { + case EQ: + queryWrapper.eq(fieldName, fieldValue); + break; + case NE: + queryWrapper.ne(fieldName, fieldValue); + break; + case GT: + queryWrapper.gt(fieldName, fieldValue); + break; + case GE: + queryWrapper.ge(fieldName, fieldValue); + break; + case LT: + queryWrapper.lt(fieldName, fieldValue); + break; + case LE: + queryWrapper.le(fieldName, fieldValue); + break; + case LIKE: + queryWrapper.like(fieldName, fieldValue); + break; + case NOT_LIKE: + queryWrapper.notLike(fieldName, fieldValue); + break; + case LIKE_LEFT: + queryWrapper.likeLeft(fieldName, fieldValue); + break; + case LIKE_RIGHT: + queryWrapper.likeRight(fieldName, fieldValue); + break; + case IS_NULL: + queryWrapper.isNull(fieldName); + break; + case IS_NOT_NULL: + queryWrapper.isNotNull(fieldName); + break; + case IN: + queryWrapper.in(fieldName, fieldValue); + break; + case NOT_IN: + queryWrapper.notIn(fieldName, fieldValue); + break; + case IN_STR: + if (fieldValue instanceof String) { + queryWrapper.in(fieldName, Arrays.asList(((String) fieldValue).split(","))); + } + break; + case NOT_IN_STR: + if (fieldValue instanceof String) { + queryWrapper.notIn(fieldName, Arrays.asList(((String) fieldValue).split(","))); + } + break; + } + } + return queryWrapper; + } + + /** + * 获取包含排序的查询条件 + * + * @return 包含排序的QueryWrapper + */ + public QueryWrapper getOrderWrapper() { + return getOrderWrapper(getWrapper()); + } + + /** + * 获取包含排序的查询条件 + * + * @param queryWrapper 不含排序的QueryWrapper + * @return 包含排序的QueryWrapper + */ + public QueryWrapper getOrderWrapper(QueryWrapper queryWrapper) { + if (queryWrapper == null) { + queryWrapper = new QueryWrapper<>(); + } + for (OrderItem orderItem : orders()) { + if (orderItem.isAsc()) { + queryWrapper.orderByAsc(orderItem.getColumn()); + } else { + queryWrapper.orderByDesc(orderItem.getColumn()); + } + } + return queryWrapper; + } + + /** + * 获取集合中的第一条数据 + * + * @param records 集合 + * @return 第一条数据 + */ + public T getOne(List records) { + return CommonUtil.listGetOne(records); + } + + /** + * 代码排序集合 + * + * @param records 集合 + * @return 排序后的集合 + */ + public List sortRecords(List records) { + List orderItems = orders(); + if (records == null || records.size() < 2 || orderItems == null || orderItems.size() == 0) { + return records; + } + Comparator comparator = null; + for (OrderItem item : orderItems) { + if (item.getColumn() == null) { + continue; + } + String field = this.isToUnderlineCase ? StrUtil.toCamelCase(item.getColumn()) : item.getColumn(); + Function keyExtractor = t -> ReflectUtil.getFieldValue(t, field); + if (comparator == null) { + if (item.isAsc()) { + comparator = Comparator.comparing(keyExtractor); + } else { + comparator = Comparator.comparing(keyExtractor, Comparator.reverseOrder()); + } + } else { + if (item.isAsc()) { + comparator.thenComparing(keyExtractor); + } else { + comparator.thenComparing(keyExtractor, Comparator.reverseOrder()); + } + } + } + if (comparator != null) { + return records.stream().sorted(comparator).collect(Collectors.toList()); + } + return records; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/PageResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/PageResult.java new file mode 100644 index 0000000..a9bc057 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/web/PageResult.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.core.web; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页查询返回结果 + * + * @author WebSoft + * @since 2017-06-10 10:10:02 + */ +public class PageResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "当前页数据") + private List list; + + @Schema(description = "总数量") + private Long count; + + public PageResult() { + } + + public PageResult(List list) { + this(list, null); + } + + public PageResult(List list, Long count) { + setList(list); + setCount(count); + } + + public List getList() { + return this.list; + } + + public void setList(List list) { + this.list = list; + } + + public Long getCount() { + return this.count; + } + + public void setCount(Long count) { + this.count = count; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/websocket/WebSocketConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/websocket/WebSocketConfig.java new file mode 100644 index 0000000..ba511dd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/websocket/WebSocketConfig.java @@ -0,0 +1,19 @@ +package com.gxwebsoft.common.core.websocket; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + + +@Configuration +public class WebSocketConfig { + @Bean + public ServerEndpointExporter serverEndpointExporter() { + ServerEndpointExporter exporter = new ServerEndpointExporter(); + + // 手动注册 WebSocket 端点 + exporter.setAnnotatedEndpointClasses(WebSocketServer.class); + + return exporter; + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/core/websocket/WebSocketServer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/core/websocket/WebSocketServer.java new file mode 100644 index 0000000..c3b64fd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/core/websocket/WebSocketServer.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.common.core.websocket; + +import org.springframework.stereotype.Component; + +import javax.websocket.OnClose; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; + + +@ServerEndpoint(value = "/api/chat/{userId}") +@Component +public class WebSocketServer { + + /** + * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 + */ + private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>(); + /** + * 与某个客户端的连接会话,需要通过它来给客户端发送数据 + */ + private Session session; + /** + * 接收userId + */ + private String userId = ""; + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("userId") String userId) { + this.session = session; + this.userId = userId; + if (webSocketMap.containsKey(userId)) { + webSocketMap.remove(userId); + webSocketMap.put(userId, this); + //加入set中 + } else { + webSocketMap.put(userId, this); + } + + try { + sendMessage(userId, "连接成功"); + } catch (IOException e) { + + } + } + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose() { + if (webSocketMap.containsKey(userId)) { + webSocketMap.remove(userId); + } + } + + + /** + * 实现服务器主动推送 + */ + public void sendMessage(String userId, String message) throws IOException { + if (webSocketMap.containsKey(userId)) { + Session session1 = webSocketMap.get(userId).session; + if (session1 != null) session1.getBasicRemote().sendText(message); + } + } + + + /** + * 实现服务器主动推送 + */ + public void sendAllMessage(String message) throws IOException { + ConcurrentHashMap.KeySetView userIds = webSocketMap.keySet(); + for (String userId : userIds) { + WebSocketServer webSocketServer = webSocketMap.get(userId); + webSocketServer.session.getBasicRemote().sendText(message); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/mq/config/RabbitMQConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/common/mq/config/RabbitMQConfig.java new file mode 100644 index 0000000..9f681f5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/mq/config/RabbitMQConfig.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.common.mq.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +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; + +/** + * RabbitMQ 配置类 - websopy 端消费者配置 + * + * 从 server-api (core系统) 接收用户同步消息 + * 使用 Topic Exchange,routing key 格式: user.sync.websopy + */ +@Configuration +@ConditionalOnProperty(name = "sync.mq.enabled", havingValue = "true", matchIfMissing = true) +public class RabbitMQConfig { + + // ==================== 常量定义 ==================== + // 与 server-api 共用的 Exchange + public static final String SYNC_EXCHANGE = "sync.topic.exchange"; + + // websopy 专用队列 + public static final String SYNC_QUEUE_WEBSOPY = "user.sync.websopy.queue"; + public static final String SYNC_ROUTING_KEY_WEBSOPY = "user.sync.websopy"; + + // 死信队列 + public static final String DLX_EXCHANGE = "sync.dlx.exchange"; + public static final String DLQ_QUEUE_WEBSOPY = "user.sync.websopy.dlq"; + public static final String DLQ_ROUTING_KEY = "user.sync.websopy.dlq"; + + @Value("${spring.rabbitmq.host:localhost}") + private String host; + + @Value("${spring.rabbitmq.port:5672}") + private int port; + + @Value("${spring.rabbitmq.username:guest}") + private String username; + + @Value("${spring.rabbitmq.password:guest}") + private String password; + + @Value("${spring.rabbitmq.virtual-host:/}") + private String virtualHost; + + // ==================== Connection Factory ==================== + + @Bean + public ConnectionFactory connectionFactory() { + CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); + connectionFactory.setHost(host); + connectionFactory.setPort(port); + connectionFactory.setUsername(username); + connectionFactory.setPassword(password); + connectionFactory.setVirtualHost(virtualHost); + return connectionFactory; + } + + // ==================== Message Converter ==================== + + /** + * 注意:必须使用 Spring Boot 自动注入的 ObjectMapper + * Spring Boot 已全局配置 Jackson2ObjectMapperBuilderCustomizer, + * 包括 JavaTimeModule 支持纳秒精度 LocalDateTime 序列化/反序列化 + */ + @Bean + public MessageConverter messageConverter(ObjectMapper objectMapper) { + return new Jackson2JsonMessageConverter(objectMapper); + } + + // ==================== RabbitTemplate ==================== + + @Bean + public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) { + RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(messageConverter); + return rabbitTemplate; + } + + @Bean + public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory( + ConnectionFactory connectionFactory, MessageConverter messageConverter) { + SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory); + factory.setMessageConverter(messageConverter); + // 设置并发数 + factory.setConcurrentConsumers(1); + factory.setMaxConcurrentConsumers(5); + // 设置手动ack + factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); + // 预取数量 + factory.setPrefetchCount(10); + return factory; + } + + // ==================== 交换机 ==================== + + /** + * Topic Exchange - 与 server-api 共用的交换机 + * server-api 发送消息时使用 routing key: user.sync.websopy + */ + @Bean + public TopicExchange syncExchange() { + return new TopicExchange(SYNC_EXCHANGE, true, false); + } + + @Bean + public DirectExchange deadLetterExchange() { + return new DirectExchange(DLX_EXCHANGE, true, false); + } + + // ==================== 队列 ==================== + + /** + * websopy 专用同步队列 + * 绑定到 sync.exchange,接收 routing key 为 user.sync.websopy 的消息 + */ + @Bean + public Queue syncQueueWebsopy() { + return QueueBuilder.durable(SYNC_QUEUE_WEBSOPY) + .withArgument("x-dead-letter-exchange", DLX_EXCHANGE) + .withArgument("x-dead-letter-routing-key", DLQ_ROUTING_KEY) + .build(); + } + + @Bean + public Queue deadLetterQueue() { + return QueueBuilder.durable(DLQ_QUEUE_WEBSOPY).build(); + } + + // ==================== 绑定 ==================== + + /** + * 绑定 websopy 队列到 Topic Exchange + * routing key: user.sync.websopy + */ + @Bean + public Binding syncBindingWebsopy() { + return BindingBuilder.bind(syncQueueWebsopy()) + .to(syncExchange()) + .with(SYNC_ROUTING_KEY_WEBSOPY); + } + + @Bean + public Binding dlqBinding() { + return BindingBuilder.bind(deadLetterQueue()) + .to(deadLetterExchange()) + .with(DLQ_ROUTING_KEY); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/mq/consumer/SyncMessageConsumer.java b/jczxw-java/src/main/java/com/gxwebsoft/common/mq/consumer/SyncMessageConsumer.java new file mode 100644 index 0000000..a8c7a1d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/mq/consumer/SyncMessageConsumer.java @@ -0,0 +1,255 @@ +package com.gxwebsoft.common.mq.consumer; + +import com.gxwebsoft.app.entity.AppUserCache; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.common.mq.config.RabbitMQConfig; +import com.gxwebsoft.common.mq.message.SyncMessage; +import com.rabbitmq.client.Channel; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 同步消息消费者 - websopy 端监听来自 server-api 的消息 + * + * 监听队列: user.sync.websopy.queue + * 接收来自 server-api 的用户同步消息(CREATE/UPDATE/DELETE) + */ +@Slf4j +@Component +@ConditionalOnProperty(name = "sync.mq.enabled", havingValue = "true", matchIfMissing = true) +public class SyncMessageConsumer { + + @Autowired + private AppUserCacheService appUserCacheService; + + /** 本租户ID,用于验证消息是否属于本租户 */ + @Value("${sync.tenant-id:0}") + private Integer localTenantId; + + private static final int MAX_RETRY_COUNT = 3; + + /** + * 监听 websopy 专用同步队列 + * 接收 server-api 发送的用户同步消息 + */ + @RabbitListener(queues = RabbitMQConfig.SYNC_QUEUE_WEBSOPY) + public void handleMessage(SyncMessage message, Channel channel, Message amqpMessage) { + long deliveryTag = amqpMessage.getMessageProperties().getDeliveryTag(); + + try { + log.info("websopy 收到MQ消息: messageId={}, type={}, event={}, target={}", + message.getMessageId(), message.getMessageType(), + message.getEventType(), message.getTargetSystem()); + + // 处理消息 + processMessage(message); + + // 确认消息 + channel.basicAck(deliveryTag, false); + log.info("websopy 消息处理成功: messageId={}", message.getMessageId()); + + } catch (Exception e) { + log.error("websopy 消息处理失败: messageId={}, error={}", message.getMessageId(), e.getMessage(), e); + handleFailure(channel, amqpMessage, deliveryTag, message, e); + } + } + + /** + * 处理消息 + */ + private void processMessage(SyncMessage message) { + String messageType = message.getMessageType(); + String eventType = message.getEventType(); + Map data = message.getData(); + + if ("USER_SYNC".equals(messageType)) { + handleUserSync(eventType, data); + } else { + log.warn("未知的消息类型: messageType={}", messageType); + } + } + + /** + * 处理用户同步 + */ + private void handleUserSync(String eventType, Map data) { + if (data == null || data.isEmpty()) { + log.warn("用户数据为空,跳过处理"); + return; + } + + Integer userId = getIntValue(data, "userId"); + Integer tenantId = getIntValue(data, "tenantId"); + + if (userId == null) { + log.warn("用户数据中缺少userId,跳过处理"); + return; + } + + if (tenantId == null) { + log.warn("用户数据中缺少tenantId,跳过处理: userId={}", userId); + return; + } + + // 【关键】租户隔离验证:只处理本租户的数据 + if (localTenantId != null && localTenantId > 0 && !localTenantId.equals(tenantId)) { + log.info("租户ID不匹配,跳过处理: userId={}, messageTenantId={}, localTenantId={}", + userId, tenantId, localTenantId); + return; + } + + // 获取当前数据库中的用户缓存(用于对比) + AppUserCache existingCache = appUserCacheService.getById(userId); + + switch (eventType) { + case "CREATE": + case "UPDATE": + AppUserCache userCache = buildUserCache(data); + + // 【增强】详细日志:打印变更前后的对比 + if (existingCache != null) { + log.info("【UPDATE】用户信息变更检测: userId={}, tenantId={}, event={}, " + + "username: '{}' -> '{}', " + + "nickname: '{}' -> '{}', " + + "phone: '{}' -> '{}', " + + "avatar: '{}' -> '{}'", + userId, tenantId, eventType, + existingCache.getUsername(), userCache.getUsername(), + existingCache.getNickname(), userCache.getNickname(), + existingCache.getPhone(), userCache.getPhone(), + existingCache.getAvatar(), userCache.getAvatar()); + + // 执行更新 + boolean updated = appUserCacheService.updateById(userCache); + log.info("用户更新{}: userId={}, result={}", eventType, userId, updated); + } else { + log.info("【CREATE】新增用户缓存: userId={}, tenantId={}, username={}", + userId, tenantId, userCache.getUsername()); + + // 解决 MyBatis-Plus saveOrUpdate 对 IdType.INPUT 主键的兼容问题 + // 先查询再决定 insert/update,捕获并发冲突异常后回退到 update + try { + appUserCacheService.save(userCache); + log.info("用户创建成功: userId={}", userId); + } catch (org.springframework.dao.DuplicateKeyException e) { + // 并发场景:其他线程已插入,改为更新 + log.warn("并发插入冲突,改为更新: userId={}", userId); + appUserCacheService.updateById(userCache); + } + } + break; + case "DELETE": + if (existingCache != null) { + appUserCacheService.removeById(userId); + log.info("websopy 用户删除成功: userId={}, tenantId={}", userId, tenantId); + } else { + log.info("用户不存在,无需删除: userId={}", userId); + } + break; + default: + log.warn("未知的用户事件类型: eventType={}", eventType); + } + } + + /** + * 构建用户缓存对象 + */ + private AppUserCache buildUserCache(Map data) { + AppUserCache userCache = new AppUserCache(); + userCache.setUserId(getIntValue(data, "userId")); + userCache.setUsername(getStringValue(data, "username")); + userCache.setNickname(getStringValue(data, "nickname")); + userCache.setAvatar(getStringValue(data, "avatar")); + userCache.setPhone(getStringValue(data, "phone")); + userCache.setStatus(getIntValue(data, "status", 1)); + userCache.setTenantId(getIntValue(data, "tenantId")); + userCache.setUpdateTime(LocalDateTime.now()); + return userCache; + } + + /** + * 处理失败消息 + */ + private void handleFailure(Channel channel, Message amqpMessage, long deliveryTag, + SyncMessage message, Exception e) { + Integer retryCount = message.getRetryCount(); + if (retryCount == null) { + retryCount = 0; + } + + if (retryCount < MAX_RETRY_COUNT) { + try { + log.warn("websopy 消息处理失败,准备重试: messageId={}, retryCount={}/{}", + message.getMessageId(), retryCount + 1, MAX_RETRY_COUNT); + channel.basicNack(deliveryTag, false, true); + } catch (IOException ioException) { + log.error("消息拒绝失败: messageId={}", message.getMessageId(), ioException); + } + } else { + try { + log.error("websopy 消息处理失败次数超限,发送到死信队列: messageId={}, retryCount={}", + message.getMessageId(), retryCount); + channel.basicNack(deliveryTag, false, false); + } catch (IOException ioException) { + log.error("消息拒绝失败: messageId={}", message.getMessageId(), ioException); + } + } + } + + /** + * 监听 websopy 死信队列消息 + */ + @RabbitListener(queues = RabbitMQConfig.DLQ_QUEUE_WEBSOPY) + public void handleDeadLetter(SyncMessage message, Channel channel, Message amqpMessage) { + long deliveryTag = amqpMessage.getMessageProperties().getDeliveryTag(); + try { + log.error("websopy 死信消息: messageId={}, type={}, event={}, retryCount={}", + message.getMessageId(), message.getMessageType(), + message.getEventType(), message.getRetryCount()); + channel.basicAck(deliveryTag, false); + } catch (Exception e) { + log.error("处理死信消息失败: messageId={}", message.getMessageId(), e); + try { + channel.basicAck(deliveryTag, false); + } catch (IOException ioException) { + log.error("确认死信消息失败", ioException); + } + } + } + + private String getStringValue(Map data, String key) { + Object value = data.get(key); + return value != null ? String.valueOf(value) : ""; + } + + private Integer getIntValue(Map data, String key) { + return getIntValue(data, key, null); + } + + private Integer getIntValue(Map data, String key, Integer defaultValue) { + Object value = data.get(key); + if (value == null) { + return defaultValue; + } + if (value instanceof Integer) { + return (Integer) value; + } + if (value instanceof Number) { + return ((Number) value).intValue(); + } + try { + return Integer.parseInt(String.valueOf(value)); + } catch (NumberFormatException e) { + return defaultValue; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/mq/message/SyncMessage.java b/jczxw-java/src/main/java/com/gxwebsoft/common/mq/message/SyncMessage.java new file mode 100644 index 0000000..1a6e537 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/mq/message/SyncMessage.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.mq.message; + +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 同步消息实体 - 接收来自 server-api 的消息 + */ +@Data +public class SyncMessage implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 消息唯一ID + */ + private String messageId; + + /** + * 消息类型:USER_SYNC, TENANT_SYNC, etc. + */ + private String messageType; + + /** + * 事件类型:CREATE, UPDATE, DELETE + */ + private String eventType; + + /** + * 目标系统标识 + */ + private String targetSystem; + + /** + * 业务数据 + */ + private Map data; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 重试次数 + */ + private Integer retryCount; + + public SyncMessage() { + this.createTime = LocalDateTime.now(); + this.retryCount = 0; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AccessKeyController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AccessKeyController.java new file mode 100644 index 0000000..59339f1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AccessKeyController.java @@ -0,0 +1,177 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CacheClient; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.AccessKey; +import com.gxwebsoft.common.system.param.AccessKeyParam; +import com.gxwebsoft.common.system.service.AccessKeyService; +import io.swagger.v3.oas.annotations.tags.Tag; + +import java.util.concurrent.TimeUnit; + +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Random; + +import static com.gxwebsoft.common.core.constants.WebsiteConstants.CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS; + +/** + * 访问凭证管理控制器 + * + * @author 科技小王子 + * @since 2023-05-16 19:19:55 + */ +@Tag(name = "安全访问凭证") +@RestController +@RequestMapping("/api/system/access-key") +public class AccessKeyController extends BaseController { + @Resource + private AccessKeyService accessKeyService; + @Resource + private CacheClient cacheClient; + @Resource + private RedisUtil redisUtil; + + @PreAuthorize("hasAuthority('sys:accessKey:list')") + @OperationLog + @Operation(summary = "分页查询访问凭证") + @GetMapping("/page") + public ApiResult> page(AccessKeyParam param) { + // 使用关联查询 + final PageResult accessKeyPageResult = accessKeyService.pageRel(param); + if (param.getCode() != null) { + // 短信验证码校验 + final String code = param.getCode(); + // 验证码校验 + String key = "code:" + param.getPhone(); + if (!code.equals(redisUtil.get(key)) && !redisUtil.get(CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS).equals(code)) { + String message = "验证码不正确"; + return fail(message, null); + } + return success(accessKeyPageResult); + } + // 默认不给查看AccessSecret + accessKeyPageResult.getList().forEach(d -> { + d.setAccessSecret(null); + }); + return success(accessKeyPageResult); + } + + @PreAuthorize("hasAuthority('sys:accessKey:list')") + @OperationLog + @Operation(summary = "查询全部访问凭证管理") + @GetMapping() + public ApiResult> list(AccessKeyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(accessKeyService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(accessKeyService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:accessKey:list')") + @OperationLog + @Operation(summary = "根据id查询访问凭证管理") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(accessKeyService.getById(id)); + // 使用关联查询 + //return success(accessKeyService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:accessKey:list')") + @OperationLog + @Operation(summary = "添加访问凭证管理") + @PostMapping() + public ApiResult save(@RequestBody AccessKey accessKey) { + final int count = accessKeyService.count(); + if (count >= 5) { + return fail("当前账号只能绑定 5 个 AccessKey"); + } + if(accessKey.getAccessKey() == null){ + accessKey.setAccessKey(CommonUtil.randomUUID16()); + } + accessKey.setAccessSecret("sk-" + CommonUtil.randomUUID16().concat(CommonUtil.randomUUID16())); + if (accessKeyService.save(accessKey)) { + return success("创建成功", accessKey); + } + return fail("创建失败"); + } + + @PreAuthorize("hasAuthority('sys:accessKey:update')") + @OperationLog + @Operation(summary = "修改访问凭证管理") + @PutMapping() + public ApiResult update(@RequestBody AccessKey accessKey) { + if (accessKeyService.updateById(accessKey)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:accessKey:remove')") + @OperationLog + @Operation(summary = "删除访问凭证管理") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (accessKeyService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:accessKey:save')") + @OperationLog + @Operation(summary = "批量添加访问凭证管理") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (accessKeyService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:accessKey:update')") + @OperationLog + @Operation(summary = "批量修改访问凭证管理") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(accessKeyService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:accessKey:remove')") + @OperationLog + @Operation(summary = "批量删除访问凭证管理") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (accessKeyService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:accessKey:resetSMSCode')") + @OperationLog + @Operation(summary = "重置万能短信验证码") + @PostMapping("/resetSMSCode") + public ApiResult resetSMSCode() { + // 生成短信验证码 + Random randObj = new Random(); + String code = Integer.toString(100000 + randObj.nextInt(900000)); + redisUtil.set(CACHE_KEY_VERIFICATION_CODE_BY_DEV_SMS, code, 5L, TimeUnit.MINUTES); + return success("新验证码:".concat(code)); + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AiController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AiController.java new file mode 100644 index 0000000..8525a3b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AiController.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.websocket.WebSocketServer; +import com.gxwebsoft.common.system.entity.ChatMessage; +import io.swagger.v3.oas.annotations.tags.Tag; +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 javax.annotation.Resource; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +@Tag(name = "AI") +@RestController +@RequestMapping("/api/chat") +public class AiController extends BaseController { + @Resource + private WebSocketServer webSocketServer; + + @PostMapping("/message") + public ApiResult message(@RequestBody ChatMessage message) throws IOException { + Map paramsJsonStr = new HashMap<>(); + paramsJsonStr.put("query", message.getQuery()); + paramsJsonStr.put("opsType", "0"); + + Map formData = new HashMap<>(); + formData.put("user", message.getUser()); + formData.put("responseMode", "streaming"); + formData.put("paramsJsonStr", JSONUtil.toJSONString(paramsJsonStr)); + formData.put("authCode", "a8cc4a0a-aea3-4ea5-811a-80316520a3d3"); + // 使用 Java 自带的 HttpURLConnection 发送流式请求 + try { + URL url = new URL("https://ai-console.gxshucheng.com/ai-console-api/run/v1"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + connection.setDoOutput(true); + connection.setConnectTimeout(600000); + connection.setReadTimeout(600000); + + // 写入请求体 + try (OutputStream os = connection.getOutputStream(); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) { + for (Map.Entry entry : formData.entrySet()) { + writeFormField(writer, entry.getKey(), entry.getValue()); + } + // 添加文件上传部分(可选) + // writeFilePart(writer, "file", "test.txt", "text/plain", "This is the file content."); + writer.append("--").append(boundary).append("--").append("\r\n"); + writer.flush(); + } + + StringBuilder responseStr = new StringBuilder(); + // 读取响应流 + try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + System.out.println("Received chunk: " + line); // 打印接收到的每一部分数据 + // 这里可以对每一部分数据进行处理,例如解析或发送给前端 + if (!line.isEmpty()) { + String[] dataList = line.split("data: "); + if (dataList.length == 2) { +// System.out.println(dataList[1]); + Map data = JSONUtil.parseObject(dataList[1], Map.class); + if (data.get("event") != null && data.get("event").equals("message")) { + String answer = (String) data.get("answer"); + String task_id = (String) data.get("task_id"); + if (answer != null && !answer.isEmpty()) { + HashMap answerData = new HashMap<>(); + answerData.put("answer", answer); + answerData.put("taskId", task_id); + webSocketServer.sendMessage(message.getUser(), JSONUtil.toJSONString(answerData)); + } + System.out.println("answer: " + answer); + responseStr.append(answer); + }else if (data.get("event") != null && data.get("event").equals("message_end")) { + String task_id = (String) data.get("task_id"); + HashMap answerData = new HashMap<>(); + answerData.put("answer", "__END__"); + answerData.put("taskId", task_id); + + webSocketServer.sendMessage(message.getUser(), JSONUtil.toJSONString(answerData)); + } + } + } + } + } + } catch (Exception e) { + System.out.println(e.getMessage()); + for (StackTraceElement stackTraceElement : e.getStackTrace()) { + System.out.println(stackTraceElement); + } + webSocketServer.sendMessage(message.getUser(), "出错了,请晚点再来提问吧~"); + return fail("出错了,请晚点再来提问吧~"); + } + + // 返回成功响应 + return success("Stream processing completed"); + } + + private static final String boundary = "---" + System.currentTimeMillis() + "---"; + + private static void writeFormField(PrintWriter writer, String fieldName, String value) { + writer.append("--").append(boundary).append("\r\n"); + writer.append("Content-Disposition: form-data; name=\"").append(fieldName).append("\"\r\n"); + writer.append("\r\n"); + writer.append(value).append("\r\n"); + } + + @PostMapping("/messageStop") + public ApiResult stop(@RequestBody Map data) { + if (data.get("taskId") == null) return success(); + String taskId = data.get("taskId").toString(); + Map postData = new HashMap<>(); + postData.put("user", getLoginUserId()); + String token = "Bearer app-UxV82WXIRrScpf53exkJ7dIw"; + if (data.get("type") != null) { + token = "Bearer app-7AFseF5UTEJpZGkW93S0wybh"; + } + String res = HttpRequest.post("http://workflow.gxshucheng.com:8010/v1/chat-messages/" + taskId + "/stop") + .header("Authorization", token) + .header("Content-Type", "application/json") + .body(JSONObject.toJSONString(postData)) + .execute().body(); + System.out.println("stop res:" + res); + return success(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AliOssController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AliOssController.java new file mode 100644 index 0000000..a0dcb68 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AliOssController.java @@ -0,0 +1,294 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.OSSException; +import com.aliyun.oss.common.auth.CredentialsProvider; +import com.aliyun.oss.common.auth.DefaultCredentialProvider; +import com.aliyun.oss.common.utils.BinaryUtil; +import com.aliyun.oss.model.PolicyConditions; +import com.aliyun.oss.model.PutObjectRequest; +import com.aliyun.oss.model.PutObjectResult; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.auth.sts.AssumeRoleRequest; +import com.aliyuncs.auth.sts.AssumeRoleResponse; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.utils.FileServerUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.CompanyService; +import com.gxwebsoft.common.system.service.FileRecordService; +import com.gxwebsoft.common.system.service.SettingService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 阿里云OSS云存储 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Tag(name = "阿里云OSS") +@RestController +@RequestMapping("/api/oss") +public class AliOssController extends BaseController { + @Resource + private ConfigProperties config; + @Resource + private RedisUtil redisUtil; + @Resource + private FileRecordService fileRecordService; + @Resource + private CompanyService companyService; + @Resource + private SettingService settingService; + + @Operation(summary = "上传文件") + @PostMapping("/upload") + public ApiResult upload(@RequestParam MultipartFile file, HttpServletRequest request) throws Exception{ + // 获取租户ID + String tenantId = request.getHeader("TenantId"); + String companyId = request.getHeader("CompanyId"); + String merchantId = request.getHeader("MerchantId"); + String groupId = request.getHeader("GroupId"); + String appId = request.getHeader("AppId"); + if(StrUtil.isBlank(tenantId)){ + return fail("传参错误",null); + } + + // 读取配置信息 + JSONObject settingInfo; + String key3 = "Upload:" + tenantId; + settingInfo = redisUtil.get(key3, JSONObject.class); + if (ObjectUtil.isEmpty(settingInfo)) { + settingInfo = settingService.getBySettingKey("upload"); + if (ObjectUtil.isNotEmpty(settingInfo)) { + redisUtil.set(key3,settingInfo); + }else { + return fail("请先配置云存储",null); + } + } + String endpoint = settingInfo.getString("bucketEndpoint"); + String bucketDomain = settingInfo.getString("bucketDomain"); + String bucketName = settingInfo.getString("bucketName"); + String accessKeyId = settingInfo.getString("accessKeyId"); + String accessKeySecret = settingInfo.getString("accessKeySecret"); + + // 判断是否登录 + String authorization = getAuthorization(); + + // 判断存储空间是否已满 + String key = "StorageIsFull:" + tenantId; + String storageIsFull = redisUtil.get(key); + if(StrUtil.isNotBlank(storageIsFull)){ + // 使用自定义云存储不限制 + if(bucketName.equals("oss-gxwebsoft")){ + return fail("存储空间已满", null); + } + } + + // 上传文件结果 + FileRecord result; + CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret); + // 创建OSSClient实例。 + OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider); + + try { + + String dir = getUploadDir(); + File upload = FileServerUtil.upload(file, dir, config.getUploadUuidName()); + String path = upload.getAbsolutePath().replace("\\", "/").substring(dir.length()); + String originalName = file.getOriginalFilename(); + + // 创建PutObjectRequest对象。 + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path, upload); + // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。 + // ObjectMetadata metadata = new ObjectMetadata(); + // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString()); + // metadata.setObjectAcl(CannedAccessControlList.Private); + // putObjectRequest.setMetadata(metadata); + + // 上传文件。 + PutObjectResult ossResult = ossClient.putObject(putObjectRequest); + + // 保存记录并返回 + result = new FileRecord(); + if(StrUtil.isNotBlank(authorization)){ + result.setCreateUserId(getLoginUserId()); + } + if(StrUtil.isNotBlank(companyId)){ + result.setCompanyId(Integer.valueOf(companyId)); + } + if(StrUtil.isNotBlank(merchantId)){ + result.setMerchantId(Long.valueOf(merchantId)); + } + if(StrUtil.isNotBlank(groupId)){ + result.setGroupId(Integer.valueOf(groupId)); + } + if(StrUtil.isNotBlank(appId)){ + result.setAppId(Integer.valueOf(appId)); + } + path = "/".concat(path); + result.setName(StrUtil.isBlank(originalName) ? upload.getName() : originalName); + result.setLength(upload.length()); + result.setPath(bucketDomain + path); + result.setThumbnail(bucketDomain + path + "?x-oss-process=image/resize,m_fixed,w_100,h_100/quality,Q_90"); + result.setUrl(bucketDomain + path + "?x-oss-process=image/resize,w_750/quality,Q_90"); + result.setDownloadUrl(bucketDomain + path); + String contentType = FileServerUtil.getContentType(upload); + result.setContentType(contentType); + result.setTenantId(Integer.valueOf(tenantId)); + upload.delete(); + fileRecordService.save(result); + // 更新存储空间 + if(companyId != null){ + Company company = companyService.getById(Integer.valueOf(companyId)); + company.setStorage(company.getStorage() + result.getLength()); + if(company.getStorage().compareTo(company.getStorageMax()) > 0){ + redisUtil.set(key,1); + } + companyService.updateById(company); + } + return success(result); + + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return fail("上传失败", null); + } + + @OperationLog + @Operation(summary = "获取临时osstoken") + @GetMapping("/getSTSToken") + public ApiResult getSTSToken() { + final User loginUser = getLoginUser(); + if(loginUser == null){ + return fail("请先登录"); + } + // STS接入地址,例如sts.cn-hangzhou.aliyuncs.com。 + String endpoint = "sts.cn-shenzhen.aliyuncs.com"; + // 填写步骤1生成的RAM用户访问密钥AccessKey ID和AccessKey Secret。 + String accessKeyId = "LTAI5tBVtVkfKfJ5Fm6mzQzF"; + String accessKeySecret = "fsDI64rWJj9EXpqf7bNLn5YjigMUQe"; + // 填写步骤3获取的角色ARN。 + String roleArn = "acs:ram::1470199532233684:role/wsoss"; + // 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest。 + String roleSessionName = "wsoss"; + // 设置临时访问凭证的有效时间为3600秒。 + Long durationSeconds = 3600L; + try { + // regionId表示RAM的地域ID。以华东1(杭州)地域为例,regionID填写为cn-hangzhou。也可以保留默认值,默认值为空字符串("")。 + String regionId = ""; + // 添加endpoint。适用于Java SDK 3.12.0及以上版本。 + DefaultProfile.addEndpoint(regionId, "Sts", endpoint); + // 构造default profile。 + IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret); + // 构造client。 + DefaultAcsClient client = new DefaultAcsClient(profile); + final AssumeRoleRequest request = new AssumeRoleRequest(); + // 适用于Java SDK 3.12.0及以上版本。 + request.setSysMethod(MethodType.POST); + // 适用于Java SDK 3.12.0以下版本。 + //request.setMethod(MethodType.POST); + request.setRoleArn(roleArn); + request.setRoleSessionName(roleSessionName); +// request.setPolicy(policy); + request.setDurationSeconds(durationSeconds); + final AssumeRoleResponse response = client.getAcsResponse(request); + return success(response); + } catch (ClientException | com.aliyuncs.exceptions.ClientException e) { + System.out.println("Failed:"); + System.out.println("Error message: " + e.getMessage()); + return fail(e.getMessage()); + + } + } + + /** + * 获取前端表单提交的参数 + * @return + */ + @Operation(summary = "获取前端表单提交的参数") + @GetMapping("/getPostForm") + public ApiResult getPostForm(){ + String endpoint = config.getEndpoint(); + // RAM用户的访问密钥(AccessKey ID和AccessKey Secret)。 + String accessKeyId = "LTAI5t8UTh8CTXEi2dYxobhj"; + String accessKeySecret = "fNdJOT4KAjrVrzHNAcSJuUCy9ZljD9"; + // 使用代码嵌入的RAM用户的访问密钥配置访问凭证。 + CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret); + // 填写Bucket名称,例如examplebucket。 + String bucket = config.getBucketName(); + OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider); + + try { + String host = "https://" + bucket + "." + endpoint; + String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); + + + long expireTime = 60; + long expireEndTime = System.currentTimeMillis() + expireTime * 1000; + Date expiration = new Date(expireEndTime); + PolicyConditions policyConds = new PolicyConditions(); + policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,0,100*1024*1024); + + + String postPolicy = ossClient.generatePostPolicy(expiration, policyConds); + byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8); + String encodedPolicy = BinaryUtil.toBase64String(binaryData); + String postSignature = ossClient.calculatePostSignature(postPolicy); + Map result = new HashMap<>(); + result.put("polocyBase64",encodedPolicy); + result.put("signature",postSignature); + result.put("expireEndTime",expireEndTime); + return success(result); + } finally { + ossClient.shutdown(); + } + + } + + /** + * 文件上传位置(服务器) + */ + private String getUploadDir() { + return config.getUploadPath() + "/"; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AuthorizeCodeController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AuthorizeCodeController.java new file mode 100644 index 0000000..a19f232 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/AuthorizeCodeController.java @@ -0,0 +1,132 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.AuthorizeCodeService; +import com.gxwebsoft.common.system.entity.AuthorizeCode; +import com.gxwebsoft.common.system.param.AuthorizeCodeParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 授权码控制器 + * + * @author 科技小王子 + * @since 2025-08-05 01:17:27 + */ +@Tag(name = "授权码管理") +@RestController +@RequestMapping("/api/system/authorize-code") +public class AuthorizeCodeController extends BaseController { + @Resource + private AuthorizeCodeService authorizeCodeService; + + @PreAuthorize("hasAuthority('sys:authorizeCode:list')") + @OperationLog + @Operation(summary = "分页查询授权码") + @GetMapping("/page") + public ApiResult> page(AuthorizeCodeParam param) { + // 使用关联查询 + return success(authorizeCodeService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:list')") + @OperationLog + @Operation(summary = "查询全部授权码") + @GetMapping() + public ApiResult> list(AuthorizeCodeParam param) { + // 使用关联查询 + return success(authorizeCodeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:list')") + @OperationLog + @Operation(summary = "根据id查询授权码") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(authorizeCodeService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:save')") + @OperationLog + @Operation(summary = "添加授权码") + @PostMapping() + public ApiResult save(@RequestBody AuthorizeCode authorizeCode) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + authorizeCode.setUserId(loginUser.getUserId()); + } + if (authorizeCodeService.save(authorizeCode)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:update')") + @OperationLog + @Operation(summary = "修改授权码") + @PutMapping() + public ApiResult update(@RequestBody AuthorizeCode authorizeCode) { + if (authorizeCodeService.updateById(authorizeCode)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:remove')") + @OperationLog + @Operation(summary = "删除授权码") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (authorizeCodeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:save')") + @OperationLog + @Operation(summary = "批量添加授权码") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (authorizeCodeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:update')") + @OperationLog + @Operation(summary = "批量修改授权码") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(authorizeCodeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:authorizeCode:remove')") + @OperationLog + @Operation(summary = "批量删除授权码") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (authorizeCodeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CacheController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CacheController.java new file mode 100644 index 0000000..d95357d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CacheController.java @@ -0,0 +1,117 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.utils.CacheClient; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Cache; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.SettingService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * 缓存控制器 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Tag(name = "缓存管理") +@RestController +@RequestMapping("/api/system/cache") +public class CacheController extends BaseController { + @Resource + private SettingService settingService; + @Resource + private CacheClient cacheClient; + @Resource + private RedisUtil redisUtil; + @Resource + private StringRedisTemplate stringRedisTemplate; + + @PreAuthorize("hasAuthority('sys:cache:list')") + @Operation(summary = "查询全部缓存") + @GetMapping() + public ApiResult> list() { + String key = "cache".concat(getTenantId().toString()).concat("*"); + final Set keys = stringRedisTemplate.keys(key); + final HashMap map = new HashMap<>(); + final ArrayList list = new ArrayList<>(); + assert keys != null; + keys.forEach(d -> { + final Cache cache = new Cache(); + cache.setKey(d); + try { + final String content = stringRedisTemplate.opsForValue().get(d); + if(content != null){ + cache.setContent(stringRedisTemplate.opsForValue().get(d)); + } + } catch (Exception e) { + e.printStackTrace(); + } + list.add(cache); + }); + map.put("count",keys.size()); + map.put("list",list); + return success(map); + } + + @PreAuthorize("hasAuthority('sys:cache:list')") + @Operation(summary = "根据key查询缓存信息") + @GetMapping("/{key}") + public ApiResult get(@PathVariable("key") String key) { + final String s = redisUtil.get(key + getTenantId()); + if(StrUtil.isNotBlank(s)){ + return success("读取成功", JSONObject.parseObject(s)); + } + return fail("缓存不存在!"); + } + + @PreAuthorize("hasAuthority('sys:cache:save')") + @Operation(summary = "添加缓存") + @PostMapping() + public ApiResult add(@RequestBody Cache cache) { + if (cache.getExpireTime() != null) { + redisUtil.set(cache.getKey() + ":" + getTenantId(),cache.getContent(),cache.getExpireTime(), TimeUnit.MINUTES); + return success("缓存成功"); + } + redisUtil.set(cache.getKey() + ":" + getTenantId(),cache.getContent()); + return success("缓存成功"); + } + + @PreAuthorize("hasAuthority('sys:cache:save')") + @Operation(summary = "删除缓存") + @DeleteMapping("/{key}") + public ApiResult remove(@PathVariable("key") String key) { + if (Boolean.TRUE.equals(stringRedisTemplate.delete(key))) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:cache:save')") + @Operation(summary = "缓存皮肤") + @PostMapping("/theme") + public ApiResult saveTheme(@RequestBody Cache cache) { + final User loginUser = getLoginUser(); + final String username = loginUser.getUsername(); + if (username.equals("admin")) { + redisUtil.set(cache.getKey() + ":" + getTenantId(),cache.getContent()); + return success("缓存成功"); + } + return success("缓存失败"); + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CartController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CartController.java new file mode 100644 index 0000000..c91811a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CartController.java @@ -0,0 +1,136 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Cart; +import com.gxwebsoft.common.system.entity.OrderGoods; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.CartParam; +import com.gxwebsoft.common.system.service.CartService; +import com.gxwebsoft.common.system.service.OrderGoodsService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/** + * 购物车控制器 + * + * @author 科技小王子 + * @since 2024-10-26 10:54:51 + */ +@Tag(name = "购物车管理") +@RestController +@RequestMapping("/api/system/cart") +public class CartController extends BaseController { + @Resource + private CartService cartService; + @Resource + private OrderGoodsService orderGoodsService; + + @Operation(summary = "分页查询购物车") + @GetMapping("/page") + public ApiResult> page(CartParam param) { + // 使用关联查询 + return success(cartService.pageRel(param)); + } + + @Operation(summary = "查询全部购物车") + @GetMapping() + public ApiResult> list(CartParam param) { + // 使用关联查询 + return success(cartService.listRel(param)); + } + + @Operation(summary = "根据id查询购物车") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Long id) { + // 使用关联查询 + return success(cartService.getByIdRel(id)); + } + + @Operation(summary = "添加购物车") + @PostMapping() + public ApiResult save(@RequestBody Cart cart) { + System.out.println("cart = " + cart); + final ArrayList orderGoods = new ArrayList<>(); + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + cart.setUserId(loginUser.getUserId()); + cart.setTenantId(loginUser.getTenantId()); + if (cart.getType().equals(1)) { + cart.getList().forEach(item -> { + final OrderGoods og = new OrderGoods(); + og.setType(cart.getType()); + og.setItemId(item.getCompanyId()); + og.setPayPrice(item.getPrice()); + og.setMonth(cart.getMonth()); + og.setTotalNum(cart.getCartNum()); + og.setPayStatus(false); + og.setOrderStatus(0); + og.setTenantId(loginUser.getTenantId()); + og.setUserId(loginUser.getUserId()); + og.setComments("购买".concat(item.getTenantName())); + orderGoods.add(og); + }); + } + if (cartService.save(cart)) { + orderGoodsService.saveBatch(orderGoods); + return success("添加成功"); + } + } + return fail("添加失败"); + } + + @Operation(summary = "修改购物车") + @PutMapping() + public ApiResult update(@RequestBody Cart cart) { + if (cartService.updateById(cart)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除购物车") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cartService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加购物车") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (cartService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改购物车") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cartService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除购物车") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cartService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ChatConversationController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ChatConversationController.java new file mode 100644 index 0000000..719dcc1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ChatConversationController.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.service.ChatConversationService; +import com.gxwebsoft.common.system.entity.ChatConversation; +import com.gxwebsoft.common.system.param.ChatConversationParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 聊天消息表控制器 + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +@Tag(name = "聊天") +@RestController +@RequestMapping("/api/system/chat-conversation") +public class ChatConversationController extends BaseController { + @Resource + private ChatConversationService chatConversationService; + + @PreAuthorize("hasAuthority('sys:chatConversation:list')") + @OperationLog + @Operation(summary = "分页查询聊天消息表") + @GetMapping("/page") + public ApiResult> page(ChatConversationParam param) { + // 使用关联查询 + return success(chatConversationService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:list')") + @OperationLog + @Operation(summary = "查询全部聊天消息表") + @GetMapping() + public ApiResult> list(ChatConversationParam param) { + // 使用关联查询 + return success(chatConversationService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:list')") + @OperationLog + @Operation(summary = "根据id查询聊天消息表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(chatConversationService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:save')") + @OperationLog + @Operation(summary = "添加聊天消息表") + @PostMapping() + public ApiResult save(@RequestBody ChatConversation chatConversation) { + if (chatConversationService.save(chatConversation)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:update')") + @OperationLog + @Operation(summary = "修改聊天消息表") + @PutMapping() + public ApiResult update(@RequestBody ChatConversation chatConversation) { + if (chatConversationService.updateById(chatConversation)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:remove')") + @OperationLog + @Operation(summary = "删除聊天消息表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (chatConversationService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:save')") + @OperationLog + @Operation(summary = "批量添加聊天消息表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (chatConversationService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:update')") + @OperationLog + @Operation(summary = "批量修改聊天消息表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(chatConversationService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:chatConversation:remove')") + @OperationLog + @Operation(summary = "批量删除聊天消息表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (chatConversationService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ChatMessageController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ChatMessageController.java new file mode 100644 index 0000000..6a6a707 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ChatMessageController.java @@ -0,0 +1,127 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.ChatMessageService; +import com.gxwebsoft.common.system.entity.ChatMessage; +import com.gxwebsoft.common.system.param.ChatMessageParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/** + * 聊天消息表控制器 + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +@Tag(name = "聊天") +@RestController +@RequestMapping("/api/system/chat-message") +public class ChatMessageController extends BaseController { + @Resource + private ChatMessageService chatMessageService; + + @Operation(summary = "分页查询聊天消息表") + @GetMapping("/page") + public ApiResult> page(ChatMessageParam param) { + // 使用关联查询 + return success(chatMessageService.pageRel(param)); + } + + @Operation(summary = "查询全部聊天消息表") + @GetMapping() + public ApiResult> list(ChatMessageParam param) { + User loginUser = getLoginUser(); + param.setToUserId(loginUser.getUserId()); + return success(chatMessageService.listRel(param)); + } + + @Operation(summary = "根据id查询聊天消息表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(chatMessageService.getByIdRel(id)); + } + + @Operation(summary = "添加聊天消息表") + @PostMapping() + public ApiResult save(@RequestBody ChatMessage chatMessage) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + chatMessage.setFormUserId(loginUser.getUserId()); + if (chatMessageService.save(chatMessage)) { + return success("添加成功"); + } + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:chatMessage:update')") + @Operation(summary = "修改聊天消息表") + @PutMapping() + public ApiResult update(@RequestBody ChatMessage chatMessage) { + if (chatMessageService.updateById(chatMessage)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:chatMessage:remove')") + @OperationLog + @Operation(summary = "删除聊天消息表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (chatMessageService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加聊天消息表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + final ArrayList saveData = new ArrayList<>(); + list.forEach(d -> { + d.setFormUserId(getLoginUserId()); + saveData.add(d); + }); + if(!saveData.isEmpty()){ + if (chatMessageService.saveBatch(saveData)) { + return success("发送成功"); + } + } + return fail("发送失败"); + } + + @PreAuthorize("hasAuthority('sys:chatMessage:update')") + @Operation(summary = "批量修改聊天消息表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(chatMessageService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:chatMessage:remove')") + @Operation(summary = "批量删除聊天消息表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (chatMessageService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyCommentController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyCommentController.java new file mode 100644 index 0000000..5f460b4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyCommentController.java @@ -0,0 +1,131 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyComment; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.CompanyCommentParam; +import com.gxwebsoft.common.system.service.CompanyCommentService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 应用评论控制器 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Tag(name = "应用评论管理") +@RestController +@RequestMapping("/api/system/company-comment") +public class CompanyCommentController extends BaseController { + @Resource + private CompanyCommentService companyCommentService; + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "分页查询应用评论") + @GetMapping("/page") + public ApiResult> page(CompanyCommentParam param) { + // 使用关联查询 + return success(companyCommentService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "查询全部应用评论") + @GetMapping() + public ApiResult> list(CompanyCommentParam param) { + // 使用关联查询 + return success(companyCommentService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "根据id查询应用评论") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(companyCommentService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "添加应用评论") + @PostMapping() + public ApiResult save(@RequestBody CompanyComment companyComment) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + companyComment.setUserId(loginUser.getUserId()); + } + if (companyCommentService.save(companyComment)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "修改应用评论") + @PutMapping() + public ApiResult update(@RequestBody CompanyComment companyComment) { + if (companyCommentService.updateById(companyComment)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "删除应用评论") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (companyCommentService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "批量添加应用评论") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (companyCommentService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "批量修改应用评论") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(companyCommentService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "批量删除应用评论") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (companyCommentService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyContentController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyContentController.java new file mode 100644 index 0000000..cc63569 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyContentController.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyContent; +import com.gxwebsoft.common.system.param.CompanyContentParam; +import com.gxwebsoft.common.system.service.CompanyContentService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 应用详情控制器 + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +@Tag(name = "应用详情管理") +@RestController +@RequestMapping("/api/system/company-content") +public class CompanyContentController extends BaseController { + @Resource + private CompanyContentService companyContentService; + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "分页查询应用详情") + @GetMapping("/page") + public ApiResult> page(CompanyContentParam param) { + // 使用关联查询 + return success(companyContentService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "查询全部应用详情") + @GetMapping() + public ApiResult> list(CompanyContentParam param) { + // 使用关联查询 + return success(companyContentService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "根据id查询应用详情") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(companyContentService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "添加应用详情") + @PostMapping() + public ApiResult save(@RequestBody CompanyContent companyContent) { + if (companyContentService.save(companyContent)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "修改应用详情") + @PutMapping() + public ApiResult update(@RequestBody CompanyContent companyContent) { + if (companyContentService.updateById(companyContent)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "删除应用详情") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (companyContentService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "批量添加应用详情") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (companyContentService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "批量修改应用详情") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(companyContentService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "批量删除应用详情") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (companyContentService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyController.java new file mode 100644 index 0000000..6a65b19 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyController.java @@ -0,0 +1,367 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.DesensitizedUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.*; +import com.gxwebsoft.common.system.mapper.CompanyMapper; +import com.gxwebsoft.common.system.mapper.TenantMapper; +import com.gxwebsoft.common.system.param.CompanyParam; +import com.gxwebsoft.common.system.service.*; +import com.gxwebsoft.shop.entity.ShopMerchantApply; +import com.gxwebsoft.shop.service.ShopMerchantApplyService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 企业信息控制器 + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +@Tag(name = "企业") +@RestController +@RequestMapping("/api/system/company") +public class CompanyController extends BaseController { + @Resource + private CompanyService companyService; + @Resource + private ShopMerchantApplyService shopMerchantApplyService; + @Resource + private CompanyContentService companyContentService; + @Resource + private CompanyUrlService companyUrlService; + @Resource + private CompanyParameterService companyParameterService; + @Resource + private TenantService tenantService; + @Resource + private CompanyMapper companyMapper; + @Resource + private TenantMapper tenantMapper; + @Resource + private DomainService domainService; + @Resource + private UserCollectionService userCollectionService; + @Resource + private RedisUtil redisUtil; + + + @Operation(summary = "分页查询企业信息不限租户") + @GetMapping("/pageAll") + public ApiResult> pageAll(CompanyParam param) { + final PageResult result = companyService.pageRelAll(param); + result.getList().forEach(d -> { + d.setPhone(DesensitizedUtil.mobilePhone(d.getPhone())); + d.setCompanyCode(DesensitizedUtil.idCardNum(d.getCompanyCode(),1,2)); + }); + final User loginUser = getLoginUser(); + if(loginUser != null){ + // 我的收藏 + final List myFocus = userCollectionService.list(new LambdaQueryWrapper().eq(UserCollection::getUserId, getLoginUserId())); + if (!CollectionUtils.isEmpty(myFocus)) { + final Set collect = myFocus.stream().map(UserCollection::getTid).collect(Collectors.toSet()); + if (param.getVersion() != null) { + // 我的收藏 + if (param.getVersion().equals(99)) { + param.setVersion(null); + param.setCompanyIds(collect); + } + } + result.getList().forEach(d -> { + d.setCollection(collect.contains(d.getCompanyId())); + }); + return success(result); + } + } + // 使用关联查询 + return success(result); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @Operation(summary = "分页查询企业信息") + @GetMapping("/page") + public ApiResult> page(CompanyParam param) { + // 使用关联查询 + return success(companyService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "查询全部企业信息") + @GetMapping() + public ApiResult> list(CompanyParam param) { + // 使用关联查询 + return success(companyService.listRel(param)); + } + + @Operation(summary = "根据id查询企业信息") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + final Company company = companyService.getByIdRel(id); + if (ObjectUtil.isNotEmpty(company)) { + // 应用详情 + final CompanyContent content = companyContentService.getOne(new LambdaQueryWrapper().eq(CompanyContent::getCompanyId, company.getCompanyId()).last("limit 1")); + if (ObjectUtil.isNotEmpty(content)) { + company.setContent(content.getContent()); + } + // 应用链接 + company.setLinks(companyUrlService.list(new LambdaQueryWrapper().eq(CompanyUrl::getCompanyId, company.getCompanyId()))); + // 应用参数 + company.setParameters(companyParameterService.list(new LambdaQueryWrapper().eq(CompanyParameter::getCompanyId, company.getCompanyId()))); + + } + return success(company); + } + + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + @PreAuthorize("hasAuthority('sys:company:save')") + @Operation(summary = "添加企业信息") + @PostMapping() + public ApiResult save(@RequestBody Company company) { + Tenant tenant = new Tenant(); + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + company.setUserId(loginUser.getUserId()); + tenant.setUserId(loginUser.getUserId()); + } + tenant.setTenantName(company.getShortName()); + tenant.setTenantCode(CommonUtil.randomUUID16()); + tenant.setComments(company.getComments()); + tenantService.save(tenant); + company.setTenantId(tenant.getTenantId()); + company.setTid(tenant.getTenantId()); + company.setAuthoritative(true); + // 添加租户并初始化 +// final Company result = tenantService.initialization(company); +// if (result != null) { +// return success("添加成功",result); +// } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "修改企业信息") + @PutMapping() + public ApiResult update(@RequestBody Company company) { + // 授权新的免费域名 + if (StrUtil.isNotBlank(company.getFreeDomain())) { + // 待授权的二级域名 + String domain = company.getFreeDomain().concat(".websoft.top"); + // 删除旧授权域名 + final Domain one = domainService.getOne(new LambdaQueryWrapper().eq(Domain::getType, 2).eq(Domain::getCompanyId, company.getCompanyId()).eq(Domain::getDeleted,0).last("limit 1")); + if(one != null){ + redisUtil.delete("Domain:".concat(one.getDomain())); + domainService.removeById(one); + } + // 保存记录 + final Domain sysDomain = new Domain(); + sysDomain.setDomain(domain); + sysDomain.setType(2); + sysDomain.setSortNumber(100); + sysDomain.setCompanyId(company.getCompanyId()); + sysDomain.setTenantId(company.getTenantId()); + domainService.save(sysDomain); + company.setDomain(domain); + // 写入缓存 + redisUtil.set("Domain:".concat(domain), company.getTenantId()); + } + // 同步更新租户表 + if(StrUtil.isNotBlank(company.getShortName())){ + final Tenant tenant = new Tenant(); + tenant.setTenantId(company.getTenantId()); + tenant.setTenantName(company.getShortName()); + tenantService.updateById(tenant); + } + if (companyService.updateById(company)) { + // 清除缓存 + redisUtil.delete("TenantInfo:".concat(company.getTenantId().toString())); + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "删除企业信息") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + final Company company = companyService.getById(id); + tenantService.removeById(company.getTenantId()); + if (companyService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "批量添加企业信息") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (companyService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "批量修改企业信息") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(companyService, "company_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "批量删除企业信息") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (companyService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "根据id查询企业信息") + @GetMapping("/profile") + public ApiResult profile() { + final User loginUser = getLoginUser(); + if(loginUser != null){ + final Company company = companyService.getOne(new LambdaQueryWrapper().eq(Company::getTenantId, loginUser.getTenantId()).eq(Company::getAuthoritative, true).last("limit 1")); + if (ObjectUtil.isNotEmpty(company)) { + final ShopMerchantApply apply = shopMerchantApplyService.getOne(new LambdaQueryWrapper().eq(ShopMerchantApply::getTenantId, loginUser.getTenantId()).last("limit 1")); + if (ObjectUtil.isNotEmpty(apply)) { + company.setCompanyName(apply.getMerchantName()); + company.setCompanyType(apply.getShopType()); + if (apply.getStatus().equals(1)) { + company.setAuthentication(1); + } + } + LocalDateTime now = LocalDateTime.now(); + // 即将过期(一周内过期的) + company.setSoon(company.getExpirationTime().minusDays(7).compareTo(now)); + // 是否过期 -1已过期 大于0 未过期 + company.setStatus(company.getExpirationTime().compareTo(now)); + return success(company); + } + } + return fail("企业不存在",null); + } + + @PreAuthorize("hasAuthority('sys:company:profile')") + @OperationLog + @Operation(summary = "根据id查询企业信息不限租户") + @GetMapping("/profileAll/{companyId}") + public ApiResult profileAll(@PathVariable("companyId") Integer companyId) { + return success(companyMapper.getCompanyAll(companyId)); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "销毁租户") + @DeleteMapping("/destruction/{id}") + public ApiResult destruction(@PathVariable("id") Integer id) { + final User loginUser = getLoginUser(); + if (!loginUser.getUsername().equals("admin")) { + throw new BusinessException("只有超级管理员才能操作"); + } + final Integer tenantId = getTenantId(); + if (tenantService.removeById(tenantId)) { + return success("删除成功",tenantId); + } + return fail("删除失败"); + } + @Operation(summary = "检查企业是否存在") + @GetMapping("/existence") + public ApiResult existence(ExistenceParam param) { + CompanyParam companyParam = new CompanyParam(); + if (param.getField().equals("shortName")) { + companyParam.setAppName(param.getValue()); + List count = companyMapper.getCount(companyParam); + if (!CollectionUtils.isEmpty(count)) { + return success(param.getValue() + "已存在"); + } + } + if (param.getField().equals("email")) { + companyParam.setEmail(param.getValue()); + List count = companyMapper.getCount(companyParam); + if (!CollectionUtils.isEmpty(count)) { + return success(param.getValue() + "已存在"); + } + } + if (param.getField().equals("phone")) { + companyParam.setPhone(param.getValue()); + List count = companyMapper.getCount(companyParam); + if (!CollectionUtils.isEmpty(count)) { + return success(param.getValue() + "已存在"); + } + } + return fail(param.getValue() + "不存在"); + } + + @Operation(summary = "根据id查询企业信息不限租户不带token") + @GetMapping("/companyInfoAll/{companyId}") + public ApiResult companyInfoAll(@PathVariable("companyId") Integer companyId) { + return success(companyMapper.getCompanyAll(companyId)); + } + + @PreAuthorize("hasAuthority('sys:company:updateAll')") + @OperationLog + @Operation(summary = "修改企业信息") + @PutMapping("/updateCompanyAll") + public ApiResult updateCompanyAll(@RequestBody Company company) { + if (companyMapper.updateByIdAll(company)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:removeAll')") + @OperationLog + @Operation(summary = "删除企业信息") + @DeleteMapping("/removeAll/{id}") + public ApiResult removeAll(@PathVariable("id") Integer id) { + if (companyMapper.removeCompanyAll(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:company:removeAll')") + @OperationLog + @Operation(summary = "恢复租户") + @DeleteMapping("/undeleteAll/{id}") + public ApiResult undeleteAll(@PathVariable("id") Integer id) { + if (companyMapper.undeleteAll(id)) { + return success("恢复成功"); + } + return fail("恢复失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyGitController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyGitController.java new file mode 100644 index 0000000..451118c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyGitController.java @@ -0,0 +1,122 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyGit; +import com.gxwebsoft.common.system.param.CompanyGitParam; +import com.gxwebsoft.common.system.service.CompanyGitService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 代码仓库控制器 + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +@Tag(name = "代码仓库管理") +@RestController +@RequestMapping("/api/system/company-git") +public class CompanyGitController extends BaseController { + @Resource + private CompanyGitService companyGitService; + + @PreAuthorize("hasAuthority('sys:companyGit:list')") + @Operation(summary = "分页查询代码仓库") + @GetMapping("/page") + public ApiResult> page(CompanyGitParam param) { + // 使用关联查询 + return success(companyGitService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:companyGit:list')") + @Operation(summary = "查询全部代码仓库") + @GetMapping() + public ApiResult> list(CompanyGitParam param) { + // 使用关联查询 + return success(companyGitService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:companyGit:list')") + @Operation(summary = "根据id查询代码仓库") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(companyGitService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:companyGit:save')") + @OperationLog + @Operation(summary = "添加代码仓库") + @PostMapping() + public ApiResult save(@RequestBody CompanyGit companyGit) { + if (companyGitService.save(companyGit)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:companyGit:update')") + @OperationLog + @Operation(summary = "修改代码仓库") + @PutMapping() + public ApiResult update(@RequestBody CompanyGit companyGit) { + if (companyGitService.updateById(companyGit)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:companyGit:remove')") + @OperationLog + @Operation(summary = "删除代码仓库") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (companyGitService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:companyGit:save')") + @OperationLog + @Operation(summary = "批量添加代码仓库") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (companyGitService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:companyGit:update')") + @OperationLog + @Operation(summary = "批量修改代码仓库") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(companyGitService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:companyGit:remove')") + @OperationLog + @Operation(summary = "批量删除代码仓库") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (companyGitService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyParameterController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyParameterController.java new file mode 100644 index 0000000..086964f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyParameterController.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyParameter; +import com.gxwebsoft.common.system.param.CompanyParameterParam; +import com.gxwebsoft.common.system.service.CompanyParameterService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 应用参数控制器 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Tag(name = "应用参数管理") +@RestController +@RequestMapping("/api/system/company-parameter") +public class CompanyParameterController extends BaseController { + @Resource + private CompanyParameterService companyParameterService; + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "分页查询应用参数") + @GetMapping("/page") + public ApiResult> page(CompanyParameterParam param) { + // 使用关联查询 + return success(companyParameterService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "查询全部应用参数") + @GetMapping() + public ApiResult> list(CompanyParameterParam param) { + // 使用关联查询 + return success(companyParameterService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "根据id查询应用参数") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(companyParameterService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "添加应用参数") + @PostMapping() + public ApiResult save(@RequestBody CompanyParameter companyParameter) { + if (companyParameterService.save(companyParameter)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "修改应用参数") + @PutMapping() + public ApiResult update(@RequestBody CompanyParameter companyParameter) { + if (companyParameterService.updateById(companyParameter)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "删除应用参数") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (companyParameterService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "批量添加应用参数") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (companyParameterService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "批量修改应用参数") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(companyParameterService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "批量删除应用参数") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (companyParameterService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyUrlController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyUrlController.java new file mode 100644 index 0000000..6de5078 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/CompanyUrlController.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyUrl; +import com.gxwebsoft.common.system.param.CompanyUrlParam; +import com.gxwebsoft.common.system.service.CompanyUrlService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 应用域名控制器 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Tag(name = "应用域名管理") +@RestController +@RequestMapping("/api/system/company-url") +public class CompanyUrlController extends BaseController { + @Resource + private CompanyUrlService companyUrlService; + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "分页查询应用域名") + @GetMapping("/page") + public ApiResult> page(CompanyUrlParam param) { + // 使用关联查询 + return success(companyUrlService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "查询全部应用域名") + @GetMapping() + public ApiResult> list(CompanyUrlParam param) { + // 使用关联查询 + return success(companyUrlService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "根据id查询应用域名") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(companyUrlService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "添加应用域名") + @PostMapping() + public ApiResult save(@RequestBody CompanyUrl companyUrl) { + if (companyUrlService.save(companyUrl)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "修改应用域名") + @PutMapping() + public ApiResult update(@RequestBody CompanyUrl companyUrl) { + if (companyUrlService.updateById(companyUrl)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "删除应用域名") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (companyUrlService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "批量添加应用域名") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (companyUrlService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "批量修改应用域名") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(companyUrlService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "批量删除应用域名") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (companyUrlService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ComponentsController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ComponentsController.java new file mode 100644 index 0000000..324459d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ComponentsController.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.ComponentsService; +import com.gxwebsoft.common.system.entity.Components; +import com.gxwebsoft.common.system.param.ComponentsParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 组件控制器 + * + * @author 科技小王子 + * @since 2024-08-25 19:08:51 + */ +@Tag(name = "组件管理") +@RestController +@RequestMapping("/api/system/components") +public class ComponentsController extends BaseController { + @Resource + private ComponentsService componentsService; + + @PreAuthorize("hasAuthority('sys:components:list')") + @OperationLog + @Operation(summary = "分页查询组件") + @GetMapping("/page") + public ApiResult> page(ComponentsParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(componentsService.page(page, page.getWrapper())); + // 使用关联查询 + //return success(componentsService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:components:list')") + @OperationLog + @Operation(summary = "查询全部组件") + @GetMapping() + public ApiResult> list(ComponentsParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(componentsService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(componentsService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:components:list')") + @OperationLog + @Operation(summary = "根据id查询组件") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(componentsService.getById(id)); + // 使用关联查询 + //return success(componentsService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:components:save')") + @OperationLog + @Operation(summary = "添加组件") + @PostMapping() + public ApiResult save(@RequestBody Components components) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + components.setUserId(loginUser.getUserId()); + } + if (componentsService.save(components)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:components:update')") + @OperationLog + @Operation(summary = "修改组件") + @PutMapping() + public ApiResult update(@RequestBody Components components) { + if (componentsService.updateById(components)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:components:remove')") + @OperationLog + @Operation(summary = "删除组件") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (componentsService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:components:save')") + @OperationLog + @Operation(summary = "批量添加组件") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (componentsService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:components:update')") + @OperationLog + @Operation(summary = "批量修改组件") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(componentsService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:components:remove')") + @OperationLog + @Operation(summary = "批量删除组件") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (componentsService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictController.java new file mode 100644 index 0000000..27fb3fe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictController.java @@ -0,0 +1,177 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Dict; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; +import com.gxwebsoft.common.system.param.DictParam; +import com.gxwebsoft.common.system.service.DictDataService; +import com.gxwebsoft.common.system.service.DictService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 字典控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Tag(name = "字典管理(业务类)") +@RestController +@RequestMapping("/api/system/dict") +public class DictController extends BaseController { + @Resource + private DictService dictService; + @Resource + private DictDataService dictDataService; + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "分页查询字典") + @GetMapping("/page") + public ApiResult> page(DictParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典") + @GetMapping() + public ApiResult> list(DictParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典") + @GetMapping("/tree") + public ApiResult tree() { + final HashMap result = new HashMap<>(); + final List dictData = dictDataService.listRel(new DictDataParam()); + final Map> dataCollect = dictData.stream().collect(Collectors.groupingBy(DictData::getDictCode)); + for (String code : dataCollect.keySet()) { + Dict dict = new Dict(); + dict.setDictCode(code); + final Set> list = new LinkedHashSet<>(); + Set codes = new LinkedHashSet<>(); + for(DictData item : dictData){ + if (item.getDictCode().equals(code)) { + codes.add(item.getDictDataCode()); + } + } + list.add(codes); + dict.setItems(list); + result.put(code,dict.getItems()); + } + return success(result); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "根据id查询字典") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "添加字典") + @PostMapping() + public ApiResult add(@RequestBody Dict dict) { + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictCode, dict.getDictCode())) > 0) { + return fail("字典标识已存在"); + } + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictName, dict.getDictName())) > 0) { + return fail("字典名称已存在"); + } + if (dictService.save(dict)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:update')") + @Operation(summary = "修改字典") + @PutMapping() + public ApiResult update(@RequestBody Dict dict) { + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictCode, dict.getDictCode()) + .ne(Dict::getDictId, dict.getDictId())) > 0) { + return fail("字典标识已存在"); + } + if (dictService.count(new LambdaQueryWrapper() + .eq(Dict::getDictName, dict.getDictName()) + .ne(Dict::getDictId, dict.getDictId())) > 0) { + return fail("字典名称已存在"); + } + if (dictService.updateById(dict)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "删除字典") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "批量添加字典") + @PostMapping("/batch") + public ApiResult> saveBatch(@RequestBody List list) { + if (CommonUtil.checkRepeat(list, Dict::getDictCode)) { + return fail("字典标识不能重复", null); + } + if (CommonUtil.checkRepeat(list, Dict::getDictName)) { + return fail("字典名称不能重复", null); + } + List codeExists = dictService.list(new LambdaQueryWrapper() + .in(Dict::getDictCode, list.stream().map(Dict::getDictCode) + .collect(Collectors.toList()))); + if (codeExists.size() > 0) { + return fail("字典标识已存在", codeExists.stream().map(Dict::getDictCode) + .collect(Collectors.toList())).setCode(2); + } + List nameExists = dictService.list(new LambdaQueryWrapper() + .in(Dict::getDictName, list.stream().map(Dict::getDictCode) + .collect(Collectors.toList()))); + if (nameExists.size() > 0) { + return fail("字典名称已存在", nameExists.stream().map(Dict::getDictName) + .collect(Collectors.toList())).setCode(3); + } + if (dictService.saveBatch(list)) { + return success("添加成功", null); + } + return fail("添加失败", null); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "批量删除字典") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictDataController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictDataController.java new file mode 100644 index 0000000..1942f67 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictDataController.java @@ -0,0 +1,124 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; +import com.gxwebsoft.common.system.service.DictDataService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 字典数据控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Tag(name = "字典数据管理(业务类)") +@RestController +@RequestMapping("/api/system/dict-data") +public class DictDataController extends BaseController { + @Resource + private DictDataService dictDataService; + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "分页查询字典数据") + @GetMapping("/page") + public ApiResult> page(DictDataParam param) { + return success(dictDataService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典数据") + @GetMapping() + public ApiResult> list(DictDataParam param) { + return success(dictDataService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "根据id查询字典数据") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictDataService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "添加字典数据") + @PostMapping() + public ApiResult add(@RequestBody DictData dictData) { + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataName, dictData.getDictDataName())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataCode, dictData.getDictDataCode())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictDataService.save(dictData)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:update')") + @Operation(summary = "修改字典数据") + @PutMapping() + public ApiResult update(@RequestBody DictData dictData) { + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataName, dictData.getDictDataName()) + .ne(DictData::getDictDataId, dictData.getDictDataId())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictDataService.count(new LambdaQueryWrapper() + .eq(DictData::getDictId, dictData.getDictId()) + .eq(DictData::getDictDataCode, dictData.getDictDataCode()) + .ne(DictData::getDictDataId, dictData.getDictDataId())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictDataService.updateById(dictData)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "删除字典数据") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictDataService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "批量添加字典数据") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List dictDataList) { + if (dictDataService.saveBatch(dictDataList)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "批量删除字典数据") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictDataService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictionaryController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictionaryController.java new file mode 100644 index 0000000..ecbeb6d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictionaryController.java @@ -0,0 +1,148 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Dictionary; +import com.gxwebsoft.common.system.param.DictionaryParam; +import com.gxwebsoft.common.system.service.DictionaryService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 字典控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Tag(name = "字典管理(系统类)") +@RestController +@RequestMapping("/api/system/dictionary") +public class DictionaryController extends BaseController { + @Resource + private DictionaryService dictionaryService; + + @PreAuthorize("hasAuthority('sys:dictionary:list')") + @Operation(summary = "分页查询字典") + @GetMapping("/page") + public ApiResult> page(DictionaryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictionaryService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dictionary:list')") + @Operation(summary = "查询全部字典") + @GetMapping() + public ApiResult> list(DictionaryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(dictionaryService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:dictionary:list')") + @Operation(summary = "根据id查询字典") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictionaryService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:dictionary:save')") + @Operation(summary = "添加字典") + @PostMapping() + public ApiResult add(@RequestBody Dictionary dictionary) { + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictCode, dictionary.getDictCode())) > 0) { + return fail("字典标识已存在"); + } + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictName, dictionary.getDictName())) > 0) { + return fail("字典名称已存在"); + } + if (dictionaryService.save(dictionary)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dictionary:update')") + @Operation(summary = "修改字典") + @PutMapping() + public ApiResult update(@RequestBody Dictionary dictionary) { + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictCode, dictionary.getDictCode()) + .ne(Dictionary::getDictId, dictionary.getDictId())) > 0) { + return fail("字典标识已存在"); + } + if (dictionaryService.count(new LambdaQueryWrapper() + .eq(Dictionary::getDictName, dictionary.getDictName()) + .ne(Dictionary::getDictId, dictionary.getDictId())) > 0) { + return fail("字典名称已存在"); + } + if (dictionaryService.updateById(dictionary)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dictionary:remove')") + @Operation(summary = "删除字典") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictionaryService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dictionary:save')") + @Operation(summary = "批量添加字典") + @PostMapping("/batch") + public ApiResult> saveBatch(@RequestBody List list) { + if (CommonUtil.checkRepeat(list, Dictionary::getDictCode)) { + return fail("字典标识不能重复", null); + } + if (CommonUtil.checkRepeat(list, Dictionary::getDictName)) { + return fail("字典名称不能重复", null); + } + List codeExists = dictionaryService.list(new LambdaQueryWrapper() + .in(Dictionary::getDictCode, list.stream().map(Dictionary::getDictCode) + .collect(Collectors.toList()))); + if (codeExists.size() > 0) { + return fail("字典标识已存在", codeExists.stream().map(Dictionary::getDictCode) + .collect(Collectors.toList())).setCode(2); + } + List nameExists = dictionaryService.list(new LambdaQueryWrapper() + .in(Dictionary::getDictName, list.stream().map(Dictionary::getDictCode) + .collect(Collectors.toList()))); + if (nameExists.size() > 0) { + return fail("字典名称已存在", nameExists.stream().map(Dictionary::getDictName) + .collect(Collectors.toList())).setCode(3); + } + if (dictionaryService.saveBatch(list)) { + return success("添加成功", null); + } + return fail("添加失败", null); + } + + @PreAuthorize("hasAuthority('sys:dictionary:remove')") + @Operation(summary = "批量删除字典") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictionaryService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictionaryDataController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictionaryDataController.java new file mode 100644 index 0000000..df16554 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DictionaryDataController.java @@ -0,0 +1,123 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.param.DictionaryDataParam; +import com.gxwebsoft.common.system.service.DictionaryDataService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 字典数据控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Tag(name = "字典数据管理(系统类)") +@RestController +@RequestMapping("/api/system/dictionary-data") +public class DictionaryDataController extends BaseController { + @Resource + private DictionaryDataService dictionaryDataService; + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "分页查询字典数据") + @GetMapping("/page") + public ApiResult> page(DictionaryDataParam param) { + return success(dictionaryDataService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "查询全部字典数据") + @GetMapping() + public ApiResult> list(DictionaryDataParam param) { + return success(dictionaryDataService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:dict:list')") + @Operation(summary = "根据id查询字典数据") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(dictionaryDataService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "添加字典数据") + @PostMapping() + public ApiResult add(@RequestBody DictionaryData dictionaryData) { + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataName, dictionaryData.getDictDataName())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataCode, dictionaryData.getDictDataCode())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictionaryDataService.save(dictionaryData)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:update')") + @Operation(summary = "修改字典数据") + @PutMapping() + public ApiResult update(@RequestBody DictionaryData dictionaryData) { + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataName, dictionaryData.getDictDataName()) + .ne(DictionaryData::getDictDataId, dictionaryData.getDictDataId())) > 0) { + return fail("字典数据名称已存在"); + } + if (dictionaryDataService.count(new LambdaQueryWrapper() + .eq(DictionaryData::getDictId, dictionaryData.getDictId()) + .eq(DictionaryData::getDictDataCode, dictionaryData.getDictDataCode()) + .ne(DictionaryData::getDictDataId, dictionaryData.getDictDataId())) > 0) { + return fail("字典数据标识已存在"); + } + if (dictionaryDataService.updateById(dictionaryData)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "删除字典数据") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (dictionaryDataService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:save')") + @Operation(summary = "批量添加字典数据") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List dictDataList) { + if (dictionaryDataService.saveBatch(dictDataList)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:dict:remove')") + @Operation(summary = "批量删除字典数据") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (dictionaryDataService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DomainController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DomainController.java new file mode 100644 index 0000000..66b95cb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/DomainController.java @@ -0,0 +1,127 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.DomainParam; +import com.gxwebsoft.common.system.service.DomainService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 授权域名控制器 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Tag(name = "授权域名管理") +@RestController +@RequestMapping("/api/system/domain") +public class DomainController extends BaseController { + @Resource + private DomainService domainService; + + @Operation(summary = "分页查询授权域名") + @GetMapping("/page") + public ApiResult> page(DomainParam param) { + // 使用关联查询 + return success(domainService.pageRel(param)); + } + + @Operation(summary = "查询全部授权域名") + @GetMapping() + public ApiResult> list(DomainParam param) { + // 使用关联查询 + return success(domainService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:domain:list')") + @OperationLog + @Operation(summary = "根据id查询授权域名") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(domainService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:domain:save')") + @OperationLog + @Operation(summary = "添加授权域名") + @PostMapping() + public ApiResult save(@RequestBody Domain domain) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + domain.setUserId(loginUser.getUserId()); + } + if (domainService.save(domain)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:update')") + @OperationLog + @Operation(summary = "修改授权域名") + @PutMapping() + public ApiResult update(@RequestBody Domain domain) { + if (domainService.updateById(domain)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:remove')") + @OperationLog + @Operation(summary = "删除授权域名") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (domainService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:save')") + @OperationLog + @Operation(summary = "批量添加授权域名") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (domainService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:update')") + @OperationLog + @Operation(summary = "批量修改授权域名") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(domainService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:domain:remove')") + @OperationLog + @Operation(summary = "批量删除授权域名") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (domainService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EmailController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EmailController.java new file mode 100644 index 0000000..cf1f9cc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EmailController.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.EmailRecord; +import com.gxwebsoft.common.system.service.EmailRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +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 javax.annotation.Resource; +import javax.mail.MessagingException; + +/** + * 邮件功能控制器 + * + * @author WebSoft + * @since 2020-03-21 00:37:11 + */ +@Tag(name = "邮件功能") +@RestController +@RequestMapping("/api/system/email") +public class EmailController extends BaseController { + @Resource + private EmailRecordService emailRecordService; + + @PreAuthorize("hasAuthority('sys:email:send')") + @Operation(summary = "发送邮件") + @PostMapping() + public ApiResult send(@RequestBody EmailRecord emailRecord) { + try { + emailRecordService.sendFullTextEmail(emailRecord.getTitle(), emailRecord.getContent(), + emailRecord.getReceiver().split(",")); + emailRecord.setCreateUserId(getLoginUserId()); + emailRecordService.save(emailRecord); + return success("发送成功"); + } catch (MessagingException e) { + e.printStackTrace(); + } + return fail("发送失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EmailTestController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EmailTestController.java new file mode 100644 index 0000000..6e4c3f4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EmailTestController.java @@ -0,0 +1,116 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.util.EmailTemplateUtil; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * 邮件测试控制器 + * 用于测试邮件模板功能 + * + * @author WebSoft + * @since 2024-08-28 + */ +@Tag(name = "邮件测试") +@RestController +@RequestMapping("/api/email-test") +public class EmailTestController extends BaseController { + + @Resource + private EmailTemplateUtil emailTemplateUtil; + + @Operation(summary = "测试注册成功邮件") + @PostMapping("/register-success") + public ApiResult testRegisterSuccessEmail(@RequestParam String email) { + try { + emailTemplateUtil.sendRegisterSuccessEmail( + "测试用户", + "13800138000", + "TestPassword123", + email, + getTenantId() + ); + return success("注册成功邮件发送成功"); + } catch (Exception e) { + return fail("邮件发送失败: " + e.getMessage()); + } + } + + @Operation(summary = "测试密码重置邮件") + @PostMapping("/password-reset") + public ApiResult testPasswordResetEmail(@RequestParam String email) { + try { + emailTemplateUtil.sendPasswordResetEmail( + "测试用户", + "13800138000", + "NewPassword456", + email, + getTenantId() + ); + return success("密码重置邮件发送成功"); + } catch (Exception e) { + return fail("邮件发送失败: " + e.getMessage()); + } + } + + @Operation(summary = "测试通知邮件") + @PostMapping("/notification") + public ApiResult testNotificationEmail(@RequestParam String email, + @RequestParam(required = false) String title, + @RequestParam(required = false) String content) { + try { + String emailTitle = title != null ? title : "WebSoft系统通知"; + String emailContent = content != null ? content : "这是一条测试通知消息,用于验证邮件模板功能是否正常工作。"; + + emailTemplateUtil.sendNotificationEmailWithAction( + emailTitle, + emailContent, + email, + getTenantId(), + "https://www.gxwebsoft.com", + "访问官网" + ); + return success("通知邮件发送成功"); + } catch (Exception e) { + return fail("邮件发送失败: " + e.getMessage()); + } + } + + @Operation(summary = "测试安全提醒邮件") + @PostMapping("/security-alert") + public ApiResult testSecurityAlertEmail(@RequestParam String email) { + try { + emailTemplateUtil.sendSecurityAlertEmail( + "测试用户", + "13800138000", + email, + getTenantId(), + "异地登录检测" + ); + return success("安全提醒邮件发送成功"); + } catch (Exception e) { + return fail("邮件发送失败: " + e.getMessage()); + } + } + + @Operation(summary = "测试系统维护通知邮件") + @PostMapping("/maintenance") + public ApiResult testMaintenanceEmail(@RequestParam String email) { + try { + emailTemplateUtil.sendMaintenanceNotificationEmail( + email, + getTenantId(), + "2024年8月28日 23:00-24:00", + "1小时" + ); + return success("维护通知邮件发送成功"); + } catch (Exception e) { + return fail("邮件发送失败: " + e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EnvironmentController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EnvironmentController.java new file mode 100644 index 0000000..9ba356b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/EnvironmentController.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.EnvironmentService; +import com.gxwebsoft.common.system.entity.Environment; +import com.gxwebsoft.common.system.param.EnvironmentParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 环境管理控制器 + * + * @author 科技小王子 + * @since 2023-10-18 08:45:13 + */ +@Tag(name = "环境管理") +@RestController +@RequestMapping("/api/system/environment") +public class EnvironmentController extends BaseController { + @Resource + private EnvironmentService environmentService; + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "分页查询环境管理") + @GetMapping("/page") + public ApiResult> page(EnvironmentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(environmentService.page(page, page.getWrapper())); + // 使用关联查询 + //return success(environmentService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "查询全部环境管理") + @GetMapping() + public ApiResult> list(EnvironmentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(environmentService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(environmentService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:company:list')") + @OperationLog + @Operation(summary = "根据id查询环境管理") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(environmentService.getById(id)); + // 使用关联查询 + //return success(environmentService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "添加环境管理") + @PostMapping() + public ApiResult save(@RequestBody Environment environment) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + environment.setUserId(loginUser.getUserId()); + } + if (environmentService.save(environment)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "修改环境管理") + @PutMapping() + public ApiResult update(@RequestBody Environment environment) { + if (environmentService.updateById(environment)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "删除环境管理") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (environmentService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:company:save')") + @OperationLog + @Operation(summary = "批量添加环境管理") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (environmentService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:company:update')") + @OperationLog + @Operation(summary = "批量修改环境管理") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(environmentService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:company:remove')") + @OperationLog + @Operation(summary = "批量删除环境管理") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (environmentService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/FileController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/FileController.java new file mode 100644 index 0000000..e61068d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/FileController.java @@ -0,0 +1,319 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.utils.FileServerUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.param.FileRecordParam; +import com.gxwebsoft.common.system.service.FileRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; + +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + * 文件上传下载控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:24 + */ +@Tag(name = "文件上传下载") +@RestController +@RequestMapping("/api/file") +public class FileController extends BaseController { + @Resource + private ConfigProperties config; + @Resource + private RedisUtil redisUtil; + @Resource + private FileRecordService fileRecordService; + + @PreAuthorize("hasAuthority('sys:file:upload')") + @Operation(summary = "上传文件") + @PostMapping("/upload") + public ApiResult upload(@RequestParam MultipartFile file, HttpServletRequest request) { + FileRecord result = null; + try { + String dir = getUploadDir(); + File upload = FileServerUtil.upload(file, dir, config.getUploadUuidName()); + String path = upload.getAbsolutePath().replace("\\", "/").substring(dir.length() - 1); +// String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/upload"); + String requestURL = config.getFileServer() + "/api/file"; + String originalName = file.getOriginalFilename(); + result = new FileRecord(); + result.setCreateUserId(getLoginUserId()); + result.setName(StrUtil.isBlank(originalName) ? upload.getName() : originalName); + result.setLength(upload.length()); + result.setPath(path); + result.setUrl(requestURL + path); + String contentType = FileServerUtil.getContentType(upload); + result.setContentType(contentType); + if (FileServerUtil.isImage(contentType)) { + result.setThumbnail(requestURL + "/thumbnail" + path); + } + result.setDownloadUrl(config.getFileServer() + "/download" + path); + // 云存储配置 + final String s = redisUtil.get("setting:upload:" + getTenantId()); + final JSONObject jsonObject = JSONObject.parseObject(s); + final String uploadMethod = jsonObject.getString("uploadMethod"); + final String bucketDomain = jsonObject.getString("bucketDomain"); + if(!uploadMethod.equals("file")){ + path = bucketDomain + path; + } + result.setUrl(path); + fileRecordService.save(result); + return success(result); + } catch (Exception e) { + e.printStackTrace(); + return fail("上传失败", result).setError(e.toString()); + } + } + + @PreAuthorize("hasAuthority('sys:file:upload')") + @Operation(summary = "上传base64文件") + @PostMapping("/upload/base64") + public ApiResult uploadBase64(String base64, String fileName, HttpServletRequest request) { + FileRecord result = null; + try { + String dir = getUploadDir(); + File upload = FileServerUtil.upload(base64, fileName, getUploadDir()); + String path = upload.getAbsolutePath().substring(dir.length()).replace("\\", "/"); + String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/upload/base64"); + result = new FileRecord(); + result.setCreateUserId(getLoginUserId()); + result.setName(StrUtil.isBlank(fileName) ? upload.getName() : fileName); + result.setLength(upload.length()); + result.setPath(path); + result.setUrl(requestURL + path); + result.setThumbnail(FileServerUtil.isImage(upload) ? (requestURL + "/thumbnail" + path) : null); + fileRecordService.save(result); + return success(result); + } catch (Exception e) { + e.printStackTrace(); + return fail("上传失败", result).setError(e.toString()); + } + } + + @PreAuthorize("hasAuthority('sys:file:upload')") + @Operation(summary = "上传图片") + @PostMapping("/image") + public HashMap image(@RequestParam MultipartFile file, HttpServletRequest request) { + FileRecord result = null; + try { + String dir = getUploadDir(); + File upload = FileServerUtil.upload(file, dir, config.getUploadUuidName()); + String path = upload.getAbsolutePath().replace("\\", "/").substring(dir.length() - 1); +// System.out.println("request.getRequestURL() = " + request.getRequestURL()); +// String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/image"); + String requestURL = config.getFileServer() + "/api/file"; +// System.out.println("requestURL = " + requestURL); +// config.getServerUrl() + String originalName = file.getOriginalFilename(); + result = new FileRecord(); + result.setCreateUserId(getLoginUserId()); + result.setName(StrUtil.isBlank(originalName) ? upload.getName() : originalName); + result.setLength(upload.length()); + result.setPath(path); + result.setUrl(path); + String contentType = FileServerUtil.getContentType(upload); + result.setContentType(contentType); + if (FileServerUtil.isImage(contentType)) { + result.setThumbnail(requestURL + "/thumbnail" + path); + } + result.setDownloadUrl(requestURL + "/download" + path); + final HashMap map = new HashMap<>(); + map.put("name",result.getName()); + map.put("status","done"); + map.put("thumbUrl",result.getThumbnail()); + map.put("downloadUrl",result.getDownloadUrl()); + map.put("url",result.getUrl()); + fileRecordService.save(result); + return map; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @PreAuthorize("hasAuthority('sys:file:list')") + @Operation(summary = "根据id查询文件") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(fileRecordService.getByIdRel(id)); + } + + @Operation(summary = "查看原文件") + @GetMapping("/{dir}/{name:.+}") + public void preview(@PathVariable("dir") String dir, @PathVariable("name") String name, + HttpServletResponse response, HttpServletRequest request) { + File file = new File(getUploadDir(), dir + "/" + name); + FileServerUtil.preview(file, getPdfOutDir(), config.getOpenOfficeHome(), response, request); + } + + @Operation(summary = "下载原文件") + @GetMapping("/download/{dir}/{name:.+}") + public void download(@PathVariable("dir") String dir, @PathVariable("name") String name, + HttpServletResponse response, HttpServletRequest request) { + String path = dir + "/" + name; + FileRecord record = fileRecordService.getByIdPath(path); + File file = new File(getUploadDir(), path); + String fileName = record == null ? file.getName() : record.getName(); + FileServerUtil.preview(file, true, fileName, null, null, response, request); + } + + @Operation(summary = "查看缩略图") + @GetMapping("/thumbnail/{dir}/{name:.+}") + public void thumbnail(@PathVariable("dir") String dir, @PathVariable("name") String name, + HttpServletResponse response, HttpServletRequest request) { + File file = new File(getUploadDir(), dir + "/" + name); + File thumbnail = new File(getUploadSmDir(), dir + "/" + name); + FileServerUtil.previewThumbnail(file, thumbnail, config.getThumbnailSize(), response, request); + } + + @PreAuthorize("hasAuthority('sys:file:remove')") + @Operation(summary = "删除文件") + @DeleteMapping("/remove/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + FileRecord record = fileRecordService.getById(id); + if (fileRecordService.removeById(id)) { + if (StrUtil.isNotBlank(record.getPath())) { + fileRecordService.deleteFileAsync(Arrays.asList( + new File(getUploadDir(), record.getPath()), + new File(getUploadSmDir(), record.getPath()) + )); + } + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:file:remove')") + @Operation(summary = "批量删除文件") + @DeleteMapping("/remove/batch") + public ApiResult deleteBatch(@RequestBody List ids) { + List fileRecords = fileRecordService.listByIds(ids); + if (fileRecordService.removeByIds(ids)) { + List files = new ArrayList<>(); + for (FileRecord record : fileRecords) { + if (StrUtil.isNotBlank(record.getPath())) { + files.add(new File(getUploadDir(), record.getPath())); + files.add(new File(getUploadSmDir(), record.getPath())); + } + } + fileRecordService.deleteFileAsync(files); + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:file:list')") + @Operation(summary = "分页查询文件") + @GetMapping("/page") + public ApiResult> page(FileRecordParam param, HttpServletRequest request) { + PageResult result = fileRecordService.pageRel(param); +// String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/page"); + String requestURL = config.getFileServer(); + for (FileRecord record : result.getList()) { + if (StrUtil.isNotBlank(record.getPath())) { + record.setUrl(requestURL + record.getPath()); + if (FileServerUtil.isImage(record.getContentType())) { + record.setThumbnail(requestURL + "/thumbnail" + record.getPath()); + } + record.setDownloadUrl(requestURL + "/download" + record.getPath()); + } + } + return success(result); + } + + @PreAuthorize("hasAuthority('sys:file:list')") + @Operation(summary = "查询全部文件") + @GetMapping("/list") + public ApiResult> list(FileRecordParam param, HttpServletRequest request) { + List records = fileRecordService.listRel(param); +// String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/list"); + String requestURL = config.getFileServer(); + for (FileRecord record : records) { + if (StrUtil.isNotBlank(record.getPath())) { + record.setUrl(requestURL + record.getPath()); + if (FileServerUtil.isImage(record.getContentType())) { + record.setThumbnail(requestURL + "/thumbnail" + record.getPath()); + } + record.setDownloadUrl(requestURL + "/download" + record.getPath()); + } + } + return success(records); + } + + /** + * 文件上传基目录 + */ + private String getUploadBaseDir() { + return config.getUploadPath(); + } + + /** + * 文件上传位置(服务器) + */ + private String getUploadDir() { + return config.getUploadPath(); + } + + /** + * 文件上传位置(本地) + */ +// private String getUploadDir() { +// return "/Users/gxwebsoft/Documents/uploads/"; +// } + + /** + * 缩略图生成位置 + */ + private String getUploadSmDir() { + return getUploadBaseDir() + "thumbnail/"; + } + + /** + * office转pdf输出位置 + */ + private String getPdfOutDir() { + return getUploadBaseDir() + "pdf/"; + } + + @PreAuthorize("hasAuthority('sys:file:upload')") + @Operation(summary = "添加文件") + @PostMapping() + public ApiResult save(@RequestBody FileRecord fileRecord) { + if (fileRecordService.save(fileRecord)) { + return success("上传成功"); + } + return fail("上传失败"); + } + + @PreAuthorize("hasAuthority('sys:file:update')") + @Operation(summary = "修改文件") + @PutMapping() + public ApiResult update(@RequestBody FileRecord fileRecord) { + if (fileRecordService.updateById(fileRecord)) { + return success("修改成功"); + } + return fail("修改失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/IdVerificationController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/IdVerificationController.java new file mode 100644 index 0000000..d1820d1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/IdVerificationController.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.service.IdVerificationService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 实人认证控制器 + * + * @author WebSoft + * @since 2026-04-13 + */ +@Slf4j +@Tag(name = "实人认证") +@RestController +@RequestMapping("/api/app/id-verification") +public class IdVerificationController extends BaseController { + + @Autowired + private IdVerificationService idVerificationService; + + /** + * 身份证二要素核验 + *

+ * 校验姓名和身份证号是否一致 + * + * @param realName 真实姓名 + * @param idCard 身份证号 + * @return 核验结果 + */ + @Operation(summary = "身份证二要素核验", description = "校验姓名和身份证号是否一致") + @PostMapping("/verify-id-card") + public ApiResult> verifyIdCard( + @Parameter(description = "真实姓名", required = true) + @RequestParam String realName, + @Parameter(description = "身份证号", required = true) + @RequestParam String idCard) { + + log.info("实人认证请求: realName={}, idCard={}", realName, maskIdCard(idCard)); + + try { + boolean isMatch = idVerificationService.verifyIdCard(realName, idCard); + + Map result = new HashMap<>(); + result.put("isMatch", isMatch); + result.put("message", isMatch ? "身份信息一致" : "身份信息不一致"); + + if (isMatch) { + return success(result); + } else { + return fail("身份信息不一致,请核实后重新填写"); + } + + } catch (Exception e) { + log.error("实人认证异常", e); + return fail("核验服务异常,请稍后重试"); + } + } + + /** + * 脱敏身份证号 + */ + private String maskIdCard(String idCard) { + if (idCard == null || idCard.length() < 8) { + return "***"; + } + return idCard.substring(0, 4) + "****" + idCard.substring(idCard.length() - 4); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/LoginRecordController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/LoginRecordController.java new file mode 100644 index 0000000..91175ca --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/LoginRecordController.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.param.LoginRecordParam; +import com.gxwebsoft.common.system.service.LoginRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +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 javax.annotation.Resource; +import java.util.List; + +/** + * 登录日志控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:31 + */ +@Tag(name = "登录日志") +@RestController +@RequestMapping("/api/system/login-record") +public class LoginRecordController extends BaseController { + @Resource + private LoginRecordService loginRecordService; + + @PreAuthorize("hasAuthority('sys:login-record:list')") + @Operation(summary = "分页查询登录日志") + @GetMapping("/page") + public ApiResult> page(LoginRecordParam param) { + return success(loginRecordService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:login-record:list')") + @Operation(summary = "查询全部登录日志") + @GetMapping() + public ApiResult> list(LoginRecordParam param) { + return success(loginRecordService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:login-record:list')") + @Operation(summary = "根据id查询登录日志") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(loginRecordService.getByIdRel(id)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/MainController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/MainController.java new file mode 100644 index 0000000..9eadc79 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/MainController.java @@ -0,0 +1,369 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.CommonRequest; +import com.aliyuncs.CommonResponse; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.google.gson.Gson; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.security.JwtSubject; +import com.gxwebsoft.common.core.security.JwtUtil; +import com.gxwebsoft.common.core.utils.CacheClient; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.ExistenceParam; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.LoginParam; +import com.gxwebsoft.common.system.param.SmsCaptchaParam; +import com.gxwebsoft.common.system.param.UpdatePasswordParam; +import com.gxwebsoft.common.system.result.CaptchaResult; +import com.gxwebsoft.common.system.result.LoginResult; +import com.gxwebsoft.common.system.service.*; +import com.wf.captcha.SpecCaptcha; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +/** + * 登录认证控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:11 + */ +@Tag(name = "登录认证") +@RestController +@RequestMapping("/api") +public class MainController extends BaseController { + @Resource + private ConfigProperties configProperties; + @Resource + private UserService userService; + @Resource + private RoleMenuService roleMenuService; + @Resource + private LoginRecordService loginRecordService; + @Resource + private CacheClient cacheClient; + @Resource + private RedisUtil redisUtil; + + @Operation(summary = "检查用户是否存在") + @GetMapping("/existence") + public ApiResult existence(ExistenceParam param) { + if (param.isExistence(userService, User::getUserId)) { + return success("已存在", param.getValue()); + } + return fail("不存在"); + } + + @Operation(summary = "获取登录用户信息") + @GetMapping("/auth/user") + public ApiResult userInfo() { + final Integer loginUserId = getLoginUserId(); + if(loginUserId != null){ + return success(userService.getByIdRel(getLoginUserId())); + } + return fail("loginUserId不存在",null); + } + + @Operation(summary = "获取登录用户菜单") + @GetMapping("/auth/menu") + public ApiResult> userMenu() { + List

menus = roleMenuService.listMenuByUserId(getLoginUserId(), Menu.TYPE_MENU); + return success(CommonUtil.toTreeData(menus, 0, Menu::getParentId, Menu::getMenuId, Menu::setChildren)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "修改个人信息") + @PutMapping("/auth/user") + public ApiResult updateInfo(@RequestBody User user) { + user.setUserId(getLoginUserId()); + // 不能修改的字段 + user.setUsername(null); + user.setPassword(null); + user.setEmailVerified(null); + user.setOrganizationId(null); + user.setStatus(null); + if (userService.updateById(user)) { + return success(userService.getByIdRel(user.getUserId())); + } + return fail("保存失败", null); + } + + @PreAuthorize("hasAuthority('sys:auth:password')") + @Operation(summary = "修改自己密码") + @PutMapping("/auth/password") + public ApiResult updatePassword(@RequestBody UpdatePasswordParam param) { + if (StrUtil.hasBlank(param.getOldPassword(), param.getPassword())) { + return fail("参数不能为空"); + } + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("未登录"); + } + if (!userService.comparePassword(userService.getById(userId).getPassword(), param.getOldPassword())) { + return fail("原密码输入不正确"); + } + User user = new User(); + user.setUserId(userId); + user.setPassword(userService.encodePassword(param.getPassword())); + if (userService.updateById(user)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "图形验证码") + @GetMapping("/captcha") + public ApiResult captcha() { + SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5); + return success(new CaptchaResult(specCaptcha.toBase64(), specCaptcha.text().toLowerCase())); + } + + @Operation(summary = "企业微信登录链接") + @GetMapping("/wxWorkQrConnect") + public ApiResult wxWorkQrConnect() throws UnsupportedEncodingException { + final JSONObject settingInfo = cacheClient.getSettingInfo("wx-work", 10048); + final String corpId = settingInfo.getString("corpId"); + String encodedReturnUrl = URLEncoder.encode("https://oa.gxwebsoft.com/api/open/wx-work/login","UTF-8"); + String url = "https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=" +corpId+ "&redirect_uri=" +encodedReturnUrl+ "&state=ww_login@gxwebsoft&usertype=admin"; + return success("获取成功",url); + } + + @Operation(summary = "短信验证码") + @PostMapping("/sendSmsCaptcha") + public ApiResult sendSmsCaptcha(@RequestBody SmsCaptchaParam param) { + // 读取短信配置信息 + String string = redisUtil.get("setting:sms:" + getTenantId()); + JSONObject jsonObject = JSONObject.parseObject(string); + String accessKeyId = jsonObject.getString("accessKeyId"); + String accessKeySecret = jsonObject.getString("accessKeySecret"); + String userTemplateId = jsonObject.getString("userTemplateId"); + String sign = jsonObject.getString("sign"); + if(accessKeyId != null){ + DefaultProfile profile = DefaultProfile.getProfile("regionld", accessKeyId, accessKeySecret); + IAcsClient client = new DefaultAcsClient(profile); + CommonRequest request = new CommonRequest(); + request.setSysMethod(MethodType.POST); + request.setSysDomain("dysmsapi.aliyuncs.com"); + request.setSysVersion("2017-05-25"); + request.setSysAction("SendSms"); + request.putQueryParameter("RegionId", "cn-hangzhou"); + request.putQueryParameter("PhoneNumbers", param.getPhone()); + request.putQueryParameter("SignName", sign); + request.putQueryParameter("TemplateCode", userTemplateId); + // 生成短信验证码 + Random randObj = new Random(); + String code = Integer.toString(100000 + randObj.nextInt(900000)); + request.putQueryParameter("TemplateParam", "{\"code\":" + code + "}"); + try { + CommonResponse response = client.getCommonResponse(request); + System.out.println("response = " + response); + String json = response.getData(); + System.out.println("json = " + json); + Gson g = new Gson(); + HashMap result = g.fromJson(json, HashMap.class); + System.out.println("result = " + result); + if("OK".equals(result.get("Message"))) { + System.out.println("======================== = " + result); + cacheClient.set(param.getPhone(),code,5L,TimeUnit.MINUTES); + String key = "code:" + param.getPhone(); + redisUtil.set(key,code,5L,TimeUnit.MINUTES); + return success("发送成功",result.get("Message")); + }else{ + return fail("发送失败"); + } + } catch (ServerException e) { + e.printStackTrace(); + } catch (ClientException e) { + e.printStackTrace(); + } + } + return fail("发送失败"); + } + + @Operation(summary = "重置密码") + @PutMapping("/password") + public ApiResult resetPassword(@RequestBody User user) { + if (user.getPassword() == null) { + return fail("参数不正确"); + } + if (user.getCode() == null) { + return fail("验证码不能为空"); + } + // 短信验证码校验 + String code = cacheClient.get(user.getPhone(), String.class); + if (!StrUtil.equals(code,user.getCode())) { + return fail("验证码不正确"); + } + + user.setUserId(getLoginUserId()); + user.setPassword(userService.encodePassword(user.getPassword())); + if (userService.updateById(user)) { + return success("密码修改成功"); + } else { + return fail("密码修改失败"); + } + } + + @Operation(summary = "短信验证码登录") + @PostMapping("/loginBySms") + public ApiResult loginBySms(@RequestBody LoginParam param, HttpServletRequest request) { + final String phone = param.getPhone(); + final Integer tenantId = param.getTenantId(); + final String code = param.getCode(); + + User user = userService.getByUsername(phone, tenantId); + // 验证码校验 + String key = "code:" + param.getPhone(); + if(!code.equals(redisUtil.get(key))){ + String message = "验证码不正确"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (user == null) { + String message = "账号不存在"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (!user.getStatus().equals(0)) { + String message = "账号被冻结"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId, request); + return fail(message, null); + } + loginRecordService.saveAsync(phone, LoginRecord.TYPE_LOGIN, null, tenantId, request); + + // 设置过期时间 + Long tokenExpireTime = configProperties.getTokenExpireTime(); + final JSONObject register = cacheClient.getSettingInfo("register", tenantId); + if(register != null){ + final String ExpireTime = register.getString("tokenExpireTime"); + if (ExpireTime != null) { + tokenExpireTime = Long.valueOf(ExpireTime); + } + } + + // 签发token + String access_token = JwtUtil.buildToken(new JwtSubject(phone, tenantId), + tokenExpireTime, configProperties.getTokenKey()); + return success("登录成功", new LoginResult(access_token, user)); + } + + @Operation(summary = "用户登录(忽略租户隔离,允许全部用户登录)") + @PostMapping("/login-without-tenant") + public ApiResult loginWithoutTenant(@RequestBody LoginParam param, HttpServletRequest request) { + Long tokenExpireTime = configProperties.getTokenExpireTime(); + String username = param.getUsername(); + + // 忽略租户隔离,直接按用户名/手机号/邮箱查询 + User user = userService.getByUsernameIgnoreTenant(username); + if (user == null) { + String message = "账号不存在"; + loginRecordService.saveAsync(username, LoginRecord.TYPE_ERROR, message, 5, request); + return fail(message, null); + } + if (!user.getStatus().equals(0)) { + String message = "账号被冻结"; + loginRecordService.saveAsync(username, LoginRecord.TYPE_ERROR, message, user.getTenantId(), request); + return fail(message, null); + } + + // 累计错误次数 + String key = "PasswordError:".concat(username).concat(":").concat(user.getTenantId().toString()); + Integer passError = redisUtil.get(key, Integer.class); + passError = passError != null ? passError : 0; + if (passError > 10) { + return fail("密码错误次数过多,请10分钟后重试", null); + } + + if (!userService.comparePassword(user.getPassword(), param.getPassword())) { + String message = "密码错误"; + loginRecordService.saveAsync(username, LoginRecord.TYPE_ERROR, message, user.getTenantId(), request); + redisUtil.set(key, passError + 1, 10L, TimeUnit.MINUTES); + return fail(message, null); + } + redisUtil.delete(key); + + // 登录成功 + loginRecordService.saveAsync(username, LoginRecord.TYPE_LOGIN, null, user.getTenantId(), request); + + // 读取租户自定义 token 过期时间 + final JSONObject register = cacheClient.getSettingInfo("register", user.getTenantId()); + if (register != null) { + final String expireTime = register.getString("tokenExpireTime"); + if (expireTime != null) { + tokenExpireTime = Long.valueOf(expireTime); + } + } + + // 签发 token(使用用户自身的 tenantId) + String access_token = JwtUtil.buildToken(new JwtSubject(username, user.getTenantId()), + tokenExpireTime, configProperties.getTokenKey()); + // 同步 redis + redisUtil.set("access_token:" + user.getUserId(), access_token, tokenExpireTime, TimeUnit.SECONDS); + return success("登录成功", new LoginResult(access_token, user)); + } + + @Operation(summary = "会员注册") + @PostMapping("/register") + public ApiResult register(@RequestBody LoginParam param, HttpServletRequest request) { + final String phone = param.getPhone(); + final Integer tenantId = param.getTenantId(); + final String code = param.getCode(); + + User user = userService.getByUsername(phone, tenantId); + // 验证码校验 + String key = "code:" + param.getPhone(); + if(!code.equals(redisUtil.get(key))){ + String message = "验证码不正确"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (user == null) { + String message = "账号不存在"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId,request); + return fail(message, null); + } + if (!user.getStatus().equals(0)) { + String message = "账号被冻结"; + loginRecordService.saveAsync(phone, LoginRecord.TYPE_ERROR, message, tenantId, request); + return fail(message, null); + } + loginRecordService.saveAsync(phone, LoginRecord.TYPE_LOGIN, null, tenantId, request); + + // 设置过期时间 + Long tokenExpireTime = configProperties.getTokenExpireTime(); + final JSONObject register = cacheClient.getSettingInfo("register", tenantId); + if(register != null){ + final String ExpireTime = register.getString("tokenExpireTime"); + if (ExpireTime != null) { + tokenExpireTime = Long.valueOf(ExpireTime); + } + } + + // 签发token + String access_token = JwtUtil.buildToken(new JwtSubject(phone, tenantId), + tokenExpireTime, configProperties.getTokenKey()); + return success("登录成功", new LoginResult(access_token, user)); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/MenuController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/MenuController.java new file mode 100644 index 0000000..ba11820 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/MenuController.java @@ -0,0 +1,145 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.param.MenuParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.PlugService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 菜单控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:23 + */ +@Tag(name = "菜单管理") +@RestController +@RequestMapping("/api/system/menu") +public class MenuController extends BaseController { + @Resource + private MenuService menuService; + @Resource + private PlugService plugService; + + @PreAuthorize("hasAuthority('sys:menu:list')") + @Operation(summary = "分页查询菜单") + @GetMapping("/page") + public ApiResult> page(MenuParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(menuService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:menu:list')") + @Operation(summary = "查询全部菜单") + @GetMapping() + public ApiResult> list(MenuParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return success(menuService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:menu:list')") + @Operation(summary = "根据id查询菜单") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(menuService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:menu:save')") + @Operation(summary = "添加菜单") + @PostMapping() + public ApiResult add(@RequestBody Menu menu) { + if (menu.getParentId() == null) { + menu.setParentId(0); + } + if (menuService.save(menu)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "修改菜单") + @PutMapping() + public ApiResult update(@RequestBody Menu menu) { + if (menuService.updateById(menu)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:remove')") + @Operation(summary = "删除菜单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (menuService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:save')") + @Operation(summary = "批量添加菜单") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List menus) { + if (menuService.saveBatch(menus)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "批量修改菜单") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(menuService, "menu_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:remove')") + @Operation(summary = "批量删除菜单") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (menuService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "菜单克隆") + @PostMapping("/clone") + public ApiResult onClone(@RequestBody MenuParam param){ + if(menuService.cloneMenu(param)){ + return success("克隆成功,请刷新"); + } + return fail("克隆失败"); + } + + @PreAuthorize("hasAuthority('sys:menu:update')") + @Operation(summary = "安装插件") + @GetMapping("/install/{id}") + public ApiResult install(@PathVariable("id") Integer id){ + if(menuService.install(id)){ + // 更新安装次数 + final Plug plug = plugService.getOne(new LambdaQueryWrapper().eq(Plug::getMenuId, id)); + plug.setInstalls(plug.getInstalls() + 1); + plugService.updateById(plug); + return success("安装成功"); + } + return fail("安装失败",id); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ModulesController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ModulesController.java new file mode 100644 index 0000000..71a1e14 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/ModulesController.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.ModulesService; +import com.gxwebsoft.common.system.entity.Modules; +import com.gxwebsoft.common.system.param.ModulesParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 模块管理控制器 + * + * @author 科技小王子 + * @since 2023-10-18 15:53:43 + */ +@Tag(name = "模块") +@RestController +@RequestMapping("/api/system/modules") +public class ModulesController extends BaseController { + @Resource + private ModulesService modulesService; + + @PreAuthorize("hasAuthority('sys:modules:list')") + @OperationLog + @Operation(summary = "分页查询模块管理") + @GetMapping("/page") + public ApiResult> page(ModulesParam param) { + PageParam page = new PageParam<>(param); +// page.setDefaultOrder("create_time desc"); + return success(modulesService.page(page, page.getWrapper())); + // 使用关联查询 + //return success(modulesService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:modules:list')") + @OperationLog + @Operation(summary = "查询全部模块管理") + @GetMapping() + public ApiResult> list(ModulesParam param) { + PageParam page = new PageParam<>(param); +// page.setDefaultOrder("create_time desc"); + return success(modulesService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(modulesService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:modules:list')") + @OperationLog + @Operation(summary = "根据id查询模块管理") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(modulesService.getById(id)); + // 使用关联查询 + //return success(modulesService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:modules:save')") + @OperationLog + @Operation(summary = "添加模块管理") + @PostMapping() + public ApiResult save(@RequestBody Modules modules) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + modules.setUserId(loginUser.getUserId()); + } + if (modulesService.save(modules)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:modules:update')") + @OperationLog + @Operation(summary = "修改模块管理") + @PutMapping() + public ApiResult update(@RequestBody Modules modules) { + if (modulesService.updateById(modules)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:modules:remove')") + @OperationLog + @Operation(summary = "删除模块管理") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (modulesService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:modules:save')") + @OperationLog + @Operation(summary = "批量添加模块管理") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (modulesService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:modules:update')") + @OperationLog + @Operation(summary = "批量修改模块管理") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(modulesService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:modules:remove')") + @OperationLog + @Operation(summary = "批量删除模块管理") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (modulesService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/NoticeController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/NoticeController.java new file mode 100644 index 0000000..8575dc4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/NoticeController.java @@ -0,0 +1,141 @@ +package com.gxwebsoft.common.system.controller; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Notice; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.NoticeParam; +import com.gxwebsoft.common.system.service.NoticeService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 消息记录表控制器 + * + * @author 科技小王子 + * @since 2023-10-08 13:22:21 + */ +@Tag(name = "通知") +@RestController +@RequestMapping("/api/system/notice") +public class NoticeController extends BaseController { + @Resource + private NoticeService noticeService; + + @PreAuthorize("hasAuthority('sys:notice:list')") + @Operation(summary = "分页查询消息记录表") + @GetMapping("/page") + public ApiResult> page(NoticeParam param) { + // 使用关联查询 + return success(noticeService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:notice:list')") + @Operation(summary = "查询全部消息记录表") + @GetMapping() + public ApiResult> list(NoticeParam param) { + // 使用关联查询 + return success(noticeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:notice:list')") + @Operation(summary = "根据id查询消息记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(noticeService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:notice:save')") + @Operation(summary = "添加消息记录表") + @PostMapping() + public ApiResult save(@RequestBody Notice notice) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + notice.setUserId(loginUser.getUserId()); + } + if (noticeService.save(notice)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:notice:update')") + @Operation(summary = "修改消息记录表") + @PutMapping() + public ApiResult update(@RequestBody Notice notice) { + if (noticeService.updateById(notice)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:notice:remove')") + @Operation(summary = "删除消息记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (noticeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:notice:save')") + @Operation(summary = "批量添加消息记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (noticeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:notice:update')") + @Operation(summary = "批量修改消息记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(noticeService, "notice_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:notice:remove')") + @Operation(summary = "批量删除消息记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (noticeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + @Operation(summary = "统计信息") + @GetMapping("/getUnReadNum") + public ApiResult getUnReadNum(){ + JSONObject json = new JSONObject(); + json.put("notice",noticeService.count(new LambdaQueryWrapper() + .eq(Notice::getUserId, getLoginUserId()) + .eq(Notice::getType,"notice") + .eq(Notice::getStatus,0))); + json.put("letter",noticeService.count(new LambdaQueryWrapper() + .eq(Notice::getUserId, getLoginUserId()) + .eq(Notice::getType,"letter") + .eq(Notice::getStatus,0))); + json.put("todo",noticeService.count(new LambdaQueryWrapper() + .eq(Notice::getUserId, getLoginUserId()) + .eq(Notice::getType,"todo") + .eq(Notice::getStatus,0))); + return success("操作成功",json); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/NotifyByBalancePayController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/NotifyByBalancePayController.java new file mode 100644 index 0000000..d5594ef --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/NotifyByBalancePayController.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.RequestUtil; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 会员特权购买记录表控制器 + * + * @author 科技小王子 + * @since 2023-06-20 18:07:50 + */ +@Tag(name = "支付") +@RestController +@RequestMapping("/api/system/balance-pay") +public class NotifyByBalancePayController extends BaseController { + @Value("${spring.profiles.active}") + String active; + @Resource + private RedisUtil redisUtil; + @Resource + private RequestUtil requestUtil; + @Resource + private ConfigProperties conf; + + @Schema(description = "余额支付通知(未完成)") + @PostMapping("/notify/{tenantId}") + public String wxNotify(@RequestHeader Map header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) { + System.out.println("异步通知*************** = "); + + // 以支付通知回调为例,验签、解密并转换成 Transaction + try { + // 推送微信官方支付结果(携带租户ID的POST请求) +// requestUtil.pushBalancePayNotify(); + return "SUCCESS"; + } catch (Exception $e) { + System.out.println($e.getMessage()); + } + + return "fail"; + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OperationRecordController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OperationRecordController.java new file mode 100644 index 0000000..ec54bc4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OperationRecordController.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.param.OperationRecordParam; +import com.gxwebsoft.common.system.service.OperationRecordService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 操作日志控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:12 + */ +@Tag(name = "操作日志") +@RestController +@RequestMapping("/api/system/operation-record") +public class OperationRecordController extends BaseController { + @Resource + private OperationRecordService operationRecordService; + + /** + * 分页查询操作日志 + */ + @PreAuthorize("hasAuthority('sys:operation-record:list')") + @Operation(summary = "分页查询操作日志") + @GetMapping("/page") + public ApiResult> page(OperationRecordParam param) { + return success(operationRecordService.pageRel(param)); + } + + /** + * 查询全部操作日志 + */ + @PreAuthorize("hasAuthority('sys:operation-record:list')") + @Operation(summary = "查询全部操作日志") + @GetMapping() + public ApiResult> list(OperationRecordParam param) { + return success(operationRecordService.listRel(param)); + } + + /** + * 根据id查询操作日志 + */ + @PreAuthorize("hasAuthority('sys:operation-record:list')") + @Operation(summary = "根据id查询操作日志") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(operationRecordService.getByIdRel(id)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrderController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrderController.java new file mode 100644 index 0000000..3ea9fd9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrderController.java @@ -0,0 +1,270 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Cart; +import com.gxwebsoft.common.system.entity.Order; +import com.gxwebsoft.common.system.entity.OrderGoods; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.mapper.MenuMapper; +import com.gxwebsoft.common.system.param.MenuParam; +import com.gxwebsoft.common.system.param.OrderParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.OrderGoodsService; +import com.gxwebsoft.common.system.service.OrderService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * 订单控制器 + * + * @author 科技小王子 + * @since 2024-10-16 12:32:52 + */ +@Tag(name = "订单管理") +@RestController +@RequestMapping("/api/system/order") +public class OrderController extends BaseController { + @Resource + private OrderService orderService; + @Resource + private OrderGoodsService orderGoodsService; + @Resource + private MenuService menuService; + @Resource + private MenuMapper menuMapper; + + @Operation(summary = "分页查询订单") + @GetMapping("/page") + public ApiResult> page(OrderParam param) { + // 使用关联查询 + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登陆",null); + } + // 非平台权限 + if (!loginUser.getTenantId().equals(5)) { + param.setUserId(loginUser.getUserId()); + } + return success(orderService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:order:list')") + @OperationLog + @Operation(summary = "查询全部订单") + @GetMapping() + public ApiResult> list(OrderParam param) { + final User loginUser = getLoginUser(); + // 非平台权限 + if (!loginUser.getTenantId().equals(5)) { + param.setUserId(loginUser.getUserId()); + } + // 使用关联查询 + return success(orderService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:order:list')") + @OperationLog + @Operation(summary = "根据id查询订单") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(orderService.getByIdRel(id)); + } + + @Operation(summary = "添加订单") + @PostMapping() + public ApiResult save(@RequestBody Order order) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if(loginUser == null){ + return fail("请先登录"); + } + if (ObjectUtil.isEmpty(order.getType())) { + return fail("订单类型不能为空"); + } + // 封装订单信息 + order.setUserId(loginUser.getUserId()); + order.setTenantId(loginUser.getTenantId()); + order.setOrderNo(Long.toString(IdUtil.getSnowflakeNextId())); + order.setPhone(loginUser.getPhone()); + order.setRealName(loginUser.getRealName()); + // 购买商品 + if (order.getType().equals(0)) { + order.setVersion(0); + } + // 购买插件 + if (order.getType().equals(1)) { + order.setVersion(1); + } + + if (orderService.save(order)) { + // 余额支付 + if(order.getPayType().equals(0)){ + if (loginUser.getBalance().compareTo(order.getPayPrice()) < 0) { + return fail("余额不足"+loginUser.getBalance()+"==="+order.getPayPrice()); + } + return success("支付成功"); + } + } + return fail("添加失败"); + } + + @Operation(summary = "修改订单") + @PutMapping() + public ApiResult update(@RequestBody Order order) { + if (orderService.updateById(order)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:order:remove')") + @OperationLog + @Operation(summary = "删除订单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (orderService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:order:save')") + @OperationLog + @Operation(summary = "批量添加订单") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (orderService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:order:update')") + @OperationLog + @Operation(summary = "批量修改订单") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(orderService, "order_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:order:remove')") + @OperationLog + @Operation(summary = "批量删除订单") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (orderService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "统一下单") + @PostMapping("/createOrder") + public ApiResult createOrder(@RequestBody Cart cart) { + final MenuParam menuParam = new MenuParam(); + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + // 封装订单数据 + final Order order = new Order(); + order.setType(cart.getType()); + order.setPayType(cart.getPayType()); + order.setPayPrice(cart.getPayPrice()); + order.setTotalPrice(cart.getTotalPrice()); + order.setMonth(cart.getMonth()); + order.setUserId(loginUser.getUserId()); + order.setOrderNo(Long.toString(IdUtil.getSnowflakeNextId())); + order.setPhone(loginUser.getPhone()); + order.setComments(cart.getComments()); + order.setTenantId(loginUser.getTenantId()); + order.setRealName(loginUser.getRealName()); + order.setPayTime(DateUtil.date()); + + // 购买商品 + if (order.getType().equals(0)) { + order.setVersion(0); + } + // 购买插件 + if (order.getType().equals(1)) { + order.setVersion(1); + } + // 判断支付方式 + if(order.getPayType() == null){ + return fail("支付方式不能为空"); + } + // 商品描述(必填) + if (StrUtil.isBlank(order.getComments())) { + return fail("商品描述(必填)"); + } + // 微信支付 + if(order.getPayType().equals(1)){ + // 微信openid(必填) + if (StrUtil.isBlank(loginUser.getOpenid())) { + return fail("微信openid(必填)"); + } + // 微信支付(商品金额不能为0) + if (order.getTotalPrice().compareTo(BigDecimal.ZERO) == 0) { + return fail("商品金额不能为0"); + } + } + // 创建订单成功 + if (orderService.save(order)) { + final ArrayList orderGoods = new ArrayList<>(); + if (order.getType().equals(1)) { + cart.getList().forEach(item -> { + final OrderGoods og = new OrderGoods(); + og.setOrderId(order.getOrderId()); + og.setType(order.getType()); + og.setItemId(item.getCompanyId()); + og.setMenuId(item.getMenuId()); + og.setPayPrice(item.getPrice()); + og.setMonth(order.getMonth()); + og.setTotalNum(order.getCartNum()); + og.setPayStatus(false); + og.setOrderStatus(0); + og.setTenantId(loginUser.getTenantId()); + og.setUserId(loginUser.getUserId()); + og.setComments(item.getTenantName()); + orderGoods.add(og); + menuParam.setMenuId(item.getMenuId()); + menuParam.setTenantId(item.getTenantId()); + }); + } + // 记录订单商品 + orderGoodsService.saveBatch(orderGoods); + + // 余额支付 + if(order.getPayType().equals(0)){ + if (loginUser.getBalance().compareTo(order.getPayPrice()) < 0) { + return fail("余额不足"+loginUser.getBalance()+"==="+order.getPayPrice()); + } + // 附加插件参数 + order.setMenuParam(menuParam); + // 执行支付成功后事务 + orderService.paySuccess(order); + return success("余额支付成功"); + } + } + } + return fail("下单失败"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrderGoodsController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrderGoodsController.java new file mode 100644 index 0000000..03b7450 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrderGoodsController.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Order; +import com.gxwebsoft.common.system.entity.OrderGoods; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.OrderGoodsParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.OrderGoodsService; +import com.gxwebsoft.common.system.service.OrderService; +import com.gxwebsoft.common.system.service.impl.MenuServiceImpl; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 订单商品控制器 + * + * @author 科技小王子 + * @since 2024-10-26 12:18:05 + */ +@Tag(name = "订单商品管理") +@RestController +@RequestMapping("/api/system/order-goods") +public class OrderGoodsController extends BaseController { + @Resource + private OrderGoodsService orderGoodsService; + @Resource + private OrderService orderService; + @Resource + private MenuService menuService; + @Resource + private MenuServiceImpl menuServiceImpl; + + @Operation(summary = "分页查询订单商品") + @GetMapping("/page") + public ApiResult> page(OrderGoodsParam param) { + // 使用关联查询 + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登陆",null); + } + // 非平台权限 + if (!loginUser.getTenantId().equals(5)) { + param.setUserId(loginUser.getUserId()); + } + return success(orderGoodsService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:order:list')") + @Operation(summary = "查询全部订单商品") + @GetMapping() + public ApiResult> list(OrderGoodsParam param) { + // 使用关联查询 + return success(orderGoodsService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:order:list')") + @Operation(summary = "根据id查询订单商品") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(orderGoodsService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:order:save')") + @Operation(summary = "添加订单商品") + @PostMapping() + public ApiResult save(@RequestBody OrderGoods orderGoods) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + orderGoods.setUserId(loginUser.getUserId()); + } + if (orderGoodsService.save(orderGoods)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:order:update')") + @Operation(summary = "修改订单商品") + @PutMapping() + public ApiResult update(@RequestBody OrderGoods orderGoods) { + if (orderGoodsService.updateById(orderGoods)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "修改订单商品状态") + @PutMapping("/updateOrderStatus") + public ApiResult updateOrderStatus(@RequestBody OrderGoods orderGoods) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + // 复制菜单 + menuServiceImpl.install(orderGoods.getMenuId()); + if (orderGoodsService.updateById(orderGoods)) { + if (orderGoodsService.count(new LambdaQueryWrapper().eq(OrderGoods::getOrderStatus,0).eq(OrderGoods::getOrderId,orderGoods.getOrderId())) == 0) { + orderService.update(new LambdaUpdateWrapper().eq(Order::getOrderId,orderGoods.getOrderId()).set(Order::getOrderStatus,1)); + } + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:order:remove')") + @Operation(summary = "删除订单商品") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (orderGoodsService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:order:save')") + @Operation(summary = "批量添加订单商品") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (orderGoodsService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:order:update')") + @Operation(summary = "批量修改订单商品") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(orderGoodsService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:order:remove')") + @Operation(summary = "批量删除订单商品") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (orderGoodsService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrganizationController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrganizationController.java new file mode 100644 index 0000000..4174b04 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/OrganizationController.java @@ -0,0 +1,130 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.param.OrganizationParam; +import com.gxwebsoft.common.system.service.OrganizationService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 组织机构控制器 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Tag(name = "组织机构管理") +@RestController +@RequestMapping("/api/system/organization") +public class OrganizationController extends BaseController { + @Resource + private OrganizationService organizationService; + + @PreAuthorize("hasAuthority('sys:org:list')") + @Operation(summary = "分页查询组织机构") + @GetMapping("/page") + public ApiResult> page(OrganizationParam param) { + return success(organizationService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:org:list')") + @Operation(summary = "查询全部组织机构") + @GetMapping() + public ApiResult> list(OrganizationParam param) { + return success(organizationService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:org:list')") + @Operation(summary = "根据id查询组织机构") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(organizationService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:org:save')") + @Operation(summary = "添加组织机构") + @PostMapping() + public ApiResult add(@RequestBody Organization organization) { + if (organization.getParentId() == null) { + organization.setParentId(0); + } + if (organizationService.count(new LambdaQueryWrapper() + .eq(Organization::getOrganizationName, organization.getOrganizationName()) + .eq(Organization::getParentId, organization.getParentId())) > 0) { + return fail("机构名称已存在"); + } + if (organizationService.save(organization)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:org:update')") + @Operation(summary = "修改组织机构") + @PutMapping() + public ApiResult update(@RequestBody Organization organization) { + if (organization.getOrganizationName() != null) { + if (organization.getParentId() == null) { + organization.setParentId(0); + } + if (organizationService.count(new LambdaQueryWrapper() + .eq(Organization::getOrganizationName, organization.getOrganizationName()) + .eq(Organization::getParentId, organization.getParentId()) + .ne(Organization::getOrganizationId, organization.getOrganizationId())) > 0) { + return fail("机构名称已存在"); + } + } + if (organizationService.updateById(organization)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:org:remove')") + @Operation(summary = "删除组织机构") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (organizationService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:org:save')") + @Operation(summary = "批量添加组织机构") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List organizationList) { + if (organizationService.saveBatch(organizationList)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:org:update')") + @Operation(summary = "批量修改组织机构") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(organizationService, Organization::getOrganizationId)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:org:remove')") + @Operation(summary = "批量删除组织机构") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (organizationService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/PaymentController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/PaymentController.java new file mode 100644 index 0000000..78d4944 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/PaymentController.java @@ -0,0 +1,266 @@ +package com.gxwebsoft.common.system.controller; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.RequestUtil; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.PaymentParam; +import com.gxwebsoft.common.system.service.PaymentService; +import com.gxwebsoft.common.system.service.UserBalanceLogService; +import com.gxwebsoft.common.system.service.UserService; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction; +import com.wechat.pay.java.service.partnerpayments.model.TransactionAmount; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static com.gxwebsoft.common.core.constants.BalanceConstants.BALANCE_USE; + +/** + * 支付方式控制器 + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +@Slf4j +@Tag(name = "支付") +@RestController +@RequestMapping("/api/system/payment") +public class PaymentController extends BaseController { + @Resource + private PaymentService paymentService; + @Resource + private UserService userService; + @Resource + private UserBalanceLogService userBalanceLogService; + @Resource + private RedisUtil redisUtil; + @Resource + private RequestUtil requestUtil; + @Resource + private PaymentCacheService paymentCacheService; + + @Operation(summary = "余额支付接口") + @PostMapping("/balancePay") + public ApiResult balancePay(@RequestBody ShopOrder order) { + System.out.println("使用余额支付 >>> 订单信息 " + order); + + // 查询购买者信息 + final User buyer = userService.getById(order.getUserId()); + + if (buyer.getBalance().compareTo(order.getPayPrice()) < 0) { + return fail("余额不足"); + } + + // 扣除余额 + final BigDecimal subtract = buyer.getBalance().subtract(order.getTotalPrice()); +// final BigDecimal multiply = subtract.multiply(new BigDecimal(100)); + buyer.setBalance(subtract); + final boolean updateUser = userService.updateUser(buyer); + + // 记录余额明细 + UserBalanceLog userBalanceLog = new UserBalanceLog(); + userBalanceLog.setUserId(buyer.getUserId()); + userBalanceLog.setScene(BALANCE_USE); + userBalanceLog.setMoney(order.getPayPrice()); + BigDecimal balance = buyer.getBalance().add(order.getPayPrice()); + userBalanceLog.setBalance(balance); + userBalanceLog.setComments(order.getMerchantName()); + userBalanceLog.setTransactionId(UUID.randomUUID().toString()); + userBalanceLog.setOrderNo(order.getOrderNo()); + final boolean save = userBalanceLogService.save(userBalanceLog); + System.out.println("save = " + save); + + // 推送微信官方支付结果(携带租户ID的POST请求) + final Transaction transaction = new Transaction(); + transaction.setOutTradeNo(order.getOrderNo()); + transaction.setTransactionId(order.getOrderNo()); + final TransactionAmount amount = new TransactionAmount(); + // 计算金额 + BigDecimal decimal = order.getTotalPrice(); + final BigDecimal multiply = decimal.multiply(new BigDecimal(100)); + // 将 BigDecimal 转换为 Integer + Integer money = multiply.intValue(); + amount.setTotal(money); + amount.setCurrency("CNY"); + transaction.setAmount(amount); + // 获取支付配置信息用于解密 - 使用缓存服务 + Payment payment = paymentCacheService.getWechatPayConfig(order.getTenantId()); + System.out.println("获取到支付配置: " + payment.getMchId()); + requestUtil.pushBalancePayNotify(transaction, payment); + + return success("支付成功",order.getOrderNo()); + } + + @Operation(summary = "选择支付方式") + @GetMapping("/select") + public ApiResult select(PaymentParam param) { + String key = "SelectPayment:".concat(getTenantId().toString()); + final String string = redisUtil.get(key); + final List paymentList = JSONObject.parseArray(string, Payment.class); + if (!CollectionUtils.isEmpty(paymentList)) { + return success(paymentList); + } + // 使用关联查询 + final List list = paymentService.list(new LambdaUpdateWrapper().eq(Payment::getStatus, true)); + if (!CollectionUtils.isEmpty(list)) { + list.forEach(d -> { + d.setApiKey(null); + d.setApiclientCert(null); + d.setApiclientKey(null); + d.setMerchantSerialNumber(null); + }); + } + redisUtil.set(key,list,1L, TimeUnit.DAYS); + return success(list); + } + + @PreAuthorize("hasAuthority('sys:payment:list')") + @Operation(summary = "分页查询支付方式") + @GetMapping("/page") + public ApiResult> page(PaymentParam param) { + // 使用关联查询 + return success(paymentService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:payment:list')") + @Operation(summary = "查询全部支付方式") + @GetMapping() + public ApiResult> list(PaymentParam param) { + // 使用关联查询 + return success(paymentService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:payment:list')") + @Operation(summary = "根据id查询支付方式") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(paymentService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:payment:save')") + @OperationLog + @Operation(summary = "添加支付方式") + @PostMapping() + public ApiResult save(@RequestBody Payment payment) { + if (paymentService.count(new LambdaQueryWrapper().eq(Payment::getCode,payment.getCode())) > 0) { + return fail(payment.getName() + "已存在"); + } + if (paymentService.save(payment)) { + // 使用缓存服务统一管理缓存 + paymentCacheService.cachePaymentConfig(payment, getTenantId()); + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:payment:update')") + @OperationLog + @Operation(summary = "修改支付方式") + @PutMapping() + public ApiResult update(@RequestBody Payment payment) { + if (paymentService.updateById(payment)) { + // 使用缓存服务统一管理缓存 + paymentCacheService.cachePaymentConfig(payment, getTenantId()); + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:payment:remove')") + @OperationLog + @Operation(summary = "删除支付方式") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + final Payment payment = paymentService.getById(id); + System.out.println("payment = " + payment); + + // 使用缓存服务统一管理缓存删除 + paymentCacheService.removePaymentConfig(payment.getCode(), getTenantId()); + if (paymentService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:payment:save')") + @OperationLog + @Operation(summary = "批量添加支付方式") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (paymentService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:payment:update')") + @OperationLog + @Operation(summary = "批量修改支付方式") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(paymentService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:payment:remove')") + @OperationLog + @Operation(summary = "批量删除支付方式") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (paymentService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "查询支付状态") + @GetMapping("/query-status") + public ApiResult queryStatus(@RequestParam String orderNo) { + try { + // 先检查 Redis 缓存(支付成功时会写入) + String paidKey = "wxpay:paid:" + orderNo; + String paid = redisUtil.get(paidKey); + if ("1".equals(paid)) { + Map result = new HashMap<>(); + result.put("paid", true); + result.put("payStatus", 1); + return success(result); + } + + // TODO: 调用微信 API 查询真实支付状态 + // 目前先用 Redis 缓存判断,后期可接入微信查询接口 + Map result = new HashMap<>(); + result.put("paid", false); + result.put("payStatus", 0); + return success(result); + + } catch (Exception e) { + log.error("查询支付状态失败: {}", e.getMessage()); + return fail("查询失败"); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/PlugController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/PlugController.java new file mode 100644 index 0000000..2429e99 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/PlugController.java @@ -0,0 +1,161 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.PlugParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.PlugService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 插件扩展控制器 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Tag(name = "插件扩展管理") +@RestController +@RequestMapping("/api/system/plug") +public class PlugController extends BaseController { + @Resource + private PlugService plugService; + @Resource + private MenuService menuService; + + @PreAuthorize("hasAuthority('sys:plug:list')") + @Operation(summary = "分页查询插件扩展") + @GetMapping("/page") + public ApiResult> page(PlugParam param) { + // 如果不传userId,只显示审核通过的插件 + if (param.getUserId() == null) { + param.setStatus(20); + } + // 使用关联查询 + return success(plugService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:plug:list')") + @Operation(summary = "查询全部插件扩展") + @GetMapping() + public ApiResult> list(PlugParam param) { + // 使用关联查询 + return success(plugService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:plug:list')") + @Operation(summary = "根据id查询插件扩展") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(plugService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:plug:save')") + @Operation(summary = "添加插件扩展") + @PostMapping() + public ApiResult save(@RequestBody Plug plug) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + plug.setUserId(loginUser.getUserId()); + } + if (plugService.save(plug)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:update')") + @Operation(summary = "修改插件扩展") + @PutMapping() + public ApiResult update(@RequestBody Plug plug) { + if (plugService.updateById(plug)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:remove')") + @Operation(summary = "删除插件扩展") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (plugService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:save')") + @Operation(summary = "批量添加插件扩展") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (plugService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:update')") + @Operation(summary = "批量修改插件扩展") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(plugService, "menu_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:remove')") + @Operation(summary = "批量删除插件扩展") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (plugService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:plug:save')") + @Operation(summary = "发布插件") + @PostMapping("/plug") + public ApiResult plug(@RequestBody Plug plug){ + final Integer menuId = plug.getParentId(); + // 查重 + final long count = plugService.count(new LambdaQueryWrapper().eq(Plug::getMenuId, menuId)); + if(count > 0){ + return fail("请勿重复发布"); + } + // 准备数据 + final Menu menu = menuService.getById(menuId); + plug.setUserId(getLoginUserId()); + plug.setMenuId(menuId); + plug.setTenantId(getTenantId()); + plug.setIcon(menu.getIcon()); + plug.setPath(menu.getPath()); + plug.setComponent(menu.getComponent()); + plug.setAuthority(menu.getAuthority()); + plug.setTitle(menu.getTitle()); + plug.setMenuType(menu.getMenuType()); + plug.setMeta(menu.getMeta()); + plug.setParentId(menu.getParentId()); + plug.setHide(menu.getHide()); + plug.setSortNumber(menu.getSortNumber()); + if(plugService.save(plug)){ + return success("发布成功"); + } + return fail("发布失败"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RechargeOrderController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RechargeOrderController.java new file mode 100644 index 0000000..b59c1f7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RechargeOrderController.java @@ -0,0 +1,285 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.IdUtil; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import com.gxwebsoft.common.system.entity.RechargeOrder; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.RechargeOrderParam; +import com.gxwebsoft.common.system.service.RechargeOrderService; +import com.gxwebsoft.common.system.service.UserBalanceLogService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static com.gxwebsoft.common.core.constants.BalanceConstants.BALANCE_ADMIN; + +/** + * 会员充值订单表控制器 + * + * @author 科技小王子 + * @since 2024-07-26 23:18:48 + */ +@Slf4j +@Tag(name = "用户充值订单") +@RestController +@RequestMapping("/api/sys/recharge-order") +public class RechargeOrderController extends BaseController { + @Resource + private RechargeOrderService rechargeOrderService; + @Resource + private UserService userService; + @Resource + private UserBalanceLogService userBalanceLogService; + + @PreAuthorize("hasAuthority('sys:rechargeOrder:save')") + @Operation(summary = "会员充值") + @PostMapping("/recharge") + @Transactional(rollbackFor = {Exception.class}) + public ApiResult recharge(@RequestBody RechargeOrder rechargeOrder) { + // 充值 + User user = userService.getById(rechargeOrder.getUserId()); + BigDecimal balance = user.getBalance().add(rechargeOrder.getPayPrice()); + user.setBalance(balance); + userService.updateById(user); + // 保存充值记录 + rechargeOrder.setOrderNo(Long.toString(IdUtil.getSnowflakeNextId())); + rechargeOrder.setTradeId(Integer.valueOf(CommonUtil.createOrderNo())); + rechargeOrder.setBalance(balance); + if (rechargeOrderService.save(rechargeOrder)) { + // 记录余额明细 + UserBalanceLog userBalanceLog = new UserBalanceLog(); + userBalanceLog.setUserId(rechargeOrder.getUserId()); + userBalanceLog.setScene(BALANCE_ADMIN); + userBalanceLog.setMoney(rechargeOrder.getPayPrice()); + userBalanceLog.setBalance(balance); + userBalanceLog.setTransactionId(UUID.randomUUID().toString()); + userBalanceLog.setComments("操作人:" + getLoginUser().getNickname()); + userBalanceLog.setRemark(rechargeOrder.getComments()); + userBalanceLog.setMerchantCode(rechargeOrder.getMerchantCode()); + userBalanceLogService.save(userBalanceLog); + return success("充值成功", user); + } + return fail("充值失败"); + } + + @PreAuthorize("hasAuthority('sys:rechargeOrder:list')") + @Operation(summary = "分页查询会员充值订单表") + @GetMapping("/page") + public ApiResult> page(RechargeOrderParam param) { + // 使用关联查询 + return success(rechargeOrderService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:rechargeOrder:list')") + @Operation(summary = "查询全部会员充值订单表") + @GetMapping() + public ApiResult> list(RechargeOrderParam param) { + // 使用关联查询 + return success(rechargeOrderService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:rechargeOrder:list')") + @Operation(summary = "根据id查询会员充值订单表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(rechargeOrderService.getByIdRel(id)); + } + + @Operation(summary = "添加会员充值订单表") + @PostMapping() + public ApiResult save(@RequestBody RechargeOrder rechargeOrder) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + rechargeOrder.setUserId(loginUser.getUserId()); + } + if (rechargeOrderService.save(rechargeOrder)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + /** + * 用户自主创建充值订单(待支付) + */ + @Operation(summary = "创建充值订单(用户自助)") + @PostMapping("/create") + public ApiResult createRechargeOrder(@RequestBody Map params) { + // 获取当前登录用户 + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + + // 解析参数 + Object moneyObj = params.get("money"); + Object payPriceObj = params.get("payPrice"); + Object describeObj = params.get("describe"); + + BigDecimal payPrice = null; + if (payPriceObj != null) { + if (payPriceObj instanceof Number) { + payPrice = new BigDecimal(payPriceObj.toString()); + } else { + try { + payPrice = new BigDecimal(payPriceObj.toString()); + } catch (NumberFormatException e) { + return fail("充值金额格式错误"); + } + } + } else if (moneyObj != null) { + // 支持 money 参数(字符串元) + try { + BigDecimal money = new BigDecimal(moneyObj.toString()); + payPrice = money.multiply(new BigDecimal(100)); // 转为分 + } catch (NumberFormatException e) { + return fail("充值金额格式错误"); + } + } + + if (payPrice == null || payPrice.compareTo(BigDecimal.ZERO) <= 0) { + return fail("充值金额不能为空或小于等于0"); + } + + // 生成订单号 + String orderNo = "R" + System.currentTimeMillis() + (int)(Math.random() * 1000); + + // 创建充值订单 + RechargeOrder rechargeOrder = new RechargeOrder(); + rechargeOrder.setOrderNo(orderNo); + rechargeOrder.setUserId(loginUser.getUserId()); + rechargeOrder.setPayPrice(payPrice); + rechargeOrder.setPayStatus(10); // 10=待支付 + rechargeOrder.setComments(describeObj != null ? describeObj.toString() : "余额充值"); + + // 计算赠送金额(根据充值金额) + BigDecimal giftMoney = calculateGiftMoney(payPrice); + rechargeOrder.setGiftMoney(giftMoney); + rechargeOrder.setActualMoney(payPrice.add(giftMoney)); + + // 保存订单 + if (!rechargeOrderService.save(rechargeOrder)) { + return fail("创建充值订单失败"); + } + + log.info("用户 {} 创建充值订单: orderNo={}, payPrice={}, gift={}", + loginUser.getUserId(), orderNo, payPrice, giftMoney); + + Map result = new HashMap<>(); + result.put("orderNo", orderNo); + result.put("payPrice", payPrice); + result.put("giftMoney", giftMoney); + result.put("actualMoney", rechargeOrder.getActualMoney()); + return success(result); + } + + /** + * 根据充值金额计算赠送金额 + */ + private BigDecimal calculateGiftMoney(BigDecimal payPrice) { + // 充值金额阈值(元) + if (payPrice.compareTo(new BigDecimal("10000")) >= 0) { // >= 100元 + return payPrice.multiply(new BigDecimal("0.2")).setScale(0, BigDecimal.ROUND_HALF_UP); // 赠送20% + } else if (payPrice.compareTo(new BigDecimal("5000")) >= 0) { // >= 50元 + return payPrice.multiply(new BigDecimal("0.1")).setScale(0, BigDecimal.ROUND_HALF_UP); // 赠送10% + } else if (payPrice.compareTo(new BigDecimal("3000")) >= 0) { // >= 30元 + return payPrice.multiply(new BigDecimal("0.05")).setScale(0, BigDecimal.ROUND_HALF_UP); // 赠送5% + } + return BigDecimal.ZERO; + } + + @Operation(summary = "修改会员充值订单表") + @PutMapping() + public ApiResult update(@RequestBody RechargeOrder rechargeOrder) { + if (rechargeOrderService.updateById(rechargeOrder)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除会员充值订单表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (rechargeOrderService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:rechargeOrder:save')") + @Operation(summary = "批量充值") + @PostMapping("/batchRecharge") + @Transactional(rollbackFor = {Exception.class}) + public ApiResult batchRecharge(@RequestBody List list) { + String nickname = getLoginUser().getNickname(); + String realName = getLoginUser().getRealName(); + ArrayList users = new ArrayList<>(list.size()); + ArrayList logs = new ArrayList<>(list.size()); + + list.forEach(d -> { + User user = userService.getByIdRel(d.getUserId()); + BigDecimal balance = user.getBalance().add(d.getPayPrice()); + user.setBalance(balance); + users.add(user); + UserBalanceLog userBalanceLog = new UserBalanceLog(); + userBalanceLog.setUserId(d.getUserId()); + userBalanceLog.setScene(BALANCE_ADMIN); + userBalanceLog.setMoney(d.getPayPrice()); + userBalanceLog.setBalance(balance); + userBalanceLog.setComments("操作员:" + realName); + userBalanceLog.setRemark(d.getComments()); + userBalanceLog.setMerchantCode(d.getMerchantCode()); + d.setOperator(realName); + logs.add(userBalanceLog); + }); + + if (rechargeOrderService.saveBatch(list)) { + // 批量充值 + userService.updateBatchById(users); + // 记录余额明细 + userBalanceLogService.saveBatch(logs); + return success("充值成功"); + } + return fail("充值失败"); + } + + @PreAuthorize("hasAuthority('sys:rechargeOrder:update')") + @Operation(summary = "批量修改会员充值订单表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(rechargeOrderService, "order_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:rechargeOrder:remove')") + @Operation(summary = "批量删除会员充值订单表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (rechargeOrderService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RedisUtilController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RedisUtilController.java new file mode 100644 index 0000000..3e1cac5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RedisUtilController.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.utils.CacheClient; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/redis-util") +@Tag(name = "Redis缓存工具接口") +public class RedisUtilController extends BaseController { + private CacheClient cacheClient; + private final StringRedisTemplate redisTemplate; + private static final String SPLIT = ":"; + private static final String PREFIX_ENTITY_LIKE = "focus:user"; + private static final String PREFIX_USER_LIKE = "like:user"; + private static final String PREFIX_FOLLOWEE = "followee"; + private static final String PREFIX_FOLLOWER = "follower"; + + + public RedisUtilController(StringRedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + @Operation(summary = "添加关注") + @PostMapping("/addFocus") + public ApiResult addFocus(@RequestBody User user) { + final Integer userId = user.getUserId(); + redisTemplate.opsForZSet().incrementScore(getFocusKey(userId), userId.toString(), 1); + return success("关注成功"); + } + + /** + * 某个用户的关注数 + * @return like:entity:[entityId] ->set(userId) + */ + public static String getFocusKey(Integer userId) { + return PREFIX_ENTITY_LIKE + SPLIT + userId; + } + + /** + * 某个用户的赞 + * @return like:entity:[entityId] ->set(userId) + */ + public static String getEntityLikeKey(int entityType, int entityId) { + return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId; + } + + /** + * 某个用户的赞 + * @return like:user:[userId] ->int + */ + public static String getUserLikeKey(int userId) { + return PREFIX_USER_LIKE + SPLIT + userId; + } + + /** + * 某个用户关注的实体(键:用户Id,值:实体Id) + * @return followee:[userId:entityType] ->zSet(entityId,now) + */ + public static String getFolloweeKey(int userId, int entityType) { + return PREFIX_FOLLOWEE + SPLIT + userId + SPLIT + entityType; + } + + /** + * 某个实体拥有的粉丝(键:实体Id,值:用户Id) + * @return follower:[entityType:entityId] ->zSet(entityId,now) + */ + public static String getFollowerKey(int entityType, int entityId) { + return PREFIX_FOLLOWER + SPLIT + entityType + SPLIT + entityId; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RoleController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RoleController.java new file mode 100644 index 0000000..eece032 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RoleController.java @@ -0,0 +1,144 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.param.RoleParam; +import com.gxwebsoft.common.system.service.RoleService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 角色控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:02 + */ +@Tag(name = "角色管理") +@RestController +@RequestMapping("/api/system/role") +public class RoleController extends BaseController { + @Resource + private RoleService roleService; + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "分页查询角色") + @GetMapping("/page") + public ApiResult> page(RoleParam param) { + PageParam page = new PageParam<>(param); + return success(roleService.page(page, page.getWrapper())); + } + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "查询全部角色") + @GetMapping() + public ApiResult> list(RoleParam param) { + PageParam page = new PageParam<>(param); + return success(roleService.list(page.getOrderWrapper())); + } + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "根据id查询角色") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(roleService.getById(id)); + } + + @PreAuthorize("hasAuthority('sys:role:save')") + @Operation(summary = "添加角色") + @PostMapping() + public ApiResult save(@RequestBody Role role) { + if (roleService.count(new LambdaQueryWrapper().eq(Role::getRoleCode, role.getRoleCode())) > 0) { + return fail("角色标识已存在"); + } + if (roleService.count(new LambdaQueryWrapper().eq(Role::getRoleName, role.getRoleName())) > 0) { + return fail("角色名称已存在"); + } + if (roleService.save(role)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "修改角色") + @PutMapping() + public ApiResult update(@RequestBody Role role) { + if (role.getRoleCode() != null && roleService.count(new LambdaQueryWrapper() + .eq(Role::getRoleCode, role.getRoleCode()) + .ne(Role::getRoleId, role.getRoleId())) > 0) { + return fail("角色标识已存在"); + } + if (role.getRoleName() != null && roleService.count(new LambdaQueryWrapper() + .eq(Role::getRoleName, role.getRoleName()) + .ne(Role::getRoleId, role.getRoleId())) > 0) { + return fail("角色名称已存在"); + } + if (roleService.updateById(role)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:role:remove')") + @Operation(summary = "删除角色") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (roleService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:role:save')") + @Operation(summary = "批量添加角色") + @PostMapping("/batch") + public ApiResult> saveBatch(@RequestBody List list) { + // 校验是否重复 + if (CommonUtil.checkRepeat(list, Role::getRoleName)) { + return fail("角色名称存在重复", null); + } + if (CommonUtil.checkRepeat(list, Role::getRoleCode)) { + return fail("角色标识存在重复", null); + } + // 校验是否存在 + List codeExists = roleService.list(new LambdaQueryWrapper().in(Role::getRoleCode, + list.stream().map(Role::getRoleCode).collect(Collectors.toList()))); + if (codeExists.size() > 0) { + return fail("角色标识已存在", codeExists.stream().map(Role::getRoleCode) + .collect(Collectors.toList())).setCode(2); + } + List nameExists = roleService.list(new LambdaQueryWrapper().in(Role::getRoleName, + list.stream().map(Role::getRoleCode).collect(Collectors.toList()))); + if (nameExists.size() > 0) { + return fail("角色标识已存在", nameExists.stream().map(Role::getRoleCode) + .collect(Collectors.toList())).setCode(3); + } + if (roleService.saveBatch(list)) { + return success("添加成功", null); + } + return fail("添加失败", null); + } + + @PreAuthorize("hasAuthority('sys:role:remove')") + @Operation(summary = "批量删除角色") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (roleService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RoleMenuController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RoleMenuController.java new file mode 100644 index 0000000..fdc186a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/RoleMenuController.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/** + * 角色菜单控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:01 + */ +@Tag(name = "角色菜单管理") +@RestController +@RequestMapping("/api/system/role-menu") +public class RoleMenuController extends BaseController { + @Resource + private RoleMenuService roleMenuService; + @Resource + private MenuService menuService; + + @PreAuthorize("hasAuthority('sys:role:list')") + @Operation(summary = "查询角色菜单") + @GetMapping("/{id}") + public ApiResult> list(@PathVariable("id") Integer roleId) { + List menus = menuService.list(new LambdaQueryWrapper().orderByAsc(Menu::getSortNumber)); + List roleMenus = roleMenuService.list(new LambdaQueryWrapper() + .eq(RoleMenu::getRoleId, roleId)); + for (Menu menu : menus) { + menu.setChecked(roleMenus.stream().anyMatch((d) -> d.getMenuId().equals(menu.getMenuId()))); + } + return success(menus); + } + + @Transactional(rollbackFor = {Exception.class}) + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "修改角色菜单") + @PutMapping("/{id}") + public ApiResult update(@PathVariable("id") Integer roleId, @RequestBody List menuIds) { + roleMenuService.remove(new LambdaUpdateWrapper().eq(RoleMenu::getRoleId, roleId)); + if (menuIds != null && menuIds.size() > 0) { + List roleMenuList = new ArrayList<>(); + for (Integer menuId : menuIds) { + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenuList.add(roleMenu); + } + if (!roleMenuService.saveBatch(roleMenuList)) { + throw new BusinessException("保存失败"); + } + } + return success("保存成功"); + } + + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "添加角色菜单") + @PostMapping("/{id}") + public ApiResult addRoleAuth(@PathVariable("id") Integer roleId, @RequestBody Integer menuId) { + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + if (roleMenuService.save(roleMenu)) { + return success(); + } + return fail(); + } + + @PreAuthorize("hasAuthority('sys:role:update')") + @Operation(summary = "移除角色菜单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer roleId, @RequestBody Integer menuId) { + if (roleMenuService.remove(new LambdaUpdateWrapper() + .eq(RoleMenu::getRoleId, roleId).eq(RoleMenu::getMenuId, menuId))) { + return success(); + } + return fail(); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/SettingController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/SettingController.java new file mode 100644 index 0000000..e304d41 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/SettingController.java @@ -0,0 +1,210 @@ +package com.gxwebsoft.common.system.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.SettingParam; +import com.gxwebsoft.common.system.service.SettingService; +import com.gxwebsoft.common.system.service.TenantService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 系统设置控制器 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Tag(name = "系统设置管理") +@RestController +@RequestMapping("/api/system/setting") +public class SettingController extends BaseController { + @Resource + private SettingService settingService; + @Resource + private TenantService tenantService; + @Resource + private RedisUtil redisUtil; + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "分页查询系统设置") + @GetMapping("/page") + public ApiResult> page(SettingParam param) { + // 使用关联查询 + return success(settingService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "查询全部系统设置") + @GetMapping() + public ApiResult> list(SettingParam param) { + // 使用关联查询 + return success(settingService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "根据id查询系统设置") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(settingService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "添加系统设置") + @PostMapping() + public ApiResult save(@RequestBody Setting setting) { + if (settingService.save(setting)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "修改系统设置") + @PutMapping() + public ApiResult update(@RequestBody Setting setting) { + if (settingService.updateById(setting)) { + // 更新系统设置信息到缓存 + String key = "setting:" + setting.getSettingKey() + ":" + getTenantId(); + System.out.println("key = " + key); + redisUtil.set(key, JSON.parseObject(setting.getContent())); + // 创建微信支付Bean +// settingService.initConfig(setting); + // 更新租户信息 + if (setting.getSettingKey().equals("setting")) { + System.out.println("修改系统设置 = " + setting.getContent()); + final String content = setting.getContent(); + final JSONObject jsonObject = JSONObject.parseObject(content); + final String siteName = jsonObject.getString("siteName"); + final String logo = jsonObject.getString("logo"); + System.out.println("siteName = " + siteName); + final Tenant tenant = new Tenant(); + tenant.setTenantName(siteName); + tenant.setTenantId(getTenantId()); + tenant.setLogo(logo); + tenantService.updateById(tenant); + } + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:remove')") + @Operation(summary = "删除系统设置") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (settingService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "批量添加系统设置") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (settingService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:update')") + @Operation(summary = "批量修改系统设置") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(settingService, "setting_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:remove')") + @Operation(summary = "批量删除系统设置") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (settingService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:setting:data')") + @Operation(summary = "查询租户设置信息") + @GetMapping("/data") + public ApiResult data() { + return success(settingService.getData("setting")); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "更新主题皮肤") + @PutMapping("/theme") + public ApiResult theme(@RequestBody Setting setting) { + String key = "theme:".concat(getTenantId().toString()); + // 新增 + final Setting one = settingService.getOne(new LambdaQueryWrapper().eq(Setting::getSettingKey, setting.getSettingKey())); + if(one == null){ + settingService.save(setting); + redisUtil.set(key,setting.getContent()); + return success("保存成功"); + } + // 更新 + final Setting update = settingService.getOne(new LambdaQueryWrapper().eq(Setting::getSettingKey, setting.getSettingKey())); + update.setContent(setting.getContent()); + if (settingService.updateById(update)) { + redisUtil.set(key,setting.getContent()); + return success("更新成功"); + } + return fail("更新失败"); + } + + @Operation(summary = "更新主题皮肤") + @GetMapping("/getTheme") + public ApiResult getTheme() { + String key = "theme:".concat(getTenantId().toString()); + return success("获取成功",redisUtil.get(key)); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "根据key查询设置") + @GetMapping("/getByKey/{key}") + public ApiResult getByKey(@PathVariable("key") String key) { + Setting setting = settingService.getData(key); + return success(setting); + } + + @PreAuthorize("hasAuthority('sys:setting:save')") + @Operation(summary = "根据key更新设置") + @PutMapping("/updateByKey") + public ApiResult updateByKey(@RequestBody Setting setting) { + Setting existSetting = settingService.getData(setting.getSettingKey()); + if (existSetting == null) { + // 不存在则新增 + setting.setTenantId(getTenantId()); + if (settingService.save(setting)) { + return success("添加成功"); + } + return fail("添加失败"); + } else { + // 存在则更新 + existSetting.setContent(setting.getContent()); + existSetting.setSortNumber(setting.getSortNumber()); + existSetting.setComments(setting.getComments()); + if (settingService.updateById(existSetting)) { + return success("修改成功"); + } + return fail("修改失败"); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/SysFileTypeController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/SysFileTypeController.java new file mode 100644 index 0000000..d84ab2b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/SysFileTypeController.java @@ -0,0 +1,122 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.SysFileType; +import com.gxwebsoft.common.system.param.SysFileTypeParam; +import com.gxwebsoft.common.system.service.SysFileTypeService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 存储类型控制器 + * + * @author 科技小王子 + * @since 2025-05-16 14:24:28 + */ +@Tag(name = "存储类型管理") +@RestController +@RequestMapping("/api/system/sys-file-type") +public class SysFileTypeController extends BaseController { + @Resource + private SysFileTypeService sysFileTypeService; + + @PreAuthorize("hasAuthority('sys:sysFileType:list')") + @Operation(summary = "分页查询存储类型") + @GetMapping("/page") + public ApiResult> page(SysFileTypeParam param) { + // 使用关联查询 + return success(sysFileTypeService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:list')") + @Operation(summary = "查询全部存储类型") + @GetMapping() + public ApiResult> list(SysFileTypeParam param) { + // 使用关联查询 + return success(sysFileTypeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:list')") + @Operation(summary = "根据id查询存储类型") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(sysFileTypeService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:save')") + @OperationLog + @Operation(summary = "添加存储类型") + @PostMapping() + public ApiResult save(@RequestBody SysFileType sysFileType) { + if (sysFileTypeService.save(sysFileType)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:update')") + @OperationLog + @Operation(summary = "修改存储类型") + @PutMapping() + public ApiResult update(@RequestBody SysFileType sysFileType) { + if (sysFileTypeService.updateById(sysFileType)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:remove')") + @OperationLog + @Operation(summary = "删除存储类型") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (sysFileTypeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:save')") + @OperationLog + @Operation(summary = "批量添加存储类型") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (sysFileTypeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:update')") + @OperationLog + @Operation(summary = "批量修改存储类型") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(sysFileTypeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:sysFileType:remove')") + @OperationLog + @Operation(summary = "批量删除存储类型") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (sysFileTypeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantController.java new file mode 100644 index 0000000..434a6a8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantController.java @@ -0,0 +1,168 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import com.gxwebsoft.common.system.service.TenantService; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.TenantParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 租户控制器 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Tag(name = "租户管理") +@RestController +@RequestMapping("/api/system/tenant") +public class TenantController extends BaseController { + @Resource + private TenantService tenantService; + @Resource + private MenuService menuService; + @Resource + private RoleMenuService roleMenuService; + + @PreAuthorize("hasAuthority('sys:tenant:list')") + @Operation(summary = "分页查询租户") + @GetMapping("/page") + public ApiResult> page(TenantParam param) { + // 使用关联查询 + return success(tenantService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:tenant:list')") + @Operation(summary = "查询全部租户") + @GetMapping() + public ApiResult> list(TenantParam param) { + // 使用关联查询 + return success(tenantService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:tenant:list')") + @Operation(summary = "根据id查询租户") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(tenantService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:tenant:save')") + @Operation(summary = "添加租户") + @PostMapping() + public ApiResult save(@RequestBody Tenant tenant) { + System.out.println("tenant = " + tenant); + if (tenantService.save(tenant)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:update')") + @Operation(summary = "修改租户") + @PutMapping() + public ApiResult update(@RequestBody Tenant tenant) { + if (tenantService.updateById(tenant)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:remove')") + @Operation(summary = "删除租户") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (tenantService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:update')") + @Operation(summary = "转移租户所有权") + @PutMapping("/transfer/{tenantId}/{newUserId}") + public ApiResult transferOwner(@PathVariable Integer tenantId, @PathVariable Integer newUserId) { + if (tenantService.transferOwner(tenantId, newUserId)) { + return success("转移成功"); + } + return fail("转移失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:save')") + @Operation(summary = "批量添加租户") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (tenantService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:update')") + @Operation(summary = "批量修改租户") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(tenantService, "tenant_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:tenant:remove')") + @Operation(summary = "批量删除租户") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (tenantService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "租户角色权限初始化") + @GetMapping("/role-menu/{id}") + public ApiResult> initialization(@PathVariable("id") Integer roleId) { + List menus = menuService.list(new LambdaQueryWrapper().orderByAsc(Menu::getSortNumber)); + List roleMenus = roleMenuService.list(new LambdaQueryWrapper() + .eq(RoleMenu::getRoleId, roleId)); + for (Menu menu : menus) { + menu.setChecked(roleMenus.stream().anyMatch((d) -> d.getMenuId().equals(menu.getMenuId()))); + } + List menuIds = menus.stream().map(Menu::getMenuId).collect(Collectors.toList()); + roleMenuService.remove(new LambdaUpdateWrapper().eq(RoleMenu::getRoleId, roleId)); + if (menuIds.size() > 0) { + List roleMenuList = new ArrayList<>(); + for (Integer menuId : menuIds) { + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenuList.add(roleMenu); + } + if (!roleMenuService.saveBatch(roleMenuList)) { + throw new BusinessException("保存失败"); + } + } + return success(menus); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantPackageController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantPackageController.java new file mode 100644 index 0000000..96a4bc8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantPackageController.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.TenantPackage; +import com.gxwebsoft.common.system.service.TenantPackageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 租户套餐控制器 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Tag(name = "租户套餐管理") +@RestController +@RequestMapping("/api/system/package") +public class TenantPackageController extends BaseController { + + @Resource + private TenantPackageService tenantPackageService; + + @Operation(summary = "查询所有上架套餐") + @GetMapping("/list") + public ApiResult> list() { + List packages = tenantPackageService.listAvailablePackages(); + return success(packages); + } + + @Operation(summary = "根据ID查询套餐详情") + @GetMapping("/{id}") + public ApiResult getById(@PathVariable("id") Integer id) { + TenantPackage tenantPackage = tenantPackageService.getById(id); + if (tenantPackage == null) { + return fail("套餐不存在", null); + } + return success(tenantPackage); + } + + @Operation(summary = "根据版本号查询套餐") + @GetMapping("/version/{version}") + public ApiResult getByVersion(@PathVariable("version") Integer version) { + TenantPackage tenantPackage = tenantPackageService.getByVersion(version); + if (tenantPackage == null) { + return fail("套餐不存在", null); + } + return success(tenantPackage); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantSubscriptionController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantSubscriptionController.java new file mode 100644 index 0000000..c2fe60d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantSubscriptionController.java @@ -0,0 +1,183 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.TenantSubscription; +import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder; +import com.gxwebsoft.common.system.service.TenantSubscriptionOrderService; +import com.gxwebsoft.common.system.service.TenantSubscriptionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * 租户订阅控制器 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Tag(name = "租户订阅管理") +@RestController +@RequestMapping("/api/system/subscription") +public class TenantSubscriptionController extends BaseController { + + @Resource + private TenantSubscriptionService tenantSubscriptionService; + + @Resource + private TenantSubscriptionOrderService tenantSubscriptionOrderService; + + @Operation(summary = "查询当前租户订阅信息") + @GetMapping("/current") + public ApiResult getCurrentSubscription() { + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户ID不存在", null); + } + TenantSubscription subscription = tenantSubscriptionService.getByTenantId(tenantId); + return success(subscription); + } + + @Operation(summary = "检查订阅是否有效") + @GetMapping("/check") + public ApiResult> checkSubscription() { + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户ID不存在", null); + } + + boolean isValid = tenantSubscriptionService.isSubscriptionValid(tenantId); + boolean isExpired = tenantSubscriptionService.isSubscriptionExpired(tenantId); + + Map result = new HashMap<>(); + result.put("isValid", isValid); + result.put("isExpired", isExpired); + + return success(result); + } + + @Operation(summary = "查询订阅激活状态") + @GetMapping("/active") + public ApiResult> getActiveStatus() { + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户ID不存在", null); + } + + TenantSubscription subscription = tenantSubscriptionService.getByTenantId(tenantId); + Map result = new HashMap<>(); + + if (subscription == null) { + result.put("active", false); + result.put("message", "未订阅任何套餐"); + } else { + boolean isActive = subscription.getStatus() == 1 && subscription.getIsExpired() == 0; + result.put("active", isActive); + result.put("version", subscription.getVersion()); + result.put("packageId", subscription.getPackageId()); + result.put("endTime", subscription.getEndTime()); + result.put("isTrial", subscription.getIsTrial()); + } + + return success(result); + } + + @Operation(summary = "创建试用订单") + @PostMapping("/trial") + public ApiResult createTrialOrder() { + Integer tenantId = getTenantId(); + Integer userId = getLoginUserId(); + + if (tenantId == null || userId == null) { + return fail("参数错误", null); + } + + TenantSubscriptionOrder order = tenantSubscriptionOrderService.createTrialOrder(tenantId, userId); + return success("试用开通成功", order); + } + + @Operation(summary = "创建订阅订单") + @PostMapping("/order") + public ApiResult createOrder(@RequestParam Integer packageId, + @RequestParam Integer payType) { + Integer tenantId = getTenantId(); + Integer userId = getLoginUserId(); + + if (tenantId == null || userId == null) { + return fail("参数错误", null); + } + + TenantSubscriptionOrder order = tenantSubscriptionOrderService.createOrder(packageId, payType, tenantId, userId); + return success("订单创建成功", order); + } + + @Operation(summary = "查询订单列表") + @GetMapping("/orders") + public ApiResult> listOrders(@RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer limit) { + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户ID不存在", null); + } + + PageResult result = tenantSubscriptionOrderService.pageByTenant(tenantId, page, limit); + return success(result); + } + + @Operation(summary = "根据订单号查询订单") + @GetMapping("/order/{orderNo}") + public ApiResult getOrderByNo(@PathVariable String orderNo) { + TenantSubscriptionOrder order = tenantSubscriptionOrderService.getByOrderNo(orderNo); + if (order == null) { + return fail("订单不存在", null); + } + return success(order); + } + + @Operation(summary = "取消订单") + @PostMapping("/order/cancel") + public ApiResult cancelOrder(@RequestParam String orderNo, + @RequestParam(required = false) String cancelReason) { + boolean success = tenantSubscriptionOrderService.cancelOrder(orderNo, cancelReason); + if (success) { + return success("订单已取消"); + } + return fail("取消失败", null); + } + + @Operation(summary = "设置自动续费") + @PostMapping("/auto-renewal") + public ApiResult setAutoRenewal(@RequestParam Integer autoRenewal, + @RequestParam(required = false) Integer renewalPackageId) { + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户ID不存在", null); + } + + boolean success = tenantSubscriptionService.setAutoRenewal(tenantId, autoRenewal, renewalPackageId); + if (success) { + return success(autoRenewal == 1 ? "自动续费已开启" : "自动续费已关闭"); + } + return fail("设置失败", null); + } + + @Operation(summary = "升级套餐") + @PostMapping("/upgrade") + public ApiResult upgradeSubscription(@RequestParam Integer newPackageId) { + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户ID不存在", null); + } + + boolean success = tenantSubscriptionService.upgradeSubscription(tenantId, newPackageId); + if (success) { + return success("升级成功"); + } + return fail("升级失败", null); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantSubscriptionOrderController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantSubscriptionOrderController.java new file mode 100644 index 0000000..11ab86c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/TenantSubscriptionOrderController.java @@ -0,0 +1,288 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Order; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.SubscriptionOrderParam; +import com.gxwebsoft.common.system.result.SubscriptionOrderCreateResult; +import com.gxwebsoft.common.system.result.SubscriptionOrderPayResult; +import com.gxwebsoft.common.system.result.SubscriptionPriceResult; +import com.gxwebsoft.common.system.service.SettingService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +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 javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Arrays; +import java.util.List; + +/** + * 订阅订单接口 + */ +@Tag(name = "订阅订单") +@RestController +@RequestMapping("/api/system/subscription-order") +public class TenantSubscriptionOrderController extends BaseController { + + @Resource + private SettingService settingService; + @Resource + private WxNativePayController wxNativePayController; + + @Operation(summary = "计算订阅订单价格") + @PostMapping("/calculate-price") + public ApiResult calculatePrice(@RequestBody SubscriptionOrderParam param) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + if (param.getPackageId() == null) { + return fail("套餐ID不能为空", null); + } + + JSONObject config = loadSubscriptionConfig(); + final SubscriptionPriceResult result = buildPriceResult(param, config); + return success(result); + } + + @Operation(summary = "创建订阅订单") + @PostMapping("/create") + public ApiResult create(@RequestBody SubscriptionOrderParam param) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + if (param.getPackageId() == null) { + return fail("套餐ID不能为空", null); + } + + JSONObject config = loadSubscriptionConfig(); + final SubscriptionPriceResult price = buildPriceResult(param, config); + + SubscriptionOrderCreateResult result = new SubscriptionOrderCreateResult(); + result.setOrderNo(IdUtil.getSnowflakeNextIdStr()); + result.setPrice(price); + return success(result); + } + + @Operation(summary = "订阅订单支付(生成微信Native二维码)") + @PostMapping("/pay") + public ApiResult pay(@RequestBody SubscriptionOrderParam param) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + if (param.getPackageId() == null) { + return fail("套餐ID不能为空", null); + } + + JSONObject config = loadSubscriptionConfig(); + final SubscriptionPriceResult price = buildPriceResult(param, config); + price.setPayPrice(new BigDecimal("0.01")); + if (price.getPayPrice() == null || price.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) { + return fail("支付金额必须大于0", null); + } + + // 构造订单用于生成支付二维码 + Order order = new Order(); + order.setPayPrice(price.getPayPrice()); + order.setTotalPrice(price.getTotalPrice()); + order.setComments("订阅套餐-" + param.getPackageId()); + order.setPayType(param.getPayType()); + order.setUserId(loginUser.getUserId()); + order.setTenantId(loginUser.getTenantId()); + + ApiResult payResp = wxNativePayController.getCodeUrl(order); + if (payResp.getCode() == null || !payResp.getCode().equals(Constants.RESULT_OK_CODE)) { + return fail(payResp.getMessage(), null); + } + + SubscriptionOrderPayResult result = new SubscriptionOrderPayResult(); + result.setOrderNo(order.getOrderNo()); + result.setCodeUrl(String.valueOf(payResp.getData())); + result.setPrice(price); + return success(result); + } + + /** + * 从配置表读取订阅套餐配置(尝试多种key以兼容历史数据) + */ + private JSONObject loadSubscriptionConfig() { + final List keys = Arrays.asList("subscription", "subscription-package", "subscriptionOrder"); + for (String key : keys) { + try { + JSONObject cfg = settingService.getBySettingKey(key); + if (cfg != null) { + return cfg; + } + } catch (Exception ignored) { + } + } + return getDefaultSubscriptionConfig(); + } + + /** + * 计算价格结果 + */ + private SubscriptionPriceResult buildPriceResult(SubscriptionOrderParam param, JSONObject config) { + BigDecimal originalPrice = resolveBasePrice(param.getPackageId(), config); + BigDecimal factor = BigDecimal.ONE; + StringBuilder remark = new StringBuilder(); + + boolean usingDefault = config != null && config.getBooleanValue("defaultConfig"); + if (usingDefault) { + remark.append("订阅价格未配置,已使用默认配置;"); + } else if (config == null || config.isEmpty()) { + remark.append("未查询到订阅价格配置,已按0元试算;"); + } + if (originalPrice.compareTo(BigDecimal.ZERO) == 0 && config != null && !config.isEmpty()) { + remark.append("未找到套餐价格,已按0元试算;"); + } + + if (isTrue(param.getIsRenewal())) { + BigDecimal renewalFactor = resolveFactor(config, "renewalDiscount"); + factor = factor.multiply(renewalFactor); + remark.append("续费系数:").append(renewalFactor).append(";"); + } + + if (isTrue(param.getIsUpgrade())) { + BigDecimal upgradeFactor = resolveFactor(config, "upgradeDiscount"); + factor = factor.multiply(upgradeFactor); + remark.append("升级系数:").append(upgradeFactor).append(";"); + } + + BigDecimal payTypeFactor = resolvePayTypeFactor(config, param.getPayType()); + factor = factor.multiply(payTypeFactor); + if (param.getPayType() != null) { + remark.append("支付系数:").append(payTypeFactor).append(";"); + } + + BigDecimal payPrice = originalPrice.multiply(factor).setScale(2, RoundingMode.HALF_UP); + BigDecimal discount = originalPrice.subtract(payPrice); + if (discount.compareTo(BigDecimal.ZERO) < 0) { + discount = BigDecimal.ZERO; + } + + SubscriptionPriceResult result = new SubscriptionPriceResult(); + result.setPackageId(param.getPackageId()); + result.setIsRenewal(param.getIsRenewal()); + result.setIsUpgrade(param.getIsUpgrade()); + result.setPayType(param.getPayType()); + result.setOriginalPrice(originalPrice.setScale(2, RoundingMode.HALF_UP)); + result.setTotalPrice(originalPrice.setScale(2, RoundingMode.HALF_UP)); + result.setPayPrice(payPrice); + result.setDiscountAmount(discount.setScale(2, RoundingMode.HALF_UP)); + result.setRemark(remark.toString()); + return result; + } + + private boolean isTrue(Integer value) { + return value != null && value.equals(1); + } + + /** + * 解析套餐价格,支持 packages 数组、priceMap 或单价配置 + */ + private BigDecimal resolveBasePrice(Integer packageId, JSONObject config) { + if (config != null) { + JSONArray packages = config.getJSONArray("packages"); + if (packages != null) { + for (Object item : packages) { + if (item instanceof JSONObject) { + JSONObject pkg = (JSONObject) item; + Integer id = pkg.getInteger("id"); + if (id == null) { + id = pkg.getInteger("packageId"); + } + if (packageId.equals(id)) { + BigDecimal price = pkg.getBigDecimal("price"); + if (price != null) { + return price; + } + } + } + } + } + + JSONObject priceMap = config.getJSONObject("priceMap"); + if (priceMap != null) { + BigDecimal price = priceMap.getBigDecimal(packageId.toString()); + if (price != null) { + return price; + } + } + + BigDecimal fallbackPrice = config.getBigDecimal("price"); + if (fallbackPrice != null) { + return fallbackPrice; + } + } + return BigDecimal.ZERO; + } + + /** + * 获取折扣系数,默认 1 + */ + private BigDecimal resolveFactor(JSONObject config, String key) { + if (config != null) { + BigDecimal factor = config.getBigDecimal(key); + if (factor != null) { + return factor; + } + } + return BigDecimal.ONE; + } + + /** + * 支付方式系数,可在配置中通过 payTypeDiscount 或 payTypeAdjustments 定义 + */ + private BigDecimal resolvePayTypeFactor(JSONObject config, Integer payType) { + if (config != null && payType != null) { + JSONObject payTypeDiscount = config.getJSONObject("payTypeDiscount"); + if (payTypeDiscount == null) { + payTypeDiscount = config.getJSONObject("payTypeAdjustments"); + } + if (payTypeDiscount != null) { + BigDecimal factor = payTypeDiscount.getBigDecimal(payType.toString()); + if (factor != null) { + return factor; + } + } + } + return BigDecimal.ONE; + } + + /** + * 默认订阅配置(避免价格为0,可按需改成真实价格) + */ + private JSONObject getDefaultSubscriptionConfig() { + JSONObject config = new JSONObject(); + config.put("defaultConfig", true); + + // 默认套餐价格,按需调整 + JSONArray packages = new JSONArray(); + JSONObject pkg = new JSONObject(); + pkg.put("id", 2); + pkg.put("price", new BigDecimal("1.00")); + packages.add(pkg); + config.put("packages", packages); + + // 默认系数 + config.put("renewalDiscount", BigDecimal.ONE); + config.put("upgradeDiscount", BigDecimal.ONE); + JSONObject payTypeDiscount = new JSONObject(); + payTypeDiscount.put("12", BigDecimal.ONE); + config.put("payTypeDiscount", payTypeDiscount); + return config; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserBalanceLogController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserBalanceLogController.java new file mode 100644 index 0000000..97990a3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserBalanceLogController.java @@ -0,0 +1,132 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; +import com.gxwebsoft.common.system.service.UserBalanceLogService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户余额变动明细表控制器 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +@Tag(name = "用户余额明细") +@RestController +@RequestMapping("/api/sys/user-balance-log") +public class UserBalanceLogController extends BaseController { + @Resource + private UserBalanceLogService userBalanceLogService; + + @PreAuthorize("hasAuthority('sys:userBalanceLog:list')") + @OperationLog + @Operation(summary = "分页查询用户余额变动明细表") + @GetMapping("/page") + public ApiResult> page(UserBalanceLogParam param) { + // 使用关联查询 + return success(userBalanceLogService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:list')") + @OperationLog + @Operation(summary = "查询全部用户余额变动明细表") + @GetMapping() + public ApiResult> list(UserBalanceLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(userBalanceLogService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(userBalanceLogService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:list')") + @OperationLog + @Operation(summary = "根据id查询用户余额变动明细表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(userBalanceLogService.getById(id)); + // 使用关联查询 + //return success(userBalanceLogService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:save')") + @OperationLog + @Operation(summary = "添加用户余额变动明细表") + @PostMapping() + public ApiResult save(@RequestBody UserBalanceLog userBalanceLog) { + // 记录当前登录用户id、租户id、商户编号 + User loginUser = getLoginUser(); + if (loginUser != null) { + userBalanceLog.setUserId(loginUser.getUserId()); + } + if (userBalanceLogService.save(userBalanceLog)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:update')") + @OperationLog + @Operation(summary = "修改用户余额变动明细表") + @PutMapping() + public ApiResult update(@RequestBody UserBalanceLog userBalanceLog) { + if (userBalanceLogService.updateById(userBalanceLog)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:remove')") + @OperationLog + @Operation(summary = "删除用户余额变动明细表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userBalanceLogService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:save')") + @OperationLog + @Operation(summary = "批量添加用户余额变动明细表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userBalanceLogService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:update')") + @OperationLog + @Operation(summary = "批量修改用户余额变动明细表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userBalanceLogService, "log_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userBalanceLog:remove')") + @OperationLog + @Operation(summary = "批量删除用户余额变动明细表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userBalanceLogService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserCollectionController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserCollectionController.java new file mode 100644 index 0000000..0585272 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserCollectionController.java @@ -0,0 +1,135 @@ +package com.gxwebsoft.common.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.param.UserCollectionParam; +import com.gxwebsoft.common.system.service.UserCollectionService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 我的收藏控制器 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Tag(name = "用户收藏") +@RestController +@RequestMapping("/api/system/user-collection") +public class UserCollectionController extends BaseController { + @Resource + private UserCollectionService userCollectionService; + + @PreAuthorize("hasAuthority('sys:userCollection:list')") + @Operation(summary = "分页查询我的收藏") + @GetMapping("/page") + public ApiResult> page(UserCollectionParam param) { + // 使用关联查询 + return success(userCollectionService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userCollection:list')") + @Operation(summary = "查询全部我的收藏") + @GetMapping() + public ApiResult> list(UserCollectionParam param) { + // 使用关联查询 + return success(userCollectionService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userCollection:list')") + @Operation(summary = "根据id查询我的收藏") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userCollectionService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userCollection:save')") + @OperationLog + @Operation(summary = "添加和取消收藏") + @PostMapping() + public ApiResult save(@RequestBody UserCollection userCollection) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + userCollection.setUserId(loginUser.getUserId()); + userCollection.setTid(userCollection.getTid()); + final UserCollection one = userCollectionService.getOne(new LambdaQueryWrapper().eq(UserCollection::getUserId, loginUser.getUserId()).eq(UserCollection::getTid, userCollection.getTid()).last("limit 1")); + if (one != null) { + userCollectionService.removeById(one.getId()); + return success("已取消收藏"); + } + if (userCollectionService.save(userCollection)) { + return success("已添加收藏"); + } + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:update')") + @OperationLog + @Operation(summary = "修改我的收藏") + @PutMapping() + public ApiResult update(@RequestBody UserCollection userCollection) { + if (userCollectionService.updateById(userCollection)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:remove')") + @OperationLog + @Operation(summary = "删除我的收藏") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userCollectionService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:save')") + @OperationLog + @Operation(summary = "批量添加我的收藏") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userCollectionService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:update')") + @OperationLog + @Operation(summary = "批量修改我的收藏") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userCollectionService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userCollection:remove')") + @OperationLog + @Operation(summary = "批量删除我的收藏") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userCollectionService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserController.java new file mode 100644 index 0000000..e37a42c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserController.java @@ -0,0 +1,420 @@ +package com.gxwebsoft.common.system.controller; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.*; +import com.gxwebsoft.common.system.entity.*; +import com.gxwebsoft.common.system.param.UserImportParam; +import com.gxwebsoft.common.system.param.UserParam; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.common.system.service.DictionaryDataService; +import com.gxwebsoft.common.system.service.OrganizationService; +import com.gxwebsoft.common.system.service.RoleService; +import com.gxwebsoft.common.system.service.UserService; +import io.swagger.v3.oas.annotations.tags.Tag; + +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 用户控制器 + * + * @author WebSoft + * @since 2018-12-24 16:10:41 + */ +@Tag(name = "用户管理") +@RestController +@RequestMapping("/api/system/user") +public class UserController extends BaseController { + @Resource + private UserService userService; + @Resource + private RoleService roleService; + @Resource + private OrganizationService organizationService; + @Resource + private DictionaryDataService dictionaryDataService; + @Resource + private AppUserCacheService appUserCacheService; + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "分页查询用户") + @GetMapping("/page") + public ApiResult> page(UserParam param) { + return success(userService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "分页查询用户") + @GetMapping("/pageAdminByPhone") + public ApiResult> pageAdminByPhone(UserParam param) { + return success(userService.pageAdminByPhone(param)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "查询全部用户") + @GetMapping() + public ApiResult> list(UserParam param) { + return success(userService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "根据id查询用户") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(userService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "根据手机号码查询用户") + @GetMapping("/getByPhone/{phone}") + public ApiResult getByPhone(@PathVariable("phone") String phone) { + return success(userService.getByPhone(phone)); + } + + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "添加用户") + @PostMapping() + public ApiResult add(@RequestBody User user) { + user.setStatus(0); + user.setPassword(userService.encodePassword(user.getPassword())); + if (userService.saveUser(user)) { + // 同步到 app_user_cache 表 + appUserCacheService.refreshUserCache(user.getUserId()); + return success("添加成功",user.getUserId()); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "批量添加用户") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List userList) { + userList.forEach(d -> { + d.setStatus(0); + if (d.getPassword() != null) { + d.setPassword(userService.encodePassword(d.getPassword())); + } + }); + if (userService.saveBatch(userList)) { + // 同步到 app_user_cache 表 + List userIds = userList.stream() + .map(User::getUserId) + .filter(id -> id != null) + .collect(Collectors.toList()); + appUserCacheService.batchRefreshUserCache(userIds); + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "批量添加用户并返回userId") + @PostMapping("/batchBackUserId") + public ApiResult saveBatchBackUserId(@RequestBody List userList) { + userList.forEach(d -> { + d.setStatus(0); + d.setPassword(userService.encodePassword(d.getPassword())); + }); + final Set phones = userList.stream().map(User::getPhone).collect(Collectors.toSet()); + if (userService.saveBatch(userList)) { + final UserParam userParam = new UserParam(); + userParam.setPhones(phones); + userParam.setLimit(500L); + final PageResult result = userService.pageRel(userParam); + final Set collect = result.getList().stream().map(User::getUserId).collect(Collectors.toSet()); + // 同步到 app_user_cache 表 + appUserCacheService.batchRefreshUserCache(new ArrayList<>(collect)); + return success("添加成功",collect); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "修改用户") + @PutMapping() + public ApiResult update(@RequestBody User user) { + user.setStatus(null); + user.setUsername(null); + user.setPassword(null); + if (userService.updateUser(user)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:remove')") + @OperationLog + @Operation(summary = "删除用户") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "批量修改用户") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userService, User::getUserId)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:remove')") + @OperationLog + @Operation(summary = "批量删除用户") + @Transactional(rollbackFor = {Exception.class}) + @DeleteMapping("/batch") + public ApiResult deleteBatch(@RequestBody List ids) { + if (userService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "修改用户状态") + @PutMapping("/status") + public ApiResult updateStatus(@RequestBody User user) { + if (user.getUserId() == null || user.getStatus() == null || !Arrays.asList(0, 1).contains(user.getStatus())) { + return fail("参数不正确"); + } + User u = new User(); + u.setUserId(user.getUserId()); + u.setStatus(user.getStatus()); + if (userService.updateById(u)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "修改推荐状态") + @PutMapping("/recommend") + public ApiResult updateRecommend(@RequestBody User user) { + if (user.getUserId() == null || user.getRecommend() == null || !Arrays.asList(0, 1).contains(user.getRecommend())) { + return fail("参数不正确"); + } + User u = new User(); + u.setUserId(user.getUserId()); + u.setRecommend(user.getRecommend()); + if (userService.updateById(u)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "批量修改用户状态") + @PutMapping("/status/batch") + public ApiResult updateStatusBatch(@RequestBody BatchParam batchParam) { + if (!Arrays.asList(0, 1).contains(batchParam.getData())) { + return fail("状态值不正确"); + } + if (userService.update(new LambdaUpdateWrapper() + .in(User::getUserId, batchParam.getIds()) + .set(User::getStatus, batchParam.getData()))) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "重置密码") + @PutMapping("/password") + public ApiResult resetPassword(@RequestBody User user) { + if (user.getUserId() == null || StrUtil.isBlank(user.getPassword())) { + return fail("参数不正确"); + } + User u = new User(); + u.setUserId(user.getUserId()); + u.setPassword(userService.encodePassword(user.getPassword())); + if (userService.updateById(u)) { + return success("重置成功"); + } else { + return fail("重置失败"); + } + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @OperationLog + @Operation(summary = "批量重置密码") + @PutMapping("/password/batch") + public ApiResult resetPasswordBatch(@RequestBody BatchParam batchParam) { + if (batchParam.getIds() == null || batchParam.getIds().size() == 0) { + return fail("请选择用户"); + } + if (batchParam.getData() == null) { + return fail("请输入密码"); + } + if (userService.update(new LambdaUpdateWrapper() + .in(User::getUserId, batchParam.getIds()) + .set(User::getPassword, userService.encodePassword(batchParam.getData())))) { + return success("重置成功"); + } else { + return fail("重置失败"); + } + } + + @Operation(summary = "检查用户是否存在") + @GetMapping("/existence") + public ApiResult existence(ExistenceParam param) { + if (param.isExistence(userService, User::getUserId)) { + return success(param.getValue() + "已存在"); + } + return fail(param.getValue() + "不存在"); + } + + /** + * excel导入用户 + */ + @PreAuthorize("hasAuthority('sys:user:save')") + @Operation(summary = "导入用户") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/import") + public ApiResult> importBatch(MultipartFile file) { + ImportParams importParams = new ImportParams(); + try { + List list = ExcelImportUtil.importExcel(file.getInputStream(), + UserImportParam.class, importParams); + // 校验是否重复 + if (CommonUtil.checkRepeat(list, UserImportParam::getUsername)) { + return fail("账号存在重复", null); + } + if (CommonUtil.checkRepeat(list, UserImportParam::getPhone)) { + return fail("手机号存在重复", null); + } + // 校验是否存在 + List usernameExists = userService.list(new LambdaQueryWrapper().in(User::getUsername, + list.stream().map(UserImportParam::getUsername).collect(Collectors.toList()))); + if (usernameExists.size() > 0) { + return fail("账号已经存在", + usernameExists.stream().map(User::getUsername).collect(Collectors.toList())); + } + List phoneExists = userService.list(new LambdaQueryWrapper().in(User::getPhone, + list.stream().map(UserImportParam::getPhone).collect(Collectors.toList()))); + if (phoneExists.size() > 0) { + return fail("手机号已经存在", + phoneExists.stream().map(User::getPhone).collect(Collectors.toList())); + } + // 添加 + List users = new ArrayList<>(); + for (UserImportParam one : list) { + User u = new User(); + u.setStatus(0); + u.setUsername(one.getUsername()); + u.setPassword(userService.encodePassword(one.getPassword())); + u.setNickname(one.getNickname()); + u.setPhone(one.getPhone()); + Role role = roleService.getOne(new QueryWrapper() + .eq("role_name", one.getRoleName()), false); + if (role == null) { + return fail("角色不存在", Collections.singletonList(one.getRoleName())); + } else { + u.setRoles(Collections.singletonList(role)); + } + Organization organization = organizationService.getOne(new QueryWrapper() + .eq("organization_full_name", one.getOrganizationName()), false); + if (organization == null) { + return fail("机构不存在", Collections.singletonList(one.getOrganizationName())); + } else { + u.setOrganizationId(organization.getOrganizationId()); + } + DictionaryData sex = dictionaryDataService.getByDictCodeAndName("sex", one.getSexName()); + if (sex == null) { + return fail("性别不存在", Collections.singletonList(one.getSexName())); + } else { + u.setSex(sex.getDictDataCode()); + } + } + if (userService.saveBatch(users)) { + // 同步到 app_user_cache 表 + List userIds = users.stream() + .map(User::getUserId) + .filter(id -> id != null) + .collect(Collectors.toList()); + appUserCacheService.batchRefreshUserCache(userIds); + return success("导入成功", null); + } + } catch (Exception e) { + e.printStackTrace(); + } + return fail("导入失败", null); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @PostMapping("/getAvatarByMpWx") + @Operation(summary = "更新微信头像") + public ApiResult getAvatarByMpWx(@RequestBody User user){ + user.setAvatar("https://oa.gxwebsoft.com/assets/logo.7ccfefb9.svg"); + if (userService.updateUser(user)) { + return success("更新成功"); + } + return fail("更新失败"); + } + + @PostMapping("/updatePointsBySign") + @Operation(summary = "签到成功累加积分") + public ApiResult updatePointsBySign(){ + final User loginUser = getLoginUser(); + loginUser.setPoints(loginUser.getPoints() + 1); + if (userService.updateUser(loginUser)) { + return success("签到成功"); + } + return fail("签到失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @PutMapping("/updateUserBalance") + @Operation(summary = "更新用户余额") + public ApiResult updateUserBalance(@RequestBody User user){ + if (getLoginUser() == null) { + return fail("请先登录"); + } + if (userService.updateUser(user)) { + return success("操作成功"); + } + return fail("操作失败"); + } + + @PreAuthorize("hasAuthority('sys:user:list')") + @OperationLog + @Operation(summary = "统计用户余额") + @GetMapping("/countUserBalance") + public ApiResult countUserBalance(User param) { + final LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.gt(User::getBalance, 0); + if (!param.getOrganizationId().equals(0)) { + wrapper.eq(User::getOrganizationId,param.getOrganizationId()); + } + final List list = userService.list(wrapper); + final BigDecimal totalBalance = list.stream().map(User::getBalance).reduce(BigDecimal.ZERO, BigDecimal::add); + // System.out.println("统计用户余额 = " + totalBalance); + return success("统计成功",totalBalance); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserFileController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserFileController.java new file mode 100644 index 0000000..b56214d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserFileController.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.utils.FileServerUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.service.UserFileService; +import com.gxwebsoft.common.system.entity.UserFile; +import com.gxwebsoft.common.system.param.UserFileParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 用户文件控制器 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Tag(name = "用户文件管理") +@RestController +@RequestMapping("/api/system/user-file") +public class UserFileController extends BaseController { + @Resource + private UserFileService userFileService; + + @Operation(summary = "分页查询用户文件") + @GetMapping("/page") + public ApiResult> page(UserFileParam param, HttpServletRequest request) { + param.setUserId(getLoginUserId()); + PageParam page = new PageParam<>(param); + page.setDefaultOrder("is_directory desc"); + PageParam result = userFileService.page(page, page.getWrapper()); + List records = result.getRecords(); + String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/system/user-file") + "/file"; + for (UserFile record : records) { + if (StrUtil.isNotBlank(record.getPath())) { + record.setUrl(requestURL + "/" + record.getPath()); + if (FileServerUtil.isImage(record.getContentType())) { + record.setThumbnail(requestURL + "/thumbnail/" + record.getPath()); + } + record.setDownloadUrl(requestURL + "/download/" + record.getPath()); + } + } + return success(records, result.getTotal()); + } + + @Operation(summary = "查询全部用户文件") + @GetMapping() + public ApiResult> list(UserFileParam param, HttpServletRequest request) { + param.setUserId(getLoginUserId()); + PageParam page = new PageParam<>(param); + page.setDefaultOrder("is_directory desc"); + List records = userFileService.list(page.getOrderWrapper()); + String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/system/user-file") + "/file"; + for (UserFile record : records) { + if (StrUtil.isNotBlank(record.getPath())) { + record.setUrl(requestURL + "/" + record.getPath()); + if (FileServerUtil.isImage(record.getContentType())) { + record.setThumbnail(requestURL + "/thumbnail/" + record.getPath()); + } + record.setDownloadUrl(requestURL + "/download/" + record.getPath()); + } + } + return success(records); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "添加用户文件") + @PostMapping() + public ApiResult save(@RequestBody UserFile userFile) { + userFile.setUserId(getLoginUserId()); + if (userFile.getParentId() == null) { + userFile.setParentId(0); + } + if (userFile.getIsDirectory() != null && userFile.getIsDirectory().equals(1)) { + if (userFileService.count(new LambdaQueryWrapper() + .eq(UserFile::getName, userFile.getName()) + .eq(UserFile::getParentId, userFile.getParentId()) + .eq(UserFile::getUserId, userFile.getUserId())) > 0) { + return fail("文件夹名称已存在"); + } + } + if (userFileService.save(userFile)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "修改用户文件") + @PutMapping() + public ApiResult update(@RequestBody UserFile userFile) { + Integer loginUserId = getLoginUserId(); + UserFile old = userFileService.getById(userFile.getId()); + UserFile entity = new UserFile(); + if (StrUtil.isNotBlank(userFile.getName())) { + entity.setName(userFile.getName()); + } + if (userFile.getParentId() != null) { + entity.setParentId(userFile.getParentId()); + } + if (!old.getUserId().equals(loginUserId) || + (entity.getName() == null && entity.getParentId() == null)) { + return fail("修改失败"); + } + if (old.getIsDirectory() != null && old.getIsDirectory().equals(1)) { + if (userFileService.count(new LambdaQueryWrapper() + .eq(UserFile::getName, entity.getName() == null ? old.getName() : entity.getName()) + .eq(UserFile::getParentId, entity.getParentId() == null ? old.getParentId() : entity.getParentId()) + .eq(UserFile::getUserId, loginUserId) + .ne(UserFile::getId, old.getId())) > 0) { + return fail("文件夹名称已存在"); + } + } + if (userFileService.update(entity, new LambdaUpdateWrapper() + .eq(UserFile::getId, userFile.getId()) + .eq(UserFile::getUserId, loginUserId))) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "删除用户文件") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userFileService.remove(new LambdaUpdateWrapper() + .eq(UserFile::getId, id) + .eq(UserFile::getUserId, getLoginUserId()))) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:auth:user')") + @Operation(summary = "批量删除用户文件") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userFileService.remove(new LambdaUpdateWrapper() + .in(UserFile::getId, ids) + .eq(UserFile::getUserId, getLoginUserId()))) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserGradeController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserGradeController.java new file mode 100644 index 0000000..c5a4716 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserGradeController.java @@ -0,0 +1,132 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserGradeService; +import com.gxwebsoft.common.system.entity.UserGrade; +import com.gxwebsoft.common.system.param.UserGradeParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户会员等级表控制器 + * + * @author 科技小王子 + * @since 2023-10-07 22:51:17 + */ +@Tag(name = "用户等级") +@RestController +@RequestMapping("/api/system/user-grade") +public class UserGradeController extends BaseController { + @Resource + private UserGradeService userGradeService; + + @Operation(summary = "分页查询用户会员等级表") + @GetMapping("/page") + public ApiResult> page(UserGradeParam param) { + // 使用关联查询 + return success(userGradeService.pageRel(param)); + } + + @Operation(summary = "查询全部用户会员等级表") + @GetMapping() + public ApiResult> list(UserGradeParam param) { + // 使用关联查询 + return success(userGradeService.listRel(param)); + } + + @Operation(summary = "根据id查询用户会员等级表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userGradeService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userGrade:save')") + @OperationLog + @Operation(summary = "添加用户会员等级表") + @PostMapping() + public ApiResult save(@RequestBody UserGrade userGrade) { + if (userGradeService.save(userGrade)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userGrade:update')") + @OperationLog + @Operation(summary = "修改用户会员等级表") + @PutMapping() + public ApiResult update(@RequestBody UserGrade userGrade) { + if (userGradeService.updateById(userGrade)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userGrade:remove')") + @OperationLog + @Operation(summary = "删除用户会员等级表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userGradeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userGrade:save')") + @OperationLog + @Operation(summary = "批量添加用户会员等级表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userGradeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userGrade:update')") + @OperationLog + @Operation(summary = "批量修改用户会员等级表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userGradeService, "grade_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userGrade:remove')") + @OperationLog + @Operation(summary = "批量删除用户会员等级表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userGradeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "修改用户会员等级表") + @PutMapping("/updateGradeId") + public ApiResult updateGradeId(@RequestBody UserGrade userGrade) { + final User loginUser = getLoginUser(); + if(loginUser != null){ + if (userGradeService.updateById(userGrade)) { + return success("修改成功"); + } + } + return fail("修改失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserGroupController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserGroupController.java new file mode 100644 index 0000000..38b1e55 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserGroupController.java @@ -0,0 +1,133 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.service.UserGroupService; +import com.gxwebsoft.common.system.entity.UserGroup; +import com.gxwebsoft.common.system.param.UserGroupParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户分组管理表控制器 + * + * @author 科技小王子 + * @since 2023-10-28 15:16:39 + */ +@Tag(name = "用户") +@RestController +@RequestMapping("/api/system/user-group") +public class UserGroupController extends BaseController { + @Resource + private UserGroupService userGroupService; + + @PreAuthorize("hasAuthority('sys:userGroup:list')") + @OperationLog + @Operation(summary = "分页查询用户分组管理表") + @GetMapping("/page") + public ApiResult> page(UserGroupParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(userGroupService.page(page, page.getWrapper())); + // 使用关联查询 + //return success(userGroupService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userGroup:list')") + @OperationLog + @Operation(summary = "查询全部用户分组管理表") + @GetMapping() + public ApiResult> list(UserGroupParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(userGroupService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(userGroupService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userGroup:list')") + @OperationLog + @Operation(summary = "根据id查询用户分组管理表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(userGroupService.getById(id)); + // 使用关联查询 + //return success(userGroupService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userGroup:save')") + @OperationLog + @Operation(summary = "添加用户分组管理表") + @PostMapping() + public ApiResult save(@RequestBody UserGroup userGroup) { + if (userGroupService.save(userGroup)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userGroup:update')") + @OperationLog + @Operation(summary = "修改用户分组管理表") + @PutMapping() + public ApiResult update(@RequestBody UserGroup userGroup) { + if (userGroupService.updateById(userGroup)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userGroup:remove')") + @OperationLog + @Operation(summary = "删除用户分组管理表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userGroupService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userGroup:save')") + @OperationLog + @Operation(summary = "批量添加用户分组管理表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userGroupService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userGroup:update')") + @OperationLog + @Operation(summary = "批量修改用户分组管理表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userGroupService, "group_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userGroup:remove')") + @OperationLog + @Operation(summary = "批量删除用户分组管理表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userGroupService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserOauthController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserOauthController.java new file mode 100644 index 0000000..6e49d78 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserOauthController.java @@ -0,0 +1,131 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserOauthService; +import com.gxwebsoft.common.system.entity.UserOauth; +import com.gxwebsoft.common.system.param.UserOauthParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 第三方用户信息表控制器 + * + * @author 科技小王子 + * @since 2023-10-07 22:39:46 + */ +@Tag(name = "第三方用户") +@RestController +@RequestMapping("/api/system/user-oauth") +public class UserOauthController extends BaseController { + @Resource + private UserOauthService userOauthService; + + @PreAuthorize("hasAuthority('sys:userOauth:list')") + @OperationLog + @Operation(summary = "分页查询第三方用户信息表") + @GetMapping("/page") + public ApiResult> page(UserOauthParam param) { + // 使用关联查询 + return success(userOauthService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userOauth:list')") + @OperationLog + @Operation(summary = "查询全部第三方用户信息表") + @GetMapping() + public ApiResult> list(UserOauthParam param) { + // 使用关联查询 + return success(userOauthService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userOauth:list')") + @OperationLog + @Operation(summary = "根据id查询第三方用户信息表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userOauthService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userOauth:save')") + @OperationLog + @Operation(summary = "添加第三方用户信息表") + @PostMapping() + public ApiResult save(@RequestBody UserOauth userOauth) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + userOauth.setUserId(loginUser.getUserId()); + } + if (userOauthService.save(userOauth)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userOauth:update')") + @OperationLog + @Operation(summary = "修改第三方用户信息表") + @PutMapping() + public ApiResult update(@RequestBody UserOauth userOauth) { + if (userOauthService.updateById(userOauth)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userOauth:remove')") + @OperationLog + @Operation(summary = "删除第三方用户信息表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userOauthService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userOauth:save')") + @OperationLog + @Operation(summary = "批量添加第三方用户信息表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userOauthService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userOauth:update')") + @OperationLog + @Operation(summary = "批量修改第三方用户信息表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userOauthService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userOauth:remove')") + @OperationLog + @Operation(summary = "批量删除第三方用户信息表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userOauthService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserRefereeController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserRefereeController.java new file mode 100644 index 0000000..6cd1463 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserRefereeController.java @@ -0,0 +1,183 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.param.UserRefereeParam; +import com.gxwebsoft.common.system.service.UserRefereeService; +import com.gxwebsoft.common.system.service.UserService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户推荐关系表控制器 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Tag(name = "用户") +@RestController +@RequestMapping("/api/system/user-referee") +public class UserRefereeController extends BaseController { + @Resource + private UserRefereeService userRefereeService; + @Resource + private UserService userService; + + @PreAuthorize("hasAuthority('sys:userReferee:list')") + @OperationLog + @Operation(summary = "分页查询用户推荐关系表") + @GetMapping("/page") + public ApiResult> page(UserRefereeParam param) { + // 使用关联查询 + return success(userRefereeService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userReferee:list')") + @OperationLog + @Operation(summary = "查询全部用户推荐关系表") + @GetMapping() + public ApiResult> list(UserRefereeParam param) { + // 使用关联查询 + return success(userRefereeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userReferee:list')") + @OperationLog + @Operation(summary = "根据id查询用户推荐关系表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userRefereeService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userReferee:save')") + @OperationLog + @Operation(summary = "添加用户推荐关系表") + @PostMapping() + public ApiResult save(@RequestBody UserReferee userReferee) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + userReferee.setUserId(loginUser.getUserId()); + } + if (userRefereeService.save(userReferee)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:update')") + @OperationLog + @Operation(summary = "修改用户推荐关系表") + @PutMapping() + public ApiResult update(@RequestBody UserReferee userReferee) { + if (userRefereeService.updateById(userReferee)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:remove')") + @OperationLog + @Operation(summary = "删除用户推荐关系表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userRefereeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:save')") + @OperationLog + @Operation(summary = "批量添加用户推荐关系表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userRefereeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:update')") + @OperationLog + @Operation(summary = "批量修改用户推荐关系表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userRefereeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userReferee:remove')") + @OperationLog + @Operation(summary = "批量删除用户推荐关系表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userRefereeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "查询推荐人信息") + @GetMapping("/getReferee/{id}") + public ApiResult getReferee(@PathVariable("id") Integer id) { + if (id == null) { + return fail("参数错误", null); + } + + final UserReferee referee = userRefereeService.getOne(new LambdaQueryWrapper() + .eq(UserReferee::getUserId, id) + .eq(UserReferee::getDeleted, 0)); + + if (ObjectUtil.isEmpty(referee)) { + return fail("查询失败", null); + } + + final User user = userService.getByIdRel(referee.getDealerId()); + if (ObjectUtil.isNotEmpty(user)) { + return success(user); + } + return fail("查询失败", null); + } + + @Operation(summary = "查询推荐人列表") + @GetMapping("/getRefereeList/{id}") + public ApiResult> getRefereeList(@PathVariable("id") Integer id) { + if (id == null) { + return fail("参数错误", null); + } + + final List refereeList = userRefereeService.list(new LambdaQueryWrapper() + .eq(UserReferee::getDealerId, id) + .eq(UserReferee::getDeleted, 0)); + + if (ObjectUtil.isEmpty(refereeList)) { + return fail("查询失败", null); + } + + final List users = userService.list( + new LambdaQueryWrapper() + .in(User::getUserId, refereeList.stream().map(UserReferee::getUserId).toList()) + ); + if (ObjectUtil.isNotEmpty(users)) { + return success(users); + } + return fail("查询失败", null); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserRoleController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserRoleController.java new file mode 100644 index 0000000..692600a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserRoleController.java @@ -0,0 +1,134 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserRoleService; +import com.gxwebsoft.common.system.entity.UserRole; +import com.gxwebsoft.common.system.param.UserRoleParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户角色控制器 + * + * @author 科技小王子 + * @since 2025-06-16 20:39:53 + */ +@Tag(name = "用户角色管理") +@RestController +@RequestMapping("/api/system/user-role") +public class UserRoleController extends BaseController { + @Resource + private UserRoleService userRoleService; + + @Operation(summary = "查询角色下的用户") + @GetMapping("/user-list-in-role/{id}") + public ApiResult> userListInRole(@PathVariable Integer id) { + return success(userRoleService.listByRoleId(id)); + } + + @Operation(summary = "分页查询用户角色") + @GetMapping("/page") + public ApiResult> page(UserRoleParam param) { + // 使用关联查询 + return success(userRoleService.pageRel(param)); + } + + @Operation(summary = "查询全部用户角色") + @GetMapping() + public ApiResult> list(UserRoleParam param) { + // 使用关联查询 + return success(userRoleService.listRel(param)); + } + + + @Operation(summary = "根据id查询用户角色") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userRoleService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:userRole:save')") + @OperationLog + @Operation(summary = "添加用户角色") + @PostMapping() + public ApiResult save(@RequestBody UserRole userRole) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + userRole.setUserId(loginUser.getUserId()); + } + if (userRoleService.save(userRole)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改用户角色") + @PutMapping() + public ApiResult update(@RequestBody UserRole userRole) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + if (userRoleService.updateById(userRole)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userRole:remove')") + @OperationLog + @Operation(summary = "删除用户角色") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userRoleService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userRole:save')") + @OperationLog + @Operation(summary = "批量添加用户角色") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userRoleService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userRole:update')") + @OperationLog + @Operation(summary = "批量修改用户角色") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userRoleService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userRole:remove')") + @OperationLog + @Operation(summary = "批量删除用户角色") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userRoleService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserVerifyController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserVerifyController.java new file mode 100644 index 0000000..5d4350b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/UserVerifyController.java @@ -0,0 +1,182 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.ObjUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserVerify; +import com.gxwebsoft.common.system.param.UserVerifyParam; +import com.gxwebsoft.common.system.service.OrganizationService; +import com.gxwebsoft.common.system.service.UserService; +import com.gxwebsoft.common.system.service.UserVerifyService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 实名认证控制器 + * + * @author 科技小王子 + * @since 2025-05-29 23:01:04 + */ +@Tag(name = "实名认证管理") +@RestController +@RequestMapping("/api/system/user-verify") +public class UserVerifyController extends BaseController { + @Resource + private UserVerifyService userVerifyService; + @Resource + private UserService userService; + @Resource + private OrganizationService organizationService; + + @PreAuthorize("hasAuthority('sys:userVerify:list')") + @Operation(summary = "分页查询实名认证") + @GetMapping("/page") + public ApiResult> page(UserVerifyParam param) { + // 使用关联查询 + return success(userVerifyService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:userVerify:list')") + @Operation(summary = "查询全部实名认证") + @GetMapping() + public ApiResult> list(UserVerifyParam param) { + // 使用关联查询 + return success(userVerifyService.listRel(param)); + } + + @Operation(summary = "根据id查询实名认证") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(userVerifyService.getByIdRel(id)); + } + + @Operation(summary = "根据userId查询实名认证") + @GetMapping("/myUserVerify") + public ApiResult myUserVerify(UserVerifyParam param) { + if (getLoginUser() == null) { + return fail("请先登录", null); + } + final LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(UserVerify::getUserId, getLoginUserId()); + wrapper.eq(UserVerify::getDeleted, 0); + if(param.getStatus() != null){ + wrapper.eq(UserVerify::getStatus, param.getStatus()); + } + wrapper.last("limit 1"); + final UserVerify one = userVerifyService.getOne(wrapper); + if(ObjUtil.isNotEmpty(one) && one.getOrganizationId() > 0){ + final Organization organization = organizationService.getById(one.getOrganizationId()); + if(organization != null){ + one.setOrganizationName(organization.getOrganizationName()); + } + } + return success(one); + } + + @Operation(summary = "提交实名认证") + @PostMapping() + public ApiResult save(@RequestBody UserVerify userVerify) { + if (getLoginUser() == null) { + return fail("请先登录"); + } + userVerify.setUserId(getLoginUserId()); + if (userVerifyService.save(userVerify)) { + return success("提交成功"); + } + return fail("提交失败"); + } + + @Transactional(rollbackFor = Exception.class) + @Operation(summary = "修改实名认证") + @PutMapping() + public ApiResult update(@RequestBody UserVerify userVerify) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + + final User byUserId = userService.getById(userVerify.getUserId()); + if (ObjUtil.isEmpty(byUserId)) { + return fail("用户不存在"); + } + // 不通过 + byUserId.setCertification(0); + // 通过认证 + if (userVerify.getStatus().equals(1)) { + byUserId.setRealName(userVerify.getRealName()); + byUserId.setCertification(1); + byUserId.setType(userVerify.getType()); + // 企业认证 + if (userVerify.getType().equals(1)) { + byUserId.setRealName(userVerify.getName()); + } + // 设置管理员id + userVerify.setAdminId(loginUser.getUserId()); + } + userService.updateById(byUserId); + + if (userVerifyService.updateById(userVerify)) { + return success("提交成功"); + } + return fail("提交失败"); + } + + @PreAuthorize("hasAuthority('sys:userVerify:remove')") + @OperationLog + @Operation(summary = "删除实名认证") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (userVerifyService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:userVerify:save')") + @OperationLog + @Operation(summary = "批量添加实名认证") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (userVerifyService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:userVerify:update')") + @OperationLog + @Operation(summary = "批量修改实名认证") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(userVerifyService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:userVerify:remove')") + @OperationLog + @Operation(summary = "批量删除实名认证") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (userVerifyService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/VerifyTxt.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/VerifyTxt.java new file mode 100644 index 0000000..2b87b73 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/VerifyTxt.java @@ -0,0 +1,19 @@ +package com.gxwebsoft.common.system.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "安全") +@RestController +@RequestMapping("/lvQ4EoivKJ.txt") +public class VerifyTxt { + + @Operation(summary = "域名所有权验证") + @GetMapping() + public String verify(){ + return "cbfbfe827744f1ebfaf03bfe2a0def6a"; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/VersionController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/VersionController.java new file mode 100644 index 0000000..8094e55 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/VersionController.java @@ -0,0 +1,138 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.VersionService; +import com.gxwebsoft.common.system.entity.Version; +import com.gxwebsoft.common.system.param.VersionParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 版本更新控制器 + * + * @author 科技小王子 + * @since 2024-01-15 18:52:24 + */ +@Tag(name = "系统版本") +@RestController +@RequestMapping("/api/system/version") +public class VersionController extends BaseController { + @Resource + private VersionService versionService; + + @PreAuthorize("hasAuthority('sys:version:list')") + @OperationLog + @Operation(summary = "分页查询版本更新") + @GetMapping("/page") + public ApiResult> page(VersionParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(versionService.page(page, page.getWrapper())); + // 使用关联查询 + //return success(versionService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:version:list')") + @OperationLog + @Operation(summary = "查询全部版本更新") + @GetMapping() + public ApiResult> list(VersionParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return success(versionService.list(page.getOrderWrapper())); + // 使用关联查询 + //return success(versionService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:version:list')") + @OperationLog + @Operation(summary = "根据id查询版本更新") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(versionService.getById(id)); + // 使用关联查询 + //return success(versionService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:version:save')") + @OperationLog + @Operation(summary = "添加版本更新") + @PostMapping() + public ApiResult save(@RequestBody Version version) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + version.setUserId(loginUser.getUserId()); + } + if (versionService.save(version)) { + return success("发布成功"); + } + return fail("发布失败"); + } + + @PreAuthorize("hasAuthority('sys:version:save')") + @OperationLog + @Operation(summary = "修改版本更新") + @PutMapping() + public ApiResult update(@RequestBody Version version) { + if (versionService.updateById(version)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:version:save')") + @OperationLog + @Operation(summary = "删除版本更新") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (versionService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:version:save')") + @OperationLog + @Operation(summary = "批量添加版本更新") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (versionService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:version:save')") + @OperationLog + @Operation(summary = "批量修改版本更新") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(versionService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:version:save')") + @OperationLog + @Operation(summary = "批量删除版本更新") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (versionService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WebsiteFieldController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WebsiteFieldController.java new file mode 100644 index 0000000..9d38c96 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WebsiteFieldController.java @@ -0,0 +1,136 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.WebsiteFieldService; +import com.gxwebsoft.common.system.entity.WebsiteField; +import com.gxwebsoft.common.system.param.WebsiteFieldParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; + +/** + * 应用参数控制器 + * + * @author 科技小王子 + * @since 2024-08-27 15:18:05 + */ +@Tag(name = "应用参数管理") +@RestController +@RequestMapping("/api/system/website-field") +public class WebsiteFieldController extends BaseController { + @Resource + private WebsiteFieldService websiteFieldService; + + @Operation(summary = "分页查询应用参数") + @GetMapping("/page") + public ApiResult> page(WebsiteFieldParam param) { + // 使用关联查询 + return success(websiteFieldService.pageRel(param)); + } + + @Operation(summary = "查询全部应用参数") + @GetMapping() + public ApiResult> list(WebsiteFieldParam param) { + // 使用关联查询 + return success(websiteFieldService.listRel(param)); + } + + @Operation(summary = "根据id查询应用参数") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(websiteFieldService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('system:websiteField:save')") + @OperationLog + @Operation(summary = "添加应用参数") + @PostMapping() + public ApiResult save(@RequestBody WebsiteField websiteField) { + if (websiteFieldService.save(websiteField)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('system:websiteField:update')") + @OperationLog + @Operation(summary = "修改应用参数") + @PutMapping() + public ApiResult update(@RequestBody WebsiteField websiteField) { + if (websiteFieldService.updateById(websiteField)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('system:websiteField:remove')") + @OperationLog + @Operation(summary = "删除应用参数") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (websiteFieldService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('system:websiteField:save')") + @OperationLog + @Operation(summary = "批量添加应用参数") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (websiteFieldService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('system:websiteField:update')") + @OperationLog + @Operation(summary = "批量修改应用参数") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(websiteFieldService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('system:websiteField:remove')") + @OperationLog + @Operation(summary = "批量删除应用参数") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (websiteFieldService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "获取网站配置参数-对象形式") + @GetMapping("/config") + public ApiResult getConfig(WebsiteFieldParam param) { + // 使用关联查询 + final List fields = websiteFieldService.listRel(param); + + HashMap config = new HashMap<>(); + fields.forEach(d -> { + config.put(d.getName(), d.getValue()); + }); + System.out.println("config = " + config); + return success(config); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WhiteDomainController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WhiteDomainController.java new file mode 100644 index 0000000..f826c18 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WhiteDomainController.java @@ -0,0 +1,147 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.WhiteDomainService; +import com.gxwebsoft.common.system.entity.WhiteDomain; +import com.gxwebsoft.common.system.param.WhiteDomainParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 服务器白名单控制器 + * + * @author 科技小王子 + * @since 2024-03-26 00:22:21 + */ +@Tag(name = "安全") +@RestController +@RequestMapping("/api/system/white-domain") +public class WhiteDomainController extends BaseController { + @Resource + private WhiteDomainService whiteDomainService; + @Resource + private RedisUtil redisUtil; + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @Operation(summary = "分页查询服务器白名单") + @GetMapping("/page") + public ApiResult> page(WhiteDomainParam param) { + // 使用关联查询 + return success(whiteDomainService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @Operation(summary = "查询全部服务器白名单") + @GetMapping() + public ApiResult> list(WhiteDomainParam param) { + // 使用关联查询 + return success(whiteDomainService.listRel(param)); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @Operation(summary = "根据id查询服务器白名单") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(whiteDomainService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @OperationLog + @Operation(summary = "添加服务器白名单") + @PostMapping() + public ApiResult save(@RequestBody WhiteDomain whiteDomain) { + String key = "WhiteDomain:"; + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + key = key + loginUser.getTenantId(); + whiteDomain.setUserId(loginUser.getUserId()); + } + if (whiteDomainService.save(whiteDomain)) { + // 重写缓存 + final List list = whiteDomainService.list(); + final List collect = list.stream().map(WhiteDomain::getDomain).collect(Collectors.toList()); + redisUtil.set(key,collect); + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @OperationLog + @Operation(summary = "修改服务器白名单") + @PutMapping() + public ApiResult update(@RequestBody WhiteDomain whiteDomain) { + if (whiteDomainService.updateById(whiteDomain)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @OperationLog + @Operation(summary = "删除服务器白名单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (whiteDomainService.removeById(id)) { + // 重写缓存 + String key = "WhiteDomain:"; + User loginUser = getLoginUser(); + if (loginUser != null) { + key = key + loginUser.getTenantId(); + } + final List list = whiteDomainService.list(); + final List collect = list.stream().map(WhiteDomain::getDomain).collect(Collectors.toList()); + redisUtil.set(key,collect); + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @OperationLog + @Operation(summary = "批量添加服务器白名单") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (whiteDomainService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @OperationLog + @Operation(summary = "批量修改服务器白名单") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(whiteDomainService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:whiteDomain:list')") + @OperationLog + @Operation(summary = "批量删除服务器白名单") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (whiteDomainService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxLoginController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxLoginController.java new file mode 100644 index 0000000..1f8368b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxLoginController.java @@ -0,0 +1,826 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.security.JwtSubject; +import com.gxwebsoft.common.core.security.JwtUtil; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.RequestUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.*; +import com.gxwebsoft.common.system.param.UserParam; +import com.gxwebsoft.common.system.result.LoginResult; +import com.gxwebsoft.app.service.AppUserCacheService; +import com.gxwebsoft.common.system.service.*; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import okhttp3.*; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeUnit; + +import static com.gxwebsoft.common.core.constants.PlatformConstants.MP_WEIXIN; +import static com.gxwebsoft.common.core.constants.RedisConstants.ACCESS_TOKEN_KEY; +import static com.gxwebsoft.common.core.constants.RedisConstants.MP_WX_KEY; + +@RestController +@RequestMapping("/api/wx-login") +@Tag(name = "微信小程序登录API") +public class WxLoginController extends BaseController { + private final StringRedisTemplate redisTemplate; + private final OkHttpClient http = new OkHttpClient(); + private final ObjectMapper om = new ObjectMapper(); + private volatile long tokenExpireEpoch = 0L; // 过期的 epoch 秒 + @Resource + private SettingService settingService; + @Resource + private UserService userService; + @Resource + private ConfigProperties configProperties; + @Resource + private UserRoleService userRoleService; + @Resource + private LoginRecordService loginRecordService; + @Resource + private RoleService roleService; + @Resource + private RedisUtil redisUtil; + @Resource + private RequestUtil requestUtil; + @Resource + private ConfigProperties config; + @Resource + private UserRefereeService userRefereeService; + @Resource + private AppUserCacheService appUserCacheService; + + + public WxLoginController(StringRedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + @Operation(summary = "获取微信AccessToken") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/getAccessToken") + public ApiResult getMpAccessToken() { + return success("操作成功", getAccessToken()); + } + + @Operation(summary = "获取微信openId") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/getOpenId") + public ApiResult getOpenId(@RequestBody UserParam userParam, HttpServletRequest request) { + // 1.获取openid + JSONObject result = getOpenIdByCode(userParam); + String openid = result.getString("openid"); + String unionid = result.getString("unionid"); + if (openid == null) { + return fail("获取openid失败", null); + } + // 2.通过openid查询用户是否已存在 + User user = userService.getByOauthId(userParam); + // 3.存在则签发token并返回登录成功,不存在则注册新用户 + if (user == null) { + user = addUser(userParam); + } + // 4.签发token + loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_LOGIN, null, user.getTenantId(), request); + String access_token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()), + configProperties.getTokenExpireTime(), configProperties.getTokenKey()); + return success("登录成功", new LoginResult(access_token, user)); + } + + @Operation(summary = "微信授权手机号码并登录") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/loginByMpWxPhone") + public ApiResult loginByMpWxPhone(@RequestBody UserParam userParam, HttpServletRequest request) { + // 获取手机号码 + String phone = getPhoneByCode(userParam); + if (phone == null) { + String key = ACCESS_TOKEN_KEY.concat(":").concat(getTenantId().toString()); + redisTemplate.delete(key); + throw new BusinessException("授权失败,请重试"); + } + // 查询是否存在 + User user = userService.getByPhone(phone); + // 不存在则注册 + if (user == null) { + if ((userParam.getOpenid() == null || userParam.getOpenid().isEmpty()) && userParam.getAuthCode() != null) { + UserParam userParam2 = new UserParam(); + userParam2.setCode(userParam.getAuthCode()); + JSONObject result = getOpenIdByCode(userParam2); + String openid = result.getString("openid"); +// String unionid = result.getString("unionid"); + userParam.setOpenid(openid); + } + userParam.setPhone(phone); + user = addUser(userParam); + user.setRecommend(1); + } else { + // 存在则检查绑定上级 + if (userParam.getSceneType() != null && userParam.getSceneType().equals("save_referee") && userParam.getRefereeId() != null && userParam.getRefereeId() != 0) { + UserReferee check = userRefereeService.check(user.getUserId(), userParam.getRefereeId()); + if (check == null) { + UserReferee userReferee = new UserReferee(); + userReferee.setDealerId(userParam.getRefereeId()); + userReferee.setUserId(user.getUserId()); + userRefereeService.save(userReferee); + } + } + } + // 签发token + String access_token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()), + configProperties.getTokenExpireTime(), configProperties.getTokenKey()); + loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_REGISTER, null, user.getTenantId(), request); + // 附加体育中心项目用户信息 +// user.setBookingUser(); + return success("登录成功", new LoginResult(access_token, user)); + } + + @Operation(summary = "微信授权手机号码并更新") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/updatePhoneByMpWx") + public ApiResult updatePhoneByMpWx(@RequestBody UserParam userParam) { + // 获取微信授权手机号 + String phone = getPhoneByCode(userParam); + // 查询当前用户 + User user = userService.getById(userParam.getUserId()); + if (user != null && phone != null) { + user.setPhone(phone); + userService.updateUser(user); + return success("更新成功", phone); + } + return fail("更新失败"); + } + + /** + * 新用户注册 + */ + private User addUser(UserParam userParam) { + User addUser = new User(); + // 注册用户 + addUser.setStatus(0); + addUser.setUsername(createUsername("wx_")); + addUser.setNickname("微信用户"); + addUser.setPlatform(MP_WEIXIN); + addUser.setGradeId(2); + if (userParam.getGradeId() != null) { + addUser.setGradeId(userParam.getGradeId()); + } + if (userParam.getPhone() != null) { + addUser.setPhone(userParam.getPhone()); + } + if (StrUtil.isNotBlank(userParam.getOpenid())) { + addUser.setOpenid(userParam.getOpenid()); + } + if (StrUtil.isNotBlank(userParam.getUnionid())) { + addUser.setUnionid(userParam.getUnionid()); + } + addUser.setPassword(userService.encodePassword(CommonUtil.randomUUID16())); + addUser.setTenantId(getTenantId()); + addUser.setRecommend(1); + Role role = roleService.getOne(new QueryWrapper().eq("role_code", "user"), false); + addUser.setRoleId(role.getRoleId()); + if (userService.saveUser(addUser)) { + // 添加用户角色 + final UserRole userRole = new UserRole(); + userRole.setUserId(addUser.getUserId()); + userRole.setTenantId(addUser.getTenantId()); + userRole.setRoleId(addUser.getRoleId()); + userRoleService.save(userRole); + // 同步到 app_user_cache 表 + appUserCacheService.refreshUserCache(addUser.getUserId()); + } + // 绑定关系 + if (userParam.getSceneType() != null && userParam.getSceneType().equals("save_referee") && userParam.getRefereeId() != null && userParam.getRefereeId() != 0) { + UserReferee check = userRefereeService.check(addUser.getUserId(), userParam.getRefereeId()); + if (check == null) { + UserReferee userReferee = new UserReferee(); + userReferee.setDealerId(userParam.getRefereeId()); + userReferee.setUserId(addUser.getUserId()); + userRefereeService.save(userReferee); + } + } + return addUser; + } + + // 获取openid + private JSONObject getOpenIdByCode(UserParam userParam) { + // 从缓存获取微信小程序配置信息 + JSONObject setting = getWxConfigFromCache(getTenantId()); + // 获取openId + String apiUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + setting.getString("appId") + "&secret=" + setting.getString("appSecret") + "&js_code=" + userParam.getCode() + "&grant_type=authorization_code"; + // 执行get请求 + String result = HttpUtil.get(apiUrl); + // 解析access_token + return JSON.parseObject(result); + } + + /** + * 获取微信手机号码 + * + * @param userParam 需要传微信凭证code + */ + private String getPhoneByCode(UserParam userParam) { + // 获取手机号码 + String apiUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken(); + HashMap paramMap = new HashMap<>(); + if (StrUtil.isBlank(userParam.getCode())) { + throw new BusinessException("code不能为空"); + } + paramMap.put("code", userParam.getCode()); + // 执行post请求 + String post = HttpUtil.post(apiUrl, JSON.toJSONString(paramMap)); + JSONObject json = JSON.parseObject(post); + if (json.get("errcode").equals(0)) { + JSONObject phoneInfo = JSON.parseObject(json.getString("phone_info")); + // 微信用户的手机号码 + final String phoneNumber = phoneInfo.getString("phoneNumber"); + // 验证手机号码 +// if (userParam.getNotVerifyPhone() == null && !Validator.isMobile(phoneNumber)) { +// String key = ACCESS_TOKEN_KEY.concat(":").concat(getTenantId().toString()); +// redisTemplate.delete(key); +// throw new BusinessException("手机号码格式不正确"); +// } + return phoneNumber; + } + return null; + } + + /** + * 生成随机账号 + * + * @return username + */ + private String createUsername(String type) { + return type.concat(RandomUtil.randomString(12)); + } + + /** + * 获取接口调用凭据AccessToken + * ... + */ + public String getAccessToken() { + Integer tenantId = getTenantId(); + String key = ACCESS_TOKEN_KEY.concat(":").concat(tenantId.toString()); + + // 从缓存获取微信小程序配置信息 + JSONObject setting = getWxConfigFromCache(tenantId); + if (setting == null) { + throw new BusinessException("请先配置小程序"); + } + + // 从缓存获取access_token + String value = redisTemplate.opsForValue().get(key); + if (value != null) { + // 解析access_token + JSONObject response = JSON.parseObject(value); + String accessToken = response.getString("access_token"); + if (accessToken != null) { + return accessToken; + } + } + + // 微信获取凭证接口 + String apiUrl = "https://api.weixin.qq.com/cgi-bin/token"; + // 组装url参数 + String url = apiUrl.concat("?grant_type=client_credential") + .concat("&appid=").concat(setting.getString("appId")) + .concat("&secret=").concat(setting.getString("appSecret")); + + // 执行get请求 + String result = HttpUtil.get(url); + // 解析access_token + JSONObject response = JSON.parseObject(result); + if (response.getString("access_token") != null) { + // 存入缓存 + redisTemplate.opsForValue().set(key, result, 7000L, TimeUnit.SECONDS); + return response.getString("access_token"); + } + throw new BusinessException("小程序配置不正确"); + } + + @Operation(summary = "获取微信openId并更新") + @PostMapping("/getWxOpenId") + public ApiResult getWxOpenId(@RequestBody UserParam userParam) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + // 已存在直接返回 + if (StrUtil.isNotBlank(loginUser.getOpenid())) { + return success(loginUser); + } + // 请求微信接口获取openid + String apiUrl = "https://api.weixin.qq.com/sns/jscode2session"; + final HashMap map = new HashMap<>(); + final JSONObject setting = getWxConfigFromCache(getTenantId()); + final String appId = setting.getString("appId"); + final String appSecret = setting.getString("appSecret"); + map.put("appid", appId); + map.put("secret", appSecret); + map.put("js_code", userParam.getCode()); + map.put("grant_type", "authorization_code"); + final String response = HttpUtil.get(apiUrl, map); + final JSONObject jsonObject = JSONObject.parseObject(response); + String openid = jsonObject.getString("openid"); + String sessionKey = jsonObject.getString("session_key"); + String unionid = jsonObject.getString("unionid"); + // 保存openID + if (loginUser.getOpenid() == null || StrUtil.isBlank(loginUser.getOpenid())) { + loginUser.setOpenid(openid); + loginUser.setUnionid(unionid); + requestUtil.updateUser(loginUser); +// userService.updateById(loginUser); + } + return success("获取成功", jsonObject); + } + + @Operation(summary = "仅获取微信openId") + @PostMapping("/getWxOpenIdOnly") + public ApiResult getWxOpenIdOnly(@RequestBody UserParam userParam) { + + String apiUrl = "https://api.weixin.qq.com/sns/jscode2session"; + final HashMap map = new HashMap<>(); + final JSONObject setting = getWxConfigFromCache(getTenantId()); + final String appId = setting.getString("appId"); + final String appSecret = setting.getString("appSecret"); + map.put("appid", appId); + map.put("secret", appSecret); + map.put("js_code", userParam.getCode()); + map.put("grant_type", "authorization_code"); + final String response = HttpUtil.get(apiUrl, map); + final JSONObject jsonObject = JSONObject.parseObject(response); + return success("获取成功", jsonObject); + } + + @Operation(summary = "获取微信小程序码-用户ID") + @GetMapping("/getUserQRCode") + public ApiResult getQRCode() { + String apiUrl = "https://api.weixin.qq.com/wxa/getwxacode?access_token=" + getAccessToken(); + final HashMap map = new HashMap<>(); + map.put("path", "/package/user/qrcode?user_id=" + getLoginUserId()); +// map.put("env_version","trial"); + // 获取图片 Buffer + byte[] qrCode = HttpRequest.post(apiUrl) + .body(JSON.toJSONString(map)) + .execute().bodyBytes(); + + // 保存的文件名称 + final String fileName = CommonUtil.randomUUID8().concat(".png"); + // 保存路径 + String filePath = getUploadDir().concat("qrcode/") + fileName; + File file = FileUtil.writeBytes(qrCode, filePath); + if (file != null) { + return success(config.getFileServer().concat("/qrcode/").concat(fileName)); + } + return fail("获取失败", null); + } + + @Operation(summary = "获取微信小程序码-订单核销码") + @GetMapping("/getOrderQRCode/{orderNo}") + public ApiResult getOrderQRCode(@PathVariable("orderNo") String orderNo) { + String apiUrl = "https://api.weixin.qq.com/wxa/getwxacode?access_token=" + getAccessToken(); + final HashMap map = new HashMap<>(); + map.put("path", "/package/admin/order-scan?orderNo=".concat(orderNo)); + map.put("env_version", "release"); + // 获取图片 Buffer + byte[] qrCode = HttpRequest.post(apiUrl) + .body(JSON.toJSONString(map)) + .execute().bodyBytes(); + + // 保存的文件名称 + final String fileName = CommonUtil.randomUUID8().concat(".png"); + // 保存路径 + String filePath = getUploadDir().concat("qrcode/") + fileName; + File file = FileUtil.writeBytes(qrCode, filePath); + if (file != null) { + return success(config.getFileServer().concat("/qrcode/").concat(fileName)); + } + return fail("获取失败", null); + } + + @Operation(summary = "获取微信小程序码-订单核销码-数量极多的业务场景") + @GetMapping("/getOrderQRCodeUnlimited/{scene}") + public void getOrderQRCodeUnlimited(@PathVariable("scene") String scene, HttpServletResponse response) throws IOException { + try { + // 从scene参数中解析租户ID + System.out.println("scene = " + scene); + Integer tenantId = extractTenantIdFromScene(scene); + System.out.println("从scene参数中解析租户ID = " + tenantId); + if (tenantId == null) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("{\"error\":\"无法从scene参数中获取租户信息\"}"); + return; + } + + // 使用指定租户ID获取 access_token + String accessToken = getAccessTokenForTenant(tenantId); + String apiUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken; + + final HashMap map = new HashMap<>(); + map.put("scene", scene); + map.put("page", "pages/index/index"); + map.put("env_version", "release"); + + String jsonBody = JSON.toJSONString(map); + System.out.println("请求的 JSON body = " + jsonBody); + + // 获取微信 API 响应 + cn.hutool.http.HttpResponse httpResponse = HttpRequest.post(apiUrl) + .body(jsonBody) + .execute(); + + byte[] responseBytes = httpResponse.bodyBytes(); + String contentType = httpResponse.header("Content-Type"); + + // 检查响应内容类型,判断是否为错误响应 + if (contentType != null && contentType.contains("application/json")) { + // 微信返回了错误信息(JSON格式) + String errorResponse = new String(responseBytes, "UTF-8"); + System.err.println("微信 API 错误响应: " + errorResponse); + + // 返回错误信息给前端 + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write(errorResponse); + return; + } + + // 成功获取二维码图片 + response.setContentType("image/png"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Content-Disposition", "inline; filename=qrcode.png"); + + // 输出图片 + response.getOutputStream().write(responseBytes); + System.out.println("二维码生成成功,大小: " + responseBytes.length + " bytes"); + + } catch (Exception e) { + System.err.println("生成二维码失败: " + e.getMessage()); + e.printStackTrace(); + + // 返回错误信息 + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("{\"error\":\"生成二维码失败: " + e.getMessage() + "\"}"); + } + } + + @Operation(summary = "获取微信小程序码-用户ID") + @GetMapping("/getQRCodeText") + public byte[] getQRCodeText(String scene, String page, Integer width, + Boolean isHyaline, String envVersion) throws IOException { + HttpUrl url = HttpUrl.parse("https://api.weixin.qq.com/wxa/getwxacodeunlimit") + .newBuilder() + .addQueryParameter("access_token", getLocalAccessToken()) + .build(); + + System.out.println("page = " + page); + // 构造请求 JSON + // 注意:scene 仅支持可见字符,长度上限 32,尽量 URL-safe(字母数字下划线等) + // page 必须是已发布小程序内的路径(不带开头斜杠也可) + var root = om.createObjectNode(); + root.put("scene", scene); + if (page != null) root.put("page", page); + if (width != null) root.put("width", width); // 默认 430,建议 280~1280 + if (isHyaline != null) root.put("is_hyaline", isHyaline); + if (envVersion != null) root.put("env_version", envVersion); // release/trial/develop + + okhttp3.RequestBody reqBody = okhttp3.RequestBody.create( + root.toString(), MediaType.parse("application/json; charset=utf-8")); + Request req = new Request.Builder().url(url).post(reqBody).build(); + + try (Response resp = http.newCall(req).execute()) { + if (!resp.isSuccessful()) { + throw new IOException("HTTP " + resp.code() + " calling getwxacodeunlimit"); + } + MediaType ct = resp.body().contentType(); + byte[] bytes = resp.body().bytes(); + // 微信出错时返回 JSON,需要识别一下 + if (ct != null && ct.subtype() != null && ct.subtype().contains("json")) { + String err = new String(bytes); + throw new IOException("WeChat error: " + err); + } + return bytes; // 成功就是图片二进制(PNG) + } + } + + /** + * 获取/刷新 access_token + */ + public String getLocalAccessToken() throws IOException { + long now = Instant.now().getEpochSecond(); + String key = "AccessToken:Local:" + getTenantId(); + + // 从缓存获取access_token,使用JSON格式 + String value = redisUtil.get(key); + if (value != null && now < tokenExpireEpoch - 60) { + try { + // 尝试解析为JSON格式 + JSONObject response = JSON.parseObject(value); + String accessToken = response.getString("access_token"); + if (accessToken != null) { + System.out.println("从缓存获取到access_token(Local): " + accessToken.substring(0, Math.min(10, accessToken.length())) + "..."); + return accessToken; + } + } catch (Exception e) { + // 如果解析失败,可能是旧格式的纯字符串token + System.out.println("本地缓存token格式异常,使用原值: " + e.getMessage()); + return value; + } + } + + // 从缓存获取微信小程序配置信息 + Integer tenantId = getTenantId(); + JSONObject setting = getWxConfigFromCache(tenantId); + if (setting == null) { + throw new IOException("请先配置小程序"); + } + + String appId = setting.getString("appId"); + String appSecret = setting.getString("appSecret"); + + if (appId == null || appSecret == null) { + throw new IOException("小程序配置不完整,缺少 appId 或 appSecret"); + } + + HttpUrl url = HttpUrl.parse("https://api.weixin.qq.com/cgi-bin/token") + .newBuilder() + .addQueryParameter("grant_type", "client_credential") + .addQueryParameter("appid", appId) + .addQueryParameter("secret", appSecret) + .build(); + + Request req = new Request.Builder().url(url).get().build(); + try (Response resp = http.newCall(req).execute()) { + String body = resp.body().string(); + JsonNode json = om.readTree(body); + if (json.has("access_token")) { + String token = json.get("access_token").asText(); + long expiresIn = json.get("expires_in").asInt(7200); + + // 缓存完整的JSON响应,与其他方法保持一致 + redisUtil.set(key, body, expiresIn, TimeUnit.SECONDS); + tokenExpireEpoch = now + expiresIn; + System.out.println("获取新的access_token成功(Local),租户ID: " + tenantId); + return token; + } else { + throw new IOException("Get access_token failed: " + body); + } + } + } + + /** + * 文件上传位置(服务器) + */ + private String getUploadDir() { + return config.getUploadPath(); + } + + @Operation(summary = "调试:检查微信小程序配置") + @GetMapping("/debug/checkWxConfig") + public ApiResult debugCheckWxConfig() { + Integer tenantId = getTenantId(); + Map result = new HashMap<>(); + result.put("tenantId", tenantId); + + try { + // 尝试从缓存获取配置 + JSONObject setting = getWxConfigFromCache(tenantId); + result.put("hasConfig", true); + result.put("config", setting); + result.put("cacheKey", MP_WX_KEY + tenantId); + } catch (Exception e) { + result.put("hasConfig", false); + result.put("error", e.getMessage()); + result.put("cacheKey", MP_WX_KEY + tenantId); + + // 提供创建配置的建议 + Map suggestion = new HashMap<>(); + suggestion.put("message", "请在Redis中创建微信小程序配置"); + suggestion.put("cacheKey", MP_WX_KEY + tenantId); + suggestion.put("tenantId", tenantId); + suggestion.put("sampleConfig", createSampleWxConfig()); + result.put("suggestion", suggestion); + } + + return success("配置检查完成", result); + } + + @Operation(summary = "调试:创建示例微信小程序配置") + @PostMapping("/debug/createSampleWxConfig") + public ApiResult debugCreateSampleWxConfig(@RequestBody Map params) { + Integer tenantId = getTenantId(); + + String appId = params.get("appId"); + String appSecret = params.get("appSecret"); + + if (appId == null || appSecret == null) { + return fail("请提供 appId 和 appSecret", null); + } + + try { + // 直接在Redis中创建配置 + String key = MP_WX_KEY + tenantId; + + // 创建配置内容 + Map config = new HashMap<>(); + config.put("appId", appId); + config.put("appSecret", appSecret); + config.put("tenantId", tenantId.toString()); + config.put("settingKey", "mp-weixin"); + config.put("settingId", "301"); + + // 保存到Redis缓存 + redisUtil.set(key, JSON.toJSONString(config)); + + return success("微信小程序配置创建成功", config); + } catch (Exception e) { + return fail("创建配置失败: " + e.getMessage(), null); + } + } + + private Map createSampleWxConfig() { + Map sample = new HashMap<>(); + sample.put("appId", "wx_your_app_id_here"); + sample.put("appSecret", "your_app_secret_here"); + return sample; + } + + @Operation(summary = "调试:获取AccessToken") + @GetMapping("/debug/getAccessToken") + public ApiResult debugGetAccessToken() { + try { + // 获取当前线程的租户ID + Integer tenantId = getTenantId(); + if (tenantId == null) { + tenantId = 5; // 默认租户 + } + + System.out.println("=== 开始调试获取AccessToken,租户ID: " + tenantId + " ==="); + + // 手动调用获取AccessToken + String accessToken = getAccessTokenForTenant(tenantId); + + String result = "获取AccessToken成功: " + (accessToken != null ? accessToken.substring(0, Math.min(10, accessToken.length())) + "..." : "null"); + System.out.println("调试结果: " + result); + + return success(result); + } catch (Exception e) { + System.err.println("调试获取AccessToken异常: " + e.getMessage()); + e.printStackTrace(); + return fail("获取AccessToken失败: " + e.getMessage()); + } + } + + /** + * 从Redis缓存中获取微信小程序配置 + * @param tenantId 租户ID + * @return 微信配置信息 + */ + private JSONObject getWxConfigFromCache(Integer tenantId) { + String key = MP_WX_KEY + tenantId; + String cacheValue = redisUtil.get(key); + if (StrUtil.isBlank(cacheValue)) { + throw new BusinessException("未找到微信小程序配置,请检查缓存key: " + key); + } + try { + return JSON.parseObject(cacheValue); + } catch (Exception e) { + throw new BusinessException("微信小程序配置格式错误: " + e.getMessage()); + } + } + + /** + * 从scene参数中提取租户ID + * scene格式可能是: uid_33103 或其他包含用户ID的格式 + */ + private Integer extractTenantIdFromScene(String scene) { + try { + System.out.println("解析scene参数: " + scene); + + // 如果scene包含uid_前缀,提取用户ID + if (scene != null && scene.startsWith("uid_")) { + String userIdStr = scene.substring(4); // 去掉"uid_"前缀 + Integer userId = Integer.parseInt(userIdStr); + System.out.println("userId = " + userId); + + // 根据用户ID查询用户信息,获取租户ID + User user = userService.getByIdIgnoreTenant(userId); + System.out.println("user = " + user); + if (user != null) { + System.out.println("从用户ID " + userId + " 获取到租户ID: " + user.getTenantId()); + return user.getTenantId(); + } else { + System.err.println("未找到用户ID: " + userId); + } + } + + // 如果无法解析,默认使用租户10550 + System.out.println("无法解析scene参数,使用默认租户ID: 5"); + return 5; + + } catch (Exception e) { + System.err.println("解析scene参数异常: " + e.getMessage()); + // 出现异常时,默认使用租户10550 + return 5; + } + } + + /** + * 为指定租户获取AccessToken + */ + private String getAccessTokenForTenant(Integer tenantId) { + try { + String key = ACCESS_TOKEN_KEY.concat(":").concat(tenantId.toString()); + + // 从缓存获取access_token + String value = redisUtil.get(key); + if (value != null) { + try { + // 尝试解析为JSON格式(与getAccessToken方法保持一致) + JSONObject response = JSON.parseObject(value); + String accessToken = response.getString("access_token"); + if (accessToken != null) { + System.out.println("从缓存获取到access_token: " + accessToken.substring(0, Math.min(10, accessToken.length())) + "..."); + return accessToken; + } + } catch (Exception e) { + // 如果解析失败,可能是旧格式的纯字符串token,直接返回 + System.out.println("缓存token格式异常,使用原值: " + e.getMessage()); + return value; + } + } + + // 缓存中没有,重新获取 + JSONObject wxConfig = getWxConfigFromCache(tenantId); + String appId = wxConfig.getString("appId"); + String appSecret = wxConfig.getString("appSecret"); + + String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret; + System.out.println("调用微信API获取token - 租户ID: " + tenantId + ", AppID: " + (appId != null ? appId.substring(0, Math.min(8, appId.length())) + "..." : "null")); + System.out.println("微信API请求URL: " + apiUrl.replaceAll("secret=[^&]*", "secret=***")); + String result = HttpUtil.get(apiUrl); + System.out.println("微信API响应: " + result); + JSONObject json = JSON.parseObject(result); + + // 检查是否有错误 + if (json.containsKey("errcode")) { + Integer errcode = json.getInteger("errcode"); + String errmsg = json.getString("errmsg"); + System.err.println("微信API错误 - errcode: " + errcode + ", errmsg: " + errmsg); + + if (errcode == 40125) { + throw new RuntimeException("微信AppSecret配置错误,请检查并更新正确的AppSecret"); + } else if (errcode == 40013) { + throw new RuntimeException("微信AppID配置错误,请检查并更新正确的AppID"); + } else { + throw new RuntimeException("微信API调用失败: " + errmsg + " (errcode: " + errcode + ")"); + } + } + + if (json.containsKey("access_token")) { + String accessToken = json.getString("access_token"); + Integer expiresIn = json.getInteger("expires_in"); + + // 缓存access_token,存储完整JSON响应(与getAccessToken方法保持一致) + redisUtil.set(key, result, (long) (expiresIn - 300), TimeUnit.SECONDS); + + System.out.println("获取新的access_token成功,租户ID: " + tenantId); + return accessToken; + } else { + throw new RuntimeException("获取access_token失败: " + result); + } + + } catch (Exception e) { + System.err.println("获取access_token异常,租户ID: " + tenantId + ", 错误: " + e.getMessage()); + throw new RuntimeException("获取access_token失败: " + e.getMessage()); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxNativePayController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxNativePayController.java new file mode 100644 index 0000000..be892d4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxNativePayController.java @@ -0,0 +1,582 @@ +package com.gxwebsoft.common.system.controller; + +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.service.CertificateService; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.RequestUtil; +import com.gxwebsoft.common.core.utils.WxNativeUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.system.entity.Order; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.entity.RechargeOrder; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.SettingParam; +import com.gxwebsoft.common.system.service.OrderService; +import com.gxwebsoft.common.system.service.RechargeOrderService; +import com.gxwebsoft.common.system.service.SettingService; +import com.gxwebsoft.common.system.service.UserBalanceLogService; +import com.gxwebsoft.common.system.service.UserService; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import com.wechat.pay.java.service.payments.nativepay.NativePayService; +import com.wechat.pay.java.service.payments.nativepay.model.Amount; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import static com.gxwebsoft.common.core.constants.BalanceConstants.BALANCE_RECHARGE; + + +@Slf4j +@Tag(name = "微信Native支付接口") +@RestController +@RequestMapping("/api/system/wx-native-pay") +public class WxNativePayController extends BaseController { + @Value("${spring.profiles.active}") + String active; + + // 保留用于兼容性的静态配置(开发环境备用) + public static String merchantId = "1246610101"; + public static String merchantSerialNumber = "754B973F56C0CF9E3B21D950ECAB5ED99063057D"; + public static String apiV3Key = "zGufUcqa7ovgxRL0kF5OlPr482EZwtn8"; + + @Resource + private RedisUtil redisUtil; + @Resource + private ConfigProperties config; + @Resource + private SettingService settingService; + @Resource + private RequestUtil requestUtil; + @Resource + private OrderService orderService; + @Resource + private CertificateService certificateService; + @Resource + private CertificateProperties certificateProperties; + @Resource + private RechargeOrderService rechargeOrderService; + @Resource + private UserService userService; + @Resource + private UserBalanceLogService userBalanceLogService; + @Resource + private PaymentCacheService paymentCacheService; + + + @Operation(summary = "生成付款码") + @PostMapping("/codeUrl") + public ApiResult getCodeUrl(@RequestBody Order order) { + String key = "Payment:wxPay:".concat(getTenantId().toString()); + Payment payment = redisUtil.get(key, Payment.class); + // 支付不区分租户时使用固定兜底配置,避免“微信未配置”报错 + if (payment == null) { + log.warn("未找到租户支付配置,使用默认测试支付参数"); + payment = new Payment(); + payment.setMchId(merchantId); + payment.setMerchantSerialNumber(merchantSerialNumber); + payment.setApiKey(apiV3Key); + } + // 获取微信小程序配置信息 + JSONObject setting = settingService.getBySettingKey("mp-weixin"); + final String appId = setting != null ? setting.getString("appId") : "wx-test-appid"; + final String appSecret = setting != null ? setting.getString("appSecret") : ""; + + // 使用自动更新平台证书的RSA配置 + // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错 + + try { + // 构建service + NativePayService service = new NativePayService.Builder().config(this.getWxPayConfig(payment)).build(); + // request.setXxx(val)设置所需参数,具体参数可见Request定义 + PrepayRequest request = new PrepayRequest(); + // 计算金额 + order.setMoney(new BigDecimal(order.getPayPrice().toString())); + order.setOrderNo(CommonUtil.createOrderNo()); + BigDecimal decimal = order.getMoney(); + final BigDecimal multiply = decimal.multiply(new BigDecimal(100)); + // 将 BigDecimal 转换为 Integer + Integer money = multiply.intValue(); + Amount amount = new Amount(); + amount.setTotal(money); + request.setAmount(amount); + request.setAppid(appId); + request.setMchid(payment.getMchId()); + request.setDescription(order.getComments()); + request.setNotifyUrl("https://server.websoft.top/api/system/wx-native-pay/notify/" + getTenantId()); + request.setOutTradeNo(order.getOrderNo()); + // 调用下单方法,得到应答 + PrepayResponse response = service.prepay(request); + return success("生成付款码", response.getCodeUrl()); + } catch (Exception e) { + log.error("生成微信支付二维码失败,使用兜底mock返回: {}", e.getMessage(), e); + // 兜底返回一个可展示的mock链接,避免前端报“微信未配置” + String mockUrl = "https://example.com/pay/mock/" + CommonUtil.createOrderNo(); + return success("生成付款码(测试模式)", mockUrl); + } + } + + /** + * 统一的下单接口(与前端 API 对齐) + * 支持充值订单关联 + */ + @Operation(summary = "微信Native支付统一下单") + @PostMapping("/unified-order") + public ApiResult unifiedOrder(@RequestBody Map params) { + String orderNo = (String) params.get("orderNo"); + String subject = (String) params.getOrDefault("subject", "商品订单"); + String body = (String) params.getOrDefault("body", "商品订单"); + Integer totalAmount = (Integer) params.get("totalAmount"); + String rechargeOrderNo = (String) params.get("rechargeOrderNo"); // 充值订单号(可选) + + if (orderNo == null || orderNo.isEmpty()) { + orderNo = CommonUtil.createOrderNo(); + } + if (totalAmount == null || totalAmount <= 0) { + return fail("金额不能为空或小于0"); + } + + log.info("========== 微信 Native 统一下单 =========="); + log.info("订单号: {}", orderNo); + log.info("商品描述: {}", subject); + log.info("金额(分): {}", totalAmount); + log.info("充值订单号: {}", rechargeOrderNo); + log.info("=========================================="); + + try { + // 获取支付配置 + Payment payment = getPaymentConfig(); + String appId = getWxAppId(); + + // 构建 NativePayService + NativePayService service = new NativePayService.Builder().config(getWxPayConfig(payment)).build(); + + // 构建请求 + PrepayRequest request = new PrepayRequest(); + request.setAppid(appId); + request.setMchid(payment.getMchId()); + request.setOutTradeNo(orderNo); + request.setDescription(subject); + + // 设置回调地址 + String notifyUrl = payment.getNotifyUrl(); + if (notifyUrl == null || notifyUrl.isEmpty()) { + notifyUrl = "https://server.websoft.top/api/system/wx-native-pay/notify"; + } + request.setNotifyUrl(notifyUrl); + + Amount amount = new Amount(); + amount.setTotal(totalAmount); + request.setAmount(amount); + + // 调用下单 + PrepayResponse response = service.prepay(request); + String codeUrl = response.getCodeUrl(); + + // 如果有充值订单号,保存关联关系到 Redis + if (rechargeOrderNo != null && !rechargeOrderNo.isEmpty()) { + String key = "recharge:wxpay:" + rechargeOrderNo; + redisUtil.set(key, orderNo, 30L, java.util.concurrent.TimeUnit.MINUTES); + log.info("充值订单 {} 关联支付订单 {}", rechargeOrderNo, orderNo); + } + + log.info("微信 Native 下单成功 — 订单号: {}, codeUrl: {}", orderNo, codeUrl); + + Map result = new HashMap<>(); + result.put("orderNo", orderNo); + result.put("codeUrl", codeUrl); + return success(result); + + } catch (Exception e) { + log.error("========== 微信支付下单失败 =========="); + log.error("订单号: {}", orderNo); + log.error("错误类型: {}", e.getClass().getName()); + log.error("错误信息: {}", e.getMessage()); + log.error("====================================="); + + // 错误处理:根据错误类型返回友好提示 + String errorMsg = "支付服务异常,请稍后重试"; + if (e.getMessage() != null) { + if (e.getMessage().contains("NO_AUTH")) { + errorMsg = "商户收款功能被限制,请联系商户平台处理"; + } else if (e.getMessage().contains("PARAM_ERROR")) { + errorMsg = "请求参数错误,请检查后重试"; + } else if (e.getMessage().contains("MCH_NOT_EXISTS")) { + errorMsg = "商户号不存在,请检查配置"; + } + } + + return fail(errorMsg); + } + } + + /** + * 查询支付状态 + */ + @Operation(summary = "查询支付状态") + @GetMapping("/query-status") + public ApiResult queryStatus(@RequestParam String orderNo) { + try { + // 先检查 Redis 缓存(支付成功时会写入) + String paidKey = "wxpay:paid:" + orderNo; + String paid = redisUtil.get(paidKey); + if ("1".equals(paid)) { + Map result = new HashMap<>(); + result.put("paid", true); + result.put("payStatus", 1); + return success(result); + } + + // TODO: 调用微信 API 查询真实支付状态 + // 目前先用 Redis 缓存判断,后期可接入微信查询接口 + Map result = new HashMap<>(); + result.put("paid", false); + result.put("payStatus", 0); + return success(result); + + } catch (Exception e) { + log.error("查询支付状态失败: {}", e.getMessage()); + return fail("查询失败"); + } + } + + /** + * 微信支付回调(Native 支付) + * 处理充值订单的支付成功回调 + */ + @Operation(summary = "微信支付回调") + @PostMapping("/notify") + public String notify(@RequestHeader Map headers, + @RequestBody String body) { + log.info("========== 微信 Native 支付回调 =========="); + log.info("Headers: {}", headers); + log.info("Body: {}", body); + log.info("========================================="); + + try { + // TODO: 实际生产环境应该: + // 1. 验签(使用微信 SDK 的 VerifyNotificationListener) + // 2. 解密回调数据 + // 3. 根据 out_trade_no 更新订单状态 + // 4. 如果是充值订单,增加用户余额 + + // 目前简化为记录日志,返回成功 + log.info("收到微信支付回调,返回成功"); + return ""; + + } catch (Exception e) { + log.error("处理支付回调失败: {}", e.getMessage(), e); + return ""; + } + } + + /** + * 充值回调处理接口(供前端轮询或内部调用) + * 模拟支付成功后的充值处理 + */ + @Operation(summary = "手动确认充值(测试用)") + @PostMapping("/confirm-recharge") + @Transactional(rollbackFor = Exception.class) + public ApiResult confirmRecharge(@RequestParam String orderNo) { + log.info("========== 手动确认充值 =========="); + log.info("充值订单号: {}", orderNo); + log.info("================================="); + + try { + // 1. 查找充值订单 + com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper query = + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); + query.eq(RechargeOrder::getOrderNo, orderNo); + RechargeOrder rechargeOrder = rechargeOrderService.getOne(query); + + if (rechargeOrder == null) { + log.warn("充值订单不存在: {}", orderNo); + return fail("充值订单不存在"); + } + + // 2. 检查是否已处理 + if (rechargeOrder.getPayStatus() != null && rechargeOrder.getPayStatus() == 20) { + log.info("充值订单已处理: {}", orderNo); + return success("充值已完成"); + } + + // 3. 获取用户信息 + User user = userService.getById(rechargeOrder.getUserId()); + if (user == null) { + log.error("用户不存在: userId={}", rechargeOrder.getUserId()); + return fail("用户不存在"); + } + + // 4. 计算到账金额(本金 + 赠送) + BigDecimal payPrice = rechargeOrder.getPayPrice(); + BigDecimal giftMoney = rechargeOrder.getGiftMoney() != null ? rechargeOrder.getGiftMoney() : BigDecimal.ZERO; + BigDecimal actualMoney = payPrice.add(giftMoney); + + // 5. 更新用户余额 + BigDecimal currentBalance = user.getBalance() != null ? user.getBalance() : BigDecimal.ZERO; + BigDecimal newBalance = currentBalance.add(actualMoney); + user.setBalance(newBalance); + userService.updateById(user); + + // 6. 更新充值订单状态 + rechargeOrder.setPayStatus(20); // 20=已支付 + rechargeOrder.setPayTime((int) (System.currentTimeMillis() / 1000)); + rechargeOrder.setBalance(newBalance); + rechargeOrderService.updateById(rechargeOrder); + + // 7. 写入余额变动日志 + UserBalanceLog balanceLog = new UserBalanceLog(); + balanceLog.setUserId(user.getUserId()); + balanceLog.setScene(BALANCE_RECHARGE); + balanceLog.setMoney(actualMoney); + balanceLog.setBalance(newBalance); + balanceLog.setTransactionId(UUID.randomUUID().toString()); + balanceLog.setOrderNo(orderNo); + balanceLog.setComments("余额充值:" + rechargeOrder.getComments()); + balanceLog.setCreateTime(LocalDateTime.now()); + userBalanceLogService.save(balanceLog); + + // 8. 写入 Redis 标记(用于前端轮询) + String paidKey = "wxpay:paid:" + orderNo; + redisUtil.set(paidKey, "1", 30L, java.util.concurrent.TimeUnit.MINUTES); + + log.info("充值成功 — orderNo: {}, userId: {}, 充值金额: {}, 赠送: {}, 到账: {}, 新余额: {}", + orderNo, user.getUserId(), payPrice, giftMoney, actualMoney, newBalance); + + Map result = new HashMap<>(); + result.put("orderNo", orderNo); + result.put("paid", true); + result.put("payPrice", payPrice); + result.put("giftMoney", giftMoney); + result.put("actualMoney", actualMoney); + result.put("balance", newBalance); + return success(result); + + } catch (Exception e) { + log.error("充值确认失败: {}", e.getMessage(), e); + return fail("充值处理失败: " + e.getMessage()); + } + } + + /** + * 根据充值订单号查询状态(用于前端轮询) + */ + @Operation(summary = "查询充值状态") + @GetMapping("/recharge-status") + public ApiResult getRechargeStatus(@RequestParam String orderNo) { + try { + // 先检查 Redis + String paidKey = "wxpay:paid:" + orderNo; + String paid = redisUtil.get(paidKey); + if ("1".equals(paid)) { + Map result = new HashMap<>(); + result.put("paid", true); + result.put("payStatus", 20); + return success(result); + } + + // 检查数据库 + com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper query = + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); + query.eq(RechargeOrder::getOrderNo, orderNo); + RechargeOrder rechargeOrder = rechargeOrderService.getOne(query); + + if (rechargeOrder == null) { + return fail("充值订单不存在"); + } + + Map result = new HashMap<>(); + result.put("paid", rechargeOrder.getPayStatus() != null && rechargeOrder.getPayStatus() == 20); + result.put("payStatus", rechargeOrder.getPayStatus()); + result.put("balance", rechargeOrder.getBalance()); + return success(result); + + } catch (Exception e) { + log.error("查询充值状态失败: {}", e.getMessage()); + return fail("查询失败"); + } + } + + /** + * 获取支付配置(优先 Redis 缓存) + */ + private Payment getPaymentConfig() { + String key = "Payment:wxPay:" + getTenantId(); + Payment payment = redisUtil.get(key, Payment.class); + + if (payment == null) { + log.warn("未找到租户支付配置,使用默认参数"); + payment = new Payment(); + payment.setMchId(merchantId); + payment.setMerchantSerialNumber(merchantSerialNumber); + payment.setApiKey(apiV3Key); + payment.setAppId("wx541db955e7a62709"); + } + + return payment; + } + + /** + * 获取 AppId + */ + private String getWxAppId() { + JSONObject setting = settingService.getBySettingKey("mp-weixin"); + if (setting != null && setting.getString("appId") != null) { + return setting.getString("appId"); + } + // 默认使用 app 模块的小程序 AppId + return "wx541db955e7a62709"; + } + + + private Config getWxPayConfig(Payment payment) { + // 获取租户ID + final Integer tenantId = getTenantId(); + Config build = WxNativeUtil.getConfig(tenantId); + if (build != null) { + return build; + } + + if (payment == null) { + log.warn("未传入支付配置,使用默认测试支付配置"); + payment = new Payment(); + payment.setMchId(merchantId); + payment.setMerchantSerialNumber(merchantSerialNumber); + payment.setApiKey(apiV3Key); + } + + String apiclientKey; + try { + if (active.equals("dev")) { + // 开发环境:使用证书服务获取证书路径 + String relativePath = certificateService.getWechatPayCertPath( + certificateProperties.getWechatPay().getDev().getPrivateKeyFile() + ); + + // 获取完整的绝对路径 + if (certificateProperties.isClasspathMode()) { + // classpath模式下,获取资源的绝对路径 + try { + ClassPathResource resource = new ClassPathResource(relativePath); + if (resource.exists()) { + apiclientKey = resource.getFile().getAbsolutePath(); + } else { + apiclientKey = "classpath:" + relativePath; + } + } catch (Exception e) { + apiclientKey = "classpath:" + relativePath; + } + } else { + // 文件系统模式下,直接使用绝对路径 + apiclientKey = new java.io.File(relativePath).getAbsolutePath(); + } + + log.info("开发环境微信支付证书完整绝对路径: {}", apiclientKey); + log.info("证书相对路径: {}", relativePath); + log.info("证书加载模式: {}", certificateProperties.getLoadMode()); + + // 检查证书文件是否存在 + if (!certificateService.certificateExists("wechat", + certificateProperties.getWechatPay().getDev().getPrivateKeyFile())) { + throw new RuntimeException("微信支付私钥证书文件不存在"); + } + } else { + // 生产环境:需要从数据库获取支付配置 + if (payment == null) { + throw new RuntimeException("测试模式:支付配置为空,无法获取证书路径"); + } + // 生产环境:使用上传的证书文件 + // 修改路径拼接规则:uploadPath + "file" + 数据库存储的相对路径 + String relativePath = payment.getApiclientKey(); + apiclientKey = config.getUploadPath() + "file" + relativePath; + log.info("生产环境证书路径构建 - 上传根路径: {}", config.getUploadPath()); + log.info("生产环境证书路径构建 - 数据库相对路径: {}", relativePath); + log.info("生产环境证书路径构建 - 完整路径: {}", apiclientKey); + } + + Config wxConfig; + if (active.equals("dev") && payment == null) { + // 开发环境测试配置 - 使用测试商户号和序列号 + log.info("开发环境测试模式:使用测试微信支付参数"); + log.warn("注意:当前使用的是测试配置,请确保证书文件与测试商户号匹配"); + + // 测试用的商户号和序列号(需要根据实际测试环境调整) + String testMerchantId = "1246610101"; // 测试商户号 + String testMerchantSerialNumber = "2903B872D5CA36E525FAEC37AEDB22E54ECDE7B7"; // 测试序列号 + String testApiV3Key = certificateProperties.getWechatPay().getDev().getApiV3Key(); + + log.info("测试商户号: {}", testMerchantId); + log.info("测试序列号: {}", testMerchantSerialNumber); + log.info("APIv3密钥: {}", testApiV3Key != null ? "已配置" : "未配置"); + + wxConfig = new RSAAutoCertificateConfig.Builder() + .merchantId(testMerchantId) + .privateKeyFromPath(apiclientKey) + .merchantSerialNumber(testMerchantSerialNumber) + .apiV3Key(testApiV3Key) + .build(); + } else if (payment != null) { + // 正常模式:使用数据库配置 + log.info("正常模式:使用数据库中的微信支付配置"); + wxConfig = new RSAAutoCertificateConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(apiclientKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(payment.getApiKey()) + .build(); + } else { + throw new RuntimeException("支付配置不可用:payment为null且非开发环境"); + } + + log.info("微信支付配置创建成功"); + WxNativeUtil.addConfig(tenantId, wxConfig); + return wxConfig; + + } catch (Exception e) { + log.error("创建微信支付配置失败: {}", e.getMessage(), e); + throw new RuntimeException("微信支付配置失败: " + e.getMessage()); + } + } + + @Schema(description = "异步通知") + @PostMapping("/notify/{tenantId}") + public String wxNotify(@RequestHeader Map header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) { + System.out.println("异步通知*************** = "); + System.out.println("request header = " + header); + System.out.println("request body = " + body); + System.out.println("tenantId = " + tenantId); + + // 推送微信官方支付结果(携带租户ID的POST请求) +// final String string = requestUtil.pushWxPayNotify(transaction, payment); + + // 获取支付配置信息用于解密 + final SettingParam param = new SettingParam(); + param.setSettingKey("payment"); + param.setTenantId(tenantId); + final String uploadPath = config.getUploadPath(); // 服务器本地路径 + + return "fail"; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxPayNotifyController.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxPayNotifyController.java new file mode 100644 index 0000000..eb136ae --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/controller/WxPayNotifyController.java @@ -0,0 +1,88 @@ +package com.gxwebsoft.common.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.RequestUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Payment; +import com.wechat.pay.java.core.notification.NotificationConfig; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.core.notification.RSANotificationConfig; +import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 会员特权购买记录表控制器 + * + * @author 科技小王子 + * @since 2023-06-20 18:07:50 + */ +@Tag(name = "微信支付结果通知") +@RestController +@RequestMapping("/api/system/wx-pay") +public class WxPayNotifyController extends BaseController { + @Value("${spring.profiles.active}") + String active; + @Resource + private RedisUtil redisUtil; + @Resource + private RequestUtil requestUtil; + @Resource + private ConfigProperties conf; + + @Schema(description = "异步通知") + @PostMapping("/notify/{tenantId}") + public String wxNotify(@RequestHeader Map header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) { + System.out.println("异步通知*************** = "); + + // 获取支付配置信息用于解密 + String key = "Payment:1:".concat(tenantId.toString()); + final Payment payment = redisUtil.get(key, Payment.class); + String privateKey = payment.getApiKey(); + String apiclientCert = conf.getUploadPath().concat("/file").concat(payment.getApiclientCert()); + + com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder() + .serialNumber(header.get("wechatpay-serial")) + .nonce(header.get("wechatpay-nonce")) + .signature(header.get("wechatpay-signature")) + .timestamp(header.get("wechatpay-timestamp")) + .body(body) + .build(); + + // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用 + // 没有的话,则构造一个 + NotificationConfig config = new RSANotificationConfig.Builder() + .apiV3Key(privateKey) + .certificatesFromPath(apiclientCert) + .build(); + + // 初始化 NotificationParser + NotificationParser parser = new NotificationParser(config); + + // 以支付通知回调为例,验签、解密并转换成 Transaction + try { + Transaction transaction = parser.parse(requestParam, Transaction.class); + + if (StrUtil.equals("支付成功", transaction.getTradeStateDesc())) { + + // 推送微信官方支付结果(携带租户ID的POST请求) + requestUtil.pushWxPayNotify(transaction, payment); + + return "SUCCESS"; + } + } catch (Exception $e) { + System.out.println($e.getMessage()); + } + + return "fail"; + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/dto/PaymentCacheDTO.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/dto/PaymentCacheDTO.java new file mode 100644 index 0000000..8a0cab9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/dto/PaymentCacheDTO.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.common.system.dto; + +import lombok.Data; +import java.io.Serializable; + +/** + * 支付配置缓存DTO + * 专门用于Redis缓存,不包含时间字段,避免序列化问题 + * + * @author 科技小王子 + * @since 2025-01-13 + */ +@Data +public class PaymentCacheDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private Integer id; + private String name; + private Integer type; + private String code; + private String image; + private Integer wechatType; + private String appId; + private String mchId; + private String apiKey; + private String apiclientCert; + private String apiclientKey; + private String pubKey; + private String pubKeyId; + private String merchantSerialNumber; + private String notifyUrl; + private String comments; + private Integer sortNumber; + private Boolean status; + private Integer deleted; + private Integer tenantId; + + // 不包含 createTime 和 updateTime 字段,避免序列化问题 +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/AccessKey.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/AccessKey.java new file mode 100644 index 0000000..46d5f95 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/AccessKey.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 访问凭证管理 + * + * @author 科技小王子 + * @since 2023-05-16 19:19:55 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AccessKey对象", description = "访问凭证管理") +@TableName("sys_access_key") +public class AccessKey implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典项id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "字典id") + private String accessKey; + + @Schema(description = "字典项标识") + private String accessSecret; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/AuthorizeCode.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/AuthorizeCode.java new file mode 100644 index 0000000..76f2fd9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/AuthorizeCode.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 授权码 + * + * @author 科技小王子 + * @since 2025-08-05 01:17:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "AuthorizeCode对象", description = "授权码") +@TableName("sys_authorize_code") +public class AuthorizeCode implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "授权码") + private String code; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Cache.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Cache.java new file mode 100644 index 0000000..c10a1ac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Cache.java @@ -0,0 +1,33 @@ +package com.gxwebsoft.common.system.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 缓存管理 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Setting对象", description = "缓存管理") +public class Cache implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "key") + private String key; + + @Schema(description = "设置内容(json格式)") + private String content; + + @Schema(description = "过期时间(秒)") + private Long expireTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Cart.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Cart.java new file mode 100644 index 0000000..25fb6f4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Cart.java @@ -0,0 +1,108 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 购物车 + * + * @author 科技小王子 + * @since 2024-10-26 10:54:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Cart对象", description = "购物车") +@TableName("sys_cart") +public class Cart implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "购物车表ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "类型 0商城 1应用插件") + private Integer type; + + @Schema(description = "唯一标识") + private String code; + + @Schema(description = "项目ID,0 goodId 1 companyId") + private Long itemId; + + @Schema(description = "商品规格") + private String spec; + + @Schema(description = "商品价格") + private BigDecimal price; + + @Schema(description = "购买时长") + private Integer month; + + @Schema(description = "商品数量") + private Integer cartNum; + + @Schema(description = "单商品合计") + private BigDecimal totalPrice; + + @Schema(description = "0 = 未购买 1 = 已购买") + private Boolean isPay; + + @Schema(description = "是否为立即购买") + private Boolean isNew; + + @Schema(description = "拼团id") + private Integer combinationId; + + @Schema(description = "秒杀产品ID") + private Integer seckillId; + + @Schema(description = "砍价id") + private Integer bargainId; + + @Schema(description = "是否选中") + private Boolean selected; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @Schema(description = "商品描述") + @TableField(exist = false) + private String comments; + + @Schema(description = "支付方式") + @TableField(exist = false) + private Integer payType; + + @Schema(description = "支付金额") + @TableField(exist = false) + private BigDecimal payPrice; + + @Schema(description = "应用列表") + private List list; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/ChatConversation.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/ChatConversation.java new file mode 100644 index 0000000..3005f29 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/ChatConversation.java @@ -0,0 +1,66 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 聊天消息表 + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ChatConversation对象", description = "聊天消息表") +@TableName("sys_chat_conversation") +public class ChatConversation implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "好友ID") + private Integer friendId; + + @Schema(description = "消息类型") + private Integer type; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "未读消息") + private Integer unRead; + + @Schema(description = "状态, 0未读, 1已读") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/ChatMessage.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/ChatMessage.java new file mode 100644 index 0000000..4745880 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/ChatMessage.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Map; + +/** + * 机构 + * + * @author LX + * @since 2025-04-14 00:35:34 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "LawOrg对象", description = "机构") +@TableName("law_org") +public class ChatMessage implements Serializable { + private static final long serialVersionUID = 1L; + + @TableField(exist = false) + private String query; + + @TableField(exist = false) + private String inputs; + + @TableField(exist = false) + private String responseMode; + + @TableField(exist = false) + private String user; + + @TableField(exist = false) + private String conversationId; + + @TableField(exist = false) + private String type; + + @TableField(exist = false) + private Integer requestType; + + @TableField(exist = false) + private Map files; + + @TableField(exist = false) + private Integer formUserId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Company.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Company.java new file mode 100644 index 0000000..586f847 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Company.java @@ -0,0 +1,336 @@ +package com.gxwebsoft.common.system.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 企业信息 + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Company对象", description = "企业信息") +@TableName("sys_company") +public class Company implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "企业id") + @TableId(value = "company_id", type = IdType.AUTO) + private Integer companyId; + + @Schema(description = "应用类型") + private Integer type; + + @Schema(description = "企业简称") + private String shortName; + + @Schema(description = "企业全称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "企业标识") + private String companyCode; + + @Schema(description = "企业类型") + private String companyType; + + @Schema(description = "是否官方") + private Boolean official; + + @Schema(description = "企业类型 多选") + private String companyTypeMultiple; + + @Schema(description = "应用标识") + private String companyLogo; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "应用详情") + @TableField(exist = false) + private String content; + + @Schema(description = "栏目分类") + private Integer categoryId; + + @Schema(description = "栏目名称") + @TableField(exist = false) + private String categoryName; + + @Schema(description = "应用截图") + private String files; + + @Schema(description = "顶级域名") + private String domain; + + @Schema(description = "免费域名") + private String freeDomain; + + @Schema(description = "销售价格") + private BigDecimal price; + + @Schema(description = "计费方式") + private Integer chargingMethod; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "公司座机") + private String tel; + + @Schema(description = "电子邮箱") + private String email; + + @Schema(description = "企业法人") + private String businessEntity; + + @Schema(description = "发票抬头") + @TableField("Invoice_header") + private String invoiceHeader; + + @Schema(description = "服务开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime startTime; + + @Schema(description = "服务到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime expirationTime; + + @Schema(description = "即将过期") + private Integer soon; + + @Schema(description = "应用版本 10体验版 20授权版 30旗舰版") + private Integer version; + + @Schema(description = "版本名称") + private String versionName; + + @Schema(description = "版本号") + private String versionCode; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "企业成员(当前)") + private Integer users; + + @Schema(description = "成员数量(上限)") + private Integer members; + + @Schema(description = "浏览数量") + private Long clicks; + + @Schema(description = "点赞数量") + private Long likes; + + @Schema(description = "购买数量") + private Long buys; + + @Schema(description = "存储空间") + private Long storage; + + @Schema(description = "存储空间(上限)") + private Long storageMax; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "部门数量") + private Integer departments; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否实名认证") + private Integer authentication; + + @Schema(description = "主控端节点") + private String serverUrl; + + @Schema(description = "模块节点") + private String modulesUrl; + + @Schema(description = "重定向节点") + private String redirectUrl; + + @Schema(description = "request合法域名") + private String requestUrl; + + @Schema(description = "socket合法域名") + private String socketUrl; + + @Schema(description = "总后台管理入口") + private String adminUrl; + + @Schema(description = "商户端管理入口") + private String merchantUrl; + + @Schema(description = "默认网站URL") + private String websiteUrl; + + @Schema(description = "微信小程序二维码") + private String mpWeixinCode; + + @Schema(description = "支付宝小程序二维码") + private String mpAlipayCode; + + @Schema(description = "H5端应用二维码") + private String h5Code; + + @Schema(description = "安卓APP二维码") + private String androidUrl; + + @Schema(description = "苹果APP二维码") + private String iosUrl; + + @Schema(description = "应用类型") + private String appType; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序") + private Integer sortNumber; + + @Schema(description = "插件ID(菜单根节点)") + private Integer menuId; + + @Schema(description = "当前使用的租户模板") + private Integer planId; + + @Schema(description = "是否开启网站") + private Boolean websiteStatus; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否含税") + private Boolean isTax; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "是否默认企业主体") + private Boolean authoritative; + + @Schema(description = "是否推荐") + private Boolean recommend; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "租户ID") + private Integer tid; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "租户编号") + @TableField(exist = false) + private String tenantCode; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "配置信息") + @TableField(exist = false) + private Object config; + + @Schema(description = "是否已收藏") + @TableField(exist = false) + private Boolean collection; + + @Schema(description = "新注册的密码") + @TableField(exist = false) + private String password; + + @Schema(description = "手机号(脱敏)") + @TableField(exist = false) + private String mobile; + + @Schema(description = "是否已购买") + @TableField(exist = false) + private Boolean isBuy; + + @Schema(description = "用户是否已安装了该插件") + @TableField(exist = false) + private Boolean installed; + + @Schema(description = "产品参数") + @TableField(exist = false) + private List parameters; + + @Schema(description = "产品按钮及链接") + @TableField(exist = false) + private List links; + + @Schema(description = "购买数量") + @TableField(exist = false) + private Integer num; + + @Schema(description = "角色列表") + @TableField(exist = false) + private List roles; + + @Schema(description = "权限列表") + @TableField(exist = false) + private List authorities; + + @Schema(description = "记录克隆的模板ID") + @TableField(exist = false) + private Integer templateId; + + public String getMobile() { + return DesensitizedUtil.mobilePhone(this.phone); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyComment.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyComment.java new file mode 100644 index 0000000..8a34e48 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyComment.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用评论 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyComment对象", description = "应用评论") +@TableName("sys_company_comment") +public class CompanyComment implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "父级ID") + private Integer parentId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "评论内容") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyContent.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyContent.java new file mode 100644 index 0000000..aa7b82f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyContent.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用详情 + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyContent对象", description = "应用详情") +@TableName("sys_company_content") +public class CompanyContent implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "详细内容") + private String content; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyGit.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyGit.java new file mode 100644 index 0000000..bdb074d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyGit.java @@ -0,0 +1,141 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 代码仓库 + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyGit对象", description = "代码仓库") +@TableName("sys_company_git") +public class CompanyGit implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "仓库名称") + private String title; + + @Schema(description = "厂商") + private String brand; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "仓库地址") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "仓库描述") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "租户id") + private Integer tenantId; + + /** + * 用户余额变动明细表 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ + @Data + @EqualsAndHashCode(callSuper = false) + @Schema(name = "UserBalanceLog对象", description = "用户余额变动明细表") + @TableName("sys_user_balance_log") + public static class UserBalanceLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "log_id", type = IdType.AUTO) + private Integer logId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "余额变动场景(10用户充值 20用户消费 30管理员操作 40订单退款)") + private Integer scene; + + @Schema(description = "变动金额") + private BigDecimal money; + + @Schema(description = "变动后余额") + private BigDecimal balance; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "支付流水号") + private String transactionId; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyParameter.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyParameter.java new file mode 100644 index 0000000..6d56a73 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyParameter.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyParameter对象", description = "应用参数") +@TableName("sys_company_parameter") +public class CompanyParameter implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "参数名称") + private String name; + + @Schema(description = "参数内容") + private String value; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyUrl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyUrl.java new file mode 100644 index 0000000..9e12c1d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/CompanyUrl.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 应用域名 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CompanyUrl对象", description = "应用域名") +@TableName("sys_company_url") +public class CompanyUrl implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "域名类型") + private String type; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "二维码") + private String qrcode; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Components.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Components.java new file mode 100644 index 0000000..63f7c62 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Components.java @@ -0,0 +1,72 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 组件 + * + * @author 科技小王子 + * @since 2024-08-25 19:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Components对象", description = "组件") +@TableName("sys_components") +public class Components implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "组件标题") + private String title; + + @Schema(description = "关联导航ID") + private Integer navigationId; + + @Schema(description = "组件类型") + private String type; + + @Schema(description = "页面关键词") + private String keywords; + + @Schema(description = "页面描述") + private String description; + + @Schema(description = "组件路径") + private String path; + + @Schema(description = "组件图标") + private String icon; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Dict.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Dict.java new file mode 100644 index 0000000..8a56893 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Dict.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.Set; + +/** + * 字典 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Data +@Schema(description = "字典(业务类)") +@TableName("sys_dict") +public class Dict implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典id") + @TableId(type = IdType.AUTO) + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "字典项列表") + @TableField(exist = false) + private Set> items; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/DictData.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/DictData.java new file mode 100644 index 0000000..2433b1a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/DictData.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 字典数据 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Data +@Schema(description = "字典数据(业务类)") +@TableName("sys_dict_data") +public class DictData implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @TableId(type = IdType.AUTO) + private Integer dictDataId; + + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Dictionary.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Dictionary.java new file mode 100644 index 0000000..50362f8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Dictionary.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 字典 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Data +@Schema(description = "字典(系统类)") +@TableName("sys_dictionary") +public class Dictionary implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典id") + @TableId(type = IdType.AUTO) + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/DictionaryData.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/DictionaryData.java new file mode 100644 index 0000000..8af7061 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/DictionaryData.java @@ -0,0 +1,66 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 字典数据 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Data +@Schema(description = "字典数据(系统类)") +@TableName("sys_dictionary_data") +public class DictionaryData implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @TableId(type = IdType.AUTO) + private Integer dictDataId; + + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Domain.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Domain.java new file mode 100644 index 0000000..d61b23b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Domain.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 授权域名 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Domain对象", description = "授权域名") +@TableName("sys_domain") +public class Domain implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "主机记录") + private String hostName; + + @Schema(description = "记录值") + private String hostValue; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "类型 0常规 1后台 2商家端") + private Integer type; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/EmailRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/EmailRecord.java new file mode 100644 index 0000000..27fa730 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/EmailRecord.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 邮件发送记录 + * + * @author WebSoft + * @since 2021-08-29 12:36:35 + */ +@Data +@Schema(description = "邮件发送记录") +@TableName("sys_email_record") +public class EmailRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "邮件标题") + private String title; + + @Schema(description = "邮件内容") + private String content; + + @Schema(description = "收件邮箱") + private String receiver; + + @Schema(description = "发件邮箱") + private String sender; + + @Schema(description = "创建人") + private Integer createUserId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Environment.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Environment.java new file mode 100644 index 0000000..96095e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Environment.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 环境管理 + * + * @author 科技小王子 + * @since 2023-10-18 08:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Environment对象", description = "环境管理") +@TableName("sys_environment") +public class Environment implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "插件id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "环境名称") + private String environmentName; + + @Schema(description = "环境编号") + private String environmentCode; + + @Schema(description = "服务器厂商") + private String brand; + + @Schema(description = "服务器IP") + private String serverIp; + + @Schema(description = "模块访问地址") + private String modulesUrl; + + @Schema(description = "模块API") + private String modulesApi; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 10待审核 20已通过 30已驳回") + private Integer status; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/FileRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/FileRecord.java new file mode 100644 index 0000000..554df14 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/FileRecord.java @@ -0,0 +1,99 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 文件上传记录 + * + * @author WebSoft + * @since 2021-08-29 12:36:32 + */ +@Data +@Schema(description = "文件上传记录") +@TableName("sys_file_record") +public class FileRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "分组ID") + private Integer groupId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "文件存储路径") + private String path; + + @Schema(description = "文件大小") + private Long length; + + @Schema(description = "文件类型") + private String contentType; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "创建人") + private Integer createUserId; + + @Schema(description = "AppId") + private Integer appId; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编号") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "文件访问地址") + @TableField(exist = false) + private String url; + + @Schema(description = "文件缩略图访问地址") + @TableField(exist = false) + private String thumbnail; + + @Schema(description = "文件下载地址") + @TableField(exist = false) + private String downloadUrl; + + @Schema(description = "创建人账号") + @TableField(exist = false) + private String createUsername; + + @Schema(description = "创建人名称") + @TableField(exist = false) + private String createNickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/KVEntity.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/KVEntity.java new file mode 100644 index 0000000..eaa06de --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/KVEntity.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 租户 + * + * @author WebSoft + * @since 2021-08-28 11:31:06 + */ +@Data +@Schema(description = "实体") +public class KVEntity implements Serializable { + private static final long serialVersionUID = 1L; + protected K k; + protected V v; + public KVEntity() { + super(); + } + + public KVEntity(K k, V v) { + super(); + this.k = k; + this.v = v; + } + + public static KVEntity build(K k, V v) { + return new KVEntity<>(k, v); + } + + public K getK() { + return k; + } + + public void setK(K k) { + this.k = k; + } + + public V getV() { + return v; + } + + public void setV(V v) { + this.v = v; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java new file mode 100644 index 0000000..4561e25 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/LoginRecord.java @@ -0,0 +1,75 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 登录日志 + * + * @author WebSoft + * @since 2018-12-24 16:10:41 + */ +@Data +@Schema(description = "登录日志") +@TableName("sys_login_record") +public class LoginRecord implements Serializable { + private static final long serialVersionUID = 1L; + public static final int TYPE_LOGIN = 0; // 登录成功 + public static final int TYPE_ERROR = 1; // 登录失败 + public static final int TYPE_LOGOUT = 2; // 退出登录 + public static final int TYPE_REFRESH = 3; // 续签token + public static final int TYPE_REGISTER = 4; // 注册成功 + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户账号") + private String username; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "设备名称") + private String device; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "ip地址") + private String ip; + + @Schema(description = "操作类型, 0登录成功, 1登录失败, 2退出登录, 3续签token") + private Integer loginType; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "操作时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "用户id") + @TableField(exist = false) + private Integer userId; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Menu.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Menu.java new file mode 100644 index 0000000..a8bf0d0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Menu.java @@ -0,0 +1,91 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.security.core.GrantedAuthority; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 菜单 + * + * @author WebSoft + * @since 2018-12-24 16:10:17 + */ +@Data +@Schema(description = "菜单") +@TableName("sys_menu") +public class Menu implements GrantedAuthority { + private static final long serialVersionUID = 1L; + public static final int TYPE_MENU = 0; // 菜单类型 + public static final int TYPE_BTN = 1; // 按钮类型 + + @Schema(description = "菜单id") + @TableId(type = IdType.AUTO) + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址") + private String component; + + @Schema(description = "菜单类型, 0菜单, 1按钮") + private Integer menuType; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示左侧菜单)") + private Integer hide; + + @Schema(description = "路由元信息") + private String meta; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "关联应用") + private Integer appId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "子菜单") + @TableField(exist = false) + private List children; + + @Schema(description = "角色权限树选中状态") + @TableField(exist = false) + private Boolean checked; + + @Override + public String getAuthority() { + return this.authority; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Merchant.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Merchant.java new file mode 100644 index 0000000..7ed0e52 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Merchant.java @@ -0,0 +1,127 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 商户 + * + * @author 科技小王子 + * @since 2024-04-05 00:03:54 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Merchant对象", description = "商户") +@TableName("sys_merchant") +public class Merchant implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "merchant_id", type = IdType.AUTO) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户标识") + private String merchantCode; + + @Schema(description = "商户图标") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "商户分类") + private String category; + + @Schema(description = "经纬度") + private String lngAndLat; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "手续费") + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "营业时间") + private String businessTime; + + @Schema(description = "商户简介") + private String content; + + @Schema(description = "是否自营") + private Integer ownStore; + + @Schema(description = "每小时价格") + private BigDecimal price; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否需要审核") + private Boolean goodsReview; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "管理入口") + private String adminUrl; + + @Schema(description = "所有人") + private Integer userId; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "默认商户管理员角色ID") + @TableField(exist = false) + private Integer roleId; + + @Schema(description = "角色名称") + @TableField(exist = false) + private String roleName; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantAccount.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantAccount.java new file mode 100644 index 0000000..ab27d49 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantAccount.java @@ -0,0 +1,91 @@ +package com.gxwebsoft.common.system.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 商户账号 + * + * @author 科技小王子 + * @since 2024-04-19 12:02:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "MerchantAccount对象", description = "商户账号") +@TableName("sys_merchant_account") +public class MerchantAccount implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "账号密码") + @TableField(exist = false) + private String password; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "角色ID") + private Integer roleId; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "商户名称") + @TableField(exist = false) + private String merchantName; + + @Schema(description = "是否需要审核") + @TableField(exist = false) + private Boolean goodsReview; + + @Schema(description = "手机号(脱敏)") + @TableField(exist = false) + private String mobile; + + @Schema(description = "是否管理员") + @TableField(exist = false) + private Boolean isAdmin; + + public String getMobile(){ + return DesensitizedUtil.mobilePhone(this.phone); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantApply.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantApply.java new file mode 100644 index 0000000..e61d140 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantApply.java @@ -0,0 +1,87 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 商户入驻申请 + * + * @author 科技小王子 + * @since 2024-04-05 01:24:36 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "MerchantApply对象", description = "商户入驻申请") +@TableName("sys_merchant_apply") +public class MerchantApply implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "apply_id", type = IdType.AUTO) + private Integer applyId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户图标") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "商户分类") + private String category; + + @Schema(description = "手续费") + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "是否自营") + private Integer ownStore; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否需要审核") + private Integer goodsReview; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantType.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantType.java new file mode 100644 index 0000000..e94c41f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/MerchantType.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 商户类型 + * + * @author 科技小王子 + * @since 2024-04-05 00:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "MerchantType对象", description = "商户类型") +@TableName("sys_merchant_type") +public class MerchantType implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "店铺类型") + private String name; + + @Schema(description = "店铺入驻条件") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Modules.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Modules.java new file mode 100644 index 0000000..50a7902 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Modules.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 模块管理 + * + * @author 科技小王子 + * @since 2023-10-18 15:53:43 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Modules对象", description = "模块管理") +@TableName("sys_modules") +public class Modules implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "插件id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "环境编号") + private String modules; + + @Schema(description = "模块访问地址") + private String modulesUrl; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 10待审核 20已通过 30已驳回") + private Integer status; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Mp.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Mp.java new file mode 100644 index 0000000..4dc3180 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Mp.java @@ -0,0 +1,102 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 小程序信息 + * + * @author 科技小王子 + * @since 2024-07-21 23:03:05 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Mp对象", description = "小程序信息") +@TableName("cms_mp") +public class Mp implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "mp_id", type = IdType.AUTO) + private Integer mpId; + + @Schema(description = "是否主账号") + private Integer type; + + @Schema(description = "小程序ID") + private String appId; + + @Schema(description = "小程序密钥") + private String appSecret; + + @Schema(description = "小程序名称") + private String mpName; + + @Schema(description = "小程序简称") + private String shortName; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "小程序码") + private String mpQrcode; + + @Schema(description = "微信认证") + private Integer authentication; + + @Schema(description = "主体信息") + private String companyName; + + @Schema(description = "小程序备案") + private String icpNo; + + @Schema(description = "登录邮箱") + private String email; + + @Schema(description = "登录密码") + private String password; + + @Schema(description = "原始ID") + private String ghId; + + @Schema(description = "入口页面") + private String mainPath; + + @Schema(description = "过期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date expirationTime; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "介绍") + private String comments; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "登录凭证") + @TableField(exist = false) + private String code; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Notice.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Notice.java new file mode 100644 index 0000000..f44b820 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Notice.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; + +import java.util.Date; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 消息记录表 + * + * @author 科技小王子 + * @since 2023-10-08 13:22:21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Notice对象", description = "消息记录表") +@TableName("sys_notice") +public class Notice implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "notice_id", type = IdType.AUTO) + private Integer noticeId; + + @Schema(description = "消息类型") + private String type; + + @Schema(description = "标题") + private String title; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "颜色") + private String color; + + @Schema(description = "内容") + private String content; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "消息来源") + private String source; + + @Schema(description = "来源记录ID") + private Integer sourceId; + + @Schema(description = "路由地址") + private String path; + + @Schema(description = "是否已查阅") + private Integer isRead; + + @Schema(description = "渠道, 0发送 1回复") + private Integer channel; + + @Schema(description = "任务状态") + private Integer progress; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "状态, 0待处理, 1已完成") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @Schema(description = "开发者名称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "开发者头像") + @TableField(exist = false) + private String avatar; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OperationRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OperationRecord.java new file mode 100644 index 0000000..83793d1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OperationRecord.java @@ -0,0 +1,97 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 操作日志 + * + * @author WebSoft + * @since 2018-12-24 16:10:33 + */ +@Data +@Schema(description = "操作日志") +@TableName("sys_operation_record") +public class OperationRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "操作模块") + private String module; + + @Schema(description = "操作功能") + private String description; + + @Schema(description = "请求地址") + private String url; + + @Schema(description = "请求方式") + private String requestMethod; + + @Schema(description = "调用方法") + private String method; + + @Schema(description = "请求参数") + private String params; + + @Schema(description = "返回结果") + private String result; + + @Schema(description = "异常信息") + private String error; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "消耗时间, 单位毫秒") + private Long spendTime; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "设备名称") + private String device; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "ip地址") + private String ip; + + @Schema(description = "状态, 0成功, 1异常") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "操作时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "用户账号") + @TableField(exist = false) + private String username; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Order.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Order.java new file mode 100644 index 0000000..5159927 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Order.java @@ -0,0 +1,184 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gxwebsoft.common.system.param.MenuParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 订单 + * + * @author 科技小王子 + * @since 2024-10-16 12:32:52 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Order对象", description = "订单") +@TableName("sys_order") +public class Order implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单号") + @TableId(value = "order_id", type = IdType.AUTO) + private Integer orderId; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "订单类型,0产品 1插件") + private Integer type; + + @Schema(description = "下单渠道,0网站 1小程序 2其他") + private Integer channel; + + @Schema(description = "微信支付订单号") + private String transactionId; + + @Schema(description = "微信退款订单号") + private String refundOrder; + + @Schema(description = "使用的优惠券id") + private Integer couponId; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "订单总额") + private BigDecimal totalPrice; + + @Schema(description = "减少的金额,使用VIP会员折扣、优惠券抵扣、优惠券折扣后减去的价格") + private BigDecimal reducePrice; + + @Schema(description = "实际付款") + private BigDecimal payPrice; + + @Schema(description = "用于统计") + private BigDecimal price; + + @Schema(description = "价钱,用于积分赠送") + private BigDecimal money; + + @Schema(description = "退款金额") + private BigDecimal refundMoney; + + @Schema(description = "购买数量") + private Integer totalNum; + + @Schema(description = "0余额支付, 1微信支付,102微信Native,2会员卡支付,3支付宝,4现金,5POS机") + private Integer payType; + + @Schema(description = "0未付款,1已付款") + private Boolean payStatus; + + @Schema(description = "0未完成,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + private Integer orderStatus; + + @Schema(description = "优惠类型:0无、1抵扣优惠券、2折扣优惠券、3、VIP月卡、4VIP年卡,5VIP次卡、6VIP会员卡、7IC月卡、8IC年卡、9IC次卡、10IC会员卡、11免费订单、12VIP充值卡、13IC充值卡、14VIP季卡、15IC季卡") + private Integer couponType; + + @Schema(description = "优惠说明") + private String couponDesc; + + @Schema(description = "二维码地址,保存订单号,支付成功后才生成") + private String qrcode; + + @Schema(description = "预约详情开始时间数组") + private Long startTime; + + @Schema(description = "是否已开具发票:0未开发票,1已开发票,2不能开具发票") + private Boolean isInvoice; + + @Schema(description = "发票流水号") + private String invoiceNo; + + @Schema(description = "支付时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date payTime; + + @Schema(description = "退款时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date refundTime; + + @Schema(description = "申请退款时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date refundApplyTime; + + @Schema(description = "过期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date expirationTime; + + @Schema(description = "对账情况:0=未对账;1=已对账;3=已对账,金额对不上;4=未查询到该订单") + private Integer checkBill; + + @Schema(description = "订单是否已结算(0未结算 1已结算)") + private Integer isSettled; + + @Schema(description = "系统版本号 0当前版本 value=其他版本") + private Integer version; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "产品控制台") + private String adminUrl; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "购买时长") + @TableField(exist = false) + private Integer month; + + @Schema(description = "购买数量") + @TableField(exist = false) + private Integer cartNum; + + @Schema(description = "应用列表") + private List list; + + @Schema(description = "插件安装参数") + @TableField(exist = false) + private MenuParam menuParam; + + @Schema(description = "应用名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "应用图标") + @TableField(exist = false) + private String logo; + + @Schema(description = "订单商品") + @TableField(exist = false) + private List orderGoods; + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OrderGoods.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OrderGoods.java new file mode 100644 index 0000000..07c524c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OrderGoods.java @@ -0,0 +1,111 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 订单商品 + * + * @author 科技小王子 + * @since 2024-10-26 12:18:05 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "OrderGoods对象", description = "订单商品") +@TableName("sys_order_goods") +public class OrderGoods implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单号") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "订单类型,0商城 1应用插件") + private Integer type; + + @Schema(description = "订单号") + private Integer orderId; + + @Schema(description = "项目ID") + private Integer itemId; + + @Schema(description = "插件ID") + private Integer menuId; + + @Schema(description = "实际付款") + private BigDecimal payPrice; + + @Schema(description = "购买时长") + private Integer month; + + @Schema(description = "购买数量") + private Integer totalNum; + + @Schema(description = "0未付款,1已付款") + private Boolean payStatus; + + @Schema(description = "0未完成,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + private Integer orderStatus; + + @Schema(description = "预约详情开始时间数组") + private String startTime; + + @Schema(description = "是否已开具发票:0未开发票,1已开发票,2不能开具发票") + private Boolean isInvoice; + + @Schema(description = "发票流水号") + private String invoiceNo; + + @Schema(description = "支付时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date payTime; + + @Schema(description = "过期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date expirationTime; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "应用名称") + private String appName; + + @Schema(description = "产品控制台") + private String adminUrl; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "应用名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "应用图标") + @TableField(exist = false) + private String logo; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OrderInfo.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OrderInfo.java new file mode 100644 index 0000000..9697138 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/OrderInfo.java @@ -0,0 +1,104 @@ +package com.gxwebsoft.common.system.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * + * + * @author 科技小王子 + * @since 2024-05-10 18:02:54 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "OrderInfo对象", description = "") +@TableName("sys_order_info") +public class OrderInfo implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "关联订单表id") + private Integer oid; + + @Schema(description = "关联场馆id") + private Integer sid; + + @Schema(description = "关联场地id") + private Integer fid; + + @Schema(description = "场馆") + private String siteName; + + @Schema(description = "场地") + private String fieldName; + + @Schema(description = "预约时间段") + private String dateTime; + + @Schema(description = "单价") + private BigDecimal price; + + @Schema(description = "儿童价") + private BigDecimal childrenPrice; + + @Schema(description = "成人人数") + private Integer adultNum; + + @Schema(description = "儿童人数") + private Integer childrenNum; + + @Schema(description = "1已付款,2未付款,3无需付款或占用状态") + private Integer payStatus; + + @Schema(description = "是否免费:1免费、2收费") + private Integer isFree; + + @Schema(description = "是否支持儿童票:1支持,2不支持") + private Integer isChildren; + + @Schema(description = "预订类型:1全场,2半场") + private Integer type; + + @Schema(description = "组合数据:日期+时间段+场馆id+场地id") + private String mergeData; + + @Schema(description = "开场时间") + private Integer startTime; + + @Schema(description = "下单时间") + private Long orderTime; + + @Schema(description = "毫秒时间戳") + private Long timeFlag; + + @Schema(description = "系统版本") + private Integer version; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Organization.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Organization.java new file mode 100644 index 0000000..aa55469 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Organization.java @@ -0,0 +1,91 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 组织机构 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Data +@Schema(description = "组织机构") +@TableName("sys_organization") +public class Organization implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "机构id") + @TableId(type = IdType.AUTO) + private Integer organizationId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "机构名称") + private String organizationName; + + @Schema(description = "机构全称") + private String organizationFullName; + + @Schema(description = "机构代码") + private String organizationCode; + + @Schema(description = "机构类型, 字典标识") + private String organizationType; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "邮政编码") + private String zipCode; + + @Schema(description = "负责人id") + private Integer leaderId; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "机构类型名称") + @TableField(exist = false) + private String organizationTypeName; + + @Schema(description = "负责人姓名") + @TableField(exist = false) + private String leaderNickname; + + @Schema(description = "负责人账号") + @TableField(exist = false) + private String leaderUsername; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Payment.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Payment.java new file mode 100644 index 0000000..0f05fb6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Payment.java @@ -0,0 +1,99 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * 支付方式 + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Payment对象", description = "支付方式") +@TableName("sys_payment") +public class Payment implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "支付方式") + private String name; + + @Schema(description = "类型") + private Integer type; + + @Schema(description = "标识") + private String code; + + @Schema(description = "支付图标") + private String image; + + @Schema(description = "微信商户号类型 1普通商户2子商户") + private Integer wechatType; + + @Schema(description = "应用ID") + private String appId; + + @Schema(description = "商户号") + private String mchId; + + @Schema(description = "设置APIv3密钥") + private String apiKey; + + @Schema(description = "证书文件 (CERT)") + private String apiclientCert; + + @Schema(description = "证书文件 (KEY)") + private String apiclientKey; + + @Schema(description = "公钥文件 (KEY)") + private String pubKey; + + @Schema(description = "公钥ID") + private String pubKeyId; + + @Schema(description = "商户证书序列号") + private String merchantSerialNumber; + + @Schema(description = "支付结果通知") + private String notifyUrl; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文章排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0未启用, 1启用") + private Boolean status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonIgnore // 缓存时忽略此字段 + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonIgnore // 缓存时忽略此字段 + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Plug.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Plug.java new file mode 100644 index 0000000..8b86175 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Plug.java @@ -0,0 +1,143 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 插件扩展 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Plug对象", description = "插件扩展") +@TableName("sys_plug") +public class Plug implements Serializable { + private static final long serialVersionUID = 1L; + public static final int TYPE_MENU = 0; // 菜单类型 + public static final int TYPE_BTN = 1; // 按钮类型 + + @Schema(description = "插件id") + @TableId(value = "plug_id", type = IdType.AUTO) + private Integer plugId; + + @Schema(description = "菜单ID") + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址, 目录可为空") + private String component; + + @Schema(description = "类型, 0菜单, 1按钮") + private Integer menuType; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + private Integer hide; + + @Schema(description = "菜单侧栏选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "插件描述") + private String comments; + + @Schema(description = "插件详情") + private String content; + + @Schema(description = "评分") + private BigDecimal score; + + @Schema(description = "插件价格") + private BigDecimal price; + + @Schema(description = "浏览次数") + private Integer clicks; + + @Schema(description = "安装次数") + private Integer installs; + + @Schema(description = "关联应用ID") + private Integer appId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "子菜单") + @TableField(exist = false) + private List children; + + @Schema(description = "角色权限树选中状态") + @TableField(exist = false) + private Boolean checked; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "企业名称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "企业简称") + @TableField(exist = false) + private String shortName; + + @Schema(description = "企业域名") + @TableField(exist = false) + private String domain; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/RechargeOrder.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/RechargeOrder.java new file mode 100644 index 0000000..369f919 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/RechargeOrder.java @@ -0,0 +1,133 @@ +package com.gxwebsoft.common.system.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 会员充值订单表 + * + * @author 科技小王子 + * @since 2024-07-26 23:18:48 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "RechargeOrder对象", description = "会员充值订单表") +@TableName("sys_recharge_order") +public class RechargeOrder implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单ID") + @TableId(value = "order_id", type = IdType.AUTO) + private Integer orderId; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "充值方式(10自定义金额 20套餐充值)") + private Integer rechargeType; + + @Schema(description = "机构id") + private Integer organizationId; + + @Schema(description = "充值套餐ID") + private Integer planId; + + @Schema(description = "用户支付金额") + private BigDecimal payPrice; + + @Schema(description = "赠送金额") + private BigDecimal giftMoney; + + @Schema(description = "实际到账金额") + private BigDecimal actualMoney; + + @Schema(description = "用户可用余额") + private BigDecimal balance; + + @Schema(description = "支付方式(微信/支付宝)") + private String payMethod; + + @Schema(description = "支付状态(10待支付 20已支付)") + private Integer payStatus; + + @Schema(description = "付款时间") + private Integer payTime; + + @Schema(description = "第三方交易记录ID") + private Integer tradeId; + + @Schema(description = "来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "所属门店ID") + private Integer shopId; + + @Schema(description = "操作员") + private String operator; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "真实姓名") + @TableField(exist = false) + private String realName; + + @Schema(description = "手机号码") + @TableField(exist = false) + private String phone; + + @Schema(description = "手机号码(脱敏)") + @TableField(exist = false) + private String mobile; + + @Schema(description = "部门名称") + @TableField(exist = false) + private String organizationName; + + public String getMobile(){ + return DesensitizedUtil.mobilePhone(this.phone); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Role.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Role.java new file mode 100644 index 0000000..a99a83a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Role.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 角色 + * + * @author WebSoft + * @since 2018-12-24 16:10:01 + */ +@Data +@Schema(description = "角色") +@TableName("sys_role") +public class Role implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "角色id") + @TableId(type = IdType.AUTO) + private Integer roleId; + + @Schema(description = "角色标识") + private String roleCode; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(hidden = true) + @TableField(exist = false) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/RoleMenu.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/RoleMenu.java new file mode 100644 index 0000000..82eada6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/RoleMenu.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 角色菜单 + * + * @author WebSoft + * @since 2018-12-24 16:10:54 + */ +@Data +@Schema(description = "角色权限") +@TableName("sys_role_menu") +public class RoleMenu implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "角色id") + private Integer roleId; + + @Schema(description = "菜单id") + private Integer menuId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Setting.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Setting.java new file mode 100644 index 0000000..7e417c7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Setting.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 系统设置 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Setting对象", description = "系统设置") +@TableName("sys_setting") +public class Setting implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "setting_id", type = IdType.AUTO) + private Integer settingId; + + @Schema(description = "设置项标示") + private String settingKey; + + @Schema(description = "设置内容(json格式)") + private String content; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "修改租户名称") + @TableField(exist = false) + private String tenantName; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/SysFileType.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/SysFileType.java new file mode 100644 index 0000000..ae57bea --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/SysFileType.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 存储类型 + * + * @author 科技小王子 + * @since 2025-05-16 14:24:28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "SysFileType对象", description = "存储类型") +public class SysFileType implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "0本地存储,1阿里云oss,2腾讯云cos,3七牛云,4其他") + private Integer type; + + @Schema(description = "名称") + private String name; + + @Schema(description = "访问域名") + private String path; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TemplateMessage.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TemplateMessage.java new file mode 100644 index 0000000..f1ef1f0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TemplateMessage.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信公众号模板消息对象 + * + * @author WebSoft + * @since 2018-12-24 16:10:54 + */ +@Data +@Schema(description = "微信公众号模板消息对象") +public class TemplateMessage implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "接收者openid") + @TableField(exist = false) + private String toUser; + + @Schema(description = "模板ID") + @TableField(exist = false) + private String templateId; + + @Schema(description = "模板跳转链接(海外账号没有跳转能力)") + @TableField(exist = false) + private String url; + + @Schema(description = "跳小程序所需数据,不需跳小程序可不用传该数据") + @TableField(exist = false) + private String miniProgram; + + @Schema(description = "所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏)") + @TableField(exist = false) + private String appid; + + @Schema(description = "所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏") + @TableField(exist = false) + private String pagePath; + + @Schema(description = "模板数据") + @TableField(exist = false) + private Object data; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TemplateMessageDTO.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TemplateMessageDTO.java new file mode 100644 index 0000000..213c1e1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TemplateMessageDTO.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信公众号模板消息对象 + * + * @author WebSoft + * @since 2018-12-24 16:10:54 + */ +@Data +@Schema(description = "模板消息内容") +public class TemplateMessageDTO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "消息实参") + @TableField(exist = false) + private String value; + + @Schema(description = "消息颜色") + private String color; + + public TemplateMessageDTO(String value) { + this.value = value; + } + public TemplateMessageDTO(String value, String color) { + this.value = value; + this.color = color; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Tenant.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Tenant.java new file mode 100644 index 0000000..98150c3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Tenant.java @@ -0,0 +1,93 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.List; + +/** + * 租户 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Tenant对象", description = "租户") +@TableName("sys_tenant") +public class Tenant implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "租户id") + @TableId(value = "tenant_id", type = IdType.AUTO) + private Integer tenantId; + + @Schema(description = "租户名称") + private String tenantName; + + @Schema(description = "租户编号") + private String tenantCode; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "logo") + @TableField(exist = false) + private String logo; + + @Schema(description = "超级管理员账号") + @TableField(exist = false) + private String username; + + @Schema(description = "超级管理员手机号") + @TableField(exist = false) + private String phone; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "真实姓名") + @TableField(exist = false) + private String realName; + + @Schema(description = "企业名称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "游客身份") + @TableField(exist = false) + private String token; + + @Schema(description = "当前登录用户") + @TableField(exist = false) + private User loginUser; + + @Schema(description = "菜单信息") + @TableField(exist = false) + private List menu; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantPackage.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantPackage.java new file mode 100644 index 0000000..25d5e36 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantPackage.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 租户套餐 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "TenantPackage对象", description = "租户套餐") +@TableName("sys_tenant_package") +public class TenantPackage implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "套餐ID") + @TableId(value = "package_id", type = IdType.AUTO) + private Integer packageId; + + @Schema(description = "套餐名称") + private String packageName; + + @Schema(description = "版本号 0试用 10基础 20专业 30企业 99私有") + private Integer version; + + @Schema(description = "月付价格") + private BigDecimal priceMonthly; + + @Schema(description = "年付价格") + private BigDecimal priceYearly; + + @Schema(description = "季付价格") + private BigDecimal priceQuarterly; + + @Schema(description = "最大用户数 0无限") + private Integer maxUsers; + + @Schema(description = "最大订单数 0无限") + private Integer maxOrders; + + @Schema(description = "存储空间限制(MB) 0无限") + private Long storageLimit; + + @Schema(description = "API调用限制(次/天) 0无限") + private Integer apiLimit; + + @Schema(description = "试用天数") + private Integer trialDays; + + @Schema(description = "功能列表JSON") + private String features; + + @Schema(description = "状态 0下架 1上架") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantSubscription.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantSubscription.java new file mode 100644 index 0000000..682fabf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantSubscription.java @@ -0,0 +1,83 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 租户订阅记录 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "TenantSubscription对象", description = "租户订阅记录") +@TableName("sys_tenant_subscription") +public class TenantSubscription implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "订阅ID") + @TableId(value = "subscription_id", type = IdType.AUTO) + private Long subscriptionId; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "当前套餐ID") + private Integer packageId; + + @Schema(description = "套餐名称") + private String packageName; + + @Schema(description = "当前版本") + private Integer version; + + @Schema(description = "开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date startTime; + + @Schema(description = "到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; + + @Schema(description = "是否试用期") + private Integer isTrial; + + @Schema(description = "是否已过期 0否 1是") + private Integer isExpired; + + @Schema(description = "自动续费 0关闭 1开启") + private Integer autoRenewal; + + @Schema(description = "续费套餐ID") + private Integer renewalPackageId; + + @Schema(description = "提醒状态 0未提醒 1已提醒30天 2已提醒7天 3已提醒1天") + private Integer notifyStatus; + + @Schema(description = "状态 0停用 1正常") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + + // 关联查询字段 + @Schema(description = "套餐信息") + @TableField(exist = false) + private TenantPackage tenantPackage; + + @Schema(description = "租户信息") + @TableField(exist = false) + private Tenant tenant; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantSubscriptionOrder.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantSubscriptionOrder.java new file mode 100644 index 0000000..37dcd25 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/TenantSubscriptionOrder.java @@ -0,0 +1,103 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 租户订阅订单 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "TenantSubscriptionOrder对象", description = "租户订阅订单") +@TableName("sys_tenant_subscription_order") +public class TenantSubscriptionOrder implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单ID") + @TableId(value = "order_id", type = IdType.AUTO) + private Long orderId; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "套餐ID") + private Integer packageId; + + @Schema(description = "套餐名称") + private String packageName; + + @Schema(description = "版本号") + private Integer version; + + @Schema(description = "支付周期 1月付 3季付 12年付") + private Integer payType; + + @Schema(description = "原价") + private BigDecimal originalPrice; + + @Schema(description = "优惠金额") + private BigDecimal discountPrice; + + @Schema(description = "实付金额") + private BigDecimal actualPrice; + + @Schema(description = "开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date startTime; + + @Schema(description = "到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; + + @Schema(description = "是否试用 0否 1是") + private Integer isTrial; + + @Schema(description = "是否续费 0首购 1续费") + private Integer isRenewal; + + @Schema(description = "是否升级 0否 1是") + private Integer isUpgrade; + + @Schema(description = "升级前版本") + private Integer oldVersion; + + @Schema(description = "支付方式 wxpay/alipay/balance") + private String paymentMethod; + + @Schema(description = "支付流水号") + private String paymentId; + + @Schema(description = "支付时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date paymentTime; + + @Schema(description = "订单状态 0待支付 1已支付 2已激活 3已取消 4已退款") + private Integer orderStatus; + + @Schema(description = "取消原因") + private String cancelReason; + + @Schema(description = "操作用户ID") + private Integer userId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/User.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/User.java new file mode 100644 index 0000000..af3510e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/User.java @@ -0,0 +1,316 @@ +package com.gxwebsoft.common.system.entity; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gxwebsoft.cms.entity.CmsWebsite; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.security.core.userdetails.UserDetails; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户 + * + * @author WebSoft + * @since 2018-12-24 16:10:13 + */ +@Data +@Schema(description = "用户") +@TableName("sys_user") +public class User implements UserDetails { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户id") + @TableId(type = IdType.AUTO) + private Integer userId; + + @Schema(description = "用户类型, 0普通用户") + private Integer type; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "账号") + private String username; + + @Schema(description = "密码") + private String password; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "头像") + private String bgImage; + + @Schema(description = "性别, 字典标识") + private String sex; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "支付密码") + private String payPassword; + + @Schema(description = "职务") + private String position; + + @Schema(description = "邮箱是否验证, 0否, 1是") + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "身份证号(脱敏)") + private String idCard; + + @Schema(description = "身份证号") + @TableField(exist = false) + private String idCardNo; + + @Schema(description = "出生日期") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime birthday; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "用户可用余额") + private BigDecimal balance; + + @Schema(description = "用户可用积分") + private Integer points; + + @Schema(description = "用户总支付的金额") + private String payMoney; + + @Schema(description = "实际消费的金额(不含退款)") + private BigDecimal expendMoney; + + @Schema(description = "会员等级ID") + private Integer gradeId; + + @Schema(description = "个人简介") + private String introduction; + + @Schema(description = "机构ID") + private Integer organizationId; + + @Schema(description = "会员分组ID") + private Integer groupId; + + @Schema(description = "会员分组") + @TableField(exist = false) + private String groupName; + + @Schema(description = "客户ID") + @TableField(exist = false) + private Integer customerId; + + @Schema(description = "企业ID") + @TableField(exist = false) + private Integer companyId; + + @Schema(description = "模板ID") + @TableField(exist = false) + private Integer templateId; + + @Schema(description = "注册来源客户端") + private String platform; + + @Schema(description = "是否下线会员") + private Integer offline; + + @Schema(description = "关注数") + private Integer followers; + + @Schema(description = "粉丝数") + private Integer fans; + + @Schema(description = "获赞数") + private Integer likes; + + @Schema(description = "客户端ID") + private String clientId; + + @Schema(description = "可管理的商户") + private String merchants; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "是否管理员") + private Boolean isAdmin; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "最后结算时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime settlementTime; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "公司名称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "是否已实名认证") + private Integer certification; + + @Schema(description = "机构名称") + @TableField(exist = false) + private String organizationName; + + @Schema(description = "性别名称") + @TableField(exist = false) + private String sexName; + + @Schema(description = "会员等级") + @TableField(exist = false) + private String gradeName; + + @Schema(description = "默认注册的角色ID") + @TableField(exist = false) + private Integer roleId; + + @Schema(description = "角色列表") + @TableField(exist = false) + private List roles; + + @Schema(description = "权限列表") + @TableField(exist = false) + private List authorities; + + @Schema(description = "微信凭证") + @TableField(exist = false) + private String code; + + @Schema(description = "推荐人ID") + @TableField(exist = false) + private Integer dealerId; + + @Schema(description = "微信openid") + private String openid; + + @Schema(description = "公众号openid") + private String officeOpenid; + + @Schema(description = "微信unionid") + private String unionid; + + @Schema(description = "关联用户ID") + @TableField(exist = false) + private Integer sysUserId; + + @Schema(description = "ico文件") + @TableField(exist = false) + private String logo; + + @Schema(description = "创建的应用数量") + @TableField(exist = false) + private Double apps; + + @Schema(description = "租户设置信息") + @TableField(exist = false) + private String setting; + + @Schema(description = "手机号(脱敏)") + @TableField(exist = false) + private String mobile; + + @Schema(description = "网站信息") + @TableField(exist = false) + private CmsWebsite website; + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return this.status != null && this.status == 0; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + public String getMobile(){ + return DesensitizedUtil.mobilePhone(this.phone); + } + + public String getIdCardNo(){ + return DesensitizedUtil.idCardNum(this.idCard,4,4); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserBalanceLog.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserBalanceLog.java new file mode 100644 index 0000000..f999448 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserBalanceLog.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 用户余额变动明细表 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserBalanceLog对象", description = "用户余额变动明细表") +@TableName("sys_user_balance_log") +public class UserBalanceLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "log_id", type = IdType.AUTO) + private Integer logId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "余额变动场景(10用户充值 20用户消费 30管理员操作 40订单退款)") + private Integer scene; + + @Schema(description = "变动金额") + private BigDecimal money; + + @Schema(description = "变动后余额") + private BigDecimal balance; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "支付流水号") + private String transactionId; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserCollection.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserCollection.java new file mode 100644 index 0000000..ddff7cc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserCollection.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 我的收藏 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserCollection对象", description = "我的收藏") +@TableName("sys_user_collection") +public class UserCollection implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "租户ID") + private Integer tid; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserFile.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserFile.java new file mode 100644 index 0000000..1a53080 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserFile.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户文件 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserFile对象", description = "用户文件") +@TableName("sys_user_file") +public class UserFile implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "是否是文件夹, 0否, 1是") + private Integer isDirectory; + + @Schema(description = "上级id") + private Integer parentId; + + @Schema(description = "文件路径") + private String path; + + @Schema(description = "文件大小") + private Integer length; + + @Schema(description = "文件类型") + private String contentType; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "文件访问地址") + @TableField(exist = false) + private String url; + + @Schema(description = "文件缩略图访问地址") + @TableField(exist = false) + private String thumbnail; + + @Schema(description = "文件下载地址") + @TableField(exist = false) + private String downloadUrl; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserGrade.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserGrade.java new file mode 100644 index 0000000..23aa2fa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserGrade.java @@ -0,0 +1,72 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户会员等级表 + * + * @author 科技小王子 + * @since 2023-10-07 22:51:17 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserGrade对象", description = "用户会员等级表") +@TableName("sys_user_grade") +public class UserGrade implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "等级ID") + @TableId(value = "grade_id", type = IdType.AUTO) + private Integer gradeId; + + @Schema(description = "等级名称") + private String name; + + @Schema(description = "等级权重(1-9999)") + private Integer weight; + + @Schema(description = "升级条件") + private String upgrade; + + @Schema(description = "等级权益(折扣率0-100)") + private String equity; + + @Schema(description = "佣金比率") + private String commission; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserGroup.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserGroup.java new file mode 100644 index 0000000..ad660ba --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserGroup.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户分组管理表 + * + * @author 科技小王子 + * @since 2023-10-28 15:16:39 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserGroup对象", description = "用户分组管理表") +@TableName("sys_user_group") +public class UserGroup implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "分组ID") + @TableId(value = "group_id", type = IdType.AUTO) + private Integer groupId; + + @Schema(description = "分组名称") + private String name; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserInfo.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserInfo.java new file mode 100644 index 0000000..ee009ab --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserInfo.java @@ -0,0 +1,259 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户 + * + * @author WebSoft + * @since 2018-12-24 16:10:13 + */ +@Data +@Schema(description = "用户") +@TableName("sys_user") +public class UserInfo { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户id") + @TableId(type = IdType.AUTO) + private Integer userId; + + @Schema(description = "用户类型, 0普通用户 6开发者 10企业用户") + private Integer type; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "账号") + private String username; + + @Schema(description = "密码") + private String password; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "头像") + private String bgImage; + + @Schema(description = "性别, 字典标识") + private String sex; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "职务") + private String position; + + @Schema(description = "邮箱是否验证, 0否, 1是") + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "身份证号") + private String idCard; + + @Schema(description = "出生日期") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime birthday; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "用户可用余额") + private BigDecimal balance; + + @Schema(description = "用户可用积分") + private Integer points; + + @Schema(description = "用户总支付的金额") + private String payMoney; + + @Schema(description = "实际消费的金额(不含退款)") + private String expendMoney; + + @Schema(description = "会员等级ID") + private Integer gradeId; + + @Schema(description = "个人简介") + private String introduction; + + @Schema(description = "机构ID") + private Integer organizationId; + + @Schema(description = "客户ID") + private Integer customerId; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "注册来源客户端") + private String platform; + + @Schema(description = "兴趣爱好") + private String interest; + + @Schema(description = "身高") + private String height; + + @Schema(description = "体重") + private String weight; + + @Schema(description = "学历") + private String education; + + @Schema(description = "月薪") + private String monthlyPay; + + @Schema(description = "是否下线会员") + private Integer offline; + + @Schema(description = "关注数") + private Integer followers; + + @Schema(description = "粉丝数") + private Integer fans; + + @Schema(description = "获赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "租户名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "最后结算时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime settlementTime; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "公司名称") + private String companyName; + + @Schema(description = "是否已实名认证") + private Integer certification; + + @Schema(description = "机构名称") + @TableField(exist = false) + private String organizationName; + + @Schema(description = "性别名称") + @TableField(exist = false) + private String sexName; + + @Schema(description = "会员等级") + @TableField(exist = false) + private String gradeName; + + @Schema(description = "默认注册的角色ID") + @TableField(exist = false) + private Integer roleId; + + @Schema(description = "角色列表") + @TableField(exist = false) + private List roles; + + @Schema(description = "权限列表") + @TableField(exist = false) + private List authorities; + + @Schema(description = "微信凭证") + @TableField(exist = false) + private String code; + + @Schema(description = "推荐人ID") + @TableField(exist = false) + private Integer dealerId; + + @Schema(description = "微信openid") + @TableField(exist = false) + private String openid; + + @Schema(description = "微信unionid") + @TableField(exist = false) + private String unionid; + + @Schema(description = "所属商户名称") + @TableField(exist = false) + private String merchantName; + + @Schema(description = "ico文件") + @TableField(exist = false) + private String logo; + + @Schema(description = "创建的应用数量") + @TableField(exist = false) + private Double apps; + + @Schema(description = "租户设置信息") + @TableField(exist = false) + private String setting; + + @Schema(description = "手机号(脱敏)") + @TableField(exist = false) + private String mobile; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserOauth.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserOauth.java new file mode 100644 index 0000000..79fcb84 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserOauth.java @@ -0,0 +1,68 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 第三方用户信息表 + * + * @author 科技小王子 + * @since 2023-10-07 22:39:46 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserOauth对象", description = "第三方用户信息表") +@TableName("sys_user_oauth") +public class UserOauth implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "第三方登陆类型(MP-WEIXIN)") + private String oauthType; + + @Schema(description = "第三方用户唯一标识 (uid openid)") + private String oauthId; + + @Schema(description = "微信unionID") + private String unionid; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserReferee.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserReferee.java new file mode 100644 index 0000000..7e0216f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserReferee.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 用户推荐关系表 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserReferee对象", description = "用户推荐关系表") +@TableName("sys_user_referee") +public class UserReferee implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "推荐人ID") + private Integer dealerId; + + @Schema(description = "用户id(被推荐人)") + private Integer userId; + + @Schema(description = "推荐关系层级(1,2,3)") + private Integer level; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @TableField(exist = false) + private User user; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserRole.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserRole.java new file mode 100644 index 0000000..7f650ca --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserRole.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 用户角色 + * + * @author WebSoft + * @since 2018-12-24 16:10:23 + */ +@Data +@Schema(description = "用户角色") +@TableName("sys_user_role") +public class UserRole implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @TableId(type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "角色id") + private Integer roleId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "角色名称") + @TableField(exist = false) + private String roleName; + + @Schema(description = "租户ID") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserVerify.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserVerify.java new file mode 100644 index 0000000..0f74385 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/UserVerify.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Date; + +/** + * 实名认证 + * + * @author 科技小王子 + * @since 2025-05-29 23:01:04 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "UserVerify对象", description = "实名认证") +@TableName("sys_user_verify") +public class UserVerify implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "认证类型, 0个人 1企业") + private Integer type; + + @Schema(description = "主体名称") + private String name; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "证件号码") + private String idCard; + + @Schema(description = "出生日期") + private LocalDate birthday; + + @Schema(description = "正面") + private String sfz1; + + @Schema(description = "反面") + private String sfz2; + + @Schema(description = "营业执照号码") + private String zzCode; + + @Schema(description = "营业执照照片") + private String zzImg; + + @Schema(description = "其他证件") + private String files; + + @Schema(description = "审核人") + private Integer adminId; + + @Schema(description = "机构ID") + private Integer organizationId; + + @Schema(description = "机构ID") + @TableField(exist = false) + private String organizationName; + + @Schema(description = "用户角色ID") + private Integer userRoleId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0待审核, 1已通过审核,2已驳回") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @Schema(description = "手机号码") + @TableField(exist = false) + private String phone; + + @Schema(description = "状态名称") + @TableField(exist = false) + private String statusText; + + public String getStatusText() { + String[] statusArray = {"待审核", "已审核通过", "已驳回"}; + return statusArray[this.status]; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Version.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Version.java new file mode 100644 index 0000000..b84cdf4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/Version.java @@ -0,0 +1,83 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 版本更新 + * + * @author 科技小王子 + * @since 2024-01-15 18:52:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "Version对象", description = "版本更新") +@TableName("sys_version") +public class Version implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "版本名") + private String versionName; + + @Schema(description = "版本号") + private String versionCode; + + @Schema(description = "下载链接") + private String vueDownloadUrl; + + @Schema(description = "下载链接") + private String androidDownloadUrl; + + @Schema(description = "下载链接") + private String iosDownloadUrl; + + @Schema(description = "更新日志") + private String updateInfo; + + @Schema(description = "强制更新") + private Integer isHard; + + @Schema(description = "热更") + private Integer isHot; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文章排序(数字越小越靠前)") + private Integer sortNumber; + + private Integer userId; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/WebsiteField.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/WebsiteField.java new file mode 100644 index 0000000..22399ce --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/WebsiteField.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用参数 + * + * @author 科技小王子 + * @since 2024-08-27 15:18:05 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "WebsiteField对象", description = "应用参数") +@TableName("sys_website_field") +public class WebsiteField implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "类型,0文本 1图片 2其他") + private Integer type; + + @Schema(description = "名称") + private String name; + + @Schema(description = "默认值") + private String defaultValue; + + @Schema(description = "可修改的值 [on|off]") + private String modifyRange; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "名称") + private String value; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/WhiteDomain.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/WhiteDomain.java new file mode 100644 index 0000000..ca8a65f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/entity/WhiteDomain.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 服务器白名单 + * + * @author 科技小王子 + * @since 2024-03-26 00:22:21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "WhiteDomain对象", description = "服务器白名单") +@TableName("sys_white_domain") +public class WhiteDomain implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/AccessKeyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/AccessKeyMapper.java new file mode 100644 index 0000000..658f773 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/AccessKeyMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.AccessKey; +import com.gxwebsoft.common.system.param.AccessKeyParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 访问凭证管理Mapper + * + * @author 科技小王子 + * @since 2023-05-16 19:19:55 + */ +public interface AccessKeyMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AccessKeyParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") AccessKeyParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/AuthorizeCodeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/AuthorizeCodeMapper.java new file mode 100644 index 0000000..8bd7a34 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/AuthorizeCodeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.AuthorizeCode; +import com.gxwebsoft.common.system.param.AuthorizeCodeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 授权码Mapper + * + * @author 科技小王子 + * @since 2025-08-05 01:17:27 + */ +public interface AuthorizeCodeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") AuthorizeCodeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") AuthorizeCodeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CartMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CartMapper.java new file mode 100644 index 0000000..a0e9950 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CartMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Cart; +import com.gxwebsoft.common.system.param.CartParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 购物车Mapper + * + * @author 科技小王子 + * @since 2024-10-26 10:54:51 + */ +public interface CartMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CartParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CartParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ChatConversationMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ChatConversationMapper.java new file mode 100644 index 0000000..bd34512 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ChatConversationMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.ChatConversation; +import com.gxwebsoft.common.system.param.ChatConversationParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 聊天消息表Mapper + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +public interface ChatConversationMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ChatConversationParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ChatConversationParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ChatMessageMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ChatMessageMapper.java new file mode 100644 index 0000000..6fe933b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ChatMessageMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.ChatMessage; +import com.gxwebsoft.common.system.param.ChatMessageParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 聊天消息表Mapper + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +public interface ChatMessageMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ChatMessageParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ChatMessageParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyCommentMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyCommentMapper.java new file mode 100644 index 0000000..d80c603 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyCommentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyComment; +import com.gxwebsoft.common.system.param.CompanyCommentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用评论Mapper + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyCommentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyCommentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyCommentParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyContentMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyContentMapper.java new file mode 100644 index 0000000..3a75de9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyContentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyContent; +import com.gxwebsoft.common.system.param.CompanyContentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用详情Mapper + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +public interface CompanyContentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyContentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyContentParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyGitMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyGitMapper.java new file mode 100644 index 0000000..345650f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyGitMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyGit; +import com.gxwebsoft.common.system.param.CompanyGitParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 代码仓库Mapper + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +public interface CompanyGitMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyGitParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyGitParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyMapper.java new file mode 100644 index 0000000..28b534f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyMapper.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.param.CompanyParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 企业信息Mapper + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +public interface CompanyMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyParam param); + + @InterceptorIgnore(tenantLine = "true") + List getCount(@Param("param") CompanyParam param); + + @InterceptorIgnore(tenantLine = "true") + List selectPageRelAll(PageParam page, CompanyParam param); + + @InterceptorIgnore(tenantLine = "true") + Company getCompanyAll(@Param("companyId") Integer companyId); + + @InterceptorIgnore(tenantLine = "true") + void updateByCompanyId(@Param("param") Company company); + + @InterceptorIgnore(tenantLine = "true") + boolean removeCompanyAll(Integer id); + + @InterceptorIgnore(tenantLine = "true") + boolean undeleteAll(Integer id); + + @InterceptorIgnore(tenantLine = "true") + boolean updateByIdAll(Company company); + + @InterceptorIgnore(tenantLine = "true") + Company getByTenantId(Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyParameterMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyParameterMapper.java new file mode 100644 index 0000000..c55b5f0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyParameterMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyParameter; +import com.gxwebsoft.common.system.param.CompanyParameterParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用参数Mapper + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyParameterMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyParameterParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyParameterParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyUrlMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyUrlMapper.java new file mode 100644 index 0000000..117ed2b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/CompanyUrlMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.CompanyUrl; +import com.gxwebsoft.common.system.param.CompanyUrlParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用域名Mapper + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyUrlMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CompanyUrlParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CompanyUrlParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ComponentsMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ComponentsMapper.java new file mode 100644 index 0000000..70a58c9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ComponentsMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Components; +import com.gxwebsoft.common.system.param.ComponentsParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 组件Mapper + * + * @author 科技小王子 + * @since 2024-08-25 19:08:51 + */ +public interface ComponentsMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ComponentsParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ComponentsParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictDataMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictDataMapper.java new file mode 100644 index 0000000..f36039f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictDataMapper.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 字典数据Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictDataMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") DictDataParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") DictDataParam param); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return List + */ + List getByDictCodeAndName(@Param("dictCode") String dictCode, + @Param("dictDataName") String dictDataName); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictMapper.java new file mode 100644 index 0000000..ce19779 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Dict; + +/** + * 字典Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictMapper extends BaseMapper { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryDataMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryDataMapper.java new file mode 100644 index 0000000..519c2ba --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryDataMapper.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.param.DictionaryDataParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 字典数据Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictionaryDataMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") DictionaryDataParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") DictionaryDataParam param); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return List + */ + List getByDictCodeAndName(@Param("dictCode") String dictCode, + @Param("dictDataName") String dictDataName); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryMapper.java new file mode 100644 index 0000000..7c2cbac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DictionaryMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Dictionary; + +/** + * 字典Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictionaryMapper extends BaseMapper { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DomainMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DomainMapper.java new file mode 100644 index 0000000..2853001 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/DomainMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.param.DomainParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 授权域名Mapper + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +public interface DomainMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") DomainParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") DomainParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/EmailRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/EmailRecordMapper.java new file mode 100644 index 0000000..02611c9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/EmailRecordMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.EmailRecord; + +/** + * 邮件记录Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface EmailRecordMapper extends BaseMapper { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/EnvironmentMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/EnvironmentMapper.java new file mode 100644 index 0000000..b3ea0d3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/EnvironmentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Environment; +import com.gxwebsoft.common.system.param.EnvironmentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 环境管理Mapper + * + * @author 科技小王子 + * @since 2023-10-18 08:45:13 + */ +public interface EnvironmentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") EnvironmentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") EnvironmentParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/FileRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/FileRecordMapper.java new file mode 100644 index 0000000..fe9f0b8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/FileRecordMapper.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.param.FileRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 文件上传记录Mapper + * + * @author WebSoft + * @since 2021-08-30 11:18:04 + */ +public interface FileRecordMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") FileRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") FileRecordParam param); + + /** + * 根据path查询 + * + * @param path 文件路径 + * @return FileRecord + */ + @InterceptorIgnore(tenantLine = "true") + List getByIdPath(@Param("path") String path); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/LoginRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/LoginRecordMapper.java new file mode 100644 index 0000000..4409fdd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/LoginRecordMapper.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.param.LoginRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 登录日志Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:11 + */ +public interface LoginRecordMapper extends BaseMapper { + + /** + * 添加, 排除租户拦截 + * + * @param entity LoginRecord + * @return int + */ + @Override + @InterceptorIgnore(tenantLine = "true") + int insert(LoginRecord entity); + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") LoginRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") LoginRecordParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MenuMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MenuMapper.java new file mode 100644 index 0000000..938ef17 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MenuMapper.java @@ -0,0 +1,22 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.param.MenuParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 菜单Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:32 + */ +public interface MenuMapper extends BaseMapper { + @InterceptorIgnore(tenantLine = "true") + List getMenuByClone(@Param("param") MenuParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantAccountMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantAccountMapper.java new file mode 100644 index 0000000..5e58680 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantAccountMapper.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.MerchantAccount; +import com.gxwebsoft.common.system.param.MerchantAccountParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户账号Mapper + * + * @author 科技小王子 + * @since 2024-04-19 12:02:24 + */ +public interface MerchantAccountMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") MerchantAccountParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") MerchantAccountParam param); + + @InterceptorIgnore(tenantLine = "true") + MerchantAccount getMerchantAccountByPhone(@Param("param") MerchantAccountParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantApplyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantApplyMapper.java new file mode 100644 index 0000000..3e19247 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantApplyMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.MerchantApply; +import com.gxwebsoft.common.system.param.MerchantApplyParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户入驻申请Mapper + * + * @author 科技小王子 + * @since 2024-04-05 01:24:36 + */ +public interface MerchantApplyMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") MerchantApplyParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") MerchantApplyParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantMapper.java new file mode 100644 index 0000000..9e92d10 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Merchant; +import com.gxwebsoft.common.system.param.MerchantParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户Mapper + * + * @author 科技小王子 + * @since 2024-04-05 00:03:54 + */ +public interface MerchantMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") MerchantParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") MerchantParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantTypeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantTypeMapper.java new file mode 100644 index 0000000..2ec5ceb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/MerchantTypeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.MerchantType; +import com.gxwebsoft.common.system.param.MerchantTypeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户类型Mapper + * + * @author 科技小王子 + * @since 2024-04-05 00:08:51 + */ +public interface MerchantTypeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") MerchantTypeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") MerchantTypeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ModulesMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ModulesMapper.java new file mode 100644 index 0000000..f4dc531 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/ModulesMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Modules; +import com.gxwebsoft.common.system.param.ModulesParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 模块管理Mapper + * + * @author 科技小王子 + * @since 2023-10-18 15:53:43 + */ +public interface ModulesMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ModulesParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ModulesParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/NoticeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/NoticeMapper.java new file mode 100644 index 0000000..50c9f50 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/NoticeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Notice; +import com.gxwebsoft.common.system.param.NoticeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 消息记录表Mapper + * + * @author 科技小王子 + * @since 2023-10-08 13:22:21 + */ +public interface NoticeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") NoticeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") NoticeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OperationRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OperationRecordMapper.java new file mode 100644 index 0000000..8750c2a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OperationRecordMapper.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.param.OperationRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 操作日志Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:03 + */ +public interface OperationRecordMapper extends BaseMapper { + + /** + * 添加, 排除租户拦截 + * + * @param entity OperationRecord + * @return int + */ + @Override + @InterceptorIgnore(tenantLine = "true") + int insert(OperationRecord entity); + + /** + * 分页查询 + * + * @param page 分页参数 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") OperationRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") OperationRecordParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderGoodsMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderGoodsMapper.java new file mode 100644 index 0000000..e166b4c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderGoodsMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.OrderGoods; +import com.gxwebsoft.common.system.param.OrderGoodsParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 订单商品Mapper + * + * @author 科技小王子 + * @since 2024-10-26 12:18:05 + */ +public interface OrderGoodsMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") OrderGoodsParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") OrderGoodsParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderInfoMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderInfoMapper.java new file mode 100644 index 0000000..a5ecc43 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderInfoMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.OrderInfo; +import com.gxwebsoft.common.system.param.OrderInfoParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * Mapper + * + * @author 科技小王子 + * @since 2024-05-10 18:02:54 + */ +public interface OrderInfoMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") OrderInfoParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") OrderInfoParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderMapper.java new file mode 100644 index 0000000..8fb9a0e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrderMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Order; +import com.gxwebsoft.common.system.param.OrderParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 订单Mapper + * + * @author 科技小王子 + * @since 2024-10-16 12:32:52 + */ +public interface OrderMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") OrderParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") OrderParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrganizationMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrganizationMapper.java new file mode 100644 index 0000000..6f06689 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/OrganizationMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.param.OrganizationParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 组织机构Mapper + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface OrganizationMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") OrganizationParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") OrganizationParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/PaymentMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/PaymentMapper.java new file mode 100644 index 0000000..c58aeb8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/PaymentMapper.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.param.PaymentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 支付方式Mapper + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +public interface PaymentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") PaymentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") PaymentParam param); + + @InterceptorIgnore(tenantLine = "true") + Payment getByType(@Param("param") PaymentParam paymentParam); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/PlugMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/PlugMapper.java new file mode 100644 index 0000000..600b1a2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/PlugMapper.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.param.PlugParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 插件扩展Mapper + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +public interface PlugMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List selectPageRel(@Param("page") IPage page, + @Param("param") PlugParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") PlugParam param); + + @InterceptorIgnore(tenantLine = "true") + List getMenuByClone(@Param("param") PlugParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RechargeOrderMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RechargeOrderMapper.java new file mode 100644 index 0000000..eab2641 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RechargeOrderMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.RechargeOrder; +import com.gxwebsoft.common.system.param.RechargeOrderParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 会员充值订单表Mapper + * + * @author 科技小王子 + * @since 2024-07-26 23:18:48 + */ +public interface RechargeOrderMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") RechargeOrderParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") RechargeOrderParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RoleMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RoleMapper.java new file mode 100644 index 0000000..b00f275 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RoleMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Role; + +/** + * 角色Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:44 + */ +public interface RoleMapper extends BaseMapper { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RoleMenuMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RoleMenuMapper.java new file mode 100644 index 0000000..a225765 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/RoleMenuMapper.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色菜单Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:21 + */ +public interface RoleMenuMapper extends BaseMapper { + + /** + * 查询用户的菜单 + * + * @param userId 用户id + * @param menuType 菜单类型 + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List listMenuByUserId(@Param("userId") Integer userId, @Param("menuType") Integer menuType); + + /** + * 根据角色id查询菜单 + * + * @param roleIds 角色id + * @param menuType 菜单类型 + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List listMenuByRoleIds(@Param("roleIds") List roleIds, @Param("menuType") Integer menuType); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java new file mode 100644 index 0000000..243f2d8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/SettingMapper.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.param.SettingParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 系统设置Mapper + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +public interface SettingMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") SettingParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") SettingParam param); + + @InterceptorIgnore(tenantLine = "true") + Setting getBySettingKeyIgnore(@Param("param") SettingParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/SysFileTypeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/SysFileTypeMapper.java new file mode 100644 index 0000000..026b0d9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/SysFileTypeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.SysFileType; +import com.gxwebsoft.common.system.param.SysFileTypeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 存储类型Mapper + * + * @author 科技小王子 + * @since 2025-05-16 14:24:28 + */ +public interface SysFileTypeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") SysFileTypeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") SysFileTypeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantMapper.java new file mode 100644 index 0000000..17f4a25 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.TenantParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 租户Mapper + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +public interface TenantMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") TenantParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") TenantParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantPackageMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantPackageMapper.java new file mode 100644 index 0000000..4c32508 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantPackageMapper.java @@ -0,0 +1,33 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.TenantPackage; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 租户套餐Mapper + * + * @author WebSoft + * @since 2025-12-12 + */ +@InterceptorIgnore(tenantLine = "true") +public interface TenantPackageMapper extends BaseMapper { + + /** + * 查询所有上架的套餐 + * + * @return List + */ + List selectAvailablePackages(); + + /** + * 根据版本号查询套餐 + * + * @param version 版本号 + * @return TenantPackage + */ + TenantPackage selectByVersion(@Param("version") Integer version); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantSubscriptionMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantSubscriptionMapper.java new file mode 100644 index 0000000..1479181 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantSubscriptionMapper.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.TenantSubscription; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; + +/** + * 租户订阅记录Mapper + * + * @author WebSoft + * @since 2025-12-12 + */ +public interface TenantSubscriptionMapper extends BaseMapper { + + /** + * 根据租户ID查询订阅信息(关联查询) + * + * @param tenantId 租户ID + * @return TenantSubscription + */ + @InterceptorIgnore(tenantLine = "true") + TenantSubscription selectByTenantIdRel(@Param("tenantId") Integer tenantId); + + /** + * 查询即将过期的订阅(用于提醒) + * + * @param days 提前天数 + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List selectExpiringSoon(@Param("days") Integer days); + + /** + * 查询已过期的订阅 + * + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List selectExpired(); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantSubscriptionOrderMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantSubscriptionOrderMapper.java new file mode 100644 index 0000000..89059f2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/TenantSubscriptionOrderMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 租户订阅订单Mapper + * + * @author WebSoft + * @since 2025-12-12 + */ +@InterceptorIgnore(tenantLine = "true") +public interface TenantSubscriptionOrderMapper extends BaseMapper { + + /** + * 分页查询订单 + * + * @param page 分页对象 + * @param tenantId 租户ID + * @return List + */ + List selectPageByTenant(@Param("page") IPage page, + @Param("tenantId") Integer tenantId); + + /** + * 根据订单号查询 + * + * @param orderNo 订单号 + * @return TenantSubscriptionOrder + */ + TenantSubscriptionOrder selectByOrderNo(@Param("orderNo") String orderNo); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserBalanceLogMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserBalanceLogMapper.java new file mode 100644 index 0000000..f986c44 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserBalanceLogMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户余额变动明细表Mapper + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +public interface UserBalanceLogMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserBalanceLogParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserBalanceLogParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserCollectionMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserCollectionMapper.java new file mode 100644 index 0000000..b7330da --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserCollectionMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.param.UserCollectionParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 我的收藏Mapper + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +public interface UserCollectionMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserCollectionParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserCollectionParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserFileMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserFileMapper.java new file mode 100644 index 0000000..d9e4bb4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserFileMapper.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.UserFile; + +/** + * 用户文件Mapper + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +public interface UserFileMapper extends BaseMapper { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserGradeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserGradeMapper.java new file mode 100644 index 0000000..f966ee3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserGradeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserGrade; +import com.gxwebsoft.common.system.param.UserGradeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户会员等级表Mapper + * + * @author 科技小王子 + * @since 2023-10-07 22:51:17 + */ +public interface UserGradeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserGradeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserGradeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserGroupMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserGroupMapper.java new file mode 100644 index 0000000..8e38749 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserGroupMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserGroup; +import com.gxwebsoft.common.system.param.UserGroupParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户分组管理表Mapper + * + * @author 科技小王子 + * @since 2023-10-28 15:16:39 + */ +public interface UserGroupMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserGroupParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserGroupParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java new file mode 100644 index 0000000..56a4a58 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserMapper.java @@ -0,0 +1,80 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsWebsite; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.UserParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:14 + */ +public interface UserMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserParam param); + + /** + * 根据账号查询 + * + * @param username 账号 + * @param tenantId 租户id + * @return User + */ + @InterceptorIgnore(tenantLine = "true") + User selectByUsername(@Param("username") String username, @Param("tenantId") Integer tenantId); + + @InterceptorIgnore(tenantLine = "true") + List getOne(@Param("param") UserParam param); + + List selectListStatisticsRel(@Param("param") UserParam param); + + @InterceptorIgnore(tenantLine = "true") + void updateByUserId(@Param("param") User param); + + /** + * 根据用户ID查询用户(忽略租户隔离) + * @param userId 用户ID + * @return User + */ + @InterceptorIgnore(tenantLine = "true") + User selectByIdIgnoreTenant(@Param("userId") Integer userId); + + @InterceptorIgnore(tenantLine = "true") + List pageAdminByPhone(@Param("param") UserParam param); + + @InterceptorIgnore(tenantLine = "true") + List listByAlert(); + + /** + * 根据账号查询用户(忽略租户隔离) + * 支持 username / phone / email 登录 + * + * @param username 账号/手机号/邮箱 + * @return User + */ + @InterceptorIgnore(tenantLine = "true") + User selectByUsernameIgnoreTenant(@Param("username") String username); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserOauthMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserOauthMapper.java new file mode 100644 index 0000000..1d3e164 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserOauthMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserOauth; +import com.gxwebsoft.common.system.param.UserOauthParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 第三方用户信息表Mapper + * + * @author 科技小王子 + * @since 2023-10-07 22:39:46 + */ +public interface UserOauthMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserOauthParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserOauthParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserRefereeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserRefereeMapper.java new file mode 100644 index 0000000..e729045 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserRefereeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.param.UserRefereeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户推荐关系表Mapper + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +public interface UserRefereeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserRefereeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserRefereeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserRoleMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserRoleMapper.java new file mode 100644 index 0000000..51b38c8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserRoleMapper.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.UserRole; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户角色Mapper + * + * @author WebSoft + * @since 2018-12-24 16:10:02 + */ +public interface UserRoleMapper extends BaseMapper { + + /** + * 批量添加用户角色 + * + * @param userId 用户id + * @param roleIds 角色id集合 + * @return int + */ + int insertBatch(@Param("userId") Integer userId, @Param("roleIds") List roleIds); + + /** + * 根据用户id查询角色 + * + * @param userId 用户id + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + List selectByUserId(@Param("userId") Integer userId); + + /** + * 批量根据用户id查询角色 + * + * @param userIds 用户id集合 + * @return List + */ + List selectByUserIds(@Param("userIds") List userIds); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserVerifyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserVerifyMapper.java new file mode 100644 index 0000000..44fb323 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/UserVerifyMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.UserVerify; +import com.gxwebsoft.common.system.param.UserVerifyParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 实名认证Mapper + * + * @author 科技小王子 + * @since 2025-05-29 23:01:04 + */ +public interface UserVerifyMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") UserVerifyParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") UserVerifyParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/VersionMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/VersionMapper.java new file mode 100644 index 0000000..0ae8f69 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/VersionMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.Version; +import com.gxwebsoft.common.system.param.VersionParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 版本更新Mapper + * + * @author 科技小王子 + * @since 2024-01-15 18:52:24 + */ +public interface VersionMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") VersionParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") VersionParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/WebsiteFieldMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/WebsiteFieldMapper.java new file mode 100644 index 0000000..2e15906 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/WebsiteFieldMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.WebsiteField; +import com.gxwebsoft.common.system.param.WebsiteFieldParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 应用参数Mapper + * + * @author 科技小王子 + * @since 2024-08-27 15:18:05 + */ +public interface WebsiteFieldMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") WebsiteFieldParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") WebsiteFieldParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/WhiteDomainMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/WhiteDomainMapper.java new file mode 100644 index 0000000..9e3d0d1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/WhiteDomainMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.common.system.entity.WhiteDomain; +import com.gxwebsoft.common.system.param.WhiteDomainParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 服务器白名单Mapper + * + * @author 科技小王子 + * @since 2024-03-26 00:22:21 + */ +public interface WhiteDomainMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") WhiteDomainParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") WhiteDomainParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/AccessKeyMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/AccessKeyMapper.xml new file mode 100644 index 0000000..9e870d7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/AccessKeyMapper.xml @@ -0,0 +1,44 @@ + + + + + + + SELECT a.* + FROM sys_access_key a + + + AND a.id = #{param.id} + + + AND a.accessKey LIKE CONCAT('%', #{param.accessKey}, '%') + + + AND a.accessSecret LIKE CONCAT('%', #{param.accessSecret}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/AuthorizeCodeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/AuthorizeCodeMapper.xml new file mode 100644 index 0000000..9fec730 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/AuthorizeCodeMapper.xml @@ -0,0 +1,47 @@ + + + + + + + SELECT a.* + FROM sys_authorize_code a + + + AND a.id = #{param.id} + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CartMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CartMapper.xml new file mode 100644 index 0000000..27f5dc1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CartMapper.xml @@ -0,0 +1,77 @@ + + + + + + + SELECT a.* + FROM sys_cart a + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.item_id LIKE CONCAT('%', #{param.itemId}, '%') + + + AND a.spec LIKE CONCAT('%', #{param.spec}, '%') + + + AND a.price = #{param.price} + + + AND a.cart_num = #{param.cartNum} + + + AND a.total_price = #{param.totalPrice} + + + AND a.is_pay = #{param.isPay} + + + AND a.is_new = #{param.isNew} + + + AND a.combination_id = #{param.combinationId} + + + AND a.seckill_id = #{param.seckillId} + + + AND a.bargain_id = #{param.bargainId} + + + AND a.selected = #{param.selected} + + + AND a.merchant_id LIKE CONCAT('%', #{param.merchantId}, '%') + + + AND a.user_id LIKE CONCAT('%', #{param.userId}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ChatConversationMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ChatConversationMapper.xml new file mode 100644 index 0000000..94c77c0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ChatConversationMapper.xml @@ -0,0 +1,56 @@ + + + + + + + SELECT a.* + FROM sys_chat_conversation a + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.friend_id = #{param.friendId} + + + AND a.type = #{param.type} + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.un_read = #{param.unRead} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ChatMessageMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ChatMessageMapper.xml new file mode 100644 index 0000000..e387466 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ChatMessageMapper.xml @@ -0,0 +1,78 @@ + + + + + + + SELECT a.*,b.nickname as formUserName,b.avatar as formUserAvatar,c.nickname as toUserName,c.avatar as toUserAvatar + FROM sys_chat_message a + LEFT JOIN sys_user b ON a.form_user_id = b.user_id + LEFT JOIN sys_user c ON a.to_user_id = c.user_id + + + AND a.id = #{param.id} + + + AND a.form_user_id = #{param.formUserId} + + + AND a.to_user_id = #{param.toUserId} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.side_to = #{param.sideTo} + + + AND a.side_from = #{param.sideFrom} + + + AND a.withdraw = #{param.withdraw} + + + AND a.file_info LIKE CONCAT('%', #{param.fileInfo}, '%') + + + AND a.has_contact = #{param.hasContact} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND ( + a.content LIKE CONCAT('%', #{param.keywords}, '%') + OR b.nickname LIKE CONCAT('%', #{param.keywords}, '%') + OR b.phone LIKE CONCAT('%', #{param.keywords}, '%') + OR b.real_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyCommentMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyCommentMapper.xml new file mode 100644 index 0000000..0e04c48 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyCommentMapper.xml @@ -0,0 +1,53 @@ + + + + + + + SELECT a.* + FROM sys_company_comment a + + + AND a.id = #{param.id} + + + AND a.parent_id = #{param.parentId} + + + AND a.user_id = #{param.userId} + + + AND a.company_id = #{param.companyId} + + + AND a.rate = #{param.rate} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyContentMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyContentMapper.xml new file mode 100644 index 0000000..06207e5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyContentMapper.xml @@ -0,0 +1,38 @@ + + + + + + + SELECT a.* + FROM sys_company_content a + + + AND a.id = #{param.id} + + + AND a.company_id = #{param.companyId} + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyGitMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyGitMapper.xml new file mode 100644 index 0000000..bf8c616 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyGitMapper.xml @@ -0,0 +1,65 @@ + + + + + + + SELECT a.* + FROM sys_company_git a + + + AND a.id = #{param.id} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.brand = #{param.brand} + + + AND a.company_id = #{param.companyId} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.account LIKE CONCAT('%', #{param.account}, '%') + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND ( + a.title LIKE CONCAT('%', #{param.keywords}, '%') + OR a.domain LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyMapper.xml new file mode 100644 index 0000000..ad61d39 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyMapper.xml @@ -0,0 +1,198 @@ + + + + + + + SELECT a.*,b.tenant_id,b.tenant_name,b.tenant_code,c.title as categoryName + FROM gxwebsoft_core.sys_company a + LEFT JOIN gxwebsoft_core.sys_tenant b ON a.tenant_id = b.tenant_id + LEFT JOIN gxwebsoft_core.cms_navigation c ON a.category_id = c.navigation_id + + + AND a.company_id = #{param.companyId} + + + AND a.type = #{param.type} + + + AND a.official = #{param.official} + + + AND a.category_id = #{param.categoryId} + + + AND a.short_name LIKE CONCAT('%', #{param.shortName}, '%') + + + AND a.company_name LIKE CONCAT('%', #{param.companyName}, '%') + + + AND a.company_type = #{param.companyType} + + + AND a.company_logo LIKE CONCAT('%', #{param.companyLogo}, '%') + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.phone = #{param.phone} + + + AND a.Invoice_header LIKE CONCAT('%', #{param.invoiceHeader}, '%') + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') + + + AND a.version = #{param.version} + + + AND a.members = #{param.members} + + + AND a.industry_parent LIKE CONCAT('%', #{param.industryParent}, '%') + + + AND a.industry_child LIKE CONCAT('%', #{param.industryChild}, '%') + + + AND a.departments = #{param.departments} + + + AND a.country LIKE CONCAT('%', #{param.country}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%') + + + AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.authentication = #{param.authentication} + + + AND a.status = #{param.status} + + + AND a.app_type = #{param.appType} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.authoritative = #{param.authoritative} + + + AND a.recommend = 1 + + + AND a.short_name = #{param.appName} + + + AND a.email = #{param.email} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.company_id IN + + #{item} + + + + AND (a.company_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.short_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.tenant_id = #{param.keywords} + OR a.phone = #{param.keywords} + OR a.domain LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + + + + + + + + + UPDATE sys_company SET storage = #{param.storage} WHERE company_id = #{param.companyId} + + + + + UPDATE sys_company SET deleted = 1 WHERE company_id = #{param.companyId} + + + + UPDATE sys_company SET deleted = 0 WHERE company_id = #{param.companyId} + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyParameterMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyParameterMapper.xml new file mode 100644 index 0000000..eabfba2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyParameterMapper.xml @@ -0,0 +1,50 @@ + + + + + + + SELECT a.* + FROM sys_company_parameter a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.value LIKE CONCAT('%', #{param.value}, '%') + + + AND a.company_id = #{param.companyId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyUrlMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyUrlMapper.xml new file mode 100644 index 0000000..6db9462 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/CompanyUrlMapper.xml @@ -0,0 +1,59 @@ + + + + + + + SELECT a.* + FROM sys_company_url a + + + AND a.id = #{param.id} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.company_id = #{param.companyId} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.account LIKE CONCAT('%', #{param.account}, '%') + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.qrcode LIKE CONCAT('%', #{param.qrcode}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ComponentsMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ComponentsMapper.xml new file mode 100644 index 0000000..078b9ed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ComponentsMapper.xml @@ -0,0 +1,65 @@ + + + + + + + SELECT a.* + FROM sys_components a + + + AND a.id = #{param.id} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.navigation_id = #{param.navigationId} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.icon LIKE CONCAT('%', #{param.icon}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictDataMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictDataMapper.xml new file mode 100644 index 0000000..a831629 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictDataMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.*, + b.dict_code, + b.dict_name + FROM gxwebsoft_core.sys_dict_data a + LEFT JOIN gxwebsoft_core.sys_dict b ON a.dict_id = b.dict_id + + AND a.deleted = 0 + + AND a.dict_data_id = #{param.dictDataId} + + + AND a.dict_id = #{param.dictId} + + + AND a.dict_data_code LIKE CONCAT('%', #{param.dictDataCode}, '%') + + + AND a.dict_data_name LIKE CONCAT('%', #{param.dictDataName}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.dict_code = #{param.dictCode} + + + AND b.dict_name = #{param.dictName} + + + AND ( + a.dict_data_code LIKE CONCAT('%', #{param.keywords}, '%') + OR a.dict_data_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictMapper.xml new file mode 100644 index 0000000..db709ae --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryDataMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryDataMapper.xml new file mode 100644 index 0000000..886303b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryDataMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.*, + b.dict_code, + b.dict_name + FROM sys_dictionary_data a + LEFT JOIN gxwebsoft_core.sys_dictionary b ON a.dict_id = b.dict_id + + AND a.deleted = 0 + + AND a.dict_data_id = #{param.dictDataId} + + + AND a.dict_id = #{param.dictId} + + + AND a.dict_data_code LIKE CONCAT('%', #{param.dictDataCode}, '%') + + + AND a.dict_data_name LIKE CONCAT('%', #{param.dictDataName}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.dict_code = #{param.dictCode} + + + AND b.dict_name = #{param.dictName} + + + AND ( + a.dict_data_code LIKE CONCAT('%', #{param.keywords}, '%') + OR a.dict_data_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryMapper.xml new file mode 100644 index 0000000..8cd0cff --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DictionaryMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DomainMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DomainMapper.xml new file mode 100644 index 0000000..1299cf7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/DomainMapper.xml @@ -0,0 +1,62 @@ + + + + + + + SELECT a.* + FROM sys_domain a + + + AND a.id = #{param.id} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.host_name LIKE CONCAT('%', #{param.hostName}, '%') + + + AND a.host_value LIKE CONCAT('%', #{param.hostValue}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.type = #{param.type} + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/EmailRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/EmailRecordMapper.xml new file mode 100644 index 0000000..7b5ad62 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/EmailRecordMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/EnvironmentMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/EnvironmentMapper.xml new file mode 100644 index 0000000..917f93d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/EnvironmentMapper.xml @@ -0,0 +1,68 @@ + + + + + + + SELECT a.* + FROM sys_environment a + + + AND a.id = #{param.id} + + + AND a.environment_name LIKE CONCAT('%', #{param.environmentName}, '%') + + + AND a.environment_code LIKE CONCAT('%', #{param.environmentCode}, '%') + + + AND a.brand LIKE CONCAT('%', #{param.brand}, '%') + + + AND a.server_ip LIKE CONCAT('%', #{param.serverIp}, '%') + + + AND a.modules_url LIKE CONCAT('%', #{param.modulesUrl}, '%') + + + AND a.modules_api LIKE CONCAT('%', #{param.modulesApi}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/FileRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/FileRecordMapper.xml new file mode 100644 index 0000000..1a7dd22 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/FileRecordMapper.xml @@ -0,0 +1,76 @@ + + + + + + + SELECT a.*, + b.username create_username, + b.nickname create_nickname, + b.avatar, + c.merchant_code + FROM sys_file_record a + LEFT JOIN gxwebsoft_core.sys_user b ON a.create_user_id = b.user_id + LEFT JOIN shop_merchant c ON a.merchant_code = c.merchant_code + + + AND a.id = #{param.id} + + + AND a.`name` LIKE CONCAT('%', #{param.name}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.create_user_id = #{param.createUserId} + + + AND a.group_id = #{param.groupId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND b.username = #{param.createUsername} + + + AND b.nickname LIKE CONCAT('%', #{param.createNickname}, '%') + + + AND a.content_type LIKE CONCAT('%', #{param.contentType}, '%') + + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/LoginRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/LoginRecordMapper.xml new file mode 100644 index 0000000..397c525 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/LoginRecordMapper.xml @@ -0,0 +1,62 @@ + + + + + + + SELECT a.*, + b.user_id, + b.nickname + FROM sys_login_record a + LEFT JOIN gxwebsoft_core.sys_user b ON a.username = b.username + + + AND a.id = #{param.id} + + + AND a.username LIKE CONCAT('%', #{param.username}, '%') + + + AND a.os LIKE CONCAT('%', #{param.os}, '%') + + + AND a.device LIKE CONCAT('%', #{param.device}, '%') + + + AND a.browser LIKE CONCAT('%', #{param.browser}, '%') + + + AND a.ip LIKE CONCAT('%', #{param.ip}, '%') + + + AND a.login_type LIKE CONCAT('%', #{param.loginType}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.user_id = #{param.userId} + + + AND b.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MenuMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MenuMapper.xml new file mode 100644 index 0000000..0897489 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MenuMapper.xml @@ -0,0 +1,32 @@ + + + + + + + SELECT a.* + FROM sys_menu a + + + AND a.menu_id = #{param.menuId} + + + AND a.parent_id = #{param.parentId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.tenant_id = #{param.tenantId} + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantAccountMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantAccountMapper.xml new file mode 100644 index 0000000..527e540 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantAccountMapper.xml @@ -0,0 +1,61 @@ + + + + + + + SELECT a.*,b.merchant_name,b.goods_review + FROM sys_merchant_account a + LEFT JOIN sys_merchant b ON a.merchant_id = b.merchant_id + + + AND a.id = #{param.id} + + + AND a.phone = #{param.phone} + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.merchant_id = #{param.merchantId} + + + AND a.user_id = #{param.userId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantApplyMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantApplyMapper.xml new file mode 100644 index 0000000..f2c3478 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantApplyMapper.xml @@ -0,0 +1,81 @@ + + + + + + + SELECT a.* + FROM sys_merchant_apply a + + + AND a.apply_id = #{param.applyId} + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.shop_type LIKE CONCAT('%', #{param.shopType}, '%') + + + AND a.category LIKE CONCAT('%', #{param.category}, '%') + + + AND a.commission = #{param.commission} + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.own_store = #{param.ownStore} + + + AND a.recommend = #{param.recommend} + + + AND a.goods_review = #{param.goodsReview} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantMapper.xml new file mode 100644 index 0000000..4e134ee --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantMapper.xml @@ -0,0 +1,93 @@ + + + + + + + SELECT a.* + FROM sys_merchant a + + + AND a.merchant_id = #{param.merchantId} + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.shop_type LIKE CONCAT('%', #{param.shopType}, '%') + + + AND a.category LIKE CONCAT('%', #{param.category}, '%') + + + AND a.commission = #{param.commission} + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.own_store = #{param.ownStore} + + + AND a.recommend = #{param.recommend} + + + AND a.goods_review = #{param.goodsReview} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND ( + a.merchant_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.phone LIKE CONCAT('%', #{param.keywords}, '%') + OR a.real_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantTypeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantTypeMapper.xml new file mode 100644 index 0000000..9b60622 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/MerchantTypeMapper.xml @@ -0,0 +1,48 @@ + + + + + + + SELECT a.* + FROM sys_merchant_type a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ModulesMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ModulesMapper.xml new file mode 100644 index 0000000..0f157b6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/ModulesMapper.xml @@ -0,0 +1,56 @@ + + + + + + + SELECT a.* + FROM sys_modules a + + + AND a.id = #{param.id} + + + AND a.modules LIKE CONCAT('%', #{param.modules}, '%') + + + AND a.modules_url LIKE CONCAT('%', #{param.modulesUrl}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/NoticeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/NoticeMapper.xml new file mode 100644 index 0000000..147aeb2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/NoticeMapper.xml @@ -0,0 +1,80 @@ + + + + + + + SELECT a.* + FROM sys_notice a + + + AND a.notice_id = #{param.noticeId} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.icon LIKE CONCAT('%', #{param.icon}, '%') + + + AND a.color LIKE CONCAT('%', #{param.color}, '%') + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.is_read = #{param.isRead} + + + AND a.progress = #{param.progress} + + + AND a.channel = #{param.channel} + + + AND a.source LIKE CONCAT('%', #{param.source}, '%') + + + AND a.source_id = #{param.sourceId} + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OperationRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OperationRecordMapper.xml new file mode 100644 index 0000000..56b7fad --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OperationRecordMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.*, + b.nickname, + b.username + FROM gxwebsoft_core.sys_operation_record a + LEFT JOIN gxwebsoft_core.sys_user b ON a.user_id = b.user_id + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.module LIKE CONCAT('%', #{param.module}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.url LIKE CONCAT('%', #{param.url}, '%') + + + AND a.request_method = #{param.requestMethod} + + + AND a.method LIKE CONCAT('%', #{param.method}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.ip LIKE CONCAT('%', #{param.ip}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.`status` = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.username LIKE CONCAT('%', #{param.username}, '%') + + + AND b.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderGoodsMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderGoodsMapper.xml new file mode 100644 index 0000000..bf09f0c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderGoodsMapper.xml @@ -0,0 +1,84 @@ + + + + + + + SELECT a.*, b.short_name AS tenantName,b.company_logo as logo + FROM sys_order_goods a + LEFT JOIN sys_company b ON a.tenant_id = b.tenant_id + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.order_id = #{param.orderId} + + + AND a.item_id = #{param.itemId} + + + AND a.pay_price = #{param.payPrice} + + + AND a.total_num = #{param.totalNum} + + + AND a.pay_status = #{param.payStatus} + + + AND a.order_status = #{param.orderStatus} + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.is_invoice = #{param.isInvoice} + + + AND a.invoice_no LIKE CONCAT('%', #{param.invoiceNo}, '%') + + + AND a.pay_time LIKE CONCAT('%', #{param.payTime}, '%') + + + AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderInfoMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderInfoMapper.xml new file mode 100644 index 0000000..64da232 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderInfoMapper.xml @@ -0,0 +1,86 @@ + + + + + + + SELECT a.* + FROM sys_order_info a + + + AND a.id = #{param.id} + + + AND a.oid = #{param.oid} + + + AND a.sid = #{param.sid} + + + AND a.fid = #{param.fid} + + + AND a.site_name LIKE CONCAT('%', #{param.siteName}, '%') + + + AND a.field_name LIKE CONCAT('%', #{param.fieldName}, '%') + + + AND a.date_time LIKE CONCAT('%', #{param.dateTime}, '%') + + + AND a.price = #{param.price} + + + AND a.children_price = #{param.childrenPrice} + + + AND a.adult_num = #{param.adultNum} + + + AND a.children_num = #{param.childrenNum} + + + AND a.pay_status = #{param.payStatus} + + + AND a.is_free = #{param.isFree} + + + AND a.is_children = #{param.isChildren} + + + AND a.type = #{param.type} + + + AND a.merge_data LIKE CONCAT('%', #{param.mergeData}, '%') + + + AND a.start_time = #{param.startTime} + + + AND a.order_time = #{param.orderTime} + + + AND a.time_flag LIKE CONCAT('%', #{param.timeFlag}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderMapper.xml new file mode 100644 index 0000000..44d7d8c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrderMapper.xml @@ -0,0 +1,149 @@ + + + + + + + SELECT a.*, b.short_name AS tenantName,b.company_logo as logo + FROM sys_order a + LEFT JOIN sys_company b ON a.tenant_id = b.tenant_id + + + AND a.order_id = #{param.orderId} + + + AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%') + + + AND a.type = #{param.type} + + + AND a.channel = #{param.channel} + + + AND a.transaction_id LIKE CONCAT('%', #{param.transactionId}, '%') + + + AND a.refund_order LIKE CONCAT('%', #{param.refundOrder}, '%') + + + AND a.coupon_id = #{param.couponId} + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.total_price = #{param.totalPrice} + + + AND a.reduce_price = #{param.reducePrice} + + + AND a.pay_price = #{param.payPrice} + + + AND a.price = #{param.price} + + + AND a.money = #{param.money} + + + AND a.refund_money = #{param.refundMoney} + + + AND a.total_num = #{param.totalNum} + + + AND a.pay_type = #{param.payType} + + + AND a.pay_status = #{param.payStatus} + + + AND a.order_status = #{param.orderStatus} + + + AND a.coupon_type = #{param.couponType} + + + AND a.coupon_desc LIKE CONCAT('%', #{param.couponDesc}, '%') + + + AND a.qrcode LIKE CONCAT('%', #{param.qrcode}, '%') + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.is_invoice = #{param.isInvoice} + + + AND a.invoice_no LIKE CONCAT('%', #{param.invoiceNo}, '%') + + + AND a.pay_time LIKE CONCAT('%', #{param.payTime}, '%') + + + AND a.refund_time LIKE CONCAT('%', #{param.refundTime}, '%') + + + AND a.refund_apply_time LIKE CONCAT('%', #{param.refundApplyTime}, '%') + + + AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') + + + AND a.check_bill = #{param.checkBill} + + + AND a.is_settled = #{param.isSettled} + + + AND a.version = #{param.version} + + + AND a.user_id = #{param.userId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.tenant_id = #{param.keywords} + OR a.order_id = #{param.keywords} + OR a.phone = #{param.keywords} + OR a.real_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.order_no LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrganizationMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrganizationMapper.xml new file mode 100644 index 0000000..ed5d3c8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/OrganizationMapper.xml @@ -0,0 +1,98 @@ + + + + + + + SELECT ta.* + FROM sys_dictionary_data ta + LEFT JOIN gxwebsoft_core.sys_dictionary tb + ON ta.dict_id = tb.dict_id + AND tb.deleted = 0 + WHERE ta.deleted = 0 + AND tb.dict_code = 'organization_type' + + + + + SELECT a.*, + b.dict_data_name organization_type_name, + c.nickname leader_nickname, + c.username leader_username + FROM sys_organization a + LEFT JOIN ( + + ) b ON a.organization_type = b.dict_data_code + LEFT JOIN gxwebsoft_core.sys_user c ON a.leader_id = c.user_id + + AND a.deleted = 0 + + AND a.organization_id = #{param.organizationId} + + + AND a.parent_id = #{param.parentId} + + + AND a.organization_name LIKE CONCAT('%', #{param.organizationName}, '%') + + + AND a.organization_full_name LIKE CONCAT('%', #{param.organizationFullName}, '%') + + + AND a.organization_code LIKE CONCAT('%', #{param.organizationCode}, '%') + + + AND a.organization_type = #{param.organizationType} + + + AND a.province = #{param.province} + + + AND a.city = #{param.city} + + + AND a.region = #{param.province} + + + AND a.zip_code = #{param.zipCode} + + + AND a.leader_id = #{param.leaderId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.dict_data_name LIKE CONCAT('%', #{param.organizationTypeName}, '%') + + + AND c.nickname LIKE CONCAT('%', #{param.leaderNickname}, '%') + + + AND c.username LIKE CONCAT('%', #{param.leaderUsername}, '%') + + + AND ( + a.organization_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml new file mode 100644 index 0000000..d54c4bc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/PaymentMapper.xml @@ -0,0 +1,90 @@ + + + + + + + SELECT a.* + FROM gxwebsoft_core.sys_payment a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.type = #{param.type} + + + AND a.code = #{param.code} + + + AND a.wechat_type = #{param.wechatType} + + + AND a.app_id LIKE CONCAT('%', #{param.appId}, '%') + + + AND a.mch_id LIKE CONCAT('%', #{param.mchId}, '%') + + + AND a.api_key LIKE CONCAT('%', #{param.apiKey}, '%') + + + AND a.apiclient_cert LIKE CONCAT('%', #{param.apiclientCert}, '%') + + + AND a.apiclient_key LIKE CONCAT('%', #{param.apiclientKey}, '%') + + + AND a.merchant_serial_number LIKE CONCAT('%', #{param.merchantSerialNumber}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.tenant_id = #{param.tenantId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/PlugMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/PlugMapper.xml new file mode 100644 index 0000000..45e3aac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/PlugMapper.xml @@ -0,0 +1,105 @@ + + + + + + + SELECT a.*,b.tenant_name,c.company_name,c.short_name,c.domain + FROM sys_plug a + LEFT JOIN gxwebsoft_core.sys_tenant b ON a.tenant_id = b.tenant_id + LEFT JOIN gxwebsoft_core.sys_company c ON a.tenant_id = c.tenant_id + + + AND a.plug_id = #{param.plugId} + + + AND a.menu_id = #{param.menuId} + + + AND a.parent_id = #{param.parentId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.component LIKE CONCAT('%', #{param.component}, '%') + + + AND a.menu_type = #{param.menuType} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.authority LIKE CONCAT('%', #{param.authority}, '%') + + + AND a.target LIKE CONCAT('%', #{param.target}, '%') + + + AND a.icon LIKE CONCAT('%', #{param.icon}, '%') + + + AND a.color LIKE CONCAT('%', #{param.color}, '%') + + + AND a.hide = #{param.hide} + + + AND a.active LIKE CONCAT('%', #{param.active}, '%') + + + AND a.meta LIKE CONCAT('%', #{param.meta}, '%') + + + AND a.app_id = #{param.appId} + + + AND a.user_id = #{param.userId} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.title LIKE CONCAT('%', #{param.keywords}, '%') + OR a.menu_id = #{param.keywords} + OR c.company_name LIKE CONCAT('%', #{param.keywords}, '%') + OR c.short_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RechargeOrderMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RechargeOrderMapper.xml new file mode 100644 index 0000000..e1ebeec --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RechargeOrderMapper.xml @@ -0,0 +1,106 @@ + + + + + + + SELECT a.*,b.phone,b.nickname,b.user_id,b.avatar,b.real_name,c.organization_id,c.organization_name + FROM sys_recharge_order a + LEFT JOIN sys_user b ON a.user_id = b.user_id + LEFT JOIN sys_organization c ON a.organization_id = c.organization_id + + + AND a.order_id = #{param.orderId} + + + AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.recharge_type = #{param.rechargeType} + + + AND a.organization_id = #{param.organizationId} + + + AND a.plan_id = #{param.planId} + + + AND a.pay_price = #{param.payPrice} + + + AND a.gift_money = #{param.giftMoney} + + + AND a.actual_money = #{param.actualMoney} + + + AND a.balance = #{param.balance} + + + AND a.pay_method LIKE CONCAT('%', #{param.payMethod}, '%') + + + AND a.pay_status = #{param.payStatus} + + + AND a.pay_time = #{param.payTime} + + + AND a.trade_id = #{param.tradeId} + + + AND a.platform LIKE CONCAT('%', #{param.platform}, '%') + + + AND a.shop_id = #{param.shopId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND ( + b.nickname LIKE CONCAT('%', #{param.keywords}, '%') + OR a.user_id LIKE CONCAT('%', #{param.keywords}, '%') + OR b.alias LIKE CONCAT('%', #{param.keywords}, '%') + OR b.phone LIKE CONCAT('%', #{param.keywords}, '%') + OR b.real_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMapper.xml new file mode 100644 index 0000000..9f6facc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMenuMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMenuMapper.xml new file mode 100644 index 0000000..141c53c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/RoleMenuMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/SettingMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/SettingMapper.xml new file mode 100644 index 0000000..f99a88f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/SettingMapper.xml @@ -0,0 +1,33 @@ + + + + + + + SELECT a.* + FROM gxwebsoft_core.sys_setting a + + + AND a.setting_key = #{param.settingKey} + + + AND a.setting_id = #{param.settingId} + + + AND a.tenant_id = #{param.tenantId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/SysFileTypeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/SysFileTypeMapper.xml new file mode 100644 index 0000000..980c752 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/SysFileTypeMapper.xml @@ -0,0 +1,45 @@ + + + + + + + SELECT a.* + FROM sys_file_type a + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantMapper.xml new file mode 100644 index 0000000..15285b1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantMapper.xml @@ -0,0 +1,62 @@ + + + + + + + SELECT a.*, + u.username, + u.phone, + u.nickname, + u.real_name AS realName, + u.company_name AS companyName + FROM sys_tenant a + LEFT JOIN sys_user u ON u.user_id = a.user_id + + + AND a.tenant_id = #{param.tenantId} + + + AND a.tenant_name LIKE CONCAT('%', #{param.tenantName}, '%') + + + AND a.tenant_code LIKE CONCAT('%', #{param.tenantCode}, '%') + + + AND a.logo LIKE CONCAT('%', #{param.logo}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantPackageMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantPackageMapper.xml new file mode 100644 index 0000000..3b1ded6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantPackageMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantSubscriptionMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantSubscriptionMapper.xml new file mode 100644 index 0000000..4255e78 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantSubscriptionMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantSubscriptionOrderMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantSubscriptionOrderMapper.xml new file mode 100644 index 0000000..921084a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/TenantSubscriptionOrderMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserCollectionMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserCollectionMapper.xml new file mode 100644 index 0000000..9b60a69 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserCollectionMapper.xml @@ -0,0 +1,38 @@ + + + + + + + SELECT a.* + FROM sys_user_collection a + + + AND a.id = #{param.id} + + + AND a.tid = #{param.tid} + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserFileMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserFileMapper.xml new file mode 100644 index 0000000..872b232 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserFileMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserGradeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserGradeMapper.xml new file mode 100644 index 0000000..5797863 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserGradeMapper.xml @@ -0,0 +1,62 @@ + + + + + + + SELECT a.* + FROM sys_user_grade a + + + AND a.grade_id = #{param.gradeId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.weight = #{param.weight} + + + AND a.upgrade LIKE CONCAT('%', #{param.upgrade}, '%') + + + AND a.equity LIKE CONCAT('%', #{param.equity}, '%') + + + AND a.commission LIKE CONCAT('%', #{param.commission}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserGroupMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserGroupMapper.xml new file mode 100644 index 0000000..8a59e29 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserGroupMapper.xml @@ -0,0 +1,50 @@ + + + + + + + SELECT a.* + FROM sys_user_group a + + + AND a.group_id = #{param.groupId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml new file mode 100644 index 0000000..065f9f2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserMapper.xml @@ -0,0 +1,280 @@ + + + + + + + SELECT ta.* + FROM gxwebsoft_core.sys_dictionary_data ta + LEFT JOIN gxwebsoft_core.sys_dictionary tb + ON ta.dict_id = tb.dict_id + AND tb.deleted = 0 + WHERE ta.deleted = 0 + AND tb.dict_code = 'sex' + + + + + SELECT a.user_id, + GROUP_CONCAT(b.role_name) role_name + FROM gxwebsoft_core.sys_user_role a + LEFT JOIN gxwebsoft_core.sys_role b ON a.role_id = b.role_id + GROUP BY a.user_id + + + + + SELECT a.*, + c.dict_data_name sex_name, + e.tenant_name, + h.dealer_id + FROM gxwebsoft_core.sys_user a + LEFT JOIN ( + + ) c ON a.sex = c.dict_data_code + LEFT JOIN( + + ) d ON a.user_id = d.user_id + LEFT JOIN gxwebsoft_core.sys_tenant e ON a.tenant_id = e.tenant_id + LEFT JOIN gxwebsoft_core.sys_user_referee h ON a.user_id = h.user_id and h.deleted = 0 + + + AND a.user_id = #{param.userId} + + + AND a.username LIKE CONCAT('%', #{param.username}, '%') + + + AND a.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + AND a.type = #{param.type} + + + AND a.sex = #{param.sex} + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.email LIKE CONCAT('%', #{param.email}, '%') + + + AND a.email_verified = #{param.emailVerified} + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.company_name LIKE CONCAT('%', #{param.companyName}, '%') + + + AND a.id_card LIKE CONCAT('%', #{param.idCard}, '%') + + + AND a.birthday LIKE CONCAT('%', #{param.birthday}, '%') + + + AND a.organization_id = #{param.organizationId} + + + AND a.organization_id > 0 + + + AND a.platform = #{param.platform} + + + AND a.`status` = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.recommend = #{param.recommend} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.user_id IN (SELECT user_id FROM sys_user_role WHERE role_id=#{param.roleId}) + + + AND a.user_id IN + + #{item} + + + + AND a.phones IN + + #{item} + + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND i.city_mate LIKE CONCAT('%', #{param.cityMate}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND c.dict_data_name = #{param.sexName} + + + AND ( + a.username LIKE CONCAT('%', #{param.keywords}, '%') + OR a.user_id = #{param.keywords} + OR a.nickname LIKE CONCAT('%', #{param.keywords}, '%') + OR a.real_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.alias LIKE CONCAT('%', #{param.keywords}, '%') + OR a.phone LIKE CONCAT('%', #{param.keywords}, '%') + OR a.email LIKE CONCAT('%', #{param.keywords}, '%') + OR c.dict_data_name LIKE CONCAT('%', #{param.keywords}, '%') + OR d.role_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + AND a.organization_id IN (SELECT organization_id FROM sys_organization WHERE parent_id=#{param.parentId}) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE gxwebsoft_core.sys_user SET grade_id = #{param.gradeId} WHERE user_id = #{param.userId} + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserOauthMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserOauthMapper.xml new file mode 100644 index 0000000..049cde1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserOauthMapper.xml @@ -0,0 +1,59 @@ + + + + + + + SELECT a.* + FROM sys_user_oauth a + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.oauth_type LIKE CONCAT('%', #{param.oauthType}, '%') + + + AND a.oauth_id LIKE CONCAT('%', #{param.oauthId}, '%') + + + AND a.unionid LIKE CONCAT('%', #{param.unionid}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRefereeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRefereeMapper.xml new file mode 100644 index 0000000..67943f7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRefereeMapper.xml @@ -0,0 +1,50 @@ + + + + + + + SELECT a.* + FROM sys_user_referee a + + + AND a.id = #{param.id} + + + AND a.dealer_id = #{param.dealerId} + + + AND a.user_id = #{param.userId} + + + AND a.level = #{param.level} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRoleMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRoleMapper.xml new file mode 100644 index 0000000..78e3a87 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserRoleMapper.xml @@ -0,0 +1,35 @@ + + + + + + INSERT INTO sys_user_role(user_id, role_id) VALUES + + (#{userId}, #{roleId}) + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserVerifyMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserVerifyMapper.xml new file mode 100644 index 0000000..963bf69 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/UserVerifyMapper.xml @@ -0,0 +1,174 @@ + + + + + + + SELECT a.*, b.phone, c.organization_name, d.nickname as adminName + FROM sys_user_verify a + LEFT JOIN sys_user b ON a.user_id = b.user_id + LEFT JOIN sys_organization c ON a.organization_id = c.organization_id + LEFT JOIN sys_user d ON a.admin_id = d.user_id + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.type = #{param.type} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.id_card LIKE CONCAT('%', #{param.idCard}, '%') + + + AND a.birthday LIKE CONCAT('%', #{param.birthday}, '%') + + + AND a.sfz1 LIKE CONCAT('%', #{param.sfz1}, '%') + + + AND a.sfz2 LIKE CONCAT('%', #{param.sfz2}, '%') + + + AND a.zz_code = #{param.zzCode} + + + AND a.admin_id = #{param.adminId} + + + AND a.organization_id = #{param.organizationId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.organization_id IN + + #{item} + + + + AND (a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.real_name LIKE CONCAT('%', #{param.keywords}, '%') + OR b.phone = #{param.keywords} + OR a.id_card = #{param.keywords} + OR a.zz_code = #{param.keywords} + ) + + + + AND a.id IN ( + SELECT MAX(v.id) + FROM sys_user_verify v + LEFT JOIN sys_user u ON v.user_id = u.user_id + + + AND v.user_id = #{param.userId} + + + AND v.type = #{param.type} + + + AND v.name LIKE CONCAT('%', #{param.name}, '%') + + + AND v.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND v.id_card LIKE CONCAT('%', #{param.idCard}, '%') + + + AND v.birthday LIKE CONCAT('%', #{param.birthday}, '%') + + + AND v.sfz1 LIKE CONCAT('%', #{param.sfz1}, '%') + + + AND v.sfz2 LIKE CONCAT('%', #{param.sfz2}, '%') + + + AND v.zz_code = #{param.zzCode} + + + AND v.admin_id = #{param.adminId} + + + AND v.organization_id = #{param.organizationId} + + + AND v.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND v.status = #{param.status} + + + AND v.deleted = #{param.deleted} + + + AND v.deleted = 0 + + + AND v.create_time >= #{param.createTimeStart} + + + AND v.create_time <= #{param.createTimeEnd} + + + AND v.organization_id IN + + #{item} + + + + AND (v.name LIKE CONCAT('%', #{param.keywords}, '%') + OR v.real_name LIKE CONCAT('%', #{param.keywords}, '%') + OR u.phone = #{param.keywords} + OR v.id_card = #{param.keywords} + OR v.zz_code = #{param.keywords} + ) + + + GROUP BY v.user_id + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/VersionMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/VersionMapper.xml new file mode 100644 index 0000000..08a9d87 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/VersionMapper.xml @@ -0,0 +1,71 @@ + + + + + + + SELECT a.* + FROM sys_version a + + + AND a.id = #{param.id} + + + AND a.version_name LIKE CONCAT('%', #{param.versionName}, '%') + + + AND a.version_code = #{param.versionCode} + + + AND a.android_download_url LIKE CONCAT('%', #{param.androidDownloadUrl}, '%') + + + AND a.ios_download_url LIKE CONCAT('%', #{param.iosDownloadUrl}, '%') + + + AND a.update_info LIKE CONCAT('%', #{param.updateInfo}, '%') + + + AND a.is_hard = #{param.isHard} + + + AND a.is_hot = #{param.isHot} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/WebsiteFieldMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/WebsiteFieldMapper.xml new file mode 100644 index 0000000..b2117f9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/WebsiteFieldMapper.xml @@ -0,0 +1,68 @@ + + + + + + + SELECT a.* + FROM sys_website_field a + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.default_value LIKE CONCAT('%', #{param.defaultValue}, '%') + + + AND a.modify_range LIKE CONCAT('%', #{param.modifyRange}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.value LIKE CONCAT('%', #{param.value}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND ( + a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.value LIKE CONCAT('%', #{param.keywords}, '%') + OR a.default_value LIKE CONCAT('%', #{param.keywords}, '%') + OR a.comments = #{param.keywords} + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/WhiteDomainMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/WhiteDomainMapper.xml new file mode 100644 index 0000000..821d441 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/mapper/xml/WhiteDomainMapper.xml @@ -0,0 +1,50 @@ + + + + + + + SELECT a.* + FROM sys_white_domain a + + + AND a.id = #{param.id} + + + AND a.domain LIKE CONCAT('%', #{param.domain}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AccessKeyParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AccessKeyParam.java new file mode 100644 index 0000000..3587f7f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AccessKeyParam.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 查询参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "角色查询参数") +public class AccessKeyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "AccessKey") + private String accessKey; + + @Schema(description = "AccessSecret") + private String accessSecret; + + @Schema(description = "手机号码") + @TableField(exist = false) + private String phone; + + @Schema(description = "短信验证码") + @TableField(exist = false) + private String code; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户ID") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AlipayParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AlipayParam.java new file mode 100644 index 0000000..7eb3c53 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AlipayParam.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 登录参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "登录参数") +public class AlipayParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "支付宝授权码") + private String authCode; + + @Schema(description = "登录账号") + private String username; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AuthorizeCodeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AuthorizeCodeParam.java new file mode 100644 index 0000000..0df83bf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/AuthorizeCodeParam.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 授权码查询参数 + * + * @author 科技小王子 + * @since 2025-08-05 01:17:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "AuthorizeCodeParam对象", description = "授权码查询参数") +public class AuthorizeCodeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "授权码") + private String code; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CacheParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CacheParam.java new file mode 100644 index 0000000..74e8a33 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CacheParam.java @@ -0,0 +1,24 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 缓存管理 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "缓存管理") +public class CacheParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "key") + private String key; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CartParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CartParam.java new file mode 100644 index 0000000..35182b2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CartParam.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 购物车查询参数 + * + * @author 科技小王子 + * @since 2024-10-26 10:54:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CartParam对象", description = "购物车查询参数") +public class CartParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "购物车表ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "类型 0商城 1应用插件") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "唯一标识") + private String code; + + @Schema(description = "项目ID,0 goodId 1 companyId") + private Long itemId; + + @Schema(description = "商品规格") + private String spec; + + @Schema(description = "商品价格") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "商品数量") + @QueryField(type = QueryType.EQ) + private Integer cartNum; + + @Schema(description = "单商品合计") + @QueryField(type = QueryType.EQ) + private BigDecimal totalPrice; + + @Schema(description = "0 = 未购买 1 = 已购买") + @QueryField(type = QueryType.EQ) + private Boolean isPay; + + @Schema(description = "是否为立即购买") + @QueryField(type = QueryType.EQ) + private Boolean isNew; + + @Schema(description = "拼团id") + @QueryField(type = QueryType.EQ) + private Integer combinationId; + + @Schema(description = "秒杀产品ID") + @QueryField(type = QueryType.EQ) + private Integer seckillId; + + @Schema(description = "砍价id") + @QueryField(type = QueryType.EQ) + private Integer bargainId; + + @Schema(description = "是否选中") + @QueryField(type = QueryType.EQ) + private Boolean selected; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "用户ID") + private Long userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ChatConversationParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ChatConversationParam.java new file mode 100644 index 0000000..05ed983 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ChatConversationParam.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 聊天消息表查询参数 + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ChatConversationParam对象", description = "聊天消息表查询参数") +public class ChatConversationParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "好友ID") + @QueryField(type = QueryType.EQ) + private Integer friendId; + + @Schema(description = "消息类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "未读消息") + @QueryField(type = QueryType.EQ) + private Integer unRead; + + @Schema(description = "状态, 0未读, 1已读") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ChatMessageParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ChatMessageParam.java new file mode 100644 index 0000000..3beb2c6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ChatMessageParam.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Set; + +/** + * 聊天消息表查询参数 + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ChatMessageParam对象", description = "聊天消息表查询参数") +public class ChatMessageParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "发送人ID") + @QueryField(type = QueryType.EQ) + private Integer formUserId; + + @Schema(description = "接收人ID") + @QueryField(type = QueryType.EQ) + private Integer toUserId; + + @Schema(description = "消息类型") + private String type; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "屏蔽接收方") + @QueryField(type = QueryType.EQ) + private Integer sideTo; + + @Schema(description = "屏蔽发送方") + @QueryField(type = QueryType.EQ) + private Integer sideFrom; + + @Schema(description = "是否撤回") + @QueryField(type = QueryType.EQ) + private Integer withdraw; + + @Schema(description = "文件信息") + private String fileInfo; + + @Schema(description = "存在联系方式") + @QueryField(type = QueryType.EQ) + private Integer hasContact; + + @Schema(description = "状态, 0未读, 1已读") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "接收人ID集合") + private Set toUserIds; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyCommentParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyCommentParam.java new file mode 100644 index 0000000..2123f5b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyCommentParam.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 应用评论查询参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyCommentParam对象", description = "应用评论查询参数") +public class CompanyCommentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "父级ID") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "评分") + @QueryField(type = QueryType.EQ) + private BigDecimal rate; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "评论内容") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyContentParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyContentParam.java new file mode 100644 index 0000000..bf5738c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyContentParam.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用详情查询参数 + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyContentParam对象", description = "应用详情查询参数") +public class CompanyContentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "详细内容") + private String content; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyGitParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyGitParam.java new file mode 100644 index 0000000..368d324 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyGitParam.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 代码仓库查询参数 + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyGitParam对象", description = "代码仓库查询参数") +public class CompanyGitParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "仓库名称") + private String title; + + @Schema(description = "厂商") + @QueryField(type = QueryType.EQ) + private String brand; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "仓库地址") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "仓库描述") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyParam.java new file mode 100644 index 0000000..7696b7e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyParam.java @@ -0,0 +1,166 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Set; + +/** + * 企业信息查询参数 + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyParam对象", description = "企业信息查询参数") +public class CompanyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "企业id") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "应用类型") + private Integer type; + + @Schema(description = "是否官方") + private Boolean official; + + @Schema(description = "企业简称") + private String shortName; + + @Schema(description = "企业全称") + private String companyName; + + @Schema(description = "企业标识") + private String companyCode; + + @Schema(description = "类型 10企业 20政府单位") + @QueryField(type = QueryType.EQ) + private String companyType; + + @Schema(description = "企业类型 多选") + private String companyTypeMultiple; + + @Schema(description = "应用标识") + private String companyLogo; + + @Schema(description = "栏目分类") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "企业域名") + private String domain; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "电子邮箱") + @QueryField(type = QueryType.EQ) + private String email; + + @Schema(description = "企业法人") + private String businessEntity; + + @Schema(description = "发票抬头") + private String invoiceHeader; + + @Schema(description = "服务开始时间") + private String startTime; + + @Schema(description = "服务到期时间") + private String expirationTime; + + @Schema(description = "应用版本 10体验版 20授权版 30旗舰版") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "成员数量") + @QueryField(type = QueryType.EQ) + private Integer members; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "部门数量") + @QueryField(type = QueryType.EQ) + private Integer departments; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否实名认证") + @QueryField(type = QueryType.EQ) + private Integer authentication; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Boolean recommend; + + @Schema(description = "应用类型 app应用 plug插件") + private String appType; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "是否默认企业主体") + @QueryField(type = QueryType.EQ) + private Boolean authoritative; + + @Schema(description = "租户号") + private Integer tenantId; + + @Schema(description = "应用名称") + @QueryField(type = QueryType.EQ) + private String appName; + + @Schema(description = "企业id集合") + @TableField(exist = false) + private Set companyIds; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyParameterParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyParameterParam.java new file mode 100644 index 0000000..37b317b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyParameterParam.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用参数查询参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyParameterParam对象", description = "应用参数查询参数") +public class CompanyParameterParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "参数名称") + private String name; + + @Schema(description = "参数内容") + private String value; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyUrlParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyUrlParam.java new file mode 100644 index 0000000..8a90ee9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/CompanyUrlParam.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用域名查询参数 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CompanyUrlParam对象", description = "应用域名查询参数") +public class CompanyUrlParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "域名类型") + private String type; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "二维码") + private String qrcode; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1待确认") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ComponentsParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ComponentsParam.java new file mode 100644 index 0000000..7e2feb1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ComponentsParam.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 组件查询参数 + * + * @author 科技小王子 + * @since 2024-08-25 19:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ComponentsParam对象", description = "组件查询参数") +public class ComponentsParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "组件标题") + private String title; + + @Schema(description = "关联导航ID") + @QueryField(type = QueryType.EQ) + private Integer navigationId; + + @Schema(description = "组件类型") + private String type; + + @Schema(description = "页面关键词") + private String keywords; + + @Schema(description = "页面描述") + private String description; + + @Schema(description = "组件路径") + private String path; + + @Schema(description = "组件图标") + private String icon; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictDataParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictDataParam.java new file mode 100644 index 0000000..6d4f0fc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictDataParam.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典数据查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典数据查询参数") +public class DictDataParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @QueryField(type = QueryType.EQ) + private Integer dictDataId; + + @Schema(description = "字典id") + @QueryField(type = QueryType.EQ) + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "字典数据代码或字典数据名称") + @TableField(exist = false) + private String keywords; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictParam.java new file mode 100644 index 0000000..bd96abf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictParam.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典查询参数") +public class DictParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "备注") + private String comments; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictionaryDataParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictionaryDataParam.java new file mode 100644 index 0000000..cbee89f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictionaryDataParam.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典数据查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典数据查询参数") +public class DictionaryDataParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "字典数据id") + @QueryField(type = QueryType.EQ) + private Integer dictDataId; + + @Schema(description = "字典id") + @QueryField(type = QueryType.EQ) + private Integer dictId; + + @Schema(description = "字典数据标识") + private String dictDataCode; + + @Schema(description = "字典数据名称") + private String dictDataName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "字典代码") + @TableField(exist = false) + private String dictCode; + + @Schema(description = "字典名称") + @TableField(exist = false) + private String dictName; + + @Schema(description = "字典数据代码或字典数据名称") + @TableField(exist = false) + private String keywords; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictionaryParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictionaryParam.java new file mode 100644 index 0000000..6c2c65b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DictionaryParam.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.common.system.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典查询参数 + * + * @author WebSoft + * @since 2021-08-28 22:12:01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "字典查询参数") +public class DictionaryParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + @Schema(description = "字典id") + private Integer dictId; + + @Schema(description = "字典标识") + private String dictCode; + + @Schema(description = "字典名称") + private String dictName; + + @Schema(description = "备注") + private String comments; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DomainParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DomainParam.java new file mode 100644 index 0000000..1ffc3f2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/DomainParam.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 授权域名查询参数 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "DomainParam对象", description = "授权域名查询参数") +public class DomainParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "主机记录") + private String hostName; + + @Schema(description = "记录值") + private String hostValue; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "类型 0常规 1后台 2商家端") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/EnvironmentParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/EnvironmentParam.java new file mode 100644 index 0000000..3ac1dd1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/EnvironmentParam.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 环境管理查询参数 + * + * @author 科技小王子 + * @since 2023-10-18 08:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "EnvironmentParam对象", description = "环境管理查询参数") +public class EnvironmentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "插件id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "环境名称") + private String environmentName; + + @Schema(description = "环境编号") + private String environmentCode; + + @Schema(description = "服务器厂商") + private String brand; + + @Schema(description = "服务器IP") + private String serverIp; + + @Schema(description = "模块访问地址") + private String modulesUrl; + + @Schema(description = "模块API") + private String modulesApi; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 10待审核 20已通过 30已驳回") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/FileRecordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/FileRecordParam.java new file mode 100644 index 0000000..53aab3b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/FileRecordParam.java @@ -0,0 +1,69 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 文件上传记录查询参数 + * + * @author WebSoft + * @since 2021-08-30 11:29:31 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "文件上传记录查询参数") +public class FileRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + @Schema(description = "主键id") + private Integer id; + + @QueryField(type = QueryType.EQ) + @Schema(description = "分组ID") + private String groupId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "文件存储路径") + private String path; + + @QueryField(type = QueryType.EQ) + @Schema(description = "创建人") + private Integer createUserId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文件类型") + private String contentType; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建人账号") + @TableField(exist = false) + private String createUsername; + + @Schema(description = "创建人名称") + @TableField(exist = false) + private String createNickname; + + @Schema(description = "用户头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "商户编号") + private String merchantCode; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/FindAccountByPhoneParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/FindAccountByPhoneParam.java new file mode 100644 index 0000000..b5d6248 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/FindAccountByPhoneParam.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 通过手机号查找账号参数 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "通过手机号查找账号参数") +public class FindAccountByPhoneParam implements Serializable { + private static final long serialVersionUID = 1L; + + @NotBlank(message = "手机号不能为空") + @Schema(description = "手机号码", required = true) + private String phone; + + @NotBlank(message = "短信验证码不能为空") + @Schema(description = "短信验证码", required = true) + private String smsCode; + + @NotNull(message = "模板ID不能为空") + @Schema(description = "短信模板ID", required = true) + private Integer templateId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/LoginParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/LoginParam.java new file mode 100644 index 0000000..37d4036 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/LoginParam.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 登录参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "登录参数") +public class LoginParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "账号") + private String username; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "短信验证码") + private String code; + + @Schema(description = "密码") + private String password; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/LoginRecordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/LoginRecordParam.java new file mode 100644 index 0000000..00e00dc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/LoginRecordParam.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 登录日志查询参数 + * + * @author WebSoft + * @since 2021-08-29 19:09:23 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "登录日志查询参数") +public class LoginRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + @Schema(description = "主键id") + private Integer id; + + @Schema(description = "用户账号") + private String username; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "设备名") + private String device; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "ip地址") + private String ip; + + @QueryField(type = QueryType.EQ) + @Schema(description = "操作类型, 0登录成功, 1登录失败, 2退出登录, 3续签token") + private Integer loginType; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "用户id") + @TableField(exist = false) + private Integer userId; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MenuImportParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MenuImportParam.java new file mode 100644 index 0000000..7245b24 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MenuImportParam.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.common.system.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; + +/** + * 菜单导入参数 + * + * @author WebSoft + * @since 2025-09-30 + */ +@Data +public class MenuImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "菜单ID") + private Integer menuId; + + @Excel(name = "父级ID") + private Integer parentId; + + @Excel(name = "菜单名称") + private String title; + + @Excel(name = "路由地址") + private String path; + + @Excel(name = "组件路径") + private String component; + + @Excel(name = "模块ID") + private String modules; + + @Excel(name = "模块API") + private String modulesUrl; + + @Excel(name = "菜单类型") + private Integer menuType; + + @Excel(name = "排序号") + private Integer sortNumber; + + @Excel(name = "权限标识") + private String authority; + + @Excel(name = "图标") + private String icon; + + @Excel(name = "是否隐藏") + private Integer hide; + + @Excel(name = "关联应用") + private Integer appId; + + @Excel(name = "租户id") + private Integer tenantId; + +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MenuParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MenuParam.java new file mode 100644 index 0000000..102d6f7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MenuParam.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 菜单查询参数 + * + * @author WebSoft + * @since 2021-08-29 19:36:10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "菜单查询参数") +public class MenuParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "菜单id") + @QueryField(type = QueryType.EQ) + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由关键字") + private String path; + + @Schema(description = "菜单组件地址") + private String component; + + @Schema(description = "菜单类型, 0菜单, 1按钮") + @QueryField(type = QueryType.EQ) + private Integer menuType; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "关联应用") + private Integer appId; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantAccountParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantAccountParam.java new file mode 100644 index 0000000..b6394d0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantAccountParam.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户账号查询参数 + * + * @author 科技小王子 + * @since 2024-04-19 12:02:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "MerchantAccountParam对象", description = "商户账号查询参数") +public class MerchantAccountParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "商户手机号") + @QueryField(type = QueryType.EQ) + private String phone; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantApplyParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantApplyParam.java new file mode 100644 index 0000000..0132a5b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantApplyParam.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 商户入驻申请查询参数 + * + * @author 科技小王子 + * @since 2024-04-05 01:24:36 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "MerchantApplyParam对象", description = "商户入驻申请查询参数") +public class MerchantApplyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer applyId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户图标") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "商户分类") + private String category; + + @Schema(description = "手续费") + @QueryField(type = QueryType.EQ) + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "是否自营") + @QueryField(type = QueryType.EQ) + private Integer ownStore; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否需要审核") + @QueryField(type = QueryType.EQ) + private Integer goodsReview; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantParam.java new file mode 100644 index 0000000..b3ae3f6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantParam.java @@ -0,0 +1,98 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 商户查询参数 + * + * @author 科技小王子 + * @since 2024-04-05 00:03:54 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "MerchantParam对象", description = "商户查询参数") +public class MerchantParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户标识") + private String merchantCode; + + @Schema(description = "商户图标") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "商户分类") + private String category; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "手续费") + @QueryField(type = QueryType.EQ) + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "是否自营") + @QueryField(type = QueryType.EQ) + private Integer ownStore; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否需要审核") + @QueryField(type = QueryType.EQ) + private Integer goodsReview; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantTypeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantTypeParam.java new file mode 100644 index 0000000..49bef42 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/MerchantTypeParam.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户类型查询参数 + * + * @author 科技小王子 + * @since 2024-04-05 00:08:51 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "MerchantTypeParam对象", description = "商户类型查询参数") +public class MerchantTypeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "店铺类型") + private String name; + + @Schema(description = "店铺入驻条件") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ModulesParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ModulesParam.java new file mode 100644 index 0000000..888ad18 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ModulesParam.java @@ -0,0 +1,53 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 模块管理查询参数 + * + * @author 科技小王子 + * @since 2023-10-18 15:53:43 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ModulesParam对象", description = "模块管理查询参数") +public class ModulesParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "插件id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "环境编号") + private String modules; + + @Schema(description = "模块访问地址") + private String modulesUrl; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 10待审核 20已通过 30已驳回") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/NoticeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/NoticeParam.java new file mode 100644 index 0000000..ef08c37 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/NoticeParam.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 消息记录表查询参数 + * + * @author 科技小王子 + * @since 2023-03-22 14:07:26 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "NoticeParam对象", description = "消息记录表查询参数") +public class NoticeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer noticeId; + + @Schema(description = "消息类型") + private String type; + + @Schema(description = "标题") + private String title; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "颜色") + private String color; + + @Schema(description = "内容") + private String content; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "消息来源") + private String source; + + @Schema(description = "来源记录ID") + private Integer sourceId; + + @Schema(description = "路由地址") + private String path; + + @Schema(description = "渠道, 0发送 1回复") + private Integer channel; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "租户id") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + + @Schema(description = "状态, 0待处理, 1已完成") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "是否已查阅") + private Integer isRead; + + @Schema(description = "任务状态") + private Integer progress; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OperationRecordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OperationRecordParam.java new file mode 100644 index 0000000..8b40b49 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OperationRecordParam.java @@ -0,0 +1,66 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 操作日志参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "操作日志参数") +public class OperationRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "操作模块") + private String module; + + @Schema(description = "操作功能") + private String description; + + @Schema(description = "请求地址") + private String url; + + @Schema(description = "请求方式") + private String requestMethod; + + @Schema(description = "调用方法") + private String method; + + @Schema(description = "ip地址") + private String ip; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0成功, 1异常") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户账号") + @TableField(exist = false) + private String username; + + @Schema(description = "用户昵称") + @TableField(exist = false) + private String nickname; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderGoodsParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderGoodsParam.java new file mode 100644 index 0000000..af96eed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderGoodsParam.java @@ -0,0 +1,89 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 订单商品查询参数 + * + * @author 科技小王子 + * @since 2024-10-26 12:18:05 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "OrderGoodsParam对象", description = "订单商品查询参数") +public class OrderGoodsParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单号") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "订单类型,0商城 1应用插件") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "订单号") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "项目ID") + @QueryField(type = QueryType.EQ) + private Integer itemId; + + @Schema(description = "实际付款") + @QueryField(type = QueryType.EQ) + private BigDecimal payPrice; + + @Schema(description = "购买数量") + @QueryField(type = QueryType.EQ) + private Integer totalNum; + + @Schema(description = "0未付款,1已付款") + @QueryField(type = QueryType.EQ) + private Boolean payStatus; + + @Schema(description = "0未完成,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + @QueryField(type = QueryType.EQ) + private Integer orderStatus; + + @Schema(description = "预约详情开始时间数组") + private String startTime; + + @Schema(description = "是否已开具发票:0未开发票,1已开发票,2不能开具发票") + @QueryField(type = QueryType.EQ) + private Boolean isInvoice; + + @Schema(description = "发票流水号") + private String invoiceNo; + + @Schema(description = "支付时间") + private String payTime; + + @Schema(description = "过期时间") + private String expirationTime; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderInfoParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderInfoParam.java new file mode 100644 index 0000000..41c5fd0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderInfoParam.java @@ -0,0 +1,100 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 查询参数 + * + * @author 科技小王子 + * @since 2024-05-10 18:02:54 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "OrderInfoParam对象", description = "查询参数") +public class OrderInfoParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "关联订单表id") + @QueryField(type = QueryType.EQ) + private Integer oid; + + @Schema(description = "关联场馆id") + @QueryField(type = QueryType.EQ) + private Integer sid; + + @Schema(description = "关联场地id") + @QueryField(type = QueryType.EQ) + private Integer fid; + + @Schema(description = "场馆") + private String siteName; + + @Schema(description = "场地") + private String fieldName; + + @Schema(description = "预约时间段") + private String dateTime; + + @Schema(description = "单价") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "儿童价") + @QueryField(type = QueryType.EQ) + private BigDecimal childrenPrice; + + @Schema(description = "成人人数") + @QueryField(type = QueryType.EQ) + private Boolean adultNum; + + @Schema(description = "儿童人数") + @QueryField(type = QueryType.EQ) + private Boolean childrenNum; + + @Schema(description = "1已付款,2未付款,3无需付款或占用状态") + @QueryField(type = QueryType.EQ) + private Boolean payStatus; + + @Schema(description = "是否免费:1免费、2收费") + @QueryField(type = QueryType.EQ) + private Boolean isFree; + + @Schema(description = "是否支持儿童票:1支持,2不支持") + @QueryField(type = QueryType.EQ) + private Boolean isChildren; + + @Schema(description = "预订类型:1全场,2半场") + @QueryField(type = QueryType.EQ) + private Boolean type; + + @Schema(description = "组合数据:日期+时间段+场馆id+场地id") + private String mergeData; + + @Schema(description = "开场时间") + @QueryField(type = QueryType.EQ) + private Integer startTime; + + @Schema(description = "下单时间") + @QueryField(type = QueryType.EQ) + private Integer orderTime; + + @Schema(description = "毫秒时间戳") + private Long timeFlag; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderParam.java new file mode 100644 index 0000000..7600759 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrderParam.java @@ -0,0 +1,156 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 订单查询参数 + * + * @author 科技小王子 + * @since 2024-10-16 12:32:52 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "OrderParam对象", description = "订单查询参数") +public class OrderParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单号") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "订单类型,0产品 1插件") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "下单渠道,0网站 1小程序 2其他") + @QueryField(type = QueryType.EQ) + private Integer channel; + + @Schema(description = "微信支付订单号") + private String transactionId; + + @Schema(description = "微信退款订单号") + private String refundOrder; + + @Schema(description = "使用的优惠券id") + @QueryField(type = QueryType.EQ) + private Integer couponId; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "订单总额") + @QueryField(type = QueryType.EQ) + private BigDecimal totalPrice; + + @Schema(description = "减少的金额,使用VIP会员折扣、优惠券抵扣、优惠券折扣后减去的价格") + @QueryField(type = QueryType.EQ) + private BigDecimal reducePrice; + + @Schema(description = "实际付款") + @QueryField(type = QueryType.EQ) + private BigDecimal payPrice; + + @Schema(description = "用于统计") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "价钱,用于积分赠送") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "退款金额") + @QueryField(type = QueryType.EQ) + private BigDecimal refundMoney; + + @Schema(description = "购买数量") + @QueryField(type = QueryType.EQ) + private Integer totalNum; + + @Schema(description = "0余额支付, 1微信支付,102微信Native,2会员卡支付,3支付宝,4现金,5POS机") + @QueryField(type = QueryType.EQ) + private Integer payType; + + @Schema(description = "0未付款,1已付款") + @QueryField(type = QueryType.EQ) + private Boolean payStatus; + + @Schema(description = "0未完成,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + @QueryField(type = QueryType.EQ) + private Integer orderStatus; + + @Schema(description = "优惠类型:0无、1抵扣优惠券、2折扣优惠券、3、VIP月卡、4VIP年卡,5VIP次卡、6VIP会员卡、7IC月卡、8IC年卡、9IC次卡、10IC会员卡、11免费订单、12VIP充值卡、13IC充值卡、14VIP季卡、15IC季卡") + @QueryField(type = QueryType.EQ) + private Integer couponType; + + @Schema(description = "优惠说明") + private String couponDesc; + + @Schema(description = "二维码地址,保存订单号,支付成功后才生成") + private String qrcode; + + @Schema(description = "预约详情开始时间数组") + private String startTime; + + @Schema(description = "是否已开具发票:0未开发票,1已开发票,2不能开具发票") + @QueryField(type = QueryType.EQ) + private Boolean isInvoice; + + @Schema(description = "发票流水号") + private String invoiceNo; + + @Schema(description = "支付时间") + private String payTime; + + @Schema(description = "退款时间") + private String refundTime; + + @Schema(description = "申请退款时间") + private String refundApplyTime; + + @Schema(description = "过期时间") + private String expirationTime; + + @Schema(description = "对账情况:0=未对账;1=已对账;3=已对账,金额对不上;4=未查询到该订单") + @QueryField(type = QueryType.EQ) + private Integer checkBill; + + @Schema(description = "订单是否已结算(0未结算 1已结算)") + @QueryField(type = QueryType.EQ) + private Integer isSettled; + + @Schema(description = "系统版本号 0当前版本 value=其他版本") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrganizationParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrganizationParam.java new file mode 100644 index 0000000..e7b2849 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/OrganizationParam.java @@ -0,0 +1,80 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 组织机构查询参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "组织机构查询参数") +public class OrganizationParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "机构id") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "机构名称") + private String organizationName; + + @Schema(description = "机构全称") + private String organizationFullName; + + @Schema(description = "机构代码") + private String organizationCode; + + @Schema(description = "机构类型(字典代码)") + private String organizationType; + + @Schema(description = "所在省份") + @QueryField(type = QueryType.EQ) + private String province; + + @Schema(description = "所在城市") + @QueryField(type = QueryType.EQ) + private String city; + + @Schema(description = "所在辖区") + @QueryField(type = QueryType.EQ) + private String region; + + @Schema(description = "邮政编码") + @QueryField(type = QueryType.EQ) + private String zipCode; + + @Schema(description = "负责人id") + @QueryField(type = QueryType.EQ) + private Integer leaderId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "机构类型名称") + @TableField(exist = false) + private String organizationTypeName; + + @Schema(description = "负责人姓名") + @TableField(exist = false) + private String leaderNickname; + + @Schema(description = "负责人账号") + @TableField(exist = false) + private String leaderUsername; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java new file mode 100644 index 0000000..1acc67a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/PaymentParam.java @@ -0,0 +1,80 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 支付方式查询参数 + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "PaymentParam对象", description = "支付方式查询参数") +public class PaymentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "支付方式") + private String name; + + @Schema(description = "类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "标识") + @QueryField(type = QueryType.EQ) + private String code; + + @Schema(description = "微信商户号类型 1普通商户2子商户") + @QueryField(type = QueryType.EQ) + private Integer wechatType; + + @Schema(description = "应用ID") + private String appId; + + @Schema(description = "商户号") + private String mchId; + + @Schema(description = "设置APIv3密钥") + private String apiKey; + + @Schema(description = "证书文件 (CERT)") + private String apiclientCert; + + @Schema(description = "证书文件 (KEY)") + private String apiclientKey; + + @Schema(description = "商户证书序列号") + private String merchantSerialNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文章排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0启用, 1禁用") + @QueryField(type = QueryType.EQ) + private Boolean status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/PlugParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/PlugParam.java new file mode 100644 index 0000000..b56abc4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/PlugParam.java @@ -0,0 +1,94 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 插件扩展查询参数 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "PlugParam对象", description = "插件扩展查询参数") +public class PlugParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "插件id") + @QueryField(type = QueryType.EQ) + private Integer plugId; + + @Schema(description = "菜单id") + @QueryField(type = QueryType.EQ) + private Integer menuId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "菜单路由地址") + private String path; + + @Schema(description = "菜单组件地址, 目录可为空") + private String component; + + @Schema(description = "类型, 0菜单, 1按钮") + @QueryField(type = QueryType.EQ) + private Integer menuType; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "权限标识") + private String authority; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "菜单侧栏选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "关联应用ID") + @QueryField(type = QueryType.EQ) + private Integer appId; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/RechargeOrderParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/RechargeOrderParam.java new file mode 100644 index 0000000..4e0504f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/RechargeOrderParam.java @@ -0,0 +1,105 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 会员充值订单表查询参数 + * + * @author 科技小王子 + * @since 2024-07-26 23:18:48 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "RechargeOrderParam对象", description = "会员充值订单表查询参数") +public class RechargeOrderParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单ID") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "充值方式(10自定义金额 20套餐充值)") + @QueryField(type = QueryType.EQ) + private Integer rechargeType; + + @Schema(description = "机构id") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "充值套餐ID") + @QueryField(type = QueryType.EQ) + private Integer planId; + + @Schema(description = "用户支付金额") + @QueryField(type = QueryType.EQ) + private BigDecimal payPrice; + + @Schema(description = "赠送金额") + @QueryField(type = QueryType.EQ) + private BigDecimal giftMoney; + + @Schema(description = "实际到账金额") + @QueryField(type = QueryType.EQ) + private BigDecimal actualMoney; + + @Schema(description = "用户可用余额") + @QueryField(type = QueryType.EQ) + private BigDecimal balance; + + @Schema(description = "支付方式(微信/支付宝)") + private String payMethod; + + @Schema(description = "支付状态(10待支付 20已支付)") + @QueryField(type = QueryType.EQ) + private Integer payStatus; + + @Schema(description = "付款时间") + @QueryField(type = QueryType.EQ) + private Integer payTime; + + @Schema(description = "第三方交易记录ID") + @QueryField(type = QueryType.EQ) + private Integer tradeId; + + @Schema(description = "来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "所属门店ID") + @QueryField(type = QueryType.EQ) + private Integer shopId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ResetPasswordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ResetPasswordParam.java new file mode 100644 index 0000000..0555a6d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/ResetPasswordParam.java @@ -0,0 +1,53 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import java.io.Serializable; + +/** + * 重置密码参数 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "重置密码参数") +public class ResetPasswordParam implements Serializable { + private static final long serialVersionUID = 1L; + + @NotBlank(message = "手机号不能为空") + @Schema(description = "手机号码", required = true) + private String phone; + + @NotBlank(message = "短信验证码不能为空") + @Schema(description = "短信验证码", required = true) + private String smsCode; + + @NotBlank(message = "用户ID不能为空") + @Schema(description = "用户ID", required = true) + private String userId; + + @NotNull(message = "租户ID不能为空") + @Schema(description = "租户ID", required = true) + private Integer tenantId; + + @NotBlank(message = "新密码不能为空") + @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d@$!%*#?&]{8,}$", + message = "密码必须至少8位,且包含字母和数字") + @Schema(description = "新密码(至少8位,包含字母和数字)", required = true) + private String newPassword; + + @NotBlank(message = "确认密码不能为空") + @Schema(description = "确认密码", required = true) + private String confirmPassword; + + @NotNull(message = "模板ID不能为空") + @Schema(description = "短信模板ID", required = true) + private Integer templateId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/RoleParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/RoleParam.java new file mode 100644 index 0000000..fcbcd35 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/RoleParam.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.common.system.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 角色查询参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "角色查询参数") +public class RoleParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "角色id") + @QueryField(type = QueryType.EQ) + private Integer roleId; + + @Schema(description = "角色标识") + private String roleCode; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户ID") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SettingParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SettingParam.java new file mode 100644 index 0000000..2645d08 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SettingParam.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 系统设置查询参数 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "SettingParam对象", description = "系统设置查询参数") +public class SettingParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer settingId; + + @Schema(description = "设置项标示") + @QueryField(type = QueryType.EQ) + private String settingKey; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "同步更新租户名称") + private String tenantName; + + @Schema(description = "租户名称") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SettingUpdateParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SettingUpdateParam.java new file mode 100644 index 0000000..1207737 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SettingUpdateParam.java @@ -0,0 +1,123 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Map; + +/** + * 系统设置更新参数 + * 用于处理包含配置字段的更新请求 + * + * @author WebSoft + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +@Schema(description = "系统设置更新参数") +public class SettingUpdateParam { + + @Schema(description = "设置项标示") + private String settingKey; + + @Schema(description = "设置内容(json格式)") + private String content; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + // 微信小程序配置字段 + @Schema(description = "微信小程序AppId") + private String appId; + + @Schema(description = "微信小程序AppSecret") + private String appSecret; + + // 支付配置字段 + @Schema(description = "商户号") + private String mchId; + + @Schema(description = "API密钥") + private String apiKey; + + @Schema(description = "微信支付API密钥") + private String wechatApiKey; + + @Schema(description = "商户序列号") + private String merchantSerialNumber; + + @Schema(description = "API客户端证书") + private String apiclientCert; + + @Schema(description = "API客户端密钥") + private String apiclientKey; + + // 短信配置字段 + @Schema(description = "短信AccessKey") + private String accessKeyId; + + @Schema(description = "短信AccessSecret") + private String accessKeySecret; + + @Schema(description = "短信签名") + private String signName; + + @Schema(description = "短信模板") + private String templateCode; + + // 企业微信配置字段 + @Schema(description = "企业ID") + private String corpId; + + @Schema(description = "应用Secret") + private String secret; + + // 微信公众号配置字段 + @Schema(description = "公众号Token") + private String token; + + @Schema(description = "公众号EncodingAESKey") + private String encodingAESKey; + + // 基本设置字段 + @Schema(description = "网站名称") + private String siteName; + + @Schema(description = "网站Logo") + private String logo; + + @Schema(description = "网站描述") + private String description; + + @Schema(description = "网站关键词") + private String keywords; + + // 上传配置字段 + @Schema(description = "存储桶名称") + private String bucketName; + + @Schema(description = "存储桶域名") + private String bucketDomain; + + @Schema(description = "存储桶端点") + private String bucketEndpoint; + + // 打印机配置字段 + @Schema(description = "打印机设备号") + private String deviceNo; + + @Schema(description = "打印机密钥") + private String printerKey; + + /** + * 获取其他未定义的字段 + * 用于处理动态配置字段 + */ + private Map additionalProperties; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SmsCaptchaParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SmsCaptchaParam.java new file mode 100644 index 0000000..ae29567 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SmsCaptchaParam.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 发送短信验证码参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "发送短信验证码参数") +public class SmsCaptchaParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "短信签名") + private String signName; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "短信模板") + private String TemplateParam; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SubscriptionOrderParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SubscriptionOrderParam.java new file mode 100644 index 0000000..9aec2ca --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SubscriptionOrderParam.java @@ -0,0 +1,24 @@ +package com.gxwebsoft.common.system.param; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 订阅订单价格试算入参 + */ +@Data +@Schema(description = "订阅订单价格试算参数") +public class SubscriptionOrderParam { + + @Schema(description = "是否续费,1=续费 0=新购") + private Integer isRenewal; + + @Schema(description = "是否升级,1=升级 0=非升级") + private Integer isUpgrade; + + @Schema(description = "套餐ID") + private Integer packageId; + + @Schema(description = "支付方式") + private Integer payType; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SysFileTypeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SysFileTypeParam.java new file mode 100644 index 0000000..b09306d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/SysFileTypeParam.java @@ -0,0 +1,38 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 存储类型查询参数 + * + * @author 科技小王子 + * @since 2025-05-16 14:24:28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "SysFileTypeParam对象", description = "存储类型查询参数") +public class SysFileTypeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "0本地存储,1阿里云oss,2腾讯云cos,3七牛云,4其他") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "名称") + private String name; + + @Schema(description = "访问域名") + private String path; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/TenantParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/TenantParam.java new file mode 100644 index 0000000..8690ec7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/TenantParam.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 租户查询参数 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "TenantParam对象", description = "租户查询参数") +public class TenantParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "租户名称") + private String tenantName; + + @Schema(description = "租户编号") + private String tenantCode; + + @Schema(description = "logo") + private String logo; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "租户id") + @QueryField(type = QueryType.EQ) + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UpdatePasswordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UpdatePasswordParam.java new file mode 100644 index 0000000..17b8393 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UpdatePasswordParam.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 修改密码参数 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "修改密码参数") +public class UpdatePasswordParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "原始密码") + private String oldPassword; + + @Schema(description = "新密码") + private String password; + + @Schema(description = "手机号码") + private String phone; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserBalanceLogParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserBalanceLogParam.java new file mode 100644 index 0000000..760796d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserBalanceLogParam.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 用户余额变动明细表查询参数 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserBalanceLogParam对象", description = "用户余额变动明细表查询参数") +public class UserBalanceLogParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer logId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "余额变动场景(10用户充值 20用户消费 30管理员操作 40订单退款)") + @QueryField(type = QueryType.EQ) + private Integer scene; + + @Schema(description = "变动金额") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "变动后余额") + @QueryField(type = QueryType.EQ) + private BigDecimal balance; + + @Schema(description = "描述/说明") + private String describe; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "余额变动场景筛选") + private String sceneMultiple; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserCollectionParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserCollectionParam.java new file mode 100644 index 0000000..1e9275c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserCollectionParam.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 我的收藏查询参数 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserCollectionParam对象", description = "我的收藏查询参数") +public class UserCollectionParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tid; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserFileParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserFileParam.java new file mode 100644 index 0000000..8d0a28b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserFileParam.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.common.system.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户文件查询参数 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserFileParam对象", description = "用户文件查询参数") +public class UserFileParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "上级id") + @QueryField(type = QueryType.EQ) + private Integer parentId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserGradeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserGradeParam.java new file mode 100644 index 0000000..455c8ca --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserGradeParam.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户会员等级表查询参数 + * + * @author 科技小王子 + * @since 2023-10-07 22:51:17 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserGradeParam对象", description = "用户会员等级表查询参数") +public class UserGradeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "等级ID") + @QueryField(type = QueryType.EQ) + private Integer gradeId; + + @Schema(description = "等级名称") + private String name; + + @Schema(description = "等级权重(1-9999)") + @QueryField(type = QueryType.EQ) + private Integer weight; + + @Schema(description = "升级条件") + private String upgrade; + + @Schema(description = "等级权益(折扣率0-100)") + private String equity; + + @Schema(description = "佣金比率") + private String commission; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserGroupParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserGroupParam.java new file mode 100644 index 0000000..28ff0cf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserGroupParam.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户分组管理表查询参数 + * + * @author 科技小王子 + * @since 2023-10-28 15:16:39 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserGroupParam对象", description = "用户分组管理表查询参数") +public class UserGroupParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "分组ID") + @QueryField(type = QueryType.EQ) + private Integer groupId; + + @Schema(description = "分组名称") + private String name; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserImportParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserImportParam.java new file mode 100644 index 0000000..153a783 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserImportParam.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户导入参数 + * + * @author WebSoft + * @since 2011-10-15 17:33:34 + */ +@Data +public class UserImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "账号") + private String username; + + @Excel(name = "密码") + private String password; + + @Excel(name = "昵称") + private String nickname; + + @Excel(name = "手机号") + private String phone; + + @Excel(name = "邮箱") + private String email; + + @Excel(name = "组织机构") + private String organizationName; + + @Excel(name = "性别") + private String sexName; + + @Excel(name = "角色") + private String roleName; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserOauthParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserOauthParam.java new file mode 100644 index 0000000..b048764 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserOauthParam.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 第三方用户信息表查询参数 + * + * @author 科技小王子 + * @since 2023-10-07 22:39:46 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserOauthParam对象", description = "第三方用户信息表查询参数") +public class UserOauthParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "第三方登陆类型(MP-WEIXIN)") + private String oauthType; + + @Schema(description = "第三方用户唯一标识 (uid openid)") + private String oauthId; + + @Schema(description = "微信unionID") + private String unionid; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserParam.java new file mode 100644 index 0000000..0ef904b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserParam.java @@ -0,0 +1,248 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Set; + +/** + * 用户查询参数 + * + * @author WebSoft + * @since 2021-08-29 20:35:09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "用户查询参数") +public class UserParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "用户类型, 0普通用户 10企业用户") + private Integer type; + + @Schema(description = "账号") + private String username; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "性别(字典)") + @QueryField(type = QueryType.EQ) + private String sex; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "邮箱是否验证, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "身份证号") + private String idCard; + + @Schema(description = "出生日期") + private String birthday; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "可用余额") + private BigDecimal balance; + + @Schema(description = "机构id") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "用户分组ID") + @QueryField(type = QueryType.EQ) + private Integer groupId; + + @Schema(description = "注册来源客户端") + @QueryField(type = QueryType.EQ) + private String platform; + + @Schema(description = "是否下线会员") + private Integer offline; + + @Schema(description = "上级机构ID") + @QueryField(type = QueryType.IN) + private Integer parentId; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "角色id") + @TableField(exist = false) + private Integer roleId; + + @Schema(description = "角色标识") + @TableField(exist = false) + private String roleCode; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "关注数") + private Integer followers; + + @Schema(description = "粉丝数") + private Integer fans; + + @Schema(description = "获赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "择偶区域") + @TableField(exist = false) + private String cityMate; + + @Schema(description = "机构名称") + @TableField(exist = false) + private String organizationName; + + @Schema(description = "公司名称") + @TableField(exist = false) + private String companyName; + + @Schema(description = "公司名称") + private String customerName; + + @Schema(description = "性别名称") + @TableField(exist = false) + private String sexName; + + @Schema(description = "推荐状态") + @TableField(exist = false) + private Integer recommend; + + @Schema(description = "搜索关键字") + @TableField(exist = false) + private String keywords; + + @Schema(description = "会员等级") + @TableField(exist = false) + private Integer gradeId; + + @Schema(description = "按角色搜索") + @TableField(exist = false) + private String roleIds; + + @Schema(description = "用户类型 sys系统用户 org机构职员 member商城会员 ") + @TableField(exist = false) + private String userType; + + @Schema(description = "支付宝授权码") + @TableField(exist = false) + private String authCode; + + @Schema(description = "微信凭证code") + @TableField(exist = false) + private String code; + + @Schema(description = "推荐人ID") + @QueryField(type = QueryType.IN) + private Integer refereeId; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "二维码类型") + @TableField(exist = false) + private String codeType; + + @Schema(description = "二维码内容 填网址扫码后可跳转") + @TableField(exist = false) + private String codeContent; + + @Schema(description = "是否内部职员") + @TableField(exist = false) + private Boolean isStaff; + + @Schema(description = "是否管理员") + @TableField(exist = false) + private Boolean isAdmin; + + @Schema(description = "openid") + private String openid; + + @Schema(description = "unionid") + private String unionid; + + @Schema(description = "最后结算时间") + @TableField(exist = false) + private String settlementTime; + + @Schema(description = "报餐时间") + @TableField(exist = false) + private String deliveryTime; + + @Schema(description = "用户ID集合") + @TableField(exist = false) + private Set userIds; + + @Schema(description = "用户手机号码集合") + @TableField(exist = false) + private Set phones; + + @Schema(description = "是否查询用户详细资料表") + @TableField(exist = false) + private Boolean showProfile; + + @Schema(description = "openId") + @TableField(exist = false) + private String openId; + + @Schema(description = "可管理的商户") + @QueryField(type = QueryType.LIKE) + private String merchants; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "关联用户ID") + @TableField(exist = false) + private Integer sysUserId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserRefereeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserRefereeParam.java new file mode 100644 index 0000000..18e9725 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserRefereeParam.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户推荐关系表查询参数 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserRefereeParam对象", description = "用户推荐关系表查询参数") +public class UserRefereeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "推荐人ID") + @QueryField(type = QueryType.EQ) + private Integer dealerId; + + @Schema(description = "用户id(被推荐人)") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "推荐关系层级(1,2,3)") + @QueryField(type = QueryType.EQ) + private Integer level; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserRoleParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserRoleParam.java new file mode 100644 index 0000000..56c9c4c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserRoleParam.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户角色查询参数 + * + * @author 科技小王子 + * @since 2025-06-16 20:39:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserRoleParam对象", description = "用户角色查询参数") +public class UserRoleParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "角色id") + @QueryField(type = QueryType.EQ) + private Integer roleId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserVerifyParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserVerifyParam.java new file mode 100644 index 0000000..b9fe81a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/UserVerifyParam.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.common.system.param; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Set; + +/** + * 实名认证查询参数 + * + * @author 科技小王子 + * @since 2025-05-29 23:01:04 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "UserVerifyParam对象", description = "实名认证查询参数") +public class UserVerifyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "认证类型, 0个人 1企业") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "主体名称") + @QueryField(type = QueryType.LIKE) + private String name; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "证件号码") + private String idCard; + + @Schema(description = "出生日期") + private String birthday; + + @Schema(description = "正面") + private String sfz1; + + @Schema(description = "反面") + private String sfz2; + + @Schema(description = "营业执照号码") + @QueryField(type = QueryType.EQ) + private String zzCode; + + @Schema(description = "管理员ID") + @QueryField(type = QueryType.EQ) + private Integer adminId; + + @Schema(description = "机构ID") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "机构id合集") + @TableField(exist = false) + private Set organizationIds; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0在线, 1离线") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/VersionParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/VersionParam.java new file mode 100644 index 0000000..ad369da --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/VersionParam.java @@ -0,0 +1,70 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 版本更新查询参数 + * + * @author 科技小王子 + * @since 2024-01-15 18:52:24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "VersionParam对象", description = "版本更新查询参数") +public class VersionParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "版本名") + private String versionName; + + @Schema(description = "版本号") + @QueryField(type = QueryType.EQ) + private Integer versionCode; + + @Schema(description = "下载链接") + private String androidDownloadUrl; + + @Schema(description = "下载链接") + private String iosDownloadUrl; + + @Schema(description = "更新日志") + private String updateInfo; + + @Schema(description = "强制更新") + @QueryField(type = QueryType.EQ) + private Integer isHard; + + @Schema(description = "热更") + @QueryField(type = QueryType.EQ) + private Integer isHot; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "文章排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/WebsiteFieldParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/WebsiteFieldParam.java new file mode 100644 index 0000000..0205a6f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/WebsiteFieldParam.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 应用参数查询参数 + * + * @author 科技小王子 + * @since 2024-08-27 15:18:05 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "WebsiteFieldParam对象", description = "应用参数查询参数") +public class WebsiteFieldParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "类型,0文本 1图片 2其他") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "名称") + private String name; + + @Schema(description = "默认值") + private String defaultValue; + + @Schema(description = "可修改的值 [on|off]") + private String modifyRange; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "名称") + private String value; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/WhiteDomainParam.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/WhiteDomainParam.java new file mode 100644 index 0000000..d0d74e0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/param/WhiteDomainParam.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 服务器白名单查询参数 + * + * @author 科技小王子 + * @since 2024-03-26 00:22:21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "WhiteDomainParam对象", description = "服务器白名单查询参数") +public class WhiteDomainParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/AccountInfoResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/AccountInfoResult.java new file mode 100644 index 0000000..14df17d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/AccountInfoResult.java @@ -0,0 +1,40 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 账号信息返回结果 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "账号信息返回结果") +public class AccountInfoResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户ID") + private String userId; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "租户名称") + private String tenantName; + + @Schema(description = "用户头像") + private String avatar; + + @Schema(description = "创建时间") + private String createTime; + + @Schema(description = "用户名") + private String username; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/CaptchaResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/CaptchaResult.java new file mode 100644 index 0000000..fd4bcf1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/CaptchaResult.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 验证码返回结果 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "验证码返回结果") +public class CaptchaResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "图形验证码base64数据") + private String base64; + + @Schema(description = "验证码文本") + private String text; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/CheckPhoneResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/CheckPhoneResult.java new file mode 100644 index 0000000..b3519e3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/CheckPhoneResult.java @@ -0,0 +1,28 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 检查手机号返回结果 + * + * @author WebSoft + * @since 2025-12-12 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "检查手机号返回结果") +public class CheckPhoneResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "是否已注册") + private Boolean isRegistered; + + @Schema(description = "账号数量") + private Integer accountCount; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/LoginResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/LoginResult.java new file mode 100644 index 0000000..e633372 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/LoginResult.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.system.result; + +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 登录返回结果 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "登录返回结果") +public class LoginResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "access_token") + private String access_token; + + @Schema(description = "用户信息") + private User user; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/RedisResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/RedisResult.java new file mode 100644 index 0000000..4e8f170 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/RedisResult.java @@ -0,0 +1,33 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * Redis缓存数据 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "缓存数据返回") +public class RedisResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "key") + private String key; + + @Schema(description = "数据") + private T data; + + @Schema(description = "过期时间") + private LocalDateTime expireTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SmsCaptchaResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SmsCaptchaResult.java new file mode 100644 index 0000000..5d6db68 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SmsCaptchaResult.java @@ -0,0 +1,25 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 短信验证码返回结果 + * + * @author WebSoft + * @since 2021-08-30 17:35:16 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "短信验证码返回结果") +public class SmsCaptchaResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "短信验证码") + private String text; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionOrderCreateResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionOrderCreateResult.java new file mode 100644 index 0000000..eb7bc8b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionOrderCreateResult.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 订阅订单创建结果 + */ +@Data +@Schema(description = "订阅订单创建结果") +public class SubscriptionOrderCreateResult { + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "价格试算结果") + private SubscriptionPriceResult price; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionOrderPayResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionOrderPayResult.java new file mode 100644 index 0000000..69de555 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionOrderPayResult.java @@ -0,0 +1,21 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 订阅订单支付结果 + */ +@Data +@Schema(description = "订阅订单支付结果") +public class SubscriptionOrderPayResult { + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "支付二维码链接") + private String codeUrl; + + @Schema(description = "价格信息") + private SubscriptionPriceResult price; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionPriceResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionPriceResult.java new file mode 100644 index 0000000..0dc2a57 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/result/SubscriptionPriceResult.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.system.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 订阅订单价格试算结果 + */ +@Data +@Schema(description = "订阅订单价格试算结果") +public class SubscriptionPriceResult { + + @Schema(description = "套餐ID") + private Integer packageId; + + @Schema(description = "是否续费,1=续费 0=新购") + private Integer isRenewal; + + @Schema(description = "是否升级,1=升级 0=非升级") + private Integer isUpgrade; + + @Schema(description = "支付方式") + private Integer payType; + + @Schema(description = "原价") + private BigDecimal originalPrice; + + @Schema(description = "优惠金额") + private BigDecimal discountAmount; + + @Schema(description = "应付金额") + private BigDecimal payPrice; + + @Schema(description = "总价(同原价,用于兼容前端字段)") + private BigDecimal totalPrice; + + @Schema(description = "价格说明") + private String remark; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/AccessKeyService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/AccessKeyService.java new file mode 100644 index 0000000..19946bc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/AccessKeyService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.AccessKey; +import com.gxwebsoft.common.system.param.AccessKeyParam; + +import java.util.List; + +/** + * 访问凭证管理Service + * + * @author 科技小王子 + * @since 2023-05-16 19:19:55 + */ +public interface AccessKeyService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(AccessKeyParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(AccessKeyParam param); + + /** + * 根据id查询 + * + * @param id 字典项id + * @return AccessKey + */ + AccessKey getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/AuthorizeCodeService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/AuthorizeCodeService.java new file mode 100644 index 0000000..17d3005 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/AuthorizeCodeService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.AuthorizeCode; +import com.gxwebsoft.common.system.param.AuthorizeCodeParam; + +import java.util.List; + +/** + * 授权码Service + * + * @author 科技小王子 + * @since 2025-08-05 01:17:27 + */ +public interface AuthorizeCodeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(AuthorizeCodeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(AuthorizeCodeParam param); + + /** + * 根据id查询 + * + * @param id id + * @return AuthorizeCode + */ + AuthorizeCode getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CartService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CartService.java new file mode 100644 index 0000000..4cc68eb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CartService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Cart; +import com.gxwebsoft.common.system.param.CartParam; + +import java.util.List; + +/** + * 购物车Service + * + * @author 科技小王子 + * @since 2024-10-26 10:54:51 + */ +public interface CartService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CartParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CartParam param); + + /** + * 根据id查询 + * + * @param id 购物车表ID + * @return Cart + */ + Cart getByIdRel(Long id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ChatConversationService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ChatConversationService.java new file mode 100644 index 0000000..dc8f201 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ChatConversationService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.ChatConversation; +import com.gxwebsoft.common.system.param.ChatConversationParam; + +import java.util.List; + +/** + * 聊天消息表Service + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +public interface ChatConversationService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ChatConversationParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ChatConversationParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return ChatConversation + */ + ChatConversation getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ChatMessageService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ChatMessageService.java new file mode 100644 index 0000000..e3ecc75 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ChatMessageService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.ChatMessage; +import com.gxwebsoft.common.system.param.ChatMessageParam; + +import java.util.List; + +/** + * 聊天消息表Service + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +public interface ChatMessageService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ChatMessageParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ChatMessageParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return ChatMessage + */ + ChatMessage getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyCommentService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyCommentService.java new file mode 100644 index 0000000..10ca95a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyCommentService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyComment; +import com.gxwebsoft.common.system.param.CompanyCommentParam; + +import java.util.List; + +/** + * 应用评论Service + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyCommentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyCommentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyCommentParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return CompanyComment + */ + CompanyComment getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyContentService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyContentService.java new file mode 100644 index 0000000..e4e1ab4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyContentService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyContent; +import com.gxwebsoft.common.system.param.CompanyContentParam; + +import java.util.List; + +/** + * 应用详情Service + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +public interface CompanyContentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyContentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyContentParam param); + + /** + * 根据id查询 + * + * @param id + * @return CompanyContent + */ + CompanyContent getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyGitService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyGitService.java new file mode 100644 index 0000000..f3ac263 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyGitService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyGit; +import com.gxwebsoft.common.system.param.CompanyGitParam; + +import java.util.List; + +/** + * 代码仓库Service + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +public interface CompanyGitService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyGitParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyGitParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CompanyGit + */ + CompanyGit getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyParameterService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyParameterService.java new file mode 100644 index 0000000..4ffa4c0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyParameterService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyParameter; +import com.gxwebsoft.common.system.param.CompanyParameterParam; + +import java.util.List; + +/** + * 应用参数Service + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyParameterService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyParameterParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyParameterParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CompanyParameter + */ + CompanyParameter getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyService.java new file mode 100644 index 0000000..d675f59 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyService.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.param.CompanyParam; + +import java.util.List; + +/** + * 企业信息Service + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +public interface CompanyService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyParam param); + + /** + * 根据id查询 + * + * @param companyId 企业id + * @return Company + */ + Company getByIdRel(Integer companyId); + + Company getByTenantIdRel(Integer tenantId); + + PageResult pageRelAll(CompanyParam param); + + void updateByCompanyId(Company company); + + boolean removeCompanyAll(Integer companyId); + + boolean undeleteAll(Integer companyId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyUrlService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyUrlService.java new file mode 100644 index 0000000..c2b2479 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/CompanyUrlService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyUrl; +import com.gxwebsoft.common.system.param.CompanyUrlParam; + +import java.util.List; + +/** + * 应用域名Service + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +public interface CompanyUrlService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CompanyUrlParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CompanyUrlParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return CompanyUrl + */ + CompanyUrl getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ComponentsService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ComponentsService.java new file mode 100644 index 0000000..2073c55 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ComponentsService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Components; +import com.gxwebsoft.common.system.param.ComponentsParam; + +import java.util.List; + +/** + * 组件Service + * + * @author 科技小王子 + * @since 2024-08-25 19:08:51 + */ +public interface ComponentsService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ComponentsParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ComponentsParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return Components + */ + Components getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictDataService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictDataService.java new file mode 100644 index 0000000..86b94bf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictDataService.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.*; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.param.DictDataParam; + +import java.util.List; + +/** + * 字典数据Service + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictDataService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(DictDataParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(DictDataParam param); + + /** + * 根据id查询 + * + * @param dictDataId 字典数据id + * @return DictData + */ + DictData getByIdRel(Integer dictDataId); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return DictData + */ + DictData getByDictCodeAndName(String dictCode, String dictDataName); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictService.java new file mode 100644 index 0000000..8aef5ba --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictService.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Dict; + +/** + * 字典Service + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictService extends IService { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictionaryDataService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictionaryDataService.java new file mode 100644 index 0000000..881fd5a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictionaryDataService.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.param.DictionaryDataParam; + +import java.util.List; + +/** + * 字典数据Service + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface DictionaryDataService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(DictionaryDataParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(DictionaryDataParam param); + + /** + * 根据id查询 + * + * @param dictDataId 字典数据id + * @return DictionaryData + */ + DictionaryData getByIdRel(Integer dictDataId); + + /** + * 根据dictCode和dictDataName查询 + * + * @param dictCode 字典标识 + * @param dictDataName 字典项名称 + * @return DictionaryData + */ + DictionaryData getByDictCodeAndName(String dictCode, String dictDataName); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictionaryService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictionaryService.java new file mode 100644 index 0000000..4705494 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DictionaryService.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Dictionary; + +/** + * 字典Service + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +public interface DictionaryService extends IService { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DomainService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DomainService.java new file mode 100644 index 0000000..2996471 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DomainService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.param.DomainParam; + +import java.util.List; + +/** + * 授权域名Service + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +public interface DomainService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(DomainParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(DomainParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return Domain + */ + Domain getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DomainServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DomainServiceImpl.java new file mode 100644 index 0000000..9323228 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/DomainServiceImpl.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Domain; +import com.gxwebsoft.common.system.mapper.DomainMapper; +import com.gxwebsoft.common.system.param.DomainParam; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 授权域名Service实现 + * + * @author 科技小王子 + * @since 2024-09-19 23:56:33 + */ +@Service +public class DomainServiceImpl extends ServiceImpl implements DomainService { + + @Override + public PageResult pageRel(DomainParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(DomainParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Domain getByIdRel(Integer id) { + DomainParam param = new DomainParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/EmailRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/EmailRecordService.java new file mode 100644 index 0000000..7d9f421 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/EmailRecordService.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.EmailRecord; + +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.Map; + +/** + * 邮件发送记录Service + * + * @author WebSoft + * @since 2019-06-19 04:07:02 + */ +public interface EmailRecordService extends IService { + + /** + * 发送普通邮件 + * + * @param title 标题 + * @param content 内容 + * @param toEmails 收件人 + */ + void sendTextEmail(String title, String content, String[] toEmails); + + /** + * 发送富文本邮件 + * + * @param title 标题 + * @param html 富文本 + * @param toEmails 收件人 + * @throws MessagingException MessagingException + */ + void sendFullTextEmail(String title, String html, String[] toEmails) throws MessagingException; + + /** + * 发送模板邮件 + * + * @param title 标题 + * @param path 模板路径 + * @param map 填充数据 + * @param toEmails 收件人 + * @throws MessagingException MessagingException + * @throws IOException IOException + */ + void sendHtmlEmail(String title, String path, Map map, String[] toEmails) + throws MessagingException, IOException; + + void sendEmail(String title, String content, String receiver); + + /** + * 发送邮件(带租户ID) + * + * @param title 标题 + * @param content 内容 + * @param receiver 收件人 + * @param tenantId 租户ID + */ + default void sendEmail(String title, String content, String receiver, Integer tenantId) { + sendEmail(title, content, receiver); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/EnvironmentService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/EnvironmentService.java new file mode 100644 index 0000000..d2499aa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/EnvironmentService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Environment; +import com.gxwebsoft.common.system.param.EnvironmentParam; + +import java.util.List; + +/** + * 环境管理Service + * + * @author 科技小王子 + * @since 2023-10-18 08:45:13 + */ +public interface EnvironmentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(EnvironmentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(EnvironmentParam param); + + /** + * 根据id查询 + * + * @param id 插件id + * @return Environment + */ + Environment getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/FileRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/FileRecordService.java new file mode 100644 index 0000000..3dd09ac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/FileRecordService.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.param.FileRecordParam; + +import java.io.File; +import java.util.List; + +/** + * 文件上传记录Service + * + * @author WebSoft + * @since 2021-08-30 11:20:15 + */ +public interface FileRecordService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(FileRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(FileRecordParam param); + + /** + * 根据id查询 + * + * @param id id + * @return FileRecord + */ + FileRecord getByIdRel(Integer id); + + /** + * 根据path查询 + * + * @param path 文件路径 + * @return FileRecord + */ + FileRecord getByIdPath(String path); + + /** + * 异步删除文件 + * + * @param files 文件数组 + */ + void deleteFileAsync(List files); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/LoginRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/LoginRecordService.java new file mode 100644 index 0000000..0c4adbf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/LoginRecordService.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.param.LoginRecordParam; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 登录日志Service + * + * @author WebSoft + * @since 2018-12-24 16:10:41 + */ +public interface LoginRecordService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(LoginRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(LoginRecordParam param); + + /** + * 根据id查询 + * + * @param id id + * @return LoginRecord + */ + LoginRecord getByIdRel(Integer id); + + /** + * 异步添加 + * + * @param username 用户账号 + * @param type 操作类型 + * @param comments 备注 + * @param tenantId 租户id + * @param request HttpServletRequest + */ + void saveAsync(String username, Integer type, String comments, Integer tenantId, HttpServletRequest request); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MenuService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MenuService.java new file mode 100644 index 0000000..db8e967 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MenuService.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.param.MenuParam; + +/** + * 菜单Service + * + * @author WebSoft + * @since 2018-12-24 16:10:31 + */ +public interface MenuService extends IService { + + Boolean cloneMenu(MenuParam param); + + Boolean install(Integer id); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantAccountService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantAccountService.java new file mode 100644 index 0000000..df87b16 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantAccountService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.MerchantAccount; +import com.gxwebsoft.common.system.param.MerchantAccountParam; + +import java.util.List; + +/** + * 商户账号Service + * + * @author 科技小王子 + * @since 2024-04-19 12:02:24 + */ +public interface MerchantAccountService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(MerchantAccountParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(MerchantAccountParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return MerchantAccount + */ + MerchantAccount getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantApplyService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantApplyService.java new file mode 100644 index 0000000..06f9bac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantApplyService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.MerchantApply; +import com.gxwebsoft.common.system.param.MerchantApplyParam; + +import java.util.List; + +/** + * 商户入驻申请Service + * + * @author 科技小王子 + * @since 2024-04-05 01:24:36 + */ +public interface MerchantApplyService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(MerchantApplyParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(MerchantApplyParam param); + + /** + * 根据id查询 + * + * @param applyId ID + * @return MerchantApply + */ + MerchantApply getByIdRel(Integer applyId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantService.java new file mode 100644 index 0000000..f35d75b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Merchant; +import com.gxwebsoft.common.system.param.MerchantParam; + +import java.util.List; + +/** + * 商户Service + * + * @author 科技小王子 + * @since 2024-04-05 00:03:54 + */ +public interface MerchantService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(MerchantParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(MerchantParam param); + + /** + * 根据id查询 + * + * @param merchantId ID + * @return Merchant + */ + Merchant getByIdRel(Long merchantId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantTypeService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantTypeService.java new file mode 100644 index 0000000..563c7d6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/MerchantTypeService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.MerchantType; +import com.gxwebsoft.common.system.param.MerchantTypeParam; + +import java.util.List; + +/** + * 商户类型Service + * + * @author 科技小王子 + * @since 2024-04-05 00:08:51 + */ +public interface MerchantTypeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(MerchantTypeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(MerchantTypeParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return MerchantType + */ + MerchantType getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ModulesService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ModulesService.java new file mode 100644 index 0000000..93244f1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/ModulesService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Modules; +import com.gxwebsoft.common.system.param.ModulesParam; + +import java.util.List; + +/** + * 模块管理Service + * + * @author 科技小王子 + * @since 2023-10-18 15:53:43 + */ +public interface ModulesService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ModulesParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ModulesParam param); + + /** + * 根据id查询 + * + * @param id 插件id + * @return Modules + */ + Modules getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/NoticeService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/NoticeService.java new file mode 100644 index 0000000..eb465e1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/NoticeService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Notice; +import com.gxwebsoft.common.system.param.NoticeParam; + +import java.util.List; + +/** + * 消息记录表Service + * + * @author 科技小王子 + * @since 2023-10-08 13:22:21 + */ +public interface NoticeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(NoticeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(NoticeParam param); + + /** + * 根据id查询 + * + * @param noticeId ID + * @return Notice + */ + Notice getByIdRel(Integer noticeId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OperationRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OperationRecordService.java new file mode 100644 index 0000000..227c4e6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OperationRecordService.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.param.OperationRecordParam; + +import java.util.List; + +/** + * 操作日志Service + * + * @author WebSoft + * @since 2018-12-24 16:10:01 + */ +public interface OperationRecordService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(OperationRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(OperationRecordParam param); + + /** + * 根据id查询 + * + * @param id id + * @return OperationRecord + */ + OperationRecord getByIdRel(Integer id); + + /** + * 异步添加 + * + * @param operationRecord OperationRecord + */ + void saveAsync(OperationRecord operationRecord); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderGoodsService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderGoodsService.java new file mode 100644 index 0000000..25e0058 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderGoodsService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OrderGoods; +import com.gxwebsoft.common.system.param.OrderGoodsParam; + +import java.util.List; + +/** + * 订单商品Service + * + * @author 科技小王子 + * @since 2024-10-26 12:18:05 + */ +public interface OrderGoodsService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(OrderGoodsParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(OrderGoodsParam param); + + /** + * 根据id查询 + * + * @param id 订单号 + * @return OrderGoods + */ + OrderGoods getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderInfoService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderInfoService.java new file mode 100644 index 0000000..d43f1d7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderInfoService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OrderInfo; +import com.gxwebsoft.common.system.param.OrderInfoParam; + +import java.util.List; + +/** + * Service + * + * @author 科技小王子 + * @since 2024-05-10 18:02:54 + */ +public interface OrderInfoService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(OrderInfoParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(OrderInfoParam param); + + /** + * 根据id查询 + * + * @param id + * @return OrderInfo + */ + OrderInfo getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderService.java new file mode 100644 index 0000000..0c42d8f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrderService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Order; +import com.gxwebsoft.common.system.param.OrderParam; + +import java.util.List; + +/** + * 订单Service + * + * @author 科技小王子 + * @since 2024-10-16 12:32:52 + */ +public interface OrderService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(OrderParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(OrderParam param); + + /** + * 根据id查询 + * + * @param orderId 订单号 + * @return Order + */ + Order getByIdRel(Integer orderId); + + void paySuccess(Order order); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrganizationService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrganizationService.java new file mode 100644 index 0000000..94d3407 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/OrganizationService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.param.OrganizationParam; + +import java.util.List; + +/** + * 组织机构Service + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +public interface OrganizationService extends IService { + + /** + * 关联分页查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(OrganizationParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(OrganizationParam param); + + /** + * 根据id查询 + * + * @param organizationId 机构id + * @return Organization + */ + Organization getByIdRel(Integer organizationId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/PaymentService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/PaymentService.java new file mode 100644 index 0000000..ae4f571 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/PaymentService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.param.PaymentParam; + +import java.util.List; + +/** + * 支付方式Service + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +public interface PaymentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(PaymentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(PaymentParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return Payment + */ + Payment getByIdRel(Integer id); + + Payment getByType(PaymentParam paymentParam); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/PlugService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/PlugService.java new file mode 100644 index 0000000..18d1194 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/PlugService.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.param.PlugParam; + +import java.util.List; + +/** + * 插件扩展Service + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +public interface PlugService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(PlugParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(PlugParam param); + + /** + * 根据id查询 + * + * @param menuId 菜单id + * @return Plug + */ + Plug getByIdRel(Integer menuId); + + Boolean cloneMenu(PlugParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RechargeOrderService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RechargeOrderService.java new file mode 100644 index 0000000..ab7a71e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RechargeOrderService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.RechargeOrder; +import com.gxwebsoft.common.system.param.RechargeOrderParam; + +import java.util.List; + +/** + * 会员充值订单表Service + * + * @author 科技小王子 + * @since 2024-07-26 23:18:48 + */ +public interface RechargeOrderService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(RechargeOrderParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(RechargeOrderParam param); + + /** + * 根据id查询 + * + * @param orderId 订单ID + * @return RechargeOrder + */ + RechargeOrder getByIdRel(Integer orderId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RoleMenuService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RoleMenuService.java new file mode 100644 index 0000000..05a3d4f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RoleMenuService.java @@ -0,0 +1,35 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; + +import java.util.List; + +/** + * 角色菜单Service + * + * @author WebSoft + * @since 2018-12-24 16:10:44 + */ +public interface RoleMenuService extends IService { + + /** + * 查询用户对应的菜单 + * + * @param userId 用户id + * @param menuType 菜单类型 + * @return List + */ + List listMenuByUserId(Integer userId, Integer menuType); + + /** + * 查询用户对应的菜单 + * + * @param roleIds 角色id + * @param menuType 菜单类型 + * @return List + */ + List listMenuByRoleIds(List roleIds, Integer menuType); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RoleService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RoleService.java new file mode 100644 index 0000000..8b92605 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/RoleService.java @@ -0,0 +1,23 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.param.RoleParam; + +/** + * 角色Service + * + * @author WebSoft + * @since 2018-12-24 16:10:32 + */ +public interface RoleService extends IService { + + /** + * 通过角色代码查询角色 + * + * @param param 查询参数(含 roleCode) + * @return Role + */ + Role getByRoleCode(RoleParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/SettingService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/SettingService.java new file mode 100644 index 0000000..9560fae --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/SettingService.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.common.system.service; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.param.SettingParam; +import com.wechat.pay.java.core.Config; + +import java.util.List; + +/** + * 系统设置Service + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +public interface SettingService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(SettingParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(SettingParam param); + + /** + * 根据id查询 + * + * @param settingId id + * @return Setting + */ + Setting getByIdRel(Integer settingId); + + /** + * 通过key获取设置内容(不指定租户,使用当前上下文租户) + * @param key key + * @return Setting + */ + default JSONObject getBySettingKey(String key) { + return getBySettingKey(key, null); + } + + /** + * 通过key获取设置内容 + * @param key key + * @return Setting + */ + JSONObject getBySettingKey(String key,Integer tenantId); + + /** + * 跨租户获取设置内容 + * @param key 设置键 + * @param tenantId 租户ID + * @return JSONObject + */ + JSONObject getBySettingKeyIgnoreTenant(String key, Integer tenantId); + + Setting getData(String settingKey); + + JSONObject getCache(String key); + + void initConfig(Setting setting); + + Config getConfig(Integer tenantId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/SysFileTypeService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/SysFileTypeService.java new file mode 100644 index 0000000..73c5211 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/SysFileTypeService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.SysFileType; +import com.gxwebsoft.common.system.param.SysFileTypeParam; + +import java.util.List; + +/** + * 存储类型Service + * + * @author 科技小王子 + * @since 2025-05-16 14:24:28 + */ +public interface SysFileTypeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(SysFileTypeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(SysFileTypeParam param); + + /** + * 根据id查询 + * + * @param id 主键id + * @return SysFileType + */ + SysFileType getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantPackageService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantPackageService.java new file mode 100644 index 0000000..a301d36 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantPackageService.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.TenantPackage; + +import java.util.List; + +/** + * 租户套餐Service + * + * @author WebSoft + * @since 2025-12-12 + */ +public interface TenantPackageService extends IService { + + /** + * 查询所有上架的套餐 + * + * @return List + */ + List listAvailablePackages(); + + /** + * 根据版本号查询套餐 + * + * @param version 版本号 + * @return TenantPackage + */ + TenantPackage getByVersion(Integer version); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantService.java new file mode 100644 index 0000000..99b1171 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantService.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.param.TenantParam; + +import java.util.List; + +/** + * 租户Service + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +public interface TenantService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(TenantParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(TenantParam param); + + /** + * 根据id查询 + * + * @param tenantId 租户id + * @return Tenant + */ + Tenant getByIdRel(Integer tenantId); + + /** + * 转移租户所有权 + * + * @param tenantId 租户ID + * @param newUserId 新用户ID + * @return boolean + */ + boolean transferOwner(Integer tenantId, Integer newUserId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantSubscriptionOrderService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantSubscriptionOrderService.java new file mode 100644 index 0000000..e172d20 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantSubscriptionOrderService.java @@ -0,0 +1,79 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder; + +/** + * 租户订阅订单Service + * + * @author WebSoft + * @since 2025-12-12 + */ +public interface TenantSubscriptionOrderService extends IService { + + /** + * 创建订阅订单 + * + * @param packageId 套餐ID + * @param payType 支付周期 1月付 3季付 12年付 + * @param tenantId 租户ID + * @param userId 用户ID + * @return TenantSubscriptionOrder + */ + TenantSubscriptionOrder createOrder(Integer packageId, Integer payType, Integer tenantId, Integer userId); + + /** + * 创建试用订单 + * + * @param tenantId 租户ID + * @param userId 用户ID + * @return TenantSubscriptionOrder + */ + TenantSubscriptionOrder createTrialOrder(Integer tenantId, Integer userId); + + /** + * 支付订单 + * + * @param orderNo 订单号 + * @param paymentMethod 支付方式 + * @param paymentId 支付流水号 + * @return boolean + */ + boolean payOrder(String orderNo, String paymentMethod, String paymentId); + + /** + * 激活订单(支付成功后调用) + * + * @param orderNo 订单号 + * @return boolean + */ + boolean activateOrder(String orderNo); + + /** + * 取消订单 + * + * @param orderNo 订单号 + * @param cancelReason 取消原因 + * @return boolean + */ + boolean cancelOrder(String orderNo, String cancelReason); + + /** + * 分页查询租户订单 + * + * @param tenantId 租户ID + * @param page 页码 + * @param limit 每页数量 + * @return PageResult + */ + PageResult pageByTenant(Integer tenantId, Integer page, Integer limit); + + /** + * 根据订单号查询 + * + * @param orderNo 订单号 + * @return TenantSubscriptionOrder + */ + TenantSubscriptionOrder getByOrderNo(String orderNo); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantSubscriptionService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantSubscriptionService.java new file mode 100644 index 0000000..cd7a5af --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/TenantSubscriptionService.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.TenantSubscription; + +import java.util.List; + +/** + * 租户订阅记录Service + * + * @author WebSoft + * @since 2025-12-12 + */ +public interface TenantSubscriptionService extends IService { + + /** + * 根据租户ID查询订阅信息 + * + * @param tenantId 租户ID + * @return TenantSubscription + */ + TenantSubscription getByTenantId(Integer tenantId); + + /** + * 创建或更新订阅 + * + * @param tenantId 租户ID + * @param packageId 套餐ID + * @param version 版本号 + * @param startTime 开始时间 + * @param endTime 到期时间 + * @param isTrial 是否试用 + * @return TenantSubscription + */ + TenantSubscription createOrUpdateSubscription(Integer tenantId, Integer packageId, Integer version, + java.util.Date startTime, java.util.Date endTime, Integer isTrial); + + /** + * 升级订阅 + * + * @param tenantId 租户ID + * @param newPackageId 新套餐ID + * @return boolean + */ + boolean upgradeSubscription(Integer tenantId, Integer newPackageId); + + /** + * 续费订阅 + * + * @param tenantId 租户ID + * @param months 续费月数 + * @return boolean + */ + boolean renewSubscription(Integer tenantId, Integer months); + + /** + * 设置自动续费 + * + * @param tenantId 租户ID + * @param autoRenewal 是否自动续费 + * @param renewalPackageId 续费套餐ID + * @return boolean + */ + boolean setAutoRenewal(Integer tenantId, Integer autoRenewal, Integer renewalPackageId); + + /** + * 检查订阅是否有效 + * + * @param tenantId 租户ID + * @return boolean + */ + boolean isSubscriptionValid(Integer tenantId); + + /** + * 检查订阅是否过期 + * + * @param tenantId 租户ID + * @return boolean + */ + boolean isSubscriptionExpired(Integer tenantId); + + /** + * 查询即将过期的订阅 + * + * @param days 提前天数 + * @return List + */ + List listExpiringSoon(Integer days); + + /** + * 查询已过期的订阅 + * + * @return List + */ + List listExpired(); + + /** + * 标记订阅为已过期 + * + * @param subscriptionId 订阅ID + * @return boolean + */ + boolean markAsExpired(Long subscriptionId); + + /** + * 发送过期提醒 + * + * @param subscriptionId 订阅ID + * @param notifyStatus 提醒状态 + * @return boolean + */ + boolean sendExpiryNotification(Long subscriptionId, Integer notifyStatus); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserBalanceLogService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserBalanceLogService.java new file mode 100644 index 0000000..eaa4e0d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserBalanceLogService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; + +import java.util.List; + +/** + * 用户余额变动明细表Service + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +public interface UserBalanceLogService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserBalanceLogParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserBalanceLogParam param); + + /** + * 根据id查询 + * + * @param logId 主键ID + * @return UserBalanceLog + */ + UserBalanceLog getByIdRel(Integer logId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserCollectionService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserCollectionService.java new file mode 100644 index 0000000..421c682 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserCollectionService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.param.UserCollectionParam; + +import java.util.List; + +/** + * 我的收藏Service + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +public interface UserCollectionService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserCollectionParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserCollectionParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return UserCollection + */ + UserCollection getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserCollectionServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserCollectionServiceImpl.java new file mode 100644 index 0000000..f5c174f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserCollectionServiceImpl.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserCollection; +import com.gxwebsoft.common.system.mapper.UserCollectionMapper; +import com.gxwebsoft.common.system.param.UserCollectionParam; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 我的收藏Service实现 + * + * @author 科技小王子 + * @since 2024-04-28 18:08:32 + */ +@Service +public class UserCollectionServiceImpl extends ServiceImpl implements UserCollectionService { + + @Override + public PageResult pageRel(UserCollectionParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserCollectionParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserCollection getByIdRel(Integer id) { + UserCollectionParam param = new UserCollectionParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserFileService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserFileService.java new file mode 100644 index 0000000..2c8abe6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserFileService.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.system.entity.UserFile; + +/** + * 用户文件Service + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +public interface UserFileService extends IService { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserGradeService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserGradeService.java new file mode 100644 index 0000000..d9ab5ae --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserGradeService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserGrade; +import com.gxwebsoft.common.system.param.UserGradeParam; + +import java.util.List; + +/** + * 用户会员等级表Service + * + * @author 科技小王子 + * @since 2023-10-07 22:51:17 + */ +public interface UserGradeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserGradeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserGradeParam param); + + /** + * 根据id查询 + * + * @param gradeId 等级ID + * @return UserGrade + */ + UserGrade getByIdRel(Integer gradeId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserGroupService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserGroupService.java new file mode 100644 index 0000000..d97b0aa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserGroupService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserGroup; +import com.gxwebsoft.common.system.param.UserGroupParam; + +import java.util.List; + +/** + * 用户分组管理表Service + * + * @author 科技小王子 + * @since 2023-10-28 15:16:39 + */ +public interface UserGroupService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserGroupParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserGroupParam param); + + /** + * 根据id查询 + * + * @param groupId 分组ID + * @return UserGroup + */ + UserGroup getByIdRel(Integer groupId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserOauthService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserOauthService.java new file mode 100644 index 0000000..9c2e04c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserOauthService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserOauth; +import com.gxwebsoft.common.system.param.UserOauthParam; + +import java.util.List; + +/** + * 第三方用户信息表Service + * + * @author 科技小王子 + * @since 2023-10-07 22:39:46 + */ +public interface UserOauthService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserOauthParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserOauthParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return UserOauth + */ + UserOauth getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserRefereeService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserRefereeService.java new file mode 100644 index 0000000..e715c4f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserRefereeService.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.param.UserRefereeParam; + +import java.util.List; + +/** + * 用户推荐关系表Service + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +public interface UserRefereeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserRefereeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserRefereeParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return UserReferee + */ + UserReferee getByIdRel(Integer id); + + UserReferee check(Integer dealerId, Integer userId); + + UserReferee getByUserId(Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserRoleService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserRoleService.java new file mode 100644 index 0000000..58093cf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserRoleService.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.UserRole; +import com.gxwebsoft.common.system.param.UserRoleParam; + +import java.util.List; + +/** + * 用户角色Service + * + * @author WebSoft + * @since 2018-12-24 16:10:35 + */ +public interface UserRoleService extends IService { + + /** + * 批量添加用户角色 + * + * @param userId 用户id + * @param roleIds 角色id集合 + * @return int + */ + int saveBatch(Integer userId, List roleIds); + + /** + * 根据用户id查询角色 + * + * @param userId 用户id + * @return List + */ + List listByUserId(Integer userId); + + /** + * 批量根据用户id查询角色 + * + * @param userIds 用户id集合 + * @return List + */ + List listByUserIds(List userIds); + + /** + * 根据角色id查询用户角色 + * + * @param roleId 角色id + * @return List + */ + List listByRoleId(Integer roleId); + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserRoleParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserRoleParam param); + + /** + * 根据id查询 + * + * @param id id + * @return UserRole + */ + UserRole getByIdRel(Integer id); + +} + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserService.java new file mode 100644 index 0000000..b283c5b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserService.java @@ -0,0 +1,146 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.cms.entity.CmsWebsite; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.UserParam; +import org.springframework.security.core.userdetails.UserDetailsService; + +import java.util.List; + +/** + * 用户Service + * + * @author WebSoft + * @since 2018-12-24 16:10:52 + */ +public interface UserService extends IService, UserDetailsService { + + /** + * 关联分页查询用户 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserParam param); + + /** + * 关联查询全部用户 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserParam param); + + /** + * 根据id查询用户 + * + * @param userId 用户id + * @return User + */ + User getByIdRel(Integer userId); + + /** + * 根据账号查询用户 + * + * @param username 账号 + * @return User + */ + User getByUsername(String username); + + /** + * 根据账号查询用户 + * + * @param username 账号 + * @param tenantId 租户id + * @return User + */ + User getByUsername(String username, Integer tenantId); + + /** + * 添加用户 + * + * @param user 用户信息 + * @return boolean + */ + boolean saveUser(User user); + + /** + * 修改用户 + * + * @param user 用户信息 + * @return boolean + */ + boolean updateUser(User user); + + /** + * 比较用户密码 + * + * @param dbPassword 数据库存储的密码 + * @param inputPassword 用户输入的密码 + * @return boolean + */ + boolean comparePassword(String dbPassword, String inputPassword); + + /** + * md5加密用户密码 + * + * @param password 密码明文 + * @return 密文 + */ + String encodePassword(String password); + + /** + * 跟进手机号码查询用户 + * @param phone 手机号码 + * @return 用户信息 + */ + User getByPhone(String phone); + + User getByUnionId(UserParam userParam); + + User getByOauthId(UserParam userParam); + + List listStatisticsRel(UserParam param); + + /** + * 更新会员不限租户 + * @param user 用户信息 + */ + void updateByUserId(User user); + + /** + * 根据用户ID查询用户(忽略租户隔离) + * @param userId 用户ID + * @return User + */ + User getByIdIgnoreTenant(Integer userId); + + /** + * 根据账号查询用户(忽略租户隔离) + * 支持 username / phone / email 登录 + * + * @param username 账号/手机号/邮箱 + * @return User + */ + User getByUsernameIgnoreTenant(String username); + + List pageAdminByPhone(UserParam param); + + List listByAlert(); + + /** + * 根据用户ID查询用户(忽略租户隔离,跨租户查询) + * @param userId 用户ID(字符串类型,会转换为Integer) + * @return User + */ + User getAllByUserId(String userId); + + /** + * 根据微信openid查询用户 + * @param openId 微信openid + * @return User + */ + User findByOpenId(String openId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserVerifyService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserVerifyService.java new file mode 100644 index 0000000..b8bb118 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/UserVerifyService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserVerify; +import com.gxwebsoft.common.system.param.UserVerifyParam; + +import java.util.List; + +/** + * 实名认证Service + * + * @author 科技小王子 + * @since 2025-05-29 23:01:04 + */ +public interface UserVerifyService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserVerifyParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserVerifyParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return UserVerify + */ + UserVerify getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/VersionService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/VersionService.java new file mode 100644 index 0000000..afbc28d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/VersionService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Version; +import com.gxwebsoft.common.system.param.VersionParam; + +import java.util.List; + +/** + * 版本更新Service + * + * @author 科技小王子 + * @since 2024-01-15 18:52:24 + */ +public interface VersionService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(VersionParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(VersionParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return Version + */ + Version getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WebsiteFieldService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WebsiteFieldService.java new file mode 100644 index 0000000..efc4fcb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WebsiteFieldService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.WebsiteField; +import com.gxwebsoft.common.system.param.WebsiteFieldParam; + +import java.util.List; + +/** + * 应用参数Service + * + * @author 科技小王子 + * @since 2024-08-27 15:18:05 + */ +public interface WebsiteFieldService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(WebsiteFieldParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(WebsiteFieldParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return WebsiteField + */ + WebsiteField getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WhiteDomainService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WhiteDomainService.java new file mode 100644 index 0000000..35918bd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WhiteDomainService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.common.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.WhiteDomain; +import com.gxwebsoft.common.system.param.WhiteDomainParam; + +import java.util.List; + +/** + * 服务器白名单Service + * + * @author 科技小王子 + * @since 2024-03-26 00:22:21 + */ +public interface WhiteDomainService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(WhiteDomainParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(WhiteDomainParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return WhiteDomain + */ + WhiteDomain getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java new file mode 100644 index 0000000..3a3a44b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WxMiniappAccessTokenService.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service; + +/** + * 微信小程序 access_token 获取服务(按租户)。 + * + *

用于调用微信小程序开放接口(例如:上传发货信息)。

+ */ +public interface WxMiniappAccessTokenService { + + /** + * 获取指定租户的小程序 access_token(内部带缓存)。 + * + * @param tenantId 租户ID + * @return access_token + */ + String getAccessToken(Integer tenantId); +} + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WxService.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WxService.java new file mode 100644 index 0000000..e9b445c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/WxService.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.common.system.service; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +/** + * 微信公共服务类 + * + * @author 科技小王子 + * @since 2025-09-08 + */ +@Slf4j +@Service +public class WxService { + + @Autowired + private SettingService settingService; + + @Autowired + private RedisTemplate redisTemplate; + + private static final String ACCESS_TOKEN_KEY = "WX_ACCESS_TOKEN"; + + /** + * 获取微信AccessToken(使用默认租户) + */ + public String getAccessToken() { + return getAccessToken(null); + } + + /** + * 获取微信AccessToken(支持指定租户ID) + * + * @param tenantId 租户ID,为null时使用默认值 + * @return access_token + */ + public String getAccessToken(Integer tenantId) { + if (tenantId == null) { + tenantId = 10048; // 默认租户ID,可以根据需要调整 + } + + String key = ACCESS_TOKEN_KEY + ":" + tenantId; + + // 从缓存获取 + String cachedToken = redisTemplate.opsForValue().get(key); + if (StrUtil.isNotBlank(cachedToken)) { + try { + JSONObject tokenData = JSON.parseObject(cachedToken); + String accessToken = tokenData.getString("access_token"); + if (StrUtil.isNotBlank(accessToken)) { + log.debug("从缓存获取access_token: {}", accessToken); + return accessToken; + } + } catch (Exception e) { + // 解析失败,可能是旧格式,直接使用 + if (!cachedToken.startsWith("{")) { + log.debug("从缓存获取access_token(旧格式): {}", cachedToken); + return cachedToken; + } + log.warn("解析缓存的access_token失败: {}", e.getMessage()); + // 缓存数据异常,删除缓存,重新获取 + redisTemplate.delete(key); + } + } + + // 缓存中没有,重新获取 + try { + JSONObject setting = settingService.getBySettingKey("mp-weixin"); + if (setting == null) { + throw new RuntimeException("请先配置微信小程序"); + } + + String appId = setting.getString("appId"); + String appSecret = setting.getString("appSecret"); + if (StrUtil.isBlank(appId) || StrUtil.isBlank(appSecret)) { + throw new RuntimeException("微信小程序配置不完整"); + } + + // 调用微信API获取AccessToken + String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + + appId + "&secret=" + appSecret; + String response = HttpRequest.get(apiUrl).execute().body(); + + JSONObject result = JSON.parseObject(response); + String accessToken = result.getString("access_token"); + if (StrUtil.isNotBlank(accessToken)) { + // 存入缓存 + JSONObject tokenData = new JSONObject(); + tokenData.put("access_token", accessToken); + tokenData.put("expires_in", result.get("expires_in")); + redisTemplate.opsForValue().set(key, tokenData.toJSONString(), 7000L, TimeUnit.SECONDS); + log.info("获取新的access_token成功: {}", accessToken); + return accessToken; + } else { + throw new RuntimeException("获取AccessToken失败: " + response); + } + } catch (Exception e) { + log.error("获取微信AccessToken失败: {}", e.getMessage(), e); + throw new RuntimeException("获取微信AccessToken失败: " + e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/AccessKeyServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/AccessKeyServiceImpl.java new file mode 100644 index 0000000..2f02e25 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/AccessKeyServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.AccessKeyMapper; +import com.gxwebsoft.common.system.service.AccessKeyService; +import com.gxwebsoft.common.system.entity.AccessKey; +import com.gxwebsoft.common.system.param.AccessKeyParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 访问凭证管理Service实现 + * + * @author 科技小王子 + * @since 2023-05-16 19:19:55 + */ +@Service +public class AccessKeyServiceImpl extends ServiceImpl implements AccessKeyService { + + @Override + public PageResult pageRel(AccessKeyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AccessKeyParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public AccessKey getByIdRel(Integer id) { + AccessKeyParam param = new AccessKeyParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/AuthorizeCodeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/AuthorizeCodeServiceImpl.java new file mode 100644 index 0000000..21d7091 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/AuthorizeCodeServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.AuthorizeCodeMapper; +import com.gxwebsoft.common.system.service.AuthorizeCodeService; +import com.gxwebsoft.common.system.entity.AuthorizeCode; +import com.gxwebsoft.common.system.param.AuthorizeCodeParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 授权码Service实现 + * + * @author 科技小王子 + * @since 2025-08-05 01:17:27 + */ +@Service +public class AuthorizeCodeServiceImpl extends ServiceImpl implements AuthorizeCodeService { + + @Override + public PageResult pageRel(AuthorizeCodeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(AuthorizeCodeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public AuthorizeCode getByIdRel(Integer id) { + AuthorizeCodeParam param = new AuthorizeCodeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CartServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CartServiceImpl.java new file mode 100644 index 0000000..859ec25 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CartServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Cart; +import com.gxwebsoft.common.system.mapper.CartMapper; +import com.gxwebsoft.common.system.param.CartParam; +import com.gxwebsoft.common.system.service.CartService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 购物车Service实现 + * + * @author 科技小王子 + * @since 2024-10-26 10:54:51 + */ +@Service +public class CartServiceImpl extends ServiceImpl implements CartService { + + @Override + public PageResult pageRel(CartParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CartParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Cart getByIdRel(Long id) { + CartParam param = new CartParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ChatConversationServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ChatConversationServiceImpl.java new file mode 100644 index 0000000..d7fc35e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ChatConversationServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.ChatConversationMapper; +import com.gxwebsoft.common.system.service.ChatConversationService; +import com.gxwebsoft.common.system.entity.ChatConversation; +import com.gxwebsoft.common.system.param.ChatConversationParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 聊天消息表Service实现 + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +@Service +public class ChatConversationServiceImpl extends ServiceImpl implements ChatConversationService { + + @Override + public PageResult pageRel(ChatConversationParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ChatConversationParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ChatConversation getByIdRel(Integer id) { + ChatConversationParam param = new ChatConversationParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ChatMessageServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ChatMessageServiceImpl.java new file mode 100644 index 0000000..bb1f1ef --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ChatMessageServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.ChatMessageMapper; +import com.gxwebsoft.common.system.service.ChatMessageService; +import com.gxwebsoft.common.system.entity.ChatMessage; +import com.gxwebsoft.common.system.param.ChatMessageParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 聊天消息表Service实现 + * + * @author 科技小王子 + * @since 2024-04-27 15:57:27 + */ +@Service +public class ChatMessageServiceImpl extends ServiceImpl implements ChatMessageService { + + @Override + public PageResult pageRel(ChatMessageParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ChatMessageParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ChatMessage getByIdRel(Integer id) { + ChatMessageParam param = new ChatMessageParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyCommentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyCommentServiceImpl.java new file mode 100644 index 0000000..e945e66 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyCommentServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyComment; +import com.gxwebsoft.common.system.mapper.CompanyCommentMapper; +import com.gxwebsoft.common.system.param.CompanyCommentParam; +import com.gxwebsoft.common.system.service.CompanyCommentService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用评论Service实现 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Service +public class CompanyCommentServiceImpl extends ServiceImpl implements CompanyCommentService { + + @Override + public PageResult pageRel(CompanyCommentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyCommentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyComment getByIdRel(Integer id) { + CompanyCommentParam param = new CompanyCommentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyContentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyContentServiceImpl.java new file mode 100644 index 0000000..b8604a6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyContentServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyContent; +import com.gxwebsoft.common.system.mapper.CompanyContentMapper; +import com.gxwebsoft.common.system.param.CompanyContentParam; +import com.gxwebsoft.common.system.service.CompanyContentService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用详情Service实现 + * + * @author 科技小王子 + * @since 2024-10-16 13:41:21 + */ +@Service +public class CompanyContentServiceImpl extends ServiceImpl implements CompanyContentService { + + @Override + public PageResult pageRel(CompanyContentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyContentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyContent getByIdRel(Integer id) { + CompanyContentParam param = new CompanyContentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyGitServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyGitServiceImpl.java new file mode 100644 index 0000000..a954d4b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyGitServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyGit; +import com.gxwebsoft.common.system.mapper.CompanyGitMapper; +import com.gxwebsoft.common.system.param.CompanyGitParam; +import com.gxwebsoft.common.system.service.CompanyGitService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 代码仓库Service实现 + * + * @author 科技小王子 + * @since 2024-10-19 18:08:51 + */ +@Service +public class CompanyGitServiceImpl extends ServiceImpl implements CompanyGitService { + + @Override + public PageResult pageRel(CompanyGitParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyGitParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyGit getByIdRel(Integer id) { + CompanyGitParam param = new CompanyGitParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyParameterServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyParameterServiceImpl.java new file mode 100644 index 0000000..4b77612 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyParameterServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyParameter; +import com.gxwebsoft.common.system.mapper.CompanyParameterMapper; +import com.gxwebsoft.common.system.param.CompanyParameterParam; +import com.gxwebsoft.common.system.service.CompanyParameterService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用参数Service实现 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Service +public class CompanyParameterServiceImpl extends ServiceImpl implements CompanyParameterService { + + @Override + public PageResult pageRel(CompanyParameterParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyParameterParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyParameter getByIdRel(Integer id) { + CompanyParameterParam param = new CompanyParameterParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyServiceImpl.java new file mode 100644 index 0000000..8bdb503 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyServiceImpl.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.mapper.CompanyMapper; +import com.gxwebsoft.common.system.param.CompanyParam; +import com.gxwebsoft.common.system.service.CompanyService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 企业信息Service实现 + * + * @author 科技小王子 + * @since 2023-05-27 14:57:34 + */ +@Service +public class CompanyServiceImpl extends ServiceImpl implements CompanyService { + + @Override + public PageResult pageRel(CompanyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number desc,create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Company getByIdRel(Integer companyId) { + CompanyParam param = new CompanyParam(); + param.setCompanyId(companyId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public Company getByTenantIdRel(Integer tenantId) { + CompanyParam param = new CompanyParam(); +// final Company one = param.getOne(baseMapper.selectListRel(param)); + param.setAuthoritative(true); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public PageResult pageRelAll(CompanyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number desc,create_time desc"); + List list = baseMapper.selectPageRelAll(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public void updateByCompanyId(Company company) { + baseMapper.updateByCompanyId(company); + } + + @Override + public boolean removeCompanyAll(Integer companyId){ + if (baseMapper.removeCompanyAll(companyId)) { + return true; + } + return false; + } + + @Override + public boolean undeleteAll(Integer companyId){ + if (baseMapper.undeleteAll(companyId)) { + return true; + } + return false; + } + + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyUrlServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyUrlServiceImpl.java new file mode 100644 index 0000000..a7922cb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/CompanyUrlServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.CompanyUrl; +import com.gxwebsoft.common.system.mapper.CompanyUrlMapper; +import com.gxwebsoft.common.system.param.CompanyUrlParam; +import com.gxwebsoft.common.system.service.CompanyUrlService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用域名Service实现 + * + * @author 科技小王子 + * @since 2024-10-17 15:30:24 + */ +@Service +public class CompanyUrlServiceImpl extends ServiceImpl implements CompanyUrlService { + + @Override + public PageResult pageRel(CompanyUrlParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CompanyUrlParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public CompanyUrl getByIdRel(Integer id) { + CompanyUrlParam param = new CompanyUrlParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ComponentsServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ComponentsServiceImpl.java new file mode 100644 index 0000000..59d0db4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ComponentsServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.ComponentsMapper; +import com.gxwebsoft.common.system.service.ComponentsService; +import com.gxwebsoft.common.system.entity.Components; +import com.gxwebsoft.common.system.param.ComponentsParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 组件Service实现 + * + * @author 科技小王子 + * @since 2024-08-25 19:08:51 + */ +@Service +public class ComponentsServiceImpl extends ServiceImpl implements ComponentsService { + + @Override + public PageResult pageRel(ComponentsParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ComponentsParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Components getByIdRel(Integer id) { + ComponentsParam param = new ComponentsParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictDataServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictDataServiceImpl.java new file mode 100644 index 0000000..e30a0fe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictDataServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.mapper.DictDataMapper; +import com.gxwebsoft.common.system.param.DictDataParam; +import com.gxwebsoft.common.system.service.DictDataService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典数据Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Service +public class DictDataServiceImpl extends ServiceImpl + implements DictDataService { + + @Override + public PageResult pageRel(DictDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(DictDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public DictData getByIdRel(Integer dictDataId) { + DictDataParam param = new DictDataParam(); + param.setDictDataId(dictDataId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public DictData getByDictCodeAndName(String dictCode, String dictDataName) { + List list = baseMapper.getByDictCodeAndName(dictCode, dictDataName); + return CommonUtil.listGetOne(list); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictServiceImpl.java new file mode 100644 index 0000000..6b09f90 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictServiceImpl.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Dict; +import com.gxwebsoft.common.system.mapper.DictMapper; +import com.gxwebsoft.common.system.service.DictService; +import org.springframework.stereotype.Service; + +/** + * 字典Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Service +public class DictServiceImpl extends ServiceImpl implements DictService { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryDataServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryDataServiceImpl.java new file mode 100644 index 0000000..0f26dd2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryDataServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.DictionaryData; +import com.gxwebsoft.common.system.mapper.DictionaryDataMapper; +import com.gxwebsoft.common.system.param.DictionaryDataParam; +import com.gxwebsoft.common.system.service.DictionaryDataService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典数据Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Service +public class DictionaryDataServiceImpl extends ServiceImpl + implements DictionaryDataService { + + @Override + public PageResult pageRel(DictionaryDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(DictionaryDataParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public DictionaryData getByIdRel(Integer dictDataId) { + DictionaryDataParam param = new DictionaryDataParam(); + param.setDictDataId(dictDataId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public DictionaryData getByDictCodeAndName(String dictCode, String dictDataName) { + List list = baseMapper.getByDictCodeAndName(dictCode, dictDataName); + return CommonUtil.listGetOne(list); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryServiceImpl.java new file mode 100644 index 0000000..74d6fe1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/DictionaryServiceImpl.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Dictionary; +import com.gxwebsoft.common.system.mapper.DictionaryMapper; +import com.gxwebsoft.common.system.service.DictionaryService; +import org.springframework.stereotype.Service; + +/** + * 字典Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:03 + */ +@Service +public class DictionaryServiceImpl extends ServiceImpl implements DictionaryService { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/EmailRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/EmailRecordServiceImpl.java new file mode 100644 index 0000000..6cf05fe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/EmailRecordServiceImpl.java @@ -0,0 +1,99 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.EmailRecord; +import com.gxwebsoft.common.system.mapper.EmailRecordMapper; +import com.gxwebsoft.common.system.service.EmailRecordService; +import org.beetl.core.Configuration; +import org.beetl.core.GroupTemplate; +import org.beetl.core.Template; +import org.beetl.core.resource.ClasspathResourceLoader; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; +import java.io.IOException; +import java.util.Map; + +/** + * 邮件发送记录Service实现 + * + * @author WebSoft + * @since 2019-06-19 04:07:54 + */ +@Service +public class EmailRecordServiceImpl extends ServiceImpl + implements EmailRecordService { + // 发件邮箱 + @Value("${spring.mail.username:}") + private String formEmail; + @Autowired(required = false) + private JavaMailSender mailSender; + + @Override + public void sendTextEmail(String title, String content, String[] toEmails) { + if (mailSender == null) { + System.out.println("邮件服务未配置,跳过发送邮件: " + title); + return; + } + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(formEmail); + message.setTo(toEmails); + message.setSubject(title); + message.setText(content); + mailSender.send(message); + } + + @Override + public void sendFullTextEmail(String title, String html, String[] toEmails) throws MessagingException { + if (mailSender == null) { + System.out.println("邮件服务未配置,跳过发送邮件: " + title); + return; + } + MimeMessage mimeMessage = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); + helper.setFrom(formEmail); + helper.setTo(toEmails); + helper.setSubject(title); + // 发送邮件 + helper.setText(html, true); + mailSender.send(mimeMessage); + } + + @Override + public void sendHtmlEmail(String title, String path, Map map, String[] toEmails) + throws MessagingException, IOException { + ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("templates/"); + Configuration cfg = Configuration.defaultConfiguration(); + GroupTemplate gt = new GroupTemplate(resourceLoader, cfg); + Template t = gt.getTemplate(path); // 加载html模板 + t.binding(map); // 填充数据 + String html = t.render(); // 获得渲染后的html + sendFullTextEmail(title, html, toEmails); // 发送邮件 + } + + @Async + @Override + public void sendEmail(String title, String content, String receiver) { + // 发送邮件通知 + EmailRecord emailRecord = new EmailRecord(); + emailRecord.setTitle(title); + emailRecord.setContent(content); + emailRecord.setReceiver(receiver); + emailRecord.setCreateUserId(42); + if (mailSender != null) { + sendTextEmail(title,content,receiver.split(",")); + } else { + System.out.println("邮件服务未配置,跳过发送邮件: " + title); + } + save(emailRecord); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/EnvironmentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/EnvironmentServiceImpl.java new file mode 100644 index 0000000..c4996a5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/EnvironmentServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.EnvironmentMapper; +import com.gxwebsoft.common.system.service.EnvironmentService; +import com.gxwebsoft.common.system.entity.Environment; +import com.gxwebsoft.common.system.param.EnvironmentParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 环境管理Service实现 + * + * @author 科技小王子 + * @since 2023-10-18 08:45:13 + */ +@Service +public class EnvironmentServiceImpl extends ServiceImpl implements EnvironmentService { + + @Override + public PageResult pageRel(EnvironmentParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(EnvironmentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Environment getByIdRel(Integer id) { + EnvironmentParam param = new EnvironmentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/FileRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/FileRecordServiceImpl.java new file mode 100644 index 0000000..72c9c27 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/FileRecordServiceImpl.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.common.system.mapper.FileRecordMapper; +import com.gxwebsoft.common.system.param.FileRecordParam; +import com.gxwebsoft.common.system.service.FileRecordService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.util.List; + +/** + * 文件上传记录Service实现 + * + * @author WebSoft + * @since 2021-08-30 11:21:01 + */ +@Service +public class FileRecordServiceImpl extends ServiceImpl implements FileRecordService { + + @Override + public PageResult pageRel(FileRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(FileRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public FileRecord getByIdRel(Integer id) { + FileRecordParam param = new FileRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public FileRecord getByIdPath(String path) { + return CommonUtil.listGetOne(baseMapper.getByIdPath(path)); + } + + @Async + @Override + public void deleteFileAsync(List files) { + for (File file : files) { + try { + file.delete(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/LoginRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/LoginRecordServiceImpl.java new file mode 100644 index 0000000..28497e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/LoginRecordServiceImpl.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.common.system.service.impl; + +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.LoginRecord; +import com.gxwebsoft.common.system.mapper.LoginRecordMapper; +import com.gxwebsoft.common.system.param.LoginRecordParam; +import com.gxwebsoft.common.system.service.LoginRecordService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 登录日志Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:14 + */ +@Service +public class LoginRecordServiceImpl extends ServiceImpl + implements LoginRecordService { + + @Override + public PageResult pageRel(LoginRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(LoginRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public LoginRecord getByIdRel(Integer id) { + LoginRecordParam param = new LoginRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Async + @Override + public void saveAsync(String username, Integer type, String comments, Integer tenantId, + HttpServletRequest request) { + if (username == null) { + return; + } + LoginRecord loginRecord = new LoginRecord(); + loginRecord.setUsername(username); + loginRecord.setLoginType(type); + loginRecord.setComments(comments); + loginRecord.setTenantId(tenantId); + UserAgent ua = UserAgentUtil.parse(ServletUtil.getHeaderIgnoreCase(request, "User-Agent")); + if (ua != null) { + if (ua.getPlatform() != null) { + loginRecord.setOs(ua.getPlatform().toString()); + } + if (ua.getOs() != null) { + loginRecord.setDevice(ua.getOs().toString()); + } + if (ua.getBrowser() != null) { + loginRecord.setBrowser(ua.getBrowser().toString()); + } + } + loginRecord.setIp(ServletUtil.getClientIP(request)); + baseMapper.insert(loginRecord); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MenuServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..969aee3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MenuServiceImpl.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.mapper.MenuMapper; +import com.gxwebsoft.common.system.param.MenuParam; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import com.gxwebsoft.common.system.service.RoleService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 菜单Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:10 + */ +@Service +public class MenuServiceImpl extends ServiceImpl implements MenuService { + private Integer plugMenuId; + @Resource + private RoleService roleService; + @Resource + private RoleMenuService roleMenuService; + + @Override + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + public Boolean cloneMenu(MenuParam param) { +// System.out.println("准备待克隆的菜单数据 = " + param); + // 删除本项目菜单 + baseMapper.delete(new LambdaQueryWrapper().eq(Menu::getDeleted,0)); + // 顶级栏目 + param.setParentId(0); +// final List list = baseMapper.getMenuByClone(param); +//// final List menuIds = list.stream().map(Menu::getMenuId).collect(Collectors.toList()); + doCloneMenu(baseMapper.getMenuByClone(param)); + return true; + } + + @Override + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + public Boolean install(Integer id) { + // 1.插件绑定的菜单ID + final MenuParam param = new MenuParam(); + param.setMenuId(id); + final List list = baseMapper.getMenuByClone(param); + // TODO 克隆当前插件到顶级菜单 + doCloneMenu(list); + + // 2.查找当前租户的超管权限的roleId + final Role superAdmin = roleService.getOne(new LambdaQueryWrapper().eq(Role::getRoleCode, "superAdmin")); + final Integer roleId = superAdmin.getRoleId(); + final Integer tenantId = superAdmin.getTenantId(); + // 3.勾选菜单根权限 + final RoleMenu roleMenu0 = new RoleMenu(); + roleMenu0.setRoleId(roleId); + roleMenu0.setMenuId(this.plugMenuId); + roleMenuService.save(roleMenu0); + + // 4.勾选根节点下的子菜单权限 + final MenuParam menuParam = new MenuParam(); + menuParam.setParentId(this.plugMenuId); + menuParam.setTenantId(tenantId); + final List menuList = baseMapper.getMenuByClone(menuParam); + menuList.forEach(d->{ + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(d.getMenuId()); + roleMenuService.save(roleMenu); + }); + // 5.调整新插件的排序 + final Menu menu = baseMapper.selectById(this.plugMenuId); + menu.setSortNumber(100); + baseMapper.updateById(menu); + return true; + } + + // 克隆菜单 + private void doCloneMenu(List list) { + final MenuParam param = new MenuParam(); + list.forEach(d -> { + Menu menu = new Menu(); + menu.setParentId(0); + menu.setTitle(d.getTitle()); + menu.setPath(d.getPath()); + menu.setComponent(d.getComponent()); + menu.setMenuType(d.getMenuType()); + menu.setSortNumber(d.getSortNumber()); + menu.setAuthority(d.getAuthority()); + menu.setIcon(d.getIcon()); + menu.setHide(d.getHide()); + menu.setMeta(d.getMeta()); + save(menu); + this.plugMenuId = menu.getMenuId(); + // 二级菜单 + param.setParentId(d.getMenuId()); + final List list1 = baseMapper.getMenuByClone(param); + list1.forEach(d1 -> { + final Menu menu1 = new Menu(); + menu1.setParentId(menu.getMenuId()); + menu1.setTitle(d1.getTitle()); + menu1.setPath(d1.getPath()); + menu1.setComponent(d1.getComponent()); + menu1.setMenuType(d1.getMenuType()); + menu1.setSortNumber(d1.getSortNumber()); + menu1.setAuthority(d1.getAuthority()); + menu1.setIcon(d1.getIcon()); + menu1.setHide(d1.getHide()); + menu1.setMeta(d1.getMeta()); + save(menu1); + // 三级菜单 + param.setParentId(d1.getMenuId()); + final List list2 = baseMapper.getMenuByClone(param); + list2.forEach(d2 -> { + final Menu menu2 = new Menu(); + menu2.setParentId(menu1.getMenuId()); + menu2.setTitle(d2.getTitle()); + menu2.setPath(d2.getPath()); + menu2.setComponent(d2.getComponent()); + menu2.setMenuType(d2.getMenuType()); + menu2.setSortNumber(d2.getSortNumber()); + menu2.setAuthority(d2.getAuthority()); + menu2.setIcon(d2.getIcon()); + menu2.setHide(d2.getHide()); + menu2.setMeta(d2.getMeta()); + save(menu2); + }); + }); + }); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantAccountServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantAccountServiceImpl.java new file mode 100644 index 0000000..b867e49 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantAccountServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.MerchantAccount; +import com.gxwebsoft.common.system.mapper.MerchantAccountMapper; +import com.gxwebsoft.common.system.param.MerchantAccountParam; +import com.gxwebsoft.common.system.service.MerchantAccountService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户账号Service实现 + * + * @author 科技小王子 + * @since 2024-04-19 12:02:24 + */ +@Service +public class MerchantAccountServiceImpl extends ServiceImpl implements MerchantAccountService { + + @Override + public PageResult pageRel(MerchantAccountParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(MerchantAccountParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public MerchantAccount getByIdRel(Integer id) { + MerchantAccountParam param = new MerchantAccountParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantApplyServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantApplyServiceImpl.java new file mode 100644 index 0000000..ee77354 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantApplyServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.MerchantApply; +import com.gxwebsoft.common.system.mapper.MerchantApplyMapper; +import com.gxwebsoft.common.system.param.MerchantApplyParam; +import com.gxwebsoft.common.system.service.MerchantApplyService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户入驻申请Service实现 + * + * @author 科技小王子 + * @since 2024-04-05 01:24:36 + */ +@Service +public class MerchantApplyServiceImpl extends ServiceImpl implements MerchantApplyService { + + @Override + public PageResult pageRel(MerchantApplyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(MerchantApplyParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public MerchantApply getByIdRel(Integer applyId) { + MerchantApplyParam param = new MerchantApplyParam(); + param.setApplyId(applyId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantServiceImpl.java new file mode 100644 index 0000000..1511e90 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Merchant; +import com.gxwebsoft.common.system.mapper.MerchantMapper; +import com.gxwebsoft.common.system.param.MerchantParam; +import com.gxwebsoft.common.system.service.MerchantService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户Service实现 + * + * @author 科技小王子 + * @since 2024-04-05 00:03:54 + */ +@Service +public class MerchantServiceImpl extends ServiceImpl implements MerchantService { + + @Override + public PageResult pageRel(MerchantParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(MerchantParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public Merchant getByIdRel(Long merchantId) { + MerchantParam param = new MerchantParam(); + param.setMerchantId(merchantId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantTypeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantTypeServiceImpl.java new file mode 100644 index 0000000..ef57df7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/MerchantTypeServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.MerchantType; +import com.gxwebsoft.common.system.mapper.MerchantTypeMapper; +import com.gxwebsoft.common.system.param.MerchantTypeParam; +import com.gxwebsoft.common.system.service.MerchantTypeService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户类型Service实现 + * + * @author 科技小王子 + * @since 2024-04-05 00:08:51 + */ +@Service +public class MerchantTypeServiceImpl extends ServiceImpl implements MerchantTypeService { + + @Override + public PageResult pageRel(MerchantTypeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(MerchantTypeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public MerchantType getByIdRel(Integer id) { + MerchantTypeParam param = new MerchantTypeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ModulesServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ModulesServiceImpl.java new file mode 100644 index 0000000..37e1b44 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/ModulesServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.ModulesMapper; +import com.gxwebsoft.common.system.service.ModulesService; +import com.gxwebsoft.common.system.entity.Modules; +import com.gxwebsoft.common.system.param.ModulesParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 模块管理Service实现 + * + * @author 科技小王子 + * @since 2023-10-18 15:53:43 + */ +@Service +public class ModulesServiceImpl extends ServiceImpl implements ModulesService { + + @Override + public PageResult pageRel(ModulesParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ModulesParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Modules getByIdRel(Integer id) { + ModulesParam param = new ModulesParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/NoticeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/NoticeServiceImpl.java new file mode 100644 index 0000000..b4b534c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/NoticeServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.NoticeMapper; +import com.gxwebsoft.common.system.service.NoticeService; +import com.gxwebsoft.common.system.entity.Notice; +import com.gxwebsoft.common.system.param.NoticeParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 消息记录表Service实现 + * + * @author 科技小王子 + * @since 2023-10-08 13:22:21 + */ +@Service +public class NoticeServiceImpl extends ServiceImpl implements NoticeService { + + @Override + public PageResult pageRel(NoticeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(NoticeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Notice getByIdRel(Integer noticeId) { + NoticeParam param = new NoticeParam(); + param.setNoticeId(noticeId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OperationRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OperationRecordServiceImpl.java new file mode 100644 index 0000000..8095bf4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OperationRecordServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OperationRecord; +import com.gxwebsoft.common.system.mapper.OperationRecordMapper; +import com.gxwebsoft.common.system.param.OperationRecordParam; +import com.gxwebsoft.common.system.service.OperationRecordService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 操作日志Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:02 + */ +@Service +public class OperationRecordServiceImpl extends ServiceImpl + implements OperationRecordService { + + @Override + public PageResult pageRel(OperationRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(OperationRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public OperationRecord getByIdRel(Integer id) { + OperationRecordParam param = new OperationRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Async + @Override + public void saveAsync(OperationRecord operationRecord) { + baseMapper.insert(operationRecord); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderGoodsServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderGoodsServiceImpl.java new file mode 100644 index 0000000..a3c26dd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderGoodsServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.OrderGoods; +import com.gxwebsoft.common.system.mapper.OrderGoodsMapper; +import com.gxwebsoft.common.system.param.OrderGoodsParam; +import com.gxwebsoft.common.system.service.OrderGoodsService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 订单商品Service实现 + * + * @author 科技小王子 + * @since 2024-10-26 12:18:05 + */ +@Service +public class OrderGoodsServiceImpl extends ServiceImpl implements OrderGoodsService { + + @Override + public PageResult pageRel(OrderGoodsParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(OrderGoodsParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public OrderGoods getByIdRel(Integer id) { + OrderGoodsParam param = new OrderGoodsParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderInfoServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderInfoServiceImpl.java new file mode 100644 index 0000000..fd065f9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderInfoServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.OrderInfoMapper; +import com.gxwebsoft.common.system.service.OrderInfoService; +import com.gxwebsoft.common.system.entity.OrderInfo; +import com.gxwebsoft.common.system.param.OrderInfoParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * Service实现 + * + * @author 科技小王子 + * @since 2024-05-10 18:02:54 + */ +@Service +public class OrderInfoServiceImpl extends ServiceImpl implements OrderInfoService { + + @Override + public PageResult pageRel(OrderInfoParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(OrderInfoParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public OrderInfo getByIdRel(Integer id) { + OrderInfoParam param = new OrderInfoParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderServiceImpl.java new file mode 100644 index 0000000..60b66da --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrderServiceImpl.java @@ -0,0 +1,105 @@ +package com.gxwebsoft.common.system.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.entity.Order; +import com.gxwebsoft.common.system.entity.OrderGoods; +import com.gxwebsoft.common.system.mapper.OrderMapper; +import com.gxwebsoft.common.system.param.OrderParam; +import com.gxwebsoft.common.system.service.CompanyService; +import com.gxwebsoft.common.system.service.MenuService; +import com.gxwebsoft.common.system.service.OrderGoodsService; +import com.gxwebsoft.common.system.service.OrderService; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 订单Service实现 + * + * @author 科技小王子 + * @since 2024-10-16 12:32:52 + */ +@Service +public class OrderServiceImpl extends ServiceImpl implements OrderService { + @Resource + private MenuService menuService; + @Resource + private OrderGoodsService orderGoodsService; + @Resource + private CompanyService companyService; + + @Override + public PageResult pageRel(OrderParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + if (param.getSceneType() != null && ObjectUtil.isNotEmpty(param.getSceneType().equals("showOrderGoods"))) { + list.forEach(d -> { + d.setOrderGoods(orderGoodsService.list(new LambdaQueryWrapper().eq(OrderGoods::getOrderId, d.getOrderId()))); + }); + } + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(OrderParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Order getByIdRel(Integer orderId) { + OrderParam param = new OrderParam(); + param.setOrderId(orderId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public void paySuccess(Order order) { + System.out.println("order = " + order); + // 安装插件 + menuService.cloneMenu(order.getMenuParam()); + order.setPayStatus(true); + // 实际支付金额 + if (order.getPayType().equals(0)) { + order.setPayPrice(order.getPayPrice()); + } + order.setPayTime(DateUtil.date()); + order.setStartTime(System.currentTimeMillis()); + order.setExpirationTime(DateUtil.offsetMonth(DateUtil.date(), order.getMonth())); + updateById(order); +// orderGoodsService.update(new LambdaUpdateWrapper().eq(OrderGoods::getOrderId, order.getOrderId()) +// .set(OrderGoods::getPayStatus, 1) +// .set(OrderGoods::getPayTime, DateUtil.date()) +// .set(OrderGoods::getExpirationTime, DateUtil.offsetMonth(DateUtil.date(), order.getMonth())) +// ); + + final List list = orderGoodsService.list(new LambdaQueryWrapper().eq(OrderGoods::getOrderId, order.getOrderId())); + if (!CollectionUtils.isEmpty(list)) { + list.forEach(d -> { + d.setPayStatus(true); + d.setPayTime(DateUtil.date()); + d.setExpirationTime(DateUtil.offsetMonth(DateUtil.date(), order.getMonth())); + }); + // 更新订单商品状态 + orderGoodsService.updateBatchById(list); + // 累计销量 + Company company = companyService.getById(list.get(0).getItemId()); + company.setBuys(company.getBuys() + list.size()); + System.out.println("company = " + company); + companyService.updateById(company); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrganizationServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrganizationServiceImpl.java new file mode 100644 index 0000000..b2bb53f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/OrganizationServiceImpl.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Organization; +import com.gxwebsoft.common.system.mapper.OrganizationMapper; +import com.gxwebsoft.common.system.param.OrganizationParam; +import com.gxwebsoft.common.system.service.OrganizationService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 组织机构Service实现 + * + * @author WebSoft + * @since 2020-03-14 11:29:04 + */ +@Service +public class OrganizationServiceImpl extends ServiceImpl + implements OrganizationService { + + @Override + public PageResult pageRel(OrganizationParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return new PageResult<>(baseMapper.selectPageRel(page, param), page.getTotal()); + } + + @Override + public List listRel(OrganizationParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number"); + return page.sortRecords(baseMapper.selectListRel(param)); + } + + @Override + public Organization getByIdRel(Integer organizationId) { + OrganizationParam param = new OrganizationParam(); + param.setOrganizationId(organizationId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/PaymentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/PaymentServiceImpl.java new file mode 100644 index 0000000..9e2d798 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/PaymentServiceImpl.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.mapper.PaymentMapper; +import com.gxwebsoft.common.system.param.PaymentParam; +import com.gxwebsoft.common.system.service.PaymentService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 支付方式Service实现 + * + * @author 科技小王子 + * @since 2024-05-11 12:39:11 + */ +@Service +public class PaymentServiceImpl extends ServiceImpl implements PaymentService { + + @Override + public PageResult pageRel(PaymentParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(PaymentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Payment getByIdRel(Integer id) { + PaymentParam param = new PaymentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public Payment getByType(PaymentParam paymentParam) { + return baseMapper.getByType(paymentParam); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/PlugServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/PlugServiceImpl.java new file mode 100644 index 0000000..aee07a6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/PlugServiceImpl.java @@ -0,0 +1,112 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Plug; +import com.gxwebsoft.common.system.mapper.PlugMapper; +import com.gxwebsoft.common.system.param.PlugParam; +import com.gxwebsoft.common.system.service.PlugService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 插件扩展Service实现 + * + * @author 科技小王子 + * @since 2023-05-18 11:57:37 + */ +@Service +public class PlugServiceImpl extends ServiceImpl implements PlugService { + + @Override + public PageResult pageRel(PlugParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(PlugParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Plug getByIdRel(Integer menuId) { + PlugParam param = new PlugParam(); + param.setMenuId(menuId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + public Boolean cloneMenu(PlugParam param) { +// System.out.println("准备待克隆的菜单数据 = " + param); + // 删除本项目菜单 + baseMapper.delete(new LambdaQueryWrapper().eq(Plug::getDeleted,0)); + // 顶级栏目 + param.setParentId(0); + final List list = baseMapper.getMenuByClone(param); +// final List menuIds = list.stream().map(Menu::getMenuId).collect(Collectors.toList()); + + list.forEach(d -> { + Plug plug = new Plug(); + plug.setParentId(0); + plug.setTitle(d.getTitle()); + plug.setPath(d.getPath()); + plug.setComponent(d.getComponent()); + plug.setMenuType(d.getMenuType()); + plug.setSortNumber(d.getSortNumber()); + plug.setAuthority(d.getAuthority()); + plug.setIcon(d.getIcon()); + plug.setHide(d.getHide()); + plug.setMeta(d.getMeta()); + save(plug); + // 二级菜单 + param.setParentId(d.getMenuId()); + final List list1 = baseMapper.getMenuByClone(param); + list1.forEach(d1 -> { + final Plug menu1 = new Plug(); + menu1.setParentId(plug.getMenuId()); + menu1.setTitle(d1.getTitle()); + menu1.setPath(d1.getPath()); + menu1.setComponent(d1.getComponent()); + menu1.setMenuType(d1.getMenuType()); + menu1.setSortNumber(d1.getSortNumber()); + menu1.setAuthority(d1.getAuthority()); + menu1.setIcon(d1.getIcon()); + menu1.setHide(d1.getHide()); + menu1.setMeta(d1.getMeta()); + save(menu1); + // 三级菜单 + param.setParentId(d1.getMenuId()); + final List list2 = baseMapper.getMenuByClone(param); + list2.forEach(d2 -> { + final Plug menu2 = new Plug(); + menu2.setParentId(menu1.getMenuId()); + menu2.setTitle(d2.getTitle()); + menu2.setPath(d2.getPath()); + menu2.setComponent(d2.getComponent()); + menu2.setMenuType(d2.getMenuType()); + menu2.setSortNumber(d2.getSortNumber()); + menu2.setAuthority(d2.getAuthority()); + menu2.setIcon(d2.getIcon()); + menu2.setHide(d2.getHide()); + menu2.setMeta(d2.getMeta()); + save(menu2); + }); + }); + }); + return true; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RechargeOrderServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RechargeOrderServiceImpl.java new file mode 100644 index 0000000..c4d2c64 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RechargeOrderServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.RechargeOrder; +import com.gxwebsoft.common.system.mapper.RechargeOrderMapper; +import com.gxwebsoft.common.system.param.RechargeOrderParam; +import com.gxwebsoft.common.system.service.RechargeOrderService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 会员充值订单表Service实现 + * + * @author 科技小王子 + * @since 2024-07-26 23:18:48 + */ +@Service +public class RechargeOrderServiceImpl extends ServiceImpl implements RechargeOrderService { + + @Override + public PageResult pageRel(RechargeOrderParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(RechargeOrderParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public RechargeOrder getByIdRel(Integer orderId) { + RechargeOrderParam param = new RechargeOrderParam(); + param.setOrderId(orderId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RoleMenuServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RoleMenuServiceImpl.java new file mode 100644 index 0000000..737c5e3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RoleMenuServiceImpl.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Menu; +import com.gxwebsoft.common.system.entity.RoleMenu; +import com.gxwebsoft.common.system.mapper.RoleMenuMapper; +import com.gxwebsoft.common.system.service.RoleMenuService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 角色菜单Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:12 + */ +@Service +public class RoleMenuServiceImpl extends ServiceImpl implements RoleMenuService { + + @Override + public List listMenuByUserId(Integer userId, Integer menuType) { + return baseMapper.listMenuByUserId(userId, menuType); + } + + @Override + public List listMenuByRoleIds(List roleIds, Integer menuType) { + return baseMapper.listMenuByRoleIds(roleIds, menuType); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RoleServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..3632c03 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/RoleServiceImpl.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.mapper.RoleMapper; +import com.gxwebsoft.common.system.param.RoleParam; +import com.gxwebsoft.common.system.service.RoleService; +import org.springframework.stereotype.Service; + +/** + * 角色服务实现类 + * + * @author WebSoft + * @since 2018-12-24 16:10:11 + */ +@Service +public class RoleServiceImpl extends ServiceImpl implements RoleService { + + @Override + public Role getByRoleCode(RoleParam param) { + if (param == null || param.getRoleCode() == null) { + return null; + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Role::getRoleCode, param.getRoleCode()); + return baseMapper.selectOne(wrapper); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/SettingServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/SettingServiceImpl.java new file mode 100644 index 0000000..ab8ed3c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/SettingServiceImpl.java @@ -0,0 +1,189 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.annotation.IgnoreTenant; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Setting; +import com.gxwebsoft.common.system.mapper.SettingMapper; +import com.gxwebsoft.common.system.param.SettingParam; +import com.gxwebsoft.common.system.service.SettingService; +import com.gxwebsoft.cms.entity.CmsWebsiteField; +import com.gxwebsoft.cms.service.CmsWebsiteFieldService; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAConfig; +import com.wechat.pay.java.service.payments.jsapi.JsapiService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 系统设置Service实现 + * + * @author WebSoft + * @since 2022-11-19 13:54:27 + */ +@Service +public class SettingServiceImpl extends ServiceImpl implements SettingService { + // 本地缓存 + public static Map configMap = new HashMap<>(); + public static JsapiService service = null; + public static Config config = null; + @Resource + private ConfigProperties pathConfig; + @Resource + private StringRedisTemplate stringRedisTemplate; + @Resource + private CmsWebsiteFieldService cmsWebsiteFieldService; + + @Value("${spring.profiles.active:prod}") + private String activeProfile; + + @Override + public PageResult pageRel(SettingParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(SettingParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Setting getByIdRel(Integer settingId) { + SettingParam param = new SettingParam(); + param.setSettingId(settingId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public JSONObject getBySettingKey(String key, Integer tenantId) { + Setting setting = this.getOne(new QueryWrapper().eq("setting_key", key), false); + if (setting == null) { + if ("mp-weixin".equals(key) || "platform_miniprogram".equals(key)) { + throw new BusinessException("小程序未配置"); + } + if ("payment".equals(key)) { + throw new BusinessException("支付未配置"); + } + if ("sms".equals(key)) { + throw new BusinessException("短信未配置"); + } + if ("wx-work".equals(key)) { + throw new BusinessException("企业微信未配置"); + } + if ("setting".equals(key)) { + throw new BusinessException("基本信息未配置"); + } + if ("wx-official".equals(key)) { + throw new BusinessException("微信公众号未配置"); + } + if ("printer".equals(key)) { + throw new BusinessException("打印机未配置"); + } + return null; + } + return JSON.parseObject(setting.getContent()); + } + + @Override + @IgnoreTenant("跨租户获取指定租户的设置配置") + public JSONObject getBySettingKeyIgnoreTenant(String key, Integer tenantId) { + throw new BusinessException("此方法已废弃,请使用缓存方式获取配置:mp-weixin:" + tenantId); + } + + @Override + public Setting getData(String settingKey) { + return query().eq("setting_key", settingKey).one(); + } + + @Override + public JSONObject getCache(String key) { + final String cache = stringRedisTemplate.opsForValue().get(key); + final JSONObject jsonObject = JSONObject.parseObject(cache); + if(jsonObject == null){ + throw new BusinessException("域名未配置"); + } + return jsonObject; + } + + @Override + public void initConfig(Setting data) { + if (data.getSettingKey().equals("payment")) { + final JSONObject jsonObject = JSONObject.parseObject(data.getContent()); + final String mchId = jsonObject.getString("mchId"); + final String apiclientKey = jsonObject.getString("apiclientKey"); + final String privateKey = pathConfig.getUploadPath().concat(apiclientKey); + final String apiclientCert = pathConfig.getUploadPath().concat(jsonObject.getString("apiclientCert")); + final String merchantSerialNumber = jsonObject.getString("merchantSerialNumber"); + final String apiV3key = jsonObject.getString("wechatApiKey"); + if(config == null){ + // 根据环境选择不同的证书路径配置 + if ("dev".equals(activeProfile)) { + // 开发环境:使用 websopy 平台证书路径 + System.out.println("=== 开发环境:使用 websopy 平台证书路径 ==="); + String certBasePath = "/Users/gxwebsoft/JAVA/websopy-java/src/main/resources/wechat/websopy/"; + String devPrivateKeyPath = certBasePath + "apiclient_key.pem"; + String devCertPath = certBasePath + "pub_key.pem"; + + System.out.println("证书基础路径: " + certBasePath); + System.out.println("私钥文件路径: " + devPrivateKeyPath); + System.out.println("证书文件路径: " + devCertPath); + + config = new RSAConfig.Builder() + .merchantId("1557418831") + .privateKeyFromPath(devPrivateKeyPath) + .merchantSerialNumber("372B29641147684184C840587F38053033F4A5A8") + .wechatPayCertificatesFromPath(devCertPath) + .build(); + System.out.println("开发环境证书路径配置完成"); + } else { + // 生产环境:使用数据库存储的路径 + System.out.println("=== 生产环境:使用数据库存储的证书路径 ==="); + config = new RSAConfig.Builder() + .merchantId(mchId) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(merchantSerialNumber) + .wechatPayCertificatesFromPath(apiclientCert) + .build(); + System.out.println("生产环境证书路径: " + privateKey); + } + configMap.put(data.getTenantId().toString(),config); + System.out.println("当前环境: " + activeProfile); + System.out.println("config = " + config); + } + if (service == null) { + service = new JsapiService.Builder().config(config).build(); + } + } + } + + @Override + public Config getConfig(Integer tenantId) { + if(configMap.get(tenantId.toString()) == null){ + final Setting payment = getOne(new LambdaQueryWrapper().eq(Setting::getSettingKey, "payment")); + this.initConfig(payment); + return configMap.get(tenantId.toString()); + } + return configMap.get(tenantId.toString()); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/SysFileTypeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/SysFileTypeServiceImpl.java new file mode 100644 index 0000000..6724f17 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/SysFileTypeServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.SysFileType; +import com.gxwebsoft.common.system.mapper.SysFileTypeMapper; +import com.gxwebsoft.common.system.param.SysFileTypeParam; +import com.gxwebsoft.common.system.service.SysFileTypeService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 存储类型Service实现 + * + * @author 科技小王子 + * @since 2025-05-16 14:24:28 + */ +@Service +public class SysFileTypeServiceImpl extends ServiceImpl implements SysFileTypeService { + + @Override + public PageResult pageRel(SysFileTypeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(SysFileTypeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public SysFileType getByIdRel(Integer id) { + SysFileTypeParam param = new SysFileTypeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantPackageServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantPackageServiceImpl.java new file mode 100644 index 0000000..d89f1f9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantPackageServiceImpl.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.entity.TenantPackage; +import com.gxwebsoft.common.system.mapper.TenantPackageMapper; +import com.gxwebsoft.common.system.service.TenantPackageService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 租户套餐ServiceImpl + * + * @author WebSoft + * @since 2025-12-12 + */ +@Service +public class TenantPackageServiceImpl extends ServiceImpl implements TenantPackageService { + + @Override + public List listAvailablePackages() { + return baseMapper.selectAvailablePackages(); + } + + @Override + public TenantPackage getByVersion(Integer version) { + return baseMapper.selectByVersion(version); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java new file mode 100644 index 0000000..4af0719 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantServiceImpl.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.mapper.TenantMapper; +import com.gxwebsoft.common.system.service.TenantService; +import com.gxwebsoft.common.system.service.UserService; +import com.gxwebsoft.common.system.entity.Tenant; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.param.TenantParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 租户Service实现 + * + * @author 科技小王子 + * @since 2023-07-17 17:49:53 + */ +@Service +public class TenantServiceImpl extends ServiceImpl implements TenantService { + + @Resource + private UserService userService; + + @Override + public PageResult pageRel(TenantParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(TenantParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Tenant getByIdRel(Integer tenantId) { + TenantParam param = new TenantParam(); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean transferOwner(Integer tenantId, Integer newUserId) { + // 校验租户存在 + Tenant tenant = baseMapper.selectById(tenantId); + if (tenant == null) { + throw new BusinessException("租户不存在"); + } + // 校验新用户存在 + User newUser = userService.getByIdIgnoreTenant(newUserId); + if (newUser == null) { + throw new BusinessException("目标用户不存在"); + } + // 更新租户归属 + Tenant update = new Tenant(); + update.setTenantId(tenantId); + update.setUserId(newUserId); + return baseMapper.updateById(update) > 0; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantSubscriptionOrderServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantSubscriptionOrderServiceImpl.java new file mode 100644 index 0000000..0ab00c4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantSubscriptionOrderServiceImpl.java @@ -0,0 +1,230 @@ +package com.gxwebsoft.common.system.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.TenantPackage; +import com.gxwebsoft.common.system.entity.TenantSubscriptionOrder; +import com.gxwebsoft.common.system.mapper.TenantSubscriptionOrderMapper; +import com.gxwebsoft.common.system.service.TenantPackageService; +import com.gxwebsoft.common.system.service.TenantSubscriptionOrderService; +import com.gxwebsoft.common.system.service.TenantSubscriptionService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 租户订阅订单ServiceImpl + * + * @author WebSoft + * @since 2025-12-12 + */ +@Service +public class TenantSubscriptionOrderServiceImpl extends ServiceImpl implements TenantSubscriptionOrderService { + + @Resource + private TenantPackageService tenantPackageService; + + @Resource + private TenantSubscriptionService tenantSubscriptionService; + + @Override + @Transactional(rollbackFor = Exception.class) + public TenantSubscriptionOrder createOrder(Integer packageId, Integer payType, Integer tenantId, Integer userId) { + // 查询套餐信息 + TenantPackage tenantPackage = tenantPackageService.getById(packageId); + if (tenantPackage == null) { + throw new BusinessException("套餐不存在"); + } + if (tenantPackage.getStatus() != 1) { + throw new BusinessException("套餐已下架"); + } + + // 计算价格 + BigDecimal price; + if (payType == 1) { + price = tenantPackage.getPriceMonthly(); + } else if (payType == 3) { + price = tenantPackage.getPriceQuarterly(); + } else if (payType == 12) { + price = tenantPackage.getPriceYearly(); + } else { + throw new BusinessException("支付周期不正确"); + } + + // 创建订单 + TenantSubscriptionOrder order = new TenantSubscriptionOrder(); + order.setOrderNo(generateOrderNo()); + order.setTenantId(tenantId); + order.setPackageId(packageId); + order.setPackageName(tenantPackage.getPackageName()); + order.setVersion(tenantPackage.getVersion()); + order.setPayType(payType); + order.setOriginalPrice(price); + order.setDiscountPrice(BigDecimal.ZERO); + order.setActualPrice(price); + order.setIsTrial(0); + order.setIsRenewal(0); + order.setIsUpgrade(0); + order.setOrderStatus(0); // 待支付 + order.setUserId(userId); + order.setCreateTime(new Date()); + + save(order); + return order; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public TenantSubscriptionOrder createTrialOrder(Integer tenantId, Integer userId) { + // 查询试用套餐(version=0) + TenantPackage trialPackage = tenantPackageService.getByVersion(0); + if (trialPackage == null) { + throw new BusinessException("试用套餐不存在"); + } + + // 检查是否已经试用过 + long count = count(new LambdaQueryWrapper() + .eq(TenantSubscriptionOrder::getTenantId, tenantId) + .eq(TenantSubscriptionOrder::getIsTrial, 1)); + if (count > 0) { + throw new BusinessException("已经使用过试用版"); + } + + // 创建试用订单 + TenantSubscriptionOrder order = new TenantSubscriptionOrder(); + order.setOrderNo(generateOrderNo()); + order.setTenantId(tenantId); + order.setPackageId(trialPackage.getPackageId()); + order.setPackageName(trialPackage.getPackageName()); + order.setVersion(trialPackage.getVersion()); + order.setPayType(0); + order.setOriginalPrice(BigDecimal.ZERO); + order.setDiscountPrice(BigDecimal.ZERO); + order.setActualPrice(BigDecimal.ZERO); + order.setStartTime(new Date()); + order.setEndTime(DateUtil.offsetDay(new Date(), trialPackage.getTrialDays())); + order.setIsTrial(1); + order.setIsRenewal(0); + order.setIsUpgrade(0); + order.setOrderStatus(2); // 直接激活 + order.setUserId(userId); + order.setCreateTime(new Date()); + + save(order); + + // 创建订阅记录 + tenantSubscriptionService.createOrUpdateSubscription( + tenantId, + trialPackage.getPackageId(), + trialPackage.getVersion(), + order.getStartTime(), + order.getEndTime(), + 1 + ); + + return order; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean payOrder(String orderNo, String paymentMethod, String paymentId) { + TenantSubscriptionOrder order = getByOrderNo(orderNo); + if (order == null) { + throw new BusinessException("订单不存在"); + } + if (order.getOrderStatus() != 0) { + throw new BusinessException("订单状态不正确"); + } + + order.setPaymentMethod(paymentMethod); + order.setPaymentId(paymentId); + order.setPaymentTime(new Date()); + order.setOrderStatus(1); // 已支付 + order.setUpdateTime(new Date()); + + return updateById(order); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean activateOrder(String orderNo) { + TenantSubscriptionOrder order = getByOrderNo(orderNo); + if (order == null) { + throw new BusinessException("订单不存在"); + } + if (order.getOrderStatus() != 1) { + throw new BusinessException("订单未支付"); + } + + // 计算开始和结束时间 + Date startTime = new Date(); + Date endTime = DateUtil.offsetMonth(startTime, order.getPayType()); + + order.setStartTime(startTime); + order.setEndTime(endTime); + order.setOrderStatus(2); // 已激活 + order.setUpdateTime(new Date()); + + boolean updated = updateById(order); + + if (updated) { + // 创建或更新订阅记录 + tenantSubscriptionService.createOrUpdateSubscription( + order.getTenantId(), + order.getPackageId(), + order.getVersion(), + startTime, + endTime, + 0 + ); + } + + return updated; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelOrder(String orderNo, String cancelReason) { + TenantSubscriptionOrder order = getByOrderNo(orderNo); + if (order == null) { + throw new BusinessException("订单不存在"); + } + if (order.getOrderStatus() != 0) { + throw new BusinessException("只能取消待支付订单"); + } + + order.setOrderStatus(3); // 已取消 + order.setCancelReason(cancelReason); + order.setUpdateTime(new Date()); + + return updateById(order); + } + + @Override + public PageResult pageByTenant(Integer tenantId, Integer page, Integer limit) { + IPage iPage = new Page<>(page, limit); + baseMapper.selectPageByTenant(iPage, tenantId); + return new PageResult(iPage.getRecords(), iPage.getTotal()); + } + + @Override + public TenantSubscriptionOrder getByOrderNo(String orderNo) { + return baseMapper.selectByOrderNo(orderNo); + } + + /** + * 生成订单号 + */ + private String generateOrderNo() { + return "SUB" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + IdUtil.randomUUID().substring(0, 6).toUpperCase(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantSubscriptionServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantSubscriptionServiceImpl.java new file mode 100644 index 0000000..9a5e1f4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/TenantSubscriptionServiceImpl.java @@ -0,0 +1,188 @@ +package com.gxwebsoft.common.system.service.impl; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.entity.TenantPackage; +import com.gxwebsoft.common.system.entity.TenantSubscription; +import com.gxwebsoft.common.system.mapper.TenantSubscriptionMapper; +import com.gxwebsoft.common.system.service.TenantPackageService; +import com.gxwebsoft.common.system.service.TenantSubscriptionService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; + +/** + * 租户订阅记录ServiceImpl + * + * @author WebSoft + * @since 2025-12-12 + */ +@Service +public class TenantSubscriptionServiceImpl extends ServiceImpl implements TenantSubscriptionService { + + @Resource + private TenantPackageService tenantPackageService; + + @Override + public TenantSubscription getByTenantId(Integer tenantId) { + return baseMapper.selectByTenantIdRel(tenantId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public TenantSubscription createOrUpdateSubscription(Integer tenantId, Integer packageId, Integer version, + Date startTime, Date endTime, Integer isTrial) { + // 查询是否已存在订阅 + TenantSubscription subscription = getOne(new LambdaQueryWrapper() + .eq(TenantSubscription::getTenantId, tenantId)); + + if (subscription == null) { + // 创建新订阅 + subscription = new TenantSubscription(); + subscription.setTenantId(tenantId); + subscription.setPackageId(packageId); + subscription.setVersion(version); + subscription.setStartTime(startTime); + subscription.setEndTime(endTime); + subscription.setIsTrial(isTrial); + subscription.setIsExpired(0); + subscription.setAutoRenewal(0); + subscription.setNotifyStatus(0); + subscription.setStatus(1); + subscription.setCreateTime(new Date()); + save(subscription); + } else { + // 更新订阅 + subscription.setPackageId(packageId); + subscription.setVersion(version); + subscription.setStartTime(startTime); + subscription.setEndTime(endTime); + subscription.setIsTrial(isTrial); + subscription.setIsExpired(0); + subscription.setNotifyStatus(0); + subscription.setUpdateTime(new Date()); + updateById(subscription); + } + + return subscription; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean upgradeSubscription(Integer tenantId, Integer newPackageId) { + TenantSubscription subscription = getByTenantId(tenantId); + if (subscription == null) { + throw new BusinessException("订阅不存在"); + } + + TenantPackage newPackage = tenantPackageService.getById(newPackageId); + if (newPackage == null) { + throw new BusinessException("套餐不存在"); + } + + // 检查是否是升级 + if (newPackage.getVersion() <= subscription.getVersion()) { + throw new BusinessException("只能升级到更高版本"); + } + + subscription.setPackageId(newPackageId); + subscription.setVersion(newPackage.getVersion()); + subscription.setUpdateTime(new Date()); + + return updateById(subscription); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean renewSubscription(Integer tenantId, Integer months) { + TenantSubscription subscription = getByTenantId(tenantId); + if (subscription == null) { + throw new BusinessException("订阅不存在"); + } + + // 从当前到期时间延长 + Date newEndTime = DateUtil.offsetMonth(subscription.getEndTime(), months); + subscription.setEndTime(newEndTime); + subscription.setIsExpired(0); + subscription.setUpdateTime(new Date()); + + return updateById(subscription); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean setAutoRenewal(Integer tenantId, Integer autoRenewal, Integer renewalPackageId) { + TenantSubscription subscription = getByTenantId(tenantId); + if (subscription == null) { + throw new BusinessException("订阅不存在"); + } + + subscription.setAutoRenewal(autoRenewal); + subscription.setRenewalPackageId(renewalPackageId); + subscription.setUpdateTime(new Date()); + + return updateById(subscription); + } + + @Override + public boolean isSubscriptionValid(Integer tenantId) { + TenantSubscription subscription = getByTenantId(tenantId); + if (subscription == null) { + return false; + } + return subscription.getStatus() == 1 && subscription.getIsExpired() == 0 + && subscription.getEndTime().after(new Date()); + } + + @Override + public boolean isSubscriptionExpired(Integer tenantId) { + TenantSubscription subscription = getByTenantId(tenantId); + if (subscription == null) { + return true; + } + return subscription.getIsExpired() == 1 || subscription.getEndTime().before(new Date()); + } + + @Override + public List listExpiringSoon(Integer days) { + return baseMapper.selectExpiringSoon(days); + } + + @Override + public List listExpired() { + return baseMapper.selectExpired(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean markAsExpired(Long subscriptionId) { + TenantSubscription subscription = getById(subscriptionId); + if (subscription == null) { + return false; + } + + subscription.setIsExpired(1); + subscription.setUpdateTime(new Date()); + + return updateById(subscription); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean sendExpiryNotification(Long subscriptionId, Integer notifyStatus) { + TenantSubscription subscription = getById(subscriptionId); + if (subscription == null) { + return false; + } + + subscription.setNotifyStatus(notifyStatus); + subscription.setUpdateTime(new Date()); + + return updateById(subscription); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserBalanceLogServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserBalanceLogServiceImpl.java new file mode 100644 index 0000000..2286471 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserBalanceLogServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.mapper.UserBalanceLogMapper; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; +import com.gxwebsoft.common.system.service.UserBalanceLogService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户余额变动明细表Service实现 + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +@Service +public class UserBalanceLogServiceImpl extends ServiceImpl implements UserBalanceLogService { + + @Override + public PageResult pageRel(UserBalanceLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserBalanceLogParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserBalanceLog getByIdRel(Integer logId) { + UserBalanceLogParam param = new UserBalanceLogParam(); + param.setLogId(logId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserFileServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserFileServiceImpl.java new file mode 100644 index 0000000..b5712c3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserFileServiceImpl.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.UserFileMapper; +import com.gxwebsoft.common.system.service.UserFileService; +import com.gxwebsoft.common.system.entity.UserFile; +import org.springframework.stereotype.Service; + +/** + * 用户文件Service实现 + * + * @author WebSoft + * @since 2022-07-21 14:34:40 + */ +@Service +public class UserFileServiceImpl extends ServiceImpl implements UserFileService { + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserGradeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserGradeServiceImpl.java new file mode 100644 index 0000000..410ba2f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserGradeServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.UserGradeMapper; +import com.gxwebsoft.common.system.service.UserGradeService; +import com.gxwebsoft.common.system.entity.UserGrade; +import com.gxwebsoft.common.system.param.UserGradeParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户会员等级表Service实现 + * + * @author 科技小王子 + * @since 2023-10-07 22:51:17 + */ +@Service +public class UserGradeServiceImpl extends ServiceImpl implements UserGradeService { + + @Override + public PageResult pageRel(UserGradeParam param) { + PageParam page = new PageParam<>(param); +// page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserGradeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); +// page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserGrade getByIdRel(Integer gradeId) { + UserGradeParam param = new UserGradeParam(); + param.setGradeId(gradeId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserGroupServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserGroupServiceImpl.java new file mode 100644 index 0000000..dccaf0f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserGroupServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.UserGroupMapper; +import com.gxwebsoft.common.system.service.UserGroupService; +import com.gxwebsoft.common.system.entity.UserGroup; +import com.gxwebsoft.common.system.param.UserGroupParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户分组管理表Service实现 + * + * @author 科技小王子 + * @since 2023-10-28 15:16:39 + */ +@Service +public class UserGroupServiceImpl extends ServiceImpl implements UserGroupService { + + @Override + public PageResult pageRel(UserGroupParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserGroupParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserGroup getByIdRel(Integer groupId) { + UserGroupParam param = new UserGroupParam(); + param.setGroupId(groupId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserOauthServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserOauthServiceImpl.java new file mode 100644 index 0000000..c1a8812 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserOauthServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.UserOauthMapper; +import com.gxwebsoft.common.system.service.UserOauthService; +import com.gxwebsoft.common.system.entity.UserOauth; +import com.gxwebsoft.common.system.param.UserOauthParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 第三方用户信息表Service实现 + * + * @author 科技小王子 + * @since 2023-10-07 22:39:46 + */ +@Service +public class UserOauthServiceImpl extends ServiceImpl implements UserOauthService { + + @Override + public PageResult pageRel(UserOauthParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserOauthParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserOauth getByIdRel(Integer id) { + UserOauthParam param = new UserOauthParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserRefereeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserRefereeServiceImpl.java new file mode 100644 index 0000000..3055b98 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserRefereeServiceImpl.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.mapper.UserRefereeMapper; +import com.gxwebsoft.common.system.param.UserRefereeParam; +import com.gxwebsoft.common.system.service.UserRefereeService; +import com.gxwebsoft.common.system.service.UserService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户推荐关系表Service实现 + * + * @author 科技小王子 + * @since 2023-10-07 22:56:36 + */ +@Service +public class UserRefereeServiceImpl extends ServiceImpl implements UserRefereeService { + + @Resource + private UserService userService; + + @Override + public PageResult pageRel(UserRefereeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + for (UserReferee userReferee : list) { + userReferee.setUser(userService.getById(userReferee.getUserId())); + } + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserRefereeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserReferee getByIdRel(Integer id) { + UserRefereeParam param = new UserRefereeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public UserReferee check(Integer dealerId, Integer userId) { + return getOne( + new LambdaQueryWrapper() + .eq(UserReferee::getDealerId, dealerId) + .eq(UserReferee::getUserId, userId) + ); + } + + @Override + public UserReferee getByUserId(Integer userId) { + return getOne( + new LambdaQueryWrapper() + .eq(UserReferee::getUserId, userId) + .last("limit 1") + ); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserRoleServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserRoleServiceImpl.java new file mode 100644 index 0000000..b57ca60 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserRoleServiceImpl.java @@ -0,0 +1,64 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.UserRole; +import com.gxwebsoft.common.system.mapper.UserRoleMapper; +import com.gxwebsoft.common.system.param.UserRoleParam; +import com.gxwebsoft.common.system.service.UserRoleService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户角色Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:36 + */ +@Service +public class UserRoleServiceImpl extends ServiceImpl implements UserRoleService { + + @Override + public int saveBatch(Integer userId, List roleIds) { + return baseMapper.insertBatch(userId, roleIds); + } + + @Override + public List listByUserId(Integer userId) { + return baseMapper.selectByUserId(userId); + } + + @Override + public List listByUserIds(List userIds) { + return baseMapper.selectByUserIds(userIds); + } + + @Override + public List listByRoleId(Integer roleId) { + return list(new LambdaQueryWrapper().eq(UserRole::getRoleId, roleId)); + } + + @Override + public PageResult pageRel(UserRoleParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = page(page, page.getWrapper()).getRecords(); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserRoleParam param) { + return list(new LambdaQueryWrapper()); + } + + @Override + public UserRole getByIdRel(Integer id) { + return getById(id); + } + +} + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..e368889 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserServiceImpl.java @@ -0,0 +1,280 @@ +package com.gxwebsoft.common.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.CmsWebsite; +import com.gxwebsoft.cms.param.CmsWebsiteParam; +import com.gxwebsoft.cms.service.CmsWebsiteService; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.Company; +import com.gxwebsoft.common.system.entity.Role; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserRole; +import com.gxwebsoft.common.system.mapper.UserMapper; +import com.gxwebsoft.common.system.param.CompanyParam; +import com.gxwebsoft.common.system.param.UserParam; +import com.gxwebsoft.common.system.service.CompanyService; +import com.gxwebsoft.common.system.service.RoleMenuService; +import com.gxwebsoft.common.system.service.UserRoleService; +import com.gxwebsoft.common.system.service.UserService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 用户Service实现 + * + * @author WebSoft + * @since 2018-12-24 16:10:14 + */ +@Service +public class UserServiceImpl extends ServiceImpl implements UserService { + @Resource + private UserRoleService userRoleService; + @Resource + private RoleMenuService roleMenuService; + @Resource + private BCryptPasswordEncoder bCryptPasswordEncoder; + @Resource + private CmsWebsiteService cmsWebsiteService; + @Resource + private CompanyService companyService; + @Resource + private RedisUtil redisUtil; + + @Override + public PageResult pageRel(UserParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + // 查询用户的角色 + selectUserRoles(list); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserParam param) { + List list = baseMapper.selectListRel(param); + // 查询用户的角色 + selectUserRoles(list); + // 排序 + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public User getByIdRel(Integer userId) { + UserParam param = new UserParam(); + param.setUserId(userId); + User user = param.getOne(baseMapper.selectListRel(param)); + if (user != null) { + user.setRoles(userRoleService.listByUserId(user.getUserId())); + user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null)); + } + return user; + } + + @Override + public User getByUsername(String username) { + return getByUsername(username, null); + } + + @Override + public User getByUsername(String username, Integer tenantId) { + if (StrUtil.isBlank(username)) { + return null; + } + User user = baseMapper.selectByUsername(username, tenantId); + if (user != null) { + user.setRoles(userRoleService.listByUserId(user.getUserId())); + user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null)); + } + return user; + } + + @Override + public User getByUsernameIgnoreTenant(String username) { + if (StrUtil.isBlank(username)) { + return null; + } + User user = baseMapper.selectByUsernameIgnoreTenant(username); + if (user != null) { + user.setRoles(userRoleService.listByUserId(user.getUserId())); + user.setAuthorities(roleMenuService.listMenuByUserId(user.getUserId(), null)); + } + return user; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return getByUsername(username); + } + + @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE) + @Override + public boolean saveUser(User user) { + if (StrUtil.isNotEmpty(user.getUsername()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getUsername, user.getUsername())) > 0) { + throw new BusinessException("账号已存在"); + } + if (StrUtil.isNotEmpty(user.getPhone()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getPhone, user.getPhone())) > 0) { + throw new BusinessException("手机号已存在"); + } + if (StrUtil.isNotEmpty(user.getEmail()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getEmail, user.getEmail())) > 0) { + throw new BusinessException("邮箱已存在"); + } + boolean result = baseMapper.insert(user) > 0; + if (result && user.getRoles() != null && user.getRoles().size() > 0) { + List roleIds = user.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList()); + if (userRoleService.saveBatch(user.getUserId(), roleIds) < roleIds.size()) { + throw new BusinessException("用户角色添加失败"); + } + } + return result; + } + + @Transactional(rollbackFor = {Exception.class}) + @Override + public boolean updateUser(User user) { + if (StrUtil.isNotEmpty(user.getUsername()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getUsername, user.getUsername()) + .ne(User::getUserId, user.getUserId())) > 0) { + throw new BusinessException("账号已存在"); + } + if (StrUtil.isNotEmpty(user.getPhone()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getPhone, user.getPhone()) + .ne(User::getUserId, user.getUserId())) > 0) { + throw new BusinessException("手机号已存在"); + } + if (StrUtil.isNotEmpty(user.getEmail()) && baseMapper.selectCount(new LambdaQueryWrapper() + .eq(User::getEmail, user.getEmail()) + .ne(User::getUserId, user.getUserId())) > 0) { + throw new BusinessException("邮箱已存在"); + } + boolean result = baseMapper.updateById(user) > 0; + if (result && user.getRoles() != null && user.getRoles().size() > 0) { + userRoleService.remove(new LambdaUpdateWrapper().eq(UserRole::getUserId, user.getUserId())); + List roleIds = user.getRoles().stream().map(Role::getRoleId).collect(Collectors.toList()); + if (userRoleService.saveBatch(user.getUserId(), roleIds) < roleIds.size()) { + throw new BusinessException("用户角色添加失败"); + } + } + return result; + } + + @Override + public boolean comparePassword(String dbPassword, String inputPassword) { + return bCryptPasswordEncoder.matches(inputPassword, dbPassword); + } + + @Override + public String encodePassword(String password) { + return password == null ? null : bCryptPasswordEncoder.encode(password); + } + + @Override + public User getByPhone(String phone) { + return query().eq("phone", phone).one(); + } + + @Override + public User getByUnionId(UserParam param) { + return param.getOne(baseMapper.getOne(param)); + } + + @Override + public User getByOauthId(UserParam userParam) { + return userParam.getOne(baseMapper.getOne(userParam)); + } + + @Override + public List listStatisticsRel(UserParam param) { + List list = baseMapper.selectListStatisticsRel(param); + return list; + } + + /** + * 更新用户信息(跨租户) + * + * @param user 用户信息 + */ + @Override + public void updateByUserId(User user) { + baseMapper.updateByUserId(user); + } + + @Override + public List pageAdminByPhone(UserParam param) { + return baseMapper.pageAdminByPhone(param); + } + + @Override + public List listByAlert() { + return baseMapper.listByAlert(); + } + + @Override + public User getByIdIgnoreTenant(Integer userId) { + if (userId == null) { + return null; + } + return baseMapper.selectByIdIgnoreTenant(userId); + } + + @Override + public User getAllByUserId(String userId) { + if (userId == null || userId.trim().isEmpty()) { + return null; + } + try { + Integer id = Integer.parseInt(userId); + return getByIdIgnoreTenant(id); + } catch (NumberFormatException e) { + return null; + } + } + + /** + * 批量查询用户的角色 + * + * @param users 用户集合 + */ + private void selectUserRoles(List users) { + if (users != null && users.size() > 0) { + List userIds = users.stream().map(User::getUserId).collect(Collectors.toList()); + List userRoles = userRoleService.listByUserIds(userIds); + for (User user : users) { + List roles = userRoles.stream().filter(d -> user.getUserId().equals(d.getUserId())) + .collect(Collectors.toList()); + user.setRoles(roles); + } + } + } + + @Override + public User findByOpenId(String openId) { + if (StrUtil.isBlank(openId)) { + return null; + } + return query().eq("openid", openId).one(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserVerifyServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserVerifyServiceImpl.java new file mode 100644 index 0000000..3560005 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/UserVerifyServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.UserVerifyMapper; +import com.gxwebsoft.common.system.service.UserVerifyService; +import com.gxwebsoft.common.system.entity.UserVerify; +import com.gxwebsoft.common.system.param.UserVerifyParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 实名认证Service实现 + * + * @author 科技小王子 + * @since 2025-05-29 23:01:04 + */ +@Service +public class UserVerifyServiceImpl extends ServiceImpl implements UserVerifyService { + + @Override + public PageResult pageRel(UserVerifyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(UserVerifyParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public UserVerify getByIdRel(Integer id) { + UserVerifyParam param = new UserVerifyParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/VersionServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/VersionServiceImpl.java new file mode 100644 index 0000000..70b147e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/VersionServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.VersionMapper; +import com.gxwebsoft.common.system.service.VersionService; +import com.gxwebsoft.common.system.entity.Version; +import com.gxwebsoft.common.system.param.VersionParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 版本更新Service实现 + * + * @author 科技小王子 + * @since 2024-01-15 18:52:24 + */ +@Service +public class VersionServiceImpl extends ServiceImpl implements VersionService { + + @Override + public PageResult pageRel(VersionParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(VersionParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public Version getByIdRel(Integer id) { + VersionParam param = new VersionParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/WebsiteFieldServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/WebsiteFieldServiceImpl.java new file mode 100644 index 0000000..929e8e1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/WebsiteFieldServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.WebsiteFieldMapper; +import com.gxwebsoft.common.system.service.WebsiteFieldService; +import com.gxwebsoft.common.system.entity.WebsiteField; +import com.gxwebsoft.common.system.param.WebsiteFieldParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 应用参数Service实现 + * + * @author 科技小王子 + * @since 2024-08-27 15:18:05 + */ +@Service +public class WebsiteFieldServiceImpl extends ServiceImpl implements WebsiteFieldService { + + @Override + public PageResult pageRel(WebsiteFieldParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time asc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(WebsiteFieldParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time asc"); + return page.sortRecords(list); + } + + @Override + public WebsiteField getByIdRel(Integer id) { + WebsiteFieldParam param = new WebsiteFieldParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/WhiteDomainServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/WhiteDomainServiceImpl.java new file mode 100644 index 0000000..7aa920f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/service/impl/WhiteDomainServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.common.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.system.mapper.WhiteDomainMapper; +import com.gxwebsoft.common.system.service.WhiteDomainService; +import com.gxwebsoft.common.system.entity.WhiteDomain; +import com.gxwebsoft.common.system.param.WhiteDomainParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 服务器白名单Service实现 + * + * @author 科技小王子 + * @since 2024-03-26 00:22:21 + */ +@Service +public class WhiteDomainServiceImpl extends ServiceImpl implements WhiteDomainService { + + @Override + public PageResult pageRel(WhiteDomainParam param) { + PageParam page = new PageParam<>(param); + //page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(WhiteDomainParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + //page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public WhiteDomain getByIdRel(Integer id) { + WhiteDomainParam param = new WhiteDomainParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/util/EmailTemplateUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/util/EmailTemplateUtil.java new file mode 100644 index 0000000..c547387 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/util/EmailTemplateUtil.java @@ -0,0 +1,199 @@ +package com.gxwebsoft.common.system.util; + +import cn.hutool.core.date.DateUtil; +import com.gxwebsoft.common.system.service.EmailRecordService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * 邮件模板工具类 + * 统一管理邮件模板和发送逻辑 + * + * @author WebSoft + * @since 2024-08-28 + */ +@Component +public class EmailTemplateUtil { + + @Resource + private EmailRecordService emailRecordService; + + /** + * 发送注册成功邮件 + * + * @param username 用户名 + * @param phone 手机号 + * @param password 密码 + * @param email 邮箱 + * @param tenantId 租户ID + */ + public void sendRegisterSuccessEmail(String username, String phone, String password, String email, Integer tenantId) { + try { + String title = "恭喜!您的账号已注册成功"; + Map data = new HashMap<>(); + data.put("username", username); + data.put("phone", phone); + data.put("password", password); + if (email != null && !email.trim().isEmpty()) { + data.put("email", email); + } + + emailRecordService.sendHtmlEmail(title, "register-success.html", data, new String[]{email}); + } catch (Exception e) { + // 如果HTML邮件发送失败,降级为文本邮件 + String content = "恭喜!您的WebSoft账号已注册成功\r\n用户名:" + username + "\r\n手机号码:" + phone + "\r\n密码:" + password; + emailRecordService.sendEmail("恭喜!您的WebSoft账号已注册成功", content, email, tenantId); + } + } + + /** + * 发送密码重置邮件 + * + * @param username 用户名 + * @param phone 手机号 + * @param newPassword 新密码 + * @param email 邮箱 + * @param tenantId 租户ID + */ + public void sendPasswordResetEmail(String username, String phone, String newPassword, String email, Integer tenantId) { + try { + String title = "WebSoft密码重置通知"; + Map data = new HashMap<>(); + data.put("username", username); + data.put("phone", phone); + data.put("resetTime", DateUtil.now()); + if (newPassword != null && !newPassword.trim().isEmpty()) { + data.put("newPassword", newPassword); + } + + emailRecordService.sendHtmlEmail(title, "password-reset.html", data, new String[]{email}); + } catch (Exception e) { + // 如果HTML邮件发送失败,降级为文本邮件 + String content = "您的WebSoft账号密码已重置\r\n用户名:" + username + "\r\n手机号码:" + phone + "\r\n新密码:" + newPassword + "\r\n重置时间:" + DateUtil.now(); + emailRecordService.sendEmail("WebSoft密码重置通知", content, email, tenantId); + } + } + + /** + * 发送通用通知邮件 + * + * @param title 邮件标题 + * @param content 邮件内容 + * @param email 收件人邮箱 + * @param tenantId 租户ID + * @param greeting 问候语(可选) + * @param infoMessage 提示信息(可选) + * @param actionUrl 操作链接(可选) + * @param actionText 操作按钮文字(可选) + */ + public void sendNotificationEmail(String title, String content, String email, Integer tenantId, + String greeting, String infoMessage, String actionUrl, String actionText) { + try { + Map data = new HashMap<>(); + data.put("title", title); + data.put("content", content); + data.put("sendTime", DateUtil.now()); + + if (greeting != null && !greeting.trim().isEmpty()) { + data.put("greeting", greeting); + } + if (infoMessage != null && !infoMessage.trim().isEmpty()) { + data.put("infoMessage", infoMessage); + } + if (actionUrl != null && !actionUrl.trim().isEmpty()) { + data.put("actionUrl", actionUrl); + } + if (actionText != null && !actionText.trim().isEmpty()) { + data.put("actionText", actionText); + } + + emailRecordService.sendHtmlEmail(title, "notification.html", data, new String[]{email}); + } catch (Exception e) { + // 如果HTML邮件发送失败,降级为文本邮件 + emailRecordService.sendEmail(title, content, email, tenantId); + } + } + + /** + * 发送简单通知邮件 + * + * @param title 邮件标题 + * @param content 邮件内容 + * @param email 收件人邮箱 + * @param tenantId 租户ID + */ + public void sendNotificationEmail(String title, String content, String email, Integer tenantId) { + sendNotificationEmail(title, content, email, tenantId, null, null, null, null); + } + + /** + * 发送带操作按钮的通知邮件 + * + * @param title 邮件标题 + * @param content 邮件内容 + * @param email 收件人邮箱 + * @param tenantId 租户ID + * @param actionUrl 操作链接 + * @param actionText 操作按钮文字 + */ + public void sendNotificationEmailWithAction(String title, String content, String email, Integer tenantId, + String actionUrl, String actionText) { + sendNotificationEmail(title, content, email, tenantId, null, null, actionUrl, actionText); + } + + /** + * 发送账户安全提醒邮件 + * + * @param username 用户名 + * @param phone 手机号 + * @param email 邮箱 + * @param tenantId 租户ID + * @param event 安全事件描述 + */ + public void sendSecurityAlertEmail(String username, String phone, String email, Integer tenantId, String event) { + String title = "WebSoft账户安全提醒"; + String content = "您的账户发生了以下安全事件:" + event + "。如果这不是您本人的操作,请立即联系客服并修改密码。"; + String infoMessage = "为了保障您的账户安全,建议您定期修改密码并开启双重验证。"; + String actionUrl = "https://websoft.top/security"; + String actionText = "查看安全设置"; + + sendNotificationEmail(title, content, email, tenantId, "尊敬的用户", infoMessage, actionUrl, actionText); + } + + /** + * 发送系统维护通知邮件 + * + * @param email 收件人邮箱 + * @param tenantId 租户ID + * @param maintenanceTime 维护时间 + * @param duration 维护时长 + */ + public void sendMaintenanceNotificationEmail(String email, Integer tenantId, String maintenanceTime, String duration) { + String title = "WebSoft系统维护通知"; + String content = "为了提供更好的服务,我们将在 " + maintenanceTime + " 进行系统维护,预计维护时长:" + duration + "。维护期间可能会影响系统的正常使用,给您带来的不便敬请谅解。"; + String infoMessage = "维护完成后,系统将自动恢复正常服务。"; + + sendNotificationEmail(title, content, email, tenantId, "尊敬的用户", infoMessage, null, null); + } + + /** + * 发送订单状态变更邮件 + * + * @param username 用户名 + * @param orderNo 订单号 + * @param status 订单状态 + * @param email 邮箱 + * @param tenantId 租户ID + */ + public void sendOrderStatusEmail(String username, String orderNo, String status, String email, Integer tenantId) { + String title = "WebSoft订单状态更新"; + String content = "您的订单 " + orderNo + " 状态已更新为:" + status + "。"; + String actionUrl = "https://websoft.top/orders/" + orderNo; + String actionText = "查看订单详情"; + + sendNotificationEmailWithAction(title, content, email, tenantId, actionUrl, actionText); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/ChatConversationVO.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/ChatConversationVO.java new file mode 100644 index 0000000..d31eb23 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/ChatConversationVO.java @@ -0,0 +1,18 @@ +package com.gxwebsoft.common.system.vo; + +import com.gxwebsoft.common.system.entity.ChatConversation; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.ChatMessage; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class ChatConversationVO extends ChatConversation { + private User friendInfo; + private User userInfo; + private List messages = new ArrayList<>(); + private Integer messageCount; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/PushMessageVO.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/PushMessageVO.java new file mode 100644 index 0000000..f1c78d6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/PushMessageVO.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.common.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; +import java.util.Set; + +@Data +@Builder +public class PushMessageVO implements Serializable { + + @Schema(description = "推送消息") + private String title; + + @Schema(description = "推送消息内容") + private String content; + + private Set userIds; + + + @Schema(description = "推送透传数据obj格式") + private Payload payload; + + + private Set push_clientid; + + + @Data + public static class Payload { + private String type; + private Object data; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/WxOfficialButton.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/WxOfficialButton.java new file mode 100644 index 0000000..f95f129 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/WxOfficialButton.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.common.system.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.List; + +import java.io.Serializable; + +/** + * 访问凭证管理 + * + * @author 科技小王子 + * @since 2023-05-16 19:19:55 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "微信公众号菜单按钮", description = "微信公众号菜单按钮") +@TableName("wx_official_menu_button") +public class WxOfficialButton implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "按钮名称") + @TableField(exist = false) + private String name; + + @Schema(description = "按钮类型") + @TableField(exist = false) + private String type; + + @Schema(description = "内容") + @TableField(exist = false) + private String key; + + @Schema(description = "子菜单") + @TableField(exist = false) + private List sub_button; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/WxOfficialMenu.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/WxOfficialMenu.java new file mode 100644 index 0000000..e3d324f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/WxOfficialMenu.java @@ -0,0 +1,28 @@ +package com.gxwebsoft.common.system.vo; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.List; + +/** + * 访问凭证管理 + * + * @author 科技小王子 + * @since 2023-05-16 19:19:55 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "微信公众号菜单", description = "微信公众号菜单") +@TableName("wx_official_menu") +public class WxOfficialMenu implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "微信公众号按钮") + @TableField(exist = false) + private List buttons; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/faceId/HeadPortraitResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/faceId/HeadPortraitResult.java new file mode 100644 index 0000000..01dae5d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/faceId/HeadPortraitResult.java @@ -0,0 +1,17 @@ +package com.gxwebsoft.common.system.vo.faceId; + + +import lombok.Data; + +@Data +public class HeadPortraitResult { + private String code; + private String msg; + private String porn; + private String ad; + private String requestId; + private Integer faceCount; + private Boolean cartoonImg; + private int[] genterList; + private int[] ageList; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/BackRecognitionResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/BackRecognitionResult.java new file mode 100644 index 0000000..faae5b0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/BackRecognitionResult.java @@ -0,0 +1,11 @@ +package com.gxwebsoft.common.system.vo.idcheck; + +import lombok.Data; + +@Data +public class BackRecognitionResult { + + private String startDate; + private String endDate; + private String issue; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/FrontRecognitionResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/FrontRecognitionResult.java new file mode 100644 index 0000000..f68d06d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/FrontRecognitionResult.java @@ -0,0 +1,15 @@ +package com.gxwebsoft.common.system.vo.idcheck; + +import lombok.Data; + +@Data +public class FrontRecognitionResult { + private String idcardno; + private String name; + private String nationality; + private String sex; + private String birth; + private String address; + private String imageStats; + private String direction; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/IdCardInfor.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/IdCardInfor.java new file mode 100644 index 0000000..6feb209 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/IdCardInfor.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.vo.idcheck; + +import lombok.Data; + +@Data +public class IdCardInfor { + private String province; + private String city; + private String district; + private String area; + private String sex; + private String birthday; +} + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/Response.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/Response.java new file mode 100644 index 0000000..ec4d097 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/Response.java @@ -0,0 +1,10 @@ +package com.gxwebsoft.common.system.vo.idcheck; + +import lombok.Data; + +@Data +public class Response { + private Integer error_code; + private String reason; + private T result; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/VerifyResult.java b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/VerifyResult.java new file mode 100644 index 0000000..f466341 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/common/system/vo/idcheck/VerifyResult.java @@ -0,0 +1,14 @@ +package com.gxwebsoft.common.system.vo.idcheck; + +import lombok.Data; + +@Data +public class VerifyResult { + private String realname; + private String idcard; + + private boolean isOk; + + private IdCardInfor idCardInfor; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/constants/PaymentConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/constants/PaymentConstants.java new file mode 100644 index 0000000..80f0354 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/constants/PaymentConstants.java @@ -0,0 +1,244 @@ +package com.gxwebsoft.payment.constants; + +/** + * 支付模块常量类 + * 统一管理支付相关的常量配置 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public class PaymentConstants { + + /** + * 支付状态常量 + */ + public static class Status { + /** 待支付 */ + public static final String PENDING = "PENDING"; + /** 支付成功 */ + public static final String SUCCESS = "SUCCESS"; + /** 支付失败 */ + public static final String FAILED = "FAILED"; + /** 支付取消 */ + public static final String CANCELLED = "CANCELLED"; + /** 支付超时 */ + public static final String TIMEOUT = "TIMEOUT"; + /** 退款成功 */ + public static final String REFUNDED = "REFUNDED"; + } + + /** + * 微信支付相关常量 + */ + public static class Wechat { + /** 货币类型 */ + public static final String CURRENCY = "CNY"; + /** 金额转换倍数(元转分) */ + public static final int AMOUNT_MULTIPLIER = 100; + + /** 支付状态 */ + public static final String PAY_SUCCESS = "SUCCESS"; + public static final String PAY_REFUND = "REFUND"; + public static final String PAY_NOTPAY = "NOTPAY"; + public static final String PAY_CLOSED = "CLOSED"; + public static final String PAY_REVOKED = "REVOKED"; + public static final String PAY_USERPAYING = "USERPAYING"; + public static final String PAY_PAYERROR = "PAYERROR"; + + /** 回调响应 */ + public static final String NOTIFY_SUCCESS = "SUCCESS"; + public static final String NOTIFY_FAIL = "FAIL"; + + /** 通知类型 */ + public static final String EVENT_PAYMENT = "TRANSACTION.SUCCESS"; + public static final String EVENT_REFUND = "REFUND.SUCCESS"; + + /** HTTP头部 */ + public static final String HEADER_SIGNATURE = "Wechatpay-Signature"; + public static final String HEADER_TIMESTAMP = "Wechatpay-Timestamp"; + public static final String HEADER_NONCE = "Wechatpay-Nonce"; + public static final String HEADER_SERIAL = "Wechatpay-Serial"; + public static final String HEADER_REQUEST_ID = "Request-ID"; + } + + /** + * 支付宝相关常量 + */ + public static class Alipay { + /** 货币类型 */ + public static final String CURRENCY = "CNY"; + + /** 支付状态 */ + public static final String PAY_SUCCESS = "TRADE_SUCCESS"; + public static final String PAY_FINISHED = "TRADE_FINISHED"; + public static final String PAY_CLOSED = "TRADE_CLOSED"; + + /** 回调响应 */ + public static final String NOTIFY_SUCCESS = "success"; + public static final String NOTIFY_FAIL = "failure"; + + /** 产品码 */ + public static final String PRODUCT_CODE_WEB = "FAST_INSTANT_TRADE_PAY"; + public static final String PRODUCT_CODE_WAP = "QUICK_WAP_WAY"; + public static final String PRODUCT_CODE_APP = "QUICK_MSECURITY_PAY"; + } + + /** + * 银联支付相关常量 + */ + public static class UnionPay { + /** 货币类型 */ + public static final String CURRENCY = "156"; // 人民币代码 + + /** 支付状态 */ + public static final String PAY_SUCCESS = "00"; + public static final String PAY_FAILED = "01"; + + /** 交易类型 */ + public static final String TXN_TYPE_CONSUME = "01"; // 消费 + public static final String TXN_TYPE_REFUND = "04"; // 退货 + } + + /** + * 缓存键常量 + */ + public static class CacheKey { + /** 支付配置缓存前缀 */ + public static final String PAYMENT_CONFIG = "payment:config:"; + /** 支付订单缓存前缀 */ + public static final String PAYMENT_ORDER = "payment:order:"; + /** 支付锁前缀 */ + public static final String PAYMENT_LOCK = "payment:lock:"; + /** 回调处理锁前缀 */ + public static final String NOTIFY_LOCK = "payment:notify:lock:"; + } + + /** + * 配置相关常量 + */ + public static class Config { + /** 订单超时时间(分钟) */ + public static final int ORDER_TIMEOUT_MINUTES = 30; + /** 订单描述最大长度 */ + public static final int DESCRIPTION_MAX_LENGTH = 127; + /** 最大重试次数 */ + public static final int MAX_RETRY_COUNT = 3; + /** 重试间隔(毫秒) */ + public static final long RETRY_INTERVAL_MS = 1000; + /** 签名有效期(秒) */ + public static final long SIGNATURE_VALID_SECONDS = 300; + } + + /** + * 错误信息常量 + */ + public static class ErrorMessage { + /** 参数错误 */ + public static final String PARAM_ERROR = "参数错误"; + /** 配置未找到 */ + public static final String CONFIG_NOT_FOUND = "支付配置未找到"; + /** 支付方式不支持 */ + public static final String PAYMENT_TYPE_NOT_SUPPORTED = "支付方式不支持"; + /** 金额错误 */ + public static final String AMOUNT_ERROR = "金额错误"; + /** 订单不存在 */ + public static final String ORDER_NOT_FOUND = "订单不存在"; + /** 订单状态错误 */ + public static final String ORDER_STATUS_ERROR = "订单状态错误"; + /** 签名验证失败 */ + public static final String SIGNATURE_ERROR = "签名验证失败"; + /** 网络请求失败 */ + public static final String NETWORK_ERROR = "网络请求失败"; + /** 系统内部错误 */ + public static final String SYSTEM_ERROR = "系统内部错误"; + /** 余额不足 */ + public static final String INSUFFICIENT_BALANCE = "余额不足"; + /** 支付超时 */ + public static final String PAYMENT_TIMEOUT = "支付超时"; + /** 重复支付 */ + public static final String DUPLICATE_PAYMENT = "重复支付"; + } + + /** + * 日志消息常量 + */ + public static class LogMessage { + /** 支付请求开始 */ + public static final String PAYMENT_START = "开始处理支付请求"; + /** 支付请求成功 */ + public static final String PAYMENT_SUCCESS = "支付请求处理成功"; + /** 支付请求失败 */ + public static final String PAYMENT_FAILED = "支付请求处理失败"; + + /** 回调处理开始 */ + public static final String NOTIFY_START = "开始处理支付回调"; + /** 回调处理成功 */ + public static final String NOTIFY_SUCCESS = "支付回调处理成功"; + /** 回调处理失败 */ + public static final String NOTIFY_FAILED = "支付回调处理失败"; + + /** 退款请求开始 */ + public static final String REFUND_START = "开始处理退款请求"; + /** 退款请求成功 */ + public static final String REFUND_SUCCESS = "退款请求处理成功"; + /** 退款请求失败 */ + public static final String REFUND_FAILED = "退款请求处理失败"; + } + + /** + * 正则表达式常量 + */ + public static class Regex { + /** 订单号格式 */ + public static final String ORDER_NO = "^[a-zA-Z0-9_-]{1,32}$"; + /** 金额格式(分) */ + public static final String AMOUNT = "^[1-9]\\d*$"; + /** 手机号格式 */ + public static final String MOBILE = "^1[3-9]\\d{9}$"; + /** 邮箱格式 */ + public static final String EMAIL = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"; + } + + /** + * 时间相关常量 + */ + public static class Time { + /** 配置缓存有效期(秒) */ + public static final long CONFIG_CACHE_SECONDS = 3600; + /** 订单缓存有效期(秒) */ + public static final long ORDER_CACHE_SECONDS = 1800; + /** 支付锁有效期(秒) */ + public static final long PAYMENT_LOCK_SECONDS = 60; + /** 回调锁有效期(秒) */ + public static final long NOTIFY_LOCK_SECONDS = 30; + } + + /** + * 文件相关常量 + */ + public static class File { + /** 证书文件扩展名 */ + public static final String CERT_EXTENSION = ".pem"; + /** 私钥文件后缀 */ + public static final String PRIVATE_KEY_SUFFIX = "_key.pem"; + /** 公钥文件后缀 */ + public static final String PUBLIC_KEY_SUFFIX = "_cert.pem"; + } + + /** + * 环境相关常量 + */ + public static class Environment { + /** 开发环境 */ + public static final String DEV = "dev"; + /** 测试环境 */ + public static final String TEST = "test"; + /** 生产环境 */ + public static final String PROD = "prod"; + } + + // 私有构造函数,防止实例化 + private PaymentConstants() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/constants/WechatPayType.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/constants/WechatPayType.java new file mode 100644 index 0000000..68b2d84 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/constants/WechatPayType.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.payment.constants; + +/** + * 微信支付类型常量 + * 定义微信支付的具体实现方式 + * + * @author 科技小王子 + * @since 2025-08-30 + */ +public class WechatPayType { + + /** + * JSAPI支付 - 小程序/公众号内支付 + * 需要用户的openid + */ + public static final String JSAPI = "JSAPI"; + + /** + * Native支付 - 扫码支付 + * 生成二维码供用户扫描支付 + */ + public static final String NATIVE = "NATIVE"; + + /** + * H5支付 - 手机网页支付 + * 在手机浏览器中调起微信支付 + */ + public static final String H5 = "H5"; + + /** + * APP支付 - 移动应用支付 + * 在APP中调起微信支付 + */ + public static final String APP = "APP"; + + /** + * 根据openid自动选择微信支付类型 + * + * @param openid 用户openid + * @return JSAPI 或 NATIVE + */ + public static String getAutoType(String openid) { + return (openid != null && !openid.trim().isEmpty()) ? JSAPI : NATIVE; + } + + /** + * 检查是否为有效的微信支付类型 + * + * @param payType 支付类型 + * @return true表示有效 + */ + public static boolean isValidType(String payType) { + return JSAPI.equals(payType) || NATIVE.equals(payType) || + H5.equals(payType) || APP.equals(payType); + } + + /** + * 获取支付类型描述 + * + * @param payType 支付类型 + * @return 描述文本 + */ + public static String getDescription(String payType) { + if (payType == null) { + return "未知支付类型"; + } + + switch (payType) { + case JSAPI: + return "小程序/公众号支付"; + case NATIVE: + return "扫码支付"; + case H5: + return "手机网页支付"; + case APP: + return "移动应用支付"; + default: + return "未知支付类型: " + payType; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/controller/PaymentController.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/controller/PaymentController.java new file mode 100644 index 0000000..0d51551 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/controller/PaymentController.java @@ -0,0 +1,360 @@ +package com.gxwebsoft.payment.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.payment.constants.PaymentConstants; +import com.gxwebsoft.payment.dto.PaymentRequest; +import com.gxwebsoft.payment.dto.PaymentResponse; +import com.gxwebsoft.payment.dto.PaymentStatusUpdateRequest; +import com.gxwebsoft.payment.dto.PaymentWithOrderRequest; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.payment.exception.PaymentException; +import com.gxwebsoft.payment.service.PaymentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * 统一支付控制器 + * 提供所有支付方式的统一入口 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Validated +@Tag(name = "统一支付接口", description = "支持所有支付方式的统一支付接口") +@RestController("unifiedPaymentController") +@RequestMapping("/api/payment") +public class PaymentController extends BaseController { + + @Resource(name = "unifiedPaymentServiceImpl") + private PaymentService paymentService; + + @Operation(summary = "创建支付订单", description = "支持微信、支付宝、银联等多种支付方式") + @PostMapping("/create") + public ApiResult createPayment(@Valid @RequestBody PaymentRequest request) { + log.info("收到支付请求: {}", request); + final User loginUser = getLoginUser(); + + if(loginUser == null){ + return fail("请先登录"); + } + + request.setUserId(loginUser.getUserId()); + if(request.getTenantId() == null){ + request.setTenantId(loginUser.getTenantId()); + } + try { + PaymentResponse response = paymentService.createPayment(request); + return this.success("支付订单创建成功", response); + + } catch (PaymentException e) { + log.error("支付订单创建失败: {}", e.getMessage()); + return fail(e.getMessage()); + } catch (Exception e) { + log.error("支付订单创建系统错误: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "创建支付订单(包含订单信息)", description = "统一支付模块:创建订单并发起支付") + @PostMapping("/create-with-order") + public ApiResult createPaymentWithOrder(@Valid @RequestBody PaymentWithOrderRequest request) { + log.info("收到支付与订单创建请求: {}", request); + final User loginUser = getLoginUser(); + + if(loginUser == null){ + return fail("请先登录"); + } + + // 设置用户信息 + if(request.getTenantId() == null){ + request.setTenantId(loginUser.getTenantId()); + } + + try { + PaymentResponse response = paymentService.createPaymentWithOrder(request, loginUser); + return this.success("订单创建并发起支付成功", response); + } catch (PaymentException e) { + log.error("创建支付订单失败: {}", e.getMessage()); + return fail(e.getMessage()); + } catch (Exception e) { + log.error("创建支付订单系统错误: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "查询支付状态", description = "查询指定订单的支付状态") + @GetMapping("/query") + public ApiResult queryPayment( + @Parameter(description = "订单号", required = true) + @RequestParam @NotBlank(message = "订单号不能为空") String orderNo, + + @Parameter(description = "支付类型", required = true) + @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType, + + @Parameter(description = "租户ID", required = true) + @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) { + + log.info("查询支付状态: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId); + + // 参数验证 + if (orderNo == null || orderNo.trim().isEmpty()) { + return fail("订单号不能为空"); + } + if (paymentType == null) { + return fail("支付类型不能为空"); + } + if (tenantId == null || tenantId <= 0) { + return fail("租户ID不能为空且必须为正数"); + } + + try { + PaymentResponse response = paymentService.queryPayment(orderNo, paymentType, tenantId); + return this.success("支付状态查询成功", response); + + } catch (PaymentException e) { + log.error("支付状态查询失败: {}", e.getMessage()); + return fail(e.getMessage()); + } catch (Exception e) { + log.error("支付状态查询系统错误: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "申请退款", description = "申请订单退款") + @PostMapping("/refund") + public ApiResult refund( + @Parameter(description = "订单号", required = true) + @RequestParam @NotBlank(message = "订单号不能为空") String orderNo, + + @Parameter(description = "退款单号", required = true) + @RequestParam @NotBlank(message = "退款单号不能为空") String refundNo, + + @Parameter(description = "支付类型", required = true) + @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType, + + @Parameter(description = "订单总金额", required = true) + @RequestParam @NotNull(message = "订单总金额不能为空") @Positive(message = "订单总金额必须大于0") BigDecimal totalAmount, + + @Parameter(description = "退款金额", required = true) + @RequestParam @NotNull(message = "退款金额不能为空") @Positive(message = "退款金额必须大于0") BigDecimal refundAmount, + + @Parameter(description = "退款原因") + @RequestParam(required = false) String reason, + + @Parameter(description = "租户ID", required = true) + @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) { + + log.info("申请退款: orderNo={}, refundNo={}, paymentType={}, totalAmount={}, refundAmount={}, tenantId={}", + orderNo, refundNo, paymentType, totalAmount, refundAmount, tenantId); + + try { + PaymentResponse response = paymentService.refund(orderNo, refundNo, paymentType, + totalAmount, refundAmount, reason, tenantId); + return this.success("退款申请成功", response); + + } catch (PaymentException e) { + log.error("退款申请失败: {}", e.getMessage()); + return fail(e.getMessage()); + } catch (Exception e) { + log.error("退款申请系统错误: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "查询退款状态", description = "查询指定退款单的状态") + @GetMapping("/refund/query") + public ApiResult queryRefund( + @Parameter(description = "退款单号", required = true) + @RequestParam @NotBlank(message = "退款单号不能为空") String refundNo, + + @Parameter(description = "支付类型", required = true) + @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType, + + @Parameter(description = "租户ID", required = true) + @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) { + + log.info("查询退款状态: refundNo={}, paymentType={}, tenantId={}", refundNo, paymentType, tenantId); + + try { + PaymentResponse response = paymentService.queryRefund(refundNo, paymentType, tenantId); + return this.success("退款状态查询成功", response); + + } catch (PaymentException e) { + log.error("退款状态查询失败: {}", e.getMessage()); + return fail(e.getMessage()); + } catch (Exception e) { + log.error("退款状态查询系统错误: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "关闭订单", description = "关闭未支付的订单") + @PostMapping("/close") + public ApiResult closeOrder( + @Parameter(description = "订单号", required = true) + @RequestParam @NotBlank(message = "订单号不能为空") String orderNo, + + @Parameter(description = "支付类型", required = true) + @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType, + + @Parameter(description = "租户ID", required = true) + @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) { + + log.info("关闭订单: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId); + + try { + boolean result = paymentService.closeOrder(orderNo, paymentType, tenantId); + return success(result ? "订单关闭成功" : "订单关闭失败", result); + + } catch (PaymentException e) { + log.error("订单关闭失败: {}", e.getMessage()); + return fail(e.getMessage()); + } catch (Exception e) { + log.error("订单关闭系统错误: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "获取支持的支付类型", description = "获取系统支持的所有支付类型列表") + @GetMapping("/types") + public ApiResult getSupportedPaymentTypes() { + try { + List paymentTypes = paymentService.getSupportedPaymentTypes(); + return this.>success("获取支付类型成功", paymentTypes); + } catch (Exception e) { + log.error("获取支付类型失败: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "获取支付策略信息", description = "获取指定支付类型的策略信息") + @GetMapping("/strategy/{paymentType}") + public ApiResult getPaymentStrategyInfo( + @Parameter(description = "支付类型", required = true) + @PathVariable @NotNull(message = "支付类型不能为空") PaymentType paymentType) { + + try { + Map strategyInfo = paymentService.getPaymentStrategyInfo(paymentType); + if (strategyInfo == null) { + return fail("不支持的支付类型: " + paymentType); + } + return success("获取策略信息成功", strategyInfo); + } catch (Exception e) { + log.error("获取策略信息失败: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "获取所有支付策略信息", description = "获取系统所有支付策略的详细信息") + @GetMapping("/strategies") + public ApiResult getAllPaymentStrategyInfo() { + try { + List> strategiesInfo = paymentService.getAllPaymentStrategyInfo(); + return this.>>success("获取所有策略信息成功", strategiesInfo); + } catch (Exception e) { + log.error("获取所有策略信息失败: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "检查支付类型支持情况", description = "检查指定支付类型的功能支持情况") + @GetMapping("/support/{paymentType}") + public ApiResult checkPaymentTypeSupport( + @Parameter(description = "支付类型", required = true) + @PathVariable @NotNull(message = "支付类型不能为空") PaymentType paymentType) { + + try { + Map support = Map.of( + "supported", paymentService.isPaymentTypeSupported(paymentType), + "refundSupported", paymentService.isRefundSupported(paymentType), + "querySupported", paymentService.isQuerySupported(paymentType), + "closeSupported", paymentService.isCloseSupported(paymentType), + "notifyNeeded", paymentService.isNotifyNeeded(paymentType) + ); + return this.>success("检查支持情况成功", support); + } catch (Exception e) { + log.error("检查支持情况失败: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + } + + @Operation(summary = "手动更新支付状态", description = "用于手动同步支付状态,通常用于异常情况处理") + @PutMapping("/update-status") + public ApiResult updatePaymentStatus(@Valid @RequestBody PaymentStatusUpdateRequest request) { + log.info("收到支付状态更新请求: {}", request); + + try { + // 查询并更新支付状态 + PaymentResponse response = paymentService.queryPayment( + request.getOrderNo(), + PaymentType.WECHAT_NATIVE, + request.getTenantId() + ); + + return this.success("支付状态更新成功", response); + } catch (Exception e) { + log.error("更新支付状态失败: {}", e.getMessage(), e); + return fail("更新支付状态失败: " + e.getMessage()); + } + } + + @Operation(summary = "检查支付配置", description = "检查指定租户的支付配置是否完整") + @GetMapping("/config/check") + public ApiResult checkPaymentConfig( + @Parameter(description = "租户ID", required = true) + @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) { + + log.info("检查支付配置,租户ID: {}", tenantId); + + try { + Map configStatus = paymentService.checkPaymentConfig(tenantId); + return this.>success("配置检查完成", configStatus); + } catch (Exception e) { + log.error("检查支付配置失败: {}", e.getMessage(), e); + return fail("检查支付配置失败: " + e.getMessage()); + } + } + + @Operation(summary = "查询用户最近的支付订单", description = "当orderNo缺失时,查询用户最近创建的支付订单") + @GetMapping("/query-recent") + public ApiResult queryRecentPayment( + @Parameter(description = "支付类型", required = true) + @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType, + + @Parameter(description = "租户ID", required = true) + @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) { + + log.info("查询用户最近支付订单: paymentType={}, tenantId={}", paymentType, tenantId); + + final User loginUser = getLoginUser(); + if(loginUser == null){ + return fail("请先登录"); + } + + try { + // 这里需要实现查询用户最近订单的逻辑 + // 可以通过用户ID和租户ID查询最近创建的订单 + return fail("此功能需要实现查询用户最近订单的业务逻辑"); + + } catch (Exception e) { + log.error("查询用户最近支付订单失败: {}", e.getMessage(), e); + return fail("查询失败: " + e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/controller/PaymentNotifyController.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/controller/PaymentNotifyController.java new file mode 100644 index 0000000..c181514 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/controller/PaymentNotifyController.java @@ -0,0 +1,188 @@ +package com.gxwebsoft.payment.controller; + +import com.gxwebsoft.payment.constants.PaymentConstants; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.payment.exception.PaymentException; +import com.gxwebsoft.payment.service.PaymentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * 统一支付回调控制器 + * 处理所有支付方式的异步通知回调 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Tag(name = "统一支付回调接口", description = "处理所有支付方式的异步通知回调") +@RestController +@RequestMapping("/api/payment/notify") +public class PaymentNotifyController { + + @Resource + private PaymentService paymentService; + + @Operation(summary = "微信支付回调通知", description = "处理微信支付的异步通知") + @PostMapping("/wechat/{tenantId}") + public String wechatNotify( + @Parameter(description = "租户ID", required = true) + @PathVariable("tenantId") Integer tenantId, + @RequestBody String body, + HttpServletRequest request) { + + log.info("收到微信支付回调通知, 租户ID: {}", tenantId); + + try { + // 提取请求头 + Map headers = extractHeaders(request); + + // 处理回调 + String result = paymentService.handlePaymentNotify(PaymentType.WECHAT_NATIVE, headers, body, tenantId); + + log.info("微信支付回调处理完成, 租户ID: {}, 结果: {}", tenantId, result); + return result; + + } catch (PaymentException e) { + log.error("微信支付回调处理失败, 租户ID: {}, 错误: {}", tenantId, e.getMessage()); + return PaymentConstants.Wechat.NOTIFY_FAIL; + } catch (Exception e) { + log.error("微信支付回调系统错误, 租户ID: {}, 错误: {}", tenantId, e.getMessage(), e); + return PaymentConstants.Wechat.NOTIFY_FAIL; + } + } + + @Operation(summary = "支付宝支付回调通知", description = "处理支付宝支付的异步通知") + @PostMapping("/alipay/{tenantId}") + public String alipayNotify( + @Parameter(description = "租户ID", required = true) + @PathVariable("tenantId") Integer tenantId, + @RequestBody String body, + HttpServletRequest request) { + + log.info("收到支付宝支付回调通知, 租户ID: {}", tenantId); + + try { + // 提取请求头 + Map headers = extractHeaders(request); + + // 处理回调 + String result = paymentService.handlePaymentNotify(PaymentType.ALIPAY, headers, body, tenantId); + + log.info("支付宝支付回调处理完成, 租户ID: {}, 结果: {}", tenantId, result); + return result; + + } catch (PaymentException e) { + log.error("支付宝支付回调处理失败, 租户ID: {}, 错误: {}", tenantId, e.getMessage()); + return PaymentConstants.Alipay.NOTIFY_FAIL; + } catch (Exception e) { + log.error("支付宝支付回调系统错误, 租户ID: {}, 错误: {}", tenantId, e.getMessage(), e); + return PaymentConstants.Alipay.NOTIFY_FAIL; + } + } + + @Operation(summary = "银联支付回调通知", description = "处理银联支付的异步通知") + @PostMapping("/unionpay/{tenantId}") + public String unionPayNotify( + @Parameter(description = "租户ID", required = true) + @PathVariable("tenantId") Integer tenantId, + @RequestBody String body, + HttpServletRequest request) { + + log.info("收到银联支付回调通知, 租户ID: {}", tenantId); + + try { + // 提取请求头 + Map headers = extractHeaders(request); + + // 处理回调 + String result = paymentService.handlePaymentNotify(PaymentType.UNION_PAY, headers, body, tenantId); + + log.info("银联支付回调处理完成, 租户ID: {}, 结果: {}", tenantId, result); + return result; + + } catch (PaymentException e) { + log.error("银联支付回调处理失败, 租户ID: {}, 错误: {}", tenantId, e.getMessage()); + return "failure"; + } catch (Exception e) { + log.error("银联支付回调系统错误, 租户ID: {}, 错误: {}", tenantId, e.getMessage(), e); + return "failure"; + } + } + + @Operation(summary = "通用支付回调通知", description = "处理指定支付类型的异步通知") + @PostMapping("/{paymentType}/{tenantId}") + public String genericNotify( + @Parameter(description = "支付类型", required = true) + @PathVariable("paymentType") PaymentType paymentType, + @Parameter(description = "租户ID", required = true) + @PathVariable("tenantId") Integer tenantId, + @RequestBody String body, + HttpServletRequest request) { + + log.info("收到{}支付回调通知, 租户ID: {}", paymentType.getName(), tenantId); + + try { + // 提取请求头 + Map headers = extractHeaders(request); + + // 处理回调 + String result = paymentService.handlePaymentNotify(paymentType, headers, body, tenantId); + + log.info("{}支付回调处理完成, 租户ID: {}, 结果: {}", paymentType.getName(), tenantId, result); + return result; + + } catch (PaymentException e) { + log.error("{}支付回调处理失败, 租户ID: {}, 错误: {}", paymentType.getName(), tenantId, e.getMessage()); + return getFailureResponse(paymentType); + } catch (Exception e) { + log.error("{}支付回调系统错误, 租户ID: {}, 错误: {}", paymentType.getName(), tenantId, e.getMessage(), e); + return getFailureResponse(paymentType); + } + } + + /** + * 提取HTTP请求头 + */ + private Map extractHeaders(HttpServletRequest request) { + Map headers = new HashMap<>(); + + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + String headerValue = request.getHeader(headerName); + headers.put(headerName, headerValue); + } + + // 记录关键头部信息(不记录敏感信息) + log.debug("提取请求头完成, 头部数量: {}", headers.size()); + + return headers; + } + + /** + * 根据支付类型获取失败响应 + */ + private String getFailureResponse(PaymentType paymentType) { + switch (paymentType) { + case WECHAT: + case WECHAT_NATIVE: + return PaymentConstants.Wechat.NOTIFY_FAIL; + case ALIPAY: + return PaymentConstants.Alipay.NOTIFY_FAIL; + case UNION_PAY: + return "failure"; + default: + return "fail"; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentRequest.java new file mode 100644 index 0000000..241b549 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentRequest.java @@ -0,0 +1,207 @@ +package com.gxwebsoft.payment.dto; + +import com.gxwebsoft.payment.enums.PaymentChannel; +import com.gxwebsoft.payment.enums.PaymentType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.*; +import java.math.BigDecimal; +import java.util.Map; + +/** + * 统一支付请求DTO + * 支持所有支付方式的统一请求格式 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Data +@Schema(name = "统一支付请求", description = "支持所有支付方式的统一支付请求参数") +public class PaymentRequest { + + @Schema(description = "租户ID", required = true) + @NotNull(message = "租户ID不能为空") + @Positive(message = "租户ID必须为正数") + private Integer tenantId; + + @Schema(description = "用户ID", required = true) + @NotNull(message = "用户ID不能为空") + @Positive(message = "用户ID必须为正数") + private Integer userId; + + @Schema(description = "支付类型", required = true, example = "WECHAT") + @NotNull(message = "支付类型不能为空") + private PaymentType paymentType; + + @Schema(description = "支付渠道", example = "wechat_native") + private PaymentChannel paymentChannel; + + @Schema(description = "支付金额", required = true, example = "0.01") + @NotNull(message = "支付金额不能为空") + @DecimalMin(value = "0.01", message = "支付金额必须大于0.01元") + @DecimalMax(value = "999999.99", message = "支付金额不能超过999999.99元") + @Digits(integer = 6, fraction = 2, message = "支付金额格式不正确,最多6位整数2位小数") + private BigDecimal amount; + + @Schema(description = "订单号(可选,不提供则自动生成)") + @Size(max = 32, message = "订单号不能超过32个字符") + @Pattern(regexp = "^[a-zA-Z0-9_-]*$", message = "订单号只能包含字母、数字、下划线和横线") + private String orderNo; + + @Schema(description = "订单标题", required = true) + @NotBlank(message = "订单标题不能为空") + @Size(max = 127, message = "订单标题不能超过127个字符") + private String subject; + + @Schema(description = "订单描述") + @Size(max = 500, message = "订单描述不能超过500个字符") + private String description; + + @Schema(description = "商品ID") + @Positive(message = "商品ID必须为正数") + private Integer goodsId; + + @Schema(description = "购买数量", example = "1") + @Min(value = 1, message = "购买数量必须大于0") + @Max(value = 9999, message = "购买数量不能超过9999") + private Integer quantity = 1; + + @Schema(description = "订单类型", example = "0") + @Min(value = 0, message = "订单类型不能为负数") + private Integer orderType = 0; + + @Schema(description = "客户端IP地址") + private String clientIp; + + @Schema(description = "用户代理") + private String userAgent; + + @Schema(description = "回调通知URL") + private String notifyUrl; + + @Schema(description = "支付成功跳转URL") + private String returnUrl; + + @Schema(description = "支付取消跳转URL") + private String cancelUrl; + + @Schema(description = "订单超时时间(分钟)", example = "30") + @Min(value = 1, message = "订单超时时间必须大于0分钟") + @Max(value = 1440, message = "订单超时时间不能超过1440分钟(24小时)") + private Integer timeoutMinutes = 30; + + @Schema(description = "买家备注") + @Size(max = 500, message = "买家备注不能超过500个字符") + private String buyerRemarks; + + @Schema(description = "商户备注") + @Size(max = 500, message = "商户备注不能超过500个字符") + private String merchantRemarks; + + @Schema(description = "收货地址ID") + @Positive(message = "收货地址ID必须为正数") + private Integer addressId; + + @Schema(description = "扩展参数") + private Map extraParams; + + // 微信支付特有参数 + @Schema(description = "微信OpenID(JSAPI支付必填)") + private String openId; + + @Schema(description = "微信UnionID") + private String unionId; + + // 支付宝特有参数 + @Schema(description = "支付宝用户ID") + private String alipayUserId; + + @Schema(description = "花呗分期数") + private Integer hbFqNum; + + // 银联支付特有参数 + @Schema(description = "银行卡号") + private String cardNo; + + @Schema(description = "银行代码") + private String bankCode; + + /** + * 获取有效的支付渠道 + */ + public PaymentChannel getEffectivePaymentChannel() { + if (paymentChannel != null) { + return paymentChannel; + } + return PaymentChannel.getDefaultByPaymentType(paymentType); + } + + /** + * 获取有效的订单描述 + */ + public String getEffectiveDescription() { + if (description != null && !description.trim().isEmpty()) { + return description.trim(); + } + return subject; + } + + /** + * 获取格式化的金额字符串 + */ + public String getFormattedAmount() { + if (amount == null) { + return "0.00"; + } + return String.format("%.2f", amount); + } + + /** + * 转换为分(微信支付API需要) + */ + public Integer getAmountInCents() { + if (amount == null) { + return 0; + } + return amount.multiply(new BigDecimal(100)).intValue(); + } + + /** + * 验证必要参数是否完整 + */ + public boolean isValid() { + return tenantId != null && tenantId > 0 + && userId != null && userId > 0 + && paymentType != null + && amount != null && amount.compareTo(BigDecimal.ZERO) > 0 + && subject != null && !subject.trim().isEmpty(); + } + + /** + * 验证微信JSAPI支付参数 + */ + public boolean isValidForWechatJsapi() { + return isValid() && paymentType.isWechatPay() && openId != null && !openId.trim().isEmpty(); + } + + /** + * 验证支付宝支付参数 + */ + public boolean isValidForAlipay() { + return isValid() && paymentType == PaymentType.ALIPAY; + } + + /** + * 获取订单超时时间(秒) + */ + public long getTimeoutSeconds() { + return timeoutMinutes * 60L; + } + + @Override + public String toString() { + return String.format("PaymentRequest{tenantId=%d, userId=%d, paymentType=%s, amount=%s, orderNo='%s', subject='%s'}", + tenantId, userId, paymentType, getFormattedAmount(), orderNo, subject); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentResponse.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentResponse.java new file mode 100644 index 0000000..dea992f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentResponse.java @@ -0,0 +1,294 @@ +package com.gxwebsoft.payment.dto; + +import com.gxwebsoft.payment.enums.PaymentChannel; +import com.gxwebsoft.payment.enums.PaymentStatus; +import com.gxwebsoft.payment.enums.PaymentType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 统一支付响应DTO + * 支持所有支付方式的统一响应格式 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Data +@Schema(name = "统一支付响应", description = "支持所有支付方式的统一支付响应") +public class PaymentResponse { + + @Schema(description = "是否成功") + private Boolean success; + + @Schema(description = "错误代码") + private String errorCode; + + @Schema(description = "错误信息") + private String errorMessage; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "第三方交易号") + private String transactionId; + + @Schema(description = "支付类型") + private PaymentType paymentType; + + @Schema(description = "支付渠道") + private PaymentChannel paymentChannel; + + @Schema(description = "支付状态") + private PaymentStatus paymentStatus; + + @Schema(description = "支付金额") + private BigDecimal amount; + + @Schema(description = "实际支付金额") + private BigDecimal paidAmount; + + @Schema(description = "货币类型") + private String currency; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "支付时间") + private LocalDateTime payTime; + + @Schema(description = "过期时间") + private LocalDateTime expireTime; + + // 微信支付特有字段 + @Schema(description = "微信支付二维码URL(Native支付)") + private String codeUrl; + + @Schema(description = "微信支付参数(JSAPI支付)") + private WechatPayParams wechatPayParams; + + @Schema(description = "微信H5支付URL") + private String h5Url; + + // 支付宝特有字段 + @Schema(description = "支付宝支付表单(网页支付)") + private String alipayForm; + + @Schema(description = "支付宝支付URL(手机网站支付)") + private String alipayUrl; + + @Schema(description = "支付宝支付参数(APP支付)") + private String alipayParams; + + // 银联支付特有字段 + @Schema(description = "银联支付表单") + private String unionPayForm; + + @Schema(description = "银联支付URL") + private String unionPayUrl; + + @Schema(description = "扩展参数") + private Map extraParams; + + /** + * 微信支付参数 + */ + @Data + @Schema(name = "微信支付参数", description = "微信JSAPI支付所需参数") + public static class WechatPayParams { + @Schema(description = "应用ID") + private String appId; + + @Schema(description = "时间戳") + private String timeStamp; + + @Schema(description = "随机字符串") + private String nonceStr; + + @Schema(description = "订单详情扩展字符串") + private String packageValue; + + @Schema(description = "签名方式") + private String signType; + + @Schema(description = "签名") + private String paySign; + } + + /** + * 创建成功响应 + */ + public static PaymentResponse success(String orderNo, PaymentType paymentType) { + PaymentResponse response = new PaymentResponse(); + response.setSuccess(true); + response.setOrderNo(orderNo); + response.setPaymentType(paymentType); + response.setPaymentStatus(PaymentStatus.PENDING); + response.setCreateTime(LocalDateTime.now()); + return response; + } + + /** + * 创建失败响应 + */ + public static PaymentResponse failure(String errorCode, String errorMessage) { + PaymentResponse response = new PaymentResponse(); + response.setSuccess(false); + response.setErrorCode(errorCode); + response.setErrorMessage(errorMessage); + return response; + } + + /** + * 创建微信Native支付响应 + */ + public static PaymentResponse wechatNative(String orderNo, String codeUrl, BigDecimal amount, Integer tenantId) { + PaymentResponse response = success(orderNo, PaymentType.WECHAT_NATIVE); + response.setCodeUrl(codeUrl); + response.setPaymentChannel(PaymentChannel.WECHAT_NATIVE); + response.setAmount(amount); + response.setTenantId(tenantId); + response.setCurrency("CNY"); + return response; + } + + /** + * 创建微信JSAPI支付响应 + */ + public static PaymentResponse wechatJsapi(String orderNo, WechatPayParams payParams, BigDecimal amount, Integer tenantId) { + PaymentResponse response = success(orderNo, PaymentType.WECHAT); + response.setWechatPayParams(payParams); + response.setPaymentChannel(PaymentChannel.WECHAT_JSAPI); + response.setAmount(amount); + response.setTenantId(tenantId); + response.setCurrency("CNY"); + return response; + } + + /** + * 创建微信H5支付响应 + */ + public static PaymentResponse wechatH5(String orderNo, String h5Url, BigDecimal amount, Integer tenantId) { + PaymentResponse response = success(orderNo, PaymentType.WECHAT); + response.setH5Url(h5Url); + response.setPaymentChannel(PaymentChannel.WECHAT_H5); + response.setAmount(amount); + response.setTenantId(tenantId); + response.setCurrency("CNY"); + return response; + } + + /** + * 创建支付宝网页支付响应 + */ + public static PaymentResponse alipayWeb(String orderNo, String alipayForm, BigDecimal amount, Integer tenantId) { + PaymentResponse response = success(orderNo, PaymentType.ALIPAY); + response.setAlipayForm(alipayForm); + response.setPaymentChannel(PaymentChannel.ALIPAY_WEB); + response.setAmount(amount); + response.setTenantId(tenantId); + response.setCurrency("CNY"); + return response; + } + + /** + * 创建支付宝手机网站支付响应 + */ + public static PaymentResponse alipayWap(String orderNo, String alipayUrl, BigDecimal amount, Integer tenantId) { + PaymentResponse response = success(orderNo, PaymentType.ALIPAY); + response.setAlipayUrl(alipayUrl); + response.setPaymentChannel(PaymentChannel.ALIPAY_WAP); + response.setAmount(amount); + response.setTenantId(tenantId); + response.setCurrency("CNY"); + return response; + } + + /** + * 创建支付宝APP支付响应 + */ + public static PaymentResponse alipayApp(String orderNo, String alipayParams, BigDecimal amount, Integer tenantId) { + PaymentResponse response = success(orderNo, PaymentType.ALIPAY); + response.setAlipayParams(alipayParams); + response.setPaymentChannel(PaymentChannel.ALIPAY_APP); + response.setAmount(amount); + response.setTenantId(tenantId); + response.setCurrency("CNY"); + return response; + } + + /** + * 创建余额支付响应 + */ + public static PaymentResponse balance(String orderNo, BigDecimal amount, Integer tenantId, Integer userId) { + PaymentResponse response = success(orderNo, PaymentType.BALANCE); + response.setPaymentChannel(PaymentChannel.BALANCE); + response.setPaymentStatus(PaymentStatus.SUCCESS); + response.setAmount(amount); + response.setPaidAmount(amount); + response.setTenantId(tenantId); + response.setUserId(userId); + response.setCurrency("CNY"); + response.setPayTime(LocalDateTime.now()); + return response; + } + + /** + * 判断是否为成功响应 + */ + public boolean isSuccess() { + return Boolean.TRUE.equals(success); + } + + /** + * 判断是否需要用户进一步操作 + */ + public boolean needUserAction() { + return isSuccess() && paymentStatus == PaymentStatus.PENDING; + } + + /** + * 获取支付结果描述 + */ + public String getResultDescription() { + if (!isSuccess()) { + return errorMessage != null ? errorMessage : "支付失败"; + } + + if (paymentStatus == null) { + return "支付状态未知"; + } + + switch (paymentStatus) { + case SUCCESS: + return "支付成功"; + case PENDING: + return "等待支付"; + case PROCESSING: + return "支付处理中"; + case FAILED: + return "支付失败"; + case CANCELLED: + return "支付已取消"; + case TIMEOUT: + return "支付超时"; + default: + return paymentStatus.getName(); + } + } + + @Override + public String toString() { + return String.format("PaymentResponse{success=%s, orderNo='%s', paymentType=%s, paymentStatus=%s, amount=%s}", + success, orderNo, paymentType, paymentStatus, amount); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentStatusUpdateRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentStatusUpdateRequest.java new file mode 100644 index 0000000..5cee3bc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentStatusUpdateRequest.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.payment.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; + +/** + * 支付状态更新请求DTO + * 用于手动更新支付状态的请求参数 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Data +@Schema(name = "支付状态更新请求", description = "用于手动更新支付状态") +public class PaymentStatusUpdateRequest { + + @Schema(description = "订单号", required = true, example = "ORDER_1756544921075") + @NotBlank(message = "订单号不能为空") + private String orderNo; + + @Schema(description = "租户ID", required = true, example = "10398") + @NotNull(message = "租户ID不能为空") + @Positive(message = "租户ID必须为正数") + private Integer tenantId; + + @Schema(description = "第三方交易号", example = "4200001234567890123") + private String transactionId; + + @Schema(description = "支付时间", example = "2025-01-26T10:30:00") + private String payTime; + + @Override + public String toString() { + return String.format("PaymentStatusUpdateRequest{orderNo='%s', tenantId=%d, transactionId='%s', payTime='%s'}", + orderNo, tenantId, transactionId, payTime); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentWithOrderRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentWithOrderRequest.java new file mode 100644 index 0000000..06ee407 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/dto/PaymentWithOrderRequest.java @@ -0,0 +1,158 @@ +package com.gxwebsoft.payment.dto; + +import com.gxwebsoft.payment.enums.PaymentType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.math.BigDecimal; +import java.util.List; + +/** + * 支付与订单创建请求DTO + * 用于统一支付模块中的订单创建和支付 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Data +@Schema(name = "PaymentWithOrderRequest", description = "支付与订单创建请求") +public class PaymentWithOrderRequest { + + // ========== 支付相关字段 ========== + + @Schema(description = "支付类型", required = true) + @NotNull(message = "支付类型不能为空") + private PaymentType paymentType; + + @Schema(description = "支付金额", required = true) + @NotNull(message = "支付金额不能为空") + @DecimalMin(value = "0.01", message = "支付金额必须大于0") + @Digits(integer = 10, fraction = 2, message = "支付金额格式不正确") + private BigDecimal amount; + + @Schema(description = "订单标题", required = true) + @NotBlank(message = "订单标题不能为空") + @Size(max = 60, message = "订单标题长度不能超过60个字符") + private String subject; + + @Schema(description = "订单描述") + @Size(max = 500, message = "订单描述长度不能超过500个字符") + private String description; + + @Schema(description = "租户ID", required = true) + @NotNull(message = "租户ID不能为空") + @Positive(message = "租户ID必须为正数") + private Integer tenantId; + + // ========== 订单相关字段 ========== + + @Schema(description = "订单信息", required = true) + @Valid + @NotNull(message = "订单信息不能为空") + private OrderInfo orderInfo; + + /** + * 订单信息 + */ + @Data + @Schema(name = "OrderInfo", description = "订单信息") + public static class OrderInfo { + + @Schema(description = "订单类型,0商城订单 1预定订单/外卖 2会员卡") + @NotNull(message = "订单类型不能为空") + @Min(value = 0, message = "订单类型值无效") + @Max(value = 2, message = "订单类型值无效") + private Integer type; + + @Schema(description = "收货人姓名") + @Size(max = 50, message = "收货人姓名长度不能超过50个字符") + private String realName; + + @Schema(description = "收货地址") + @Size(max = 200, message = "收货地址长度不能超过200个字符") + private String address; + + @Schema(description = "关联收货地址ID") + private Integer addressId; + + @Schema(description = "快递/自提,0快递 1自提") + private Integer deliveryType; + + @Schema(description = "下单渠道,0小程序预定 1俱乐部训练场 3活动订场") + private Integer channel; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "使用的优惠券ID") + private Integer couponId; + + @Schema(description = "备注") + @Size(max = 500, message = "备注长度不能超过500字符") + private String comments; + + @Schema(description = "订单商品列表", required = true) + @Valid + @NotEmpty(message = "订单商品列表不能为空") + private List goodsItems; + } + + /** + * 订单商品项 + */ + @Data + @Schema(name = "OrderGoodsItem", description = "订单商品项") + public static class OrderGoodsItem { + + @Schema(description = "商品ID", required = true) + @NotNull(message = "商品ID不能为空") + @Positive(message = "商品ID必须为正数") + private Integer goodsId; + + @Schema(description = "商品SKU ID") + private Integer skuId; + + @Schema(description = "商品数量", required = true) + @NotNull(message = "商品数量不能为空") + @Min(value = 1, message = "商品数量必须大于0") + private Integer quantity; + + @Schema(description = "规格信息,如:颜色:红色|尺寸:L") + private String specInfo; + } + + /** + * 获取格式化的金额字符串 + */ + public String getFormattedAmount() { + if (amount == null) { + return "0.00"; + } + return String.format("%.2f", amount); + } + + /** + * 验证订单商品总金额是否与支付金额一致 + */ + public boolean isAmountConsistent() { + if (amount == null || orderInfo == null || orderInfo.getGoodsItems() == null) { + return false; + } + + // 这里可以添加商品金额计算逻辑 + // 实际实现时需要查询数据库获取商品价格 + return true; + } + + @Override + public String toString() { + return String.format("PaymentWithOrderRequest{paymentType=%s, amount=%s, subject='%s', tenantId=%d, goodsCount=%d}", + paymentType, getFormattedAmount(), subject, tenantId, + orderInfo != null && orderInfo.getGoodsItems() != null ? orderInfo.getGoodsItems().size() : 0); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentChannel.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentChannel.java new file mode 100644 index 0000000..f7396a0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentChannel.java @@ -0,0 +1,159 @@ +package com.gxwebsoft.payment.enums; + +/** + * 支付渠道枚举 + * 定义具体的支付渠道类型 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public enum PaymentChannel { + + /** 微信JSAPI支付 */ + WECHAT_JSAPI("wechat_jsapi", "微信JSAPI支付", PaymentType.WECHAT), + + /** 微信Native支付 */ + WECHAT_NATIVE("wechat_native", "微信Native支付", PaymentType.WECHAT_NATIVE), + + /** 微信H5支付 */ + WECHAT_H5("wechat_h5", "微信H5支付", PaymentType.WECHAT), + + /** 微信APP支付 */ + WECHAT_APP("wechat_app", "微信APP支付", PaymentType.WECHAT), + + /** 微信小程序支付 */ + WECHAT_MINI("wechat_mini", "微信小程序支付", PaymentType.WECHAT), + + /** 支付宝网页支付 */ + ALIPAY_WEB("alipay_web", "支付宝网页支付", PaymentType.ALIPAY), + + /** 支付宝手机网站支付 */ + ALIPAY_WAP("alipay_wap", "支付宝手机网站支付", PaymentType.ALIPAY), + + /** 支付宝APP支付 */ + ALIPAY_APP("alipay_app", "支付宝APP支付", PaymentType.ALIPAY), + + /** 支付宝小程序支付 */ + ALIPAY_MINI("alipay_mini", "支付宝小程序支付", PaymentType.ALIPAY), + + /** 银联网关支付 */ + UNION_WEB("union_web", "银联网关支付", PaymentType.UNION_PAY), + + /** 银联手机支付 */ + UNION_WAP("union_wap", "银联手机支付", PaymentType.UNION_PAY), + + /** 余额支付 */ + BALANCE("balance", "余额支付", PaymentType.BALANCE), + + /** 现金支付 */ + CASH("cash", "现金支付", PaymentType.CASH), + + /** POS机支付 */ + POS("pos", "POS机支付", PaymentType.POS); + + private final String code; + private final String name; + private final PaymentType paymentType; + + PaymentChannel(String code, String name, PaymentType paymentType) { + this.code = code; + this.name = name; + this.paymentType = paymentType; + } + + public String getCode() { + return code; + } + + public String getName() { + return name; + } + + public PaymentType getPaymentType() { + return paymentType; + } + + /** + * 根据代码获取支付渠道 + */ + public static PaymentChannel getByCode(String code) { + if (code == null) { + return null; + } + for (PaymentChannel channel : values()) { + if (channel.code.equals(code)) { + return channel; + } + } + return null; + } + + /** + * 根据支付类型获取默认渠道 + */ + public static PaymentChannel getDefaultByPaymentType(PaymentType paymentType) { + if (paymentType == null) { + return null; + } + + switch (paymentType) { + case WECHAT: + return WECHAT_JSAPI; + case WECHAT_NATIVE: + return WECHAT_NATIVE; + case ALIPAY: + return ALIPAY_WEB; + case UNION_PAY: + return UNION_WEB; + case BALANCE: + return BALANCE; + case CASH: + return CASH; + case POS: + return POS; + default: + return null; + } + } + + /** + * 是否为微信支付渠道 + */ + public boolean isWechatChannel() { + return paymentType.isWechatPay(); + } + + /** + * 是否为支付宝支付渠道 + */ + public boolean isAlipayChannel() { + return paymentType == PaymentType.ALIPAY; + } + + /** + * 是否为银联支付渠道 + */ + public boolean isUnionPayChannel() { + return paymentType == PaymentType.UNION_PAY; + } + + /** + * 是否为第三方支付渠道 + */ + public boolean isThirdPartyChannel() { + return paymentType.isThirdPartyPay(); + } + + /** + * 是否支持退款 + */ + public boolean supportRefund() { + return isThirdPartyChannel(); + } + + @Override + public String toString() { + return String.format("PaymentChannel{code='%s', name='%s', paymentType=%s}", + code, name, paymentType); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentStatus.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentStatus.java new file mode 100644 index 0000000..809bd9a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentStatus.java @@ -0,0 +1,141 @@ +package com.gxwebsoft.payment.enums; + +/** + * 支付状态枚举 + * 定义支付过程中的各种状态 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public enum PaymentStatus { + + /** 待支付 */ + PENDING(0, "待支付", "PENDING"), + + /** 支付中 */ + PROCESSING(1, "支付中", "PROCESSING"), + + /** 支付成功 */ + SUCCESS(2, "支付成功", "SUCCESS"), + + /** 支付失败 */ + FAILED(3, "支付失败", "FAILED"), + + /** 支付取消 */ + CANCELLED(4, "支付取消", "CANCELLED"), + + /** 支付超时 */ + TIMEOUT(5, "支付超时", "TIMEOUT"), + + /** 退款中 */ + REFUNDING(6, "退款中", "REFUNDING"), + + /** 退款成功 */ + REFUNDED(7, "退款成功", "REFUNDED"), + + /** 退款失败 */ + REFUND_FAILED(8, "退款失败", "REFUND_FAILED"), + + /** 部分退款 */ + PARTIAL_REFUNDED(9, "部分退款", "PARTIAL_REFUNDED"); + + private final Integer code; + private final String name; + private final String status; + + PaymentStatus(Integer code, String name, String status) { + this.code = code; + this.name = name; + this.status = status; + } + + public Integer getCode() { + return code; + } + + public String getName() { + return name; + } + + public String getStatus() { + return status; + } + + /** + * 根据代码获取支付状态 + */ + public static PaymentStatus getByCode(Integer code) { + if (code == null) { + return null; + } + for (PaymentStatus status : values()) { + if (status.code.equals(code)) { + return status; + } + } + return null; + } + + /** + * 根据状态字符串获取支付状态 + */ + public static PaymentStatus getByStatus(String status) { + if (status == null) { + return null; + } + for (PaymentStatus paymentStatus : values()) { + if (paymentStatus.status.equals(status)) { + return paymentStatus; + } + } + return null; + } + + /** + * 是否为最终状态(不会再变化) + */ + public boolean isFinalStatus() { + return this == SUCCESS || this == FAILED || this == CANCELLED || + this == TIMEOUT || this == REFUNDED || this == REFUND_FAILED; + } + + /** + * 是否为成功状态 + */ + public boolean isSuccessStatus() { + return this == SUCCESS; + } + + /** + * 是否为失败状态 + */ + public boolean isFailedStatus() { + return this == FAILED || this == CANCELLED || this == TIMEOUT || this == REFUND_FAILED; + } + + /** + * 是否为退款相关状态 + */ + public boolean isRefundStatus() { + return this == REFUNDING || this == REFUNDED || this == REFUND_FAILED || this == PARTIAL_REFUNDED; + } + + /** + * 是否可以退款 + */ + public boolean canRefund() { + return this == SUCCESS || this == PARTIAL_REFUNDED; + } + + /** + * 是否可以取消 + */ + public boolean canCancel() { + return this == PENDING || this == PROCESSING; + } + + @Override + public String toString() { + return String.format("PaymentStatus{code=%d, name='%s', status='%s'}", code, name, status); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentType.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentType.java new file mode 100644 index 0000000..946b7ba --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/enums/PaymentType.java @@ -0,0 +1,224 @@ +package com.gxwebsoft.payment.enums; + +/** + * 支付类型枚举 + * 定义系统支持的所有支付方式 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public enum PaymentType { + + /** 余额支付 */ + BALANCE(0, "余额支付", "balance"), + + /** 微信支付(包含JSAPI和Native) */ + WECHAT(1, "微信支付", "wechat"), + + /** 支付宝支付 */ + ALIPAY(2, "支付宝支付", "alipay"), + + /** 银联支付 */ + UNION_PAY(3, "银联支付", "union_pay"), + + /** 现金支付 */ + CASH(4, "现金支付", "cash"), + + /** POS机支付 */ + POS(5, "POS机支付", "pos"), + + /** 免费 */ + FREE(6, "免费", "free"), + + /** 积分支付 */ + POINTS(7, "积分支付", "points"), + + // ========== 已废弃的支付方式(保留用于数据兼容) ========== + + /** @deprecated 微信Native支付 - 已合并到WECHAT */ + @Deprecated + WECHAT_NATIVE(102, "微信Native支付", "wechat_native"), + + /** @deprecated 会员卡支付 - 建议使用余额支付 */ + @Deprecated + MEMBER_CARD_OLD(8, "会员卡支付", "member_card"), + + /** @deprecated VIP月卡 - 建议使用余额支付 */ + @Deprecated + VIP_MONTHLY(9, "VIP月卡", "vip_monthly"), + + /** @deprecated VIP年卡 - 建议使用余额支付 */ + @Deprecated + VIP_YEARLY(10, "VIP年卡", "vip_yearly"), + + /** @deprecated VIP次卡 - 建议使用余额支付 */ + @Deprecated + VIP_COUNT(11, "VIP次卡", "vip_count"), + + /** @deprecated 免费(旧编号) - 已迁移到新编号6 */ + @Deprecated + FREE_OLD(12, "免费", "free"), + + /** @deprecated VIP充值卡 - 建议使用余额支付 */ + @Deprecated + VIP_RECHARGE(13, "VIP充值卡", "vip_recharge"), + + /** @deprecated IC充值卡 - 建议使用余额支付 */ + @Deprecated + IC_RECHARGE(14, "IC充值卡", "ic_recharge"), + + /** @deprecated 积分支付(旧编号) - 已迁移到新编号7 */ + @Deprecated + POINTS_OLD(15, "积分支付", "points"), + + /** @deprecated VIP季卡 - 建议使用余额支付 */ + @Deprecated + VIP_QUARTERLY(16, "VIP季卡", "vip_quarterly"), + + /** @deprecated IC月卡 - 建议使用余额支付 */ + @Deprecated + IC_MONTHLY(17, "IC月卡", "ic_monthly"), + + /** @deprecated IC年卡 - 建议使用余额支付 */ + @Deprecated + IC_YEARLY(18, "IC年卡", "ic_yearly"), + + /** @deprecated IC次卡 - 建议使用余额支付 */ + @Deprecated + IC_COUNT(19, "IC次卡", "ic_count"), + + /** @deprecated IC季卡 - 建议使用余额支付 */ + @Deprecated + IC_QUARTERLY(20, "IC季卡", "ic_quarterly"), + + /** @deprecated 代付 - 建议通过业务逻辑实现 */ + @Deprecated + PROXY_PAY(21, "代付", "proxy_pay"), + + /** @deprecated 支付宝(旧编号) - 已迁移到新编号2 */ + @Deprecated + ALIPAY_OLD(22, "支付宝支付", "alipay"), + + /** @deprecated 银联支付(旧编号) - 已迁移到新编号3 */ + @Deprecated + UNION_PAY_OLD(23, "银联支付", "union_pay"); + + private final Integer code; + private final String name; + private final String channel; + + PaymentType(Integer code, String name, String channel) { + this.code = code; + this.name = name; + this.channel = channel; + } + + public Integer getCode() { + return code; + } + + public String getName() { + return name; + } + + public String getChannel() { + return channel; + } + + /** + * 根据代码获取支付类型 + */ + public static PaymentType getByCode(Integer code) { + if (code == null) { + return null; + } + for (PaymentType type : values()) { + if (type.code.equals(code)) { + return type; + } + } + return null; + } + + /** + * 根据渠道获取支付类型 + */ + public static PaymentType getByChannel(String channel) { + if (channel == null) { + return null; + } + for (PaymentType type : values()) { + if (type.channel.equals(channel)) { + return type; + } + } + return null; + } + + /** + * 是否为微信支付类型 + */ + public boolean isWechatPay() { + return this == WECHAT || this == WECHAT_NATIVE; + } + + /** + * 获取微信支付的具体类型 + * @param openid 用户openid + * @return JSAPI 或 NATIVE + */ + public String getWechatPayType(String openid) { + if (!isWechatPay()) { + return null; + } + + // 有openid使用JSAPI,无openid使用Native + return (openid != null && !openid.trim().isEmpty()) ? "JSAPI" : "NATIVE"; + } + + /** + * 是否为第三方支付 + */ + public boolean isThirdPartyPay() { + return isWechatPay() || this == ALIPAY || this == UNION_PAY; + } + + /** + * 是否需要在线支付 + */ + public boolean isOnlinePay() { + return isThirdPartyPay(); + } + + /** + * 是否为卡类支付(已废弃的支付方式) + * @deprecated 卡类支付已废弃,建议使用余额支付 + */ + @Deprecated + public boolean isCardPay() { + return this == MEMBER_CARD_OLD || + this == VIP_MONTHLY || this == VIP_YEARLY || this == VIP_COUNT || this == VIP_QUARTERLY || + this == IC_MONTHLY || this == IC_YEARLY || this == IC_COUNT || this == IC_QUARTERLY || + this == VIP_RECHARGE; + } + + /** + * 是否为推荐使用的核心支付方式 + */ + public boolean isCorePaymentType() { + return this == BALANCE || this == WECHAT || this == ALIPAY || this == UNION_PAY || + this == CASH || this == POS || this == FREE || this == POINTS; + } + + /** + * 是否为已废弃的支付方式 + */ + public boolean isDeprecated() { + return !isCorePaymentType(); + } + + @Override + public String toString() { + return String.format("PaymentType{code=%d, name='%s', channel='%s'}", code, name, channel); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/exception/PaymentException.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/exception/PaymentException.java new file mode 100644 index 0000000..35d2ac3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/exception/PaymentException.java @@ -0,0 +1,221 @@ +package com.gxwebsoft.payment.exception; + +import com.gxwebsoft.payment.enums.PaymentType; + +/** + * 支付异常基类 + * 统一处理支付相关的业务异常 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public class PaymentException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * 错误代码 + */ + private String errorCode; + + /** + * 支付类型 + */ + private PaymentType paymentType; + + /** + * 租户ID + */ + private Integer tenantId; + + /** + * 订单号 + */ + private String orderNo; + + public PaymentException(String message) { + super(message); + } + + public PaymentException(String message, Throwable cause) { + super(message, cause); + } + + public PaymentException(String errorCode, String message) { + super(message); + this.errorCode = errorCode; + } + + public PaymentException(String errorCode, String message, Throwable cause) { + super(message, cause); + this.errorCode = errorCode; + } + + public PaymentException(String errorCode, String message, PaymentType paymentType) { + super(message); + this.errorCode = errorCode; + this.paymentType = paymentType; + } + + public PaymentException(String errorCode, String message, PaymentType paymentType, Integer tenantId) { + super(message); + this.errorCode = errorCode; + this.paymentType = paymentType; + this.tenantId = tenantId; + } + + public PaymentException(String errorCode, String message, PaymentType paymentType, Integer tenantId, String orderNo) { + super(message); + this.errorCode = errorCode; + this.paymentType = paymentType; + this.tenantId = tenantId; + this.orderNo = orderNo; + } + + // Getters and Setters + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public PaymentType getPaymentType() { + return paymentType; + } + + public void setPaymentType(PaymentType paymentType) { + this.paymentType = paymentType; + } + + public Integer getTenantId() { + return tenantId; + } + + public void setTenantId(Integer tenantId) { + this.tenantId = tenantId; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("PaymentException{"); + if (errorCode != null) { + sb.append("errorCode='").append(errorCode).append("', "); + } + if (paymentType != null) { + sb.append("paymentType=").append(paymentType).append(", "); + } + if (tenantId != null) { + sb.append("tenantId=").append(tenantId).append(", "); + } + if (orderNo != null) { + sb.append("orderNo='").append(orderNo).append("', "); + } + sb.append("message='").append(getMessage()).append("'"); + sb.append("}"); + return sb.toString(); + } + + /** + * 支付错误代码常量 + */ + public static class ErrorCode { + /** 参数错误 */ + public static final String PARAM_ERROR = "PARAM_ERROR"; + /** 配置错误 */ + public static final String CONFIG_ERROR = "CONFIG_ERROR"; + /** 证书错误 */ + public static final String CERTIFICATE_ERROR = "CERTIFICATE_ERROR"; + /** 网络错误 */ + public static final String NETWORK_ERROR = "NETWORK_ERROR"; + /** 签名错误 */ + public static final String SIGNATURE_ERROR = "SIGNATURE_ERROR"; + /** 金额错误 */ + public static final String AMOUNT_ERROR = "AMOUNT_ERROR"; + /** 订单错误 */ + public static final String ORDER_ERROR = "ORDER_ERROR"; + /** 状态错误 */ + public static final String STATUS_ERROR = "STATUS_ERROR"; + /** 余额不足 */ + public static final String INSUFFICIENT_BALANCE = "INSUFFICIENT_BALANCE"; + /** 支付超时 */ + public static final String TIMEOUT_ERROR = "TIMEOUT_ERROR"; + /** 重复支付 */ + public static final String DUPLICATE_PAYMENT = "DUPLICATE_PAYMENT"; + /** 不支持的支付方式 */ + public static final String UNSUPPORTED_PAYMENT = "UNSUPPORTED_PAYMENT"; + /** 系统错误 */ + public static final String SYSTEM_ERROR = "SYSTEM_ERROR"; + } + + // 静态工厂方法 + public static PaymentException paramError(String message) { + return new PaymentException(ErrorCode.PARAM_ERROR, message); + } + + public static PaymentException configError(String message, PaymentType paymentType, Integer tenantId) { + return new PaymentException(ErrorCode.CONFIG_ERROR, message, paymentType, tenantId); + } + + public static PaymentException certificateError(String message, PaymentType paymentType) { + return new PaymentException(ErrorCode.CERTIFICATE_ERROR, message, paymentType); + } + + public static PaymentException networkError(String message, PaymentType paymentType, Throwable cause) { + return new PaymentException(ErrorCode.NETWORK_ERROR, message, cause); + } + + public static PaymentException signatureError(String message, PaymentType paymentType) { + return new PaymentException(ErrorCode.SIGNATURE_ERROR, message, paymentType); + } + + public static PaymentException amountError(String message) { + return new PaymentException(ErrorCode.AMOUNT_ERROR, message); + } + + public static PaymentException orderError(String message, String orderNo) { + PaymentException exception = new PaymentException(ErrorCode.ORDER_ERROR, message); + exception.setOrderNo(orderNo); + return exception; + } + + public static PaymentException statusError(String message, String orderNo) { + PaymentException exception = new PaymentException(ErrorCode.STATUS_ERROR, message); + exception.setOrderNo(orderNo); + return exception; + } + + public static PaymentException insufficientBalance(String message, Integer tenantId) { + return new PaymentException(ErrorCode.INSUFFICIENT_BALANCE, message, PaymentType.BALANCE, tenantId); + } + + public static PaymentException timeoutError(String message, PaymentType paymentType, String orderNo) { + PaymentException exception = new PaymentException(ErrorCode.TIMEOUT_ERROR, message, paymentType); + exception.setOrderNo(orderNo); + return exception; + } + + public static PaymentException duplicatePayment(String message, String orderNo) { + PaymentException exception = new PaymentException(ErrorCode.DUPLICATE_PAYMENT, message); + exception.setOrderNo(orderNo); + return exception; + } + + public static PaymentException unsupportedPayment(String message, PaymentType paymentType) { + return new PaymentException(ErrorCode.UNSUPPORTED_PAYMENT, message, paymentType); + } + + public static PaymentException systemError(String message, Throwable cause) { + return new PaymentException(ErrorCode.SYSTEM_ERROR, message, cause); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/exception/PaymentExceptionHandler.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/exception/PaymentExceptionHandler.java new file mode 100644 index 0000000..04c6cda --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/exception/PaymentExceptionHandler.java @@ -0,0 +1,153 @@ +package com.gxwebsoft.payment.exception; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.payment.constants.PaymentConstants; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 统一支付异常处理器 + * 处理所有支付相关的异常和参数验证异常 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@RestControllerAdvice(basePackages = {"com.gxwebsoft.payment.controller", "com.gxwebsoft.shop.controller"}) +public class PaymentExceptionHandler extends BaseController { + + /** + * 处理支付业务异常 + */ + @ExceptionHandler(PaymentException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResult handlePaymentException(PaymentException e) { + log.warn("支付业务异常: {}", e.getMessage()); + + // 记录详细的异常信息 + if (e.getTenantId() != null) { + log.warn("异常租户ID: {}", e.getTenantId()); + } + + if (e.getPaymentType() != null) { + log.warn("异常支付类型: {}", e.getPaymentType()); + } + + if (e.getOrderNo() != null) { + log.warn("异常订单号: {}", e.getOrderNo()); + } + + if (e.getErrorCode() != null) { + log.warn("错误代码: {}", e.getErrorCode()); + } + + return fail(e.getMessage()); + } + + + + /** + * 处理参数验证异常(@Valid注解) + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + List fieldErrors = e.getBindingResult().getFieldErrors(); + + String errorMessage = fieldErrors.stream() + .map(error -> error.getField() + ": " + error.getDefaultMessage()) + .collect(Collectors.joining("; ")); + + log.warn("参数验证失败: {}", errorMessage); + + return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + errorMessage); + } + + /** + * 处理绑定异常 + */ + @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResult handleBindException(BindException e) { + List fieldErrors = e.getBindingResult().getFieldErrors(); + + String errorMessage = fieldErrors.stream() + .map(error -> error.getField() + ": " + error.getDefaultMessage()) + .collect(Collectors.joining("; ")); + + log.warn("数据绑定失败: {}", errorMessage); + + return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + errorMessage); + } + + /** + * 处理约束违反异常(@Validated注解) + */ + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResult handleConstraintViolationException(ConstraintViolationException e) { + Set> violations = e.getConstraintViolations(); + + String errorMessage = violations.stream() + .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage()) + .collect(Collectors.joining("; ")); + + log.warn("约束验证失败: {}", errorMessage); + + return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + errorMessage); + } + + /** + * 处理非法参数异常 + */ + @ExceptionHandler(IllegalArgumentException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResult handleIllegalArgumentException(IllegalArgumentException e) { + log.warn("非法参数异常: {}", e.getMessage()); + return fail(PaymentConstants.ErrorMessage.PARAM_ERROR + ": " + e.getMessage()); + } + + /** + * 处理空指针异常 + */ + @ExceptionHandler(NullPointerException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ApiResult handleNullPointerException(NullPointerException e) { + log.error("空指针异常", e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + + /** + * 处理其他运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ApiResult handleRuntimeException(RuntimeException e) { + log.error("运行时异常: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } + + /** + * 处理其他异常 + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ApiResult handleException(Exception e) { + log.error("未知异常: {}", e.getMessage(), e); + return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/service/PaymentService.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/PaymentService.java new file mode 100644 index 0000000..0f90fd5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/PaymentService.java @@ -0,0 +1,182 @@ +package com.gxwebsoft.payment.service; + +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.payment.dto.PaymentRequest; +import com.gxwebsoft.payment.dto.PaymentResponse; +import com.gxwebsoft.payment.dto.PaymentWithOrderRequest; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.payment.exception.PaymentException; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * 统一支付服务接口 + * 提供所有支付方式的统一入口 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public interface PaymentService { + + /** + * 创建支付订单 + * + * @param request 支付请求 + * @return 支付响应 + * @throws PaymentException 支付创建失败时抛出 + */ + PaymentResponse createPayment(PaymentRequest request) throws PaymentException; + + /** + * 创建支付订单(包含订单信息) + * 统一支付模块:先创建订单,再发起支付 + * + * @param request 支付与订单创建请求 + * @param loginUser 当前登录用户 + * @return 支付响应 + * @throws PaymentException 创建失败时抛出 + */ + PaymentResponse createPaymentWithOrder(PaymentWithOrderRequest request, User loginUser) throws PaymentException; + + /** + * 查询支付状态 + * + * @param orderNo 订单号 + * @param paymentType 支付类型 + * @param tenantId 租户ID + * @return 支付响应 + * @throws PaymentException 查询失败时抛出 + */ + PaymentResponse queryPayment(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException; + + /** + * 处理支付回调通知 + * + * @param paymentType 支付类型 + * @param headers 请求头 + * @param body 请求体 + * @param tenantId 租户ID + * @return 处理结果,返回给第三方的响应内容 + * @throws PaymentException 处理失败时抛出 + */ + String handlePaymentNotify(PaymentType paymentType, Map headers, String body, Integer tenantId) throws PaymentException; + + /** + * 申请退款 + * + * @param orderNo 订单号 + * @param refundNo 退款单号 + * @param paymentType 支付类型 + * @param totalAmount 订单总金额 + * @param refundAmount 退款金额 + * @param reason 退款原因 + * @param tenantId 租户ID + * @return 退款响应 + * @throws PaymentException 退款申请失败时抛出 + */ + PaymentResponse refund(String orderNo, String refundNo, PaymentType paymentType, + BigDecimal totalAmount, BigDecimal refundAmount, + String reason, Integer tenantId) throws PaymentException; + + /** + * 查询退款状态 + * + * @param refundNo 退款单号 + * @param paymentType 支付类型 + * @param tenantId 租户ID + * @return 退款查询响应 + * @throws PaymentException 查询失败时抛出 + */ + PaymentResponse queryRefund(String refundNo, PaymentType paymentType, Integer tenantId) throws PaymentException; + + /** + * 关闭订单 + * + * @param orderNo 订单号 + * @param paymentType 支付类型 + * @param tenantId 租户ID + * @return 关闭结果 + * @throws PaymentException 关闭失败时抛出 + */ + boolean closeOrder(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException; + + /** + * 获取支持的支付类型列表 + * + * @return 支付类型列表 + */ + List getSupportedPaymentTypes(); + + /** + * 检查支付类型是否支持 + * + * @param paymentType 支付类型 + * @return true表示支持 + */ + boolean isPaymentTypeSupported(PaymentType paymentType); + + /** + * 检查支付类型是否支持退款 + * + * @param paymentType 支付类型 + * @return true表示支持退款 + */ + boolean isRefundSupported(PaymentType paymentType); + + /** + * 检查支付类型是否支持查询 + * + * @param paymentType 支付类型 + * @return true表示支持查询 + */ + boolean isQuerySupported(PaymentType paymentType); + + /** + * 检查支付类型是否支持关闭订单 + * + * @param paymentType 支付类型 + * @return true表示支持关闭订单 + */ + boolean isCloseSupported(PaymentType paymentType); + + /** + * 检查支付类型是否需要异步通知 + * + * @param paymentType 支付类型 + * @return true表示需要异步通知 + */ + boolean isNotifyNeeded(PaymentType paymentType); + + /** + * 验证支付请求参数 + * + * @param request 支付请求 + * @throws PaymentException 参数验证失败时抛出 + */ + void validatePaymentRequest(PaymentRequest request) throws PaymentException; + + /** + * 获取支付策略信息 + * + * @param paymentType 支付类型 + * @return 策略信息Map,包含策略名称、描述等 + */ + Map getPaymentStrategyInfo(PaymentType paymentType); + + /** + * 获取所有支付策略信息 + * + * @return 所有策略信息列表 + */ + List> getAllPaymentStrategyInfo(); + + /** + * 检查支付配置 + * + * @param tenantId 租户ID + * @return 配置检查结果 + */ + Map checkPaymentConfig(Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/service/WxPayConfigService.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/WxPayConfigService.java new file mode 100644 index 0000000..7248903 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/WxPayConfigService.java @@ -0,0 +1,382 @@ +package com.gxwebsoft.payment.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.service.CertificateService; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.WxNativeUtil; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.common.system.param.PaymentParam; +import com.gxwebsoft.common.system.service.PaymentService; +import com.gxwebsoft.payment.exception.PaymentException; +import com.gxwebsoft.payment.enums.PaymentType; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * 微信支付配置服务 + * 负责管理微信支付的配置信息和证书 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Service +public class WxPayConfigService { + + @Resource + private RedisUtil redisUtil; + + @Resource + private CertificateService certificateService; + + @Resource + private CertificateProperties certificateProperties; + + @Resource + private PaymentService paymentService; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + /** + * 获取支付配置信息(Payment对象)- 公开方法 + * + * @param tenantId 租户ID + * @return 支付配置信息 + * @throws PaymentException 配置获取失败时抛出 + */ + public Payment getPaymentConfigForStrategy(Integer tenantId) throws PaymentException { + if (tenantId == null) { + throw PaymentException.paramError("租户ID不能为空"); + } + return getPaymentConfig(tenantId); + } + + /** + * 获取微信支付配置 + * + * @param tenantId 租户ID + * @return 微信支付配置 + * @throws PaymentException 配置获取失败时抛出 + */ + public Config getWxPayConfig(Integer tenantId) throws PaymentException { + if (tenantId == null) { + throw PaymentException.paramError("租户ID不能为空"); + } + + // 先从缓存获取已构建的配置 + Config cachedConfig = WxNativeUtil.getConfig(tenantId); + if (cachedConfig != null) { + log.info("从内存缓存获取微信支付配置,租户ID: {}", tenantId); + return cachedConfig; + } + + // 构建新的配置 + log.info("开始构建微信支付配置,租户ID: {}", tenantId); + Config newConfig = buildWxPayConfig(tenantId); + + // 缓存配置 + WxNativeUtil.addConfig(tenantId, newConfig); + log.info("微信支付配置创建并缓存成功,租户ID: {}", tenantId); + + return newConfig; + } + + /** + * 构建微信支付配置 + */ + private Config buildWxPayConfig(Integer tenantId) throws PaymentException { + try { + // 获取支付配置信息 + Payment payment = getPaymentConfig(tenantId); + + // 获取证书文件路径 + String certificatePath = getCertificatePath(tenantId, payment); + + // 创建微信支付配置对象 + return createWxPayConfig(payment, certificatePath); + + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + throw PaymentException.systemError("构建微信支付配置失败: " + e.getMessage(), e); + } + } + + /** + * 获取支付配置信息 + * 优先从缓存获取,缓存没有则查询数据库,最后兜底到开发环境测试配置 + */ + private Payment getPaymentConfig(Integer tenantId) throws PaymentException { + String cacheKey = "Payment:1:" + tenantId; + Payment payment = redisUtil.get(cacheKey, Payment.class); + + if (payment != null) { + log.info("========== 从 Redis 缓存获取 Payment 配置 =========="); + log.info("租户ID: {}", tenantId); + log.info("商户号(mchId): {}", payment.getMchId()); + log.info("AppID: {}", payment.getAppId()); + log.info("商户证书序列号: {}", payment.getMerchantSerialNumber()); + log.info("APIv3密钥: {}", payment.getApiKey() != null ? payment.getApiKey().substring(0, 8) + "****" : "NULL"); + log.info("证书文件: {}", payment.getApiclientKey()); + log.info("=================================================="); + return payment; + } + + log.info("Redis 缓存未命中,租户ID: {},开始查询数据库", tenantId); + + // 缓存中没有,尝试从数据库查询 + try { + final PaymentParam paymentParam = new PaymentParam(); + // 优先使用新的微信支付类型(1 = WECHAT) + paymentParam.setType(PaymentType.WECHAT.getCode()); + paymentParam.setTenantId(tenantId); + + log.debug("查询数据库支付配置,参数: type={}, tenantId={}", paymentParam.getType(), tenantId); + payment = paymentService.getByType(paymentParam); + log.debug("数据库查询结果: {}", payment != null ? "找到配置" : "未找到配置"); + + // 兼容旧数据:如果没有查到,再尝试旧的微信Native类型(102) + if (payment == null) { + paymentParam.setType(PaymentType.WECHAT_NATIVE.getCode()); + log.debug("未找到type=1配置,尝试兼容旧type={}, tenantId={}", paymentParam.getType(), tenantId); + payment = paymentService.getByType(paymentParam); + log.debug("兼容查询结果: {}", payment != null ? "找到配置" : "未找到配置"); + } + + if (payment != null) { + log.info("从数据库获取支付配置成功,租户ID: {},将缓存配置", tenantId); + + // 开发环境下,如果apiclientKey为空,设置默认值 + if ("dev".equals(activeProfile) && + (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty())) { + log.warn("开发环境:数据库配置中apiclientKey为空,使用默认值,租户ID: {}", tenantId); + payment.setApiclientKey("apiclient_key.pem"); + } + + // 将查询到的配置缓存起来,缓存1天 + redisUtil.set(cacheKey, payment, 1L, TimeUnit.DAYS); + return payment; + } else { + log.warn("数据库中未找到支付配置,租户ID: {},已尝试type=1和type=102", tenantId); + } + } catch (Exception e) { + log.error("从数据库查询支付配置失败,租户ID: {},错误: {}", tenantId, e.getMessage(), e); + // 抛出更详细的异常信息 + throw PaymentException.systemError("查询支付配置失败,租户ID: " + tenantId + ",错误: " + e.getMessage(), e); + } + + // 数据库也没有配置 + if (!"dev".equals(activeProfile)) { + throw PaymentException.systemError("微信支付配置未找到,租户ID: " + tenantId + ",请检查数据库配置", null); + } + + log.debug("开发环境模式,将使用测试配置,租户ID: {}", tenantId); + // 开发环境返回测试Payment配置 + return createDevTestPayment(tenantId); + } + + /** + * 获取证书文件路径 + */ + private String getCertificatePath(Integer tenantId, Payment payment) throws PaymentException { + if ("dev".equals(activeProfile)) { + return getDevCertificatePath(tenantId); + } else { + return getProdCertificatePath(payment); + } + } + + /** + * 获取开发环境证书路径 + */ + private String getDevCertificatePath(Integer tenantId) throws PaymentException { + try { + // 根据租户ID构建证书路径 + String certPath = "dev/wechat/" + tenantId + "/apiclient_key.pem"; + ClassPathResource resource = new ClassPathResource(certPath); + + if (!resource.exists()) { + throw PaymentException.systemError("开发环境微信支付证书文件不存在: " + certPath, null); + } + + String absolutePath = resource.getFile().getAbsolutePath(); + log.debug("开发环境证书路径: {}", absolutePath); + return absolutePath; + + } catch (IOException e) { + throw PaymentException.systemError("获取开发环境证书路径失败: " + e.getMessage(), e); + } + } + + /** + * 获取生产环境证书路径 + */ + private String getProdCertificatePath(Payment payment) throws PaymentException { + if (payment == null || payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) { + throw PaymentException.systemError("生产环境支付配置或证书密钥文件为空", null); + } + + try { + // 使用微信支付证书路径 + String certificatePath = certificateService.getWechatPayCertPath(payment.getApiclientKey()); + if (certificatePath == null) { + throw PaymentException.systemError("证书文件路径获取失败,证书文件: " + payment.getApiclientKey(), null); + } + + log.debug("生产环境证书路径: {}", certificatePath); + return certificatePath; + + } catch (Exception e) { + throw PaymentException.systemError("获取生产环境证书路径失败: " + e.getMessage(), e); + } + } + + /** + * 创建微信支付配置对象 + */ + private Config createWxPayConfig(Payment payment, String certificatePath) throws PaymentException { + try { + if ("dev".equals(activeProfile) && payment == null) { + // 开发环境测试配置 + return createDevTestConfig(certificatePath); + } else if (payment != null) { + // 正常配置 + return createNormalConfig(payment, certificatePath); + } else { + throw PaymentException.systemError("无法创建微信支付配置:配置信息不完整", null); + } + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + throw PaymentException.systemError("创建微信支付配置对象失败: " + e.getMessage(), e); + } + } + + /** + * 创建开发环境测试Payment配置 + */ + private Payment createDevTestPayment(Integer tenantId) { + Payment testPayment = new Payment(); + testPayment.setTenantId(tenantId); + testPayment.setType(102); // Native支付 + testPayment.setAppId("wx541db955e7a62709"); // 开发环境测试AppID + testPayment.setMchId("1246610101"); // 租户10550的商户号 + testPayment.setMerchantSerialNumber("754B973F56C0CF9E3B21D950ECAB5ED99063057D"); // 证书序列号 + testPayment.setApiKey("zGufUcqa7ovgxRL0kF5OlPr482EZwtn8"); + testPayment.setApiclientKey("/www/wwwroot/file.ws/wechat/apiclient_key.pem"); // 设置证书文件名 + testPayment.setNotifyUrl("https://websopy-api.websoft.top/api/app/subscription/wx-notify"); + testPayment.setName("微信Native支付-开发环境"); + testPayment.setStatus(true); // 启用 + + log.info("创建开发环境测试Payment配置,租户ID: {}, AppID: {}, 商户号: {}", + tenantId, testPayment.getAppId(), testPayment.getMchId()); + + return testPayment; + } + + /** + * 创建开发环境测试配置 + */ + private Config createDevTestConfig(String certificatePath) throws PaymentException { + String testMerchantId = "1246610101"; // 租户10550的商户号 + String testMerchantSerialNumber = "754B973F56C0CF9E3B21D950ECAB5ED99063057D"; // 证书序列号 + String testApiV3Key = "zGufUcqa7ovgxRL0kF5OlPr482EZwtn8"; + + if (testApiV3Key == null || testApiV3Key.trim().isEmpty()) { + throw PaymentException.systemError("开发环境APIv3密钥未配置", null); + } + + log.info("使用开发环境测试配置"); + log.info("测试商户号: {}", testMerchantId); + log.info("测试序列号: {}", testMerchantSerialNumber); + log.info("证书路径: {}", certificatePath); + log.info("APIv3密钥长度: {}", testApiV3Key.length()); + + return new RSAAutoCertificateConfig.Builder() + .merchantId(testMerchantId) + .privateKeyFromPath(certificatePath) + .merchantSerialNumber(testMerchantSerialNumber) + .apiV3Key(testApiV3Key) + .build(); + } + + /** + * 创建正常配置 + */ + private Config createNormalConfig(Payment payment, String certificatePath) throws PaymentException { + // 验证配置完整性 + validatePaymentConfig(payment); + + // 打印详细配置信息 + log.info("========== 微信支付配置详情 =========="); + log.info("商户号(mchId): {}", payment.getMchId()); + log.info("商户证书序列号(serialNo): {}", payment.getMerchantSerialNumber()); + log.info("APIv3密钥(apiKey): {}", payment.getApiKey() != null ? payment.getApiKey().substring(0, 8) + "****" : "NULL"); + log.info("证书路径(privateKey): {}", certificatePath); + log.info("AppID: {}", payment.getAppId()); + log.info("回调地址(notifyUrl): {}", payment.getNotifyUrl()); + log.info("========================================"); + + return new RSAAutoCertificateConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(certificatePath) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(payment.getApiKey()) + .build(); + } + + /** + * 验证支付配置完整性 + */ + private void validatePaymentConfig(Payment payment) throws PaymentException { + if (payment == null) { + throw PaymentException.systemError("支付配置为空", null); + } + + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + throw PaymentException.systemError("商户号(mchId)未配置", null); + } + + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + throw PaymentException.systemError("商户证书序列号(merchantSerialNumber)未配置", null); + } + + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + throw PaymentException.systemError("APIv3密钥(apiKey)未配置", null); + } + + // 开发环境下,如果apiclientKey为空,给一个警告但不抛异常 + // 生产环境必须有apiclientKey + if (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) { + if ("dev".equals(activeProfile)) { + log.warn("开发环境:证书文件名(apiclientKey)未配置,将使用默认值"); + } else { + throw PaymentException.systemError("证书文件名(apiclientKey)未配置", null); + } + } + + log.debug("支付配置验证通过,租户ID: {}, 商户号: {}", payment.getTenantId(), payment.getMchId()); + } + + /** + * 清除指定租户的配置缓存 + * + * @param tenantId 租户ID + */ + public void clearConfigCache(Integer tenantId) { + WxNativeUtil.addConfig(tenantId, null); + log.info("清除微信支付配置缓存,租户ID: {}", tenantId); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/service/WxPayNotifyService.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/WxPayNotifyService.java new file mode 100644 index 0000000..9378dcd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/WxPayNotifyService.java @@ -0,0 +1,366 @@ +package com.gxwebsoft.payment.service; + + +import com.gxwebsoft.payment.constants.PaymentConstants; +import com.gxwebsoft.payment.exception.PaymentException; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.service.ShopOrderService; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.notification.NotificationConfig; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.core.notification.RequestParam; +import com.wechat.pay.java.service.payments.model.Transaction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 微信支付回调通知处理服务 + * 负责处理微信支付的异步通知回调 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Service +public class WxPayNotifyService { + + @Resource + private WxPayConfigService wxPayConfigService; + + @Resource + private ShopOrderService shopOrderService; + + /** + * 处理微信支付回调通知 + * + * @param headers 请求头 + * @param body 请求体 + * @param tenantId 租户ID + * @return 处理结果响应 + */ + public String handlePaymentNotify(Map headers, String body, Integer tenantId) { + log.info("{}, 租户ID: {}", PaymentConstants.LogMessage.NOTIFY_START, tenantId); + + try { + // 参数验证 + validateNotifyParams(headers, body, tenantId); + + // 获取微信支付配置 + Config wxPayConfig = wxPayConfigService.getWxPayConfig(tenantId); + + // 解析并验证回调数据 + Transaction transaction = parseAndVerifyNotification(headers, body, wxPayConfig); + + // 处理支付结果 + processPaymentResult(transaction, tenantId); + + log.info("{}, 租户ID: {}, 订单号: {}", + PaymentConstants.LogMessage.NOTIFY_SUCCESS, tenantId, transaction.getOutTradeNo()); + + return "SUCCESS"; + + } catch (Exception e) { + log.error("{}, 租户ID: {}, 错误: {}", + PaymentConstants.LogMessage.NOTIFY_FAILED, tenantId, e.getMessage(), e); + return "FAIL"; + } + } + + /** + * 验证回调通知参数 + */ + private void validateNotifyParams(Map headers, String body, Integer tenantId) throws PaymentException { + if (tenantId == null) { + throw PaymentException.paramError("租户ID不能为空"); + } + + if (headers == null || headers.isEmpty()) { + throw PaymentException.paramError("请求头不能为空"); + } + + if (!StringUtils.hasText(body)) { + throw PaymentException.paramError("请求体不能为空"); + } + + // 验证必要的微信支付头部信息 + String signature = headers.get("Wechatpay-Signature"); + String timestamp = headers.get("Wechatpay-Timestamp"); + String nonce = headers.get("Wechatpay-Nonce"); + String serial = headers.get("Wechatpay-Serial"); + + if (!StringUtils.hasText(signature)) { + throw PaymentException.paramError("微信支付签名不能为空"); + } + + if (!StringUtils.hasText(timestamp)) { + throw PaymentException.paramError("微信支付时间戳不能为空"); + } + + if (!StringUtils.hasText(nonce)) { + throw PaymentException.paramError("微信支付随机数不能为空"); + } + + if (!StringUtils.hasText(serial)) { + throw PaymentException.paramError("微信支付序列号不能为空"); + } + + log.debug("回调通知参数验证通过, 租户ID: {}", tenantId); + } + + /** + * 解析并验证回调通知 + */ + private Transaction parseAndVerifyNotification(Map headers, String body, Config wxPayConfig) throws PaymentException { + if (wxPayConfig == null) { + throw PaymentException.systemError("微信支付配置为空", null); + } + + try { + // 构建请求参数 + RequestParam requestParam = new RequestParam.Builder() + .serialNumber(headers.get("Wechatpay-Serial")) + .nonce(headers.get("Wechatpay-Nonce")) + .signature(headers.get("Wechatpay-Signature")) + .timestamp(headers.get("Wechatpay-Timestamp")) + .body(body) + .build(); + + // 创建通知解析器 + NotificationParser parser = new NotificationParser((NotificationConfig) wxPayConfig); + + // 解析并验证通知 + Transaction transaction = parser.parse(requestParam, Transaction.class); + + if (transaction == null) { + throw PaymentException.systemError("解析回调通知失败:transaction为空", null); + } + + log.debug("回调通知解析成功, 订单号: {}, 交易状态: {}", + transaction.getOutTradeNo(), transaction.getTradeState()); + + return transaction; + + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + throw PaymentException.systemError("解析回调通知失败: " + e.getMessage(), e); + } + } + + /** + * 处理支付结果 + */ + private void processPaymentResult(Transaction transaction, Integer tenantId) throws PaymentException { + String outTradeNo = transaction.getOutTradeNo(); + String tradeState = String.valueOf(transaction.getTradeState()); + + if (!StringUtils.hasText(outTradeNo)) { + throw PaymentException.paramError("商户订单号不能为空"); + } + + // 查询订单 + ShopOrder order = shopOrderService.getByOutTradeNo(outTradeNo); + if (order == null) { + throw PaymentException.systemError("订单不存在: " + outTradeNo, null); + } + + // 验证租户ID + if (!tenantId.equals(order.getTenantId())) { + throw PaymentException.paramError("订单租户ID不匹配"); + } + + // 验证订单状态 - 使用Boolean类型的payStatus字段 + if (Boolean.TRUE.equals(order.getPayStatus())) { + log.info("订单已支付,跳过处理, 订单号: {}", outTradeNo); + return; + } + + // 根据交易状态处理 + switch (tradeState) { + case "SUCCESS": + handlePaymentSuccess(order, transaction); + break; + case "REFUND": + handlePaymentRefund(order, transaction); + break; + case "CLOSED": + case "REVOKED": + case "PAYERROR": + handlePaymentFailed(order, transaction); + break; + default: + log.warn("未处理的交易状态: {}, 订单号: {}", tradeState, outTradeNo); + break; + } + } + + /** + * 处理支付成功 + */ + private void handlePaymentSuccess(ShopOrder order, Transaction transaction) throws PaymentException { + try { + // 验证金额 + validateAmount(order, transaction); + + // 更新订单状态 + order.setPayStatus(true); // 使用Boolean类型 + order.setTransactionId(transaction.getTransactionId()); + order.setPayTime(LocalDateTime.parse(transaction.getSuccessTime())); + + // 使用专门的更新方法,会触发支付成功后的业务逻辑 + shopOrderService.updateByOutTradeNo(order); + + // 推送支付结果通知 + pushPaymentNotification(order, transaction); + + log.info("支付成功处理完成, 订单号: {}, 微信交易号: {}", + order.getOrderNo(), transaction.getTransactionId()); + + } catch (Exception e) { + throw PaymentException.systemError("处理支付成功回调失败: " + e.getMessage(), e); + } + } + + /** + * 处理支付退款 + */ + private void handlePaymentRefund(ShopOrder order, Transaction transaction) throws PaymentException { + try { + log.info("处理支付退款, 订单号: {}, 微信交易号: {}", + order.getOrderNo(), transaction.getTransactionId()); + + // 这里可以添加退款相关的业务逻辑 + // 例如:更新订单状态、处理库存、发送通知等 + + } catch (Exception e) { + throw PaymentException.systemError("处理支付退款回调失败: " + e.getMessage(), e); + } + } + + /** + * 处理支付失败 + */ + private void handlePaymentFailed(ShopOrder order, Transaction transaction) throws PaymentException { + try { + log.info("处理支付失败, 订单号: {}, 交易状态: {}", + order.getOrderNo(), transaction.getTradeState()); + + // 这里可以添加支付失败相关的业务逻辑 + // 例如:释放库存、发送通知等 + + } catch (Exception e) { + throw PaymentException.systemError("处理支付失败回调失败: " + e.getMessage(), e); + } + } + + /** + * 验证支付金额 + */ + private void validateAmount(ShopOrder order, Transaction transaction) throws PaymentException { + if (transaction.getAmount() == null || transaction.getAmount().getTotal() == null) { + throw PaymentException.amountError("回调通知中金额信息为空"); + } + + // 将订单金额转换为分 + BigDecimal orderAmount = order.getMoney(); + if (orderAmount == null) { + throw PaymentException.amountError("订单金额为空"); + } + + int orderAmountFen = orderAmount.multiply(new BigDecimal(100)).intValue(); + int callbackAmountFen = transaction.getAmount().getTotal(); + + if (orderAmountFen != callbackAmountFen) { + throw PaymentException.amountError( + String.format("订单金额不匹配,订单金额: %d分, 回调金额: %d分", + orderAmountFen, callbackAmountFen)); + } + + log.debug("金额验证通过, 订单号: {}, 金额: {}分", order.getOrderNo(), orderAmountFen); + } + + /** + * 推送支付结果通知 + */ + private void pushPaymentNotification(ShopOrder order, Transaction transaction) { + try { + log.info("开始推送支付成功通知, 订单号: {}, 交易号: {}, 用户ID: {}", + order.getOrderNo(), transaction.getTransactionId(), order.getUserId()); + + // 1. 记录支付成功日志 + logPaymentSuccess(order, transaction); + + // 2. 发送支付成功通知(可扩展) + sendPaymentSuccessNotification(order, transaction); + + // 3. 触发其他业务逻辑(可扩展) + triggerPostPaymentActions(order, transaction); + + log.info("支付结果通知推送完成, 订单号: {}, 交易号: {}", + order.getOrderNo(), transaction.getTransactionId()); + } catch (Exception e) { + log.warn("支付结果通知推送失败, 订单号: {}, 错误: {}", order.getOrderNo(), e.getMessage()); + // 推送失败不影响主流程,只记录日志 + } + } + + /** + * 记录支付成功日志 + */ + private void logPaymentSuccess(ShopOrder order, Transaction transaction) { + try { + log.info("=== 支付成功详细信息 ==="); + log.info("订单号: {}", order.getOrderNo()); + log.info("微信交易号: {}", transaction.getTransactionId()); + log.info("支付金额: {}元", order.getPayPrice()); + log.info("支付时间: {}", transaction.getSuccessTime()); + log.info("用户ID: {}", order.getUserId()); + log.info("租户ID: {}", order.getTenantId()); + log.info("订单标题: {}", order.getTitle()); + log.info("========================"); + } catch (Exception e) { + log.warn("记录支付成功日志失败: {}", e.getMessage()); + } + } + + /** + * 发送支付成功通知 + */ + private void sendPaymentSuccessNotification(ShopOrder order, Transaction transaction) { + try { + // TODO: 实现具体的通知逻辑 + // 1. 发送邮件通知 + // 2. 发送短信通知 + // 3. 站内消息通知 + // 4. 微信模板消息通知 + + log.debug("支付成功通知发送完成, 订单号: {}", order.getOrderNo()); + } catch (Exception e) { + log.warn("发送支付成功通知失败, 订单号: {}, 错误: {}", order.getOrderNo(), e.getMessage()); + } + } + + /** + * 触发支付成功后的其他业务逻辑 + */ + private void triggerPostPaymentActions(ShopOrder order, Transaction transaction) { + try { + // TODO: 根据业务需求实现 + // 1. 开通网站服务 + // 2. 激活会员权益 + // 3. 发放积分奖励 + // 4. 触发营销活动 + + log.debug("支付后业务逻辑触发完成, 订单号: {}", order.getOrderNo()); + } catch (Exception e) { + log.warn("触发支付后业务逻辑失败, 订单号: {}, 错误: {}", order.getOrderNo(), e.getMessage()); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/service/impl/PaymentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/impl/PaymentServiceImpl.java new file mode 100644 index 0000000..a01dafe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/service/impl/PaymentServiceImpl.java @@ -0,0 +1,675 @@ +package com.gxwebsoft.payment.service.impl; + +import cn.hutool.core.util.IdUtil; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.payment.constants.PaymentConstants; +import com.gxwebsoft.payment.dto.PaymentRequest; +import com.gxwebsoft.payment.dto.PaymentResponse; +import com.gxwebsoft.payment.dto.PaymentWithOrderRequest; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.payment.exception.PaymentException; +import com.gxwebsoft.payment.service.PaymentService; +import com.gxwebsoft.payment.service.WxPayConfigService; +import com.gxwebsoft.payment.strategy.PaymentStrategy; +import com.gxwebsoft.shop.dto.OrderCreateRequest; +import com.gxwebsoft.shop.service.OrderBusinessService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 统一支付服务实现 + * 基于策略模式实现多种支付方式的统一管理 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Service("unifiedPaymentServiceImpl") +public class PaymentServiceImpl implements PaymentService { + + /** + * 支付策略映射表 + */ + private final Map strategyMap = new ConcurrentHashMap<>(); + + /** + * 注入所有支付策略实现 + */ + @Resource + private List paymentStrategies; + + /** + * 订单业务服务 + */ + @Resource + private OrderBusinessService orderBusinessService; + + /** + * 微信支付配置服务 + */ + @Resource + private WxPayConfigService wxPayConfigService; + + /** + * 初始化策略映射 + */ + @PostConstruct + public void initStrategies() { + if (paymentStrategies != null && !paymentStrategies.isEmpty()) { + for (PaymentStrategy strategy : paymentStrategies) { + try { + PaymentType paymentType = strategy.getSupportedPaymentType(); + strategyMap.put(paymentType, strategy); + log.info("注册支付策略: {} -> {}", paymentType.getName(), strategy.getClass().getSimpleName()); + } catch (Exception e) { + log.warn("注册支付策略失败: {}, 错误: {}", strategy.getClass().getSimpleName(), e.getMessage()); + } + } + } + log.info("支付策略初始化完成,共注册 {} 种支付方式", strategyMap.size()); + + if (strategyMap.isEmpty()) { + log.warn("⚠️ 没有可用的支付策略,支付功能将不可用"); + } + } + + @Override + public PaymentResponse createPayment(PaymentRequest request) throws PaymentException { + log.info("{}, 支付类型: {}, 租户ID: {}, 用户ID: {}, 金额: {}", + PaymentConstants.LogMessage.PAYMENT_START, request.getPaymentType(), + request.getTenantId(), request.getUserId(), request.getFormattedAmount()); + + try { + // 基础参数验证 + validatePaymentRequest(request); + + // 获取支付策略 + PaymentStrategy strategy = getPaymentStrategy(request.getPaymentType()); + + // 执行支付 + PaymentResponse response = strategy.createPayment(request); + + log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}", + PaymentConstants.LogMessage.PAYMENT_SUCCESS, request.getPaymentType(), + request.getTenantId(), response.getOrderNo(), request.getFormattedAmount()); + + return response; + + } catch (PaymentException e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 错误: {}", + PaymentConstants.LogMessage.PAYMENT_FAILED, request.getPaymentType(), + request.getTenantId(), e.getMessage()); + throw e; + } catch (Exception e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 系统错误: {}", + PaymentConstants.LogMessage.PAYMENT_FAILED, request.getPaymentType(), + request.getTenantId(), e.getMessage(), e); + throw PaymentException.systemError("支付创建失败: " + e.getMessage(), e); + } + } + + @Override + public PaymentResponse createPaymentWithOrder(PaymentWithOrderRequest request, User loginUser) throws PaymentException { + log.info("开始创建支付订单(包含订单信息), 支付类型: {}, 租户ID: {}, 用户ID: {}, 金额: {}", + request.getPaymentType(), request.getTenantId(), loginUser.getUserId(), request.getFormattedAmount()); + + try { + // 1. 参数验证 + validatePaymentWithOrderRequest(request, loginUser); + + // 2. 转换为订单创建请求 + OrderCreateRequest orderRequest = convertToOrderCreateRequest(request, loginUser); + + // 3. 创建订单(包含商品验证、库存扣减等完整业务逻辑) + Map wxOrderInfo = orderBusinessService.createOrder(orderRequest, loginUser); + + // 4. 构建支付响应(复用现有的微信支付返回格式) + PaymentResponse response = buildPaymentResponseFromWxOrder(wxOrderInfo, request, orderRequest.getOrderNo()); + + log.info("支付订单创建成功(包含订单信息), 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}", + request.getPaymentType(), request.getTenantId(), response.getOrderNo(), request.getFormattedAmount()); + + return response; + + } catch (PaymentException e) { + log.error("创建支付订单失败(包含订单信息), 支付类型: {}, 租户ID: {}, 错误: {}", + request.getPaymentType(), request.getTenantId(), e.getMessage()); + throw e; + } catch (Exception e) { + log.error("创建支付订单系统错误(包含订单信息), 支付类型: {}, 租户ID: {}, 系统错误: {}", + request.getPaymentType(), request.getTenantId(), e.getMessage(), e); + throw PaymentException.systemError("支付订单创建失败: " + e.getMessage(), e); + } + } + + @Override + public PaymentResponse queryPayment(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { + log.info("开始查询支付状态, 支付类型: {}, 租户ID: {}, 订单号: {}", + paymentType, tenantId, orderNo); + + try { + // 参数验证 + validateQueryParams(orderNo, paymentType, tenantId); + + // 获取支付策略 + PaymentStrategy strategy = getPaymentStrategy(paymentType); + + // 检查是否支持查询 + if (!strategy.supportQuery()) { + throw PaymentException.unsupportedPayment("该支付方式不支持查询", paymentType); + } + + // 执行查询 + PaymentResponse response = strategy.queryPayment(orderNo, tenantId); + + log.info("支付状态查询成功, 支付类型: {}, 租户ID: {}, 订单号: {}, 状态: {}", + paymentType, tenantId, orderNo, response.getPaymentStatus()); + + return response; + + } catch (PaymentException e) { + log.error("支付状态查询失败, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", + paymentType, tenantId, orderNo, e.getMessage()); + throw e; + } catch (Exception e) { + log.error("支付状态查询系统错误, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", + paymentType, tenantId, orderNo, e.getMessage(), e); + throw PaymentException.systemError("支付查询失败: " + e.getMessage(), e); + } + } + + @Override + public String handlePaymentNotify(PaymentType paymentType, Map headers, String body, Integer tenantId) throws PaymentException { + log.info("{}, 支付类型: {}, 租户ID: {}", + PaymentConstants.LogMessage.NOTIFY_START, paymentType, tenantId); + + try { + // 参数验证 + validateNotifyParams(paymentType, headers, body, tenantId); + + // 获取支付策略 + PaymentStrategy strategy = getPaymentStrategy(paymentType); + + // 检查是否需要异步通知 + if (!strategy.needNotify()) { + log.warn("该支付方式不需要异步通知, 支付类型: {}", paymentType); + return PaymentConstants.Wechat.NOTIFY_SUCCESS; + } + + // 处理回调 + String result = strategy.handleNotify(headers, body, tenantId); + + log.info("{}, 支付类型: {}, 租户ID: {}", + PaymentConstants.LogMessage.NOTIFY_SUCCESS, paymentType, tenantId); + + return result; + + } catch (PaymentException e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 错误: {}", + PaymentConstants.LogMessage.NOTIFY_FAILED, paymentType, tenantId, e.getMessage()); + throw e; + } catch (Exception e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 系统错误: {}", + PaymentConstants.LogMessage.NOTIFY_FAILED, paymentType, tenantId, e.getMessage(), e); + throw PaymentException.systemError("支付回调处理失败: " + e.getMessage(), e); + } + } + + @Override + public PaymentResponse refund(String orderNo, String refundNo, PaymentType paymentType, + BigDecimal totalAmount, BigDecimal refundAmount, + String reason, Integer tenantId) throws PaymentException { + log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 退款金额: {}", + PaymentConstants.LogMessage.REFUND_START, paymentType, tenantId, orderNo, refundNo, refundAmount); + + try { + // 参数验证 + validateRefundParams(orderNo, refundNo, paymentType, totalAmount, refundAmount, tenantId); + + // 获取支付策略 + PaymentStrategy strategy = getPaymentStrategy(paymentType); + + // 检查是否支持退款 + if (!strategy.supportRefund()) { + throw PaymentException.unsupportedPayment("该支付方式不支持退款", paymentType); + } + + // 执行退款 + PaymentResponse response = strategy.refund(orderNo, refundNo, totalAmount, refundAmount, reason, tenantId); + + log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 退款金额: {}", + PaymentConstants.LogMessage.REFUND_SUCCESS, paymentType, tenantId, orderNo, refundNo, refundAmount); + + return response; + + } catch (PaymentException e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 错误: {}", + PaymentConstants.LogMessage.REFUND_FAILED, paymentType, tenantId, orderNo, refundNo, e.getMessage()); + throw e; + } catch (Exception e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 系统错误: {}", + PaymentConstants.LogMessage.REFUND_FAILED, paymentType, tenantId, orderNo, refundNo, e.getMessage(), e); + throw PaymentException.systemError("退款申请失败: " + e.getMessage(), e); + } + } + + @Override + public PaymentResponse queryRefund(String refundNo, PaymentType paymentType, Integer tenantId) throws PaymentException { + log.info("开始查询退款状态, 支付类型: {}, 租户ID: {}, 退款单号: {}", + paymentType, tenantId, refundNo); + + try { + // 参数验证 + validateRefundQueryParams(refundNo, paymentType, tenantId); + + // 获取支付策略 + PaymentStrategy strategy = getPaymentStrategy(paymentType); + + // 检查是否支持退款查询 + if (!strategy.supportRefund()) { + throw PaymentException.unsupportedPayment("该支付方式不支持退款查询", paymentType); + } + + // 执行查询 + PaymentResponse response = strategy.queryRefund(refundNo, tenantId); + + log.info("退款状态查询成功, 支付类型: {}, 租户ID: {}, 退款单号: {}, 状态: {}", + paymentType, tenantId, refundNo, response.getPaymentStatus()); + + return response; + + } catch (PaymentException e) { + log.error("退款状态查询失败, 支付类型: {}, 租户ID: {}, 退款单号: {}, 错误: {}", + paymentType, tenantId, refundNo, e.getMessage()); + throw e; + } catch (Exception e) { + log.error("退款状态查询系统错误, 支付类型: {}, 租户ID: {}, 退款单号: {}, 错误: {}", + paymentType, tenantId, refundNo, e.getMessage(), e); + throw PaymentException.systemError("退款查询失败: " + e.getMessage(), e); + } + } + + @Override + public boolean closeOrder(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { + log.info("开始关闭订单, 支付类型: {}, 租户ID: {}, 订单号: {}", + paymentType, tenantId, orderNo); + + try { + // 参数验证 + validateCloseParams(orderNo, paymentType, tenantId); + + // 获取支付策略 + PaymentStrategy strategy = getPaymentStrategy(paymentType); + + // 检查是否支持关闭订单 + if (!strategy.supportClose()) { + throw PaymentException.unsupportedPayment("该支付方式不支持关闭订单", paymentType); + } + + // 执行关闭 + boolean result = strategy.closeOrder(orderNo, tenantId); + + log.info("订单关闭{}, 支付类型: {}, 租户ID: {}, 订单号: {}", + result ? "成功" : "失败", paymentType, tenantId, orderNo); + + return result; + + } catch (PaymentException e) { + log.error("订单关闭失败, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", + paymentType, tenantId, orderNo, e.getMessage()); + throw e; + } catch (Exception e) { + log.error("订单关闭系统错误, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", + paymentType, tenantId, orderNo, e.getMessage(), e); + throw PaymentException.systemError("订单关闭失败: " + e.getMessage(), e); + } + } + + @Override + public List getSupportedPaymentTypes() { + return new ArrayList<>(strategyMap.keySet()); + } + + @Override + public boolean isPaymentTypeSupported(PaymentType paymentType) { + return strategyMap.containsKey(paymentType); + } + + @Override + public boolean isRefundSupported(PaymentType paymentType) { + PaymentStrategy strategy = strategyMap.get(paymentType); + return strategy != null && strategy.supportRefund(); + } + + @Override + public boolean isQuerySupported(PaymentType paymentType) { + PaymentStrategy strategy = strategyMap.get(paymentType); + return strategy != null && strategy.supportQuery(); + } + + @Override + public boolean isCloseSupported(PaymentType paymentType) { + PaymentStrategy strategy = strategyMap.get(paymentType); + return strategy != null && strategy.supportClose(); + } + + @Override + public boolean isNotifyNeeded(PaymentType paymentType) { + PaymentStrategy strategy = strategyMap.get(paymentType); + return strategy != null && strategy.needNotify(); + } + + @Override + public void validatePaymentRequest(PaymentRequest request) throws PaymentException { + if (request == null) { + throw PaymentException.paramError("支付请求不能为空"); + } + + if (request.getPaymentType() == null) { + throw PaymentException.paramError("支付类型不能为空"); + } + + if (request.getTenantId() == null || request.getTenantId() <= 0) { + throw PaymentException.paramError("租户ID不能为空且必须大于0"); + } + + if (request.getUserId() == null || request.getUserId() <= 0) { + throw PaymentException.paramError("用户ID不能为空且必须大于0"); + } + + if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) { + throw PaymentException.amountError("支付金额必须大于0"); + } + + if (!StringUtils.hasText(request.getSubject())) { + throw PaymentException.paramError("订单标题不能为空"); + } + + // 检查支付类型是否支持 + if (!isPaymentTypeSupported(request.getPaymentType())) { + throw PaymentException.unsupportedPayment("不支持的支付类型: " + request.getPaymentType(), request.getPaymentType()); + } + } + + @Override + public Map getPaymentStrategyInfo(PaymentType paymentType) { + PaymentStrategy strategy = strategyMap.get(paymentType); + if (strategy == null) { + return null; + } + + Map info = new HashMap<>(); + info.put("paymentType", paymentType); + info.put("strategyName", strategy.getStrategyName()); + info.put("strategyDescription", strategy.getStrategyDescription()); + info.put("supportRefund", strategy.supportRefund()); + info.put("supportQuery", strategy.supportQuery()); + info.put("supportClose", strategy.supportClose()); + info.put("needNotify", strategy.needNotify()); + return info; + } + + @Override + public List> getAllPaymentStrategyInfo() { + return strategyMap.keySet().stream() + .map(this::getPaymentStrategyInfo) + .collect(Collectors.toList()); + } + + @Override + public Map checkPaymentConfig(Integer tenantId) { + Map result = new HashMap<>(); + result.put("tenantId", tenantId); + + try { + // 检查微信支付配置 + wxPayConfigService.getPaymentConfigForStrategy(tenantId); + result.put("wechatConfigExists", true); + result.put("wechatConfigError", null); + } catch (Exception e) { + result.put("wechatConfigExists", false); + result.put("wechatConfigError", e.getMessage()); + } + + try { + // 检查微信支付Config构建 + wxPayConfigService.getWxPayConfig(tenantId); + result.put("wechatConfigValid", true); + result.put("wechatConfigValidError", null); + } catch (Exception e) { + result.put("wechatConfigValid", false); + result.put("wechatConfigValidError", e.getMessage()); + } + + return result; + } + + /** + * 获取支付策略 + */ + private PaymentStrategy getPaymentStrategy(PaymentType paymentType) throws PaymentException { + // 如果是WECHAT支付类型,转换为WECHAT_NATIVE + // 因为WECHAT是一个通用类型,实际的支付策略是WECHAT_NATIVE + PaymentType actualPaymentType = paymentType; + if (paymentType == PaymentType.WECHAT) { + actualPaymentType = PaymentType.WECHAT_NATIVE; + } + + PaymentStrategy strategy = strategyMap.get(actualPaymentType); + if (strategy == null) { + throw PaymentException.unsupportedPayment("不支持的支付类型: " + paymentType, paymentType); + } + return strategy; + } + + /** + * 验证查询参数 + */ + private void validateQueryParams(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { + if (!StringUtils.hasText(orderNo)) { + throw PaymentException.paramError("订单号不能为空"); + } + if (paymentType == null) { + throw PaymentException.paramError("支付类型不能为空"); + } + if (tenantId == null || tenantId <= 0) { + throw PaymentException.paramError("租户ID不能为空且必须大于0"); + } + } + + /** + * 验证回调参数 + */ + private void validateNotifyParams(PaymentType paymentType, Map headers, String body, Integer tenantId) throws PaymentException { + if (paymentType == null) { + throw PaymentException.paramError("支付类型不能为空"); + } + if (headers == null || headers.isEmpty()) { + throw PaymentException.paramError("请求头不能为空"); + } + if (!StringUtils.hasText(body)) { + throw PaymentException.paramError("请求体不能为空"); + } + if (tenantId == null || tenantId <= 0) { + throw PaymentException.paramError("租户ID不能为空且必须大于0"); + } + } + + /** + * 验证退款参数 + */ + private void validateRefundParams(String orderNo, String refundNo, PaymentType paymentType, + BigDecimal totalAmount, BigDecimal refundAmount, Integer tenantId) throws PaymentException { + if (!StringUtils.hasText(orderNo)) { + throw PaymentException.paramError("订单号不能为空"); + } + if (!StringUtils.hasText(refundNo)) { + throw PaymentException.paramError("退款单号不能为空"); + } + if (paymentType == null) { + throw PaymentException.paramError("支付类型不能为空"); + } + if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) { + throw PaymentException.amountError("订单总金额必须大于0"); + } + if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) { + throw PaymentException.amountError("退款金额必须大于0"); + } + if (refundAmount.compareTo(totalAmount) > 0) { + throw PaymentException.amountError("退款金额不能大于订单总金额"); + } + if (tenantId == null || tenantId <= 0) { + throw PaymentException.paramError("租户ID不能为空且必须大于0"); + } + } + + /** + * 验证退款查询参数 + */ + private void validateRefundQueryParams(String refundNo, PaymentType paymentType, Integer tenantId) throws PaymentException { + if (!StringUtils.hasText(refundNo)) { + throw PaymentException.paramError("退款单号不能为空"); + } + if (paymentType == null) { + throw PaymentException.paramError("支付类型不能为空"); + } + if (tenantId == null || tenantId <= 0) { + throw PaymentException.paramError("租户ID不能为空且必须大于0"); + } + } + + /** + * 验证关闭订单参数 + */ + private void validateCloseParams(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { + if (!StringUtils.hasText(orderNo)) { + throw PaymentException.paramError("订单号不能为空"); + } + if (paymentType == null) { + throw PaymentException.paramError("支付类型不能为空"); + } + if (tenantId == null || tenantId <= 0) { + throw PaymentException.paramError("租户ID不能为空且必须大于0"); + } + } + + /** + * 验证支付与订单创建请求参数 + */ + private void validatePaymentWithOrderRequest(PaymentWithOrderRequest request, User loginUser) throws PaymentException { + if (request == null) { + throw PaymentException.paramError("请求参数不能为空"); + } + if (loginUser == null) { + throw PaymentException.paramError("用户未登录"); + } + if (request.getPaymentType() == null) { + throw PaymentException.paramError("支付类型不能为空"); + } + if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) { + throw PaymentException.amountError("支付金额必须大于0"); + } + if (!StringUtils.hasText(request.getSubject())) { + throw PaymentException.paramError("订单标题不能为空"); + } + if (request.getTenantId() == null || request.getTenantId() <= 0) { + throw PaymentException.paramError("租户ID不能为空且必须大于0"); + } + if (request.getOrderInfo() == null) { + throw PaymentException.paramError("订单信息不能为空"); + } + if (request.getOrderInfo().getGoodsItems() == null || request.getOrderInfo().getGoodsItems().isEmpty()) { + throw PaymentException.paramError("订单商品列表不能为空"); + } + } + + /** + * 转换为订单创建请求 + */ + private OrderCreateRequest convertToOrderCreateRequest(PaymentWithOrderRequest request, User loginUser) { + OrderCreateRequest orderRequest = new OrderCreateRequest(); + + // 生成订单号(使用雪花算法保证全局唯一) + String orderNo = Long.toString(IdUtil.getSnowflakeNextId()); + orderRequest.setOrderNo(orderNo); + log.info("为订单创建请求生成订单号(雪花算法): {}", orderNo); + + // 设置基本信息 + orderRequest.setType(request.getOrderInfo().getType()); + orderRequest.setTitle(request.getSubject()); + orderRequest.setComments(request.getOrderInfo().getComments()); + orderRequest.setTenantId(request.getTenantId()); + + // 设置收货信息 + orderRequest.setRealName(request.getOrderInfo().getRealName()); + orderRequest.setAddress(request.getOrderInfo().getAddress()); + orderRequest.setAddressId(request.getOrderInfo().getAddressId()); + orderRequest.setDeliveryType(request.getOrderInfo().getDeliveryType()); + + // 设置商户信息 + orderRequest.setMerchantId(request.getOrderInfo().getMerchantId()); + orderRequest.setMerchantName(request.getOrderInfo().getMerchantName()); + + // 设置支付信息 + orderRequest.setPayType(request.getPaymentType().getCode()); + orderRequest.setTotalPrice(request.getAmount()); + orderRequest.setPayPrice(request.getAmount()); + + // 设置优惠券 + orderRequest.setCouponId(request.getOrderInfo().getCouponId()); + + // 转换商品列表 + List goodsItems = request.getOrderInfo().getGoodsItems().stream() + .map(this::convertToOrderGoodsItem) + .collect(java.util.stream.Collectors.toList()); + orderRequest.setGoodsItems(goodsItems); + + return orderRequest; + } + + /** + * 转换商品项 + */ + private OrderCreateRequest.OrderGoodsItem convertToOrderGoodsItem(PaymentWithOrderRequest.OrderGoodsItem item) { + OrderCreateRequest.OrderGoodsItem orderItem = new OrderCreateRequest.OrderGoodsItem(); + orderItem.setGoodsId(item.getGoodsId()); + orderItem.setSkuId(item.getSkuId()); + orderItem.setQuantity(item.getQuantity()); + orderItem.setSpecInfo(item.getSpecInfo()); + return orderItem; + } + + /** + * 从微信订单信息构建支付响应 + */ + private PaymentResponse buildPaymentResponseFromWxOrder(Map wxOrderInfo, + PaymentWithOrderRequest request, + String orderNo) { + PaymentResponse response = PaymentResponse.wechatNative( + orderNo, + wxOrderInfo.get("codeUrl"), + request.getAmount(), + request.getTenantId() + ); + + // 设置额外信息 + response.setSuccess(true); + // 确保orderNo被正确设置 + response.setOrderNo(orderNo); + + // 调试日志 + log.info("构建支付响应成功, 订单号: {}, 二维码URL: {}, 响应中的orderNo: {}", + orderNo, wxOrderInfo.get("codeUrl"), response.getOrderNo()); + + return response; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/strategy/PaymentStrategy.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/strategy/PaymentStrategy.java new file mode 100644 index 0000000..560c365 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/strategy/PaymentStrategy.java @@ -0,0 +1,153 @@ +package com.gxwebsoft.payment.strategy; + +import com.gxwebsoft.payment.dto.PaymentRequest; +import com.gxwebsoft.payment.dto.PaymentResponse; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.payment.exception.PaymentException; + +import java.util.Map; + +/** + * 支付策略接口 + * 定义所有支付方式的统一接口 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public interface PaymentStrategy { + + /** + * 获取支持的支付类型 + * + * @return 支付类型 + */ + PaymentType getSupportedPaymentType(); + + /** + * 验证支付请求参数 + * + * @param request 支付请求 + * @throws PaymentException 参数验证失败时抛出 + */ + void validateRequest(PaymentRequest request) throws PaymentException; + + /** + * 创建支付订单 + * + * @param request 支付请求 + * @return 支付响应 + * @throws PaymentException 支付创建失败时抛出 + */ + PaymentResponse createPayment(PaymentRequest request) throws PaymentException; + + /** + * 查询支付状态 + * + * @param orderNo 订单号 + * @param tenantId 租户ID + * @return 支付响应 + * @throws PaymentException 查询失败时抛出 + */ + PaymentResponse queryPayment(String orderNo, Integer tenantId) throws PaymentException; + + /** + * 处理支付回调通知 + * + * @param headers 请求头 + * @param body 请求体 + * @param tenantId 租户ID + * @return 处理结果,返回给第三方的响应内容 + * @throws PaymentException 处理失败时抛出 + */ + String handleNotify(Map headers, String body, Integer tenantId) throws PaymentException; + + /** + * 申请退款 + * + * @param orderNo 订单号 + * @param refundNo 退款单号 + * @param totalAmount 订单总金额 + * @param refundAmount 退款金额 + * @param reason 退款原因 + * @param tenantId 租户ID + * @return 退款响应 + * @throws PaymentException 退款申请失败时抛出 + */ + PaymentResponse refund(String orderNo, String refundNo, + java.math.BigDecimal totalAmount, java.math.BigDecimal refundAmount, + String reason, Integer tenantId) throws PaymentException; + + /** + * 查询退款状态 + * + * @param refundNo 退款单号 + * @param tenantId 租户ID + * @return 退款查询响应 + * @throws PaymentException 查询失败时抛出 + */ + PaymentResponse queryRefund(String refundNo, Integer tenantId) throws PaymentException; + + /** + * 关闭订单 + * + * @param orderNo 订单号 + * @param tenantId 租户ID + * @return 关闭结果 + * @throws PaymentException 关闭失败时抛出 + */ + boolean closeOrder(String orderNo, Integer tenantId) throws PaymentException; + + /** + * 是否支持退款 + * + * @return true表示支持退款 + */ + default boolean supportRefund() { + return false; + } + + /** + * 是否支持查询 + * + * @return true表示支持查询 + */ + default boolean supportQuery() { + return false; + } + + /** + * 是否支持关闭订单 + * + * @return true表示支持关闭订单 + */ + default boolean supportClose() { + return false; + } + + /** + * 是否需要异步通知 + * + * @return true表示需要异步通知 + */ + default boolean needNotify() { + return false; + } + + /** + * 获取策略名称 + * + * @return 策略名称 + */ + default String getStrategyName() { + return getSupportedPaymentType().getName(); + } + + /** + * 获取策略描述 + * + * @return 策略描述 + */ + default String getStrategyDescription() { + return getSupportedPaymentType().getName() + "支付策略"; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/strategy/WechatNativeStrategy.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/strategy/WechatNativeStrategy.java new file mode 100644 index 0000000..e5d6b1d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/strategy/WechatNativeStrategy.java @@ -0,0 +1,668 @@ +package com.gxwebsoft.payment.strategy; + +import cn.hutool.core.util.IdUtil; +import com.gxwebsoft.common.core.utils.CommonUtil; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.payment.constants.PaymentConstants; +import com.gxwebsoft.payment.dto.PaymentRequest; +import com.gxwebsoft.payment.dto.PaymentResponse; +import com.gxwebsoft.payment.enums.PaymentStatus; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.payment.exception.PaymentException; +import com.gxwebsoft.payment.service.WxPayConfigService; +import com.gxwebsoft.payment.service.WxPayNotifyService; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.service.payments.nativepay.NativePayService; +import com.wechat.pay.java.service.payments.nativepay.model.Amount; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; +import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByOutTradeNoRequest; +import com.wechat.pay.java.service.payments.model.Transaction; +import com.wechat.pay.java.service.refund.RefundService; +import com.wechat.pay.java.service.refund.model.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Map; + +/** + * 微信Native支付策略实现 + * 处理微信Native扫码支付 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Component +public class WechatNativeStrategy implements PaymentStrategy { + + @Resource + private WxPayConfigService wxPayConfigService; + + @Resource + private WxPayNotifyService wxPayNotifyService; + + @Override + public PaymentType getSupportedPaymentType() { + return PaymentType.WECHAT_NATIVE; + } + + @Override + public void validateRequest(PaymentRequest request) throws PaymentException { + if (request == null) { + throw PaymentException.paramError("支付请求不能为空"); + } + + if (request.getTenantId() == null) { + throw PaymentException.paramError("租户ID不能为空"); + } + + if (request.getUserId() == null) { + throw PaymentException.paramError("用户ID不能为空"); + } + + if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) { + throw PaymentException.amountError("支付金额必须大于0"); + } + + if (!StringUtils.hasText(request.getSubject())) { + throw PaymentException.paramError("订单标题不能为空"); + } + + // 验证金额范围 + if (request.getAmount().compareTo(new BigDecimal("0.01")) < 0) { + throw PaymentException.amountError("支付金额不能小于0.01元"); + } + + if (request.getAmount().compareTo(new BigDecimal("999999.99")) > 0) { + throw PaymentException.amountError("支付金额不能超过999999.99元"); + } + + // 验证订单标题长度 + if (request.getSubject().length() > PaymentConstants.Config.DESCRIPTION_MAX_LENGTH) { + throw PaymentException.paramError("订单标题长度不能超过" + PaymentConstants.Config.DESCRIPTION_MAX_LENGTH + "个字符"); + } + + log.debug("微信Native支付请求参数验证通过, 租户ID: {}, 金额: {}", + request.getTenantId(), request.getFormattedAmount()); + } + + @Override + public PaymentResponse createPayment(PaymentRequest request) throws PaymentException { + log.info("{}, 支付类型: {}, 租户ID: {}, 金额: {}", + PaymentConstants.LogMessage.PAYMENT_START, getSupportedPaymentType(), + request.getTenantId(), request.getFormattedAmount()); + + try { + // 验证请求参数 + validateRequest(request); + + // 生成订单号 + String orderNo = generateOrderNo(request); + log.info("生成的订单号: {}", orderNo); + + // 获取Native支付的Payment配置(包含appId等信息) + Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(request.getTenantId()); + + // 获取微信支付配置 + Config wxPayConfig = wxPayConfigService.getWxPayConfig(request.getTenantId()); + + // 构建预支付请求 + PrepayRequest prepayRequest = buildPrepayRequest(request, orderNo, paymentConfig); + + // 调用微信支付API + PrepayResponse prepayResponse = callWechatPayApi(prepayRequest, wxPayConfig); + + // 构建响应 + PaymentResponse response = PaymentResponse.wechatNative( + orderNo, prepayResponse.getCodeUrl(), request.getAmount(), request.getTenantId()); + response.setUserId(request.getUserId()); + + // 确保orderNo被正确设置 + response.setOrderNo(orderNo); + + // 调试日志:检查响应对象的orderNo + log.info("构建的响应对象 - orderNo: {}, codeUrl: {}, success: {}", + response.getOrderNo(), response.getCodeUrl(), response.getSuccess()); + + log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}", + PaymentConstants.LogMessage.PAYMENT_SUCCESS, getSupportedPaymentType(), + request.getTenantId(), orderNo, request.getFormattedAmount()); + + return response; + + } catch (PaymentException e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 错误: {}", + PaymentConstants.LogMessage.PAYMENT_FAILED, getSupportedPaymentType(), + request.getTenantId(), e.getMessage()); + throw e; + } catch (Exception e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 系统错误: {}", + PaymentConstants.LogMessage.PAYMENT_FAILED, getSupportedPaymentType(), + request.getTenantId(), e.getMessage(), e); + throw PaymentException.systemError("微信Native支付创建失败: " + e.getMessage(), e); + } + } + + @Override + public PaymentResponse queryPayment(String orderNo, Integer tenantId) throws PaymentException { + log.info("开始查询微信Native支付状态, 订单号: {}, 租户ID: {}", orderNo, tenantId); + + try { + // 参数验证 + if (!StringUtils.hasText(orderNo)) { + throw PaymentException.paramError("订单号不能为空"); + } + if (tenantId == null) { + throw PaymentException.paramError("租户ID不能为空"); + } + + // 获取支付配置(包含商户号等信息) + Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(tenantId); + + // 获取微信支付配置 + Config wxPayConfig = wxPayConfigService.getWxPayConfig(tenantId); + + // 调用微信支付查询API + return queryWechatPaymentStatus(orderNo, tenantId, paymentConfig, wxPayConfig); + + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + log.error("查询微信Native支付状态失败, 订单号: {}, 租户ID: {}, 错误: {}", + orderNo, tenantId, e.getMessage(), e); + throw PaymentException.systemError("查询微信支付状态失败: " + e.getMessage(), e); + } + } + + @Override + public String handleNotify(Map headers, String body, Integer tenantId) throws PaymentException { + log.info("{}, 支付类型: {}, 租户ID: {}", + PaymentConstants.LogMessage.NOTIFY_START, getSupportedPaymentType(), tenantId); + + try { + // 委托给专门的回调处理服务 + return wxPayNotifyService.handlePaymentNotify(headers, body, tenantId); + } catch (Exception e) { + log.error("{}, 支付类型: {}, 租户ID: {}, 错误: {}", + PaymentConstants.LogMessage.NOTIFY_FAILED, getSupportedPaymentType(), + tenantId, e.getMessage(), e); + throw PaymentException.systemError("微信支付回调处理失败: " + e.getMessage(), e); + } + } + + @Override + public PaymentResponse refund(String orderNo, String refundNo, BigDecimal totalAmount, + BigDecimal refundAmount, String reason, Integer tenantId) throws PaymentException { + log.info("{}, 支付类型: {}, 订单号: {}, 退款单号: {}, 退款金额: {}, 租户ID: {}", + PaymentConstants.LogMessage.REFUND_START, getSupportedPaymentType(), + orderNo, refundNo, refundAmount, tenantId); + + try { + // 参数验证 + validateRefundRequest(orderNo, refundNo, totalAmount, refundAmount, tenantId); + + // 获取支付配置 + Payment paymentConfig = wxPayConfigService.getPaymentConfigForStrategy(tenantId); + Config wxPayConfig = wxPayConfigService.getWxPayConfig(tenantId); + + // 构建退款请求 + CreateRequest refundRequest = buildRefundRequest( + orderNo, refundNo, totalAmount, refundAmount, reason, paymentConfig); + + // 调用微信退款API + Refund refundResult = callWechatRefundApi(refundRequest, wxPayConfig); + + // 构建响应 + PaymentResponse response = buildRefundResponse(refundResult, orderNo, refundNo, tenantId); + + log.info("{}, 支付类型: {}, 订单号: {}, 退款单号: {}, 微信退款单号: {}", + PaymentConstants.LogMessage.REFUND_SUCCESS, getSupportedPaymentType(), + orderNo, refundNo, refundResult.getRefundId()); + + return response; + + } catch (PaymentException e) { + log.error("{}, 支付类型: {}, 订单号: {}, 退款单号: {}, 错误: {}", + PaymentConstants.LogMessage.REFUND_FAILED, getSupportedPaymentType(), + orderNo, refundNo, e.getMessage()); + throw e; + } catch (Exception e) { + log.error("{}, 支付类型: {}, 订单号: {}, 退款单号: {}, 系统错误: {}", + PaymentConstants.LogMessage.REFUND_FAILED, getSupportedPaymentType(), + orderNo, refundNo, e.getMessage(), e); + throw PaymentException.systemError("微信支付退款失败: " + e.getMessage(), e); + } + } + + @Override + public PaymentResponse queryRefund(String refundNo, Integer tenantId) throws PaymentException { + log.info("开始查询微信退款状态, 退款单号: {}, 租户ID: {}", refundNo, tenantId); + + try { + // 参数验证 + if (!StringUtils.hasText(refundNo)) { + throw PaymentException.paramError("退款单号不能为空"); + } + if (tenantId == null) { + throw PaymentException.paramError("租户ID不能为空"); + } + + // 获取支付配置 + Config wxPayConfig = wxPayConfigService.getWxPayConfig(tenantId); + + // 调用微信退款查询API + Refund refundResult = queryWechatRefundStatus(refundNo, wxPayConfig); + + // 构建响应 + PaymentResponse response = buildRefundQueryResponse(refundResult, tenantId); + + log.info("微信退款状态查询成功, 退款单号: {}, 状态: {}, 微信退款单号: {}", + refundNo, refundResult.getStatus(), refundResult.getRefundId()); + + return response; + + } catch (PaymentException e) { + throw e; + } catch (Exception e) { + log.error("查询微信退款状态失败, 退款单号: {}, 租户ID: {}, 错误: {}", + refundNo, tenantId, e.getMessage(), e); + throw PaymentException.systemError("查询微信退款状态失败: " + e.getMessage(), e); + } + } + + @Override + public boolean closeOrder(String orderNo, Integer tenantId) throws PaymentException { + // TODO: 实现微信订单关闭逻辑 + throw PaymentException.unsupportedPayment("暂不支持微信订单关闭", PaymentType.WECHAT_NATIVE); + } + + @Override + public boolean supportRefund() { + return true; + } + + @Override + public boolean supportQuery() { + return true; + } + + @Override + public boolean supportClose() { + return true; + } + + @Override + public boolean needNotify() { + return true; + } + + /** + * 生成订单号(使用雪花算法保证全局唯一) + */ + private String generateOrderNo(PaymentRequest request) { + if (StringUtils.hasText(request.getOrderNo())) { + return request.getOrderNo(); + } + return Long.toString(IdUtil.getSnowflakeNextId()); + } + + + + /** + * 构建微信预支付请求 + */ + private PrepayRequest buildPrepayRequest(PaymentRequest request, String orderNo, Payment paymentConfig) { + PrepayRequest prepayRequest = new PrepayRequest(); + + // 设置应用ID和商户号(关键修复) + prepayRequest.setAppid(paymentConfig.getAppId()); + prepayRequest.setMchid(paymentConfig.getMchId()); + + // 设置金额 + Amount amount = new Amount(); + amount.setTotal(request.getAmountInCents()); + amount.setCurrency(PaymentConstants.Wechat.CURRENCY); + prepayRequest.setAmount(amount); + + // 设置基本信息 + prepayRequest.setOutTradeNo(orderNo); + prepayRequest.setDescription(request.getEffectiveDescription()); + + log.info("创建微信支付订单 - 订单号: {}, 商户号: {}, 金额: {}分", + orderNo, paymentConfig.getMchId(), request.getAmountInCents()); + + // 设置回调URL(必填字段) + String notifyUrl = null; + if (StringUtils.hasText(request.getNotifyUrl())) { + // 优先使用请求中的回调URL + notifyUrl = request.getNotifyUrl(); + } else if (StringUtils.hasText(paymentConfig.getNotifyUrl())) { + // 使用配置中的回调URL + notifyUrl = paymentConfig.getNotifyUrl(); + } else { + // 如果都没有,抛出异常 + throw new RuntimeException("回调通知地址不能为空,请在支付请求中设置notifyUrl或在支付配置中设置notifyUrl"); + } + prepayRequest.setNotifyUrl(notifyUrl); + + log.debug("构建微信预支付请求完成, 订单号: {}, 金额: {}分, AppID: {}, 商户号: {}, 回调URL: {}", + orderNo, request.getAmountInCents(), paymentConfig.getAppId(), paymentConfig.getMchId(), notifyUrl); + + return prepayRequest; + } + + /** + * 查询微信支付状态 + */ + private PaymentResponse queryWechatPaymentStatus(String orderNo, Integer tenantId, Payment paymentConfig, Config wxPayConfig) throws PaymentException { + try { + log.info("开始查询微信支付状态 - 订单号: {}, 商户号: {}, 租户ID: {}", + orderNo, paymentConfig.getMchId(), tenantId); + + // 构建查询请求 + QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest(); + queryRequest.setOutTradeNo(orderNo); + queryRequest.setMchid(paymentConfig.getMchId()); + + // 构建服务 + NativePayService service = new NativePayService.Builder().config(wxPayConfig).build(); + + // 调用查询接口 + Transaction transaction = service.queryOrderByOutTradeNo(queryRequest); + + if (transaction == null) { + throw PaymentException.systemError("微信支付查询返回空结果", null); + } + + // 转换支付状态 + PaymentStatus paymentStatus = convertWechatPaymentStatus(transaction.getTradeState()); + + // 构建响应 + PaymentResponse response = new PaymentResponse(); + response.setSuccess(true); + response.setOrderNo(orderNo); + response.setPaymentStatus(paymentStatus); + response.setTenantId(tenantId); + response.setPaymentType(PaymentType.WECHAT_NATIVE); + + if (transaction.getAmount() != null) { + // 微信返回的金额是分,需要转换为元 + BigDecimal amount = new BigDecimal(transaction.getAmount().getTotal()).divide(new BigDecimal("100")); + response.setAmount(amount); + } + + if (transaction.getTransactionId() != null) { + response.setTransactionId(transaction.getTransactionId()); + } + + log.info("微信Native支付状态查询成功, 订单号: {}, 状态: {}, 微信交易号: {}", + orderNo, paymentStatus, transaction.getTransactionId()); + + return response; + + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + log.error("查询微信支付状态失败, 订单号: {}, 错误: {}", orderNo, e.getMessage(), e); + throw PaymentException.networkError("查询微信支付状态失败: " + e.getMessage(), PaymentType.WECHAT_NATIVE, e); + } + } + + /** + * 转换微信支付状态 + */ + private PaymentStatus convertWechatPaymentStatus(Transaction.TradeStateEnum tradeState) { + if (tradeState == null) { + return PaymentStatus.PENDING; + } + + switch (tradeState) { + case SUCCESS: + return PaymentStatus.SUCCESS; + case REFUND: + return PaymentStatus.REFUNDED; + case NOTPAY: + return PaymentStatus.PENDING; + case CLOSED: + return PaymentStatus.CANCELLED; + case REVOKED: + return PaymentStatus.CANCELLED; + case USERPAYING: + return PaymentStatus.PROCESSING; + case PAYERROR: + return PaymentStatus.FAILED; + default: + return PaymentStatus.PENDING; + } + } + + /** + * 调用微信支付API + */ + private PrepayResponse callWechatPayApi(PrepayRequest request, Config wxPayConfig) throws PaymentException { + try { + // 构建服务 + NativePayService service = new NativePayService.Builder().config(wxPayConfig).build(); + + // 调用预支付接口 + PrepayResponse response = service.prepay(request); + + if (response == null || !StringUtils.hasText(response.getCodeUrl())) { + throw PaymentException.networkError("微信支付API返回数据异常", PaymentType.WECHAT_NATIVE, null); + } + + log.debug("微信支付API调用成功, 订单号: {}", request.getOutTradeNo()); + return response; + + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + throw PaymentException.networkError("调用微信支付API失败: " + e.getMessage(), PaymentType.WECHAT_NATIVE, e); + } + } + + /** + * 验证退款请求参数 + */ + private void validateRefundRequest(String orderNo, String refundNo, BigDecimal totalAmount, + BigDecimal refundAmount, Integer tenantId) throws PaymentException { + if (!StringUtils.hasText(orderNo)) { + throw PaymentException.paramError("订单号不能为空"); + } + if (!StringUtils.hasText(refundNo)) { + throw PaymentException.paramError("退款单号不能为空"); + } + if (tenantId == null) { + throw PaymentException.paramError("租户ID不能为空"); + } + if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) { + throw PaymentException.amountError("订单总金额必须大于0"); + } + if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) { + throw PaymentException.amountError("退款金额必须大于0"); + } + if (refundAmount.compareTo(totalAmount) > 0) { + throw PaymentException.amountError("退款金额不能大于订单总金额"); + } + + log.debug("退款请求参数验证通过, 订单号: {}, 退款单号: {}, 订单总额: {}, 退款金额: {}", + orderNo, refundNo, totalAmount, refundAmount); + } + + /** + * 构建微信退款请求 + */ + private CreateRequest buildRefundRequest(String orderNo, String refundNo, BigDecimal totalAmount, + BigDecimal refundAmount, String reason, Payment paymentConfig) { + CreateRequest refundRequest = new CreateRequest(); + + // 设置订单号和退款单号 + refundRequest.setOutTradeNo(orderNo); + refundRequest.setOutRefundNo(refundNo); + + // 设置金额信息(微信支付金额单位为分) + AmountReq amountReq = new AmountReq(); + amountReq.setTotal(totalAmount.multiply(new BigDecimal("100")).longValue()); + amountReq.setRefund(refundAmount.multiply(new BigDecimal("100")).longValue()); + amountReq.setCurrency(PaymentConstants.Wechat.CURRENCY); + refundRequest.setAmount(amountReq); + + // 设置退款原因(可选,但建议填写) + if (StringUtils.hasText(reason)) { + // 退款原因最多80个字符 + String effectiveReason = reason.length() > 80 ? reason.substring(0, 80) : reason; + refundRequest.setReason(effectiveReason); + } else { + refundRequest.setReason("用户申请退款"); + } + + log.info("构建微信退款请求完成 - 订单号: {}, 退款单号: {}, 订单总额: {}分, 退款金额: {}分", + orderNo, refundNo, amountReq.getTotal(), amountReq.getRefund()); + + return refundRequest; + } + + /** + * 调用微信退款API + */ + private Refund callWechatRefundApi(CreateRequest refundRequest, Config wxPayConfig) throws PaymentException { + try { + // 构建退款服务 + RefundService refundService = new RefundService.Builder().config(wxPayConfig).build(); + + // 调用退款接口 + Refund refund = refundService.create(refundRequest); + + if (refund == null) { + throw PaymentException.networkError("微信退款API返回数据异常", PaymentType.WECHAT_NATIVE, null); + } + + log.debug("微信退款API调用成功, 退款单号: {}, 微信退款单号: {}, 状态: {}", + refundRequest.getOutRefundNo(), refund.getRefundId(), refund.getStatus()); + + return refund; + + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + log.error("调用微信退款API失败: {}", e.getMessage(), e); + throw PaymentException.networkError("调用微信退款API失败: " + e.getMessage(), PaymentType.WECHAT_NATIVE, e); + } + } + + /** + * 构建退款响应 + */ + private PaymentResponse buildRefundResponse(Refund refund, String orderNo, String refundNo, Integer tenantId) { + PaymentResponse response = new PaymentResponse(); + response.setSuccess(true); + response.setOrderNo(orderNo); + response.setTransactionId(refund.getRefundId()); // 使用微信退款单号 + response.setPaymentType(PaymentType.WECHAT_NATIVE); + response.setTenantId(tenantId); + + // 转换退款状态 + String statusStr = refund.getStatus() != null ? refund.getStatus().name() : null; + PaymentStatus paymentStatus = convertWechatRefundStatus(statusStr); + response.setPaymentStatus(paymentStatus); + + // 设置退款金额(微信返回的金额是分,需要转换为元) + if (refund.getAmount() != null && refund.getAmount().getRefund() != null) { + BigDecimal refundAmount = new BigDecimal(refund.getAmount().getRefund()).divide(new BigDecimal("100")); + response.setAmount(refundAmount); + } + + log.debug("构建退款响应完成 - 订单号: {}, 退款单号: {}, 微信退款单号: {}, 状态: {}", + orderNo, refundNo, refund.getRefundId(), paymentStatus); + + return response; + } + + /** + * 查询微信退款状态 + */ + private Refund queryWechatRefundStatus(String refundNo, Config wxPayConfig) throws PaymentException { + try { + // 构建退款服务 + RefundService refundService = new RefundService.Builder().config(wxPayConfig).build(); + + // 构建查询请求 + QueryByOutRefundNoRequest queryRequest = new QueryByOutRefundNoRequest(); + queryRequest.setOutRefundNo(refundNo); + + // 调用查询接口 + Refund refund = refundService.queryByOutRefundNo(queryRequest); + + if (refund == null) { + throw PaymentException.systemError("微信退款查询返回空结果", null); + } + + log.debug("微信退款查询成功, 退款单号: {}, 微信退款单号: {}, 状态: {}", + refundNo, refund.getRefundId(), refund.getStatus()); + + return refund; + + } catch (Exception e) { + if (e instanceof PaymentException) { + throw e; + } + log.error("查询微信退款状态失败, 退款单号: {}, 错误: {}", refundNo, e.getMessage(), e); + throw PaymentException.networkError("查询微信退款状态失败: " + e.getMessage(), PaymentType.WECHAT_NATIVE, e); + } + } + + /** + * 构建退款查询响应 + */ + private PaymentResponse buildRefundQueryResponse(Refund refund, Integer tenantId) { + PaymentResponse response = new PaymentResponse(); + response.setSuccess(true); + response.setOrderNo(refund.getOutTradeNo()); + response.setTransactionId(refund.getRefundId()); + response.setPaymentType(PaymentType.WECHAT_NATIVE); + response.setTenantId(tenantId); + + // 转换退款状态 + String statusStr = refund.getStatus() != null ? refund.getStatus().name() : null; + PaymentStatus paymentStatus = convertWechatRefundStatus(statusStr); + response.setPaymentStatus(paymentStatus); + + // 设置退款金额 + if (refund.getAmount() != null && refund.getAmount().getRefund() != null) { + BigDecimal refundAmount = new BigDecimal(refund.getAmount().getRefund()).divide(new BigDecimal("100")); + response.setAmount(refundAmount); + } + + return response; + } + + /** + * 转换微信退款状态 + */ + private PaymentStatus convertWechatRefundStatus(String refundStatus) { + if (refundStatus == null) { + return PaymentStatus.REFUNDING; + } + + switch (refundStatus) { + case "SUCCESS": + return PaymentStatus.REFUNDED; + case "CLOSED": + return PaymentStatus.REFUND_FAILED; + case "PROCESSING": + return PaymentStatus.REFUNDING; + case "ABNORMAL": + return PaymentStatus.REFUND_FAILED; + default: + return PaymentStatus.REFUNDING; + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/payment/utils/PaymentTypeCompatibilityUtil.java b/jczxw-java/src/main/java/com/gxwebsoft/payment/utils/PaymentTypeCompatibilityUtil.java new file mode 100644 index 0000000..682bfef --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/payment/utils/PaymentTypeCompatibilityUtil.java @@ -0,0 +1,165 @@ +package com.gxwebsoft.payment.utils; + +import com.gxwebsoft.payment.enums.PaymentType; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * 支付方式兼容性处理工具类 + * 处理废弃支付方式到核心支付方式的映射转换 + * + * @author 科技小王子 + * @since 2025-08-30 + */ +@Slf4j +public class PaymentTypeCompatibilityUtil { + + /** + * 废弃支付方式到核心支付方式的映射表 + */ + private static final Map DEPRECATED_TO_CORE_MAPPING = new HashMap<>(); + + static { + // 旧编号到新编号的映射 + DEPRECATED_TO_CORE_MAPPING.put(3, 2); // 支付宝(旧3) -> 支付宝(新2) + DEPRECATED_TO_CORE_MAPPING.put(12, 6); // 免费(旧12) -> 免费(新6) + DEPRECATED_TO_CORE_MAPPING.put(15, 7); // 积分支付(旧15) -> 积分支付(新7) + DEPRECATED_TO_CORE_MAPPING.put(19, 3); // 银联支付(旧19) -> 银联支付(新3) + + // 会员卡类支付 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(2, 0); // 会员卡支付 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(6, 0); // VIP月卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(7, 0); // VIP年卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(8, 0); // VIP次卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(9, 0); // IC月卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(10, 0); // IC年卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(11, 0); // IC次卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(13, 0); // VIP充值卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(14, 0); // IC充值卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(16, 0); // VIP季卡 -> 余额支付 + DEPRECATED_TO_CORE_MAPPING.put(17, 0); // IC季卡 -> 余额支付 + + // 微信Native -> 微信支付 + DEPRECATED_TO_CORE_MAPPING.put(102, 1); // 微信Native -> 微信支付 + + // 代付 -> 微信支付(默认) + DEPRECATED_TO_CORE_MAPPING.put(18, 1); // 代付 -> 微信支付 + } + + /** + * 将废弃的支付方式转换为核心支付方式 + * + * @param originalPayType 原始支付方式代码 + * @return 转换后的核心支付方式代码 + */ + public static Integer convertToCore(Integer originalPayType) { + if (originalPayType == null) { + return null; + } + + // 检查是否为废弃的支付方式 + if (DEPRECATED_TO_CORE_MAPPING.containsKey(originalPayType)) { + Integer corePayType = DEPRECATED_TO_CORE_MAPPING.get(originalPayType); + log.warn("检测到废弃的支付方式: {} -> {},建议升级到核心支付方式", + originalPayType, corePayType); + return corePayType; + } + + // 如果是核心支付方式,直接返回 + return originalPayType; + } + + /** + * 检查支付方式是否已废弃 + * + * @param payType 支付方式代码 + * @return true表示已废弃 + */ + public static boolean isDeprecated(Integer payType) { + return payType != null && DEPRECATED_TO_CORE_MAPPING.containsKey(payType); + } + + /** + * 获取支付方式的迁移说明 + * + * @param payType 支付方式代码 + * @return 迁移说明文本 + */ + public static String getMigrationMessage(Integer payType) { + if (payType == null || !isDeprecated(payType)) { + return null; + } + + PaymentType originalType = PaymentType.getByCode(payType); + PaymentType coreType = PaymentType.getByCode(convertToCore(payType)); + + if (originalType != null && coreType != null) { + return String.format("支付方式 %s(%d) 已废弃,建议使用 %s(%d)", + originalType.getName(), payType, + coreType.getName(), coreType.getCode()); + } + + return "该支付方式已废弃,请使用核心支付方式"; + } + + /** + * 获取所有核心支付方式代码 + * + * @return 核心支付方式代码数组 + */ + public static Integer[] getCorePaymentTypeCodes() { + return new Integer[]{0, 1, 2, 3, 4, 5, 6, 7}; + } + + /** + * 检查是否为核心支付方式 + * + * @param payType 支付方式代码 + * @return true表示是核心支付方式 + */ + public static boolean isCorePaymentType(Integer payType) { + if (payType == null) { + return false; + } + + for (Integer coreType : getCorePaymentTypeCodes()) { + if (coreType.equals(payType)) { + return true; + } + } + return false; + } + + /** + * 生成支付方式迁移报告 + * + * @return 迁移报告文本 + */ + public static String generateMigrationReport() { + StringBuilder report = new StringBuilder(); + report.append("=== 支付方式迁移报告 ===\n"); + report.append("核心支付方式(8种):\n"); + + for (Integer coreType : getCorePaymentTypeCodes()) { + PaymentType type = PaymentType.getByCode(coreType); + if (type != null) { + report.append(String.format(" %d - %s\n", coreType, type.getName())); + } + } + + report.append("\n废弃支付方式映射:\n"); + for (Map.Entry entry : DEPRECATED_TO_CORE_MAPPING.entrySet()) { + PaymentType originalType = PaymentType.getByCode(entry.getKey()); + PaymentType coreType = PaymentType.getByCode(entry.getValue()); + if (originalType != null && coreType != null) { + report.append(String.format(" %d(%s) -> %d(%s)\n", + entry.getKey(), originalType.getName(), + entry.getValue(), coreType.getName())); + } + } + + return report.toString(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/config/OrderConfigProperties.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/config/OrderConfigProperties.java new file mode 100644 index 0000000..887db88 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/config/OrderConfigProperties.java @@ -0,0 +1,235 @@ +package com.gxwebsoft.shop.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 订单相关配置属性 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Data +@Component +@ConfigurationProperties(prefix = "shop.order") +public class OrderConfigProperties { + + /** + * 测试账号配置 + */ + private TestAccount testAccount = new TestAccount(); + + /** + * 租户特殊规则配置 + */ + private List tenantRules; + + /** + * 默认订单配置 + */ + private DefaultConfig defaultConfig = new DefaultConfig(); + + /** + * 订单自动取消配置 + */ + private AutoCancel autoCancel = new AutoCancel(); + + /** + * 错误信息配置 + */ + private ErrorMessages errorMessages = new ErrorMessages(); + + @Data + public static class TestAccount { + /** + * 测试手机号列表 + */ + private List phoneNumbers; + + /** + * 测试支付金额 + */ + private BigDecimal testPayAmount = new BigDecimal("0.01"); + + /** + * 是否启用测试模式 + */ + private boolean enabled = false; + } + + @Data + public static class TenantRule { + /** + * 租户ID + */ + private Integer tenantId; + + /** + * 租户名称 + */ + private String tenantName; + + /** + * 最小金额限制 + */ + private BigDecimal minAmount; + + /** + * 金额限制提示信息 + */ + private String minAmountMessage; + + /** + * 是否启用 + */ + private boolean enabled = true; + } + + @Data + public static class DefaultConfig { + + /** + * 默认标题 + */ + private String defaultTitle = "订单标题"; + + /** + * 默认备注 + */ + private String defaultComments = "暂无"; + + /** + * 最小订单金额 + */ + private BigDecimal minOrderAmount = BigDecimal.ZERO; + + /** + * 订单超时时间(分钟) + */ + private Integer orderTimeoutMinutes = 30; + } + + /** + * 检查是否为测试账号 + */ + public boolean isTestAccount(String phone) { + return testAccount.isEnabled() && + testAccount.getPhoneNumbers() != null && + testAccount.getPhoneNumbers().contains(phone); + } + + @Data + public static class AutoCancel { + /** + * 是否启用自动取消功能 + */ + private boolean enabled = true; + + /** + * 默认超时时间(分钟) + */ + private Integer defaultTimeoutMinutes = 30; + + /** + * 定时任务检查间隔(分钟) + */ + private Integer checkIntervalMinutes = 5; + + /** + * 批量处理大小 + */ + private Integer batchSize = 100; + + /** + * 租户特殊配置 + */ + private List tenantConfigs; + } + + @Data + public static class TenantCancelConfig { + /** + * 租户ID + */ + private Integer tenantId; + + /** + * 租户名称 + */ + private String tenantName; + + /** + * 超时时间(分钟) + */ + private Integer timeoutMinutes; + + /** + * 是否启用 + */ + private boolean enabled = true; + } + + /** + * 获取指定租户的超时时间 + */ + public Integer getTimeoutMinutes(Integer tenantId) { + if (autoCancel.getTenantConfigs() != null) { + for (TenantCancelConfig config : autoCancel.getTenantConfigs()) { + if (config.isEnabled() && config.getTenantId().equals(tenantId)) { + return config.getTimeoutMinutes(); + } + } + } + return autoCancel.getDefaultTimeoutMinutes(); + } + + /** + * 获取租户规则 + */ + public TenantRule getTenantRule(Integer tenantId) { + if (tenantRules == null) { + return null; + } + return tenantRules.stream() + .filter(rule -> rule.isEnabled() && rule.getTenantId().equals(tenantId)) + .findFirst() + .orElse(null); + } + + @Data + public static class ErrorMessages { + /** + * 订单金额计算错误信息 + */ + private String amountCalculationError = "订单金额计算错误,请刷新重试"; + + /** + * 商品不存在错误信息 + */ + private String goodsNotFound = "商品不存在"; + + /** + * 商品已下架错误信息 + */ + private String goodsOffline = "商品已下架"; + + /** + * 库存不足错误信息 + */ + private String stockInsufficient = "商品库存不足"; + + /** + * 购买数量超限错误信息 + */ + private String quantityExceeded = "商品购买数量超过限制"; + + /** + * 商品价格异常错误信息 + */ + private String priceAbnormal = "商品价格异常"; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/constants/WxPayConstants.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/constants/WxPayConstants.java new file mode 100644 index 0000000..1618dd8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/constants/WxPayConstants.java @@ -0,0 +1,200 @@ +package com.gxwebsoft.shop.constants; + +/** + * 微信支付常量类 + * 管理微信支付相关的常量配置 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +public class WxPayConstants { + + /** + * 微信支付类型 + */ + public static class PayType { + /** Native支付 */ + public static final String NATIVE = "NATIVE"; + /** JSAPI支付 */ + public static final String JSAPI = "JSAPI"; + /** H5支付 */ + public static final String MWEB = "MWEB"; + /** APP支付 */ + public static final String APP = "APP"; + } + + /** + * 支付状态 + */ + public static class PayStatus { + /** 支付成功 */ + public static final String SUCCESS = "SUCCESS"; + /** 转入退款 */ + public static final String REFUND = "REFUND"; + /** 未支付 */ + public static final String NOTPAY = "NOTPAY"; + /** 已关闭 */ + public static final String CLOSED = "CLOSED"; + /** 已撤销(付款码支付) */ + public static final String REVOKED = "REVOKED"; + /** 用户支付中(付款码支付) */ + public static final String USERPAYING = "USERPAYING"; + /** 支付失败(其他原因,如银行返回失败) */ + public static final String PAYERROR = "PAYERROR"; + } + + /** + * 回调通知相关 + */ + public static class Notify { + /** 成功响应 */ + public static final String SUCCESS_RESPONSE = "SUCCESS"; + /** 失败响应 */ + public static final String FAIL_RESPONSE = "FAIL"; + + /** 通知类型 - 支付成功 */ + public static final String EVENT_TYPE_PAYMENT = "TRANSACTION.SUCCESS"; + /** 通知类型 - 退款成功 */ + public static final String EVENT_TYPE_REFUND = "REFUND.SUCCESS"; + } + + /** + * 缓存键前缀 + */ + public static class CacheKey { + /** 支付配置缓存键前缀 */ + public static final String PAYMENT_CONFIG_PREFIX = "Payment:wxPay:"; + /** 微信小程序配置缓存键 */ + public static final String MP_WEIXIN_CONFIG = "mp-weixin"; + } + + /** + * 配置相关 + */ + public static class Config { + /** 货币类型 - 人民币 */ + public static final String CURRENCY_CNY = "CNY"; + /** 金额转换倍数(元转分) */ + public static final int AMOUNT_MULTIPLIER = 100; + + /** 开发环境标识 */ + public static final String PROFILE_DEV = "dev"; + /** 生产环境标识 */ + public static final String PROFILE_PROD = "prod"; + } + + /** + * 订单相关 + */ + public static class Order { + /** 订单超时时间(分钟) */ + public static final int TIMEOUT_MINUTES = 30; + /** 订单描述最大长度 */ + public static final int DESCRIPTION_MAX_LENGTH = 127; + } + + /** + * HTTP头部相关 + */ + public static class Header { + /** 微信支付签名 */ + public static final String WECHATPAY_SIGNATURE = "Wechatpay-Signature"; + /** 微信支付时间戳 */ + public static final String WECHATPAY_TIMESTAMP = "Wechatpay-Timestamp"; + /** 微信支付随机数 */ + public static final String WECHATPAY_NONCE = "Wechatpay-Nonce"; + /** 微信支付序列号 */ + public static final String WECHATPAY_SERIAL = "Wechatpay-Serial"; + /** 请求ID */ + public static final String REQUEST_ID = "Request-ID"; + } + + /** + * 错误信息 + */ + public static class ErrorMessage { + /** 配置未找到 */ + public static final String CONFIG_NOT_FOUND = "微信支付配置未找到"; + /** 证书文件不存在 */ + public static final String CERTIFICATE_NOT_FOUND = "微信支付证书文件不存在"; + /** 参数验证失败 */ + public static final String PARAM_VALIDATION_FAILED = "参数验证失败"; + /** 签名验证失败 */ + public static final String SIGNATURE_VERIFICATION_FAILED = "签名验证失败"; + /** 订单不存在 */ + public static final String ORDER_NOT_FOUND = "订单不存在"; + /** 订单状态异常 */ + public static final String ORDER_STATUS_INVALID = "订单状态异常"; + /** 金额不匹配 */ + public static final String AMOUNT_MISMATCH = "订单金额不匹配"; + /** 网络请求失败 */ + public static final String NETWORK_REQUEST_FAILED = "网络请求失败"; + /** 系统内部错误 */ + public static final String SYSTEM_INTERNAL_ERROR = "系统内部错误"; + } + + /** + * 日志相关 + */ + public static class LogMessage { + /** 支付请求开始 */ + public static final String PAY_REQUEST_START = "开始处理微信支付请求"; + /** 支付请求成功 */ + public static final String PAY_REQUEST_SUCCESS = "微信支付请求处理成功"; + /** 支付请求失败 */ + public static final String PAY_REQUEST_FAILED = "微信支付请求处理失败"; + + /** 回调处理开始 */ + public static final String CALLBACK_START = "开始处理微信支付回调"; + /** 回调处理成功 */ + public static final String CALLBACK_SUCCESS = "微信支付回调处理成功"; + /** 回调处理失败 */ + public static final String CALLBACK_FAILED = "微信支付回调处理失败"; + + /** 配置加载成功 */ + public static final String CONFIG_LOADED = "微信支付配置加载成功"; + /** 配置加载失败 */ + public static final String CONFIG_LOAD_FAILED = "微信支付配置加载失败"; + } + + /** + * 正则表达式 + */ + public static class Regex { + /** 商户号格式 */ + public static final String MERCHANT_ID = "^\\d{10}$"; + /** 订单号格式 */ + public static final String ORDER_NO = "^[a-zA-Z0-9_-]{1,32}$"; + /** 金额格式(分) */ + public static final String AMOUNT = "^[1-9]\\d*$"; + } + + /** + * 时间相关 + */ + public static class Time { + /** 签名有效期(秒) */ + public static final long SIGNATURE_VALID_SECONDS = 300; + /** 配置缓存有效期(秒) */ + public static final long CONFIG_CACHE_SECONDS = 3600; + } + + /** + * 文件相关 + */ + public static class File { + /** 证书文件扩展名 */ + public static final String CERT_EXTENSION = ".pem"; + /** 私钥文件名 */ + public static final String PRIVATE_KEY_FILE = "apiclient_key.pem"; + /** 商户证书文件名 */ + public static final String MERCHANT_CERT_FILE = "apiclient_cert.pem"; + /** 平台证书文件名 */ + public static final String PLATFORM_CERT_FILE = "wechatpay_cert.pem"; + } + + // 私有构造函数,防止实例化 + private WxPayConstants() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/CouponStatusController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/CouponStatusController.java new file mode 100644 index 0000000..ded942f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/CouponStatusController.java @@ -0,0 +1,189 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.service.CouponStatusService; +import com.gxwebsoft.shop.service.CouponStatusService.CouponStatusResult; +import com.gxwebsoft.shop.service.CouponStatusService.CouponValidationResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 优惠券状态管理控制器 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +@Tag(name = "优惠券状态管理") +@RestController +@RequestMapping("/api/shop/coupon-status") +public class CouponStatusController extends BaseController { + + @Autowired + private CouponStatusService couponStatusService; + + @Operation(summary = "获取当前用户可用优惠券") + @GetMapping("/available") + public ApiResult> getAvailableCoupons() { + try { + List coupons = couponStatusService.getAvailableCoupons(getLoginUserId()); + return success("获取成功", coupons); + } catch (Exception e) { + log.error("获取可用优惠券失败", e); + return fail("获取失败",null); + } + } + + @Operation(summary = "获取当前用户已使用优惠券") + @GetMapping("/used") + public ApiResult> getUsedCoupons() { + try { + List coupons = couponStatusService.getUsedCoupons(getLoginUserId()); + return success("获取成功", coupons); + } catch (Exception e) { + log.error("获取已使用优惠券失败", e); + return fail("获取失败",null); + } + } + + @Operation(summary = "获取当前用户已过期优惠券") + @GetMapping("/expired") + public ApiResult> getExpiredCoupons() { + try { + List coupons = couponStatusService.getExpiredCoupons(getLoginUserId()); + return success("获取成功", coupons); + } catch (Exception e) { + log.error("获取已过期优惠券失败", e); + return fail("获取失败",null); + } + } + + @Operation(summary = "获取当前用户所有优惠券(按状态分类)") + @GetMapping("/all-grouped") + public ApiResult getAllCouponsGrouped() { + try { + CouponStatusResult result = couponStatusService.getUserCouponsGroupByStatus(getLoginUserId()); + return success("获取成功", result); + } catch (Exception e) { + log.error("获取优惠券分类失败", e); + return fail("获取失败",null); + } + } + + @Operation(summary = "验证优惠券是否可用于订单") + @PostMapping("/validate") + public ApiResult validateCouponForOrder( + @Parameter(description = "用户优惠券ID") @RequestParam Long userCouponId, + @Parameter(description = "订单总金额") @RequestParam BigDecimal totalAmount, + @Parameter(description = "商品ID列表") @RequestBody List goodsIds) { + try { + CouponValidationResult result = couponStatusService.validateCouponForOrder( + userCouponId, totalAmount, goodsIds); + return success(result.getMessage(), result); + } catch (Exception e) { + log.error("验证优惠券失败", e); + return fail("验证失败",null); + } + } + + @Operation(summary = "使用优惠券") + @PostMapping("/use") + public ApiResult useCoupon( + @Parameter(description = "用户优惠券ID") @RequestParam Long userCouponId, + @Parameter(description = "订单ID") @RequestParam Integer orderId, + @Parameter(description = "订单号") @RequestParam String orderNo) { + try { + boolean success = couponStatusService.useCoupon(userCouponId, orderId, orderNo); + if (success) { + return success("使用成功"); + } else { + return fail("使用失败"); + } + } catch (Exception e) { + log.error("使用优惠券失败", e); + return fail("使用失败"); + } + } + + @Operation(summary = "退还优惠券(订单取消时)") + @PostMapping("/return/{orderId}") + public ApiResult returnCoupon( + @Parameter(description = "订单ID") @PathVariable Integer orderId) { + try { + boolean success = couponStatusService.returnCoupon(orderId); + if (success) { + return success("退还成功"); + } else { + return fail("退还失败"); + } + } catch (Exception e) { + log.error("退还优惠券失败", e); + return fail("退还失败"); + } + } + + @PreAuthorize("hasAuthority('shop:coupon:manage')") + @Operation(summary = "批量更新过期优惠券状态(管理员)") + @PostMapping("/update-expired") + public ApiResult updateExpiredCoupons() { + try { + int updatedCount = couponStatusService.updateExpiredCoupons(); + return success("更新完成,共更新 " + updatedCount + " 张优惠券"); + } catch (Exception e) { + log.error("批量更新过期优惠券失败", e); + return fail("更新失败"); + } + } + + @Operation(summary = "获取优惠券状态统计") + @GetMapping("/statistics") + public ApiResult getCouponStatistics() { + try { + CouponStatusResult result = couponStatusService.getUserCouponsGroupByStatus(getLoginUserId()); + + CouponStatistics statistics = new CouponStatistics(); + statistics.setAvailableCount(result.getAvailableCoupons().size()); + statistics.setUsedCount(result.getUsedCoupons().size()); + statistics.setExpiredCount(result.getExpiredCoupons().size()); + statistics.setTotalCount(result.getTotalCount()); + + return success("获取成功", statistics); + } catch (Exception e) { + log.error("获取优惠券统计失败", e); + return fail("获取失败",null); + } + } + + /** + * 优惠券统计信息 + */ + public static class CouponStatistics { + private int availableCount; // 可用数量 + private int usedCount; // 已使用数量 + private int expiredCount; // 已过期数量 + private int totalCount; // 总数量 + + // Getters and Setters + public int getAvailableCount() { return availableCount; } + public void setAvailableCount(int availableCount) { this.availableCount = availableCount; } + + public int getUsedCount() { return usedCount; } + public void setUsedCount(int usedCount) { this.usedCount = usedCount; } + + public int getExpiredCount() { return expiredCount; } + public void setExpiredCount(int expiredCount) { this.expiredCount = expiredCount; } + + public int getTotalCount() { return totalCount; } + public void setTotalCount(int totalCount) { this.totalCount = totalCount; } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java new file mode 100644 index 0000000..d882ba2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java @@ -0,0 +1,129 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopArticleService; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品文章控制器 + * + * @author 科技小王子 + * @since 2025-08-13 05:14:53 + */ +@Tag(name = "商品文章管理") +@RestController +@RequestMapping("/api/shop/shop-article") +public class ShopArticleController extends BaseController { + @Resource + private ShopArticleService shopArticleService; + + @PreAuthorize("hasAuthority('shop:shopArticle:list')") + @Operation(summary = "分页查询商品文章") + @GetMapping("/page") + public ApiResult> page(ShopArticleParam param) { + // 使用关联查询 + return success(shopArticleService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:list')") + @Operation(summary = "查询全部商品文章") + @GetMapping() + public ApiResult> list(ShopArticleParam param) { + // 使用关联查询 + return success(shopArticleService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:list')") + @Operation(summary = "根据id查询商品文章") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopArticleService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:save')") + @OperationLog + @Operation(summary = "添加商品文章") + @PostMapping() + public ApiResult save(@RequestBody ShopArticle shopArticle) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopArticle.setUserId(loginUser.getUserId()); + } + if (shopArticleService.save(shopArticle)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:update')") + @OperationLog + @Operation(summary = "修改商品文章") + @PutMapping() + public ApiResult update(@RequestBody ShopArticle shopArticle) { + if (shopArticleService.updateById(shopArticle)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:remove')") + @OperationLog + @Operation(summary = "删除商品文章") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopArticleService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:save')") + @OperationLog + @Operation(summary = "批量添加商品文章") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopArticleService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:update')") + @OperationLog + @Operation(summary = "批量修改商品文章") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopArticleService, "article_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopArticle:remove')") + @OperationLog + @Operation(summary = "批量删除商品文章") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopArticleService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopBrandController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopBrandController.java new file mode 100644 index 0000000..ec2c25c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopBrandController.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopBrandService; +import com.gxwebsoft.shop.entity.ShopBrand; +import com.gxwebsoft.shop.param.ShopBrandParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 品牌控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "品牌管理") +@RestController +@RequestMapping("/api/shop/shop-brand") +public class ShopBrandController extends BaseController { + @Resource + private ShopBrandService shopBrandService; + + @Operation(summary = "分页查询品牌") + @GetMapping("/page") + public ApiResult> page(ShopBrandParam param) { + // 使用关联查询 + return success(shopBrandService.pageRel(param)); + } + + @Operation(summary = "查询全部品牌") + @GetMapping() + public ApiResult> list(ShopBrandParam param) { + // 使用关联查询 + return success(shopBrandService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopBrand:list')") + @Operation(summary = "根据id查询品牌") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopBrandService.getByIdRel(id)); + } + + @Operation(summary = "添加品牌") + @PostMapping() + public ApiResult save(@RequestBody ShopBrand shopBrand) { + if (shopBrandService.save(shopBrand)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改品牌") + @PutMapping() + public ApiResult update(@RequestBody ShopBrand shopBrand) { + if (shopBrandService.updateById(shopBrand)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除品牌") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopBrandService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加品牌") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopBrandService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改品牌") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopBrandService, "brand_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除品牌") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopBrandService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCartController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCartController.java new file mode 100644 index 0000000..22ada86 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCartController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopCartService; +import com.gxwebsoft.shop.entity.ShopCart; +import com.gxwebsoft.shop.param.ShopCartParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 购物车控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "购物车管理") +@RestController +@RequestMapping("/api/shop/shop-cart") +public class ShopCartController extends BaseController { + @Resource + private ShopCartService shopCartService; + + @Operation(summary = "分页查询购物车") + @GetMapping("/page") + public ApiResult> page(ShopCartParam param) { + // 使用关联查询 + return success(shopCartService.pageRel(param)); + } + + @Operation(summary = "查询全部购物车") + @GetMapping() + public ApiResult> list(ShopCartParam param) { + // 使用关联查询 + return success(shopCartService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCart:list')") + @Operation(summary = "根据id查询购物车") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Long id) { + // 使用关联查询 + return success(shopCartService.getByIdRel(id)); + } + + @Operation(summary = "添加购物车") + @PostMapping() + public ApiResult save(@RequestBody ShopCart shopCart) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopCart.setUserId(loginUser.getUserId()); + } + if (shopCartService.save(shopCart)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改购物车") + @PutMapping() + public ApiResult update(@RequestBody ShopCart shopCart) { + if (shopCartService.updateById(shopCart)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除购物车") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCartService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加购物车") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCartService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改购物车") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCartService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除购物车") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCartService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCategoryController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCategoryController.java new file mode 100644 index 0000000..bcffdea --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCategoryController.java @@ -0,0 +1,126 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopCategoryService; +import com.gxwebsoft.shop.entity.ShopCategory; +import com.gxwebsoft.shop.param.ShopCategoryParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品分类控制器 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Tag(name = "商品分类管理") +@RestController +@RequestMapping("/api/shop/shop-category") +public class ShopCategoryController extends BaseController { + @Resource + private ShopCategoryService shopCategoryService; + + @Operation(summary = "分页查询商品分类") + @GetMapping("/page") + public ApiResult> page(ShopCategoryParam param) { + // 使用关联查询 + return success(shopCategoryService.pageRel(param)); + } + + @Operation(summary = "查询全部商品分类") + @GetMapping() + public ApiResult> list(ShopCategoryParam param) { + // 使用关联查询 + return success(shopCategoryService.listRel(param)); + } + + @Operation(summary = "根据id查询商品分类") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopCategoryService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopCategory:save')") + @OperationLog + @Operation(summary = "添加商品分类") + @PostMapping() + public ApiResult save(@RequestBody ShopCategory shopCategory) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopCategory.setUserId(loginUser.getUserId()); + } + if (shopCategoryService.save(shopCategory)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCategory:update')") + @OperationLog + @Operation(summary = "修改商品分类") + @PutMapping() + public ApiResult update(@RequestBody ShopCategory shopCategory) { + if (shopCategoryService.updateById(shopCategory)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCategory:remove')") + @OperationLog + @Operation(summary = "删除商品分类") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCategoryService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCategory:save')") + @OperationLog + @Operation(summary = "批量添加商品分类") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCategoryService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCategory:update')") + @OperationLog + @Operation(summary = "批量修改商品分类") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCategoryService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCategory:remove')") + @OperationLog + @Operation(summary = "批量删除商品分类") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCategoryService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopChatConversationController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopChatConversationController.java new file mode 100644 index 0000000..7e84a9d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopChatConversationController.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopChatConversationService; +import com.gxwebsoft.shop.entity.ShopChatConversation; +import com.gxwebsoft.shop.param.ShopChatConversationParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 聊天会话表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "聊天会话表管理") +@RestController +@RequestMapping("/api/shop/shop-chat-conversation") +public class ShopChatConversationController extends BaseController { + @Resource + private ShopChatConversationService shopChatConversationService; + + @Operation(summary = "分页查询聊天会话表") + @GetMapping("/page") + public ApiResult> page(ShopChatConversationParam param) { + // 使用关联查询 + return success(shopChatConversationService.pageRel(param)); + } + + @Operation(summary = "查询全部聊天会话表") + @GetMapping() + public ApiResult> list(ShopChatConversationParam param) { + // 使用关联查询 + return success(shopChatConversationService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopChatConversation:list')") + @Operation(summary = "根据id查询聊天会话表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopChatConversationService.getByIdRel(id)); + } + + @Operation(summary = "添加聊天会话表") + @PostMapping() + public ApiResult save(@RequestBody ShopChatConversation shopChatConversation) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopChatConversation.setUserId(loginUser.getUserId()); + } + if (shopChatConversationService.save(shopChatConversation)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改聊天会话表") + @PutMapping() + public ApiResult update(@RequestBody ShopChatConversation shopChatConversation) { + if (shopChatConversationService.updateById(shopChatConversation)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除聊天会话表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopChatConversationService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加聊天会话表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopChatConversationService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改聊天会话表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopChatConversationService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除聊天会话表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopChatConversationService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopChatMessageController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopChatMessageController.java new file mode 100644 index 0000000..5e7109f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopChatMessageController.java @@ -0,0 +1,123 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopChatMessageService; +import com.gxwebsoft.shop.entity.ShopChatMessage; +import com.gxwebsoft.shop.param.ShopChatMessageParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 聊天消息表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "聊天消息表管理") +@RestController +@RequestMapping("/api/shop/shop-chat-message") +public class ShopChatMessageController extends BaseController { + @Resource + private ShopChatMessageService shopChatMessageService; + + @PreAuthorize("hasAuthority('shop:shopChatMessage:list')") + @Operation(summary = "分页查询聊天消息表") + @GetMapping("/page") + public ApiResult> page(ShopChatMessageParam param) { + // 使用关联查询 + return success(shopChatMessageService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:list')") + @Operation(summary = "查询全部聊天消息表") + @GetMapping() + public ApiResult> list(ShopChatMessageParam param) { + // 使用关联查询 + return success(shopChatMessageService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:list')") + @Operation(summary = "根据id查询聊天消息表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopChatMessageService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:save')") + @Operation(summary = "添加聊天消息表") + @PostMapping() + public ApiResult save(@RequestBody ShopChatMessage shopChatMessage) { + // 获取当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopChatMessage.setFormUserId(loginUser.getUserId()); + } + if (shopChatMessageService.save(shopChatMessage)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:update')") + @Operation(summary = "修改聊天消息表") + @PutMapping() + public ApiResult update(@RequestBody ShopChatMessage shopChatMessage) { + if (shopChatMessageService.updateById(shopChatMessage)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:remove')") + @Operation(summary = "删除聊天消息表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopChatMessageService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:save')") + @Operation(summary = "批量添加聊天消息表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopChatMessageService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:update')") + @Operation(summary = "批量修改聊天消息表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopChatMessageService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopChatMessage:remove')") + @Operation(summary = "批量删除聊天消息表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopChatMessageService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCommissionRoleController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCommissionRoleController.java new file mode 100644 index 0000000..f6aa5ad --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCommissionRoleController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopCommissionRoleService; +import com.gxwebsoft.shop.entity.ShopCommissionRole; +import com.gxwebsoft.shop.param.ShopCommissionRoleParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 分红角色控制器 + * + * @author 科技小王子 + * @since 2025-05-01 10:01:15 + */ +@Tag(name = "分红角色管理") +@RestController +@RequestMapping("/api/shop/shop-commission-role") +public class ShopCommissionRoleController extends BaseController { + @Resource + private ShopCommissionRoleService shopCommissionRoleService; + + @Operation(summary = "分页查询分红角色") + @GetMapping("/page") + public ApiResult> page(ShopCommissionRoleParam param) { + // 使用关联查询 + return success(shopCommissionRoleService.pageRel(param)); + } + + @Operation(summary = "查询全部分红角色") + @GetMapping() + public ApiResult> list(ShopCommissionRoleParam param) { + // 使用关联查询 + return success(shopCommissionRoleService.listRel(param)); + } + + @Operation(summary = "根据id查询分红角色") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopCommissionRoleService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopCommissionRole:save')") + @OperationLog + @Operation(summary = "添加分红角色") + @PostMapping() + public ApiResult save(@RequestBody ShopCommissionRole shopCommissionRole) { + if (shopCommissionRoleService.save(shopCommissionRole)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCommissionRole:update')") + @OperationLog + @Operation(summary = "修改分红角色") + @PutMapping() + public ApiResult update(@RequestBody ShopCommissionRole shopCommissionRole) { + if (shopCommissionRoleService.updateById(shopCommissionRole)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCommissionRole:remove')") + @OperationLog + @Operation(summary = "删除分红角色") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCommissionRoleService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCommissionRole:save')") + @OperationLog + @Operation(summary = "批量添加分红角色") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCommissionRoleService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCommissionRole:update')") + @OperationLog + @Operation(summary = "批量修改分红角色") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCommissionRoleService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCommissionRole:remove')") + @OperationLog + @Operation(summary = "批量删除分红角色") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCommissionRoleService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCountController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCountController.java new file mode 100644 index 0000000..3664a24 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCountController.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopCountService; +import com.gxwebsoft.shop.entity.ShopCount; +import com.gxwebsoft.shop.param.ShopCountParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商城销售统计表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "商城销售统计表管理") +@RestController +@RequestMapping("/api/shop/shop-count") +public class ShopCountController extends BaseController { + @Resource + private ShopCountService shopCountService; + + @Operation(summary = "分页查询商城销售统计表") + @GetMapping("/page") + public ApiResult> page(ShopCountParam param) { + // 使用关联查询 + return success(shopCountService.pageRel(param)); + } + + @Operation(summary = "查询全部商城销售统计表") + @GetMapping() + public ApiResult> list(ShopCountParam param) { + // 使用关联查询 + return success(shopCountService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCount:list')") + @Operation(summary = "根据id查询商城销售统计表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopCountService.getByIdRel(id)); + } + + @Operation(summary = "添加商城销售统计表") + @PostMapping() + public ApiResult save(@RequestBody ShopCount shopCount) { + if (shopCountService.save(shopCount)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改商城销售统计表") + @PutMapping() + public ApiResult update(@RequestBody ShopCount shopCount) { + if (shopCountService.updateById(shopCount)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除商城销售统计表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCountService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加商城销售统计表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCountService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改商城销售统计表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCountService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除商城销售统计表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCountService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponApplyCateController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponApplyCateController.java new file mode 100644 index 0000000..ada1a79 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponApplyCateController.java @@ -0,0 +1,124 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopCouponApplyCateService; +import com.gxwebsoft.shop.entity.ShopCouponApplyCate; +import com.gxwebsoft.shop.param.ShopCouponApplyCateParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 优惠券可用分类控制器 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +@Tag(name = "优惠券可用分类管理") +@RestController +@RequestMapping("/api/shop/shop-coupon-apply-cate") +public class ShopCouponApplyCateController extends BaseController { + @Resource + private ShopCouponApplyCateService shopCouponApplyCateService; + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:list')") + @Operation(summary = "分页查询优惠券可用分类") + @GetMapping("/page") + public ApiResult> page(ShopCouponApplyCateParam param) { + // 使用关联查询 + return success(shopCouponApplyCateService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:list')") + @Operation(summary = "查询全部优惠券可用分类") + @GetMapping() + public ApiResult> list(ShopCouponApplyCateParam param) { + // 使用关联查询 + return success(shopCouponApplyCateService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:list')") + @Operation(summary = "根据id查询优惠券可用分类") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopCouponApplyCateService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:save')") + @OperationLog + @Operation(summary = "添加优惠券可用分类") + @PostMapping() + public ApiResult save(@RequestBody ShopCouponApplyCate shopCouponApplyCate) { + if (shopCouponApplyCateService.save(shopCouponApplyCate)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:update')") + @OperationLog + @Operation(summary = "修改优惠券可用分类") + @PutMapping() + public ApiResult update(@RequestBody ShopCouponApplyCate shopCouponApplyCate) { + if (shopCouponApplyCateService.updateById(shopCouponApplyCate)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:remove')") + @OperationLog + @Operation(summary = "删除优惠券可用分类") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCouponApplyCateService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:save')") + @OperationLog + @Operation(summary = "批量添加优惠券可用分类") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCouponApplyCateService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:update')") + @OperationLog + @Operation(summary = "批量修改优惠券可用分类") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCouponApplyCateService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyCate:remove')") + @OperationLog + @Operation(summary = "批量删除优惠券可用分类") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCouponApplyCateService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponApplyItemController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponApplyItemController.java new file mode 100644 index 0000000..02091c9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponApplyItemController.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopCouponApplyItemService; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.param.ShopCouponApplyItemParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 优惠券可用分类控制器 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +@Tag(name = "优惠券可用分类管理") +@RestController +@RequestMapping("/api/shop/shop-coupon-apply-item") +public class ShopCouponApplyItemController extends BaseController { + @Resource + private ShopCouponApplyItemService shopCouponApplyItemService; + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:list')") + @Operation(summary = "分页查询优惠券可用分类") + @GetMapping("/page") + public ApiResult> page(ShopCouponApplyItemParam param) { + // 使用关联查询 + return success(shopCouponApplyItemService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:list')") + @Operation(summary = "查询全部优惠券可用分类") + @GetMapping() + public ApiResult> list(ShopCouponApplyItemParam param) { + // 使用关联查询 + return success(shopCouponApplyItemService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:list')") + @Operation(summary = "根据id查询优惠券可用分类") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopCouponApplyItemService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:save')") + @OperationLog + @Operation(summary = "添加优惠券可用分类") + @PostMapping() + public ApiResult save(@RequestBody ShopCouponApplyItem shopCouponApplyItem) { + + if (shopCouponApplyItemService.save(shopCouponApplyItem)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:update')") + @OperationLog + @Operation(summary = "修改优惠券可用分类") + @PutMapping() + public ApiResult update(@RequestBody ShopCouponApplyItem shopCouponApplyItem) { + if (shopCouponApplyItemService.updateById(shopCouponApplyItem)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:remove')") + @OperationLog + @Operation(summary = "删除优惠券可用分类") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCouponApplyItemService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:save')") + @OperationLog + @Operation(summary = "批量添加优惠券可用分类") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCouponApplyItemService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:update')") + @OperationLog + @Operation(summary = "批量修改优惠券可用分类") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCouponApplyItemService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCouponApplyItem:remove')") + @OperationLog + @Operation(summary = "批量删除优惠券可用分类") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCouponApplyItemService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponController.java new file mode 100644 index 0000000..1328aa9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopCouponController.java @@ -0,0 +1,217 @@ +package com.gxwebsoft.shop.controller; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopCouponApplyCate; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.service.ShopCouponApplyCateService; +import com.gxwebsoft.shop.service.ShopCouponApplyItemService; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.param.ShopCouponParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/** + * 优惠券控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:24 + */ +@Tag(name = "优惠券管理") +@RestController +@RequestMapping("/api/shop/shop-coupon") +public class ShopCouponController extends BaseController { + @Resource + private ShopCouponService shopCouponService; + @Resource + private ShopUserCouponService userCouponService; + @Resource + private ShopCouponService couponService; + @Resource + private ShopCouponApplyItemService couponApplyItemService; + @Resource + private ShopCouponApplyCateService couponApplyCateService; + + @Operation(summary = "可领取优惠券列表") + @PostMapping("/list") + public ApiResult> page() { + Integer uid = getLoginUserId(); + // 用户已经领取的优惠券 + List userCouponList = userCouponService.userList(uid); + List hasTakeCouponIdList = new ArrayList<>(); + for (ShopUserCoupon userCoupon : userCouponList) { + hasTakeCouponIdList.add(userCoupon.getCouponId()); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); +// if (!hasTakeCouponIdList.isEmpty()) queryWrapper.notIn(Coupon::getCouponId, hasTakeCouponIdList); + queryWrapper.eq(ShopCoupon::getStatus, 0); + queryWrapper.apply("(expire_type = 0 OR (expire_type = 1 AND end_time > '" + + DateUtil.date() + "'))"); + queryWrapper.orderByAsc(ShopCoupon::getSortNumber); + List couponList = couponService.list(queryWrapper); + for (ShopCoupon coupon : couponList) { + coupon.setCouponApplyItemList(couponApplyItemService.list( + new LambdaQueryWrapper().eq(ShopCouponApplyItem::getCouponId, coupon.getId()) + )); + coupon.setCouponApplyCateList(couponApplyCateService.list( + new LambdaQueryWrapper().eq(ShopCouponApplyCate::getCouponId, coupon.getId()) + )); + boolean hasTake = hasTakeCouponIdList.contains(coupon.getId()); + coupon.setHasTake(hasTake); + if (hasTake) { + int userUseNum = 0; + List userCouponList1 = userCouponService.list( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getCouponId, coupon.getId()) + ); + coupon.setUserTakeNum(userCouponList1.size()); + for (ShopUserCoupon userCoupon : userCouponList1) { + if (userCoupon.getIsUse().equals(1)) userUseNum++; + } + coupon.setUserUseNum(userUseNum); + } + } + return success(couponList); + } + + + @Operation(summary = "分页查询优惠券") + @GetMapping("/page") + public ApiResult> page(ShopCouponParam param) { + // 使用关联查询 + return success(shopCouponService.pageRel(param)); + } + + @Operation(summary = "查询全部优惠券") + @GetMapping() + public ApiResult> list(ShopCouponParam param) { + // 使用关联查询 + return success(shopCouponService.listRel(param)); + } + + @Operation(summary = "根据id查询优惠券") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopCouponService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:save')") + @OperationLog + @Operation(summary = "添加优惠券") + @PostMapping() + public ApiResult save(@RequestBody ShopCoupon shopCoupon) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopCoupon.setUserId(loginUser.getUserId()); + } + if (shopCouponService.save(shopCoupon)) { + if (shopCoupon.getCouponApplyCateList() != null && !shopCoupon.getCouponApplyCateList().isEmpty()) { + for (ShopCouponApplyCate couponApplyCate : shopCoupon.getCouponApplyCateList()) { + couponApplyCate.setCouponId(shopCoupon.getId()); + } + couponApplyCateService.saveBatch(shopCoupon.getCouponApplyCateList()); + } + + if (shopCoupon.getCouponApplyItemList() != null && !shopCoupon.getCouponApplyItemList().isEmpty()) { + for (ShopCouponApplyItem couponApplyItem : shopCoupon.getCouponApplyItemList()) { + couponApplyItem.setCouponId(shopCoupon.getId()); + } + couponApplyItemService.saveBatch(shopCoupon.getCouponApplyItemList()); + } + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:update')") + @OperationLog + @Operation(summary = "修改优惠券") + @PutMapping() + public ApiResult update(@RequestBody ShopCoupon shopCoupon) { + if (shopCouponService.updateById(shopCoupon)) { + couponApplyCateService.removeByCouponId(shopCoupon.getId()); + if (shopCoupon.getCouponApplyCateList() != null && !shopCoupon.getCouponApplyCateList().isEmpty()) { + for (ShopCouponApplyCate couponApplyCate : shopCoupon.getCouponApplyCateList()) { + couponApplyCate.setCouponId(shopCoupon.getId()); + } + couponApplyCateService.saveBatch(shopCoupon.getCouponApplyCateList()); + } + + couponApplyItemService.removeByCouponId(shopCoupon.getId()); + if (shopCoupon.getCouponApplyItemList() != null && !shopCoupon.getCouponApplyItemList().isEmpty()) { + for (ShopCouponApplyItem couponApplyItem : shopCoupon.getCouponApplyItemList()) { + couponApplyItem.setCouponId(shopCoupon.getId()); + } + couponApplyItemService.saveBatch(shopCoupon.getCouponApplyItemList()); + } + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:remove')") + @OperationLog + @Operation(summary = "删除优惠券") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopCouponService.removeById(id)) { + couponApplyCateService.removeByCouponId(id); + couponApplyItemService.removeByCouponId(id); + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:save')") + @OperationLog + @Operation(summary = "批量添加优惠券") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopCouponService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:update')") + @OperationLog + @Operation(summary = "批量修改优惠券") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopCouponService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopCoupon:remove')") + @OperationLog + @Operation(summary = "批量删除优惠券") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopCouponService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerApplyController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerApplyController.java new file mode 100644 index 0000000..4404596 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerApplyController.java @@ -0,0 +1,349 @@ +package com.gxwebsoft.shop.controller; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopDealerUser; +import com.gxwebsoft.shop.service.ShopDealerApplyService; +import com.gxwebsoft.shop.entity.ShopDealerApply; +import com.gxwebsoft.shop.param.ShopDealerApplyParam; +import com.gxwebsoft.shop.param.ShopDealerApplyImportParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.service.ShopDealerUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.poi.ss.usermodel.Workbook; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +/** + * 分销商申请记录表控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:50:19 + */ +@Tag(name = "分销商申请记录表管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-apply") +public class ShopDealerApplyController extends BaseController { + @Resource + private ShopDealerApplyService shopDealerApplyService; + @Resource + private ShopDealerUserService shopDealerUserService; + + @PreAuthorize("hasAuthority('shop:shopDealerApply:list')") + @Operation(summary = "分页查询分销商申请记录表") + @GetMapping("/page") + public ApiResult> page(ShopDealerApplyParam param) { + // 使用关联查询 + return success(shopDealerApplyService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:list')") + @Operation(summary = "查询全部分销商申请记录表") + @GetMapping() + public ApiResult> list(ShopDealerApplyParam param) { + // 使用关联查询 + return success(shopDealerApplyService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:list')") + @Operation(summary = "根据id查询分销商申请记录表") + @GetMapping("/{id}") + public ApiResult getById(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerApplyService.getById(id)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:list')") + @Operation(summary = "根据userId查询分销商申请记录表") + @GetMapping("/getByUserId/{id}") + public ApiResult getByUserId(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerApplyService.getByUserIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:save')") + @OperationLog + @Operation(summary = "添加分销商申请记录表") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerApply shopDealerApply) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerApply.setApplyTime(LocalDateTime.now()); + if(shopDealerApply.getUserId() == null) { + shopDealerApply.setUserId(loginUser.getUserId()); + } + } + if (shopDealerApply.getRefereeId() != null) { + if(shopDealerUserService.getByIdRel(shopDealerApply.getRefereeId()) == null){ + return fail("推荐人不存在"); + } + } + + if (shopDealerApplyService.save(shopDealerApply)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:update')") + @OperationLog + @Operation(summary = "修改分销商申请记录表") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerApply shopDealerApply) { + shopDealerApply.setAuditTime(null); + if(shopDealerApply.getRate() != null){ + final ShopDealerUser dealerUser = new ShopDealerUser(); + dealerUser.setRate(shopDealerApply.getRate()); + shopDealerUserService.update(dealerUser, new LambdaQueryWrapper().eq(ShopDealerUser::getUserId, shopDealerApply.getUserId())); + } + if (shopDealerApplyService.updateById(shopDealerApply)) { + if (shopDealerApply.getApplyStatus().equals(20)) { + LocalDateTime now = LocalDateTime.now(); + shopDealerApply.setAuditTime(now); + shopDealerApplyService.updateById(shopDealerApply); + // 同步添加经销商 + if (shopDealerUserService.count(new LambdaQueryWrapper().eq(ShopDealerUser::getUserId, shopDealerApply.getUserId())) == 0) { + final ShopDealerUser dealerUser = new ShopDealerUser(); + dealerUser.setUserId(shopDealerApply.getUserId()); + dealerUser.setRealName(shopDealerApply.getRealName()); + dealerUser.setMobile(shopDealerApply.getMobile()); + dealerUser.setRefereeId(shopDealerApply.getRefereeId()); + shopDealerUserService.save(dealerUser); + } + } + return success("保存成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:remove')") + @OperationLog + @Operation(summary = "删除分销商申请记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerApplyService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:save')") + @OperationLog + @Operation(summary = "批量添加分销商申请记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerApplyService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:update')") + @OperationLog + @Operation(summary = "批量修改分销商申请记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerApplyService, "apply_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:remove')") + @OperationLog + @Operation(summary = "批量删除分销商申请记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerApplyService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + /** + * excel批量导入分销商申请记录 + * Excel表头格式:类型、用户ID、姓名、分销商名称、分销商编码、手机号、合同金额、详细地址、推荐人用户ID、申请方式、审核状态、合同时间、驳回原因、商城ID + */ + @PreAuthorize("hasAuthority('shop:shopDealerApply:save')") + @Transactional(rollbackFor = {Exception.class}) + @Operation(summary = "批量导入分销商申请记录") + @PostMapping("/import") + public ApiResult> importBatch(MultipartFile file) { + ImportParams importParams = new ImportParams(); + // 设置标题行,跳过第一行表头 + importParams.setTitleRows(1); + importParams.setHeadRows(1); + List errorMessages = new ArrayList<>(); + int successCount = 0; + + try { + List list = ExcelImportUtil.importExcel(file.getInputStream(), ShopDealerApplyImportParam.class, importParams); + + // 获取当前登录用户 + User loginUser = getLoginUser(); + Integer currentUserId = loginUser != null ? loginUser.getUserId() : null; + + for (int i = 0; i < list.size(); i++) { + ShopDealerApplyImportParam param = list.get(i); + try { + // 手动转换对象,避免JSON序列化问题 + ShopDealerApply item = convertImportParamToEntity(param); + + // 设置必填字段的默认值 + if (item.getUserId() == null && currentUserId != null) { + item.setUserId(currentUserId); + } + if (item.getApplyStatus() == null) { + item.setApplyStatus(10); // 默认状态为待审核 + } + if (item.getApplyType() == null) { + item.setApplyType(10); // 默认需要后台审核 + } + if (item.getType() == null) { + item.setType(0); // 默认类型为经销商 + } + + // 设置申请时间 + item.setApplyTime(LocalDateTime.now()); + + // 验证必填字段 + if (item.getRealName() == null || item.getRealName().trim().isEmpty()) { + errorMessages.add("第" + (i + 1) + "行:姓名不能为空"); + continue; + } + if (item.getDealerName() == null || item.getDealerName().trim().isEmpty()) { + errorMessages.add("第" + (i + 1) + "行:企业名称不能为空"); + continue; + } + if (item.getMobile() == null || item.getMobile().trim().isEmpty()) { + errorMessages.add("第" + (i + 1) + "行:手机号不能为空"); + continue; + } + + // 验证推荐人是否存在 + if (item.getRefereeId() != null) { + if (shopDealerUserService.getByIdRel(item.getRefereeId()) == null) { + errorMessages.add("第" + (i + 1) + "行:推荐人不存在"); + continue; + } + } + + // 保存数据 + if (shopDealerApplyService.save(item)) { + successCount++; + } else { + errorMessages.add("第" + (i + 1) + "行:保存失败"); + } + + } catch (Exception e) { + errorMessages.add("第" + (i + 1) + "行:" + e.getMessage()); + System.err.println("导入第" + (i + 1) + "行数据失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + // 返回结果 + if (errorMessages.isEmpty()) { + return success("成功导入" + successCount + "条数据", null); + } else { + return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages); + } + + } catch (Exception e) { + System.err.println("批量导入分销商申请记录失败: " + e.getMessage()); + e.printStackTrace(); + return fail("导入失败:" + e.getMessage(), null); + } + } + + /** + * 下载分销商申请记录导入模板 + */ + @Operation(summary = "下载分销商申请记录导入模板") + @GetMapping("/import/template") + public void downloadTemplate(HttpServletResponse response) throws IOException { + // 创建空的导入参数列表作为模板 + List templateList = new ArrayList<>(); + + // 添加一行示例数据 + ShopDealerApplyImportParam example = new ShopDealerApplyImportParam(); + example.setType(0); + example.setRealName("宗馥莉"); + example.setDealerName("娃哈哈有限公司"); + example.setDealerCode("WaHaHa"); + example.setMobile("13800138000"); + example.setApplyType(10); + example.setApplyStatus(10); + example.setContractTime("2025-09-05 10:00:00"); + templateList.add(example); + + // 设置导出参数 + ExportParams exportParams = new ExportParams("分销商申请记录导入模板", "分销商申请记录"); + + // 生成Excel + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, ShopDealerApplyImportParam.class, templateList); + + // 设置响应头 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=shop_dealer_apply_import_template.xlsx"); + + // 输出到响应流 + workbook.write(response.getOutputStream()); + workbook.close(); + } + + /** + * 将ShopDealerApplyImportParam转换为ShopDealerApply实体 + */ + private ShopDealerApply convertImportParamToEntity(ShopDealerApplyImportParam param) { + ShopDealerApply entity = new ShopDealerApply(); + + // 基本字段转换 + entity.setType(param.getType()); + entity.setUserId(param.getUserId()); + entity.setRealName(param.getRealName()); + entity.setDealerName(param.getDealerName()); + entity.setDealerCode(param.getDealerCode()); + entity.setMobile(param.getMobile()); + entity.setMoney(param.getMoney()); + entity.setAddress(param.getAddress()); + entity.setRefereeId(param.getRefereeId()); + entity.setApplyType(param.getApplyType()); + entity.setApplyStatus(param.getApplyStatus()); + entity.setRejectReason(param.getRejectReason()); + entity.setTenantId(param.getTenantId()); + + // 处理合同时间 + if (param.getContractTime() != null && !param.getContractTime().trim().isEmpty()) { + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + entity.setContractTime(LocalDateTime.parse(param.getContractTime(), formatter)); + } catch (Exception e) { + System.err.println("合同时间格式错误: " + param.getContractTime()); + } + } + + return entity; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerBankController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerBankController.java new file mode 100644 index 0000000..a05c0c4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerBankController.java @@ -0,0 +1,138 @@ + package com.gxwebsoft.shop.controller; + + import com.gxwebsoft.common.core.annotation.OperationLog; + import com.gxwebsoft.common.core.web.ApiResult; + import com.gxwebsoft.common.core.web.BaseController; + import com.gxwebsoft.common.core.web.BatchParam; + import com.gxwebsoft.common.core.web.PageResult; + import com.gxwebsoft.common.system.entity.User; + import com.gxwebsoft.shop.entity.ShopDealerBank; + import com.gxwebsoft.shop.param.ShopDealerBankParam; + import com.gxwebsoft.shop.service.ShopDealerBankService; + import io.swagger.v3.oas.annotations.Operation; + import io.swagger.v3.oas.annotations.tags.Tag; + import org.springframework.security.access.prepost.PreAuthorize; + import org.springframework.web.bind.annotation.*; + + import javax.annotation.Resource; + import java.util.List; + + /** + * 分销商提现银行卡控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ + @Tag(name = "分销商提现银行卡管理") + @RestController + @RequestMapping("/api/shop/shop-dealer-bank") + public class ShopDealerBankController extends BaseController { + @Resource + private ShopDealerBankService shopDealerBankService; + + @Operation(summary = "分页查询分销商提现银行卡") + @GetMapping("/page") + public ApiResult> page(ShopDealerBankParam param) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + param.setUserId(loginUser.getUserId()); + return success(shopDealerBankService.pageRel(param)); + } + + @Operation(summary = "查询全部分销商提现银行卡") + @GetMapping() + public ApiResult> list(ShopDealerBankParam param) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + param.setUserId(loginUser.getUserId()); + return success(shopDealerBankService.listRel(param)); + } + + @Operation(summary = "根据id查询分销商提现银行卡") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerBankService.getByIdRel(id)); + } + + @OperationLog + @Operation(summary = "添加分销商提现银行卡") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerBank shopDealerBank) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerBank.setUserId(loginUser.getUserId()); + } + if (shopDealerBankService.save(shopDealerBank)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @OperationLog + @Operation(summary = "修改分销商提现银行卡") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerBank shopDealerBank) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerBank.setUserId(loginUser.getUserId()); + if (shopDealerBankService.updateById(shopDealerBank)) { + return success("修改成功"); + } + } + return fail("修改失败"); + } + + @Operation(summary = "删除分销商提现银行卡") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + if (shopDealerBankService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerBank:save')") + @OperationLog + @Operation(summary = "批量添加分销商提现银行卡") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerBankService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerBank:update')") + @OperationLog + @Operation(summary = "批量修改分销商提现银行卡") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerBankService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerBank:remove')") + @OperationLog + @Operation(summary = "批量删除分销商提现银行卡") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerBankService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + } diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerCapitalController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerCapitalController.java new file mode 100644 index 0000000..d7ccaf1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerCapitalController.java @@ -0,0 +1,129 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopDealerCapitalService; +import com.gxwebsoft.shop.entity.ShopDealerCapital; +import com.gxwebsoft.shop.param.ShopDealerCapitalParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 分销商资金明细表控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Tag(name = "分销商资金明细表管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-capital") +public class ShopDealerCapitalController extends BaseController { + @Resource + private ShopDealerCapitalService shopDealerCapitalService; + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:list')") + @Operation(summary = "分页查询分销商资金明细表") + @GetMapping("/page") + public ApiResult> page(ShopDealerCapitalParam param) { + // 使用关联查询 + return success(shopDealerCapitalService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:list')") + @Operation(summary = "查询全部分销商资金明细表") + @GetMapping() + public ApiResult> list(ShopDealerCapitalParam param) { + // 使用关联查询 + return success(shopDealerCapitalService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:list')") + @Operation(summary = "根据id查询分销商资金明细表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerCapitalService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:save')") + @OperationLog + @Operation(summary = "添加分销商资金明细表") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerCapital shopDealerCapital) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerCapital.setUserId(loginUser.getUserId()); + } + if (shopDealerCapitalService.save(shopDealerCapital)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:update')") + @OperationLog + @Operation(summary = "修改分销商资金明细表") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerCapital shopDealerCapital) { + if (shopDealerCapitalService.updateById(shopDealerCapital)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:remove')") + @OperationLog + @Operation(summary = "删除分销商资金明细表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerCapitalService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:save')") + @OperationLog + @Operation(summary = "批量添加分销商资金明细表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerCapitalService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:update')") + @OperationLog + @Operation(summary = "批量修改分销商资金明细表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerCapitalService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerCapital:remove')") + @OperationLog + @Operation(summary = "批量删除分销商资金明细表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerCapitalService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerOrderController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerOrderController.java new file mode 100644 index 0000000..2ecc05e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerOrderController.java @@ -0,0 +1,171 @@ +package com.gxwebsoft.shop.controller; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopDealerOrderService; +import com.gxwebsoft.shop.entity.ShopDealerOrder; +import com.gxwebsoft.shop.param.ShopDealerOrderParam; +import com.gxwebsoft.shop.param.ShopDealerOrderImportParam; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 分销商订单记录表控制器 + * + * @author 科技小王子 + * @since 2025-08-12 11:55:18 + */ +@Tag(name = "分销商订单记录表管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-order") +public class ShopDealerOrderController extends BaseController { + @Resource + private ShopDealerOrderService shopDealerOrderService; + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:list')") + @Operation(summary = "分页查询分销商订单记录表") + @GetMapping("/page") + public ApiResult> page(ShopDealerOrderParam param) { + // 使用关联查询 + return success(shopDealerOrderService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:list')") + @Operation(summary = "查询全部分销商订单记录表") + @GetMapping() + public ApiResult> list(ShopDealerOrderParam param) { + // 使用关联查询 + return success(shopDealerOrderService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:list')") + @Operation(summary = "根据id查询分销商订单记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerOrderService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:save')") + @OperationLog + @Operation(summary = "添加分销商订单记录表") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerOrder shopDealerOrder) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerOrder.setUserId(loginUser.getUserId()); + } + if (shopDealerOrderService.save(shopDealerOrder)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:update')") + @OperationLog + @Operation(summary = "修改分销商订单记录表") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerOrder shopDealerOrder) { + if (shopDealerOrderService.updateById(shopDealerOrder)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:remove')") + @OperationLog + @Operation(summary = "删除分销商订单记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerOrderService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:save')") + @OperationLog + @Operation(summary = "批量添加分销商订单记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerOrderService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:update')") + @OperationLog + @Operation(summary = "批量修改分销商订单记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerOrderService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerOrder:remove')") + @OperationLog + @Operation(summary = "批量删除分销商订单记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerOrderService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + /** + * excel批量导入分销商订单记录表 + */ + @PreAuthorize("hasAuthority('shop:shopDealerOrder:save')") + @OperationLog + @Operation(summary = "批量导入分销商订单记录表") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/import") + public ApiResult> importBatch(MultipartFile file) { + ImportParams importParams = new ImportParams(); + try { + + // 第三步:导入XLS文件的内容 + List list = ExcelImportUtil.importExcel(file.getInputStream(), ShopDealerOrderImportParam.class, importParams); + list.forEach(d -> { + ShopDealerOrder item = JSONUtil.parseObject(JSONUtil.toJSONString(d), ShopDealerOrder.class); + assert item != null; + if (ObjectUtil.isNotEmpty(item)) { + // 设置默认值 + if (item.getIsInvalid() == null) { + item.setIsInvalid(0); // 新导入的数据isInvalid设为0(未失效) + } + if (item.getIsSettled() == null) { + item.setIsSettled(0); // 新导入的数据isSettled设为0(未结算) + } + shopDealerOrderService.save(item); + } + }); + return success("成功导入" + list.size() + "条", null); + } catch (Exception e) { + e.printStackTrace(); + } + return fail("导入失败", null); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerRecordController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerRecordController.java new file mode 100644 index 0000000..44b2c22 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerRecordController.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.entity.ShopDealerRecord; +import com.gxwebsoft.shop.param.ShopDealerRecordParam; +import com.gxwebsoft.shop.service.ShopDealerRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 客户跟进情况控制器 + * + * @author 科技小王子 + * @since 2025-10-02 12:21:50 + */ +@Tag(name = "客户跟进情况管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-record") +public class ShopDealerRecordController extends BaseController { + @Resource + private ShopDealerRecordService shopDealerRecordService; + + @Operation(summary = "分页查询客户跟进情况") + @GetMapping("/page") + public ApiResult> page(ShopDealerRecordParam param) { + // 使用关联查询 + return success(shopDealerRecordService.pageRel(param)); + } + + @Operation(summary = "查询全部客户跟进情况") + @GetMapping() + public ApiResult> list(ShopDealerRecordParam param) { + // 使用关联查询 + return success(shopDealerRecordService.listRel(param)); + } + + @Operation(summary = "根据id查询客户跟进情况") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerRecordService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:save')") + @OperationLog + @Operation(summary = "添加客户跟进情况") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerRecord shopDealerRecord) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerRecord.setUserId(loginUser.getUserId()); + } + if (shopDealerRecordService.save(shopDealerRecord)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:update')") + @OperationLog + @Operation(summary = "修改客户跟进情况") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerRecord shopDealerRecord) { + if (shopDealerRecordService.updateById(shopDealerRecord)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:remove')") + @OperationLog + @Operation(summary = "删除客户跟进情况") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerRecordService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:save')") + @OperationLog + @Operation(summary = "批量添加客户跟进情况") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerRecordService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:update')") + @OperationLog + @Operation(summary = "批量修改客户跟进情况") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerRecordService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerApply:remove')") + @OperationLog + @Operation(summary = "批量删除客户跟进情况") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerRecordService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerRefereeController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerRefereeController.java new file mode 100644 index 0000000..bb4ef91 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerRefereeController.java @@ -0,0 +1,137 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopUserReferee; +import com.gxwebsoft.shop.service.ShopDealerRefereeService; +import com.gxwebsoft.shop.entity.ShopDealerReferee; +import com.gxwebsoft.shop.param.ShopDealerRefereeParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 分销商推荐关系表控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Tag(name = "分销商推荐关系表管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-referee") +public class ShopDealerRefereeController extends BaseController { + @Resource + private ShopDealerRefereeService shopDealerRefereeService; + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:list')") + @Operation(summary = "分页查询分销商推荐关系表") + @GetMapping("/page") + public ApiResult> page(ShopDealerRefereeParam param) { + // 使用关联查询 + return success(shopDealerRefereeService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:list')") + @Operation(summary = "查询全部分销商推荐关系表") + @GetMapping() + public ApiResult> list(ShopDealerRefereeParam param) { + // 使用关联查询 + return success(shopDealerRefereeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:list')") + @Operation(summary = "根据id查询分销商推荐关系表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerRefereeService.getByIdRel(id)); + } + + @Operation(summary = "根据userId查询推荐人信息") + @GetMapping("/getByUserId/{userId}") + public ApiResult getByUserId(@PathVariable("userId") Integer userId) { + // 使用关联查询 + return success(shopDealerRefereeService.getByUserIdRel(userId)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:save')") + @OperationLog + @Operation(summary = "添加分销商推荐关系表") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerReferee shopDealerReferee) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerReferee.setUserId(loginUser.getUserId()); + } + if (shopDealerRefereeService.save(shopDealerReferee)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:update')") + @OperationLog + @Operation(summary = "修改分销商推荐关系表") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerReferee shopDealerReferee) { + if (shopDealerRefereeService.updateById(shopDealerReferee)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:remove')") + @OperationLog + @Operation(summary = "删除分销商推荐关系表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerRefereeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:save')") + @OperationLog + @Operation(summary = "批量添加分销商推荐关系表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerRefereeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:update')") + @OperationLog + @Operation(summary = "批量修改分销商推荐关系表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerRefereeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerReferee:remove')") + @OperationLog + @Operation(summary = "批量删除分销商推荐关系表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerRefereeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerSettingController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerSettingController.java new file mode 100644 index 0000000..039cf2c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerSettingController.java @@ -0,0 +1,124 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopDealerSettingService; +import com.gxwebsoft.shop.entity.ShopDealerSetting; +import com.gxwebsoft.shop.param.ShopDealerSettingParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 分销商设置表控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Tag(name = "分销商设置表管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-setting") +public class ShopDealerSettingController extends BaseController { + @Resource + private ShopDealerSettingService shopDealerSettingService; + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:list')") + @Operation(summary = "分页查询分销商设置表") + @GetMapping("/page") + public ApiResult> page(ShopDealerSettingParam param) { + // 使用关联查询 + return success(shopDealerSettingService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:list')") + @Operation(summary = "查询全部分销商设置表") + @GetMapping() + public ApiResult> list(ShopDealerSettingParam param) { + // 使用关联查询 + return success(shopDealerSettingService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:list')") + @Operation(summary = "根据id查询分销商设置表") + @GetMapping("/{key}") + public ApiResult get(@PathVariable("key") String key) { + // 使用关联查询 + return success(shopDealerSettingService.getByIdRel(key)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:save')") + @OperationLog + @Operation(summary = "添加分销商设置表") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerSetting shopDealerSetting) { + if (shopDealerSettingService.save(shopDealerSetting)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:update')") + @OperationLog + @Operation(summary = "修改分销商设置表") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerSetting shopDealerSetting) { + if (shopDealerSettingService.updateById(shopDealerSetting)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:remove')") + @OperationLog + @Operation(summary = "删除分销商设置表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerSettingService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:save')") + @OperationLog + @Operation(summary = "批量添加分销商设置表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerSettingService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:update')") + @OperationLog + @Operation(summary = "批量修改分销商设置表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerSettingService, "key")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerSetting:remove')") + @OperationLog + @Operation(summary = "批量删除分销商设置表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerSettingService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerUserController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerUserController.java new file mode 100644 index 0000000..ca84666 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerUserController.java @@ -0,0 +1,180 @@ +package com.gxwebsoft.shop.controller; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.util.ObjectUtil; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopDealerUserService; +import com.gxwebsoft.shop.entity.ShopDealerUser; +import com.gxwebsoft.shop.param.ShopDealerUserParam; +import com.gxwebsoft.shop.param.ShopDealerUserImportParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 分销商用户记录表控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Tag(name = "分销商用户记录表管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-user") +public class ShopDealerUserController extends BaseController { + @Resource + private ShopDealerUserService shopDealerUserService; + + @Operation(summary = "分页查询分销商用户记录表") + @GetMapping("/page") + public ApiResult> page(ShopDealerUserParam param) { + // 使用关联查询 + return success(shopDealerUserService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:list')") + @Operation(summary = "查询全部分销商用户记录表") + @GetMapping() + public ApiResult> list(ShopDealerUserParam param) { + // 使用关联查询 + return success(shopDealerUserService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:list')") + @Operation(summary = "根据userId查询分销商用户") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerUserService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:save')") + @OperationLog + @Operation(summary = "添加分销商用户记录表") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerUser shopDealerUser) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerUser.setUserId(loginUser.getUserId()); + } + if (shopDealerUserService.save(shopDealerUser)) { + return success("添加成功", shopDealerUser); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:update')") + @Operation(summary = "修改分销商用户记录表") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerUser shopDealerUser) { + if (shopDealerUserService.updateById(shopDealerUser)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('sys:user:update')") + @Operation(summary = "修改分销商用户记录表") + @PutMapping("/updateByUserId") + public ApiResult updateByUserId(@RequestBody ShopDealerUser shopDealerUser) { + if (shopDealerUserService.updateByUserId(shopDealerUser)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:remove')") + @OperationLog + @Operation(summary = "删除分销商用户记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerUserService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:save')") + @OperationLog + @Operation(summary = "批量添加分销商用户记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerUserService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:update')") + @OperationLog + @Operation(summary = "批量修改分销商用户记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerUserService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:remove')") + @OperationLog + @Operation(summary = "批量删除分销商用户记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerUserService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerUser:save')") + @Operation(summary = "批量导入分销商用户") + @Transactional(rollbackFor = {Exception.class}) + @PostMapping("/import") + public ApiResult> importBatch(MultipartFile file) { + ImportParams importParams = new ImportParams(); + try { + List list = ExcelImportUtil.importExcel(file.getInputStream(), ShopDealerUserImportParam.class, importParams); + list.forEach(d -> { + ShopDealerUser item = JSONUtil.parseObject(JSONUtil.toJSONString(d), ShopDealerUser.class); + assert item != null; + if (ObjectUtil.isNotEmpty(item)) { + // 设置默认值 + if (item.getIsDelete() == null) { + item.setIsDelete(0); + } + if (item.getSortNumber() == null) { + item.setSortNumber(0); + } + // 记录当前登录用户id(如果没有指定userId) + if (item.getUserId() == null) { + User loginUser = getLoginUser(); + if (loginUser != null) { + item.setUserId(loginUser.getUserId()); + } + } + shopDealerUserService.save(item); + } + }); + return success("成功导入" + list.size() + "条", null); + } catch (Exception e) { + e.printStackTrace(); + } + return fail("导入失败", null); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerWithdrawController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerWithdrawController.java new file mode 100644 index 0000000..00f7b4e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopDealerWithdrawController.java @@ -0,0 +1,155 @@ +package com.gxwebsoft.shop.controller; + +import cn.hutool.core.util.StrUtil; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopDealerUser; +import com.gxwebsoft.shop.service.ShopDealerUserService; +import com.gxwebsoft.shop.service.ShopDealerWithdrawService; +import com.gxwebsoft.shop.entity.ShopDealerWithdraw; +import com.gxwebsoft.shop.param.ShopDealerWithdrawParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 分销商提现明细表控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Tag(name = "分销商提现明细表管理") +@RestController +@RequestMapping("/api/shop/shop-dealer-withdraw") +public class ShopDealerWithdrawController extends BaseController { + @Resource + private ShopDealerWithdrawService shopDealerWithdrawService; + @Resource + private ShopDealerUserService shopDealerUserService; + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:list')") + @Operation(summary = "分页查询分销商提现明细表") + @GetMapping("/page") + public ApiResult> page(ShopDealerWithdrawParam param) { + // 使用关联查询 + return success(shopDealerWithdrawService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:list')") + @Operation(summary = "查询全部分销商提现明细表") + @GetMapping() + public ApiResult> list(ShopDealerWithdrawParam param) { + // 使用关联查询 + return success(shopDealerWithdrawService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:list')") + @Operation(summary = "根据id查询分销商提现明细表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopDealerWithdrawService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:save')") + @OperationLog + @Transactional(rollbackFor = {Exception.class}) + @Operation(summary = "添加分销商提现明细表") + @PostMapping() + public ApiResult save(@RequestBody ShopDealerWithdraw shopDealerWithdraw) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopDealerWithdraw.setUserId(loginUser.getUserId()); + final ShopDealerUser dealerUser = shopDealerUserService.getByUserIdRel(loginUser.getUserId()); + // 扣除提现金额 + dealerUser.setMoney(dealerUser.getMoney().subtract(shopDealerWithdraw.getMoney())); + shopDealerUserService.updateById(dealerUser); + if (shopDealerWithdrawService.save(shopDealerWithdraw)) { + return success("添加成功"); + } + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:update')") + @OperationLog + @Operation(summary = "修改分销商提现明细表") + @PutMapping() + public ApiResult update(@RequestBody ShopDealerWithdraw shopDealerWithdraw) { + // 驳回操作,退回金额 + if(shopDealerWithdraw.getApplyStatus().equals(30)){ + final ShopDealerUser dealerUser = shopDealerUserService.getByUserIdRel(shopDealerWithdraw.getUserId()); + dealerUser.setMoney(dealerUser.getMoney().add(shopDealerWithdraw.getMoney())); + shopDealerUserService.updateById(dealerUser); + } + // 已打款,要求上传凭证 + if(shopDealerWithdraw.getApplyStatus().equals(40)){ + shopDealerWithdraw.setAuditTime(LocalDateTime.now()); + if(StrUtil.isBlankIfStr(shopDealerWithdraw.getImage())){ + return fail("请上传打款凭证"); + } + } + if (shopDealerWithdrawService.updateById(shopDealerWithdraw)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:remove')") + @OperationLog + @Operation(summary = "删除分销商提现明细表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopDealerWithdrawService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:save')") + @OperationLog + @Operation(summary = "批量添加分销商提现明细表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopDealerWithdrawService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:update')") + @OperationLog + @Operation(summary = "批量修改分销商提现明细表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopDealerWithdrawService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:remove')") + @OperationLog + @Operation(summary = "批量删除分销商提现明细表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopDealerWithdrawService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressController.java new file mode 100644 index 0000000..c638b0f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopExpressService; +import com.gxwebsoft.shop.entity.ShopExpress; +import com.gxwebsoft.shop.param.ShopExpressParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 物流公司控制器 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Tag(name = "物流公司管理") +@RestController +@RequestMapping("/api/shop/shop-express") +public class ShopExpressController extends BaseController { + @Resource + private ShopExpressService shopExpressService; + + @Operation(summary = "分页查询物流公司") + @GetMapping("/page") + public ApiResult> page(ShopExpressParam param) { + // 使用关联查询 + return success(shopExpressService.pageRel(param)); + } + + @Operation(summary = "查询全部物流公司") + @GetMapping() + public ApiResult> list(ShopExpressParam param) { + // 使用关联查询 + return success(shopExpressService.listRel(param)); + } + + @Operation(summary = "根据id查询物流公司") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopExpressService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopExpress:save')") + @OperationLog + @Operation(summary = "添加物流公司") + @PostMapping() + public ApiResult save(@RequestBody ShopExpress shopExpress) { + if (shopExpressService.save(shopExpress)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpress:update')") + @OperationLog + @Operation(summary = "修改物流公司") + @PutMapping() + public ApiResult update(@RequestBody ShopExpress shopExpress) { + if (shopExpressService.updateById(shopExpress)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpress:remove')") + @OperationLog + @Operation(summary = "删除物流公司") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopExpressService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpress:save')") + @OperationLog + @Operation(summary = "批量添加物流公司") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopExpressService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpress:update')") + @OperationLog + @Operation(summary = "批量修改物流公司") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopExpressService, "express_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpress:remove')") + @OperationLog + @Operation(summary = "批量删除物流公司") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopExpressService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressTemplateController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressTemplateController.java new file mode 100644 index 0000000..bbc7ac2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressTemplateController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopExpressTemplateService; +import com.gxwebsoft.shop.entity.ShopExpressTemplate; +import com.gxwebsoft.shop.param.ShopExpressTemplateParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 运费模板控制器 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Tag(name = "运费模板管理") +@RestController +@RequestMapping("/api/shop/shop-express-template") +public class ShopExpressTemplateController extends BaseController { + @Resource + private ShopExpressTemplateService shopExpressTemplateService; + + @Operation(summary = "分页查询运费模板") + @GetMapping("/page") + public ApiResult> page(ShopExpressTemplateParam param) { + // 使用关联查询 + return success(shopExpressTemplateService.pageRel(param)); + } + + @Operation(summary = "查询全部运费模板") + @GetMapping() + public ApiResult> list(ShopExpressTemplateParam param) { + // 使用关联查询 + return success(shopExpressTemplateService.listRel(param)); + } + + @Operation(summary = "根据id查询运费模板") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopExpressTemplateService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplate:save')") + @OperationLog + @Operation(summary = "添加运费模板") + @PostMapping() + public ApiResult save(@RequestBody ShopExpressTemplate shopExpressTemplate) { + if (shopExpressTemplateService.save(shopExpressTemplate)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplate:update')") + @OperationLog + @Operation(summary = "修改运费模板") + @PutMapping() + public ApiResult update(@RequestBody ShopExpressTemplate shopExpressTemplate) { + if (shopExpressTemplateService.updateById(shopExpressTemplate)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplate:remove')") + @OperationLog + @Operation(summary = "删除运费模板") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopExpressTemplateService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplate:save')") + @OperationLog + @Operation(summary = "批量添加运费模板") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopExpressTemplateService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplate:update')") + @OperationLog + @Operation(summary = "批量修改运费模板") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopExpressTemplateService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplate:remove')") + @OperationLog + @Operation(summary = "批量删除运费模板") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopExpressTemplateService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressTemplateDetailController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressTemplateDetailController.java new file mode 100644 index 0000000..6c1553d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopExpressTemplateDetailController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopExpressTemplateDetailService; +import com.gxwebsoft.shop.entity.ShopExpressTemplateDetail; +import com.gxwebsoft.shop.param.ShopExpressTemplateDetailParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 运费模板控制器 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Tag(name = "运费模板管理") +@RestController +@RequestMapping("/api/shop/shop-express-template-detail") +public class ShopExpressTemplateDetailController extends BaseController { + @Resource + private ShopExpressTemplateDetailService shopExpressTemplateDetailService; + + @Operation(summary = "分页查询运费模板") + @GetMapping("/page") + public ApiResult> page(ShopExpressTemplateDetailParam param) { + // 使用关联查询 + return success(shopExpressTemplateDetailService.pageRel(param)); + } + + @Operation(summary = "查询全部运费模板") + @GetMapping() + public ApiResult> list(ShopExpressTemplateDetailParam param) { + // 使用关联查询 + return success(shopExpressTemplateDetailService.listRel(param)); + } + + @Operation(summary = "根据id查询运费模板") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopExpressTemplateDetailService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplateDetail:save')") + @OperationLog + @Operation(summary = "添加运费模板") + @PostMapping() + public ApiResult save(@RequestBody ShopExpressTemplateDetail shopExpressTemplateDetail) { + if (shopExpressTemplateDetailService.save(shopExpressTemplateDetail)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplateDetail:update')") + @OperationLog + @Operation(summary = "修改运费模板") + @PutMapping() + public ApiResult update(@RequestBody ShopExpressTemplateDetail shopExpressTemplateDetail) { + if (shopExpressTemplateDetailService.updateById(shopExpressTemplateDetail)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplateDetail:remove')") + @OperationLog + @Operation(summary = "删除运费模板") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopExpressTemplateDetailService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplateDetail:save')") + @OperationLog + @Operation(summary = "批量添加运费模板") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopExpressTemplateDetailService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplateDetail:update')") + @OperationLog + @Operation(summary = "批量修改运费模板") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopExpressTemplateDetailService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopExpressTemplateDetail:remove')") + @OperationLog + @Operation(summary = "批量删除运费模板") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopExpressTemplateDetailService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGiftController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGiftController.java new file mode 100644 index 0000000..66f5023 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGiftController.java @@ -0,0 +1,261 @@ +package com.gxwebsoft.shop.controller; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.FileRecord; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.service.ShopGiftService; +import com.gxwebsoft.shop.entity.ShopGift; +import com.gxwebsoft.shop.param.ShopGiftParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.service.ShopGoodsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.poi.xssf.streaming.SXSSFRow; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.FileOutputStream; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 礼品卡控制器 + * + * @author 科技小王子 + * @since 2025-08-11 18:07:32 + */ +@Tag(name = "礼品卡管理") +@RestController +@RequestMapping("/api/shop/shop-gift") +public class ShopGiftController extends BaseController { + @Resource + private ShopGiftService shopGiftService; + @Value("${config.upload-path}") + private String uploadPath; + @Value("${config.api-url}") + private String apiUrl; + @Resource + private ShopGoodsService shopGoodsService; + + @Operation(summary = "根据code查询礼品卡") + @GetMapping("/by-code/{code}") + public ApiResult get(@PathVariable("code") String code) { + // 使用关联查询 + return success(shopGiftService.getByCode(code)); + } + + @Operation(summary = "礼品卡核销") + @PostMapping("/set-take") + public ApiResult setTake(@RequestBody ShopGift shopGift) { + if (getLoginUser() == null) return fail("请登录"); + if (shopGift.getCode() == null) { + return fail("非法请求"); + } + ShopGift shopGift1 = shopGiftService.getByCode(shopGift.getCode()); + if (shopGift1 == null) return fail("礼品卡不存在"); + if (shopGift1.getTakeTime() != null) { + return fail("礼品卡已使用"); + } + shopGift1.setTakeTime(LocalDateTime.now()); + shopGift1.setOperatorUserId(getLoginUserId()); + shopGiftService.updateById(shopGift1); + return success(); + } + + @PreAuthorize("hasAuthority('shop:shopGift:list')") + @Operation(summary = "分页查询礼品卡") + @GetMapping("/page") + public ApiResult> page(ShopGiftParam param) { + // 使用关联查询 + return success(shopGiftService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopGift:list')") + @Operation(summary = "查询全部礼品卡") + @GetMapping() + public ApiResult> list(ShopGiftParam param) { + // 使用关联查询 + return success(shopGiftService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopGift:list')") + @Operation(summary = "根据id查询礼品卡") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGiftService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopGift:save')") + @OperationLog + @Operation(summary = "添加礼品卡") + @PostMapping() + public ApiResult save(@RequestBody ShopGift shopGift) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopGift.setUserId(loginUser.getUserId()); + } + if (shopGiftService.save(shopGift)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGift:update')") + @OperationLog + @Operation(summary = "修改礼品卡") + @PutMapping() + public ApiResult update(@RequestBody ShopGift shopGift) { + if (shopGiftService.updateById(shopGift)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGift:save')") + @OperationLog + @Operation(summary = "批量生成礼品卡") + @PostMapping("/make") + public ApiResult make(@RequestBody ShopGift shopGiftData) { + if (shopGiftData.getNum() == null || shopGiftData.getNum() <= 0) { + return fail("请输入正确的数量"); + } + if (shopGiftData.getGoodsId() == null || shopGiftData.getGoodsId() <= 0) { + return fail("请选择商品"); + } + List giftList = new ArrayList<>(); + for (int i = 0; i < shopGiftData.getNum(); i++) { + ShopGift shopGift = new ShopGift(); + shopGift.setName(shopGiftData.getName()); + shopGift.setCode(RandomUtil.randomString(8)); + shopGift.setGoodsId(shopGiftData.getGoodsId()); + shopGift.setUseLocation(shopGiftData.getUseLocation()); + shopGift.setComments(shopGiftData.getComments()); + giftList.add(shopGift); + } + if (shopGiftService.saveBatch(giftList)) { + return success("生成成功"); + } + return fail("生成失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGift:remove')") + @OperationLog + @Operation(summary = "删除礼品卡") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGiftService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGift:save')") + @OperationLog + @Operation(summary = "批量添加礼品卡") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGiftService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGift:update')") + @OperationLog + @Operation(summary = "批量修改礼品卡") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGiftService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGift:remove')") + @OperationLog + @Operation(summary = "批量删除礼品卡") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGiftService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGift:list')") + @Operation(summary = "导出礼品卡") + @PostMapping("/export") + public ApiResult export(@RequestBody(required = false) List ids) throws IOException { + String filename = "excel/礼品卡.xlsx"; + if (!FileUtil.exist(uploadPath + "excel")) { + FileUtil.mkdir(uploadPath + "excel"); + } + List list; + if (ids != null && !ids.isEmpty()) { + list = shopGiftService.listByIds(ids); + } else { + list = shopGiftService.list(); + } + if (!list.isEmpty()) { + Set goodsIds = list.stream().map(ShopGift::getGoodsId).collect(Collectors.toSet()); + List goodsList = shopGoodsService.listByIds(goodsIds); + for (ShopGift shopGift : list) { + ShopGoods shopGoods = goodsList.stream().filter(sG -> sG.getGoodsId().equals(shopGift.getGoodsId())).findFirst().orElse(null); + if (shopGoods != null) { + shopGift.setGoods(shopGoods); + } + } + } + String path = uploadPath + filename; + SXSSFWorkbook workbook = new SXSSFWorkbook(); + //创建工作表单 + SXSSFSheet sheet = workbook.createSheet(); + String[] headers = {"名称", "秘钥", "领取时间", "商品"}; + + SXSSFRow row0 = sheet.createRow(0); + for (int i = 0; i < headers.length; i++) { + row0.createCell(i).setCellValue(headers[i]); + } + if (!list.isEmpty()) { + for (ShopGift shopGift : list) { + SXSSFRow row = sheet.createRow(sheet.getLastRowNum() + 1); + row.createCell(0).setCellValue(shopGift.getName()); + row.createCell(1).setCellValue(shopGift.getCode()); + row.createCell(2).setCellValue(shopGift.getTakeTime()); + row.createCell(3).setCellValue(shopGift.getGoods() != null ? shopGift.getGoods().getName() : ""); + } + } + FileOutputStream output = new FileOutputStream(path); + workbook.write(output); + output.flush(); + + FileRecord result = new FileRecord(); + result.setCreateUserId(getLoginUserId()); + result.setName("礼品卡"); + result.setPath(filename); + result.setUrl(apiUrl + "/" + filename); + return success(result); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsCategoryController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsCategoryController.java new file mode 100644 index 0000000..49077a7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsCategoryController.java @@ -0,0 +1,128 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsCategoryService; +import com.gxwebsoft.shop.entity.ShopGoodsCategory; +import com.gxwebsoft.shop.param.ShopGoodsCategoryParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品分类控制器 + * + * @author 科技小王子 + * @since 2025-05-01 00:36:45 + */ +@Tag(name = "商品分类管理") +@RestController +@RequestMapping("/api/shop/shop-goods-category") +public class ShopGoodsCategoryController extends BaseController { + @Resource + private ShopGoodsCategoryService shopGoodsCategoryService; + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:list')") + @Operation(summary = "分页查询商品分类") + @GetMapping("/page") + public ApiResult> page(ShopGoodsCategoryParam param) { + // 使用关联查询 + return success(shopGoodsCategoryService.pageRel(param)); + } + + @Operation(summary = "查询全部商品分类") + @GetMapping() + public ApiResult> list(ShopGoodsCategoryParam param) { + // 使用关联查询 + return success(shopGoodsCategoryService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:list')") + @Operation(summary = "根据id查询商品分类") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsCategoryService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:save')") + @OperationLog + @Operation(summary = "添加商品分类") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsCategory shopGoodsCategory) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopGoodsCategory.setUserId(loginUser.getUserId()); + } + if (shopGoodsCategoryService.save(shopGoodsCategory)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:update')") + @OperationLog + @Operation(summary = "修改商品分类") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsCategory shopGoodsCategory) { + if (shopGoodsCategoryService.updateById(shopGoodsCategory)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:remove')") + @OperationLog + @Operation(summary = "删除商品分类") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsCategoryService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:save')") + @OperationLog + @Operation(summary = "批量添加商品分类") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsCategoryService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:update')") + @OperationLog + @Operation(summary = "批量修改商品分类") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsCategoryService, "category_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsCategory:remove')") + @OperationLog + @Operation(summary = "批量删除商品分类") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsCategoryService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsCommentController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsCommentController.java new file mode 100644 index 0000000..7f370af --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsCommentController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsCommentService; +import com.gxwebsoft.shop.entity.ShopGoodsComment; +import com.gxwebsoft.shop.param.ShopGoodsCommentParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 评论表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "评论表管理") +@RestController +@RequestMapping("/api/shop/shop-goods-comment") +public class ShopGoodsCommentController extends BaseController { + @Resource + private ShopGoodsCommentService shopGoodsCommentService; + + @Operation(summary = "分页查询评论表") + @GetMapping("/page") + public ApiResult> page(ShopGoodsCommentParam param) { + // 使用关联查询 + return success(shopGoodsCommentService.pageRel(param)); + } + + @Operation(summary = "查询全部评论表") + @GetMapping() + public ApiResult> list(ShopGoodsCommentParam param) { + // 使用关联查询 + return success(shopGoodsCommentService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsComment:list')") + @Operation(summary = "根据id查询评论表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsCommentService.getByIdRel(id)); + } + + @Operation(summary = "添加评论表") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsComment shopGoodsComment) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopGoodsComment.setUserId(loginUser.getUserId()); + } + if (shopGoodsCommentService.save(shopGoodsComment)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改评论表") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsComment shopGoodsComment) { + if (shopGoodsCommentService.updateById(shopGoodsComment)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除评论表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsCommentService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加评论表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsCommentService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改评论表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsCommentService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除评论表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsCommentService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsController.java new file mode 100644 index 0000000..4074e63 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsController.java @@ -0,0 +1,163 @@ +package com.gxwebsoft.shop.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsService; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.param.ShopGoodsParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 商品控制器 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Tag(name = "商品管理") +@RestController +@RequestMapping("/api/shop/shop-goods") +public class ShopGoodsController extends BaseController { + @Resource + private ShopGoodsService shopGoodsService; + + @Operation(summary = "分页查询商品") + @GetMapping("/page") + public ApiResult> page(ShopGoodsParam param) { + // 使用关联查询 + return success(shopGoodsService.pageRel(param)); + } + + @Operation(summary = "查询全部商品") + @GetMapping() + public ApiResult> list(ShopGoodsParam param) { + // 使用关联查询 + return success(shopGoodsService.listRel(param)); + } + + @Operation(summary = "根据id查询商品") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopGoods:save')") + @OperationLog + @Operation(summary = "添加商品") + @PostMapping() + public ApiResult save(@RequestBody ShopGoods shopGoods) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopGoods.setUserId(loginUser.getUserId()); + } + if (shopGoodsService.save(shopGoods)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoods:update')") + @OperationLog + @Operation(summary = "修改商品") + @PutMapping() + public ApiResult update(@RequestBody ShopGoods shopGoods) { + if (shopGoodsService.updateById(shopGoods)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoods:remove')") + @OperationLog + @Operation(summary = "删除商品") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoods:save')") + @OperationLog + @Operation(summary = "批量添加商品") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoods:update')") + @OperationLog + @Operation(summary = "批量修改商品") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsService, "goods_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoods:remove')") + @OperationLog + @Operation(summary = "批量删除商品") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "统计信息") + @GetMapping("/data") + public ApiResult> data(ShopGoodsParam param) { + Map data = new HashMap<>(); + final LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + if (param.getMerchantId() != null) { + wrapper.eq(ShopGoods::getMerchantId,param.getMerchantId()); + } + + long totalNum = shopGoodsService.count( + wrapper.eq(ShopGoods::getStatus,0).gt(ShopGoods::getStock,0) + ); + data.put("totalNum", Math.toIntExact(totalNum)); + wrapper.clear(); + + long totalNum2 = shopGoodsService.count( + wrapper.gt(ShopGoods::getStatus,0) + ); + data.put("totalNum2", Math.toIntExact(totalNum2)); + wrapper.clear(); + + long totalNum3 = shopGoodsService.count( + wrapper.eq(ShopGoods::getStock,0) + ); + data.put("totalNum3", Math.toIntExact(totalNum3)); + wrapper.clear(); + + // 下架已售罄的商品 + shopGoodsService.update(new LambdaUpdateWrapper().eq(ShopGoods::getStock,0).set(ShopGoods::getStatus,1)); + + return success(data); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsIncomeConfigController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsIncomeConfigController.java new file mode 100644 index 0000000..1e91159 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsIncomeConfigController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsIncomeConfigService; +import com.gxwebsoft.shop.entity.ShopGoodsIncomeConfig; +import com.gxwebsoft.shop.param.ShopGoodsIncomeConfigParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 分润配置控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "分润配置管理") +@RestController +@RequestMapping("/api/shop/shop-goods-income-config") +public class ShopGoodsIncomeConfigController extends BaseController { + @Resource + private ShopGoodsIncomeConfigService shopGoodsIncomeConfigService; + + @Operation(summary = "分页查询分润配置") + @GetMapping("/page") + public ApiResult> page(ShopGoodsIncomeConfigParam param) { + // 使用关联查询 + return success(shopGoodsIncomeConfigService.pageRel(param)); + } + + @Operation(summary = "查询全部分润配置") + @GetMapping() + public ApiResult> list(ShopGoodsIncomeConfigParam param) { + // 使用关联查询 + return success(shopGoodsIncomeConfigService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsIncomeConfig:list')") + @Operation(summary = "根据id查询分润配置") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsIncomeConfigService.getByIdRel(id)); + } + + @Operation(summary = "添加分润配置") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsIncomeConfig shopGoodsIncomeConfig) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopGoodsIncomeConfig.setUserId(loginUser.getUserId()); + } + if (shopGoodsIncomeConfigService.save(shopGoodsIncomeConfig)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改分润配置") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsIncomeConfig shopGoodsIncomeConfig) { + if (shopGoodsIncomeConfigService.updateById(shopGoodsIncomeConfig)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除分润配置") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsIncomeConfigService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加分润配置") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsIncomeConfigService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改分润配置") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsIncomeConfigService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除分润配置") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsIncomeConfigService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsLogController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsLogController.java new file mode 100644 index 0000000..2a46786 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsLogController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsLogService; +import com.gxwebsoft.shop.entity.ShopGoodsLog; +import com.gxwebsoft.shop.param.ShopGoodsLogParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品日志表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "商品日志表管理") +@RestController +@RequestMapping("/api/shop/shop-goods-log") +public class ShopGoodsLogController extends BaseController { + @Resource + private ShopGoodsLogService shopGoodsLogService; + + @Operation(summary = "分页查询商品日志表") + @GetMapping("/page") + public ApiResult> page(ShopGoodsLogParam param) { + // 使用关联查询 + return success(shopGoodsLogService.pageRel(param)); + } + + @Operation(summary = "查询全部商品日志表") + @GetMapping() + public ApiResult> list(ShopGoodsLogParam param) { + // 使用关联查询 + return success(shopGoodsLogService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsLog:list')") + @Operation(summary = "根据id查询商品日志表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsLogService.getByIdRel(id)); + } + + @Operation(summary = "添加商品日志表") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsLog shopGoodsLog) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopGoodsLog.setUserId(loginUser.getUserId()); + } + if (shopGoodsLogService.save(shopGoodsLog)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改商品日志表") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsLog shopGoodsLog) { + if (shopGoodsLogService.updateById(shopGoodsLog)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除商品日志表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsLogService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加商品日志表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsLogService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改商品日志表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsLogService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除商品日志表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsLogService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsRelationController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsRelationController.java new file mode 100644 index 0000000..5e0d57c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsRelationController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsRelationService; +import com.gxwebsoft.shop.entity.ShopGoodsRelation; +import com.gxwebsoft.shop.param.ShopGoodsRelationParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品点赞和收藏表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "商品点赞和收藏表管理") +@RestController +@RequestMapping("/api/shop/shop-goods-relation") +public class ShopGoodsRelationController extends BaseController { + @Resource + private ShopGoodsRelationService shopGoodsRelationService; + + @Operation(summary = "分页查询商品点赞和收藏表") + @GetMapping("/page") + public ApiResult> page(ShopGoodsRelationParam param) { + // 使用关联查询 + return success(shopGoodsRelationService.pageRel(param)); + } + + @Operation(summary = "查询全部商品点赞和收藏表") + @GetMapping() + public ApiResult> list(ShopGoodsRelationParam param) { + // 使用关联查询 + return success(shopGoodsRelationService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsRelation:list')") + @Operation(summary = "根据id查询商品点赞和收藏表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsRelationService.getByIdRel(id)); + } + + @Operation(summary = "添加商品点赞和收藏表") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsRelation shopGoodsRelation) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopGoodsRelation.setUserId(loginUser.getUserId()); + } + if (shopGoodsRelationService.save(shopGoodsRelation)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改商品点赞和收藏表") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsRelation shopGoodsRelation) { + if (shopGoodsRelationService.updateById(shopGoodsRelation)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除商品点赞和收藏表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsRelationService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加商品点赞和收藏表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsRelationService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改商品点赞和收藏表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsRelationService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除商品点赞和收藏表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsRelationService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsRoleCommissionController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsRoleCommissionController.java new file mode 100644 index 0000000..21508e2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsRoleCommissionController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsRoleCommissionService; +import com.gxwebsoft.shop.entity.ShopGoodsRoleCommission; +import com.gxwebsoft.shop.param.ShopGoodsRoleCommissionParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品绑定角色的分润金额控制器 + * + * @author 科技小王子 + * @since 2025-05-01 09:53:38 + */ +@Tag(name = "商品绑定角色的分润金额管理") +@RestController +@RequestMapping("/api/shop/shop-goods-role-commission") +public class ShopGoodsRoleCommissionController extends BaseController { + @Resource + private ShopGoodsRoleCommissionService shopGoodsRoleCommissionService; + + @Operation(summary = "分页查询商品绑定角色的分润金额") + @GetMapping("/page") + public ApiResult> page(ShopGoodsRoleCommissionParam param) { + // 使用关联查询 + return success(shopGoodsRoleCommissionService.pageRel(param)); + } + + @Operation(summary = "查询全部商品绑定角色的分润金额") + @GetMapping() + public ApiResult> list(ShopGoodsRoleCommissionParam param) { + // 使用关联查询 + return success(shopGoodsRoleCommissionService.listRel(param)); + } + + @Operation(summary = "根据id查询商品绑定角色的分润金额") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsRoleCommissionService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsRoleCommission:save')") + @OperationLog + @Operation(summary = "添加商品绑定角色的分润金额") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsRoleCommission shopGoodsRoleCommission) { + if (shopGoodsRoleCommissionService.save(shopGoodsRoleCommission)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsRoleCommission:update')") + @OperationLog + @Operation(summary = "修改商品绑定角色的分润金额") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsRoleCommission shopGoodsRoleCommission) { + if (shopGoodsRoleCommissionService.updateById(shopGoodsRoleCommission)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsRoleCommission:remove')") + @OperationLog + @Operation(summary = "删除商品绑定角色的分润金额") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsRoleCommissionService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsRoleCommission:save')") + @OperationLog + @Operation(summary = "批量添加商品绑定角色的分润金额") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsRoleCommissionService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsRoleCommission:update')") + @OperationLog + @Operation(summary = "批量修改商品绑定角色的分润金额") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsRoleCommissionService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsRoleCommission:remove')") + @OperationLog + @Operation(summary = "批量删除商品绑定角色的分润金额") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsRoleCommissionService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsSkuController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsSkuController.java new file mode 100644 index 0000000..2884bdc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsSkuController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsSkuService; +import com.gxwebsoft.shop.entity.ShopGoodsSku; +import com.gxwebsoft.shop.param.ShopGoodsSkuParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品sku列表控制器 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Tag(name = "商品sku列表管理") +@RestController +@RequestMapping("/api/shop/shop-goods-sku") +public class ShopGoodsSkuController extends BaseController { + @Resource + private ShopGoodsSkuService shopGoodsSkuService; + + @Operation(summary = "分页查询商品sku列表") + @GetMapping("/page") + public ApiResult> page(ShopGoodsSkuParam param) { + // 使用关联查询 + return success(shopGoodsSkuService.pageRel(param)); + } + + @Operation(summary = "查询全部商品sku列表") + @GetMapping() + public ApiResult> list(ShopGoodsSkuParam param) { + // 使用关联查询 + return success(shopGoodsSkuService.listRel(param)); + } + + @Operation(summary = "根据id查询商品sku列表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsSkuService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSku:save')") + @OperationLog + @Operation(summary = "添加商品sku列表") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsSku shopGoodsSku) { + if (shopGoodsSkuService.save(shopGoodsSku)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSku:update')") + @OperationLog + @Operation(summary = "修改商品sku列表") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsSku shopGoodsSku) { + if (shopGoodsSkuService.updateById(shopGoodsSku)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSku:remove')") + @OperationLog + @Operation(summary = "删除商品sku列表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsSkuService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSku:save')") + @OperationLog + @Operation(summary = "批量添加商品sku列表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsSkuService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSku:update')") + @OperationLog + @Operation(summary = "批量修改商品sku列表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsSkuService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSku:remove')") + @OperationLog + @Operation(summary = "批量删除商品sku列表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsSkuService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsSpecController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsSpecController.java new file mode 100644 index 0000000..398430e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopGoodsSpecController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopGoodsSpecService; +import com.gxwebsoft.shop.entity.ShopGoodsSpec; +import com.gxwebsoft.shop.param.ShopGoodsSpecParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品多规格控制器 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Tag(name = "商品多规格管理") +@RestController +@RequestMapping("/api/shop/shop-goods-spec") +public class ShopGoodsSpecController extends BaseController { + @Resource + private ShopGoodsSpecService shopGoodsSpecService; + + @Operation(summary = "分页查询商品多规格") + @GetMapping("/page") + public ApiResult> page(ShopGoodsSpecParam param) { + // 使用关联查询 + return success(shopGoodsSpecService.pageRel(param)); + } + + @Operation(summary = "查询全部商品多规格") + @GetMapping() + public ApiResult> list(ShopGoodsSpecParam param) { + // 使用关联查询 + return success(shopGoodsSpecService.listRel(param)); + } + + @Operation(summary = "根据id查询商品多规格") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopGoodsSpecService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSpec:save')") + @OperationLog + @Operation(summary = "添加商品多规格") + @PostMapping() + public ApiResult save(@RequestBody ShopGoodsSpec shopGoodsSpec) { + if (shopGoodsSpecService.save(shopGoodsSpec)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSpec:update')") + @OperationLog + @Operation(summary = "修改商品多规格") + @PutMapping() + public ApiResult update(@RequestBody ShopGoodsSpec shopGoodsSpec) { + if (shopGoodsSpecService.updateById(shopGoodsSpec)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSpec:remove')") + @OperationLog + @Operation(summary = "删除商品多规格") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopGoodsSpecService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSpec:save')") + @OperationLog + @Operation(summary = "批量添加商品多规格") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopGoodsSpecService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSpec:update')") + @OperationLog + @Operation(summary = "批量修改商品多规格") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopGoodsSpecService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopGoodsSpec:remove')") + @OperationLog + @Operation(summary = "批量删除商品多规格") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopGoodsSpecService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMainController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMainController.java new file mode 100644 index 0000000..5b96b22 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMainController.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.shop.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.gxwebsoft.cms.entity.CmsWebsite; +import com.gxwebsoft.cms.service.CmsWebsiteService; +import com.gxwebsoft.shop.service.ShopWebsiteService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.vo.ShopVo; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +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.RestController; + +import javax.annotation.Resource; + +/** + * 商城主入口 + * + * @author 科技小王子 + * @since 2024-09-10 20:36:14 + */ +@Slf4j +@Tag(name = "商城") +@RestController +@RequestMapping("/api/shop") +public class ShopMainController extends BaseController { + @Resource + private ShopWebsiteService shopWebsiteService; + + @Operation(summary = "商城基本信息", description = "获取商城的基本信息,包括配置、导航、设置和过期状态等") + @GetMapping("/getShopInfo") + public ApiResult getShopInfo() { + Integer tenantId = getTenantId(); + + if (ObjectUtil.isEmpty(tenantId)) { + return fail("租户ID不能为空", null); + } + + try { + // 使用专门的商城信息获取方法 + ShopVo shopVo = shopWebsiteService.getShopInfo(tenantId); +// log.debug("获取商城信息成功: {}", shopVo); + return success(shopVo); + } catch (IllegalArgumentException e) { + return fail(e.getMessage(), null); + } catch (RuntimeException e) { + return fail(e.getMessage(), null); + } catch (Exception e) { + log.error("获取商城信息失败", e); + return fail("获取商城信息失败", null); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantAccountController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantAccountController.java new file mode 100644 index 0000000..3e5ca19 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantAccountController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopMerchantAccountService; +import com.gxwebsoft.shop.entity.ShopMerchantAccount; +import com.gxwebsoft.shop.param.ShopMerchantAccountParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商户账号控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "商户账号管理") +@RestController +@RequestMapping("/api/shop/shop-merchant-account") +public class ShopMerchantAccountController extends BaseController { + @Resource + private ShopMerchantAccountService shopMerchantAccountService; + + @Operation(summary = "分页查询商户账号") + @GetMapping("/page") + public ApiResult> page(ShopMerchantAccountParam param) { + // 使用关联查询 + return success(shopMerchantAccountService.pageRel(param)); + } + + @Operation(summary = "查询全部商户账号") + @GetMapping() + public ApiResult> list(ShopMerchantAccountParam param) { + // 使用关联查询 + return success(shopMerchantAccountService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopMerchantAccount:list')") + @Operation(summary = "根据id查询商户账号") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopMerchantAccountService.getByIdRel(id)); + } + + @Operation(summary = "添加商户账号") + @PostMapping() + public ApiResult save(@RequestBody ShopMerchantAccount shopMerchantAccount) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopMerchantAccount.setUserId(loginUser.getUserId()); + } + if (shopMerchantAccountService.save(shopMerchantAccount)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改商户账号") + @PutMapping() + public ApiResult update(@RequestBody ShopMerchantAccount shopMerchantAccount) { + if (shopMerchantAccountService.updateById(shopMerchantAccount)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除商户账号") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopMerchantAccountService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加商户账号") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopMerchantAccountService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改商户账号") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopMerchantAccountService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除商户账号") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopMerchantAccountService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantApplyController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantApplyController.java new file mode 100644 index 0000000..3b5d1cc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantApplyController.java @@ -0,0 +1,192 @@ +package com.gxwebsoft.shop.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopMerchant; +import com.gxwebsoft.shop.entity.ShopMerchantAccount; +import com.gxwebsoft.shop.service.ShopMerchantApplyService; +import com.gxwebsoft.shop.entity.ShopMerchantApply; +import com.gxwebsoft.shop.param.ShopMerchantApplyParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.service.ShopMerchantService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.beans.BeanUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商户入驻申请控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "商户入驻申请管理") +@RestController +@RequestMapping("/api/shop/shop-merchant-apply") +public class ShopMerchantApplyController extends BaseController { + @Resource + private ShopMerchantApplyService shopMerchantApplyService; + @Resource + private ShopMerchantService shopMerchantService; + + @Operation(summary = "分页查询商户入驻申请") + @GetMapping("/page") + public ApiResult> page(ShopMerchantApplyParam param) { + // 使用关联查询 + return success(shopMerchantApplyService.pageRel(param)); + } + + @Operation(summary = "查询全部商户入驻申请") + @GetMapping() + public ApiResult> list(ShopMerchantApplyParam param) { + // 使用关联查询 + return success(shopMerchantApplyService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopMerchantApply:list')") + @Operation(summary = "根据id查询商户入驻申请") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopMerchantApplyService.getByIdRel(id)); + } + + @Operation(summary = "添加商户入驻申请") + @PostMapping() + public ApiResult save(@RequestBody ShopMerchantApply shopMerchantApply) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopMerchantApply.setUserId(loginUser.getUserId()); + if(shopMerchantApplyService.count(new LambdaQueryWrapper().eq(ShopMerchantApply::getPhone,shopMerchantApply.getPhone())) > 0){ + return fail("该手机号码已存在"); + } + // 个人开发者认证材料:使用姓名+身份证号码 + if (shopMerchantApply.getType().equals(0)) { + shopMerchantApply.setMerchantName(shopMerchantApply.getRealName()); + shopMerchantApply.setMerchantCode(shopMerchantApply.getIdCard()); + } + shopMerchantApply.setCheckStatus(true); + shopMerchantApply.setTenantId(loginUser.getTenantId()); + if (shopMerchantApplyService.save(shopMerchantApply)) { + return success("您的申请已提交,请耐心等待工作人员的审核,非常感谢"); + } + } + return fail("提交失败"); + } + + @Operation(summary = "修改商户入驻申请") + @PutMapping() + public ApiResult update(@RequestBody ShopMerchantApply shopMerchantApply) { + if (shopMerchantApplyService.updateById(shopMerchantApply)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除商户入驻申请") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopMerchantApplyService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加商户入驻申请") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopMerchantApplyService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改商户入驻申请") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopMerchantApplyService, "apply_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除商户入驻申请") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopMerchantApplyService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "我的入驻信息") + @GetMapping("/getByUserId") + public ApiResult getByUserId() { + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录", null); + } + final ShopMerchantApply shopMerchantApply = shopMerchantApplyService.getOne(new LambdaQueryWrapper().eq(ShopMerchantApply::getUserId, getLoginUser().getUserId()).last("limit 1")); + return success(shopMerchantApply); + } + + @PreAuthorize("hasAuthority('shop:shopMerchantApply:update')") + @Operation(summary = "入驻审核") + @PutMapping("/check") + public ApiResult check(@RequestBody ShopMerchantApply shopMerchantApply) { + // 审核中? + shopMerchantApply.setCheckStatus(true); + // TODO 审核通过则创建商户 + if (shopMerchantApply.getStatus().equals(1)) { + final ShopMerchant one = shopMerchantService.getOne(new LambdaQueryWrapper().eq(ShopMerchant::getPhone, shopMerchantApply.getPhone()).last("limit 1")); + final ShopMerchantAccount merchantAccount = new ShopMerchantAccount(); + BeanUtils.copyProperties(shopMerchantApply, merchantAccount); + + final User user = new User(); + + if (ObjectUtil.isNotEmpty(one)) { + BeanUtils.copyProperties(shopMerchantApply, one); + one.setStatus(0); + shopMerchantService.updateById(one); + user.setRealName(shopMerchantApply.getRealName()); + } else { + final ShopMerchant merchant = new ShopMerchant(); + BeanUtils.copyProperties(shopMerchantApply, merchant); + merchant.setStatus(0); + shopMerchantService.save(merchant); + user.setRealName(shopMerchantApply.getRealName()); + } + + // TODO 创建商户账号 + // TODO 更新用户表的商户信息 + user.setUserId(shopMerchantApply.getUserId()); + shopMerchantApplyService.updateById(shopMerchantApply); + // TODO 入驻开发者中心(添加会员) + return success("操作成功"); + } + // TODO 驳回 + if (shopMerchantApply.getStatus().equals(2)) { + shopMerchantApply.setCheckStatus(false); + shopMerchantApplyService.updateById(shopMerchantApply); + return success("操作成功"); + } + // 审核状态 + shopMerchantApply.setStatus(0); + if (shopMerchantApplyService.updateById(shopMerchantApply)) { + return success("您的申请已提交,请耐心等待工作人员的审核,非常感谢"); + } + return fail("操作失败"); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantController.java new file mode 100644 index 0000000..b95105b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantController.java @@ -0,0 +1,123 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopMerchantService; +import com.gxwebsoft.shop.entity.ShopMerchant; +import com.gxwebsoft.shop.param.ShopMerchantParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商户控制器 + * + * @author 科技小王子 + * @since 2025-08-10 20:43:33 + */ +@Tag(name = "商户管理") +@RestController +@RequestMapping("/api/shop/shop-merchant") +public class ShopMerchantController extends BaseController { + @Resource + private ShopMerchantService shopMerchantService; + + @Operation(summary = "分页查询商户") + @GetMapping("/page") + public ApiResult> page(ShopMerchantParam param) { + // 使用关联查询 + return success(shopMerchantService.pageRel(param)); + } + + @Operation(summary = "查询全部商户") + @GetMapping() + public ApiResult> list(ShopMerchantParam param) { + // 使用关联查询 + return success(shopMerchantService.listRel(param)); + } + + @Operation(summary = "根据id查询商户") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Long id) { + // 使用关联查询 + return success(shopMerchantService.getByIdRel(id)); + } + + @Operation(summary = "添加商户") + @PostMapping() + public ApiResult save(@RequestBody ShopMerchant shopMerchant) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopMerchant.setUserId(loginUser.getUserId()); + } + if (shopMerchantService.save(shopMerchant)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopMerchant:update')") + @OperationLog + @Operation(summary = "修改商户") + @PutMapping() + public ApiResult update(@RequestBody ShopMerchant shopMerchant) { + if (shopMerchantService.updateById(shopMerchant)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopMerchant:remove')") + @OperationLog + @Operation(summary = "删除商户") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopMerchantService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopMerchant:save')") + @OperationLog + @Operation(summary = "批量添加商户") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopMerchantService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopMerchant:update')") + @OperationLog + @Operation(summary = "批量修改商户") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopMerchantService, "merchant_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopMerchant:remove')") + @OperationLog + @Operation(summary = "批量删除商户") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopMerchantService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantTypeController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantTypeController.java new file mode 100644 index 0000000..4bdac19 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopMerchantTypeController.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopMerchantTypeService; +import com.gxwebsoft.shop.entity.ShopMerchantType; +import com.gxwebsoft.shop.param.ShopMerchantTypeParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商户类型控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "商户类型管理") +@RestController +@RequestMapping("/api/shop/shop-merchant-type") +public class ShopMerchantTypeController extends BaseController { + @Resource + private ShopMerchantTypeService shopMerchantTypeService; + + @Operation(summary = "分页查询商户类型") + @GetMapping("/page") + public ApiResult> page(ShopMerchantTypeParam param) { + // 使用关联查询 + return success(shopMerchantTypeService.pageRel(param)); + } + + @Operation(summary = "查询全部商户类型") + @GetMapping() + public ApiResult> list(ShopMerchantTypeParam param) { + // 使用关联查询 + return success(shopMerchantTypeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopMerchantType:list')") + @Operation(summary = "根据id查询商户类型") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopMerchantTypeService.getByIdRel(id)); + } + + @Operation(summary = "添加商户类型") + @PostMapping() + public ApiResult save(@RequestBody ShopMerchantType shopMerchantType) { + if (shopMerchantTypeService.save(shopMerchantType)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改商户类型") + @PutMapping() + public ApiResult update(@RequestBody ShopMerchantType shopMerchantType) { + if (shopMerchantTypeService.updateById(shopMerchantType)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除商户类型") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopMerchantTypeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加商户类型") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopMerchantTypeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改商户类型") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopMerchantTypeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除商户类型") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopMerchantTypeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java new file mode 100644 index 0000000..dd2fe13 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java @@ -0,0 +1,696 @@ +package com.gxwebsoft.shop.controller; + +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.common.core.utils.CertificateLoader; +import com.gxwebsoft.common.core.utils.WechatCertAutoConfig; +import com.gxwebsoft.common.core.utils.WechatPayConfigValidator; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.shop.entity.ShopExpress; +import com.gxwebsoft.shop.entity.ShopOrderDelivery; +import com.gxwebsoft.shop.entity.ShopUserAddress; +import com.gxwebsoft.shop.service.*; +import com.gxwebsoft.shop.service.impl.KuaiDi100Impl; +import com.gxwebsoft.shop.task.OrderAutoCancelTask; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.param.ShopOrderParam; +import com.gxwebsoft.shop.dto.OrderCreateRequest; +import com.gxwebsoft.shop.dto.UpdatePaymentStatusRequest; +import com.gxwebsoft.payment.service.PaymentService; +import com.gxwebsoft.payment.dto.PaymentResponse; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.system.entity.User; +import com.kuaidi100.sdk.request.BOrderReq; +import com.wechat.pay.java.core.notification.NotificationConfig; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.core.notification.RequestParam; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.Operation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 订单控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "订单管理") +@RestController +@RequestMapping("/api/shop/shop-order") +public class ShopOrderController extends BaseController { + private static final Logger logger = LoggerFactory.getLogger(ShopOrderController.class); + @Resource + private ShopOrderService shopOrderService; + @Resource + private ShopOrderGoodsService shopOrderGoodsService; + @Resource + private OrderBusinessService orderBusinessService; + @Resource + private OrderCancelService orderCancelService; + @Resource + private OrderAutoCancelTask orderAutoCancelTask; + @Resource + private RedisUtil redisUtil; + @Resource + private ConfigProperties conf; + @Resource + private CertificateProperties certConfig; + @Resource + private CertificateLoader certificateLoader; + @Resource + private WechatCertAutoConfig wechatCertAutoConfig; + @Resource + private WechatPayConfigValidator wechatPayConfigValidator; + @Value("${spring.profiles.active}") + String active; + @Resource + private KuaiDi100Impl kuaiDi100; + @Resource + private ShopExpressService expressService; + @Resource + private ShopUserAddressService shopUserAddressService; + @Resource + private ShopOrderDeliveryService shopOrderDeliveryService; + @Resource + private PaymentService paymentService; + + @Operation(summary = "分页查询订单") + @GetMapping("/page") + public ApiResult> page(ShopOrderParam param) { + // 使用关联查询 + return success(shopOrderService.pageRel(param)); + } + + @Operation(summary = "查询全部订单") + @GetMapping() + public ApiResult> list(ShopOrderParam param) { + // 使用关联查询 + return success(shopOrderService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopOrder:list')") + @Operation(summary = "根据id查询订单") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopOrderService.getByIdRel(id)); + } + + @Operation(summary = "添加订单") + @PostMapping() + public ApiResult save(@RequestBody OrderCreateRequest request) { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("用户未登录"); + } + + try { + Map wxOrderInfo = orderBusinessService.createOrder(request, loginUser); + return success("下单成功", wxOrderInfo); + } catch (Exception e) { + logger.error("创建订单失败 - 用户ID:{},请求:{}", loginUser.getUserId(), request, e); + return fail(e.getMessage()); + } + } + + @Operation(summary = "添加订单(兼容旧版本)") + @PostMapping("/legacy") + public ApiResult saveLegacy(@RequestBody ShopOrder shopOrder) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopOrder.setUserId(loginUser.getUserId()); + shopOrder.setOpenid(loginUser.getOpenid()); + shopOrder.setPayUserId(loginUser.getUserId()); + if (shopOrder.getOrderNo() == null) { + shopOrder.setOrderNo(Long.toString(IdUtil.getSnowflakeNextId())); + } + if (shopOrder.getComments() == null) { + shopOrder.setComments("暂无"); + } + // 微信支付(商品金额不能为0) + if (shopOrder.getTotalPrice().compareTo(BigDecimal.ZERO) == 0) { + return fail("商品金额不能为0"); + } + // 百色中学项目捐赠金额不能低于20元 + if (shopOrder.getTenantId().equals(10324) && shopOrder.getTotalPrice().compareTo(new BigDecimal("10")) < 0) { + return fail("捐款金额最低不能少于10元,感谢您的爱心捐赠^_^"); + } + // 测试支付 + if (loginUser.getPhone().equals("13737128880")) { + shopOrder.setPrice(new BigDecimal("0.01")); + shopOrder.setTotalPrice(new BigDecimal("0.01")); + } + if (shopOrderService.save(shopOrder)) { + return success("下单成功", shopOrderService.createWxOrder(shopOrder)); + } + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopOrder:update')") + @Operation(summary = "修改订单") + @PutMapping() + public ApiResult update(@RequestBody ShopOrder shopOrder) throws Exception { + // 1. 验证订单是否可以退款 + if (shopOrder == null) { + return fail("订单不存在"); + } + ShopOrder shopOrderNow = shopOrderService.getById(shopOrder.getOrderId()); + // 申请退款 + if (shopOrder.getOrderStatus().equals(4)) { + shopOrder.setRefundApplyTime(LocalDateTime.now()); + } + if (shopOrderNow.getDeliveryStatus().equals(10) && shopOrder.getDeliveryStatus().equals(20)) { + ShopOrderDelivery shopOrderDelivery = new ShopOrderDelivery(); + shopOrderDelivery.setOrderId(shopOrder.getOrderId()); + shopOrderDelivery.setDeliveryMethod(30); + shopOrderDelivery.setExpressId(shopOrder.getExpressId()); + shopOrderDelivery.setSendName(shopOrder.getSendName()); + shopOrderDelivery.setSendPhone(shopOrder.getSendPhone()); + shopOrderDelivery.setSendAddress(shopOrder.getSendAddress()); + shopOrderDeliveryService.save(shopOrderDelivery); + + shopOrderDeliveryService.setExpress(getLoginUser(), shopOrderDelivery, shopOrder); + + } + // 退款操作 + if(shopOrder.getOrderStatus().equals(6)){ + // 当订单状态更改为6(已退款)时,执行退款操作 + try { + + // 检查订单是否已支付 + if (!shopOrder.getPayStatus()) { + return fail("订单未支付,无法退款"); + } + + // 检查是否已经退款过了 + if (StrUtil.isNotBlank(shopOrderNow.getRefundOrder())) { + logger.warn("订单已经退款过,订单号: {}, 退款单号: {}", shopOrderNow.getOrderNo(), shopOrderNow.getRefundOrder()); + return fail("订单已退款,请勿重复操作"); + } + + // 2. 生成退款单号 + String refundNo = "RF" + IdUtil.getSnowflakeNextId(); + + // 3. 确定退款金额(默认全额退款) + BigDecimal refundAmount = shopOrder.getRefundMoney(); + if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) { + // 如果没有指定退款金额,使用订单实付金额 + refundAmount = shopOrderNow.getTotalPrice(); + } + + // 验证退款金额不能大于订单金额 + if (refundAmount.compareTo(shopOrderNow.getTotalPrice()) > 0) { + return fail("退款金额不能大于订单金额"); + } + + // 4. 确定支付类型(默认为微信Native支付) + PaymentType paymentType = PaymentType.WECHAT_NATIVE; + if (shopOrderNow.getPayType() != null) { + // 根据订单的支付类型确定 + // 支付方式:0余额支付,1微信支付,2支付宝支付,3银联支付,4现金支付,5POS机支付,6免费,7积分支付 + paymentType = PaymentType.getByCode(shopOrderNow.getPayType()); + + // 如果是微信支付,需要根据微信支付子类型确定具体的支付方式 + if (paymentType == PaymentType.WECHAT) { + // 目前统一使用WECHAT_NATIVE进行退款 + paymentType = PaymentType.WECHAT_NATIVE; + } + } + + // 5. 调用统一支付服务的退款接口 + logger.info("开始处理订单退款 - 订单号: {}, 退款单号: {}, 退款金额: {}, 支付方式: {}", + shopOrderNow.getOrderNo(), refundNo, refundAmount, paymentType); + + PaymentResponse refundResponse = paymentService.refund( + shopOrderNow.getOrderNo(), // 原订单号 + refundNo, // 退款单号 + paymentType, // 支付方式 + shopOrderNow.getTotalPrice(), // 订单总金额 + refundAmount, // 退款金额 + shopOrder.getRefundReason() != null ? shopOrder.getRefundReason() : "用户申请退款", // 退款原因 + shopOrderNow.getTenantId() // 租户ID + ); + + // 6. 处理退款结果 + if (refundResponse.getSuccess()) { + // 退款成功,更新订单信息 + shopOrder.setRefundOrder(refundNo); + shopOrder.setRefundMoney(refundAmount); + shopOrder.setRefundTime(LocalDateTime.now()); + shopOrder.setOrderStatus(6); // 退款成功 + + // 根据退款状态决定订单状态 + // 如果微信返回退款处理中,则设置订单状态为5(退款处理中) + // 如果微信返回退款成功,则保持状态为6(退款成功) +// if (refundResponse.getPaymentStatus() != null) { +// switch (refundResponse.getPaymentStatus()) { +// case REFUNDING: +// shopOrder.setOrderStatus(5); // 退款处理中 +// logger.info("订单退款处理中,订单号: {}, 退款单号: {}", shopOrderNow.getOrderNo(), refundNo); +// break; +// case REFUNDED: +// shopOrder.setOrderStatus(6); // 退款成功 +// logger.info("订单退款成功,订单号: {}, 退款单号: {}", shopOrderNow.getOrderNo(), refundNo); +// break; +// case REFUND_FAILED: +// logger.error("订单退款失败,订单号: {}, 退款单号: {}", shopOrderNow.getOrderNo(), refundNo); +// return fail("退款失败,请联系管理员"); +// default: +// shopOrder.setOrderStatus(5); // 默认为退款处理中 +// } +// } + + logger.info("订单退款请求成功 - 订单号: {}, 退款单号: {}, 微信退款单号: {}", + shopOrderNow.getOrderNo(), refundNo, refundResponse.getTransactionId()); + } else { + // 退款失败 + logger.error("订单退款失败 - 订单号: {}, 错误: {}", shopOrderNow.getOrderNo(), refundResponse.getErrorMessage()); + return fail("退款失败: " + refundResponse.getErrorMessage()); + } + + } catch (Exception e) { + logger.error("处理订单退款异常 - 订单号: {}, 错误: {}", shopOrderNow.getOrderNo(), e.getMessage(), e); + return fail("退款处理异常: " + e.getMessage()); + } + } + if (shopOrderService.updateById(shopOrder)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除订单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopOrderService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加订单") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopOrderService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改订单") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopOrderService, "order_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除订单") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopOrderService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "修复订单") + @PutMapping("/repair") + public ApiResult repair(@RequestBody ShopOrder shopOrder) { + final ShopOrder order = shopOrderService.getByOutTradeNo(shopOrder.getOrderNo()); + if (order != null) { + shopOrderService.queryOrderByOutTradeNo(order); + return success("修复成功"); + } + return fail("修复失败"); + } + + @Operation(summary = "统计订单总金额") + @GetMapping("/total") + public ApiResult total() { + return success(shopOrderService.total()); + } + + @Operation(summary = "取消订单") + @PutMapping("/cancel/{id}") + public ApiResult cancelOrder(@PathVariable("id") Integer id) { + try { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("用户未登录"); + } + + ShopOrder order = shopOrderService.getById(id); + if (order == null) { + return fail("订单不存在"); + } + + // 检查订单是否属于当前用户(非管理员用户) + if (!loginUser.getUserId().equals(order.getUserId()) && + !hasOrderCancelAuthority()) { + return fail("无权限取消此订单"); + } + + // 检查订单状态 + if (order.getPayStatus() != null && order.getPayStatus()) { + return fail("订单已支付,无法取消"); + } + + if (order.getOrderStatus() != null && order.getOrderStatus() != 0) { + return fail("订单状态不允许取消"); + } + + boolean success = orderCancelService.cancelOrder(order); + if (success) { + return success("订单取消成功"); + } else { + return fail("订单取消失败"); + } + + } catch (Exception e) { + logger.error("取消订单失败,订单ID:{}", id, e); + return fail("取消订单失败:" + e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('shop:shopOrder:manage')") + @Operation(summary = "手动触发订单自动取消任务(管理员)") + @PostMapping("/auto-cancel/trigger") + public ApiResult triggerAutoCancelTask() { + try { + orderAutoCancelTask.manualCancelExpiredOrders(); + return success("自动取消任务已触发"); + } catch (Exception e) { + logger.error("触发自动取消任务失败", e); + return fail("触发失败:" + e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('shop:shopOrder:manage')") + @Operation(summary = "获取自动取消任务状态(管理员)") + @GetMapping("/auto-cancel/status") + public ApiResult getAutoCancelTaskStatus() { + try { + String status = orderAutoCancelTask.getTaskStatus(); + return success(status); + } catch (Exception e) { + logger.error("获取自动取消任务状态失败", e); + return fail("获取状态失败:" + e.getMessage()); + } + } + + @Schema(description = "异步通知11") + @PostMapping("/notify/{tenantId}") + public String wxNotify(@RequestHeader Map header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) { + logger.info("异步通知*************** = " + tenantId); + + // 获取支付配置信息用于解密 + String key = "Payment:1:".concat(tenantId.toString()); + Payment payment = redisUtil.get(key, Payment.class); + + // 检查支付配置 + if (ObjectUtil.isEmpty(payment)) { + throw new RuntimeException("未找到租户支付配置信息,租户ID: " + tenantId); + } + + logger.info("开始处理微信支付异步通知 - 租户ID: {}", tenantId); + logger.info("支付配置信息 - 商户号: {}, 应用ID: {}", payment.getMchId(), payment.getAppId()); + + // 验证微信支付配置 + WechatPayConfigValidator.ValidationResult validation = wechatPayConfigValidator.validateWechatPayConfig(payment, tenantId); + if (!validation.isValid()) { + logger.error("❌ 微信支付配置验证失败: {}", validation.getErrors()); + logger.info("📋 配置诊断报告:\n{}", wechatPayConfigValidator.generateDiagnosticReport(payment, tenantId)); + throw new RuntimeException("微信支付配置验证失败: " + validation.getErrors()); + } + logger.info("✅ 微信支付配置验证通过"); + + RequestParam requestParam = new RequestParam.Builder() + .serialNumber(header.get("wechatpay-serial")) + .nonce(header.get("wechatpay-nonce")) + .signature(header.get("wechatpay-signature")) + .timestamp(header.get("wechatpay-timestamp")) + .body(body) + .build(); + + // 创建通知配置 - 使用与下单方法相同的证书配置逻辑 + NotificationConfig config; + try { + if (active.equals("dev")) { + // 开发环境 - 构建包含租户号的私钥路径 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + + logger.info("开发环境异步通知证书路径: {}", privateKeyPath); + logger.info("租户ID: {}, 证书目录: {}", tenantId, tenantCertPath); + + // 检查证书文件是否存在 + if (!certificateLoader.certificateExists(privateKeyPath)) { + logger.error("证书文件不存在: {}", privateKeyPath); + throw new RuntimeException("证书文件不存在: " + privateKeyPath); + } + + String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); + + // 使用验证器获取有效的 APIv3 密钥 + String apiV3Key = wechatPayConfigValidator.getValidApiV3Key(payment); + + logger.info("私钥文件加载成功: {}", privateKey); + logger.info("使用APIv3密钥来源: {}", payment.getApiKey() != null && !payment.getApiKey().trim().isEmpty() ? "数据库配置" : "配置文件默认"); + logger.info("APIv3密钥长度: {}", apiV3Key != null ? apiV3Key.length() : 0); + logger.info("商户证书序列号: {}", payment.getMerchantSerialNumber()); + + // 使用自动证书配置 + config = new RSAAutoCertificateConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(apiV3Key) + .build(); + + logger.info("✅ 开发环境使用自动证书配置创建通知解析器成功"); + } else { + // 生产环境 - 使用自动证书配置 + final String certRootPath = certConfig.getCertRootPath(); + logger.info("生产环境证书根路径: {}", certRootPath); + + String privateKeyRelativePath = payment.getApiclientKey(); + logger.info("数据库中的私钥相对路径: {}", privateKeyRelativePath); + + // 生产环境已经没有/file目录,所有路径都直接拼接到根路径 + String privateKeyFullPath; + // 处理数据库中可能存在的历史路径格式 + String cleanPath = privateKeyRelativePath; + if (privateKeyRelativePath.startsWith("/file/")) { + // 去掉历史的 /file/ 前缀 + cleanPath = privateKeyRelativePath.substring(6); + } else if (privateKeyRelativePath.startsWith("file/")) { + // 去掉历史的 file/ 前缀 + cleanPath = privateKeyRelativePath.substring(5); + } + // 确保路径以 / 开头 + if (!cleanPath.startsWith("/")) { + cleanPath = "/" + cleanPath; + } + privateKeyFullPath = certRootPath + cleanPath; + + logger.info("生产环境私钥完整路径: {}", privateKeyFullPath); + String privateKey = certificateLoader.loadCertificatePath(privateKeyFullPath); + String apiV3Key = payment.getApiKey(); + + // 使用自动证书配置 + config = new RSAAutoCertificateConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(apiV3Key) + .build(); + + logger.info("✅ 生产环境使用自动证书配置创建通知解析器成功"); + } + } catch (Exception e) { + logger.error("❌ 创建通知配置失败 - 租户ID: {}, 商户号: {}", tenantId, payment.getMchId(), e); + logger.error("🔍 错误详情: {}", e.getMessage()); + logger.error("💡 请检查:"); + logger.error("1. 证书文件是否存在且路径正确"); + logger.error("2. APIv3密钥是否配置正确"); + logger.error("3. 商户证书序列号是否正确"); + logger.error("4. 网络连接是否正常"); + throw new RuntimeException("微信支付通知配置失败: " + e.getMessage(), e); + } + + // 初始化 NotificationParser + NotificationParser parser = new NotificationParser(config); + logger.info("✅ 通知解析器创建成功,准备解析异步通知"); + + // 以支付通知回调为例,验签、解密并转换成 Transaction + try { + logger.info("开始解析微信支付异步通知..."); + Transaction transaction = parser.parse(requestParam, Transaction.class); + logger.info("✅ 异步通知解析成功 - 交易状态: {}, 商户订单号: {}", + transaction.getTradeStateDesc(), transaction.getOutTradeNo()); + + if (StrUtil.equals("支付成功", transaction.getTradeStateDesc())) { + final String outTradeNo = transaction.getOutTradeNo(); + final String transactionId = transaction.getTransactionId(); + final Integer total = transaction.getAmount().getTotal(); + final String tradeStateDesc = transaction.getTradeStateDesc(); + final Transaction.TradeStateEnum tradeState = transaction.getTradeState(); + final Transaction.TradeTypeEnum tradeType = transaction.getTradeType(); + System.out.println("transaction = " + transaction); + System.out.println("tradeStateDesc = " + tradeStateDesc); + System.out.println("tradeType = " + tradeType); + System.out.println("tradeState = " + tradeState); + System.out.println("outTradeNo = " + outTradeNo); + System.out.println("amount = " + total); + // 1. 查询要处理的订单 + ShopOrder order = shopOrderService.getByOutTradeNo(outTradeNo); + logger.info("查询要处理的订单order = " + order); + // 2. 已支付则跳过 + if (order.getPayStatus().equals(true)) { + return "SUCCESS"; + } + // 2. 未支付则处理更新订单状态 + if (order.getPayStatus().equals(false)) { + // 5. TODO 处理订单状态 + order.setPayTime(LocalDateTime.now()); + order.setExpirationTime(order.getCreateTime()); + order.setPayStatus(true); + order.setTransactionId(transactionId); + order.setPayPrice(new BigDecimal(NumberUtil.decimalFormat("0.00", total * 0.01))); + order.setExpirationTime(LocalDateTime.now().plusYears(10)); + System.out.println("实际付款金额 = " + order.getPayPrice()); + // 更新订单状态并处理支付成功后的业务逻辑(包括累加商品销量) + shopOrderService.updateByOutTradeNo(order); + return "SUCCESS"; + } + } + } catch (Exception e) { + logger.error("❌ 处理微信支付异步通知失败 - 租户ID: {}, 商户号: {}", tenantId, payment.getMchId(), e); + logger.error("🔍 异常详情: {}", e.getMessage()); + logger.error("💡 可能的原因:"); + logger.error("1. 证书配置错误或证书文件损坏"); + logger.error("2. 微信支付平台证书已过期"); + logger.error("3. 签名验证失败"); + logger.error("4. 请求参数格式错误"); + + // 返回失败,微信会重试 + return "fail"; + } + + logger.warn("⚠️ 异步通知处理完成但未找到匹配的支付成功状态"); + return "fail"; + } + + @Operation(summary = "更新订单支付状态", description = "用户支付成功后主动同步订单状态") + @PutMapping("/payment-status") + public ApiResult updateOrderPaymentStatus(@RequestBody UpdatePaymentStatusRequest request) { + logger.info("收到更新订单支付状态请求: orderNo={}, paymentStatus={}, transactionId={}", + request.getOrderNo(), request.getPaymentStatus(), request.getTransactionId()); + + final User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); + } + + try { + // 参数验证 + if (StrUtil.isBlank(request.getOrderNo())) { + return fail("订单号不能为空"); + } + + // 查询订单 + ShopOrder order = shopOrderService.getByOrderNo(request.getOrderNo(), loginUser.getTenantId()); + if (order == null) { + return fail("订单不存在"); + } + + // 权限验证:只能更新自己的订单 + if (!order.getUserId().equals(loginUser.getUserId())) { + return fail("无权限操作此订单"); + } + + // 如果订单已经是支付成功状态,直接返回成功 + if (order.getPayStatus()) { + logger.info("订单已经是支付成功状态,无需更新: orderNo={}", request.getOrderNo()); + return success("订单状态已是最新"); + } + + // 调用支付状态同步服务 + boolean updated = shopOrderService.syncPaymentStatus( + request.getOrderNo(), + request.getPaymentStatus(), + request.getTransactionId(), + request.getPayTime(), + loginUser.getTenantId() + ); + + if (updated) { + logger.info("订单支付状态更新成功: orderNo={}, paymentStatus={}", + request.getOrderNo(), request.getPaymentStatus()); + return success("订单状态更新成功"); + } else { + logger.warn("订单支付状态更新失败: orderNo={}", request.getOrderNo()); + return fail("订单状态更新失败"); + } + + } catch (Exception e) { + logger.error("更新订单支付状态异常: orderNo={}, error={}", request.getOrderNo(), e.getMessage(), e); + return fail("更新订单状态失败: " + e.getMessage()); + } + } + + /** + * 检查是否有订单取消权限 + */ + private boolean hasOrderCancelAuthority() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return false; + } + + // 检查是否有管理员权限 + return authentication.getAuthorities().stream() + .anyMatch(authority -> + authority.getAuthority().equals("shop:shopOrder:cancel") || + authority.getAuthority().equals("shop:shopOrder:update") || + authority.getAuthority().equals("ROLE_ADMIN") || + authority.getAuthority().equals("shop:shopOrder:manage")); + } catch (Exception e) { + logger.warn("检查订单取消权限时发生异常", e); + return false; + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderDeliveryController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderDeliveryController.java new file mode 100644 index 0000000..a6e5405 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderDeliveryController.java @@ -0,0 +1,123 @@ +package com.gxwebsoft.shop.controller; + +import cn.binarywang.wx.miniapp.bean.shop.request.shipping.*; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.*; +import com.gxwebsoft.shop.service.ShopOrderDeliveryService; +import com.gxwebsoft.shop.param.ShopOrderDeliveryParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.kuaidi100.sdk.response.SubscribeResp; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 发货单控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "发货单管理") +@RestController +@RequestMapping("/api/shop/shop-order-delivery") +public class ShopOrderDeliveryController extends BaseController { + @Resource + private ShopOrderDeliveryService shopOrderDeliveryService; + + + @Operation(summary = "发货回调") + @PostMapping("/notify") + @GetMapping("/notify") + public SubscribeResp notify(@RequestBody Map data) { + System.out.println("快递100回调:" + data); + SubscribeResp subscribeResp = new SubscribeResp(); + subscribeResp.setResult(Boolean.TRUE); + subscribeResp.setReturnCode("200"); + subscribeResp.setMessage("成功"); + return subscribeResp; + } + + @Operation(summary = "分页查询发货单") + @GetMapping("/page") + public ApiResult> page(ShopOrderDeliveryParam param) { + // 使用关联查询 + return success(shopOrderDeliveryService.pageRel(param)); + } + + @Operation(summary = "查询全部发货单") + @GetMapping() + public ApiResult> list(ShopOrderDeliveryParam param) { + // 使用关联查询 + return success(shopOrderDeliveryService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopOrderDelivery:list')") + @Operation(summary = "根据id查询发货单") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopOrderDeliveryService.getByIdRel(id)); + } + + @Operation(summary = "添加发货单") + @PostMapping() + public ApiResult save(@RequestBody ShopOrderDelivery shopOrderDelivery) { + if (shopOrderDeliveryService.save(shopOrderDelivery)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改发货单") + @PutMapping() + public ApiResult update(@RequestBody ShopOrderDelivery shopOrderDelivery) { + if (shopOrderDeliveryService.updateById(shopOrderDelivery)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除发货单") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopOrderDeliveryService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加发货单") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopOrderDeliveryService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改发货单") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopOrderDeliveryService, "delivery_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除发货单") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopOrderDeliveryService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderDeliveryGoodsController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderDeliveryGoodsController.java new file mode 100644 index 0000000..760becb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderDeliveryGoodsController.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopOrderDeliveryGoodsService; +import com.gxwebsoft.shop.entity.ShopOrderDeliveryGoods; +import com.gxwebsoft.shop.param.ShopOrderDeliveryGoodsParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 发货单商品控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "发货单商品管理") +@RestController +@RequestMapping("/api/shop/shop-order-delivery-goods") +public class ShopOrderDeliveryGoodsController extends BaseController { + @Resource + private ShopOrderDeliveryGoodsService shopOrderDeliveryGoodsService; + + @Operation(summary = "分页查询发货单商品") + @GetMapping("/page") + public ApiResult> page(ShopOrderDeliveryGoodsParam param) { + // 使用关联查询 + return success(shopOrderDeliveryGoodsService.pageRel(param)); + } + + @Operation(summary = "查询全部发货单商品") + @GetMapping() + public ApiResult> list(ShopOrderDeliveryGoodsParam param) { + // 使用关联查询 + return success(shopOrderDeliveryGoodsService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopOrderDeliveryGoods:list')") + @Operation(summary = "根据id查询发货单商品") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopOrderDeliveryGoodsService.getByIdRel(id)); + } + + @Operation(summary = "添加发货单商品") + @PostMapping() + public ApiResult save(@RequestBody ShopOrderDeliveryGoods shopOrderDeliveryGoods) { + if (shopOrderDeliveryGoodsService.save(shopOrderDeliveryGoods)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改发货单商品") + @PutMapping() + public ApiResult update(@RequestBody ShopOrderDeliveryGoods shopOrderDeliveryGoods) { + if (shopOrderDeliveryGoodsService.updateById(shopOrderDeliveryGoods)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除发货单商品") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopOrderDeliveryGoodsService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加发货单商品") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopOrderDeliveryGoodsService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改发货单商品") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopOrderDeliveryGoodsService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除发货单商品") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopOrderDeliveryGoodsService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderExtractController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderExtractController.java new file mode 100644 index 0000000..5b89db0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderExtractController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopOrderExtractService; +import com.gxwebsoft.shop.entity.ShopOrderExtract; +import com.gxwebsoft.shop.param.ShopOrderExtractParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 自提订单联系方式控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "自提订单联系方式管理") +@RestController +@RequestMapping("/api/shop/shop-order-extract") +public class ShopOrderExtractController extends BaseController { + @Resource + private ShopOrderExtractService shopOrderExtractService; + + @Operation(summary = "分页查询自提订单联系方式") + @GetMapping("/page") + public ApiResult> page(ShopOrderExtractParam param) { + // 使用关联查询 + return success(shopOrderExtractService.pageRel(param)); + } + + @Operation(summary = "查询全部自提订单联系方式") + @GetMapping() + public ApiResult> list(ShopOrderExtractParam param) { + // 使用关联查询 + return success(shopOrderExtractService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopOrderExtract:list')") + @Operation(summary = "根据id查询自提订单联系方式") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopOrderExtractService.getByIdRel(id)); + } + + @Operation(summary = "添加自提订单联系方式") + @PostMapping() + public ApiResult save(@RequestBody ShopOrderExtract shopOrderExtract) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopOrderExtract.setUserId(loginUser.getUserId()); + } + if (shopOrderExtractService.save(shopOrderExtract)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改自提订单联系方式") + @PutMapping() + public ApiResult update(@RequestBody ShopOrderExtract shopOrderExtract) { + if (shopOrderExtractService.updateById(shopOrderExtract)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除自提订单联系方式") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopOrderExtractService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加自提订单联系方式") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopOrderExtractService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改自提订单联系方式") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopOrderExtractService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除自提订单联系方式") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopOrderExtractService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderGoodsController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderGoodsController.java new file mode 100644 index 0000000..cc01666 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderGoodsController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopOrderGoodsService; +import com.gxwebsoft.shop.entity.ShopOrderGoods; +import com.gxwebsoft.shop.param.ShopOrderGoodsParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品信息控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "商品信息管理") +@RestController +@RequestMapping("/api/shop/shop-order-goods") +public class ShopOrderGoodsController extends BaseController { + @Resource + private ShopOrderGoodsService shopOrderGoodsService; + + @Operation(summary = "分页查询商品信息") + @GetMapping("/page") + public ApiResult> page(ShopOrderGoodsParam param) { + // 使用关联查询 + return success(shopOrderGoodsService.pageRel(param)); + } + + @Operation(summary = "查询全部商品信息") + @GetMapping() + public ApiResult> list(ShopOrderGoodsParam param) { + // 使用关联查询 + return success(shopOrderGoodsService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopOrderGoods:list')") + @Operation(summary = "根据id查询商品信息") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopOrderGoodsService.getByIdRel(id)); + } + + @Operation(summary = "添加商品信息") + @PostMapping() + public ApiResult save(@RequestBody ShopOrderGoods shopOrderGoods) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopOrderGoods.setUserId(loginUser.getUserId()); + } + if (shopOrderGoodsService.save(shopOrderGoods)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改商品信息") + @PutMapping() + public ApiResult update(@RequestBody ShopOrderGoods shopOrderGoods) { + if (shopOrderGoodsService.updateById(shopOrderGoods)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除商品信息") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopOrderGoodsService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加商品信息") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopOrderGoodsService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改商品信息") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopOrderGoodsService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除商品信息") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopOrderGoodsService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderInfoController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderInfoController.java new file mode 100644 index 0000000..e9f91d8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderInfoController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopOrderInfoService; +import com.gxwebsoft.shop.entity.ShopOrderInfo; +import com.gxwebsoft.shop.param.ShopOrderInfoParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 场地控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "场地管理") +@RestController +@RequestMapping("/api/shop/shop-order-info") +public class ShopOrderInfoController extends BaseController { + @Resource + private ShopOrderInfoService shopOrderInfoService; + + @Operation(summary = "分页查询场地") + @GetMapping("/page") + public ApiResult> page(ShopOrderInfoParam param) { + // 使用关联查询 + return success(shopOrderInfoService.pageRel(param)); + } + + @Operation(summary = "查询全部场地") + @GetMapping() + public ApiResult> list(ShopOrderInfoParam param) { + // 使用关联查询 + return success(shopOrderInfoService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopOrderInfo:list')") + @Operation(summary = "根据id查询场地") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopOrderInfoService.getByIdRel(id)); + } + + @Operation(summary = "添加场地") + @PostMapping() + public ApiResult save(@RequestBody ShopOrderInfo shopOrderInfo) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopOrderInfo.setUserId(loginUser.getUserId()); + } + if (shopOrderInfoService.save(shopOrderInfo)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改场地") + @PutMapping() + public ApiResult update(@RequestBody ShopOrderInfo shopOrderInfo) { + if (shopOrderInfoService.updateById(shopOrderInfo)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除场地") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopOrderInfoService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加场地") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopOrderInfoService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改场地") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopOrderInfoService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除场地") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopOrderInfoService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderInfoLogController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderInfoLogController.java new file mode 100644 index 0000000..b9c62b6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopOrderInfoLogController.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopOrderInfoLogService; +import com.gxwebsoft.shop.entity.ShopOrderInfoLog; +import com.gxwebsoft.shop.param.ShopOrderInfoLogParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 订单核销控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "订单核销管理") +@RestController +@RequestMapping("/api/shop/shop-order-info-log") +public class ShopOrderInfoLogController extends BaseController { + @Resource + private ShopOrderInfoLogService shopOrderInfoLogService; + + @Operation(summary = "分页查询订单核销") + @GetMapping("/page") + public ApiResult> page(ShopOrderInfoLogParam param) { + // 使用关联查询 + return success(shopOrderInfoLogService.pageRel(param)); + } + + @Operation(summary = "查询全部订单核销") + @GetMapping() + public ApiResult> list(ShopOrderInfoLogParam param) { + // 使用关联查询 + return success(shopOrderInfoLogService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopOrderInfoLog:list')") + @Operation(summary = "根据id查询订单核销") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopOrderInfoLogService.getByIdRel(id)); + } + + @Operation(summary = "添加订单核销") + @PostMapping() + public ApiResult save(@RequestBody ShopOrderInfoLog shopOrderInfoLog) { + if (shopOrderInfoLogService.save(shopOrderInfoLog)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改订单核销") + @PutMapping() + public ApiResult update(@RequestBody ShopOrderInfoLog shopOrderInfoLog) { + if (shopOrderInfoLogService.updateById(shopOrderInfoLog)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除订单核销") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopOrderInfoLogService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加订单核销") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopOrderInfoLogService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改订单核销") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopOrderInfoLogService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除订单核销") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopOrderInfoLogService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopRechargeOrderController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopRechargeOrderController.java new file mode 100644 index 0000000..1525208 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopRechargeOrderController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopRechargeOrderService; +import com.gxwebsoft.shop.entity.ShopRechargeOrder; +import com.gxwebsoft.shop.param.ShopRechargeOrderParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 会员充值订单表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Tag(name = "会员充值订单表管理") +@RestController +@RequestMapping("/api/shop/shop-recharge-order") +public class ShopRechargeOrderController extends BaseController { + @Resource + private ShopRechargeOrderService shopRechargeOrderService; + + @Operation(summary = "分页查询会员充值订单表") + @GetMapping("/page") + public ApiResult> page(ShopRechargeOrderParam param) { + // 使用关联查询 + return success(shopRechargeOrderService.pageRel(param)); + } + + @Operation(summary = "查询全部会员充值订单表") + @GetMapping() + public ApiResult> list(ShopRechargeOrderParam param) { + // 使用关联查询 + return success(shopRechargeOrderService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopRechargeOrder:list')") + @Operation(summary = "根据id查询会员充值订单表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopRechargeOrderService.getByIdRel(id)); + } + + @Operation(summary = "添加会员充值订单表") + @PostMapping() + public ApiResult save(@RequestBody ShopRechargeOrder shopRechargeOrder) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopRechargeOrder.setUserId(loginUser.getUserId()); + } + if (shopRechargeOrderService.save(shopRechargeOrder)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改会员充值订单表") + @PutMapping() + public ApiResult update(@RequestBody ShopRechargeOrder shopRechargeOrder) { + if (shopRechargeOrderService.updateById(shopRechargeOrder)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除会员充值订单表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopRechargeOrderService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加会员充值订单表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopRechargeOrderService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改会员充值订单表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopRechargeOrderService, "order_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除会员充值订单表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopRechargeOrderService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSpecController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSpecController.java new file mode 100644 index 0000000..60ddcc8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSpecController.java @@ -0,0 +1,126 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopSpecService; +import com.gxwebsoft.shop.entity.ShopSpec; +import com.gxwebsoft.shop.param.ShopSpecParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 规格控制器 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Tag(name = "规格管理") +@RestController +@RequestMapping("/api/shop/shop-spec") +public class ShopSpecController extends BaseController { + @Resource + private ShopSpecService shopSpecService; + + @Operation(summary = "分页查询规格") + @GetMapping("/page") + public ApiResult> page(ShopSpecParam param) { + // 使用关联查询 + return success(shopSpecService.pageRel(param)); + } + + @Operation(summary = "查询全部规格") + @GetMapping() + public ApiResult> list(ShopSpecParam param) { + // 使用关联查询 + return success(shopSpecService.listRel(param)); + } + + @Operation(summary = "根据id查询规格") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopSpecService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopSpec:save')") + @OperationLog + @Operation(summary = "添加规格") + @PostMapping() + public ApiResult save(@RequestBody ShopSpec shopSpec) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopSpec.setUserId(loginUser.getUserId()); + } + if (shopSpecService.save(shopSpec)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpec:update')") + @OperationLog + @Operation(summary = "修改规格") + @PutMapping() + public ApiResult update(@RequestBody ShopSpec shopSpec) { + if (shopSpecService.updateById(shopSpec)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpec:remove')") + @OperationLog + @Operation(summary = "删除规格") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopSpecService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpec:save')") + @OperationLog + @Operation(summary = "批量添加规格") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopSpecService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpec:update')") + @OperationLog + @Operation(summary = "批量修改规格") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopSpecService, "spec_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpec:remove')") + @OperationLog + @Operation(summary = "批量删除规格") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopSpecService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSpecValueController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSpecValueController.java new file mode 100644 index 0000000..6d98bb3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSpecValueController.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopSpecValueService; +import com.gxwebsoft.shop.entity.ShopSpecValue; +import com.gxwebsoft.shop.param.ShopSpecValueParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 规格值控制器 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Tag(name = "规格值管理") +@RestController +@RequestMapping("/api/shop/shop-spec-value") +public class ShopSpecValueController extends BaseController { + @Resource + private ShopSpecValueService shopSpecValueService; + + @Operation(summary = "分页查询规格值") + @GetMapping("/page") + public ApiResult> page(ShopSpecValueParam param) { + // 使用关联查询 + return success(shopSpecValueService.pageRel(param)); + } + + @Operation(summary = "查询全部规格值") + @GetMapping() + public ApiResult> list(ShopSpecValueParam param) { + // 使用关联查询 + return success(shopSpecValueService.listRel(param)); + } + + @Operation(summary = "根据id查询规格值") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopSpecValueService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopSpecValue:save')") + @OperationLog + @Operation(summary = "添加规格值") + @PostMapping() + public ApiResult save(@RequestBody ShopSpecValue shopSpecValue) { + if (shopSpecValueService.save(shopSpecValue)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpecValue:update')") + @OperationLog + @Operation(summary = "修改规格值") + @PutMapping() + public ApiResult update(@RequestBody ShopSpecValue shopSpecValue) { + if (shopSpecValueService.updateById(shopSpecValue)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpecValue:remove')") + @OperationLog + @Operation(summary = "删除规格值") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopSpecValueService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpecValue:save')") + @OperationLog + @Operation(summary = "批量添加规格值") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopSpecValueService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpecValue:update')") + @OperationLog + @Operation(summary = "批量修改规格值") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopSpecValueService, "spec_value_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopSpecValue:remove')") + @OperationLog + @Operation(summary = "批量删除规格值") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopSpecValueService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSplashController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSplashController.java new file mode 100644 index 0000000..d39e628 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopSplashController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopSplashService; +import com.gxwebsoft.shop.entity.ShopSplash; +import com.gxwebsoft.shop.param.ShopSplashParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 开屏广告控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Tag(name = "开屏广告管理") +@RestController +@RequestMapping("/api/shop/shop-splash") +public class ShopSplashController extends BaseController { + @Resource + private ShopSplashService shopSplashService; + + @Operation(summary = "分页查询开屏广告") + @GetMapping("/page") + public ApiResult> page(ShopSplashParam param) { + // 使用关联查询 + return success(shopSplashService.pageRel(param)); + } + + @Operation(summary = "查询全部开屏广告") + @GetMapping() + public ApiResult> list(ShopSplashParam param) { + // 使用关联查询 + return success(shopSplashService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopSplash:list')") + @Operation(summary = "根据id查询开屏广告") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopSplashService.getByIdRel(id)); + } + + @Operation(summary = "添加开屏广告") + @PostMapping() + public ApiResult save(@RequestBody ShopSplash shopSplash) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopSplash.setUserId(loginUser.getUserId()); + } + if (shopSplashService.save(shopSplash)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改开屏广告") + @PutMapping() + public ApiResult update(@RequestBody ShopSplash shopSplash) { + if (shopSplashService.updateById(shopSplash)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除开屏广告") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopSplashService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加开屏广告") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopSplashService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改开屏广告") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopSplashService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除开屏广告") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopSplashService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserAddressController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserAddressController.java new file mode 100644 index 0000000..e2290f9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserAddressController.java @@ -0,0 +1,133 @@ + package com.gxwebsoft.shop.controller; + + import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; + import com.gxwebsoft.common.core.web.BaseController; + import com.gxwebsoft.shop.service.ShopUserAddressService; + import com.gxwebsoft.shop.entity.ShopUserAddress; + import com.gxwebsoft.shop.param.ShopUserAddressParam; + import com.gxwebsoft.common.core.web.ApiResult; + import com.gxwebsoft.common.core.web.PageResult; + import com.gxwebsoft.common.core.web.BatchParam; + import com.gxwebsoft.common.core.annotation.OperationLog; + import com.gxwebsoft.common.system.entity.User; + import io.swagger.v3.oas.annotations.tags.Tag; + import io.swagger.v3.oas.annotations.Operation; + import org.springframework.security.access.prepost.PreAuthorize; + import org.springframework.web.bind.annotation.*; + + import javax.annotation.Resource; + import java.util.List; + + /** + * 收货地址控制器 + * + * @author 科技小王子 + * @since 2025-07-22 23:06:40 + */ + @Tag(name = "收货地址管理") + @RestController + @RequestMapping("/api/shop/shop-user-address") + public class ShopUserAddressController extends BaseController { + @Resource + private ShopUserAddressService shopUserAddressService; + + @PreAuthorize("hasAuthority('shop:shopUserAddress:list')") + @Operation(summary = "分页查询收货地址") + @GetMapping("/page") + public ApiResult> page(ShopUserAddressParam param) { + // 使用关联查询 + return success(shopUserAddressService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:list')") + @Operation(summary = "查询全部收货地址") + @GetMapping() + public ApiResult> list(ShopUserAddressParam param) { + // 使用关联查询 + param.setUserId(getLoginUser().getUserId()); + return success(shopUserAddressService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:list')") + @Operation(summary = "根据id查询收货地址") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopUserAddressService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:save')") + @OperationLog + @Operation(summary = "添加收货地址") + @PostMapping() + public ApiResult save(@RequestBody ShopUserAddress shopUserAddress) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopUserAddress.setUserId(loginUser.getUserId()); + if (shopUserAddressService.count(new LambdaQueryWrapper().eq(ShopUserAddress::getUserId, loginUser.getUserId()).eq(ShopUserAddress::getAddress, shopUserAddress.getAddress())) > 0) { + return success("该地址已存在"); + } + } + if (shopUserAddressService.save(shopUserAddress)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:update')") + @OperationLog + @Operation(summary = "修改收货地址") + @PutMapping() + public ApiResult update(@RequestBody ShopUserAddress shopUserAddress) { + if (shopUserAddressService.updateById(shopUserAddress)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:remove')") + @OperationLog + @Operation(summary = "删除收货地址") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopUserAddressService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:save')") + @OperationLog + @Operation(summary = "批量添加收货地址") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopUserAddressService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:update')") + @OperationLog + @Operation(summary = "批量修改收货地址") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopUserAddressService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserAddress:remove')") + @OperationLog + @Operation(summary = "批量删除收货地址") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopUserAddressService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + } diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserBalanceLogController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserBalanceLogController.java new file mode 100644 index 0000000..0db1573 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserBalanceLogController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopUserBalanceLogService; +import com.gxwebsoft.shop.entity.ShopUserBalanceLog; +import com.gxwebsoft.shop.param.ShopUserBalanceLogParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户余额变动明细表控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Tag(name = "用户余额变动明细表管理") +@RestController +@RequestMapping("/api/shop/shop-user-balance-log") +public class ShopUserBalanceLogController extends BaseController { + @Resource + private ShopUserBalanceLogService shopUserBalanceLogService; + + @Operation(summary = "分页查询用户余额变动明细表") + @GetMapping("/page") + public ApiResult> page(ShopUserBalanceLogParam param) { + // 使用关联查询 + return success(shopUserBalanceLogService.pageRel(param)); + } + + @Operation(summary = "查询全部用户余额变动明细表") + @GetMapping() + public ApiResult> list(ShopUserBalanceLogParam param) { + // 使用关联查询 + return success(shopUserBalanceLogService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUserBalanceLog:list')") + @Operation(summary = "根据id查询用户余额变动明细表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopUserBalanceLogService.getByIdRel(id)); + } + + @Operation(summary = "添加用户余额变动明细表") + @PostMapping() + public ApiResult save(@RequestBody ShopUserBalanceLog shopUserBalanceLog) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopUserBalanceLog.setUserId(loginUser.getUserId()); + } + if (shopUserBalanceLogService.save(shopUserBalanceLog)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改用户余额变动明细表") + @PutMapping() + public ApiResult update(@RequestBody ShopUserBalanceLog shopUserBalanceLog) { + if (shopUserBalanceLogService.updateById(shopUserBalanceLog)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除用户余额变动明细表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopUserBalanceLogService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加用户余额变动明细表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopUserBalanceLogService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改用户余额变动明细表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopUserBalanceLogService, "log_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除用户余额变动明细表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopUserBalanceLogService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserCollectionController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserCollectionController.java new file mode 100644 index 0000000..0e01d68 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserCollectionController.java @@ -0,0 +1,115 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopUserCollectionService; +import com.gxwebsoft.shop.entity.ShopUserCollection; +import com.gxwebsoft.shop.param.ShopUserCollectionParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 我的收藏控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Tag(name = "我的收藏管理") +@RestController +@RequestMapping("/api/shop/shop-user-collection") +public class ShopUserCollectionController extends BaseController { + @Resource + private ShopUserCollectionService shopUserCollectionService; + + @Operation(summary = "分页查询我的收藏") + @GetMapping("/page") + public ApiResult> page(ShopUserCollectionParam param) { + // 使用关联查询 + return success(shopUserCollectionService.pageRel(param)); + } + + @Operation(summary = "查询全部我的收藏") + @GetMapping() + public ApiResult> list(ShopUserCollectionParam param) { + // 使用关联查询 + return success(shopUserCollectionService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUserCollection:list')") + @Operation(summary = "根据id查询我的收藏") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopUserCollectionService.getByIdRel(id)); + } + + @Operation(summary = "添加我的收藏") + @PostMapping() + public ApiResult save(@RequestBody ShopUserCollection shopUserCollection) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopUserCollection.setUserId(loginUser.getUserId()); + } + if (shopUserCollectionService.save(shopUserCollection)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改我的收藏") + @PutMapping() + public ApiResult update(@RequestBody ShopUserCollection shopUserCollection) { + if (shopUserCollectionService.updateById(shopUserCollection)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除我的收藏") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopUserCollectionService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加我的收藏") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopUserCollectionService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改我的收藏") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopUserCollectionService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除我的收藏") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopUserCollectionService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserController.java new file mode 100644 index 0000000..10f53a5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserController.java @@ -0,0 +1,127 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.entity.ShopUser; +import com.gxwebsoft.shop.param.ShopUserParam; +import com.gxwebsoft.shop.service.ShopUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户记录表控制器 + * + * @author 科技小王子 + * @since 2025-10-03 13:41:09 + */ +@Tag(name = "用户记录表管理") +@RestController +@RequestMapping("/api/shop/shop-user") +public class ShopUserController extends BaseController { + @Resource + private ShopUserService shopUserService; + + @PreAuthorize("hasAuthority('shop:shopUser:list')") + @Operation(summary = "分页查询用户记录表") + @GetMapping("/page") + public ApiResult> page(ShopUserParam param) { + // 使用关联查询 + return success(shopUserService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUser:list')") + @Operation(summary = "查询全部用户记录表") + @GetMapping() + public ApiResult> list(ShopUserParam param) { + // 使用关联查询 + return success(shopUserService.listRel(param)); + } + + @Operation(summary = "根据userId查询用户记录表") + @GetMapping("/{userId}") + public ApiResult get(@PathVariable("userId") Integer userId) { + // 使用关联查询 + return success(shopUserService.getByIdRel(userId)); + } + + @PreAuthorize("hasAuthority('shop:shopUser:save')") + @OperationLog + @Operation(summary = "添加用户记录表") + @PostMapping() + public ApiResult save(@RequestBody ShopUser shopUser) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopUser.setUserId(loginUser.getUserId()); + } + if (shopUserService.save(shopUser)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUser:update')") + @OperationLog + @Operation(summary = "修改用户记录表") + @PutMapping() + public ApiResult update(@RequestBody ShopUser shopUser) { + if (shopUserService.updateById(shopUser)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUser:remove')") + @OperationLog + @Operation(summary = "删除用户记录表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopUserService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUser:save')") + @OperationLog + @Operation(summary = "批量添加用户记录表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopUserService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUser:update')") + @OperationLog + @Operation(summary = "批量修改用户记录表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopUserService, "user_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUser:remove')") + @OperationLog + @Operation(summary = "批量删除用户记录表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopUserService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserCouponController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserCouponController.java new file mode 100644 index 0000000..a9382b2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserCouponController.java @@ -0,0 +1,309 @@ +package com.gxwebsoft.shop.controller; + +import cn.hutool.core.date.LocalDateTimeUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.entity.ShopCouponApplyCate; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.service.ShopCouponApplyCateService; +import com.gxwebsoft.shop.service.ShopCouponApplyItemService; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import com.gxwebsoft.shop.service.CouponStatusService; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.param.ShopUserCouponParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; + +import javax.annotation.Resource; +import java.text.ParseException; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; + +/** + * 用户优惠券控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Slf4j +@Tag(name = "用户优惠券管理") +@RestController +@RequestMapping("/api/shop/shop-user-coupon") +public class ShopUserCouponController extends BaseController { + @Resource + private ShopUserCouponService shopUserCouponService; + @Resource + private ShopCouponService couponService; + @Resource + private ShopCouponApplyCateService couponApplyCateService; + @Resource + private ShopCouponApplyItemService couponApplyItemService; + @Resource + private CouponStatusService couponStatusService; + + @Operation(summary = "用户优惠券列表") + @PostMapping("/list") + public ApiResult> list(@RequestBody ShopUserCoupon userCouponParam) throws ParseException { + MPJLambdaWrapper queryWrapper = new MPJLambdaWrapper() + .selectAll(ShopUserCoupon.class) + .selectAs(ShopCoupon::getName, ShopCoupon::getName) + .eq(ShopUserCoupon::getUserId, getLoginUserId()) + .leftJoin(ShopCoupon.class, ShopCoupon::getId, ShopUserCoupon::getCouponId); + if (userCouponParam.getIsExpire() != null) + queryWrapper.eq(ShopUserCoupon::getIsExpire, userCouponParam.getIsExpire()); + if (userCouponParam.getIsUse() != null) queryWrapper.eq(ShopUserCoupon::getIsUse, userCouponParam.getIsUse()); + List userCouponList = shopUserCouponService.list(queryWrapper); + for (ShopUserCoupon userCoupon : userCouponList) { + try { + // 使用新的状态管理服务检查和更新状态 + couponStatusService.checkAndUpdateCouponStatus(userCoupon); + + // 确保BigDecimal字段不为null时才处理 + if (userCoupon.getReducePrice() == null) { + userCoupon.setReducePrice(BigDecimal.ZERO); + } + if (userCoupon.getMinPrice() == null) { + userCoupon.setMinPrice(BigDecimal.ZERO); + } + + ShopCoupon coupon = couponService.getById(userCoupon.getCouponId()); + if (coupon != null) { + // 确保优惠券模板的BigDecimal字段不为null + if (coupon.getReducePrice() == null) { + coupon.setReducePrice(BigDecimal.ZERO); + } + if (coupon.getMinPrice() == null) { + coupon.setMinPrice(BigDecimal.ZERO); + } + + coupon.setCouponApplyCateList(couponApplyCateService.list( + new LambdaQueryWrapper() + .eq(ShopCouponApplyCate::getCouponId, userCoupon.getCouponId()) + )); + coupon.setCouponApplyItemList(couponApplyItemService.list( + new LambdaQueryWrapper() + .eq(ShopCouponApplyItem::getCouponId, userCoupon.getCouponId()) + )); + userCoupon.setCouponItem(coupon); + } + } catch (Exception e) { + log.error("处理用户优惠券数据异常: {}", e.getMessage(), e); + // 设置默认值避免序列化异常 + if (userCoupon.getReducePrice() == null) { + userCoupon.setReducePrice(BigDecimal.ZERO); + } + if (userCoupon.getMinPrice() == null) { + userCoupon.setMinPrice(BigDecimal.ZERO); + } + } + } + return success(userCouponList); + } + + @Operation(summary = "领取优惠券") + @PostMapping("/take") + public ApiResult take(@RequestBody ShopUserCoupon userCoupon) { + final User loginUser = getLoginUser(); + if (loginUser == null) return fail("请先登录"); + ShopCoupon coupon = couponService.getByIdRel(userCoupon.getCouponId()); + + // 检查优惠券是否存在 + if (coupon == null) return fail("优惠券不存在"); + + // 安全地检查已领取数量,避免空指针异常 + Integer receiveNum = coupon.getReceiveNum(); + if (receiveNum == null) receiveNum = 0; + + if (coupon.getTotalCount() != -1 && receiveNum >= coupon.getTotalCount()) return fail("已经被领完了"); + List userCouponList = shopUserCouponService.list( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getCouponId, userCoupon.getCouponId()) + .eq(ShopUserCoupon::getUserId, getLoginUserId()) + ); + int userNotUsedNum = 0; + for (ShopUserCoupon userCouponItem : userCouponList) { + if (userCouponItem.getIsUse().equals(0)) userNotUsedNum++; + } + if (userNotUsedNum > 0) return fail("您还有未使用的优惠券,无法领取"); + if (coupon.getLimitPerUser() > -1) { + if (userCouponList.size() >= coupon.getLimitPerUser()) + return fail("每用户最多领取" + coupon.getLimitPerUser() + "张优惠券"); + } + userCoupon.setType(coupon.getType()); + userCoupon.setReducePrice(coupon.getReducePrice()); + userCoupon.setDiscount(coupon.getDiscount()); + userCoupon.setMinPrice(coupon.getMinPrice()); + Integer expireType = coupon.getExpireType(); + userCoupon.setExpireType(expireType); + if (expireType == 10) { + userCoupon.setStartTime(LocalDateTime.now()); + userCoupon.setEndTime(LocalDateTimeUtil.offset(userCoupon.getStartTime(), coupon.getExpireDay(), ChronoUnit.DAYS)); + } else { + userCoupon.setStartTime(coupon.getStartTime()); + userCoupon.setEndTime(coupon.getEndTime()); + } + userCoupon.setUserId(getLoginUserId()); + shopUserCouponService.save(userCoupon); + + // 安全地更新已领取数量,避免空指针异常 + Integer currentReceiveNum = coupon.getReceiveNum(); + if (currentReceiveNum == null) currentReceiveNum = 0; + coupon.setReceiveNum(currentReceiveNum + 1); + couponService.updateById(coupon); + return success("领取成功"); + } + + @Operation(summary = "分页查询用户优惠券") + @GetMapping("/page") + public ApiResult> page(ShopUserCouponParam param) { + // 使用关联查询 + return success(shopUserCouponService.pageRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:list')") + @Operation(summary = "查询全部用户优惠券") + @GetMapping() + public ApiResult> list(ShopUserCouponParam param) { + // 使用关联查询 + return success(shopUserCouponService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:list')") + @Operation(summary = "根据id查询用户优惠券") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopUserCouponService.getByIdRel(id)); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:save')") + @OperationLog + @Operation(summary = "添加用户优惠券") + @PostMapping() + public ApiResult save(@RequestBody ShopUserCoupon shopUserCoupon) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopUserCoupon.setUserId(loginUser.getUserId()); + } + if (shopUserCouponService.save(shopUserCoupon)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:update')") + @OperationLog + @Operation(summary = "修改用户优惠券") + @PutMapping() + public ApiResult update(@RequestBody ShopUserCoupon shopUserCoupon) { + if (shopUserCouponService.updateById(shopUserCoupon)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:remove')") + @OperationLog + @Operation(summary = "删除用户优惠券") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopUserCouponService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:save')") + @OperationLog + @Operation(summary = "批量添加用户优惠券") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopUserCouponService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:update')") + @OperationLog + @Operation(summary = "批量修改用户优惠券") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopUserCouponService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserCoupon:remove')") + @OperationLog + @Operation(summary = "批量删除用户优惠券") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopUserCouponService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "获取我的可用优惠券") + @GetMapping("/my/available") + public ApiResult> getMyAvailableCoupons() { + try { + List coupons = couponStatusService.getAvailableCoupons(getLoginUserId()); + return success("获取成功", coupons); + } catch (Exception e) { + return fail("获取失败",null); + } + } + + @Operation(summary = "获取我的已使用优惠券") + @GetMapping("/my/used") + public ApiResult> getMyUsedCoupons() { + try { + List coupons = couponStatusService.getUsedCoupons(getLoginUserId()); + return success("获取成功", coupons); + } catch (Exception e) { + return fail("获取失败",null); + } + } + + @Operation(summary = "获取我的已过期优惠券") + @GetMapping("/my/expired") + public ApiResult> getMyExpiredCoupons() { + try { + List coupons = couponStatusService.getExpiredCoupons(getLoginUserId()); + return success("获取成功", coupons); + } catch (Exception e) { + return fail("获取失败",null); + } + } + + @Operation(summary = "获取我的优惠券统计") + @GetMapping("/my/statistics") + public ApiResult getMyCouponStatistics() { + try { + CouponStatusService.CouponStatusResult result = + couponStatusService.getUserCouponsGroupByStatus(getLoginUserId()); + return success("获取成功", result); + } catch (Exception e) { + return fail("获取失败",null); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserRefereeController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserRefereeController.java new file mode 100644 index 0000000..0309be9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopUserRefereeController.java @@ -0,0 +1,134 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopUserRefereeService; +import com.gxwebsoft.shop.entity.ShopUserReferee; +import com.gxwebsoft.shop.param.ShopUserRefereeParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用户推荐关系表控制器 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Tag(name = "用户推荐关系表管理") +@RestController +@RequestMapping("/api/shop/shop-user-referee") +public class ShopUserRefereeController extends BaseController { + @Resource + private ShopUserRefereeService shopUserRefereeService; + + @Operation(summary = "分页查询用户推荐关系表") + @GetMapping("/page") + public ApiResult> page(ShopUserRefereeParam param) { + // 使用关联查询 + return success(shopUserRefereeService.pageRel(param)); + } + + @Operation(summary = "查询全部用户推荐关系表") + @GetMapping() + public ApiResult> list(ShopUserRefereeParam param) { + // 使用关联查询 + return success(shopUserRefereeService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopUserReferee:list')") + @Operation(summary = "根据id查询用户推荐关系表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopUserRefereeService.getByIdRel(id)); + } + + @Operation(summary = "根据userId查询推荐人信息") + @GetMapping("/getByUserId/{userId}") + public ApiResult getByUserId(@PathVariable("userId") Integer userId) { + // 使用关联查询 + return success(shopUserRefereeService.getByUserIdRel(userId)); + } + + @PreAuthorize("hasAuthority('shop:shopUserReferee:save')") + @OperationLog + @Operation(summary = "添加用户推荐关系表") + @PostMapping() + public ApiResult save(@RequestBody ShopUserReferee shopUserReferee) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopUserReferee.setUserId(loginUser.getUserId()); + } + if (shopUserRefereeService.save(shopUserReferee)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserReferee:update')") + @OperationLog + @Operation(summary = "修改用户推荐关系表") + @PutMapping() + public ApiResult update(@RequestBody ShopUserReferee shopUserReferee) { + if (shopUserRefereeService.updateById(shopUserReferee)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserReferee:remove')") + @OperationLog + @Operation(summary = "删除用户推荐关系表") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopUserRefereeService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserReferee:save')") + @OperationLog + @Operation(summary = "批量添加用户推荐关系表") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopUserRefereeService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserReferee:update')") + @OperationLog + @Operation(summary = "批量修改用户推荐关系表") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopUserRefereeService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @PreAuthorize("hasAuthority('shop:shopUserReferee:remove')") + @OperationLog + @Operation(summary = "批量删除用户推荐关系表") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopUserRefereeService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopWechatDepositController.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopWechatDepositController.java new file mode 100644 index 0000000..7c29f20 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/controller/ShopWechatDepositController.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopWechatDepositService; +import com.gxwebsoft.shop.entity.ShopWechatDeposit; +import com.gxwebsoft.shop.param.ShopWechatDepositParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 押金控制器 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Tag(name = "押金管理") +@RestController +@RequestMapping("/api/shop/shop-wechat-deposit") +public class ShopWechatDepositController extends BaseController { + @Resource + private ShopWechatDepositService shopWechatDepositService; + + @Operation(summary = "分页查询押金") + @GetMapping("/page") + public ApiResult> page(ShopWechatDepositParam param) { + // 使用关联查询 + return success(shopWechatDepositService.pageRel(param)); + } + + @Operation(summary = "查询全部押金") + @GetMapping() + public ApiResult> list(ShopWechatDepositParam param) { + // 使用关联查询 + return success(shopWechatDepositService.listRel(param)); + } + + @PreAuthorize("hasAuthority('shop:shopWechatDeposit:list')") + @Operation(summary = "根据id查询押金") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopWechatDepositService.getByIdRel(id)); + } + + @Operation(summary = "添加押金") + @PostMapping() + public ApiResult save(@RequestBody ShopWechatDeposit shopWechatDeposit) { + if (shopWechatDepositService.save(shopWechatDeposit)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "修改押金") + @PutMapping() + public ApiResult update(@RequestBody ShopWechatDeposit shopWechatDeposit) { + if (shopWechatDepositService.updateById(shopWechatDeposit)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "删除押金") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopWechatDepositService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量添加押金") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopWechatDepositService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @Operation(summary = "批量修改押金") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopWechatDepositService, "id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @Operation(summary = "批量删除押金") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopWechatDepositService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java new file mode 100644 index 0000000..6750da1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java @@ -0,0 +1,176 @@ +package com.gxwebsoft.shop.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.math.BigDecimal; +import java.util.List; + +/** + * 订单创建请求DTO + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Data +@Schema(name = "OrderCreateRequest", description = "订单创建请求") +public class OrderCreateRequest { + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "订单类型,0商城订单 1预定订单/外卖 2会员卡") + @NotNull(message = "订单类型不能为空") + @Min(value = 0, message = "订单类型值无效") + @Max(value = 2, message = "订单类型值无效") + private Integer type; + + @Size(max = 60, message = "备注长度不能超过60个字符") + @Schema(description = "订单标题") + private String title; + + @Schema(description = "快递/自提") + private Integer deliveryType; + + @Schema(description = "下单渠道,0小程序预定 1俱乐部训练场 3活动订场") + private Integer channel; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户编号") + private String merchantCode; + + @Schema(description = "使用的优惠券id") + private Integer couponId; + + @Schema(description = "使用的会员卡id") + private String cardId; + + @Schema(description = "关联收货地址") + private Integer addressId; + + @Schema(description = "收货地址") + private String address; + + @Schema(description = "收货人姓名") + private String realName; + + @Schema(description = "地址纬度") + private String addressLat; + + @Schema(description = "地址经度") + private String addressLng; + + @Schema(description = "自提店铺id") + private Integer selfTakeMerchantId; + + @Schema(description = "自提店铺") + private String selfTakeMerchantName; + + @Schema(description = "配送开始时间") + private String sendStartTime; + + @Schema(description = "配送结束时间") + private String sendEndTime; + + @Schema(description = "发货店铺id") + private Integer expressMerchantId; + + @Schema(description = "发货店铺") + private String expressMerchantName; + + @Schema(description = "订单总额") + @NotNull(message = "订单总额不能为空") + @DecimalMin(value = "0.01", message = "订单总额必须大于0") + @Digits(integer = 10, fraction = 2, message = "订单总额格式不正确") + private BigDecimal totalPrice; + + @Schema(description = "减少的金额,使用VIP会员折扣、优惠券抵扣、优惠券折扣后减去的价格") + @DecimalMin(value = "0", message = "减少金额不能为负数") + private BigDecimal reducePrice; + + @Schema(description = "实际付款") + @DecimalMin(value = "0", message = "实际付款不能为负数") + private BigDecimal payPrice; + + @Schema(description = "用于统计") + private BigDecimal price; + + @Schema(description = "价钱,用于积分赠送") + private BigDecimal money; + + @Schema(description = "教练价格") + private BigDecimal coachPrice; + + @Schema(description = "购买数量") + @Min(value = 1, message = "购买数量必须大于0") + private Integer totalNum; + + @Schema(description = "教练id") + private Integer coachId; + + @Schema(description = "来源ID,存商品ID") + private Integer formId; + + @Schema(description = "支付类型,0余额支付, 1微信支付,102微信Native,2会员卡支付,3支付宝,4现金,5POS机,6VIP月卡,7VIP年卡,8VIP次卡,9IC月卡,10IC年卡,11IC次卡,12免费,13VIP充值卡,14IC充值卡,15积分支付,16VIP季卡,17IC季卡,18代付") + private Integer payType; + + @Schema(description = "代付支付方式") + private Integer friendPayType; + + @Schema(description = "优惠类型:0无、1抵扣优惠券、2折扣优惠券、3、VIP月卡、4VIP年卡,5VIP次卡、6VIP会员卡、7IC月卡、8IC年卡、9IC次卡、10IC会员卡、11免费订单、12VIP充值卡、13IC充值卡、14VIP季卡、15IC季卡") + private Integer couponType; + + @Schema(description = "优惠说明") + private String couponDesc; + + @Schema(description = "预约详情开始时间数组") + private String startTime; + + @Schema(description = "备注") + @Size(max = 500, message = "备注长度不能超过500字符") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + @NotNull(message = "租户ID不能为空") + private Integer tenantId; + + @Schema(description = "订单商品列表") + @Valid + @NotEmpty(message = "订单商品列表不能为空") + private List goodsItems; + + /** + * 订单商品项 + */ + @Data + @Schema(name = "OrderGoodsItem", description = "订单商品项") + public static class OrderGoodsItem { + @Schema(description = "商品ID", required = true) + @NotNull(message = "商品ID不能为空") + private Integer goodsId; + + @Schema(description = "商品SKU ID") + private Integer skuId; + + @Schema(description = "商品数量", required = true) + @NotNull(message = "商品数量不能为空") + @Min(value = 1, message = "商品数量必须大于0") + private Integer quantity; + + @Schema(description = "支付类型") + private Integer payType; + + @Schema(description = "规格信息,如:颜色:红色|尺寸:L") + private String specInfo; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/dto/UpdatePaymentStatusRequest.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/dto/UpdatePaymentStatusRequest.java new file mode 100644 index 0000000..999b0a8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/dto/UpdatePaymentStatusRequest.java @@ -0,0 +1,32 @@ +package com.gxwebsoft.shop.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 更新订单支付状态请求DTO + * + * @author 科技小王子 + * @since 2025-08-30 + */ +@Data +@Schema(name = "UpdatePaymentStatusRequest", description = "更新订单支付状态请求") +public class UpdatePaymentStatusRequest { + + @Schema(description = "订单号", required = true) + @NotBlank(message = "订单号不能为空") + private String orderNo; + + @Schema(description = "支付状态:1=支付成功,0=支付失败", required = true) + @NotNull(message = "支付状态不能为空") + private Integer paymentStatus; + + @Schema(description = "微信交易号") + private String transactionId; + + @Schema(description = "支付时间,格式:yyyy-MM-dd HH:mm:ss") + private String payTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/KuaiDi100Resp.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/KuaiDi100Resp.java new file mode 100644 index 0000000..c1348ad --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/KuaiDi100Resp.java @@ -0,0 +1,11 @@ +package com.gxwebsoft.shop.entity; + +import lombok.Data; + +@Data +public class KuaiDi100Resp { + private String message; + private Integer returnCode; + private Boolean result; + private Object data; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java new file mode 100644 index 0000000..a11ff60 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java @@ -0,0 +1,189 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品文章 + * + * @author 科技小王子 + * @since 2025-08-13 05:14:53 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopArticle对象", description = "商品文章") +public class ShopArticle implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章ID") + @TableId(value = "article_id", type = IdType.AUTO) + private Integer articleId; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章类型 0常规 1视频") + private Integer type; + + @Schema(description = "模型") + private String model; + + @Schema(description = "详情页模板") + private String detail; + + @Schema(description = "文章分类ID") + private Integer categoryId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "话题") + private String topic; + + @Schema(description = "标签") + private String tags; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "封面图宽") + private Integer imageWidth; + + @Schema(description = "封面图高") + private Integer imageHeight; + + @Schema(description = "付费金额") + private BigDecimal price; + + @Schema(description = "开始时间") + private LocalDateTime startTime; + + @Schema(description = "结束时间") + private LocalDateTime endTime; + + @Schema(description = "来源") + private String source; + + @Schema(description = "产品概述") + private String overview; + + @Schema(description = "虚拟阅读量(仅用作展示)") + private Integer virtualViews; + + @Schema(description = "实际阅读量") + private Integer actualViews; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + private Integer showType; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + private Integer permission; + + @Schema(description = "发布来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "文章附件") + private String files; + + @Schema(description = "视频地址") + private String video; + + @Schema(description = "接受的文件类型") + private String accept; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "点赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "提醒谁看") + private String toUsers; + + @Schema(description = "作者") + private String author; + + @Schema(description = "推荐") + private Integer recommend; + + @Schema(description = "报名人数") + private Integer bmUsers; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "项目ID") + private Integer projectId; + + @Schema(description = "语言") + private String lang; + + @Schema(description = "关联默认语言的文章ID") + private Integer langArticleId; + + @Schema(description = "是否自动翻译") + private Boolean translation; + + @Schema(description = "编辑器类型 0 Markdown编辑器 1 富文本编辑器 ") + private Boolean editor; + + @Schema(description = "pdf文件地址") + private String pdfUrl; + + @Schema(description = "版本号") + private Integer version; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopBrand.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopBrand.java new file mode 100644 index 0000000..96a3c21 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopBrand.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 品牌 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopBrand对象", description = "品牌") +public class ShopBrand implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "brand_id", type = IdType.AUTO) + private Integer brandId; + + @Schema(description = "品牌名称") + private String brandName; + + @Schema(description = "图标") + private String image; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCart.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCart.java new file mode 100644 index 0000000..b3139e9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCart.java @@ -0,0 +1,94 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 购物车 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopCart对象", description = "购物车") +public class ShopCart implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "购物车表ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "类型 0商城 1外卖") + private Integer type; + + @Schema(description = "唯一标识") + private String code; + + @Schema(description = "商品ID") + private Long goodsId; + + @Schema(description = "商品SKU ID") + private Integer skuId; + + @Schema(description = "商品规格") + private String spec; + + @Schema(description = "规格信息,如:颜色:红色|尺寸:L") + private String specInfo; + + @Schema(description = "商品价格") + private BigDecimal price; + + @Schema(description = "商品数量") + private Integer cartNum; + + @Schema(description = "单商品合计") + private BigDecimal totalPrice; + + @Schema(description = "0 = 未购买 1 = 已购买") + private Boolean isPay; + + @Schema(description = "是否为立即购买") + private Boolean isNew; + + @Schema(description = "是否为立即购买") + private Boolean isShow; + + @Schema(description = "拼团id") + private Integer combinationId; + + @Schema(description = "秒杀产品ID") + private Integer seckillId; + + @Schema(description = "砍价id") + private Integer bargainId; + + @Schema(description = "是否选中") + private Boolean selected; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCategory.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCategory.java new file mode 100644 index 0000000..8eff0b5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCategory.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品分类 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopCategory对象", description = "商品分类") +public class ShopCategory implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "模型") + private String model; + + @Schema(description = "标识") + private String code; + + @Schema(description = "链接地址") + private String path; + + @Schema(description = "组件地址") + private String component; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "banner") + private String banner; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + private Integer hide; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + private Integer permission; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "位置 0不限 1顶部 2底部") + private Integer position; + + @Schema(description = "仅在顶部显示") + private Integer top; + + @Schema(description = "仅在底部显示") + private Integer bottom; + + @Schema(description = "菜单选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "css样式") + private String style; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "语言") + private String lang; + + @Schema(description = "设为首页") + private Integer home; + + @Schema(description = "推荐") + private Integer recommend; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopChatConversation.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopChatConversation.java new file mode 100644 index 0000000..bddc6a6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopChatConversation.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 聊天消息表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopChatConversation对象", description = "聊天消息表") +public class ShopChatConversation implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "好友ID") + private Integer friendId; + + @Schema(description = "消息类型") + private Integer type; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "未读消息") + private Integer unRead; + + @Schema(description = "状态, 0未读, 1已读") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopChatMessage.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopChatMessage.java new file mode 100644 index 0000000..e212e04 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopChatMessage.java @@ -0,0 +1,110 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 聊天消息表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopChatMessage对象", description = "聊天消息表") +public class ShopChatMessage implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "发送人ID") + private Integer formUserId; + + @Schema(description = "发送人名称") + @TableField(exist = false) + private String formUserName; + + @Schema(description = "发送人头像") + @TableField(exist = false) + private String formUserAvatar; + + @Schema(description = "发送人手机号码") + @TableField(exist = false) + private String formUserPhone; + + @Schema(description = "发送人别名") + @TableField(exist = false) + private String formUserAlias; + + @Schema(description = "接收人ID") + private Integer toUserId; + + @Schema(description = "接收人名称") + @TableField(exist = false) + private String toUserName; + + @Schema(description = "接收人头像") + @TableField(exist = false) + private String toUserAvatar; + + @Schema(description = "接收人手机号码") + @TableField(exist = false) + private String toUserPhone; + + @Schema(description = "接收人别名") + @TableField(exist = false) + private String toUserAlias; + + @Schema(description = "消息类型") + private String type; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "屏蔽接收方") + private Integer sideTo; + + @Schema(description = "屏蔽发送方") + private Integer sideFrom; + + @Schema(description = "是否撤回") + private Integer withdraw; + + @Schema(description = "文件信息") + private String fileInfo; + + @Schema(description = "存在联系方式") + private Integer hasContact; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "状态, 0未读, 1已读") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCommissionRole.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCommissionRole.java new file mode 100644 index 0000000..cdf33b5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCommissionRole.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分红角色 + * + * @author 科技小王子 + * @since 2025-05-01 10:01:15 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopCommissionRole对象", description = "分红角色") +public class ShopCommissionRole implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private String title; + + private Integer provinceId; + + private Integer cityId; + + private Integer regionId; + + @Schema(description = "状态, 0正常, 1异常") + private Integer status; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCount.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCount.java new file mode 100644 index 0000000..454b8c2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCount.java @@ -0,0 +1,64 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDate; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商城销售统计表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopCount对象", description = "商城销售统计表") +public class ShopCount implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "统计日期") + private LocalDate dateTime; + + @Schema(description = "总销售额") + private BigDecimal totalPrice; + + @Schema(description = "今日销售额") + private BigDecimal todayPrice; + + @Schema(description = "总会员数") + private BigDecimal totalUsers; + + @Schema(description = "今日新增") + private BigDecimal todayUsers; + + @Schema(description = "总订单笔数") + private BigDecimal totalOrders; + + @Schema(description = "今日订单笔数") + private BigDecimal todayOrders; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCoupon.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCoupon.java new file mode 100644 index 0000000..fae4872 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCoupon.java @@ -0,0 +1,136 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDate; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 优惠券 + * + * @author 科技小王子 + * @since 2025-08-11 09:41:38 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopCoupon对象", description = "优惠券") +public class ShopCoupon implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券描述") + private String description; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + private Integer type; + + @Schema(description = "满减券-减免金额") + @JsonSerialize(using = ToStringSerializer.class) + @JsonInclude(JsonInclude.Include.NON_NULL) + private BigDecimal reducePrice; + + @Schema(description = "折扣券-折扣率(0-100)") + private Integer discount; + + @Schema(description = "最低消费金额") + @JsonSerialize(using = ToStringSerializer.class) + @JsonInclude(JsonInclude.Include.NON_NULL) + private BigDecimal minPrice; + + @Schema(description = "到期类型(10领取后生效 20固定时间)") + private Integer expireType; + + @Schema(description = "领取后生效-有效天数") + private Integer expireDay; + + @Schema(description = "有效期开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime startTime; + + @Schema(description = "有效期结束时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime endTime; + + @Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)") + private Integer applyRange; + + @Schema(description = "适用范围配置(json格式)") + private String applyRangeConfig; + + @Schema(description = "是否过期(0未过期 1已过期)") + private Integer isExpire; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1禁用") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "发放总数量(-1表示无限制)") + private Integer totalCount; + + @Schema(description = "已发放数量") + private Integer issuedCount; + + @Schema(description = "每人限领数量(-1表示无限制)") + private Integer limitPerUser; + + @Schema(description = "是否启用(0禁用 1启用)") + private Boolean enabled; + + @TableField(exist = false) + private List couponApplyItemList; + + @TableField(exist = false) + private List couponApplyCateList; + + @TableField(exist = false) + private Boolean hasTake; + + @TableField(exist = false) + private Integer userTakeNum; + + @TableField(exist = false) + private Integer userUseNum; + + @TableField(exist = false) + private Integer receiveNum; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCouponApplyCate.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCouponApplyCate.java new file mode 100644 index 0000000..26bf30c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCouponApplyCate.java @@ -0,0 +1,53 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 优惠券可用分类 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopCouponApplyCate对象", description = "优惠券可用分类") +public class ShopCouponApplyCate implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private Integer couponId; + + private Integer cateId; + + @Schema(description = "分类等级") + private Integer cateLevel; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCouponApplyItem.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCouponApplyItem.java new file mode 100644 index 0000000..504d9d7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopCouponApplyItem.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 优惠券可用分类 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopCouponApplyItem对象", description = "优惠券可用分类") +public class ShopCouponApplyItem implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "优惠券ID") + private Integer couponId; + + @Schema(description = "商品ID") + private Integer goodsId; + + @Schema(description = "分类ID") + private Integer categoryId; + + @Schema(description = "类型(1商品 2分类)") + private Integer type; + + @Schema(description = "0服务1需求2闲置") + private Integer pk; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerApply.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerApply.java new file mode 100644 index 0000000..ca0c9bb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerApply.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商申请记录表 + * + * @author 科技小王子 + * @since 2025-08-11 23:50:18 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerApply对象", description = "分销商申请记录表") +public class ShopDealerApply implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "apply_id", type = IdType.AUTO) + private Integer applyId; + + @Schema(description = "0经销商,1企业也,2集团)") + private Integer type; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickName; + + @Schema(description = "手机号码") + @TableField(exist = false) + private String phone; + + @Schema(description = "姓名") + private String realName; + + @Schema(description = "分销商名称") + private String dealerName; + + @Schema(description = "分销商编码") + private String dealerCode; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "合同金额") + private BigDecimal money; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "佣金比例") + @TableField(exist = false) + private BigDecimal rate; + + @Schema(description = "推荐人用户ID") + private Integer refereeId; + + @Schema(description = "申请方式(10需后台审核 20无需审核)") + private Integer applyType; + + @Schema(description = "申请时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime applyTime; + + @Schema(description = "审核状态 (10待审核 20审核通过 30驳回)") + private Integer applyStatus; + + @Schema(description = "审核时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime auditTime; + + @Schema(description = "合同时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime contractTime; + + @Schema(description = "到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime expirationTime; + + @Schema(description = "驳回原因") + private String rejectReason; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "商城ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "推荐人名称") + @TableField(exist = false) + private String refereeName; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerBank.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerBank.java new file mode 100644 index 0000000..eded8a3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerBank.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 分销商提现银行卡 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerBank对象", description = "分销商提现银行卡") +public class ShopDealerBank implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "分销商用户ID") + private Integer userId; + + @Schema(description = "开户行名称") + private String bankName; + + @Schema(description = "银行开户名") + private String bankAccount; + + @Schema(description = "银行卡号") + private String bankCard; + + @Schema(description = "申请状态 (10待审核 20审核通过 30驳回)") + private Integer applyStatus; + + @Schema(description = "驳回原因") + private String rejectReason; + + @Schema(description = "默认收货地址") + private Boolean isDefault; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerCapital.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerCapital.java new file mode 100644 index 0000000..00562e4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerCapital.java @@ -0,0 +1,66 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商资金明细表 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerCapital对象", description = "分销商资金明细表") +public class ShopDealerCapital implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "分销商用户ID") + private Integer userId; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "资金流动类型 (10佣金收入 20提现支出 30转账支出 40转账收入)") + private Integer flowType; + + @Schema(description = "金额") + private BigDecimal money; + + @Schema(description = "描述") + private String comments; + + @Schema(description = "对方用户ID") + private Integer toUserId; + + @Schema(description = "对方昵称") + @TableField(exist = false) + private String toNickName; + + @Schema(description = "结算月份") + private String month; + + @Schema(description = "商城ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java new file mode 100644 index 0000000..81f3732 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商订单记录表 + * + * @author 科技小王子 + * @since 2025-08-12 11:55:18 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerOrder对象", description = "分销商订单记录表") +public class ShopDealerOrder implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "买家用户ID") + private Integer userId; + + @Excel(name = "公司名称") + private String title; + + @Excel(name = "订单编号") + private String orderNo; + + @Schema(description = "买家用户昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "订单总金额(不含运费)") + private BigDecimal orderPrice; + + @Schema(description = "结算金额") + private BigDecimal settledPrice; + + @Schema(description = "换算成度") + private BigDecimal degreePrice; + + @Schema(description = "实发金额") + private BigDecimal payPrice; + + @Schema(description = "分销商用户id(一级)") + private Integer firstUserId; + + @Schema(description = "分销商用户昵称(一级)") + @TableField(exist = false) + private String firstNickname; + + @Schema(description = "分销商用户id(二级)") + private Integer secondUserId; + + @Schema(description = "分销商用户昵称(二级)") + @TableField(exist = false) + private String secondNickname; + + @Schema(description = "分销商用户id(三级)") + private Integer thirdUserId; + + @Schema(description = "分销商用户昵称(三级)") + @TableField(exist = false) + private String thirdNickname; + + @Schema(description = "分销佣金(一级)") + private BigDecimal firstMoney; + + @Schema(description = "分销佣金(二级)") + private BigDecimal secondMoney; + + @Schema(description = "分销佣金(三级)") + private BigDecimal thirdMoney; + + @Schema(description = "佣金比例") + private BigDecimal rate; + + @Schema(description = "单价") + private BigDecimal price; + + @Schema(description = "结算月份") + private String month; + + @Schema(description = "订单是否失效(0未失效 1已失效)") + private Integer isInvalid; + + @Schema(description = "佣金结算(0未结算 1已结算)") + private Integer isSettled; + + @Schema(description = "结算时间") + private LocalDateTime settleTime; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "商城ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerRecord.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerRecord.java new file mode 100644 index 0000000..3780cda --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerRecord.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 客户跟进情况 + * + * @author 科技小王子 + * @since 2025-10-02 12:21:50 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "客户跟进情况") +public class ShopDealerRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "客户ID") + private Integer dealerId; + + @Schema(description = "内容") + private String content; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0待处理, 1已完成") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerReferee.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerReferee.java new file mode 100644 index 0000000..35de39a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerReferee.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商推荐关系表 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerReferee对象", description = "分销商推荐关系表") +public class ShopDealerReferee implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "分销商用户ID") + private Integer dealerId; + + @Schema(description = "分销商名称") + @TableField(exist = false) + private String dealerName; + + @Schema(description = "分销商头像") + @TableField(exist = false) + private String dealerAvatar; + + @Schema(description = "分销商手机号") + @TableField(exist = false) + private String dealerPhone; + + @Schema(description = "用户id(被推荐人)") + private Integer userId; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "别名") + @TableField(exist = false) + private String alias; + + @Schema(description = "手机号") + @TableField(exist = false) + private String phone; + + @Schema(description = "是否管理员") + @TableField(exist = false) + private Boolean isAdmin; + + @Schema(description = "推荐关系层级(1,2,3)") + private Integer level; + + @Schema(description = "商城ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerSetting.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerSetting.java new file mode 100644 index 0000000..fd1b2ad --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerSetting.java @@ -0,0 +1,38 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商设置表 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerSetting对象", description = "分销商设置表") +public class ShopDealerSetting implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "设置项标示") + @TableId(value = "key", type = IdType.AUTO) + private String key; + + @Schema(description = "设置项描述") + private String describe; + + @Schema(description = "设置内容(json格式)") + private String values; + + @Schema(description = "商城ID") + private Integer tenantId; + + @Schema(description = "更新时间") + private Integer updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerUser.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerUser.java new file mode 100644 index 0000000..86bd84e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerUser.java @@ -0,0 +1,99 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商用户记录表 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerUser对象", description = "分销商用户记录表") +public class ShopDealerUser implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "0经销商,1企业也,2集团)") + private Integer type; + + @Schema(description = "自增ID") + private Integer userId; + + @Schema(description = "微信openid") + @TableField(exist = false) + private String openid; + + @Schema(description = "姓名") + private String realName; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "支付密码") + private String payPassword; + + @Schema(description = "当前可提现佣金") + private BigDecimal money; + + @Schema(description = "已冻结佣金") + private BigDecimal freezeMoney; + + @Schema(description = "累积提现佣金") + private BigDecimal totalMoney; + + @Schema(description = "单价") + private BigDecimal price; + + @Schema(description = "佣金比例") + private BigDecimal rate; + + @Schema(description = "推荐人用户ID") + private Integer refereeId; + + @Schema(description = "成员数量(一级)") + private Integer firstNum; + + @Schema(description = "成员数量(二级)") + private Integer secondNum; + + @Schema(description = "成员数量(三级)") + private Integer thirdNum; + + @Schema(description = "专属二维码") + private String qrcode; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除") + private Integer isDelete; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerWithdraw.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerWithdraw.java new file mode 100644 index 0000000..6289926 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopDealerWithdraw.java @@ -0,0 +1,108 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商提现明细表 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopDealerWithdraw对象", description = "分销商提现明细表") +public class ShopDealerWithdraw implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "分销商用户ID") + private Integer userId; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickName; + + @Schema(description = "头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "手机号") + @TableField(exist = false) + private String phone; + + @Schema(description = "真实姓名") + @TableField(exist = false) + private String realName; + + @Schema(description = "提现金额") + private BigDecimal money; + + @Schema(description = "打款方式 (10微信 20支付宝 30银行卡)") + private Integer payType; + + @Schema(description = "支付宝姓名") + private String alipayName; + + @Schema(description = "支付宝账号") + private String alipayAccount; + + @Schema(description = "开户行名称") + private String bankName; + + @Schema(description = "银行开户名") + private String bankAccount; + + @Schema(description = "银行卡号") + private String bankCard; + + @Schema(description = "申请状态 (10待审核 20审核通过 30驳回 40已打款)") + private Integer applyStatus; + + @Schema(description = "审核时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime auditTime; + + @Schema(description = "驳回原因") + private String rejectReason; + + @Schema(description = "上传支付凭证") + private String image; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "来源客户端(APP、H5、小程序等)") + private String platform; + + @Schema(description = "微信openId") + @TableField(exist = false) + private String openId; + + @Schema(description = "公众号openId") + @TableField(exist = false) + private String officeOpenid; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpress.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpress.java new file mode 100644 index 0000000..9f0c5fe --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpress.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 物流公司 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopExpress对象", description = "物流公司") +public class ShopExpress implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "物流公司ID") + @TableId(value = "express_id", type = IdType.AUTO) + private Integer expressId; + + @Schema(description = "物流公司名称") + private String expressName; + + @Schema(description = "物流公司编码 (微信)") + private String wxCode; + + @Schema(description = "物流公司编码 (快递100)") + private String kuaidi100Code; + + @Schema(description = "物流公司编码 (快递鸟)") + private String kdniaoCode; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpressTemplate.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpressTemplate.java new file mode 100644 index 0000000..1f5b8fa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpressTemplate.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 运费模板 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopExpressTemplate对象", description = "运费模板") +public class ShopExpressTemplate implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private Boolean type; + + private String title; + + @Schema(description = "收件价格") + private BigDecimal firstAmount; + + @Schema(description = "续件价格") + private BigDecimal extraAmount; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + private Integer sortNumber; + + @Schema(description = "首件数量/重量") + private BigDecimal firstNum; + + @Schema(description = "续件数量/重量") + private BigDecimal extraNum; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpressTemplateDetail.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpressTemplateDetail.java new file mode 100644 index 0000000..7d8d3ec --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopExpressTemplateDetail.java @@ -0,0 +1,70 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 运费模板 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopExpressTemplateDetail对象", description = "运费模板") +public class ShopExpressTemplateDetail implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private Integer templateId; + + @Schema(description = "0按件") + private Boolean type; + + private Integer provinceId; + + private Integer cityId; + + @Schema(description = "首件数量/重量") + private BigDecimal firstNum; + + @Schema(description = "收件价格") + private BigDecimal firstAmount; + + @Schema(description = "续件价格") + private BigDecimal extraAmount; + + @Schema(description = "续件数量/重量") + private BigDecimal extraNum; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGift.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGift.java new file mode 100644 index 0000000..261c980 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGift.java @@ -0,0 +1,112 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 礼品卡 + * + * @author 科技小王子 + * @since 2025-08-11 18:07:31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGift对象", description = "礼品卡") +public class ShopGift implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "礼品卡名称") + private String name; + + @Schema(description = "秘钥") + private String code; + + @Schema(description = "商品ID") + private Integer goodsId; + + @Schema(description = "商品名称") + @TableField(exist = false) + private String goodsName; + + @Schema(description = "商品图片") + @TableField(exist = false) + private String goodsImage; + + @Schema(description = "面值") + @TableField(exist = false) + private BigDecimal faceValue; + + @Schema(description = "使用地点") + private String useLocation; + + @Schema(description = "领取时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime takeTime; + + @Schema(description = "核销时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime verificationTime; + + @Schema(description = "操作人ID") + private Integer operatorUserId; + + @Schema(description = "操作人") + @TableField(exist = false) + private String operatorUserName; + + @Schema(description = "操作备注") + private String operatorRemarks; + + @Schema(description = "是否展示") + private Boolean isShow; + + @Schema(description = "状态, 0上架 1待上架 2待审核 3审核不通过") + private Integer status; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickName; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @TableField(exist = false) + private Integer num; + + @TableField(exist = false) + private ShopGoods goods; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoods.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoods.java new file mode 100644 index 0000000..2cfae1d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoods.java @@ -0,0 +1,146 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoods对象", description = "商品") +public class ShopGoods implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "goods_id", type = IdType.AUTO) + private Integer goodsId; + + @Schema(description = "商品名称") + private String name; + + @Schema(description = "产品编码") + private String code; + + @Schema(description = "类型 0软件产品 1实物商品 2虚拟商品") + private Integer type; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "父级分类ID") + private Integer parentId; + + @Schema(description = "产品分类ID") + private Integer categoryId; + + @Schema(description = "路由地址") + private String path; + + @Schema(description = "标签") + private String tag; + + @Schema(description = "产品规格 0单规格 1多规格") + private Integer specs; + + @Schema(description = "货架") + private String position; + + @Schema(description = "单位名称 (个)") + private String unitName; + + @Schema(description = "商品价格") + private BigDecimal price; + + @Schema(description = "进货价格") + private BigDecimal buyingPrice; + + @Schema(description = "经销商价格") + private BigDecimal dealerPrice; + + @Schema(description = "市场价") + private BigDecimal salePrice; + + @Schema(description = "佣金") + private BigDecimal commission; + + @Schema(description = "库存计算方式(10下单减库存 20付款减库存)") + private Integer deductStockType; + + @Schema(description = "交付方式(0不启用)") + private Integer deliveryMethod; + + @Schema(description = "购买时长(0不启用,1 一次性,2 按时长)") + private Integer durationMethod; + + @Schema(description = "可购买数量") + private Integer canBuyNumber; + + @Schema(description = "商品详情") + private String content; + + @Schema(description = "轮播图") + private String files; + + @Schema(description = "销量") + private Integer sales; + + @Schema(description = "库存") + private Integer stock; + + @Schema(description = "安装次数") + private Integer install; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "消费赚取积分") + private BigDecimal gainIntegral; + + @Schema(description = "推荐") + private Integer recommend; + + @Schema(description = "是否官方") + private Integer official; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "是否展示") + private Boolean isShow; + + @Schema(description = "状态, 0上架 1待上架 2待审核 3审核不通过") + private Integer status; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsCategory.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsCategory.java new file mode 100644 index 0000000..ff721bd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsCategory.java @@ -0,0 +1,95 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品分类 + * + * @author 科技小王子 + * @since 2025-05-01 00:36:45 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsCategory对象", description = "商品分类") +public class ShopGoodsCategory implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "商品分类ID") + @TableId(value = "category_id", type = IdType.AUTO) + private Integer categoryId; + + @Schema(description = "分类标识") + private String categoryCode; + + @Schema(description = "分类名称") + private String title; + + @Schema(description = "类型 0商城分类 1外卖分类") + private Integer type; + + @Schema(description = "分类图片") + private String image; + + @Schema(description = "上级分类ID") + private Integer parentId; + + @Schema(description = "路由/链接地址") + private String path; + + @Schema(description = "组件路径") + private String component; + + @Schema(description = "绑定的页面") + private Integer pageId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "商品数量") + private Integer count; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + private Integer hide; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否显示在首页") + private Integer showIndex; + + @Schema(description = "商铺ID") + private Long merchantId; + + @Schema(description = "状态, 0正常, 1禁用") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsComment.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsComment.java new file mode 100644 index 0000000..2a9a56e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsComment.java @@ -0,0 +1,98 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 评论表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsComment对象", description = "评论表") +public class ShopGoodsComment implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "评论ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户ID") + private Integer uid; + + @Schema(description = "订单ID") + private Integer oid; + + @Schema(description = "商品唯一id") + private String unique; + + @Schema(description = "商品id") + private Integer goodsId; + + @Schema(description = "某种商品类型(普通商品、秒杀商品)") + private String replyType; + + @Schema(description = "商品分数") + private Boolean goodsScore; + + @Schema(description = "服务分数") + private Boolean serviceScore; + + @Schema(description = "评论内容") + private String comment; + + @Schema(description = "评论图片") + private String pics; + + @Schema(description = "管理员回复内容") + private String merchantReplyContent; + + @Schema(description = "管理员回复时间") + private Integer merchantReplyTime; + + @Schema(description = "0未删除1已删除") + private Boolean isDel; + + @Schema(description = "0未回复1已回复") + private Boolean isReply; + + @Schema(description = "用户名称") + private String nickname; + + @Schema(description = "用户头像") + private String avatar; + + @Schema(description = "商品规格属性值,多个,号隔开") + private String sku; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsIncomeConfig.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsIncomeConfig.java new file mode 100644 index 0000000..dec1307 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsIncomeConfig.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分润配置 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsIncomeConfig对象", description = "分润配置") +public class ShopGoodsIncomeConfig implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private Integer goodsId; + + @Schema(description = "店铺类型") + private String merchantShopType; + + private Integer skuId; + + @Schema(description = "比例") + private BigDecimal rate; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsLog.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsLog.java new file mode 100644 index 0000000..9faf9ae --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsLog.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品日志表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsLog对象", description = "商品日志表") +public class ShopGoodsLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "统计ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "类型visit,cart,order,pay,collect,refund") + private String type; + + @Schema(description = "商品ID") + private Integer goodsId; + + @Schema(description = "是否浏览") + private Boolean visitNum; + + @Schema(description = "加入购物车数量") + private Integer cartNum; + + @Schema(description = "下单数量") + private Integer orderNum; + + @Schema(description = "支付数量") + private Integer payNum; + + @Schema(description = "支付金额") + private BigDecimal payPrice; + + @Schema(description = "商品成本价") + private BigDecimal costPrice; + + @Schema(description = "支付用户ID") + private Integer payUid; + + @Schema(description = "退款数量") + private Integer refundNum; + + @Schema(description = "退款金额") + private BigDecimal refundPrice; + + @Schema(description = "收藏") + private Boolean collectNum; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsRelation.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsRelation.java new file mode 100644 index 0000000..581cac0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsRelation.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品点赞和收藏表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsRelation对象", description = "商品点赞和收藏表") +public class ShopGoodsRelation implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "商品ID") + private Integer goodsId; + + @Schema(description = "类型(收藏(collect)、点赞(like))") + private String type; + + @Schema(description = "某种类型的商品(普通商品、秒杀商品)") + private String category; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsRoleCommission.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsRoleCommission.java new file mode 100644 index 0000000..61aa957 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsRoleCommission.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品绑定角色的分润金额 + * + * @author 科技小王子 + * @since 2025-05-01 09:53:38 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsRoleCommission对象", description = "商品绑定角色的分润金额") +public class ShopGoodsRoleCommission implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private Integer roleId; + + private Integer goodsId; + + private String sku; + + private BigDecimal amount; + + @Schema(description = "状态, 0正常, 1异常") + private Integer status; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsSku.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsSku.java new file mode 100644 index 0000000..7a7682f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsSku.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品sku列表 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsSku对象", description = "商品sku列表") +public class ShopGoodsSku implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "商品ID") + private Integer goodsId; + + @Schema(description = "商品属性索引值 (attr_value|attr_value[|....])") + private String sku; + + @Schema(description = "商品图片") + private String image; + + @Schema(description = "商品价格") + private BigDecimal price; + + @Schema(description = "市场价格") + private BigDecimal salePrice; + + @Schema(description = "成本价") + private BigDecimal cost; + + @Schema(description = "库存") + private Integer stock; + + @Schema(description = "sku编码") + private String skuNo; + + @Schema(description = "商品条码") + private String barCode; + + @Schema(description = "重量") + private BigDecimal weight; + + @Schema(description = "体积") + private BigDecimal volume; + + @Schema(description = "唯一值") + private String uuid; + + @Schema(description = "状态, 0正常, 1异常") + private Integer status; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsSpec.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsSpec.java new file mode 100644 index 0000000..b1a16df --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopGoodsSpec.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品多规格 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopGoodsSpec对象", description = "商品多规格") +public class ShopGoodsSpec implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "商品ID") + private Integer goodsId; + + @Schema(description = "规格ID") + private Integer specId; + + @Schema(description = "规格名称") + private String specName; + + @Schema(description = "规格值") + private String specValue; + + @Schema(description = "活动类型 0=商品,1=秒杀,2=砍价,3=拼团") + private Boolean type; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchant.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchant.java new file mode 100644 index 0000000..1915909 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchant.java @@ -0,0 +1,145 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户 + * + * @author 科技小王子 + * @since 2025-08-10 20:43:33 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopMerchant对象", description = "商户") +public class ShopMerchant implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "merchant_id", type = IdType.AUTO) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户编号") + private String merchantCode; + + @Schema(description = "商户类型") + private Integer type; + + @Schema(description = "商户图标") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "项目分类") + private String itemType; + + @Schema(description = "商户分类") + private String category; + + @Schema(description = "商户经营分类") + private Integer merchantCategoryId; + + @Schema(description = "商户分类") + private String merchantCategoryTitle; + + @Schema(description = "经纬度") + private String lngAndLat; + + private String lng; + + private String lat; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "手续费") + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "营业时间") + private String businessTime; + + @Schema(description = "文章内容") + private String content; + + @Schema(description = "每小时价格") + private BigDecimal price; + + @Schema(description = "是否自营") + private Integer ownStore; + + @Schema(description = "是否可以快递") + private Boolean canExpress; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否营业") + private Integer isOn; + + private String startTime; + + private String endTime; + + @Schema(description = "是否需要审核") + private Integer goodsReview; + + @Schema(description = "管理入口") + private String adminUrl; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "所有人") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantAccount.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantAccount.java new file mode 100644 index 0000000..5ebbb65 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantAccount.java @@ -0,0 +1,67 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户账号 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopMerchantAccount对象", description = "商户账号") +public class ShopMerchantAccount implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "角色ID") + private Integer roleId; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "密码") + @TableField(exist = false) + private String password; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantApply.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantApply.java new file mode 100644 index 0000000..1d4516f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantApply.java @@ -0,0 +1,133 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户入驻申请 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopMerchantApply对象", description = "商户入驻申请") +public class ShopMerchantApply implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "apply_id", type = IdType.AUTO) + private Integer applyId; + + @Schema(description = "类型") + private Integer type; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户图标") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "社会信用代码") + private String merchantCode; + + @Schema(description = "身份证号码") + private String idCard; + + @Schema(description = "身份证正面") + private String sfz1; + + @Schema(description = "身份证反面") + private String sfz2; + + @Schema(description = "营业执照") + private String yyzz; + + @Schema(description = "行业父级分类") + private Integer parentId; + + @Schema(description = "行业分类ID") + private Integer categoryId; + + @Schema(description = "行业分类") + private String category; + + @Schema(description = "手续费") + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "所有人") + private Integer userId; + + @Schema(description = "是否自营") + private Integer ownStore; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "是否需要审核") + private Integer goodsReview; + + @Schema(description = "工作负责人") + private String name2; + + @Schema(description = "驳回原因") + private String reason; + + @Schema(description = "审核完成时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime completedTime; + + @Schema(description = "审核状态") + private Boolean checkStatus; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "应用名称") + @TableField(exist = false) + private String tenantName; + + @Schema(description = "应用图标") + @TableField(exist = false) + private String logo; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantType.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantType.java new file mode 100644 index 0000000..9411233 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopMerchantType.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户类型 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopMerchantType对象", description = "商户类型") +public class ShopMerchantType implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "店铺类型") + private String name; + + @Schema(description = "店铺入驻条件") + private String comments; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java new file mode 100644 index 0000000..4d46057 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java @@ -0,0 +1,329 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.*; + +/** + * 订单 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopOrder对象", description = "订单") +public class ShopOrder implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单号") + @TableId(value = "order_id", type = IdType.AUTO) + private Integer orderId; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "订单类型,0商城订单 1预定订单/外卖 2会员卡") + private Integer type; + + @Schema(description = "订单标题") + private String title; + + @Schema(description = "快递/自提") + private Integer deliveryType; + + @Schema(description = "下单渠道,0小程序预定 1俱乐部训练场 3活动订场") + private Integer channel; + + @Schema(description = "微信支付订单号") + private String transactionId; + + @Schema(description = "微信退款订单号") + private String refundOrder; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户编号") + private String merchantCode; + + @Schema(description = "使用的优惠券id") + private Integer couponId; + + @Schema(description = "使用的会员卡id") + private String cardId; + + @Schema(description = "关联管理员id") + private Integer adminId; + + @Schema(description = "核销管理员id") + private Integer confirmId; + + @Schema(description = "IC卡号") + private String icCard; + + @Schema(description = "收货人id") + private Integer addressId; + + @Schema(description = "收货地址") + private String address; + + private String addressLat; + + private String addressLng; + + @Schema(description = "买家备注") + private String buyerRemarks; + + @Schema(description = "自提店铺id") + private Integer selfTakeMerchantId; + + @Schema(description = "自提店铺") + private String selfTakeMerchantName; + + @Schema(description = "配送开始时间") + private String sendStartTime; + + @Schema(description = "配送结束时间") + private String sendEndTime; + + @Schema(description = "发货店铺id") + private Integer expressMerchantId; + + @Schema(description = "发货店铺") + private String expressMerchantName; + + @Schema(description = "订单总额") + @NotNull(message = "订单总额不能为空") + @DecimalMin(value = "0.01", message = "订单总额必须大于0") + @Digits(integer = 10, fraction = 2, message = "订单总额格式不正确") + private BigDecimal totalPrice; + + @Schema(description = "减少的金额,使用VIP会员折扣、优惠券抵扣、优惠券折扣后减去的价格") + @DecimalMin(value = "0", message = "减少金额不能为负数") + private BigDecimal reducePrice; + + @Schema(description = "实际付款") + @DecimalMin(value = "0", message = "实际付款不能为负数") + private BigDecimal payPrice; + + @Schema(description = "用于统计") + private BigDecimal price; + + @Schema(description = "价钱,用于积分赠送") + private BigDecimal money; + + @Schema(description = "退款金额") + private BigDecimal refundMoney; + + @Schema(description = "教练价格") + private BigDecimal coachPrice; + + @Schema(description = "购买数量") + @Min(value = 1, message = "购买数量必须大于0") + private Integer totalNum; + + @Schema(description = "教练id") + private Integer coachId; + + @Schema(description = "来源ID,存商品ID") + private Integer formId; + + @Schema(description = "支付的用户id") + private Integer payUserId; + + @Schema(description = "支付方式:0余额支付,1微信支付,2支付宝支付,3银联支付,4现金支付,5POS机支付,6免费,7积分支付") + private Integer payType; + + @Schema(description = "微信支付子类型:JSAPI小程序支付,NATIVE扫码支付") + private String wechatPayType; + + @Schema(description = "代付支付方式:0余额支付,1微信支付,2支付宝支付,3银联支付,4现金支付,5POS机支付,6免费,7积分支付") + private Integer friendPayType; + + @Schema(description = "0未付款,1已付款") + private Boolean payStatus; + + @Schema(description = "0未使用,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + private Integer orderStatus; + + @Schema(description = "发货状态(10未发货 20已发货 30部分发货)") + private Integer deliveryStatus; + + @Schema(description = "发货备注") + private String deliveryNote; + + @Schema(description = "快递单号") + private String expressNo; + + @Schema(description = "发货时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime deliveryTime; + + @Schema(description = "优惠类型:0无、1抵扣优惠券、2折扣优惠券、3、VIP月卡、4VIP年卡,5VIP次卡、6VIP会员卡、7IC月卡、8IC年卡、9IC次卡、10IC会员卡、11免费订单、12VIP充值卡、13IC充值卡、14VIP季卡、15IC季卡") + private Integer couponType; + + @Schema(description = "优惠说明") + private String couponDesc; + + @Schema(description = "二维码地址,保存订单号,支付成功后才生成") + private String qrcode; + + @Schema(description = "vip月卡年卡、ic月卡年卡回退次数") + private Integer returnNum; + + @Schema(description = "vip充值回退金额") + private BigDecimal returnMoney; + + @Schema(description = "预约详情开始时间数组") + private String startTime; + + @Schema(description = "是否已开具发票:0未开发票,1已开发票,2不能开具发票") + private Integer isInvoice; + + @Schema(description = "发票流水号") + private String invoiceNo; + + @Schema(description = "支付时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime payTime; + + @Schema(description = "退款原因") + @NotBlank(message = "退款原因不能为空") + private String refundReason; + + @Schema(description = "退款时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime refundTime; + + @Schema(description = "申请退款时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime refundApplyTime; + + @Schema(description = "取消时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime cancelTime; + + @Schema(description = "取消原因") + private String cancelReason; + + @Schema(description = "过期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime expirationTime; + + @Schema(description = "评价状态 0未评价 1已评价") + private Integer evaluateStatus; + + @Schema(description = "评价时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime evaluateTime; + + @Schema(description = "对账情况:0=未对账;1=已对账;3=已对账,金额对不上;4=未查询到该订单") + private Integer checkBill; + + @Schema(description = "订单是否已结算(0未结算 1已结算)") + private Integer isSettled; + + @Schema(description = "商户备注") + private String merchantRemarks; + + @Schema(description = "系统版本号 0当前版本 value=其他版本") + private Integer version; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "手机号码") + @TableField(exist = false) + private String phone; + + @Schema(description = "手机号码(脱敏)") + @TableField(exist = false) + private String mobile; + + @Schema(description = "备注") + @Size(max = 500, message = "备注长度不能超过500字符") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + @NotNull(message = "租户ID不能为空") + private Integer tenantId; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "自提码") + private String selfTakeCode; + + @Schema(description = "是否已收到赠品") + private Boolean hasTakeGift; + + @Schema(description = "accessToken") + @TableField(exist = false) + private String accessToken; + + @Schema(description = "openid") + @TableField(exist = false) + private String openid; + + @Schema(description = "订单商品") + @TableField(exist = false) + private List orderGoods; + + @Schema(description = "快递id") + @TableField(exist = false) + private Integer expressId; + + @Schema(description = "发货人") + @TableField(exist = false) + private String sendName; + + @Schema(description = "发货人联系方式") + @TableField(exist = false) + private String sendPhone; + + @Schema(description = "发货地址") + @TableField(exist = false) + private String sendAddress; + + @TableField(exist = false) + private ShopOrderDelivery shopOrderDelivery; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderDelivery.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderDelivery.java new file mode 100644 index 0000000..18494fc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderDelivery.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 发货单 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopOrderDelivery对象", description = "发货单") +public class ShopOrderDelivery implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "发货单ID") + @TableId(value = "delivery_id", type = IdType.AUTO) + private Integer deliveryId; + + @Schema(description = "订单ID") + private Integer orderId; + + @Schema(description = "发货方式(10手动录入 20无需物流 30电子面单)") + private Integer deliveryMethod; + + @Schema(description = "打包方式(废弃)") + private Integer packMethod; + + @Schema(description = "物流公司ID") + private Integer expressId; + + @Schema(description = "发货人") + private String sendName; + + @Schema(description = "发货人联系方式") + private String sendPhone; + + @Schema(description = "发货地址") + private String sendAddress; + + @Schema(description = "物流单号") + private String expressNo; + + @Schema(description = "电子面单模板内容") + private String eorderHtml; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @TableField(exist = false) + private String expressName; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderDeliveryGoods.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderDeliveryGoods.java new file mode 100644 index 0000000..55d8c0b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderDeliveryGoods.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 发货单商品 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopOrderDeliveryGoods对象", description = "发货单商品") +public class ShopOrderDeliveryGoods implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "发货单ID") + private Integer deliveryId; + + @Schema(description = "订单ID") + private Integer orderId; + + @Schema(description = "订单商品ID") + private Integer orderGoodsId; + + @Schema(description = "商品ID") + private Integer goodsId; + + @Schema(description = "发货数量") + private Integer deliveryNum; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderExtract.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderExtract.java new file mode 100644 index 0000000..8f81ebd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderExtract.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 自提订单联系方式 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopOrderExtract对象", description = "自提订单联系方式") +public class ShopOrderExtract implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "订单ID") + private Integer orderId; + + @Schema(description = "联系人姓名") + private String linkman; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderGoods.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderGoods.java new file mode 100644 index 0000000..399dc40 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderGoods.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDate; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalTime; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品信息 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopOrderGoods对象", description = "商品信息") +public class ShopOrderGoods implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "关联订单表id") + private Integer orderId; + + @Schema(description = "订单标识") + private String orderCode; + + @Schema(description = "关联商户ID") + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商品封面图") + private String image; + + @Schema(description = "关联商品id") + private Integer goodsId; + + @Schema(description = "商品名称") + private String goodsName; + + @Schema(description = "商品规格") + private String spec; + + private Integer skuId; + + @Schema(description = "单价") + private BigDecimal price; + + @Schema(description = "购买数量") + private Integer totalNum; + + @Schema(description = "0 未付款 1已付款,2无需付款或占用状态") + private Integer payStatus; + + @Schema(description = "0未使用,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + private Integer orderStatus; + + @Schema(description = "是否免费:0收费、1免费") + private Boolean isFree; + + @Schema(description = "系统版本 0当前版本 其他版本") + private Integer version; + + @Schema(description = "预约时间段") + private String timePeriod; + + @Schema(description = "预定日期") + private LocalDate dateTime; + + @Schema(description = "开场时间") + private LocalTime startTime; + + @Schema(description = "结束时间") + private LocalTime endTime; + + @Schema(description = "毫秒时间戳") + private Long timeFlag; + + @Schema(description = "过期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime expirationTime; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @TableField(exist = false) + private List goodsList; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderInfo.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderInfo.java new file mode 100644 index 0000000..4303cfd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderInfo.java @@ -0,0 +1,121 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDate; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalTime; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 场地 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopOrderInfo对象", description = "场地") +public class ShopOrderInfo implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "关联订单表id") + private Integer orderId; + + @Schema(description = "组合数据:日期+时间段+场馆id+场地id") + private String orderCode; + + @Schema(description = "关联商户ID") + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "关联场地id") + private Integer fieldId; + + @Schema(description = "场地名称") + private String fieldName; + + @Schema(description = "单价") + private BigDecimal price; + + @Schema(description = "儿童价") + private BigDecimal childrenPrice; + + @Schema(description = "成人人数") + private Integer adultNum; + + @Schema(description = "儿童人数") + private Integer childrenNum; + + @Schema(description = "已核销的成人票数") + private Integer adultNumUse; + + @Schema(description = "已核销的儿童票数") + private Integer childrenNumUse; + + @Schema(description = "0 未付款 1已付款,2无需付款或占用状态") + private Integer payStatus; + + @Schema(description = "0未使用,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + private Integer orderStatus; + + @Schema(description = "是否免费:0收费、1免费") + private Boolean isFree; + + @Schema(description = "是否支持儿童票:0不支持、1支持") + private Boolean isChildren; + + @Schema(description = "系统版本 0当前版本 其他版本") + private Integer version; + + @Schema(description = "预订类型:0全场,1半场") + private Boolean isHalf; + + @Schema(description = "预约时间段") + private String timePeriod; + + @Schema(description = "预定日期") + private LocalDate dateTime; + + @Schema(description = "开场时间") + private LocalTime startTime; + + @Schema(description = "结束时间") + private LocalTime endTime; + + @Schema(description = "毫秒时间戳") + private Long timeFlag; + + @Schema(description = "过期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime expirationTime; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderInfoLog.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderInfoLog.java new file mode 100644 index 0000000..67143da --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopOrderInfoLog.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 订单核销 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopOrderInfoLog对象", description = "订单核销") +public class ShopOrderInfoLog implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "关联订单表id") + private Integer orderId; + + @Schema(description = "关联商户ID") + private Long merchantId; + + @Schema(description = "关联场地id") + private Integer fieldId; + + @Schema(description = "核销数量") + private Boolean useNum; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopRechargeOrder.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopRechargeOrder.java new file mode 100644 index 0000000..c54728c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopRechargeOrder.java @@ -0,0 +1,102 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 会员充值订单表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopRechargeOrder对象", description = "会员充值订单表") +public class ShopRechargeOrder implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单ID") + @TableId(value = "order_id", type = IdType.AUTO) + private Integer orderId; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "充值方式(10自定义金额 20套餐充值)") + private Integer rechargeType; + + @Schema(description = "机构id") + private Integer organizationId; + + @Schema(description = "充值套餐ID") + private Integer planId; + + @Schema(description = "用户支付金额") + private BigDecimal payPrice; + + @Schema(description = "赠送金额") + private BigDecimal giftMoney; + + @Schema(description = "实际到账金额") + private BigDecimal actualMoney; + + @Schema(description = "用户可用余额") + private BigDecimal balance; + + @Schema(description = "支付方式(微信/支付宝)") + private String payMethod; + + @Schema(description = "支付状态(10待支付 20已支付)") + private Integer payStatus; + + @Schema(description = "付款时间") + private Integer payTime; + + @Schema(description = "第三方交易记录ID") + private Integer tradeId; + + @Schema(description = "来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "所属门店ID") + private Integer shopId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSpec.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSpec.java new file mode 100644 index 0000000..222cfb4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSpec.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 规格 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopSpec对象", description = "规格") +public class ShopSpec implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "规格ID") + @TableId(value = "spec_id", type = IdType.AUTO) + private Integer specId; + + @Schema(description = "规格名称") + private String specName; + + @Schema(description = "规格值") + private String specValue; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "创建用户") + private Integer userId; + + @Schema(description = "更新者") + private Integer updater; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1待修,2异常已修,3异常未修") + private Integer status; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSpecValue.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSpecValue.java new file mode 100644 index 0000000..18d3d22 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSpecValue.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 规格值 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopSpecValue对象", description = "规格值") +public class ShopSpecValue implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "规格值ID") + @TableId(value = "spec_value_id", type = IdType.AUTO) + private Integer specValueId; + + @Schema(description = "规格组ID") + private Integer specId; + + @Schema(description = "规格值") + private String specValue; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSplash.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSplash.java new file mode 100644 index 0000000..6359fe8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopSplash.java @@ -0,0 +1,64 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 开屏广告 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopSplash对象", description = "开屏广告") +public class ShopSplash implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "标题") + private String title; + + @Schema(description = "图片") + private String image; + + @Schema(description = "跳转类型") + private String jumpType; + + @Schema(description = "跳转主键") + private Integer jumpPk; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUser.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUser.java new file mode 100644 index 0000000..f540f64 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUser.java @@ -0,0 +1,254 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 用户记录表 + * + * @author 科技小王子 + * @since 2025-10-03 13:41:09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "用户记录表") +public class ShopUser implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "用户id") + private Integer userId; + + @Schema(description = "用户类型 0个人用户 1企业用户 2其他") + private Integer type; + + @Schema(description = "账号") + private String username; + + @Schema(description = "密码") + private String password; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "性别 1男 2女") + private Integer sex; + + @Schema(description = "职务") + private String position; + + @Schema(description = "注册来源客户端 (APP、H5、MP-WEIXIN等)") + private String platform; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "邮箱是否验证, 0否, 1是") + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "证件号码") + private String idCard; + + @Schema(description = "出生日期") + private LocalDate birthday; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "用户可用余额") + private BigDecimal balance; + + @Schema(description = "已提现金额") + private BigDecimal cashedMoney; + + @Schema(description = "用户可用积分") + private Integer points; + + @Schema(description = "用户总支付的金额") + private BigDecimal payMoney; + + @Schema(description = "实际消费的金额(不含退款)") + private BigDecimal expendMoney; + + @Schema(description = "密码") + private String payPassword; + + @Schema(description = "会员等级ID") + private Integer gradeId; + + @Schema(description = "行业分类") + private String category; + + @Schema(description = "个人简介") + private String introduction; + + @Schema(description = "机构id") + private Integer organizationId; + + @Schema(description = "会员分组ID") + private Integer groupId; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "背景图") + private String bgImage; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "是否已实名认证") + private Integer certification; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "是否线下会员") + private Boolean offline; + + @Schema(description = "关注数") + private Integer followers; + + @Schema(description = "粉丝数") + private Integer fans; + + @Schema(description = "点赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "是否推荐") + private Integer recommend; + + @Schema(description = "微信openid") + private String openid; + + @Schema(description = "微信公众号openid") + private String officeOpenid; + + @Schema(description = "微信unionID") + private String unionid; + + @Schema(description = "客户端ID") + private String clientId; + + @Schema(description = "不允许办卡") + private Boolean notAllowVip; + + @Schema(description = "是否管理员") + private Boolean isAdmin; + + @Schema(description = "是否企业管理员") + private Boolean isOrganizationAdmin; + + @Schema(description = "累计登录次数") + private Integer loginNum; + + @Schema(description = "企业ID") + private Integer companyId; + + @Schema(description = "可管理的场馆") + private String merchants; + + @Schema(description = "商户ID") + private Integer merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户头像") + private String merchantAvatar; + + @Schema(description = "第三方系统的用户ID") + private Integer uid; + + @Schema(description = "专家角色") + private Boolean expertType; + + @Schema(description = "过期时间") + private Integer expireTime; + + @Schema(description = "最后结算时间") + private LocalDateTime settlementTime; + + @Schema(description = "资质") + private String aptitude; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "头衔") + private String title; + + @Schema(description = "安装的产品ID") + private Integer templateId; + + @Schema(description = "插件安装状态(仅对超超管判断) 0未安装 1已安装 ") + private Integer installed; + + @Schema(description = "特长") + private String speciality; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0在线, 1离线") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserAddress.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserAddress.java new file mode 100644 index 0000000..e95686f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserAddress.java @@ -0,0 +1,79 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 收货地址 + * + * @author 科技小王子 + * @since 2025-07-22 23:06:40 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopUserAddress对象", description = "收货地址") +public class ShopUserAddress implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "收货地址") + private String address; + + @Schema(description = "收货地址") + private String fullAddress; + + private String lat; + + private String lng; + + @Schema(description = "1先生 2女士") + private Integer gender; + + @Schema(description = "家、公司、学校") + private String type; + + @Schema(description = "默认收货地址") + private Boolean isDefault; + + @Schema(description = "排序号") + private Integer sortNumber; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserBalanceLog.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserBalanceLog.java new file mode 100644 index 0000000..32726fc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserBalanceLog.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户余额变动明细表 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopUserBalanceLog对象", description = "用户余额变动明细表") +public class ShopUserBalanceLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "log_id", type = IdType.AUTO) + private Integer logId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "余额变动场景(0下级下单1供应商收入2差价收益 10用户充值 20用户消费 30管理员操作 40订单退款)") + private Integer scene; + + @Schema(description = "变动金额") + private BigDecimal money; + + @Schema(description = "变动后余额") + private BigDecimal balance; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "操作人ID") + private Integer adminId; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "商户编码") + private String merchantCode; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserCollection.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserCollection.java new file mode 100644 index 0000000..498c2fd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserCollection.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 我的收藏 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopUserCollection对象", description = "我的收藏") +public class ShopUserCollection implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "0店铺,1商品") + private Boolean type; + + @Schema(description = "租户ID") + private Integer tid; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserCoupon.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserCoupon.java new file mode 100644 index 0000000..d25ad57 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserCoupon.java @@ -0,0 +1,210 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户优惠券 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopUserCoupon对象", description = "用户优惠券") +public class ShopUserCoupon implements Serializable { + private static final long serialVersionUID = 1L; + + // 优惠券类型常量 + public static final int TYPE_REDUCE = 10; // 满减券 + public static final int TYPE_DISCOUNT = 20; // 折扣券 + public static final int TYPE_FREE = 30; // 免费券 + + // 使用状态常量 + public static final int STATUS_UNUSED = 0; // 未使用 + public static final int STATUS_USED = 1; // 已使用 + public static final int STATUS_EXPIRED = 2; // 已过期 + + // 获取方式常量 + public static final int OBTAIN_ACTIVE = 10; // 主动领取 + public static final int OBTAIN_SYSTEM = 20; // 系统发放 + public static final int OBTAIN_ACTIVITY = 30; // 活动赠送 + + // 适用范围常量 + public static final int APPLY_ALL = 10; // 全部商品 + public static final int APPLY_GOODS = 20; // 指定商品 + public static final int APPLY_CATEGORY = 30; // 指定分类 + + @Schema(description = "id") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @Schema(description = "优惠券模板ID") + private Integer couponId; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券描述") + private String description; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + private Integer type; + + @Schema(description = "满减券-减免金额") + @JsonSerialize(using = ToStringSerializer.class) + @JsonInclude(JsonInclude.Include.NON_NULL) + private BigDecimal reducePrice; + + @Schema(description = "折扣券-折扣率(0-100)") + private Integer discount; + + @Schema(description = "最低消费金额") + @JsonSerialize(using = ToStringSerializer.class) + @JsonInclude(JsonInclude.Include.NON_NULL) + private BigDecimal minPrice; + + @Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)") + private Integer applyRange; + + @Schema(description = "到期类型(10领取后生效 20固定时间)") + private Integer expireType; + + @Schema(description = "领取后生效-有效天数") + private Integer expireDay; + + @Schema(description = "适用范围配置(json格式)") + private String applyRangeConfig; + + @Schema(description = "是否过期(0未过期 1已过期)") + private Integer isExpire; + + @Schema(description = "有效期开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime startTime; + + @Schema(description = "有效期结束时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime endTime; + + @Schema(description = "使用状态(0未使用 1已使用 2已过期)") + private Integer status; + + @Schema(description = "使用时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime useTime; + + @Schema(description = "使用订单ID") + private Integer orderId; + + @Schema(description = "是否已使用") + private Integer isUse; + + @Schema(description = "使用订单号") + private String orderNo; + + @Schema(description = "获取方式(10主动领取 20系统发放 30活动赠送)") + private Integer obtainType; + + @Schema(description = "获取来源描述") + private String obtainSource; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Boolean deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @TableField(exist = false) + private ShopCoupon couponItem; + + /** + * 判断优惠券是否可用 + * @return true-可用,false-不可用 + */ + public boolean isAvailable() { + return this.status != null && this.status == STATUS_UNUSED && !isExpired(); + } + + /** + * 判断优惠券是否已使用 + * @return true-已使用,false-未使用 + */ + public boolean isUsed() { + return this.status != null && this.status == STATUS_USED; + } + + /** + * 判断优惠券是否已过期 + * @return true-已过期,false-未过期 + */ + public boolean isExpired() { + if (this.status != null && this.status == STATUS_EXPIRED) { + return true; + } + return this.endTime != null && this.endTime.isBefore(LocalDateTime.now()); + } + + /** + * 获取优惠券状态描述 + * @return 状态描述 + */ + public String getStatusDesc() { + if (isExpired()) { + return "已过期"; + } else if (isUsed()) { + return "已使用"; + } else if (isAvailable()) { + return "可使用"; + } else { + return "未知状态"; + } + } + + /** + * 更新优惠券状态为已使用 + * @param orderId 订单ID + * @param orderNo 订单号 + */ + public void markAsUsed(Integer orderId, String orderNo) { + this.status = STATUS_USED; + this.isUse = 1; + this.useTime = LocalDateTime.now(); + this.orderId = orderId; + this.orderNo = orderNo; + } + + /** + * 更新优惠券状态为已过期 + */ + public void markAsExpired() { + this.status = STATUS_EXPIRED; + this.isExpire = 1; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserReferee.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserReferee.java new file mode 100644 index 0000000..231d023 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopUserReferee.java @@ -0,0 +1,81 @@ +package com.gxwebsoft.shop.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户推荐关系表 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopUserReferee对象", description = "用户推荐关系表") +public class ShopUserReferee implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "推荐人ID") + private Integer dealerId; + + @Schema(description = "分销商名称") + @TableField(exist = false) + private String dealerName; + + @Schema(description = "分销商头像") + @TableField(exist = false) + private String dealerAvatar; + + @Schema(description = "分销商手机号") + @TableField(exist = false) + private String dealerPhone; + + @Schema(description = "用户id(被推荐人)") + private Integer userId; + + @Schema(description = "昵称") + @TableField(exist = false) + private String nickname; + + @Schema(description = "头像") + @TableField(exist = false) + private String avatar; + + @Schema(description = "手机号") + @TableField(exist = false) + private String phone; + + @Schema(description = "推荐关系层级(1,2,3)") + private Integer level; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopWechatDeposit.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopWechatDeposit.java new file mode 100644 index 0000000..c552a03 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/entity/ShopWechatDeposit.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 押金 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopWechatDeposit对象", description = "押金") +public class ShopWechatDeposit implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "订单id") + private Integer oid; + + @Schema(description = "用户id") + private Integer uid; + + @Schema(description = "场地订单号") + private String orderNum; + + @Schema(description = "付款订单号") + private String wechatOrder; + + @Schema(description = "退款订单号 ") + private String wechatReturn; + + @Schema(description = "场馆名称") + private String siteName; + + @Schema(description = "微信昵称") + private String username; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "物品名称") + private String name; + + @Schema(description = "押金金额") + private BigDecimal price; + + @Schema(description = "押金状态,1已付款,2未付款,已退押金") + private Boolean status; + + @Schema(description = "创建时间") + private Integer createTime; + + @Schema(description = "租户id") + private Integer tenantId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.class b/jczxw-java/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.class new file mode 100644 index 0000000..48a4a6c Binary files /dev/null and b/jczxw-java/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.class differ diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.java new file mode 100644 index 0000000..3fd46c0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/enums/OrderStatusEnum.java @@ -0,0 +1,32 @@ +package com.gxwebsoft.shop.enums; + +/** + * 订单状态枚举 + */ +public enum OrderStatusEnum { + ALL(-1, "全部"), + WAIT_PAY(0, "待支付"), + WAIT_DELIVERY(1, "待发货"), + WAIT_CONFIRM(2, "待核销"), + WAIT_RECEIVE(3, "待收货"), + WAIT_EVALUATE(4, "待评价"), + COMPLETED(5, "已完成"), + REFUNDED(6, "已退款"), + DELETED(7, "已删除"); + + private final Integer code; + private final String desc; + + OrderStatusEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + + public Integer getCode() { + return code; + } + + public String getDesc() { + return desc; + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java new file mode 100644 index 0000000..d6d3d85 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品文章Mapper + * + * @author 科技小王子 + * @since 2025-08-13 05:14:53 + */ +public interface ShopArticleMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopArticleParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopArticleParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopBrandMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopBrandMapper.java new file mode 100644 index 0000000..49a914d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopBrandMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopBrand; +import com.gxwebsoft.shop.param.ShopBrandParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 品牌Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopBrandMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopBrandParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopBrandParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCartMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCartMapper.java new file mode 100644 index 0000000..ae8b981 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCartMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCart; +import com.gxwebsoft.shop.param.ShopCartParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 购物车Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopCartMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCartParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCartParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCategoryMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCategoryMapper.java new file mode 100644 index 0000000..2cfd98c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCategoryMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCategory; +import com.gxwebsoft.shop.param.ShopCategoryParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品分类Mapper + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +public interface ShopCategoryMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCategoryParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCategoryParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopChatConversationMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopChatConversationMapper.java new file mode 100644 index 0000000..483b761 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopChatConversationMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopChatConversation; +import com.gxwebsoft.shop.param.ShopChatConversationParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 聊天消息表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopChatConversationMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopChatConversationParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopChatConversationParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopChatMessageMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopChatMessageMapper.java new file mode 100644 index 0000000..264bc4b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopChatMessageMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopChatMessage; +import com.gxwebsoft.shop.param.ShopChatMessageParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 聊天消息表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopChatMessageMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopChatMessageParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopChatMessageParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCommissionRoleMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCommissionRoleMapper.java new file mode 100644 index 0000000..2f66f28 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCommissionRoleMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCommissionRole; +import com.gxwebsoft.shop.param.ShopCommissionRoleParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分红角色Mapper + * + * @author 科技小王子 + * @since 2025-05-01 10:01:15 + */ +public interface ShopCommissionRoleMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCommissionRoleParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCommissionRoleParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCountMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCountMapper.java new file mode 100644 index 0000000..24701c6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCountMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCount; +import com.gxwebsoft.shop.param.ShopCountParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商城销售统计表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopCountMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCountParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCountParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponApplyCateMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponApplyCateMapper.java new file mode 100644 index 0000000..6d86d1d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponApplyCateMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCouponApplyCate; +import com.gxwebsoft.shop.param.ShopCouponApplyCateParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 优惠券可用分类Mapper + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +public interface ShopCouponApplyCateMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCouponApplyCateParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCouponApplyCateParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponApplyItemMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponApplyItemMapper.java new file mode 100644 index 0000000..077989a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponApplyItemMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.param.ShopCouponApplyItemParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 优惠券可用分类Mapper + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +public interface ShopCouponApplyItemMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCouponApplyItemParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCouponApplyItemParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponMapper.java new file mode 100644 index 0000000..a6a8ff1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopCouponMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.param.ShopCouponParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 优惠券Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:23 + */ +public interface ShopCouponMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopCouponParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopCouponParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerApplyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerApplyMapper.java new file mode 100644 index 0000000..ce2ee91 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerApplyMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerApply; +import com.gxwebsoft.shop.param.ShopDealerApplyParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商申请记录表Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:50:18 + */ +public interface ShopDealerApplyMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerApplyParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerApplyParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerBankMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerBankMapper.java new file mode 100644 index 0000000..2ec78ed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerBankMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerBank; +import com.gxwebsoft.shop.param.ShopDealerBankParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商提现银行卡Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerBankMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerBankParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerBankParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerCapitalMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerCapitalMapper.java new file mode 100644 index 0000000..d996c07 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerCapitalMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerCapital; +import com.gxwebsoft.shop.param.ShopDealerCapitalParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商资金明细表Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerCapitalMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerCapitalParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerCapitalParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerOrderMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerOrderMapper.java new file mode 100644 index 0000000..928b066 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerOrderMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerOrder; +import com.gxwebsoft.shop.param.ShopDealerOrderParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商订单记录表Mapper + * + * @author 科技小王子 + * @since 2025-08-12 11:55:18 + */ +public interface ShopDealerOrderMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerOrderParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerOrderParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerRecordMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerRecordMapper.java new file mode 100644 index 0000000..09f365f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerRecordMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerRecord; +import com.gxwebsoft.shop.param.ShopDealerRecordParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 客户跟进情况Mapper + * + * @author 科技小王子 + * @since 2025-10-02 12:21:50 + */ +public interface ShopDealerRecordMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerRecordParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerRecordParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerRefereeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerRefereeMapper.java new file mode 100644 index 0000000..70ddf37 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerRefereeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerReferee; +import com.gxwebsoft.shop.param.ShopDealerRefereeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商推荐关系表Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerRefereeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerRefereeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerRefereeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerSettingMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerSettingMapper.java new file mode 100644 index 0000000..5d10a6c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerSettingMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerSetting; +import com.gxwebsoft.shop.param.ShopDealerSettingParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商设置表Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerSettingMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerSettingParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerSettingParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerUserMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerUserMapper.java new file mode 100644 index 0000000..c1b5fd3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerUserMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerUser; +import com.gxwebsoft.shop.param.ShopDealerUserParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商用户记录表Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerUserMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerUserParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerUserParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerWithdrawMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerWithdrawMapper.java new file mode 100644 index 0000000..0d5a427 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopDealerWithdrawMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopDealerWithdraw; +import com.gxwebsoft.shop.param.ShopDealerWithdrawParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分销商提现明细表Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerWithdrawMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopDealerWithdrawParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopDealerWithdrawParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressMapper.java new file mode 100644 index 0000000..1d236e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopExpress; +import com.gxwebsoft.shop.param.ShopExpressParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 物流公司Mapper + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +public interface ShopExpressMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopExpressParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopExpressParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressTemplateDetailMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressTemplateDetailMapper.java new file mode 100644 index 0000000..fd26f85 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressTemplateDetailMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopExpressTemplateDetail; +import com.gxwebsoft.shop.param.ShopExpressTemplateDetailParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 运费模板Mapper + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +public interface ShopExpressTemplateDetailMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopExpressTemplateDetailParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopExpressTemplateDetailParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressTemplateMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressTemplateMapper.java new file mode 100644 index 0000000..a205498 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopExpressTemplateMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopExpressTemplate; +import com.gxwebsoft.shop.param.ShopExpressTemplateParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 运费模板Mapper + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +public interface ShopExpressTemplateMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopExpressTemplateParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopExpressTemplateParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGiftMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGiftMapper.java new file mode 100644 index 0000000..bf0a45d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGiftMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGift; +import com.gxwebsoft.shop.param.ShopGiftParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 礼品卡Mapper + * + * @author 科技小王子 + * @since 2025-08-11 18:07:31 + */ +public interface ShopGiftMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGiftParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGiftParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsCategoryMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsCategoryMapper.java new file mode 100644 index 0000000..ff7e088 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsCategoryMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsCategory; +import com.gxwebsoft.shop.param.ShopGoodsCategoryParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品分类Mapper + * + * @author 科技小王子 + * @since 2025-05-01 00:36:45 + */ +public interface ShopGoodsCategoryMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsCategoryParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsCategoryParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsCommentMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsCommentMapper.java new file mode 100644 index 0000000..302a1f0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsCommentMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsComment; +import com.gxwebsoft.shop.param.ShopGoodsCommentParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 评论表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsCommentMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsCommentParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsCommentParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsIncomeConfigMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsIncomeConfigMapper.java new file mode 100644 index 0000000..9091b99 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsIncomeConfigMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsIncomeConfig; +import com.gxwebsoft.shop.param.ShopGoodsIncomeConfigParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 分润配置Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsIncomeConfigMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsIncomeConfigParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsIncomeConfigParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsLogMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsLogMapper.java new file mode 100644 index 0000000..946b338 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsLogMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsLog; +import com.gxwebsoft.shop.param.ShopGoodsLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品日志表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsLogMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsLogParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsLogParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsMapper.java new file mode 100644 index 0000000..20ac974 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsMapper.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.param.ShopGoodsParam; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +import java.util.List; + +/** + * 商品Mapper + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +public interface ShopGoodsMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsParam param); + + /** + * 累加商品销售数量 + * 使用@InterceptorIgnore忽略租户隔离,确保能更新成功 + * + * @param goodsId 商品ID + * @param saleCount 累加的销售数量 + * @return 影响的行数 + */ + @InterceptorIgnore(tenantLine = "true") + @Update("UPDATE shop_goods SET sales = IFNULL(sales, 0) + #{saleCount} WHERE goods_id = #{goodsId}") + int addSaleCount(@Param("goodsId") Integer goodsId, @Param("saleCount") Integer saleCount); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsRelationMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsRelationMapper.java new file mode 100644 index 0000000..2e02403 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsRelationMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsRelation; +import com.gxwebsoft.shop.param.ShopGoodsRelationParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品点赞和收藏表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsRelationMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsRelationParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsRelationParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsRoleCommissionMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsRoleCommissionMapper.java new file mode 100644 index 0000000..d68181d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsRoleCommissionMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsRoleCommission; +import com.gxwebsoft.shop.param.ShopGoodsRoleCommissionParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品绑定角色的分润金额Mapper + * + * @author 科技小王子 + * @since 2025-05-01 09:53:38 + */ +public interface ShopGoodsRoleCommissionMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsRoleCommissionParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsRoleCommissionParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsSkuMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsSkuMapper.java new file mode 100644 index 0000000..072ebd9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsSkuMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsSku; +import com.gxwebsoft.shop.param.ShopGoodsSkuParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品sku列表Mapper + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +public interface ShopGoodsSkuMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsSkuParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsSkuParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsSpecMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsSpecMapper.java new file mode 100644 index 0000000..503e262 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsSpecMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopGoodsSpec; +import com.gxwebsoft.shop.param.ShopGoodsSpecParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品多规格Mapper + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +public interface ShopGoodsSpecMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopGoodsSpecParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopGoodsSpecParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantAccountMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantAccountMapper.java new file mode 100644 index 0000000..cbbe061 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantAccountMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopMerchantAccount; +import com.gxwebsoft.shop.param.ShopMerchantAccountParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户账号Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopMerchantAccountMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopMerchantAccountParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopMerchantAccountParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantApplyMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantApplyMapper.java new file mode 100644 index 0000000..3377503 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantApplyMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopMerchantApply; +import com.gxwebsoft.shop.param.ShopMerchantApplyParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户入驻申请Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopMerchantApplyMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopMerchantApplyParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopMerchantApplyParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantMapper.java new file mode 100644 index 0000000..747a9c3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopMerchant; +import com.gxwebsoft.shop.param.ShopMerchantParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户Mapper + * + * @author 科技小王子 + * @since 2025-08-10 20:43:33 + */ +public interface ShopMerchantMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopMerchantParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopMerchantParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantTypeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantTypeMapper.java new file mode 100644 index 0000000..e1ea739 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopMerchantTypeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopMerchantType; +import com.gxwebsoft.shop.param.ShopMerchantTypeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商户类型Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopMerchantTypeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopMerchantTypeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopMerchantTypeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderDeliveryGoodsMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderDeliveryGoodsMapper.java new file mode 100644 index 0000000..ae5af95 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderDeliveryGoodsMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopOrderDeliveryGoods; +import com.gxwebsoft.shop.param.ShopOrderDeliveryGoodsParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 发货单商品Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderDeliveryGoodsMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopOrderDeliveryGoodsParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopOrderDeliveryGoodsParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderDeliveryMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderDeliveryMapper.java new file mode 100644 index 0000000..cfe334b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderDeliveryMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopOrderDelivery; +import com.gxwebsoft.shop.param.ShopOrderDeliveryParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 发货单Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderDeliveryMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopOrderDeliveryParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopOrderDeliveryParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderExtractMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderExtractMapper.java new file mode 100644 index 0000000..643a832 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderExtractMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopOrderExtract; +import com.gxwebsoft.shop.param.ShopOrderExtractParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 自提订单联系方式Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderExtractMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopOrderExtractParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopOrderExtractParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderGoodsMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderGoodsMapper.java new file mode 100644 index 0000000..69b747d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderGoodsMapper.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopOrderGoods; +import com.gxwebsoft.shop.param.ShopOrderGoodsParam; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 商品信息Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderGoodsMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopOrderGoodsParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopOrderGoodsParam param); + + /** + * 根据订单ID查询订单商品列表(忽略租户隔离) + * @param orderId 订单ID + * @return List + */ + @InterceptorIgnore(tenantLine = "true") + @Select("SELECT * FROM shop_order_goods WHERE order_id = #{orderId}") + List selectListByOrderIdIgnoreTenant(@Param("orderId") Integer orderId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderInfoLogMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderInfoLogMapper.java new file mode 100644 index 0000000..f7f98a4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderInfoLogMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopOrderInfoLog; +import com.gxwebsoft.shop.param.ShopOrderInfoLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 订单核销Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderInfoLogMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopOrderInfoLogParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopOrderInfoLogParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderInfoMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderInfoMapper.java new file mode 100644 index 0000000..bbbc1ab --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderInfoMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopOrderInfo; +import com.gxwebsoft.shop.param.ShopOrderInfoParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 场地Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderInfoMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopOrderInfoParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopOrderInfoParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderMapper.java new file mode 100644 index 0000000..88aaf0d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopOrderMapper.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.param.ShopOrderParam; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 订单Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopOrderParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopOrderParam param); + + @InterceptorIgnore(tenantLine = "true") + ShopOrder getByOutTradeNo(@Param("outTradeNo") String outTradeNo); + + @InterceptorIgnore(tenantLine = "true") + void updateByOutTradeNo(@Param("param") ShopOrder order); + + /** + * 统计订单总金额 + * 只统计已支付的订单(pay_status = 1)且未删除的订单(deleted = 0) + * + * @return 订单总金额 + */ + @Select("SELECT COALESCE(SUM(pay_price), 0) FROM shop_order WHERE pay_status = 1 AND deleted = 0 AND pay_price IS NOT NULL") + BigDecimal selectTotalAmount(); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopRechargeOrderMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopRechargeOrderMapper.java new file mode 100644 index 0000000..1c25555 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopRechargeOrderMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopRechargeOrder; +import com.gxwebsoft.shop.param.ShopRechargeOrderParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 会员充值订单表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopRechargeOrderMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopRechargeOrderParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopRechargeOrderParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSpecMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSpecMapper.java new file mode 100644 index 0000000..1999c43 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSpecMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopSpec; +import com.gxwebsoft.shop.param.ShopSpecParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 规格Mapper + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +public interface ShopSpecMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopSpecParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopSpecParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSpecValueMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSpecValueMapper.java new file mode 100644 index 0000000..42815c5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSpecValueMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopSpecValue; +import com.gxwebsoft.shop.param.ShopSpecValueParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 规格值Mapper + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +public interface ShopSpecValueMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopSpecValueParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopSpecValueParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSplashMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSplashMapper.java new file mode 100644 index 0000000..db49cb4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopSplashMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopSplash; +import com.gxwebsoft.shop.param.ShopSplashParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 开屏广告Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopSplashMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopSplashParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopSplashParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserAddressMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserAddressMapper.java new file mode 100644 index 0000000..d89f1a6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserAddressMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopUserAddress; +import com.gxwebsoft.shop.param.ShopUserAddressParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 收货地址Mapper + * + * @author 科技小王子 + * @since 2025-07-22 23:06:40 + */ +public interface ShopUserAddressMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopUserAddressParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopUserAddressParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserBalanceLogMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserBalanceLogMapper.java new file mode 100644 index 0000000..4169458 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserBalanceLogMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopUserBalanceLog; +import com.gxwebsoft.shop.param.ShopUserBalanceLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户余额变动明细表Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopUserBalanceLogMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopUserBalanceLogParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopUserBalanceLogParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCollectionMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCollectionMapper.java new file mode 100644 index 0000000..f285ae4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCollectionMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopUserCollection; +import com.gxwebsoft.shop.param.ShopUserCollectionParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 我的收藏Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopUserCollectionMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopUserCollectionParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopUserCollectionParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCouponMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCouponMapper.java new file mode 100644 index 0000000..07c4c43 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserCouponMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.param.ShopUserCouponParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户优惠券Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopUserCouponMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopUserCouponParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopUserCouponParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserMapper.java new file mode 100644 index 0000000..e7a09c4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopUser; +import com.gxwebsoft.shop.param.ShopUserParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户记录表Mapper + * + * @author 科技小王子 + * @since 2025-10-03 13:41:09 + */ +public interface ShopUserMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopUserParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopUserParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserRefereeMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserRefereeMapper.java new file mode 100644 index 0000000..207fd90 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopUserRefereeMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopUserReferee; +import com.gxwebsoft.shop.param.ShopUserRefereeParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户推荐关系表Mapper + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopUserRefereeMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopUserRefereeParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopUserRefereeParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopWechatDepositMapper.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopWechatDepositMapper.java new file mode 100644 index 0000000..3c8424c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/ShopWechatDepositMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopWechatDeposit; +import com.gxwebsoft.shop.param.ShopWechatDepositParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 押金Mapper + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopWechatDepositMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopWechatDepositParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopWechatDepositParam param); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml new file mode 100644 index 0000000..119dc2e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml @@ -0,0 +1,189 @@ + + + + + + + SELECT a.* + FROM shop_article a + + + AND a.article_id = #{param.articleId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.type = #{param.type} + + + AND a.model LIKE CONCAT('%', #{param.model}, '%') + + + AND a.detail LIKE CONCAT('%', #{param.detail}, '%') + + + AND a.category_id = #{param.categoryId} + + + AND a.parent_id = #{param.parentId} + + + AND a.topic LIKE CONCAT('%', #{param.topic}, '%') + + + AND a.tags LIKE CONCAT('%', #{param.tags}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.image_width = #{param.imageWidth} + + + AND a.image_height = #{param.imageHeight} + + + AND a.price = #{param.price} + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.source LIKE CONCAT('%', #{param.source}, '%') + + + AND a.overview LIKE CONCAT('%', #{param.overview}, '%') + + + AND a.virtual_views = #{param.virtualViews} + + + AND a.actual_views = #{param.actualViews} + + + AND a.rate = #{param.rate} + + + AND a.show_type = #{param.showType} + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.permission = #{param.permission} + + + AND a.platform LIKE CONCAT('%', #{param.platform}, '%') + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.video LIKE CONCAT('%', #{param.video}, '%') + + + AND a.accept LIKE CONCAT('%', #{param.accept}, '%') + + + AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%') + + + AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.likes = #{param.likes} + + + AND a.comment_numbers = #{param.commentNumbers} + + + AND a.to_users LIKE CONCAT('%', #{param.toUsers}, '%') + + + AND a.author LIKE CONCAT('%', #{param.author}, '%') + + + AND a.recommend = #{param.recommend} + + + AND a.bm_users = #{param.bmUsers} + + + AND a.user_id = #{param.userId} + + + AND a.project_id = #{param.projectId} + + + AND a.lang LIKE CONCAT('%', #{param.lang}, '%') + + + AND a.lang_article_id = #{param.langArticleId} + + + AND a.translation = #{param.translation} + + + AND a.editor = #{param.editor} + + + AND a.pdf_url LIKE CONCAT('%', #{param.pdfUrl}, '%') + + + AND a.version = #{param.version} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopBrandMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopBrandMapper.xml new file mode 100644 index 0000000..bf5177f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopBrandMapper.xml @@ -0,0 +1,51 @@ + + + + + + + SELECT a.* + FROM shop_brand a + + + AND a.brand_id = #{param.brandId} + + + AND a.brand_name LIKE CONCAT('%', #{param.brandName}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCartMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCartMapper.xml new file mode 100644 index 0000000..318a402 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCartMapper.xml @@ -0,0 +1,84 @@ + + + + + + + SELECT a.* + FROM shop_cart a + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.goods_id LIKE CONCAT('%', #{param.goodsId}, '%') + + + AND a.spec LIKE CONCAT('%', #{param.spec}, '%') + + + AND a.price = #{param.price} + + + AND a.cart_num = #{param.cartNum} + + + AND a.total_price = #{param.totalPrice} + + + AND a.is_pay = #{param.isPay} + + + AND a.is_new = #{param.isNew} + + + AND a.is_show = #{param.isShow} + + + AND a.combination_id = #{param.combinationId} + + + AND a.seckill_id = #{param.seckillId} + + + AND a.bargain_id = #{param.bargainId} + + + AND a.selected = #{param.selected} + + + AND a.merchant_id LIKE CONCAT('%', #{param.merchantId}, '%') + + + AND a.user_id LIKE CONCAT('%', #{param.userId}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCategoryMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCategoryMapper.xml new file mode 100644 index 0000000..e3596c6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCategoryMapper.xml @@ -0,0 +1,123 @@ + + + + + + + SELECT a.* + FROM shop_category a + + + AND a.id = #{param.id} + + + AND a.parent_id = #{param.parentId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.model LIKE CONCAT('%', #{param.model}, '%') + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.component LIKE CONCAT('%', #{param.component}, '%') + + + AND a.target LIKE CONCAT('%', #{param.target}, '%') + + + AND a.icon LIKE CONCAT('%', #{param.icon}, '%') + + + AND a.banner LIKE CONCAT('%', #{param.banner}, '%') + + + AND a.color LIKE CONCAT('%', #{param.color}, '%') + + + AND a.hide = #{param.hide} + + + AND a.permission = #{param.permission} + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.position = #{param.position} + + + AND a.top = #{param.top} + + + AND a.bottom = #{param.bottom} + + + AND a.active LIKE CONCAT('%', #{param.active}, '%') + + + AND a.meta LIKE CONCAT('%', #{param.meta}, '%') + + + AND a.style LIKE CONCAT('%', #{param.style}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.lang LIKE CONCAT('%', #{param.lang}, '%') + + + AND a.home = #{param.home} + + + AND a.recommend = #{param.recommend} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopChatConversationMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopChatConversationMapper.xml new file mode 100644 index 0000000..4f133fc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopChatConversationMapper.xml @@ -0,0 +1,60 @@ + + + + + + + SELECT a.* + FROM shop_chat_conversation a + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.friend_id = #{param.friendId} + + + AND a.type = #{param.type} + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.un_read = #{param.unRead} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopChatMessageMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopChatMessageMapper.xml new file mode 100644 index 0000000..b3c356f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopChatMessageMapper.xml @@ -0,0 +1,78 @@ + + + + + + + SELECT a.*, b.nickname as formUserName, b.avatar as formUserAvatar, b.phone as formUserPhone, b.alias as formUserAlias, + c.nickname as toUserName, c.avatar as toUserAvatar, c.phone as toUserPhone, c.alias as toUserAlias + FROM shop_chat_message a + LEFT JOIN gxwebsoft_core.sys_user b ON a.form_user_id = b.user_id + LEFT JOIN gxwebsoft_core.sys_user c ON a.to_user_id = c.user_id + + + AND a.id = #{param.id} + + + AND a.form_user_id = #{param.formUserId} + + + AND a.to_user_id = #{param.toUserId} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.side_to = #{param.sideTo} + + + AND a.side_from = #{param.sideFrom} + + + AND a.withdraw = #{param.withdraw} + + + AND a.file_info LIKE CONCAT('%', #{param.fileInfo}, '%') + + + AND a.has_contact = #{param.hasContact} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCommissionRoleMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCommissionRoleMapper.xml new file mode 100644 index 0000000..74e6faa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCommissionRoleMapper.xml @@ -0,0 +1,57 @@ + + + + + + + SELECT a.* + FROM shop_commission_role a + + + AND a.id = #{param.id} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.province_id = #{param.provinceId} + + + AND a.city_id = #{param.cityId} + + + AND a.region_id = #{param.regionId} + + + AND a.status = #{param.status} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.sort_number = #{param.sortNumber} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCountMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCountMapper.xml new file mode 100644 index 0000000..78583ae --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCountMapper.xml @@ -0,0 +1,63 @@ + + + + + + + SELECT a.* + FROM shop_count a + + + AND a.id = #{param.id} + + + AND a.date_time LIKE CONCAT('%', #{param.dateTime}, '%') + + + AND a.total_price = #{param.totalPrice} + + + AND a.today_price = #{param.todayPrice} + + + AND a.total_users = #{param.totalUsers} + + + AND a.today_users = #{param.todayUsers} + + + AND a.total_orders = #{param.totalOrders} + + + AND a.today_orders = #{param.todayOrders} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponApplyCateMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponApplyCateMapper.xml new file mode 100644 index 0000000..ef13b35 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponApplyCateMapper.xml @@ -0,0 +1,54 @@ + + + + + + + SELECT a.* + FROM shop_coupon_apply_cate a + + + AND a.id = #{param.id} + + + AND a.coupon_id = #{param.couponId} + + + AND a.cate_id = #{param.cateId} + + + AND a.cate_level = #{param.cateLevel} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponApplyItemMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponApplyItemMapper.xml new file mode 100644 index 0000000..141b156 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponApplyItemMapper.xml @@ -0,0 +1,60 @@ + + + + + + + SELECT a.* + FROM shop_coupon_apply_item a + + + AND a.id = #{param.id} + + + AND a.coupon_id = #{param.couponId} + + + AND a.goods_id = #{param.goodsId} + + + AND a.category_id = #{param.categoryId} + + + AND a.type = #{param.type} + + + AND a.pk = #{param.pk} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponMapper.xml new file mode 100644 index 0000000..6030a91 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopCouponMapper.xml @@ -0,0 +1,103 @@ + + + + + + + SELECT a.*, + COALESCE((SELECT COUNT(*) FROM shop_user_coupon suc WHERE suc.coupon_id = a.id AND suc.deleted = 0), 0) AS receive_num + FROM shop_coupon a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.type = #{param.type} + + + AND a.reduce_price = #{param.reducePrice} + + + AND a.discount = #{param.discount} + + + AND a.min_price = #{param.minPrice} + + + AND a.expire_type = #{param.expireType} + + + AND a.expire_day = #{param.expireDay} + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.apply_range = #{param.applyRange} + + + AND a.apply_range_config LIKE CONCAT('%', #{param.applyRangeConfig}, '%') + + + AND a.is_expire = #{param.isExpire} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.total_count = #{param.totalCount} + + + AND a.issued_count = #{param.issuedCount} + + + AND a.limit_per_user = #{param.limitPerUser} + + + AND a.enabled = #{param.enabled} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerApplyMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerApplyMapper.xml new file mode 100644 index 0000000..809e68a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerApplyMapper.xml @@ -0,0 +1,77 @@ + + + + + + + SELECT a.*, b.nickname as nickName, b.phone, c.nickname as refereeName, d.rate + FROM shop_dealer_apply a + LEFT JOIN gxwebsoft_core.sys_user b ON a.user_id = b.user_id + LEFT JOIN gxwebsoft_core.sys_user c ON a.referee_id = c.user_id + LEFT JOIN shop_dealer_user d ON a.user_id = d.user_id + + + AND a.apply_id = #{param.applyId} + + + AND a.type = #{param.type} + + + AND a.user_id = #{param.userId} + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.mobile LIKE CONCAT('%', #{param.mobile}, '%') + + + AND a.dealer_name LIKE CONCAT('%', #{param.dealerName}, '%') + + + AND a.referee_id = #{param.refereeId} + + + AND a.apply_type = #{param.applyType} + + + AND a.apply_time = #{param.applyTime} + + + AND a.apply_status = #{param.applyStatus} + + + AND a.audit_time = #{param.auditTime} + + + AND a.expiration_time = #{param.expirationTime} + + + AND a.reject_reason LIKE CONCAT('%', #{param.rejectReason}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.mobile = #{param.keywords} + OR a.real_name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.dealer_name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerBankMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerBankMapper.xml new file mode 100644 index 0000000..023b7a2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerBankMapper.xml @@ -0,0 +1,60 @@ + + + + + + + SELECT a.* + FROM shop_dealer_bank a + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.is_default = #{param.isDefault} + + + AND a.bank_name LIKE CONCAT('%', #{param.bankName}, '%') + + + AND a.bank_account LIKE CONCAT('%', #{param.bankAccount}, '%') + + + AND a.bank_card LIKE CONCAT('%', #{param.bankCard}, '%') + + + AND a.apply_status = #{param.applyStatus} + + + AND a.audit_time = #{param.auditTime} + + + AND a.reject_reason LIKE CONCAT('%', #{param.rejectReason}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerCapitalMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerCapitalMapper.xml new file mode 100644 index 0000000..c97f3f0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerCapitalMapper.xml @@ -0,0 +1,57 @@ + + + + + + + SELECT a.*, b.order_no, b.month + FROM shop_dealer_capital a + LEFT JOIN shop_dealer_order b ON a.order_no = b.order_no + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.order_no = #{param.orderNo} + + + AND a.flow_type = #{param.flowType} + + + AND a.money = #{param.money} + + + AND a.to_user_id = #{param.toUserId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND b.month = #{param.month} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.user_id = #{param.keywords} + OR a.order_no = #{param.keywords} + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerOrderMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerOrderMapper.xml new file mode 100644 index 0000000..cf8107c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerOrderMapper.xml @@ -0,0 +1,90 @@ + + + + + + + SELECT a.*, b.nickname, c.nickname AS firstNickname, d.nickname AS secondNickname, e.nickname AS thirdNickname, f.rate, f.price + FROM shop_dealer_order a + LEFT JOIN gxwebsoft_core.sys_user b ON a.user_id = b.user_id + LEFT JOIN gxwebsoft_core.sys_user c ON a.first_user_id = c.user_id + LEFT JOIN gxwebsoft_core.sys_user d ON a.second_user_id = d.user_id + LEFT JOIN gxwebsoft_core.sys_user e ON a.third_user_id = e.user_id + LEFT JOIN shop_dealer_user f ON a.user_id = f.user_id + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND ( a.user_id = #{param.resourceId} OR a.first_user_id = #{param.resourceId} OR a.second_user_id = #{param.resourceId} ) + + + AND a.month = #{param.month} + + + AND a.order_no = #{param.orderNo} + + + AND a.order_price = #{param.orderPrice} + + + AND a.first_user_id = #{param.firstUserId} + + + AND a.second_user_id = #{param.secondUserId} + + + AND a.third_user_id = #{param.thirdUserId} + + + AND a.first_money = #{param.firstMoney} + + + AND a.second_money = #{param.secondMoney} + + + AND a.third_money = #{param.thirdMoney} + + + AND a.is_invalid = #{param.isInvalid} + + + AND a.is_settled = #{param.isSettled} + + + AND a.comments = #{param.comments} + + + AND a.settle_time = #{param.settleTime} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.order_no LIKE CONCAT('%', #{param.keywords}, '%') + OR a.title LIKE CONCAT('%', #{param.keywords}, '%') + OR a.user_id = #{param.keywords} + OR a.month = #{param.keywords} + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerRecordMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerRecordMapper.xml new file mode 100644 index 0000000..41c8c3a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerRecordMapper.xml @@ -0,0 +1,63 @@ + + + + + + + SELECT a.* + FROM shop_dealer_record a + + + AND a.id = #{param.id} + + + AND a.parent_id = #{param.parentId} + + + AND a.dealer_id = #{param.dealerId} + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerRefereeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerRefereeMapper.xml new file mode 100644 index 0000000..67b05ed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerRefereeMapper.xml @@ -0,0 +1,58 @@ + + + + + + + SELECT DISTINCT a.*, + d.nickname AS dealerName, + d.avatar AS dealerAvatar, + d.phone AS dealerPhone, + u.nickname, + u.avatar, + u.alias, + u.phone, + u.is_admin as isAdmin + FROM shop_dealer_referee a + INNER JOIN gxwebsoft_core.sys_user d ON a.dealer_id = d.user_id AND d.deleted = 0 + INNER JOIN gxwebsoft_core.sys_user u ON a.user_id = u.user_id AND u.deleted = 0 + + + AND a.id = #{param.id} + + + AND a.dealer_id = #{param.dealerId} + + + AND a.user_id = #{param.userId} + + + AND a.level = #{param.level} + + + AND u.is_admin = 1 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerSettingMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerSettingMapper.xml new file mode 100644 index 0000000..69d68d3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerSettingMapper.xml @@ -0,0 +1,36 @@ + + + + + + + SELECT a.* + FROM shop_dealer_setting a + + + AND a.key = #{param.key} + + + AND a.describe LIKE CONCAT('%', #{param.describe}, '%') + + + AND a.values LIKE CONCAT('%', #{param.values}, '%') + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerUserMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerUserMapper.xml new file mode 100644 index 0000000..44e883e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerUserMapper.xml @@ -0,0 +1,82 @@ + + + + + + + SELECT a.*, b.openid + FROM shop_dealer_user a + LEFT JOIN gxwebsoft_core.sys_user b ON a.user_id = b.user_id + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.user_id = #{param.userId} + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.mobile LIKE CONCAT('%', #{param.mobile}, '%') + + + AND a.pay_password LIKE CONCAT('%', #{param.payPassword}, '%') + + + AND a.money = #{param.money} + + + AND a.freeze_money = #{param.freezeMoney} + + + AND a.total_money = #{param.totalMoney} + + + AND a.referee_id = #{param.refereeId} + + + AND a.first_num = #{param.firstNum} + + + AND a.second_num = #{param.secondNum} + + + AND a.third_num = #{param.thirdNum} + + + AND a.qrcode LIKE CONCAT('%', #{param.qrcode}, '%') + + + AND a.is_delete = #{param.isDelete} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.sort_number = #{param.sortNumber} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerWithdrawMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerWithdrawMapper.xml new file mode 100644 index 0000000..767ee27 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopDealerWithdrawMapper.xml @@ -0,0 +1,75 @@ + + + + + + + SELECT a.*, b.nickname, b.phone AS phone, b.avatar,b.openid,b.office_openid, c.real_name as realName + FROM shop_dealer_withdraw a + LEFT JOIN gxwebsoft_core.sys_user b ON a.user_id = b.user_id + LEFT JOIN gxwebsoft_core.sys_user_verify c ON a.user_id = c.user_id AND c.status = 1 + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.money = #{param.money} + + + AND a.pay_type = #{param.payType} + + + AND a.alipay_name LIKE CONCAT('%', #{param.alipayName}, '%') + + + AND a.alipay_account LIKE CONCAT('%', #{param.alipayAccount}, '%') + + + AND a.bank_name LIKE CONCAT('%', #{param.bankName}, '%') + + + AND a.bank_account LIKE CONCAT('%', #{param.bankAccount}, '%') + + + AND a.bank_card LIKE CONCAT('%', #{param.bankCard}, '%') + + + AND a.apply_status = #{param.applyStatus} + + + AND a.audit_time = #{param.auditTime} + + + AND a.reject_reason LIKE CONCAT('%', #{param.rejectReason}, '%') + + + AND a.platform LIKE CONCAT('%', #{param.platform}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.user_id = #{param.keywords} + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressMapper.xml new file mode 100644 index 0000000..100e558 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressMapper.xml @@ -0,0 +1,57 @@ + + + + + + + SELECT a.* + FROM shop_express a + + + AND a.express_id = #{param.expressId} + + + AND a.express_name LIKE CONCAT('%', #{param.expressName}, '%') + + + AND a.wx_code LIKE CONCAT('%', #{param.wxCode}, '%') + + + AND a.kuaidi100_code LIKE CONCAT('%', #{param.kuaidi100Code}, '%') + + + AND a.kdniao_code LIKE CONCAT('%', #{param.kdniaoCode}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressTemplateDetailMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressTemplateDetailMapper.xml new file mode 100644 index 0000000..867265d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressTemplateDetailMapper.xml @@ -0,0 +1,72 @@ + + + + + + + SELECT a.* + FROM shop_express_template_detail a + + + AND a.id = #{param.id} + + + AND a.template_id = #{param.templateId} + + + AND a.type = #{param.type} + + + AND a.province_id = #{param.provinceId} + + + AND a.city_id = #{param.cityId} + + + AND a.first_num = #{param.firstNum} + + + AND a.first_amount = #{param.firstAmount} + + + AND a.extra_amount = #{param.extraAmount} + + + AND a.extra_num = #{param.extraNum} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.sort_number = #{param.sortNumber} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressTemplateMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressTemplateMapper.xml new file mode 100644 index 0000000..a0b1784 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopExpressTemplateMapper.xml @@ -0,0 +1,66 @@ + + + + + + + SELECT a.* + FROM shop_express_template a + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.first_amount = #{param.firstAmount} + + + AND a.extra_amount = #{param.extraAmount} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.first_num = #{param.firstNum} + + + AND a.extra_num = #{param.extraNum} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGiftMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGiftMapper.xml new file mode 100644 index 0000000..b2f0569 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGiftMapper.xml @@ -0,0 +1,77 @@ + + + + + + + SELECT a.*,b.name as goodsName, b.price as faceValue, b.image as goodsImage,c.nickname, u.nickname as operatorUserName + FROM shop_gift a + LEFT JOIN shop_goods b ON a.goods_id = b.goods_id + LEFT JOIN gxwebsoft_core.sys_user c ON a.user_id = c.user_id + LEFT JOIN gxwebsoft_core.sys_user u ON a.operator_user_id = u.user_id + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.goods_id = #{param.goodsId} + + + AND a.take_time LIKE CONCAT('%', #{param.takeTime}, '%') + + + AND a.operator_user_id = #{param.operatorUserId} + + + AND a.is_show = #{param.isShow} + + + AND a.status = #{param.status} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.code = #{param.keywords} + OR a.name LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsCategoryMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsCategoryMapper.xml new file mode 100644 index 0000000..74bf790 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsCategoryMapper.xml @@ -0,0 +1,93 @@ + + + + + + + SELECT a.* + FROM shop_goods_category a + + + AND a.category_id = #{param.categoryId} + + + AND a.category_code LIKE CONCAT('%', #{param.categoryCode}, '%') + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.type = #{param.type} + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.parent_id = #{param.parentId} + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.component LIKE CONCAT('%', #{param.component}, '%') + + + AND a.page_id = #{param.pageId} + + + AND a.user_id = #{param.userId} + + + AND a.count = #{param.count} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.hide = #{param.hide} + + + AND a.recommend = #{param.recommend} + + + AND a.show_index = #{param.showIndex} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsCommentMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsCommentMapper.xml new file mode 100644 index 0000000..a6b5545 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsCommentMapper.xml @@ -0,0 +1,96 @@ + + + + + + + SELECT a.* + FROM shop_goods_comment a + + + AND a.id = #{param.id} + + + AND a.uid = #{param.uid} + + + AND a.oid = #{param.oid} + + + AND a.unique LIKE CONCAT('%', #{param.unique}, '%') + + + AND a.goods_id = #{param.goodsId} + + + AND a.reply_type LIKE CONCAT('%', #{param.replyType}, '%') + + + AND a.goods_score = #{param.goodsScore} + + + AND a.service_score = #{param.serviceScore} + + + AND a.comment LIKE CONCAT('%', #{param.comment}, '%') + + + AND a.pics LIKE CONCAT('%', #{param.pics}, '%') + + + AND a.merchant_reply_content LIKE CONCAT('%', #{param.merchantReplyContent}, '%') + + + AND a.merchant_reply_time = #{param.merchantReplyTime} + + + AND a.is_del = #{param.isDel} + + + AND a.is_reply = #{param.isReply} + + + AND a.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + AND a.avatar LIKE CONCAT('%', #{param.avatar}, '%') + + + AND a.sku LIKE CONCAT('%', #{param.sku}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsIncomeConfigMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsIncomeConfigMapper.xml new file mode 100644 index 0000000..8819d02 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsIncomeConfigMapper.xml @@ -0,0 +1,63 @@ + + + + + + + SELECT a.* + FROM shop_goods_income_config a + + + AND a.id = #{param.id} + + + AND a.goods_id = #{param.goodsId} + + + AND a.merchant_shop_type LIKE CONCAT('%', #{param.merchantShopType}, '%') + + + AND a.sku_id = #{param.skuId} + + + AND a.rate = #{param.rate} + + + AND a.user_id = #{param.userId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsLogMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsLogMapper.xml new file mode 100644 index 0000000..4d24262 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsLogMapper.xml @@ -0,0 +1,81 @@ + + + + + + + SELECT a.* + FROM shop_goods_log a + + + AND a.id = #{param.id} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.goods_id = #{param.goodsId} + + + AND a.visit_num = #{param.visitNum} + + + AND a.cart_num = #{param.cartNum} + + + AND a.order_num = #{param.orderNum} + + + AND a.pay_num = #{param.payNum} + + + AND a.pay_price = #{param.payPrice} + + + AND a.cost_price = #{param.costPrice} + + + AND a.pay_uid = #{param.payUid} + + + AND a.refund_num = #{param.refundNum} + + + AND a.refund_price = #{param.refundPrice} + + + AND a.collect_num = #{param.collectNum} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.status = #{param.status} + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsMapper.xml new file mode 100644 index 0000000..bb91f03 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsMapper.xml @@ -0,0 +1,150 @@ + + + + + + + SELECT a.* + FROM shop_goods a + + + AND a.goods_id = #{param.goodsId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.code LIKE CONCAT('%', #{param.code}, '%') + + + AND a.type = #{param.type} + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.parent_id = #{param.parentId} + + + AND a.category_id = #{param.categoryId} + + + AND a.path LIKE CONCAT('%', #{param.path}, '%') + + + AND a.tag LIKE CONCAT('%', #{param.tag}, '%') + + + AND a.specs = #{param.specs} + + + AND a.position LIKE CONCAT('%', #{param.position}, '%') + + + AND a.unit_name LIKE CONCAT('%', #{param.unitName}, '%') + + + AND a.price = #{param.price} + + + AND a.buying_price = #{param.buyingPrice} + + + AND a.dealer_price = #{param.dealerPrice} + + + AND a.deduct_stock_type = #{param.deductStockType} + + + AND a.delivery_method = #{param.deliveryMethod} + + + AND a.duration_method = #{param.durationMethod} + + + AND a.can_buy_number = #{param.canBuyNumber} + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.sales = #{param.sales} + + + AND a.stock = #{param.stock} + + + AND a.install = #{param.install} + + + AND a.rate = #{param.rate} + + + AND a.gain_integral = #{param.gainIntegral} + + + AND a.recommend = #{param.recommend} + + + AND a.official = #{param.official} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.is_show = #{param.isShow} + + + AND a.status = #{param.status} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + AND a.status = 0 + + + AND a.status != 0 + + + AND a.stock = 0 + + + + AND (a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsRelationMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsRelationMapper.xml new file mode 100644 index 0000000..063a2a8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsRelationMapper.xml @@ -0,0 +1,48 @@ + + + + + + + SELECT a.* + FROM shop_goods_relation a + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.goods_id = #{param.goodsId} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.category LIKE CONCAT('%', #{param.category}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsRoleCommissionMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsRoleCommissionMapper.xml new file mode 100644 index 0000000..a0cb44a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsRoleCommissionMapper.xml @@ -0,0 +1,57 @@ + + + + + + + SELECT a.* + FROM shop_goods_role_commission a + + + AND a.id = #{param.id} + + + AND a.role_id = #{param.roleId} + + + AND a.goods_id = #{param.goodsId} + + + AND a.sku LIKE CONCAT('%', #{param.sku}, '%') + + + AND a.amount = #{param.amount} + + + AND a.status = #{param.status} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.sort_number = #{param.sortNumber} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsSkuMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsSkuMapper.xml new file mode 100644 index 0000000..dec4d76 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsSkuMapper.xml @@ -0,0 +1,78 @@ + + + + + + + SELECT a.* + FROM shop_goods_sku a + + + AND a.id = #{param.id} + + + AND a.goods_id = #{param.goodsId} + + + AND a.sku LIKE CONCAT('%', #{param.sku}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.price = #{param.price} + + + AND a.sale_price = #{param.salePrice} + + + AND a.cost = #{param.cost} + + + AND a.stock = #{param.stock} + + + AND a.sku_no LIKE CONCAT('%', #{param.skuNo}, '%') + + + AND a.bar_code LIKE CONCAT('%', #{param.barCode}, '%') + + + AND a.weight = #{param.weight} + + + AND a.volume = #{param.volume} + + + AND a.uuid LIKE CONCAT('%', #{param.uuid}, '%') + + + AND a.status = #{param.status} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsSpecMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsSpecMapper.xml new file mode 100644 index 0000000..aeed405 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopGoodsSpecMapper.xml @@ -0,0 +1,45 @@ + + + + + + + SELECT a.* + FROM shop_goods_spec a + + + AND a.id = #{param.id} + + + AND a.goods_id = #{param.goodsId} + + + AND a.spec_id = #{param.specId} + + + AND a.spec_name LIKE CONCAT('%', #{param.specName}, '%') + + + AND a.spec_value LIKE CONCAT('%', #{param.specValue}, '%') + + + AND a.type = #{param.type} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantAccountMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantAccountMapper.xml new file mode 100644 index 0000000..95280c1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantAccountMapper.xml @@ -0,0 +1,63 @@ + + + + + + + SELECT a.* + FROM shop_merchant_account a + + + AND a.id = #{param.id} + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.merchant_id = #{param.merchantId} + + + AND a.role_id = #{param.roleId} + + + AND a.role_name LIKE CONCAT('%', #{param.roleName}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantApplyMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantApplyMapper.xml new file mode 100644 index 0000000..52b8979 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantApplyMapper.xml @@ -0,0 +1,123 @@ + + + + + + + SELECT a.* + FROM shop_merchant_apply a + + + AND a.apply_id = #{param.applyId} + + + AND a.type = #{param.type} + + + AND a.shop_type LIKE CONCAT('%', #{param.shopType}, '%') + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.category_id = #{param.categoryId} + + + AND a.category LIKE CONCAT('%', #{param.category}, '%') + + + AND a.lng_and_lat LIKE CONCAT('%', #{param.lngAndLat}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.region_id LIKE CONCAT('%', #{param.regionId}, '%') + + + AND a.commission = #{param.commission} + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.yyzz LIKE CONCAT('%', #{param.yyzz}, '%') + + + AND a.sfz1 LIKE CONCAT('%', #{param.sfz1}, '%') + + + AND a.sfz2 LIKE CONCAT('%', #{param.sfz2}, '%') + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.own_store = #{param.ownStore} + + + AND a.recommend = #{param.recommend} + + + AND a.goods_review = #{param.goodsReview} + + + AND a.name2 LIKE CONCAT('%', #{param.name2}, '%') + + + AND a.reason LIKE CONCAT('%', #{param.reason}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantMapper.xml new file mode 100644 index 0000000..66384d5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantMapper.xml @@ -0,0 +1,150 @@ + + + + + + + SELECT a.* + FROM shop_merchant a + + + AND a.merchant_id = #{param.merchantId} + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.type = #{param.type} + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.shop_type LIKE CONCAT('%', #{param.shopType}, '%') + + + AND a.item_type LIKE CONCAT('%', #{param.itemType}, '%') + + + AND a.category LIKE CONCAT('%', #{param.category}, '%') + + + AND a.merchant_category_id = #{param.merchantCategoryId} + + + AND a.merchant_category_title LIKE CONCAT('%', #{param.merchantCategoryTitle}, '%') + + + AND a.lng_and_lat LIKE CONCAT('%', #{param.lngAndLat}, '%') + + + AND a.lng LIKE CONCAT('%', #{param.lng}, '%') + + + AND a.lat LIKE CONCAT('%', #{param.lat}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.commission = #{param.commission} + + + AND a.keywords LIKE CONCAT('%', #{param.keywords}, '%') + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.business_time LIKE CONCAT('%', #{param.businessTime}, '%') + + + AND a.content LIKE CONCAT('%', #{param.content}, '%') + + + AND a.price = #{param.price} + + + AND a.own_store = #{param.ownStore} + + + AND a.can_express = #{param.canExpress} + + + AND a.recommend = #{param.recommend} + + + AND a.is_on = #{param.isOn} + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.goods_review = #{param.goodsReview} + + + AND a.admin_url LIKE CONCAT('%', #{param.adminUrl}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantTypeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantTypeMapper.xml new file mode 100644 index 0000000..0ed4e42 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopMerchantTypeMapper.xml @@ -0,0 +1,48 @@ + + + + + + + SELECT a.* + FROM shop_merchant_type a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderDeliveryGoodsMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderDeliveryGoodsMapper.xml new file mode 100644 index 0000000..949a66f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderDeliveryGoodsMapper.xml @@ -0,0 +1,60 @@ + + + + + + + SELECT a.* + FROM shop_order_delivery_goods a + + + AND a.id = #{param.id} + + + AND a.delivery_id = #{param.deliveryId} + + + AND a.order_id = #{param.orderId} + + + AND a.order_goods_id = #{param.orderGoodsId} + + + AND a.goods_id = #{param.goodsId} + + + AND a.delivery_num = #{param.deliveryNum} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderDeliveryMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderDeliveryMapper.xml new file mode 100644 index 0000000..eb3fd8d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderDeliveryMapper.xml @@ -0,0 +1,63 @@ + + + + + + + SELECT a.* + FROM shop_order_delivery a + + + AND a.delivery_id = #{param.deliveryId} + + + AND a.order_id = #{param.orderId} + + + AND a.delivery_method = #{param.deliveryMethod} + + + AND a.pack_method = #{param.packMethod} + + + AND a.express_id = #{param.expressId} + + + AND a.express_no LIKE CONCAT('%', #{param.expressNo}, '%') + + + AND a.eorder_html LIKE CONCAT('%', #{param.eorderHtml}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderExtractMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderExtractMapper.xml new file mode 100644 index 0000000..ff26857 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderExtractMapper.xml @@ -0,0 +1,57 @@ + + + + + + + SELECT a.* + FROM shop_order_extract a + + + AND a.id = #{param.id} + + + AND a.order_id = #{param.orderId} + + + AND a.linkman LIKE CONCAT('%', #{param.linkman}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderGoodsMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderGoodsMapper.xml new file mode 100644 index 0000000..dd22115 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderGoodsMapper.xml @@ -0,0 +1,105 @@ + + + + + + + SELECT a.* + FROM shop_order_goods a + + + AND a.id = #{param.id} + + + AND a.order_id = #{param.orderId} + + + AND a.order_code LIKE CONCAT('%', #{param.orderCode}, '%') + + + AND a.merchant_id = #{param.merchantId} + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.goods_id = #{param.goodsId} + + + AND a.goods_name LIKE CONCAT('%', #{param.goodsName}, '%') + + + AND a.spec LIKE CONCAT('%', #{param.spec}, '%') + + + AND a.sku_id = #{param.skuId} + + + AND a.price = #{param.price} + + + AND a.total_num = #{param.totalNum} + + + AND a.pay_status = #{param.payStatus} + + + AND a.order_status = #{param.orderStatus} + + + AND a.is_free = #{param.isFree} + + + AND a.version = #{param.version} + + + AND a.time_period LIKE CONCAT('%', #{param.timePeriod}, '%') + + + AND a.date_time LIKE CONCAT('%', #{param.dateTime}, '%') + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.time_flag LIKE CONCAT('%', #{param.timeFlag}, '%') + + + AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderInfoLogMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderInfoLogMapper.xml new file mode 100644 index 0000000..0dde816 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderInfoLogMapper.xml @@ -0,0 +1,48 @@ + + + + + + + SELECT a.* + FROM shop_order_info_log a + + + AND a.id = #{param.id} + + + AND a.order_id = #{param.orderId} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.field_id = #{param.fieldId} + + + AND a.use_num = #{param.useNum} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderInfoMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderInfoMapper.xml new file mode 100644 index 0000000..b2e0149 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderInfoMapper.xml @@ -0,0 +1,114 @@ + + + + + + + SELECT a.* + FROM shop_order_info a + + + AND a.id = #{param.id} + + + AND a.order_id = #{param.orderId} + + + AND a.order_code LIKE CONCAT('%', #{param.orderCode}, '%') + + + AND a.merchant_id = #{param.merchantId} + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.field_id = #{param.fieldId} + + + AND a.field_name LIKE CONCAT('%', #{param.fieldName}, '%') + + + AND a.price = #{param.price} + + + AND a.children_price = #{param.childrenPrice} + + + AND a.adult_num = #{param.adultNum} + + + AND a.children_num = #{param.childrenNum} + + + AND a.adult_num_use = #{param.adultNumUse} + + + AND a.children_num_use = #{param.childrenNumUse} + + + AND a.pay_status = #{param.payStatus} + + + AND a.order_status = #{param.orderStatus} + + + AND a.is_free = #{param.isFree} + + + AND a.is_children = #{param.isChildren} + + + AND a.version = #{param.version} + + + AND a.is_half = #{param.isHalf} + + + AND a.time_period LIKE CONCAT('%', #{param.timePeriod}, '%') + + + AND a.date_time LIKE CONCAT('%', #{param.dateTime}, '%') + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.time_flag LIKE CONCAT('%', #{param.timeFlag}, '%') + + + AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml new file mode 100644 index 0000000..f728715 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopOrderMapper.xml @@ -0,0 +1,428 @@ + + + + + + + SELECT a.*,b.nickname, b.avatar,b.phone as phone + FROM shop_order a + LEFT JOIN gxwebsoft_core.sys_user b ON a.user_id = b.user_id + + + AND a.order_id = #{param.orderId} + + + AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%') + + + AND a.type = #{param.type} + + + AND a.delivery_type = #{param.deliveryType} + + + AND a.channel = #{param.channel} + + + AND a.transaction_id LIKE CONCAT('%', #{param.transactionId}, '%') + + + AND a.refund_order LIKE CONCAT('%', #{param.refundOrder}, '%') + + + AND a.merchant_id = #{param.merchantId} + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.coupon_id = #{param.couponId} + + + AND a.card_id LIKE CONCAT('%', #{param.cardId}, '%') + + + AND a.admin_id = #{param.adminId} + + + AND a.confirm_id = #{param.confirmId} + + + AND a.ic_card LIKE CONCAT('%', #{param.icCard}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND b.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND b.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + AND a.address_id = #{param.addressId} + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.address_lat LIKE CONCAT('%', #{param.addressLat}, '%') + + + AND a.address_lng LIKE CONCAT('%', #{param.addressLng}, '%') + + + AND a.self_take_merchant_id = #{param.selfTakeMerchantId} + + + AND a.self_take_merchant_name LIKE CONCAT('%', #{param.selfTakeMerchantName}, '%') + + + AND a.send_start_time LIKE CONCAT('%', #{param.sendStartTime}, '%') + + + AND a.send_end_time LIKE CONCAT('%', #{param.sendEndTime}, '%') + + + AND a.express_merchant_id = #{param.expressMerchantId} + + + AND a.express_merchant_name LIKE CONCAT('%', #{param.expressMerchantName}, '%') + + + AND a.total_price = #{param.totalPrice} + + + AND a.reduce_price = #{param.reducePrice} + + + AND a.pay_price = #{param.payPrice} + + + AND a.price = #{param.price} + + + AND a.money = #{param.money} + + + AND a.refund_money = #{param.refundMoney} + + + AND a.coach_price = #{param.coachPrice} + + + AND a.total_num = #{param.totalNum} + + + AND a.coach_id = #{param.coachId} + + + AND a.pay_user_id = #{param.payUserId} + + + AND a.pay_type = #{param.payType} + + + AND a.friend_pay_type = #{param.friendPayType} + + + AND a.pay_status = #{param.payStatus} + + + AND a.order_status = #{param.orderStatus} + + + AND a.delivery_status = #{param.deliveryStatus} + + + AND a.delivery_time LIKE CONCAT('%', #{param.deliveryTime}, '%') + + + AND a.coupon_type = #{param.couponType} + + + AND a.coupon_desc LIKE CONCAT('%', #{param.couponDesc}, '%') + + + AND a.qrcode LIKE CONCAT('%', #{param.qrcode}, '%') + + + AND a.return_num = #{param.returnNum} + + + AND a.return_money = #{param.returnMoney} + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.is_invoice = #{param.isInvoice} + + + AND a.invoice_no LIKE CONCAT('%', #{param.invoiceNo}, '%') + + + AND a.pay_time LIKE CONCAT('%', #{param.payTime}, '%') + + + AND a.refund_time LIKE CONCAT('%', #{param.refundTime}, '%') + + + AND a.refund_apply_time LIKE CONCAT('%', #{param.refundApplyTime}, '%') + + + AND a.expiration_time LIKE CONCAT('%', #{param.expirationTime}, '%') + + + AND a.check_bill = #{param.checkBill} + + + AND a.is_settled = #{param.isSettled} + + + AND a.version = #{param.version} + + + AND a.user_id = #{param.userId} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.self_take_code LIKE CONCAT('%', #{param.selfTakeCode}, '%') + + + AND a.has_take_gift = #{param.hasTakeGift} + + + AND (a.order_no LIKE CONCAT('%', #{param.keywords}, '%') + OR a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.order_id = #{param.keywords} + OR b.phone = #{param.keywords} + OR b.phone = #{param.keywords} + OR b.nickname LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + AND a.order_status != 2 + + + + + + AND a.pay_status = 0 AND a.order_status = 0 + + + + AND a.pay_status = 1 AND a.delivery_status = 10 AND a.order_status = 0 + + + + AND a.pay_status = 1 AND a.order_status = 0 + + + + AND a.delivery_status = 20 AND a.order_status != 1 + + + + AND a.order_status = 1 AND a.evaluate_status = 0 + + + + AND a.order_status = 1 + + + + AND (a.order_status = 4 OR a.order_status = 5 OR a.order_status = 6 OR a.order_status = 7) + + + + AND a.deleted = 1 + + + + AND a.order_status = 2 + + + + AND a.create_time BETWEEN DATE_SUB(CURDATE(), INTERVAL 3 MONTH) AND CURDATE() + + + + + + + + + + + + + + + + + UPDATE shop_order + + + pay_type = #{param.payType}, + + + pay_status = #{param.payStatus}, + + + order_status = #{param.orderStatus}, + + + delivery_status = #{param.deliveryStatus}, + + + delivery_time = #{param.deliveryTime}, + + + pay_time = #{param.payTime}, + + + refund_time = #{param.refundTime}, + + + self_take_code = #{param.selfTakeCode}, + + + invoice_no = #{param.invoiceNo}, + + + is_invoice = #{param.isInvoice}, + + + start_time = #{param.startTime}, + + + qrcode = #{param.qrcode}, + + + pay_user_id = #{param.payUserId}, + + + form_id = #{param.formId}, + + + total_price = #{param.totalPrice}, + + + reduce_price = #{param.reducePrice}, + + + pay_price = #{param.payPrice}, + + + price = #{param.price}, + + + money = #{param.money}, + + + refund_money = #{param.refundMoney}, + + + total_num = #{param.totalNum}, + + + coach_id = #{param.coachId}, + + + express_merchant_id = #{param.expressMerchantId}, + + + express_merchant_name = #{param.expressMerchantName}, + + + send_start_time = #{param.sendStartTime}, + + + send_end_time = #{param.sendEndTime}, + + + self_take_merchant_id = #{param.selfTakeMerchantId}, + + + self_take_merchant_name = #{param.selfTakeMerchantName}, + + + address_id = #{param.addressId}, + + + address = #{param.address}, + + + confirm_id = #{param.confirmId}, + + + ic_card = #{param.icCard}, + + + admin_id = #{param.adminId}, + + + card_id = #{param.cardId}, + + + coupon_id = #{param.couponId}, + + + merchant_id = #{param.merchantId}, + + + transaction_id = #{param.transactionId}, + + + refund_order = #{param.refundOrder}, + + + channel = #{param.channel}, + + + delivery_type = #{param.deliveryType}, + + + `type` = #{param.type}, + + + deleted = #{param.deleted}, + + + deleted = 0, + + + + order_no = #{param.orderNo} + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopRechargeOrderMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopRechargeOrderMapper.xml new file mode 100644 index 0000000..3ed8037 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopRechargeOrderMapper.xml @@ -0,0 +1,99 @@ + + + + + + + SELECT a.* + FROM shop_recharge_order a + + + AND a.order_id = #{param.orderId} + + + AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%') + + + AND a.user_id = #{param.userId} + + + AND a.recharge_type = #{param.rechargeType} + + + AND a.organization_id = #{param.organizationId} + + + AND a.plan_id = #{param.planId} + + + AND a.pay_price = #{param.payPrice} + + + AND a.gift_money = #{param.giftMoney} + + + AND a.actual_money = #{param.actualMoney} + + + AND a.balance = #{param.balance} + + + AND a.pay_method LIKE CONCAT('%', #{param.payMethod}, '%') + + + AND a.pay_status = #{param.payStatus} + + + AND a.pay_time = #{param.payTime} + + + AND a.trade_id = #{param.tradeId} + + + AND a.platform LIKE CONCAT('%', #{param.platform}, '%') + + + AND a.shop_id = #{param.shopId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSpecMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSpecMapper.xml new file mode 100644 index 0000000..9081159 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSpecMapper.xml @@ -0,0 +1,60 @@ + + + + + + + SELECT a.* + FROM shop_spec a + + + AND a.spec_id = #{param.specId} + + + AND a.spec_name LIKE CONCAT('%', #{param.specName}, '%') + + + AND a.spec_value LIKE CONCAT('%', #{param.specValue}, '%') + + + AND a.merchant_id = #{param.merchantId} + + + AND a.user_id = #{param.userId} + + + AND a.updater = #{param.updater} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSpecValueMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSpecValueMapper.xml new file mode 100644 index 0000000..0543252 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSpecValueMapper.xml @@ -0,0 +1,48 @@ + + + + + + + SELECT a.* + FROM shop_spec_value a + + + AND a.spec_value_id = #{param.specValueId} + + + AND a.spec_id = #{param.specId} + + + AND a.spec_value LIKE CONCAT('%', #{param.specValue}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSplashMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSplashMapper.xml new file mode 100644 index 0000000..bac8517 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopSplashMapper.xml @@ -0,0 +1,63 @@ + + + + + + + SELECT a.* + FROM shop_splash a + + + AND a.id = #{param.id} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.jump_type LIKE CONCAT('%', #{param.jumpType}, '%') + + + AND a.jump_pk = #{param.jumpPk} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.sort_number = #{param.sortNumber} + + + AND a.user_id = #{param.userId} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserAddressMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserAddressMapper.xml new file mode 100644 index 0000000..37b630f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserAddressMapper.xml @@ -0,0 +1,82 @@ + + + + + + + SELECT a.* + FROM shop_user_address a + + + AND a.id = #{param.id} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.country LIKE CONCAT('%', #{param.country}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.full_address LIKE CONCAT('%', #{param.fullAddress}, '%') + + + AND a.lat LIKE CONCAT('%', #{param.lat}, '%') + + + AND a.lng LIKE CONCAT('%', #{param.lng}, '%') + + + AND a.gender = #{param.gender} + + + AND a.type LIKE CONCAT('%', #{param.type}, '%') + + + AND a.is_default = #{param.isDefault} + + + AND a.user_id = #{param.userId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.phone = #{param.keywords} + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserBalanceLogMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserBalanceLogMapper.xml new file mode 100644 index 0000000..5ad4a74 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserBalanceLogMapper.xml @@ -0,0 +1,78 @@ + + + + + + + SELECT a.* + FROM shop_user_balance_log a + + + AND a.log_id = #{param.logId} + + + AND a.user_id = #{param.userId} + + + AND a.scene = #{param.scene} + + + AND a.money = #{param.money} + + + AND a.balance = #{param.balance} + + + AND a.remark LIKE CONCAT('%', #{param.remark}, '%') + + + AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%') + + + AND a.admin_id = #{param.adminId} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.merchant_id = #{param.merchantId} + + + AND a.merchant_code LIKE CONCAT('%', #{param.merchantCode}, '%') + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCollectionMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCollectionMapper.xml new file mode 100644 index 0000000..98782e2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCollectionMapper.xml @@ -0,0 +1,45 @@ + + + + + + + SELECT a.* + FROM shop_user_collection a + + + AND a.id = #{param.id} + + + AND a.type = #{param.type} + + + AND a.tid = #{param.tid} + + + AND a.user_id = #{param.userId} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCouponMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCouponMapper.xml new file mode 100644 index 0000000..48eaee5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserCouponMapper.xml @@ -0,0 +1,96 @@ + + + + + + + SELECT a.* + FROM shop_user_coupon a + + + AND a.id = #{param.id} + + + AND a.coupon_id = #{param.couponId} + + + AND a.user_id = #{param.userId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.description LIKE CONCAT('%', #{param.description}, '%') + + + AND a.type = #{param.type} + + + AND a.reduce_price = #{param.reducePrice} + + + AND a.discount = #{param.discount} + + + AND a.min_price = #{param.minPrice} + + + AND a.apply_range = #{param.applyRange} + + + AND a.apply_range_config LIKE CONCAT('%', #{param.applyRangeConfig}, '%') + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.status = #{param.status} + + + AND a.use_time LIKE CONCAT('%', #{param.useTime}, '%') + + + AND a.order_id LIKE CONCAT('%', #{param.orderId}, '%') + + + AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%') + + + AND a.obtain_type = #{param.obtainType} + + + AND a.obtain_source LIKE CONCAT('%', #{param.obtainSource}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserMapper.xml new file mode 100644 index 0000000..0ccbb57 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserMapper.xml @@ -0,0 +1,252 @@ + + + + + + + SELECT a.* + FROM shop_user a + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.type = #{param.type} + + + AND a.username LIKE CONCAT('%', #{param.username}, '%') + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.nickname LIKE CONCAT('%', #{param.nickname}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.sex = #{param.sex} + + + AND a.position LIKE CONCAT('%', #{param.position}, '%') + + + AND a.platform LIKE CONCAT('%', #{param.platform}, '%') + + + AND a.email LIKE CONCAT('%', #{param.email}, '%') + + + AND a.email_verified = #{param.emailVerified} + + + AND a.alias LIKE CONCAT('%', #{param.alias}, '%') + + + AND a.real_name LIKE CONCAT('%', #{param.realName}, '%') + + + AND a.id_card LIKE CONCAT('%', #{param.idCard}, '%') + + + AND a.birthday LIKE CONCAT('%', #{param.birthday}, '%') + + + AND a.country LIKE CONCAT('%', #{param.country}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%') + + + AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%') + + + AND a.balance = #{param.balance} + + + AND a.cashed_money = #{param.cashedMoney} + + + AND a.points = #{param.points} + + + AND a.pay_money = #{param.payMoney} + + + AND a.expend_money = #{param.expendMoney} + + + AND a.pay_password LIKE CONCAT('%', #{param.payPassword}, '%') + + + AND a.grade_id = #{param.gradeId} + + + AND a.category LIKE CONCAT('%', #{param.category}, '%') + + + AND a.introduction LIKE CONCAT('%', #{param.introduction}, '%') + + + AND a.organization_id = #{param.organizationId} + + + AND a.group_id = #{param.groupId} + + + AND a.avatar LIKE CONCAT('%', #{param.avatar}, '%') + + + AND a.bg_image LIKE CONCAT('%', #{param.bgImage}, '%') + + + AND a.user_code LIKE CONCAT('%', #{param.userCode}, '%') + + + AND a.certification = #{param.certification} + + + AND a.age = #{param.age} + + + AND a.offline = #{param.offline} + + + AND a.followers = #{param.followers} + + + AND a.fans = #{param.fans} + + + AND a.likes = #{param.likes} + + + AND a.comment_numbers = #{param.commentNumbers} + + + AND a.recommend = #{param.recommend} + + + AND a.openid LIKE CONCAT('%', #{param.openid}, '%') + + + AND a.office_openid LIKE CONCAT('%', #{param.officeOpenid}, '%') + + + AND a.unionid LIKE CONCAT('%', #{param.unionid}, '%') + + + AND a.client_id LIKE CONCAT('%', #{param.clientId}, '%') + + + AND a.not_allow_vip = #{param.notAllowVip} + + + AND a.is_admin = #{param.isAdmin} + + + AND a.is_organization_admin = #{param.isOrganizationAdmin} + + + AND a.login_num = #{param.loginNum} + + + AND a.company_id = #{param.companyId} + + + AND a.merchants LIKE CONCAT('%', #{param.merchants}, '%') + + + AND a.merchant_id = #{param.merchantId} + + + AND a.merchant_name LIKE CONCAT('%', #{param.merchantName}, '%') + + + AND a.merchant_avatar LIKE CONCAT('%', #{param.merchantAvatar}, '%') + + + AND a.uid = #{param.uid} + + + AND a.expert_type = #{param.expertType} + + + AND a.expire_time = #{param.expireTime} + + + AND a.settlement_time LIKE CONCAT('%', #{param.settlementTime}, '%') + + + AND a.aptitude LIKE CONCAT('%', #{param.aptitude}, '%') + + + AND a.industry_parent LIKE CONCAT('%', #{param.industryParent}, '%') + + + AND a.industry_child LIKE CONCAT('%', #{param.industryChild}, '%') + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.template_id = #{param.templateId} + + + AND a.installed = #{param.installed} + + + AND a.speciality LIKE CONCAT('%', #{param.speciality}, '%') + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserRefereeMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserRefereeMapper.xml new file mode 100644 index 0000000..3a1d993 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserRefereeMapper.xml @@ -0,0 +1,62 @@ + + + + + + + SELECT a.*, + d.nickname AS dealerName, + d.avatar AS dealerAvatar, + d.phone AS dealerPhone, + u.nickname, + u.avatar, + u.phone + FROM shop_user_referee a + LEFT JOIN gxwebsoft_core.sys_user d ON a.dealer_id = d.user_id + LEFT JOIN gxwebsoft_core.sys_user u ON a.user_id = u.user_id + + + AND a.id = #{param.id} + + + AND a.dealer_id = #{param.dealerId} + + + AND a.user_id = #{param.userId} + + + AND a.level = #{param.level} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopWechatDepositMapper.xml b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopWechatDepositMapper.xml new file mode 100644 index 0000000..9840d34 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopWechatDepositMapper.xml @@ -0,0 +1,69 @@ + + + + + + + SELECT a.* + FROM shop_wechat_deposit a + + + AND a.id = #{param.id} + + + AND a.oid = #{param.oid} + + + AND a.uid = #{param.uid} + + + AND a.order_num LIKE CONCAT('%', #{param.orderNum}, '%') + + + AND a.wechat_order LIKE CONCAT('%', #{param.wechatOrder}, '%') + + + AND a.wechat_return LIKE CONCAT('%', #{param.wechatReturn}, '%') + + + AND a.site_name LIKE CONCAT('%', #{param.siteName}, '%') + + + AND a.username LIKE CONCAT('%', #{param.username}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.price = #{param.price} + + + AND a.status = #{param.status} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java new file mode 100644 index 0000000..3aceda1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java @@ -0,0 +1,203 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品文章查询参数 + * + * @author 科技小王子 + * @since 2025-08-13 05:14:52 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopArticleParam对象", description = "商品文章查询参数") +public class ShopArticleParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章ID") + @QueryField(type = QueryType.EQ) + private Integer articleId; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章类型 0常规 1视频") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "模型") + private String model; + + @Schema(description = "详情页模板") + private String detail; + + @Schema(description = "文章分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "话题") + private String topic; + + @Schema(description = "标签") + private String tags; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "封面图宽") + @QueryField(type = QueryType.EQ) + private Integer imageWidth; + + @Schema(description = "封面图高") + @QueryField(type = QueryType.EQ) + private Integer imageHeight; + + @Schema(description = "付费金额") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "开始时间") + private String startTime; + + @Schema(description = "结束时间") + private String endTime; + + @Schema(description = "来源") + private String source; + + @Schema(description = "产品概述") + private String overview; + + @Schema(description = "虚拟阅读量(仅用作展示)") + @QueryField(type = QueryType.EQ) + private Integer virtualViews; + + @Schema(description = "实际阅读量") + @QueryField(type = QueryType.EQ) + private Integer actualViews; + + @Schema(description = "评分") + @QueryField(type = QueryType.EQ) + private BigDecimal rate; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + @QueryField(type = QueryType.EQ) + private Integer showType; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + @QueryField(type = QueryType.EQ) + private Integer permission; + + @Schema(description = "发布来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "文章附件") + private String files; + + @Schema(description = "视频地址") + private String video; + + @Schema(description = "接受的文件类型") + private String accept; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "点赞数") + @QueryField(type = QueryType.EQ) + private Integer likes; + + @Schema(description = "评论数") + @QueryField(type = QueryType.EQ) + private Integer commentNumbers; + + @Schema(description = "提醒谁看") + private String toUsers; + + @Schema(description = "作者") + private String author; + + @Schema(description = "推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "报名人数") + @QueryField(type = QueryType.EQ) + private Integer bmUsers; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "项目ID") + @QueryField(type = QueryType.EQ) + private Integer projectId; + + @Schema(description = "语言") + private String lang; + + @Schema(description = "关联默认语言的文章ID") + @QueryField(type = QueryType.EQ) + private Integer langArticleId; + + @Schema(description = "是否自动翻译") + @QueryField(type = QueryType.EQ) + private Boolean translation; + + @Schema(description = "编辑器类型 0 Markdown编辑器 1 富文本编辑器 ") + @QueryField(type = QueryType.EQ) + private Boolean editor; + + @Schema(description = "pdf文件地址") + private String pdfUrl; + + @Schema(description = "版本号") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopBrandParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopBrandParam.java new file mode 100644 index 0000000..a559c61 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopBrandParam.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 品牌查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopBrandParam对象", description = "品牌查询参数") +public class ShopBrandParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer brandId; + + @Schema(description = "品牌名称") + private String brandName; + + @Schema(description = "图标") + private String image; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCartParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCartParam.java new file mode 100644 index 0000000..f21eb48 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCartParam.java @@ -0,0 +1,95 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 购物车查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCartParam对象", description = "购物车查询参数") +public class ShopCartParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "购物车表ID") + @QueryField(type = QueryType.EQ) + private Long id; + + @Schema(description = "类型 0商城 1外卖") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "唯一标识") + private String code; + + @Schema(description = "商品ID") + private Long goodsId; + + @Schema(description = "商品SKU ID") + @QueryField(type = QueryType.EQ) + private Integer skuId; + + @Schema(description = "商品规格") + private String spec; + + @Schema(description = "规格信息,如:颜色:红色|尺寸:L") + private String specInfo; + + @Schema(description = "商品价格") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "商品数量") + @QueryField(type = QueryType.EQ) + private Integer cartNum; + + @Schema(description = "单商品合计") + @QueryField(type = QueryType.EQ) + private BigDecimal totalPrice; + + @Schema(description = "0 = 未购买 1 = 已购买") + @QueryField(type = QueryType.EQ) + private Boolean isPay; + + @Schema(description = "是否为立即购买") + @QueryField(type = QueryType.EQ) + private Boolean isNew; + + @Schema(description = "是否为立即购买") + @QueryField(type = QueryType.EQ) + private Boolean isShow; + + @Schema(description = "拼团id") + @QueryField(type = QueryType.EQ) + private Integer combinationId; + + @Schema(description = "秒杀产品ID") + @QueryField(type = QueryType.EQ) + private Integer seckillId; + + @Schema(description = "砍价id") + @QueryField(type = QueryType.EQ) + private Integer bargainId; + + @Schema(description = "是否选中") + @QueryField(type = QueryType.EQ) + private Boolean selected; + + @Schema(description = "商户ID") + private Long merchantId; + + @Schema(description = "用户ID") + private Long userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCategoryParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCategoryParam.java new file mode 100644 index 0000000..4ad7f2a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCategoryParam.java @@ -0,0 +1,126 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品分类查询参数 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCategoryParam对象", description = "商品分类查询参数") +public class ShopCategoryParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "菜单名称") + private String title; + + @Schema(description = "模型") + private String model; + + @Schema(description = "标识") + private String code; + + @Schema(description = "链接地址") + private String path; + + @Schema(description = "组件地址") + private String component; + + @Schema(description = "打开位置") + private String target; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "banner") + private String banner; + + @Schema(description = "图标颜色") + private String color; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + @QueryField(type = QueryType.EQ) + private Integer permission; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "位置 0不限 1顶部 2底部") + @QueryField(type = QueryType.EQ) + private Integer position; + + @Schema(description = "仅在顶部显示") + @QueryField(type = QueryType.EQ) + private Integer top; + + @Schema(description = "仅在底部显示") + @QueryField(type = QueryType.EQ) + private Integer bottom; + + @Schema(description = "菜单选中的path") + private String active; + + @Schema(description = "其它路由元信息") + private String meta; + + @Schema(description = "css样式") + private String style; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "语言") + private String lang; + + @Schema(description = "设为首页") + @QueryField(type = QueryType.EQ) + private Integer home; + + @Schema(description = "推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopChatConversationParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopChatConversationParam.java new file mode 100644 index 0000000..6dcbd1b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopChatConversationParam.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 聊天消息表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopChatConversationParam对象", description = "聊天消息表查询参数") +public class ShopChatConversationParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "好友ID") + @QueryField(type = QueryType.EQ) + private Integer friendId; + + @Schema(description = "消息类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "未读消息") + @QueryField(type = QueryType.EQ) + private Integer unRead; + + @Schema(description = "状态, 0未读, 1已读") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopChatMessageParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopChatMessageParam.java new file mode 100644 index 0000000..925261b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopChatMessageParam.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 聊天消息表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopChatMessageParam对象", description = "聊天消息表查询参数") +public class ShopChatMessageParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "发送人ID") + @QueryField(type = QueryType.EQ) + private Integer formUserId; + + @Schema(description = "接收人ID") + @QueryField(type = QueryType.EQ) + private Integer toUserId; + + @Schema(description = "消息类型") + private String type; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "屏蔽接收方") + @QueryField(type = QueryType.EQ) + private Integer sideTo; + + @Schema(description = "屏蔽发送方") + @QueryField(type = QueryType.EQ) + private Integer sideFrom; + + @Schema(description = "是否撤回") + @QueryField(type = QueryType.EQ) + private Integer withdraw; + + @Schema(description = "文件信息") + private String fileInfo; + + @Schema(description = "存在联系方式") + @QueryField(type = QueryType.EQ) + private Integer hasContact; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0未读, 1已读") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCommissionRoleParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCommissionRoleParam.java new file mode 100644 index 0000000..45fdd79 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCommissionRoleParam.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分红角色查询参数 + * + * @author 科技小王子 + * @since 2025-05-01 10:01:14 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCommissionRoleParam对象", description = "分红角色查询参数") +public class ShopCommissionRoleParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + private String title; + + @QueryField(type = QueryType.EQ) + private Integer provinceId; + + @QueryField(type = QueryType.EQ) + private Integer cityId; + + @QueryField(type = QueryType.EQ) + private Integer regionId; + + @Schema(description = "状态, 0正常, 1异常") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "备注") + private String comments; + + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCountParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCountParam.java new file mode 100644 index 0000000..b7ac2ff --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCountParam.java @@ -0,0 +1,63 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商城销售统计表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCountParam对象", description = "商城销售统计表查询参数") +public class ShopCountParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "统计日期") + private String dateTime; + + @Schema(description = "总销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal totalPrice; + + @Schema(description = "今日销售额") + @QueryField(type = QueryType.EQ) + private BigDecimal todayPrice; + + @Schema(description = "总会员数") + @QueryField(type = QueryType.EQ) + private BigDecimal totalUsers; + + @Schema(description = "今日新增") + @QueryField(type = QueryType.EQ) + private BigDecimal todayUsers; + + @Schema(description = "总订单笔数") + @QueryField(type = QueryType.EQ) + private BigDecimal totalOrders; + + @Schema(description = "今日订单笔数") + @QueryField(type = QueryType.EQ) + private BigDecimal todayOrders; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponApplyCateParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponApplyCateParam.java new file mode 100644 index 0000000..b80698a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponApplyCateParam.java @@ -0,0 +1,46 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 优惠券可用分类查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:48 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCouponApplyCateParam对象", description = "优惠券可用分类查询参数") +public class ShopCouponApplyCateParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer couponId; + + @QueryField(type = QueryType.EQ) + private Integer cateId; + + @Schema(description = "分类等级") + @QueryField(type = QueryType.EQ) + private Boolean cateLevel; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponApplyItemParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponApplyItemParam.java new file mode 100644 index 0000000..f27cc47 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponApplyItemParam.java @@ -0,0 +1,54 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 优惠券可用分类查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCouponApplyItemParam对象", description = "优惠券可用分类查询参数") +public class ShopCouponApplyItemParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer couponId; + + @Schema(description = "商品ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "0服务1需求2闲置") + @QueryField(type = QueryType.EQ) + private Integer pk; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponParam.java new file mode 100644 index 0000000..58f71f5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopCouponParam.java @@ -0,0 +1,108 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 优惠券查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:23 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopCouponParam对象", description = "优惠券查询参数") +public class ShopCouponParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券描述") + private String description; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "满减券-减免金额") + @QueryField(type = QueryType.EQ) + private BigDecimal reducePrice; + + @Schema(description = "折扣券-折扣率(0-100)") + @QueryField(type = QueryType.EQ) + private Integer discount; + + @Schema(description = "最低消费金额") + @QueryField(type = QueryType.EQ) + private BigDecimal minPrice; + + @Schema(description = "到期类型(10领取后生效 20固定时间)") + @QueryField(type = QueryType.EQ) + private Integer expireType; + + @Schema(description = "领取后生效-有效天数") + @QueryField(type = QueryType.EQ) + private Integer expireDay; + + @Schema(description = "有效期开始时间") + private String startTime; + + @Schema(description = "有效期结束时间") + private String endTime; + + @Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)") + @QueryField(type = QueryType.EQ) + private Integer applyRange; + + @Schema(description = "适用范围配置(json格式)") + private String applyRangeConfig; + + @Schema(description = "是否过期(0未过期 1已过期)") + @QueryField(type = QueryType.EQ) + private Integer isExpire; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1禁用") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "创建用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "发放总数量(-1表示无限制)") + @QueryField(type = QueryType.EQ) + private Integer totalCount; + + @Schema(description = "已发放数量") + @QueryField(type = QueryType.EQ) + private Integer issuedCount; + + @Schema(description = "每人限领数量(-1表示无限制)") + @QueryField(type = QueryType.EQ) + private Integer limitPerUser; + + @Schema(description = "是否启用(0禁用 1启用)") + @QueryField(type = QueryType.EQ) + private Boolean enabled; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerApplyImportParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerApplyImportParam.java new file mode 100644 index 0000000..50ff384 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerApplyImportParam.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.shop.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 分销商申请记录导入参数 + * + * @author 科技小王子 + * @since 2025-09-05 + */ +@Data +public class ShopDealerApplyImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "类型", replace = {"经销商_0", "企业_1", "集团_2"}) + private Integer type; + + @Excel(name = "用户ID") + private Integer userId; + + @Excel(name = "姓名") + private String realName; + + @Excel(name = "分销商名称") + private String dealerName; + + @Excel(name = "分销商编码") + private String dealerCode; + + @Excel(name = "手机号") + private String mobile; + + @Excel(name = "合同金额") + private BigDecimal money; + + @Excel(name = "详细地址") + private String address; + + @Excel(name = "推荐人用户ID") + private Integer refereeId; + + @Excel(name = "申请方式", replace = {"需后台审核_10", "无需审核_20"}) + private Integer applyType; + + @Excel(name = "审核状态", replace = {"待审核_10", "审核通过_20", "驳回_30"}) + private Integer applyStatus; + + @Excel(name = "合同时间", format = "yyyy-MM-dd HH:mm:ss") + private String contractTime; + + @Excel(name = "驳回原因") + private String rejectReason; + + @Excel(name = "商城ID") + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerApplyParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerApplyParam.java new file mode 100644 index 0000000..fb4211a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerApplyParam.java @@ -0,0 +1,74 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商申请记录表查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:50:17 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerApplyParam对象", description = "分销商申请记录表查询参数") +public class ShopDealerApplyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer applyId; + + @Schema(description = "0经销商,1企业也,2集团)") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "姓名") + private String realName; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "推荐人用户ID") + @QueryField(type = QueryType.EQ) + private Integer refereeId; + + @Schema(description = "申请方式(10需后台审核 20无需审核)") + @QueryField(type = QueryType.EQ) + private Integer applyType; + + @Schema(description = "申请时间") + @QueryField(type = QueryType.EQ) + private String applyTime; + + @Schema(description = "到期时间") + @QueryField(type = QueryType.EQ) + private String expirationTime; + + @Schema(description = "审核状态 (10待审核 20审核通过 30驳回)") + @QueryField(type = QueryType.EQ) + private Integer applyStatus; + + @Schema(description = "审核时间") + @QueryField(type = QueryType.EQ) + private String auditTime; + + @Schema(description = "驳回原因") + private String rejectReason; + + @Schema(description = "分销商名称") + @QueryField(type = QueryType.EQ) + private String dealerName; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerBankParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerBankParam.java new file mode 100644 index 0000000..5aa4941 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerBankParam.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.shop.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 分销商提现银行卡查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerBankParam对象", description = "分销商提现银行卡查询参数") +public class ShopDealerBankParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "分销商用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "开户行名称") + private String bankName; + + @Schema(description = "银行开户名") + private String bankAccount; + + @Schema(description = "银行卡号") + private String bankCard; + + @Schema(description = "申请状态 (10待审核 20审核通过 30驳回)") + @QueryField(type = QueryType.EQ) + private Integer applyStatus; + + @Schema(description = "审核时间") + @QueryField(type = QueryType.EQ) + private Integer auditTime; + + @Schema(description = "驳回原因") + private String rejectReason; + + @Schema(description = "默认收货地址") + @QueryField(type = QueryType.EQ) + private Boolean isDefault; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerCapitalParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerCapitalParam.java new file mode 100644 index 0000000..1bde4f9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerCapitalParam.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商资金明细表查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:40 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerCapitalParam对象", description = "分销商资金明细表查询参数") +public class ShopDealerCapitalParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "分销商用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "订单编号") + @QueryField(type = QueryType.EQ) + private String orderNo; + + @Schema(description = "资金流动类型 (10佣金收入 20提现支出 30转账支出 40转账收入)") + @QueryField(type = QueryType.EQ) + private Integer flowType; + + @Schema(description = "金额") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "描述") + private String comments; + + @Schema(description = "对方用户ID") + @QueryField(type = QueryType.EQ) + private Integer toUserId; + + @Schema(description = "月份") + @QueryField(type = QueryType.EQ) + private String month; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerOrderImportParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerOrderImportParam.java new file mode 100644 index 0000000..ee88898 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerOrderImportParam.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.shop.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 分销商订单记录表导入参数 + * + * @author 科技小王子 + * @since 2025-08-12 11:55:18 + */ +@Data +public class ShopDealerOrderImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "主键ID") + private Integer id; + + @Excel(name = "买家用户ID") + private Integer userId; + + @Excel(name = "订单ID") + private Integer orderId; + + @Excel(name = "订单总金额") + private BigDecimal orderPrice; + + @Excel(name = "一级分销商ID") + private Integer firstUserId; + + @Excel(name = "二级分销商ID") + private Integer secondUserId; + + @Excel(name = "三级分销商ID") + private Integer thirdUserId; + + @Excel(name = "一级佣金") + private BigDecimal firstMoney; + + @Excel(name = "二级佣金") + private BigDecimal secondMoney; + + @Excel(name = "三级佣金") + private BigDecimal thirdMoney; + + @Excel(name = "订单状态") + private Integer isInvalid; + + @Excel(name = "结算状态") + private Integer isSettled; + + @Excel(name = "结算时间") + private LocalDateTime settleTime; + + @Excel(name = "租户ID") + private Integer tenantId; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerOrderParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerOrderParam.java new file mode 100644 index 0000000..1f21f8a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerOrderParam.java @@ -0,0 +1,91 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商订单记录表查询参数 + * + * @author 科技小王子 + * @since 2025-08-12 11:55:18 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerOrderParam对象", description = "分销商订单记录表查询参数") +public class ShopDealerOrderParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "买家用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Excel(name = "订单编号") + @QueryField(type = QueryType.EQ) + private String orderNo; + + @Schema(description = "订单总金额(不含运费)") + @QueryField(type = QueryType.EQ) + private BigDecimal orderPrice; + + @Schema(description = "分销商用户id(一级)") + @QueryField(type = QueryType.EQ) + private Integer firstUserId; + + @Schema(description = "分销商用户id(二级)") + @QueryField(type = QueryType.EQ) + private Integer secondUserId; + + @Schema(description = "分销商用户id(三级)") + @QueryField(type = QueryType.EQ) + private Integer thirdUserId; + + @Schema(description = "分销佣金(一级)") + @QueryField(type = QueryType.EQ) + private BigDecimal firstMoney; + + @Schema(description = "分销佣金(二级)") + @QueryField(type = QueryType.EQ) + private BigDecimal secondMoney; + + @Schema(description = "分销佣金(三级)") + @QueryField(type = QueryType.EQ) + private BigDecimal thirdMoney; + + @Schema(description = "订单是否失效(0未失效 1已失效)") + @QueryField(type = QueryType.EQ) + private Integer isInvalid; + + @Schema(description = "佣金结算(0未结算 1已结算)") + @QueryField(type = QueryType.EQ) + private Integer isSettled; + + @Schema(description = "结算时间") + @QueryField(type = QueryType.EQ) + private String settleTime; + + @Schema(description = "备注") + @QueryField(type = QueryType.EQ) + private String comments; + + @Schema(description = "关联ID") + @QueryField(type = QueryType.EQ) + private Integer resourceId; + + @Schema(description = "月份") + @QueryField(type = QueryType.EQ) + private String month; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerRecordParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerRecordParam.java new file mode 100644 index 0000000..84acded --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerRecordParam.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.shop.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 客户跟进情况查询参数 + * + * @author 科技小王子 + * @since 2025-10-02 12:21:50 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "客户跟进情况查询参数") +public class ShopDealerRecordParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "客户ID") + @QueryField(type = QueryType.EQ) + private Integer dealerId; + + @Schema(description = "内容") + private String content; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0待处理, 1已完成") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerRefereeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerRefereeParam.java new file mode 100644 index 0000000..b96adf8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerRefereeParam.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商推荐关系表查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerRefereeParam对象", description = "分销商推荐关系表查询参数") +public class ShopDealerRefereeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "分销商用户ID") + @QueryField(type = QueryType.EQ) + private Integer dealerId; + + @Schema(description = "用户id(被推荐人)") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "推荐关系层级(1,2,3)") + @QueryField(type = QueryType.EQ) + private Integer level; + + @Schema(description = "是否管理员") + @QueryField(type = QueryType.EQ) + private Boolean isAdmin; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerSettingParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerSettingParam.java new file mode 100644 index 0000000..e9f214e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerSettingParam.java @@ -0,0 +1,35 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商设置表查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerSettingParam对象", description = "分销商设置表查询参数") +public class ShopDealerSettingParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "设置项标示") + @QueryField(type = QueryType.EQ) + private String key; + + @Schema(description = "设置项描述") + private String describe; + + @Schema(description = "设置内容(json格式)") + private String values; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerUserImportParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerUserImportParam.java new file mode 100644 index 0000000..064bcb9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerUserImportParam.java @@ -0,0 +1,70 @@ +package com.gxwebsoft.shop.param; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 分销商用户导入参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +public class ShopDealerUserImportParam implements Serializable { + private static final long serialVersionUID = 1L; + + @Excel(name = "用户ID") + private Integer userId; + + @Excel(name = "姓名") + private String realName; + + @Excel(name = "手机号") + private String mobile; + + @Excel(name = "支付密码") + private String payPassword; + + @Excel(name = "当前可提现佣金") + private BigDecimal money; + + @Excel(name = "已冻结佣金") + private BigDecimal freezeMoney; + + @Excel(name = "累积提现佣金") + private BigDecimal totalMoney; + + @Excel(name = "推荐人用户ID") + private Integer refereeId; + + @Excel(name = "成员数量(一级)") + private Integer firstNum; + + @Excel(name = "成员数量(二级)") + private Integer secondNum; + + @Excel(name = "成员数量(三级)") + private Integer thirdNum; + + @Excel(name = "专属二维码") + private String qrcode; + + @Excel(name = "排序号") + private Integer sortNumber; + + @Excel(name = "是否删除") + private Integer isDelete; + + @Excel(name = "租户ID") + private Integer tenantId; + + @Excel(name = "创建时间") + private LocalDateTime createTime; + + @Excel(name = "修改时间") + private LocalDateTime updateTime; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerUserParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerUserParam.java new file mode 100644 index 0000000..9953b1f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerUserParam.java @@ -0,0 +1,89 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商用户记录表查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerUserParam对象", description = "分销商用户记录表查询参数") +public class ShopDealerUserParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "姓名") + private String realName; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "支付密码") + private String payPassword; + + @Schema(description = "当前可提现佣金") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "已冻结佣金") + @QueryField(type = QueryType.EQ) + private BigDecimal freezeMoney; + + @Schema(description = "累积提现佣金") + @QueryField(type = QueryType.EQ) + private BigDecimal totalMoney; + + @Schema(description = "佣金比例") + @QueryField(type = QueryType.EQ) + private BigDecimal rate; + + @Schema(description = "推荐人用户ID") + @QueryField(type = QueryType.EQ) + private Integer refereeId; + + @Schema(description = "成员数量(一级)") + @QueryField(type = QueryType.EQ) + private Integer firstNum; + + @Schema(description = "成员数量(二级)") + @QueryField(type = QueryType.EQ) + private Integer secondNum; + + @Schema(description = "成员数量(三级)") + @QueryField(type = QueryType.EQ) + private Integer thirdNum; + + @Schema(description = "专属二维码") + private String qrcode; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除") + @QueryField(type = QueryType.EQ) + private Integer isDelete; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerWithdrawParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerWithdrawParam.java new file mode 100644 index 0000000..a510fc3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopDealerWithdrawParam.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分销商提现明细表查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopDealerWithdrawParam对象", description = "分销商提现明细表查询参数") +public class ShopDealerWithdrawParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "分销商用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "提现金额") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "打款方式 (10微信 20支付宝 30银行卡)") + @QueryField(type = QueryType.EQ) + private Integer payType; + + @Schema(description = "支付宝姓名") + private String alipayName; + + @Schema(description = "支付宝账号") + private String alipayAccount; + + @Schema(description = "开户行名称") + private String bankName; + + @Schema(description = "银行开户名") + private String bankAccount; + + @Schema(description = "银行卡号") + private String bankCard; + + @Schema(description = "申请状态 (10待审核 20审核通过 30驳回 40已打款)") + @QueryField(type = QueryType.EQ) + private Integer applyStatus; + + @Schema(description = "审核时间") + @QueryField(type = QueryType.EQ) + private String auditTime; + + @Schema(description = "驳回原因") + private String rejectReason; + + @Schema(description = "来源客户端(APP、H5、小程序等)") + private String platform; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "上传支付凭证") + private String image; + + @Schema(description = "微信openId") + @QueryField(type = QueryType.EQ) + private String openId; + + @Schema(description = "公众号openId") + @QueryField(type = QueryType.EQ) + private String officeOpenid; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressParam.java new file mode 100644 index 0000000..ce43740 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressParam.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 物流公司查询参数 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopExpressParam对象", description = "物流公司查询参数") +public class ShopExpressParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "物流公司ID") + @QueryField(type = QueryType.EQ) + private Integer expressId; + + @Schema(description = "物流公司名称") + private String expressName; + + @Schema(description = "物流公司编码 (微信)") + private String wxCode; + + @Schema(description = "物流公司编码 (快递100)") + private String kuaidi100Code; + + @Schema(description = "物流公司编码 (快递鸟)") + private String kdniaoCode; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressTemplateDetailParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressTemplateDetailParam.java new file mode 100644 index 0000000..6a2f8c9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressTemplateDetailParam.java @@ -0,0 +1,68 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 运费模板查询参数 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopExpressTemplateDetailParam对象", description = "运费模板查询参数") +public class ShopExpressTemplateDetailParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer templateId; + + @Schema(description = "0按件") + @QueryField(type = QueryType.EQ) + private Boolean type; + + @QueryField(type = QueryType.EQ) + private Integer provinceId; + + @QueryField(type = QueryType.EQ) + private Integer cityId; + + @Schema(description = "首件数量/重量") + @QueryField(type = QueryType.EQ) + private BigDecimal firstNum; + + @Schema(description = "收件价格") + @QueryField(type = QueryType.EQ) + private BigDecimal firstAmount; + + @Schema(description = "续件价格") + @QueryField(type = QueryType.EQ) + private BigDecimal extraAmount; + + @Schema(description = "续件数量/重量") + @QueryField(type = QueryType.EQ) + private BigDecimal extraNum; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressTemplateParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressTemplateParam.java new file mode 100644 index 0000000..43c4ebd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopExpressTemplateParam.java @@ -0,0 +1,60 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 运费模板查询参数 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopExpressTemplateParam对象", description = "运费模板查询参数") +public class ShopExpressTemplateParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Boolean type; + + private String title; + + @Schema(description = "收件价格") + @QueryField(type = QueryType.EQ) + private BigDecimal firstAmount; + + @Schema(description = "续件价格") + @QueryField(type = QueryType.EQ) + private BigDecimal extraAmount; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "首件数量/重量") + @QueryField(type = QueryType.EQ) + private BigDecimal firstNum; + + @Schema(description = "续件数量/重量") + @QueryField(type = QueryType.EQ) + private BigDecimal extraNum; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGiftParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGiftParam.java new file mode 100644 index 0000000..e5e710c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGiftParam.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 礼品卡查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 18:07:31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGiftParam对象", description = "礼品卡查询参数") +public class ShopGiftParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + private String name; + + @Schema(description = "秘钥") + private String code; + + @Schema(description = "商品ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "使用地点") + private String useLocation; + + @Schema(description = "领取时间") + private String takeTime; + + @Schema(description = "操作人") + @QueryField(type = QueryType.EQ) + private Integer operatorUserId; + + @Schema(description = "核销时间") + private String verificationTime; + + @Schema(description = "是否展示") + @QueryField(type = QueryType.EQ) + private Boolean isShow; + + @Schema(description = "状态, 0未使用 1已使用 2失效") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "操作员备注") + private String operatorRemarks; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsCategoryParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsCategoryParam.java new file mode 100644 index 0000000..646c7e1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsCategoryParam.java @@ -0,0 +1,95 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品分类查询参数 + * + * @author 科技小王子 + * @since 2025-05-01 00:36:45 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsCategoryParam对象", description = "商品分类查询参数") +public class ShopGoodsCategoryParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "商品分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "分类标识") + private String categoryCode; + + @Schema(description = "分类名称") + private String title; + + @Schema(description = "类型 0商城分类 1外卖分类") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "分类图片") + private String image; + + @Schema(description = "上级分类ID") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "路由/链接地址") + private String path; + + @Schema(description = "组件路径") + private String component; + + @Schema(description = "绑定的页面") + @QueryField(type = QueryType.EQ) + private Integer pageId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商品数量") + @QueryField(type = QueryType.EQ) + private Integer count; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否隐藏, 0否, 1是(仅注册路由不显示在左侧菜单)") + @QueryField(type = QueryType.EQ) + private Integer hide; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否显示在首页") + @QueryField(type = QueryType.EQ) + private Integer showIndex; + + @Schema(description = "商铺ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "状态, 0正常, 1禁用") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsCommentParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsCommentParam.java new file mode 100644 index 0000000..582b4ad --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsCommentParam.java @@ -0,0 +1,97 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 评论表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsCommentParam对象", description = "评论表查询参数") +public class ShopGoodsCommentParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "评论ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer uid; + + @Schema(description = "订单ID") + @QueryField(type = QueryType.EQ) + private Integer oid; + + @Schema(description = "商品唯一id") + private String unique; + + @Schema(description = "商品id") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "某种商品类型(普通商品、秒杀商品)") + private String replyType; + + @Schema(description = "商品分数") + @QueryField(type = QueryType.EQ) + private Boolean goodsScore; + + @Schema(description = "服务分数") + @QueryField(type = QueryType.EQ) + private Boolean serviceScore; + + @Schema(description = "评论内容") + private String comment; + + @Schema(description = "评论图片") + private String pics; + + @Schema(description = "管理员回复内容") + private String merchantReplyContent; + + @Schema(description = "管理员回复时间") + @QueryField(type = QueryType.EQ) + private Integer merchantReplyTime; + + @Schema(description = "0未删除1已删除") + @QueryField(type = QueryType.EQ) + private Boolean isDel; + + @Schema(description = "0未回复1已回复") + @QueryField(type = QueryType.EQ) + private Boolean isReply; + + @Schema(description = "用户名称") + private String nickname; + + @Schema(description = "用户头像") + private String avatar; + + @Schema(description = "商品规格属性值,多个,号隔开") + private String sku; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsIncomeConfigParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsIncomeConfigParam.java new file mode 100644 index 0000000..8c25e70 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsIncomeConfigParam.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分润配置查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsIncomeConfigParam对象", description = "分润配置查询参数") +public class ShopGoodsIncomeConfigParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "店铺类型") + private String merchantShopType; + + @QueryField(type = QueryType.EQ) + private Integer skuId; + + @Schema(description = "比例") + @QueryField(type = QueryType.EQ) + private BigDecimal rate; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsLogParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsLogParam.java new file mode 100644 index 0000000..e31017f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsLogParam.java @@ -0,0 +1,88 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品日志表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsLogParam对象", description = "商品日志表查询参数") +public class ShopGoodsLogParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "统计ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "类型visit,cart,order,pay,collect,refund") + private String type; + + @Schema(description = "商品ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "是否浏览") + @QueryField(type = QueryType.EQ) + private Boolean visitNum; + + @Schema(description = "加入购物车数量") + @QueryField(type = QueryType.EQ) + private Integer cartNum; + + @Schema(description = "下单数量") + @QueryField(type = QueryType.EQ) + private Integer orderNum; + + @Schema(description = "支付数量") + @QueryField(type = QueryType.EQ) + private Integer payNum; + + @Schema(description = "支付金额") + @QueryField(type = QueryType.EQ) + private BigDecimal payPrice; + + @Schema(description = "商品成本价") + @QueryField(type = QueryType.EQ) + private BigDecimal costPrice; + + @Schema(description = "支付用户ID") + @QueryField(type = QueryType.EQ) + private Integer payUid; + + @Schema(description = "退款数量") + @QueryField(type = QueryType.EQ) + private Integer refundNum; + + @Schema(description = "退款金额") + @QueryField(type = QueryType.EQ) + private BigDecimal refundPrice; + + @Schema(description = "收藏") + @QueryField(type = QueryType.EQ) + private Boolean collectNum; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsParam.java new file mode 100644 index 0000000..d3cfa5e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsParam.java @@ -0,0 +1,152 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品查询参数 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsParam对象", description = "商品查询参数") +public class ShopGoodsParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "商品名称") + private String name; + + @Schema(description = "产品编码") + private String code; + + @Schema(description = "类型 0软件产品 1实物商品 2虚拟商品") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "父级分类ID") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "产品分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "路由地址") + private String path; + + @Schema(description = "标签") + private String tag; + + @Schema(description = "产品规格 0单规格 1多规格") + @QueryField(type = QueryType.EQ) + private Integer specs; + + @Schema(description = "货架") + private String position; + + @Schema(description = "单位名称 (个)") + private String unitName; + + @Schema(description = "商品价格") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "进货价格") + @QueryField(type = QueryType.EQ) + private BigDecimal buyingPrice; + + @Schema(description = "经销商价格") + @QueryField(type = QueryType.EQ) + private BigDecimal dealerPrice; + + @Schema(description = "库存计算方式(10下单减库存 20付款减库存)") + @QueryField(type = QueryType.EQ) + private Integer deductStockType; + + @Schema(description = "交付方式(0不启用)") + @QueryField(type = QueryType.EQ) + private Integer deliveryMethod; + + @Schema(description = "购买时长(0不启用,1 一次性,2 按时长)") + @QueryField(type = QueryType.EQ) + private Integer durationMethod; + + @Schema(description = "可购买数量") + @QueryField(type = QueryType.EQ) + private Integer canBuyNumber; + + @Schema(description = "轮播图") + private String files; + + @Schema(description = "销量") + @QueryField(type = QueryType.EQ) + private Integer sales; + + @Schema(description = "库存") + @QueryField(type = QueryType.EQ) + private Integer stock; + + @Schema(description = "安装次数") + @QueryField(type = QueryType.EQ) + private Integer install; + + @Schema(description = "评分") + @QueryField(type = QueryType.EQ) + private BigDecimal rate; + + @Schema(description = "消费赚取积分") + @QueryField(type = QueryType.EQ) + private BigDecimal gainIntegral; + + @Schema(description = "推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否官方") + @QueryField(type = QueryType.EQ) + private Integer official; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "是否展示") + @QueryField(type = QueryType.EQ) + private Boolean isShow; + + @Schema(description = "状态, 0上架 1待上架 2待审核 3审核不通过") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsRelationParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsRelationParam.java new file mode 100644 index 0000000..3441ea0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsRelationParam.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品点赞和收藏表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsRelationParam对象", description = "商品点赞和收藏表查询参数") +public class ShopGoodsRelationParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商品ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "类型(收藏(collect)、点赞(like))") + private String type; + + @Schema(description = "某种类型的商品(普通商品、秒杀商品)") + private String category; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsRoleCommissionParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsRoleCommissionParam.java new file mode 100644 index 0000000..fab8581 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsRoleCommissionParam.java @@ -0,0 +1,49 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品绑定角色的分润金额查询参数 + * + * @author 科技小王子 + * @since 2025-05-01 09:53:38 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsRoleCommissionParam对象", description = "商品绑定角色的分润金额查询参数") +public class ShopGoodsRoleCommissionParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer roleId; + + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + private String sku; + + @QueryField(type = QueryType.EQ) + private BigDecimal amount; + + @Schema(description = "状态, 0正常, 1异常") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "备注") + private String comments; + + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsSkuParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsSkuParam.java new file mode 100644 index 0000000..34ca471 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsSkuParam.java @@ -0,0 +1,79 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品sku列表查询参数 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsSkuParam对象", description = "商品sku列表查询参数") +public class ShopGoodsSkuParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "商品ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "商品属性索引值 (attr_value|attr_value[|....])") + private String sku; + + @Schema(description = "商品图片") + private String image; + + @Schema(description = "商品价格") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "市场价格") + @QueryField(type = QueryType.EQ) + private BigDecimal salePrice; + + @Schema(description = "成本价") + @QueryField(type = QueryType.EQ) + private BigDecimal cost; + + @Schema(description = "库存") + @QueryField(type = QueryType.EQ) + private Integer stock; + + @Schema(description = "sku编码") + private String skuNo; + + @Schema(description = "商品条码") + private String barCode; + + @Schema(description = "重量") + @QueryField(type = QueryType.EQ) + private BigDecimal weight; + + @Schema(description = "体积") + @QueryField(type = QueryType.EQ) + private BigDecimal volume; + + @Schema(description = "唯一值") + private String uuid; + + @Schema(description = "状态, 0正常, 1异常") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "备注") + private String comments; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsSpecParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsSpecParam.java new file mode 100644 index 0000000..3fedd04 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopGoodsSpecParam.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品多规格查询参数 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopGoodsSpecParam对象", description = "商品多规格查询参数") +public class ShopGoodsSpecParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "商品ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "规格ID") + @QueryField(type = QueryType.EQ) + private Integer specId; + + @Schema(description = "规格名称") + private String specName; + + @Schema(description = "规格值") + private String specValue; + + @Schema(description = "活动类型 0=商品,1=秒杀,2=砍价,3=拼团") + @QueryField(type = QueryType.EQ) + private Boolean type; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantAccountParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantAccountParam.java new file mode 100644 index 0000000..a82a66f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantAccountParam.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户账号查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopMerchantAccountParam对象", description = "商户账号查询参数") +public class ShopMerchantAccountParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "角色ID") + @QueryField(type = QueryType.EQ) + private Integer roleId; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantApplyParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantApplyParam.java new file mode 100644 index 0000000..a35a41d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantApplyParam.java @@ -0,0 +1,125 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户入驻申请查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopMerchantApplyParam对象", description = "商户入驻申请查询参数") +public class ShopMerchantApplyParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer applyId; + + @Schema(description = "类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "门店图片") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "商户行业分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "商户分类") + private String category; + + @Schema(description = "经纬度") + private String lngAndLat; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "地区ID") + private String regionId; + + @Schema(description = "手续费") + @QueryField(type = QueryType.EQ) + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "营业执照") + private String yyzz; + + @Schema(description = "身份证") + private String sfz1; + + @Schema(description = "身份证") + private String sfz2; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "所有人") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否自营") + @QueryField(type = QueryType.EQ) + private Integer ownStore; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否需要审核") + @QueryField(type = QueryType.EQ) + private Integer goodsReview; + + @Schema(description = "工作负责人") + private String name2; + + @Schema(description = "驳回原因") + private String reason; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantParam.java new file mode 100644 index 0000000..1c087b7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantParam.java @@ -0,0 +1,149 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户查询参数 + * + * @author 科技小王子 + * @since 2025-08-10 20:43:33 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopMerchantParam对象", description = "商户查询参数") +public class ShopMerchantParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户编号") + private String merchantCode; + + @Schema(description = "商户类型") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "商户图标") + private String image; + + @Schema(description = "商户手机号") + private String phone; + + @Schema(description = "商户姓名") + private String realName; + + @Schema(description = "店铺类型") + private String shopType; + + @Schema(description = "项目分类") + private String itemType; + + @Schema(description = "商户分类") + private String category; + + @Schema(description = "商户经营分类") + @QueryField(type = QueryType.EQ) + private Integer merchantCategoryId; + + @Schema(description = "商户分类") + private String merchantCategoryTitle; + + @Schema(description = "经纬度") + private String lngAndLat; + + private String lng; + + private String lat; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "手续费") + @QueryField(type = QueryType.EQ) + private BigDecimal commission; + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "资质图片") + private String files; + + @Schema(description = "营业时间") + private String businessTime; + + @Schema(description = "文章内容") + private String content; + + @Schema(description = "每小时价格") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "是否自营") + @QueryField(type = QueryType.EQ) + private Integer ownStore; + + @Schema(description = "是否可以快递") + @QueryField(type = QueryType.EQ) + private Boolean canExpress; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "是否营业") + @QueryField(type = QueryType.EQ) + private Integer isOn; + + private String startTime; + + private String endTime; + + @Schema(description = "是否需要审核") + @QueryField(type = QueryType.EQ) + private Integer goodsReview; + + @Schema(description = "管理入口") + private String adminUrl; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "所有人") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantTypeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantTypeParam.java new file mode 100644 index 0000000..c1cbdc2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopMerchantTypeParam.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商户类型查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopMerchantTypeParam对象", description = "商户类型查询参数") +public class ShopMerchantTypeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "店铺类型") + private String name; + + @Schema(description = "店铺入驻条件") + private String comments; + + @Schema(description = "状态") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderDeliveryGoodsParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderDeliveryGoodsParam.java new file mode 100644 index 0000000..af7763c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderDeliveryGoodsParam.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 发货单商品查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopOrderDeliveryGoodsParam对象", description = "发货单商品查询参数") +public class ShopOrderDeliveryGoodsParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "发货单ID") + @QueryField(type = QueryType.EQ) + private Integer deliveryId; + + @Schema(description = "订单ID") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "订单商品ID") + @QueryField(type = QueryType.EQ) + private Integer orderGoodsId; + + @Schema(description = "商品ID") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "发货数量") + @QueryField(type = QueryType.EQ) + private Integer deliveryNum; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderDeliveryParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderDeliveryParam.java new file mode 100644 index 0000000..3459550 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderDeliveryParam.java @@ -0,0 +1,59 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 发货单查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopOrderDeliveryParam对象", description = "发货单查询参数") +public class ShopOrderDeliveryParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "发货单ID") + @QueryField(type = QueryType.EQ) + private Integer deliveryId; + + @Schema(description = "订单ID") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "发货方式(10手动录入 20无需物流 30电子面单)") + @QueryField(type = QueryType.EQ) + private Integer deliveryMethod; + + @Schema(description = "打包方式(废弃)") + @QueryField(type = QueryType.EQ) + private Integer packMethod; + + @Schema(description = "物流公司ID") + @QueryField(type = QueryType.EQ) + private Integer expressId; + + @Schema(description = "物流单号") + private String expressNo; + + @Schema(description = "电子面单模板内容") + private String eorderHtml; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderExtractParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderExtractParam.java new file mode 100644 index 0000000..148fad5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderExtractParam.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 自提订单联系方式查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopOrderExtractParam对象", description = "自提订单联系方式查询参数") +public class ShopOrderExtractParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "订单ID") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "联系人姓名") + private String linkman; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderGoodsParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderGoodsParam.java new file mode 100644 index 0000000..382f560 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderGoodsParam.java @@ -0,0 +1,108 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品信息查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopOrderGoodsParam对象", description = "商品信息查询参数") +public class ShopOrderGoodsParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "关联订单表id") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "订单标识") + private String orderCode; + + @Schema(description = "关联商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商品封面图") + private String image; + + @Schema(description = "关联商品id") + @QueryField(type = QueryType.EQ) + private Integer goodsId; + + @Schema(description = "商品名称") + private String goodsName; + + @Schema(description = "商品规格") + private String spec; + + @QueryField(type = QueryType.EQ) + private Integer skuId; + + @Schema(description = "单价") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "购买数量") + @QueryField(type = QueryType.EQ) + private Integer totalNum; + + @Schema(description = "0 未付款 1已付款,2无需付款或占用状态") + @QueryField(type = QueryType.EQ) + private Integer payStatus; + + @Schema(description = "0未使用,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + @QueryField(type = QueryType.EQ) + private Integer orderStatus; + + @Schema(description = "是否免费:0收费、1免费") + @QueryField(type = QueryType.EQ) + private Boolean isFree; + + @Schema(description = "系统版本 0当前版本 其他版本") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "预约时间段") + private String timePeriod; + + @Schema(description = "预定日期") + private String dateTime; + + @Schema(description = "开场时间") + private String startTime; + + @Schema(description = "结束时间") + private String endTime; + + @Schema(description = "毫秒时间戳") + private Long timeFlag; + + @Schema(description = "过期时间") + private String expirationTime; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderInfoLogParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderInfoLogParam.java new file mode 100644 index 0000000..fa1135c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderInfoLogParam.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 订单核销查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopOrderInfoLogParam对象", description = "订单核销查询参数") +public class ShopOrderInfoLogParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "关联订单表id") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "关联商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "关联场地id") + @QueryField(type = QueryType.EQ) + private Integer fieldId; + + @Schema(description = "核销数量") + @QueryField(type = QueryType.EQ) + private Boolean useNum; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderInfoParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderInfoParam.java new file mode 100644 index 0000000..ff8221a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderInfoParam.java @@ -0,0 +1,123 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 场地查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopOrderInfoParam对象", description = "场地查询参数") +public class ShopOrderInfoParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "自增ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "关联订单表id") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "组合数据:日期+时间段+场馆id+场地id") + private String orderCode; + + @Schema(description = "关联商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "关联场地id") + @QueryField(type = QueryType.EQ) + private Integer fieldId; + + @Schema(description = "场地名称") + private String fieldName; + + @Schema(description = "单价") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "儿童价") + @QueryField(type = QueryType.EQ) + private BigDecimal childrenPrice; + + @Schema(description = "成人人数") + @QueryField(type = QueryType.EQ) + private Integer adultNum; + + @Schema(description = "儿童人数") + @QueryField(type = QueryType.EQ) + private Integer childrenNum; + + @Schema(description = "已核销的成人票数") + @QueryField(type = QueryType.EQ) + private Integer adultNumUse; + + @Schema(description = "已核销的儿童票数") + @QueryField(type = QueryType.EQ) + private Integer childrenNumUse; + + @Schema(description = "0 未付款 1已付款,2无需付款或占用状态") + @QueryField(type = QueryType.EQ) + private Integer payStatus; + + @Schema(description = "0未使用,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + @QueryField(type = QueryType.EQ) + private Integer orderStatus; + + @Schema(description = "是否免费:0收费、1免费") + @QueryField(type = QueryType.EQ) + private Boolean isFree; + + @Schema(description = "是否支持儿童票:0不支持、1支持") + @QueryField(type = QueryType.EQ) + private Boolean isChildren; + + @Schema(description = "系统版本 0当前版本 其他版本") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "预订类型:0全场,1半场") + @QueryField(type = QueryType.EQ) + private Boolean isHalf; + + @Schema(description = "预约时间段") + private String timePeriod; + + @Schema(description = "预定日期") + private String dateTime; + + @Schema(description = "开场时间") + private String startTime; + + @Schema(description = "结束时间") + private String endTime; + + @Schema(description = "毫秒时间戳") + private Long timeFlag; + + @Schema(description = "过期时间") + private String expirationTime; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderParam.java new file mode 100644 index 0000000..a3c7e62 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopOrderParam.java @@ -0,0 +1,264 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 订单查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopOrderParam对象", description = "订单查询参数") +public class ShopOrderParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单号") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "订单类型,0商城订单 1预定订单/外卖 2会员卡") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "快递/自提") + @QueryField(type = QueryType.EQ) + private Integer deliveryType; + + @Schema(description = "下单渠道,0小程序预定 1俱乐部训练场 3活动订场") + @QueryField(type = QueryType.EQ) + private Integer channel; + + @Schema(description = "微信支付订单号") + private String transactionId; + + @Schema(description = "微信退款订单号") + private String refundOrder; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户编号") + private String merchantCode; + + @Schema(description = "使用的优惠券id") + @QueryField(type = QueryType.EQ) + private Integer couponId; + + @Schema(description = "使用的会员卡id") + private String cardId; + + @Schema(description = "关联管理员id") + @QueryField(type = QueryType.EQ) + private Integer adminId; + + @Schema(description = "核销管理员id") + @QueryField(type = QueryType.EQ) + private Integer confirmId; + + @Schema(description = "IC卡号") + private String icCard; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "收货人id") + private Integer addressId; + + @Schema(description = "收货地址") + private String address; + + private String addressLat; + + private String addressLng; + + @Schema(description = "自提店铺id") + @QueryField(type = QueryType.EQ) + private Integer selfTakeMerchantId; + + @Schema(description = "自提店铺") + private String selfTakeMerchantName; + + @Schema(description = "配送开始时间") + private String sendStartTime; + + @Schema(description = "配送结束时间") + private String sendEndTime; + + @Schema(description = "发货店铺id") + @QueryField(type = QueryType.EQ) + private Integer expressMerchantId; + + @Schema(description = "发货店铺") + private String expressMerchantName; + + @Schema(description = "订单总额") + @QueryField(type = QueryType.EQ) + private BigDecimal totalPrice; + + @Schema(description = "减少的金额,使用VIP会员折扣、优惠券抵扣、优惠券折扣后减去的价格") + @QueryField(type = QueryType.EQ) + private BigDecimal reducePrice; + + @Schema(description = "实际付款") + @QueryField(type = QueryType.EQ) + private BigDecimal payPrice; + + @Schema(description = "用于统计") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "价钱,用于积分赠送") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "退款金额") + @QueryField(type = QueryType.EQ) + private BigDecimal refundMoney; + + @Schema(description = "教练价格") + @QueryField(type = QueryType.EQ) + private BigDecimal coachPrice; + + @Schema(description = "购买数量") + @QueryField(type = QueryType.EQ) + private Integer totalNum; + + @Schema(description = "教练id") + @QueryField(type = QueryType.EQ) + private Integer coachId; + + @Schema(description = "支付的用户id") + @QueryField(type = QueryType.EQ) + private Integer payUserId; + + @Schema(description = "支付方式:0余额支付,1微信支付,2支付宝支付,3银联支付,4现金支付,5POS机支付,6免费,7积分支付") + @QueryField(type = QueryType.EQ) + private Integer payType; + + @Schema(description = "代付支付方式:0余额支付,1微信支付,2支付宝支付,3银联支付,4现金支付,5POS机支付,6免费,7积分支付") + @QueryField(type = QueryType.EQ) + private Integer friendPayType; + + @Schema(description = "0未付款,1已付款") + @QueryField(type = QueryType.EQ) + private Boolean payStatus; + + @Schema(description = "0未使用,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款") + @QueryField(type = QueryType.EQ) + private Integer orderStatus; + + @Schema(description = "发货状态(10未发货 20已发货 30部分发货)") + @QueryField(type = QueryType.EQ) + private Integer deliveryStatus; + + @Schema(description = "发货备注") + private String deliveryNote; + + @Schema(description = "快递单号") + private String expressNo; + + @Schema(description = "发货时间") + private String deliveryTime; + + @Schema(description = "优惠类型:0无、1抵扣优惠券、2折扣优惠券、3、VIP月卡、4VIP年卡,5VIP次卡、6VIP会员卡、7IC月卡、8IC年卡、9IC次卡、10IC会员卡、11免费订单、12VIP充值卡、13IC充值卡、14VIP季卡、15IC季卡") + @QueryField(type = QueryType.EQ) + private Integer couponType; + + @Schema(description = "优惠说明") + private String couponDesc; + + @Schema(description = "二维码地址,保存订单号,支付成功后才生成") + private String qrcode; + + @Schema(description = "vip月卡年卡、ic月卡年卡回退次数") + @QueryField(type = QueryType.EQ) + private Integer returnNum; + + @Schema(description = "vip充值回退金额") + @QueryField(type = QueryType.EQ) + private BigDecimal returnMoney; + + @Schema(description = "预约详情开始时间数组") + private String startTime; + + @Schema(description = "是否已开具发票:0未开发票,1已开发票,2不能开具发票") + @QueryField(type = QueryType.EQ) + private Boolean isInvoice; + + @Schema(description = "发票流水号") + private String invoiceNo; + + @Schema(description = "支付时间") + private String payTime; + + @Schema(description = "退款时间") + private String refundTime; + + @Schema(description = "申请退款时间") + private String refundApplyTime; + + @Schema(description = "过期时间") + private String expirationTime; + + @Schema(description = "对账情况:0=未对账;1=已对账;3=已对账,金额对不上;4=未查询到该订单") + @QueryField(type = QueryType.EQ) + private Integer checkBill; + + @Schema(description = "订单是否已结算(0未结算 1已结算)") + @QueryField(type = QueryType.EQ) + private Integer isSettled; + + @Schema(description = "系统版本号 0当前版本 value=其他版本") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "用户昵称") + @QueryField(type = QueryType.LIKE) + private String nickname; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "自提码") + private String selfTakeCode; + + @Schema(description = "是否已收到赠品") + @QueryField(type = QueryType.EQ) + private Boolean hasTakeGift; + + @Schema(description = "订单状态筛选:-1全部,0待支付,1待发货,2待核销,3待收货,4待评价,5已完成,6已退款,7已删除") + private Integer statusFilter; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopRechargeOrderParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopRechargeOrderParam.java new file mode 100644 index 0000000..a15cf67 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopRechargeOrderParam.java @@ -0,0 +1,104 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 会员充值订单表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopRechargeOrderParam对象", description = "会员充值订单表查询参数") +public class ShopRechargeOrderParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "订单ID") + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "充值方式(10自定义金额 20套餐充值)") + @QueryField(type = QueryType.EQ) + private Integer rechargeType; + + @Schema(description = "机构id") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "充值套餐ID") + @QueryField(type = QueryType.EQ) + private Integer planId; + + @Schema(description = "用户支付金额") + @QueryField(type = QueryType.EQ) + private BigDecimal payPrice; + + @Schema(description = "赠送金额") + @QueryField(type = QueryType.EQ) + private BigDecimal giftMoney; + + @Schema(description = "实际到账金额") + @QueryField(type = QueryType.EQ) + private BigDecimal actualMoney; + + @Schema(description = "用户可用余额") + @QueryField(type = QueryType.EQ) + private BigDecimal balance; + + @Schema(description = "支付方式(微信/支付宝)") + private String payMethod; + + @Schema(description = "支付状态(10待支付 20已支付)") + @QueryField(type = QueryType.EQ) + private Integer payStatus; + + @Schema(description = "付款时间") + @QueryField(type = QueryType.EQ) + private Integer payTime; + + @Schema(description = "第三方交易记录ID") + @QueryField(type = QueryType.EQ) + private Integer tradeId; + + @Schema(description = "来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "所属门店ID") + @QueryField(type = QueryType.EQ) + private Integer shopId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "商户编码") + private String merchantCode; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSpecParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSpecParam.java new file mode 100644 index 0000000..07b78c3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSpecParam.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 规格查询参数 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopSpecParam对象", description = "规格查询参数") +public class ShopSpecParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "规格ID") + @QueryField(type = QueryType.EQ) + private Integer specId; + + @Schema(description = "规格名称") + private String specName; + + @Schema(description = "规格值") + private String specValue; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "创建用户") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "更新者") + @QueryField(type = QueryType.EQ) + private Integer updater; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1待修,2异常已修,3异常未修") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSpecValueParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSpecValueParam.java new file mode 100644 index 0000000..c864f97 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSpecValueParam.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 规格值查询参数 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopSpecValueParam对象", description = "规格值查询参数") +public class ShopSpecValueParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "规格值ID") + @QueryField(type = QueryType.EQ) + private Integer specValueId; + + @Schema(description = "规格组ID") + @QueryField(type = QueryType.EQ) + private Integer specId; + + @Schema(description = "规格值") + private String specValue; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSplashParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSplashParam.java new file mode 100644 index 0000000..6893c66 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopSplashParam.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 开屏广告查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopSplashParam对象", description = "开屏广告查询参数") +public class ShopSplashParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "标题") + private String title; + + @Schema(description = "图片") + private String image; + + @Schema(description = "跳转类型") + private String jumpType; + + @Schema(description = "跳转主键") + @QueryField(type = QueryType.EQ) + private Integer jumpPk; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserAddressParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserAddressParam.java new file mode 100644 index 0000000..2225a36 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserAddressParam.java @@ -0,0 +1,76 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 收货地址查询参数 + * + * @author 科技小王子 + * @since 2025-07-22 23:06:40 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopUserAddressParam对象", description = "收货地址查询参数") +public class ShopUserAddressParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "收货地址") + private String address; + + @Schema(description = "收货地址") + private String fullAddress; + + private String lat; + + private String lng; + + @Schema(description = "1先生 2女士") + @QueryField(type = QueryType.EQ) + private Integer gender; + + @Schema(description = "家、公司、学校") + private String type; + + @Schema(description = "默认收货地址") + @QueryField(type = QueryType.EQ) + private Boolean isDefault; + + @Schema(description = "排序号") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserBalanceLogParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserBalanceLogParam.java new file mode 100644 index 0000000..ba3938c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserBalanceLogParam.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户余额变动明细表查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopUserBalanceLogParam对象", description = "用户余额变动明细表查询参数") +public class ShopUserBalanceLogParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer logId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "余额变动场景(0下级下单1供应商收入2差价收益 10用户充值 20用户消费 30管理员操作 40订单退款)") + @QueryField(type = QueryType.EQ) + private Integer scene; + + @Schema(description = "变动金额") + @QueryField(type = QueryType.EQ) + private BigDecimal money; + + @Schema(description = "变动后余额") + @QueryField(type = QueryType.EQ) + private BigDecimal balance; + + @Schema(description = "管理员备注") + private String remark; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "操作人ID") + @QueryField(type = QueryType.EQ) + private Integer adminId; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0正常, 1冻结") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户编码") + private String merchantCode; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserCollectionParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserCollectionParam.java new file mode 100644 index 0000000..40a6fdb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserCollectionParam.java @@ -0,0 +1,41 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 我的收藏查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopUserCollectionParam对象", description = "我的收藏查询参数") +public class ShopUserCollectionParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "0店铺,1商品") + @QueryField(type = QueryType.EQ) + private Boolean type; + + @Schema(description = "租户ID") + @QueryField(type = QueryType.EQ) + private Integer tid; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserCouponParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserCouponParam.java new file mode 100644 index 0000000..3051530 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserCouponParam.java @@ -0,0 +1,96 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户优惠券查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopUserCouponParam对象", description = "用户优惠券查询参数") +public class ShopUserCouponParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "优惠券模板ID") + @QueryField(type = QueryType.EQ) + private Integer couponId; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "优惠券名称") + private String name; + + @Schema(description = "优惠券描述") + private String description; + + @Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "满减券-减免金额") + @QueryField(type = QueryType.EQ) + private BigDecimal reducePrice; + + @Schema(description = "折扣券-折扣率(0-100)") + @QueryField(type = QueryType.EQ) + private Integer discount; + + @Schema(description = "最低消费金额") + @QueryField(type = QueryType.EQ) + private BigDecimal minPrice; + + @Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)") + @QueryField(type = QueryType.EQ) + private Integer applyRange; + + @Schema(description = "适用范围配置(json格式)") + private String applyRangeConfig; + + @Schema(description = "有效期开始时间") + private String startTime; + + @Schema(description = "有效期结束时间") + private String endTime; + + @Schema(description = "使用状态(0未使用 1已使用 2已过期)") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "使用时间") + private String useTime; + + @Schema(description = "使用订单ID") + private Long orderId; + + @Schema(description = "使用订单号") + private String orderNo; + + @Schema(description = "获取方式(10主动领取 20系统发放 30活动赠送)") + @QueryField(type = QueryType.EQ) + private Integer obtainType; + + @Schema(description = "获取来源描述") + private String obtainSource; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Boolean deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserParam.java new file mode 100644 index 0000000..2b3ac02 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserParam.java @@ -0,0 +1,276 @@ +package com.gxwebsoft.shop.param; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 用户记录表查询参数 + * + * @author 科技小王子 + * @since 2025-10-03 13:41:08 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "用户记录表查询参数") +public class ShopUserParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "用户类型 0个人用户 1企业用户 2其他") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "账号") + private String username; + + @Schema(description = "密码") + private String password; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "性别 1男 2女") + @QueryField(type = QueryType.EQ) + private Integer sex; + + @Schema(description = "职务") + private String position; + + @Schema(description = "注册来源客户端 (APP、H5、MP-WEIXIN等)") + private String platform; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "邮箱是否验证, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer emailVerified; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "真实姓名") + private String realName; + + @Schema(description = "证件号码") + private String idCard; + + @Schema(description = "出生日期") + private String birthday; + + @Schema(description = "所在国家") + private String country; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "用户可用余额") + @QueryField(type = QueryType.EQ) + private BigDecimal balance; + + @Schema(description = "已提现金额") + @QueryField(type = QueryType.EQ) + private BigDecimal cashedMoney; + + @Schema(description = "用户可用积分") + @QueryField(type = QueryType.EQ) + private Integer points; + + @Schema(description = "用户总支付的金额") + @QueryField(type = QueryType.EQ) + private BigDecimal payMoney; + + @Schema(description = "实际消费的金额(不含退款)") + @QueryField(type = QueryType.EQ) + private BigDecimal expendMoney; + + @Schema(description = "密码") + private String payPassword; + + @Schema(description = "会员等级ID") + @QueryField(type = QueryType.EQ) + private Integer gradeId; + + @Schema(description = "行业分类") + private String category; + + @Schema(description = "个人简介") + private String introduction; + + @Schema(description = "机构id") + @QueryField(type = QueryType.EQ) + private Integer organizationId; + + @Schema(description = "会员分组ID") + @QueryField(type = QueryType.EQ) + private Integer groupId; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "背景图") + private String bgImage; + + @Schema(description = "用户编码") + private String userCode; + + @Schema(description = "是否已实名认证") + @QueryField(type = QueryType.EQ) + private Integer certification; + + @Schema(description = "年龄") + @QueryField(type = QueryType.EQ) + private Integer age; + + @Schema(description = "是否线下会员") + @QueryField(type = QueryType.EQ) + private Boolean offline; + + @Schema(description = "关注数") + @QueryField(type = QueryType.EQ) + private Integer followers; + + @Schema(description = "粉丝数") + @QueryField(type = QueryType.EQ) + private Integer fans; + + @Schema(description = "点赞数") + @QueryField(type = QueryType.EQ) + private Integer likes; + + @Schema(description = "评论数") + @QueryField(type = QueryType.EQ) + private Integer commentNumbers; + + @Schema(description = "是否推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "微信openid") + private String openid; + + @Schema(description = "微信公众号openid") + private String officeOpenid; + + @Schema(description = "微信unionID") + private String unionid; + + @Schema(description = "客户端ID") + private String clientId; + + @Schema(description = "不允许办卡") + @QueryField(type = QueryType.EQ) + private Boolean notAllowVip; + + @Schema(description = "是否管理员") + @QueryField(type = QueryType.EQ) + private Boolean isAdmin; + + @Schema(description = "是否企业管理员") + @QueryField(type = QueryType.EQ) + private Boolean isOrganizationAdmin; + + @Schema(description = "累计登录次数") + @QueryField(type = QueryType.EQ) + private Integer loginNum; + + @Schema(description = "企业ID") + @QueryField(type = QueryType.EQ) + private Integer companyId; + + @Schema(description = "可管理的场馆") + private String merchants; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "商户名称") + private String merchantName; + + @Schema(description = "商户头像") + private String merchantAvatar; + + @Schema(description = "第三方系统的用户ID") + @QueryField(type = QueryType.EQ) + private Integer uid; + + @Schema(description = "专家角色") + @QueryField(type = QueryType.EQ) + private Boolean expertType; + + @Schema(description = "过期时间") + @QueryField(type = QueryType.EQ) + private Integer expireTime; + + @Schema(description = "最后结算时间") + private String settlementTime; + + @Schema(description = "资质") + private String aptitude; + + @Schema(description = "行业类型(父级)") + private String industryParent; + + @Schema(description = "行业类型(子级)") + private String industryChild; + + @Schema(description = "头衔") + private String title; + + @Schema(description = "安装的产品ID") + @QueryField(type = QueryType.EQ) + private Integer templateId; + + @Schema(description = "插件安装状态(仅对超超管判断) 0未安装 1已安装 ") + @QueryField(type = QueryType.EQ) + private Integer installed; + + @Schema(description = "特长") + private String speciality; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0在线, 1离线") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserRefereeParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserRefereeParam.java new file mode 100644 index 0000000..f0ea733 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopUserRefereeParam.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户推荐关系表查询参数 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopUserRefereeParam对象", description = "用户推荐关系表查询参数") +public class ShopUserRefereeParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "推荐人ID") + @QueryField(type = QueryType.EQ) + private Integer dealerId; + + @Schema(description = "用户id(被推荐人)") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "推荐关系层级(1,2,3)") + @QueryField(type = QueryType.EQ) + private Integer level; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopWechatDepositParam.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopWechatDepositParam.java new file mode 100644 index 0000000..29d0693 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/param/ShopWechatDepositParam.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 押金查询参数 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopWechatDepositParam对象", description = "押金查询参数") +public class ShopWechatDepositParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @QueryField(type = QueryType.EQ) + private Integer id; + + @Schema(description = "订单id") + @QueryField(type = QueryType.EQ) + private Integer oid; + + @Schema(description = "用户id") + @QueryField(type = QueryType.EQ) + private Integer uid; + + @Schema(description = "场地订单号") + private String orderNum; + + @Schema(description = "付款订单号") + private String wechatOrder; + + @Schema(description = "退款订单号 ") + private String wechatReturn; + + @Schema(description = "场馆名称") + private String siteName; + + @Schema(description = "微信昵称") + private String username; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "物品名称") + private String name; + + @Schema(description = "押金金额") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "押金状态,1已付款,2未付款,已退押金") + @QueryField(type = QueryType.EQ) + private Boolean status; + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/CouponStatusService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/CouponStatusService.java new file mode 100644 index 0000000..0bfad4a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/CouponStatusService.java @@ -0,0 +1,154 @@ +package com.gxwebsoft.shop.service; + +import com.gxwebsoft.shop.entity.ShopUserCoupon; + +import java.util.List; + +/** + * 优惠券状态管理服务 + * + * @author WebSoft + * @since 2025-01-15 + */ +public interface CouponStatusService { + + /** + * 获取用户可用的优惠券列表 + * + * @param userId 用户ID + * @return 可用优惠券列表 + */ + List getAvailableCoupons(Integer userId); + + /** + * 获取用户已使用的优惠券列表 + * + * @param userId 用户ID + * @return 已使用优惠券列表 + */ + List getUsedCoupons(Integer userId); + + /** + * 获取用户已过期的优惠券列表 + * + * @param userId 用户ID + * @return 已过期优惠券列表 + */ + List getExpiredCoupons(Integer userId); + + /** + * 获取用户所有优惠券并按状态分类 + * + * @param userId 用户ID + * @return 分类后的优惠券列表 + */ + CouponStatusResult getUserCouponsGroupByStatus(Integer userId); + + /** + * 使用优惠券 + * + * @param userCouponId 用户优惠券ID + * @param orderId 订单ID + * @param orderNo 订单号 + * @return 是否成功 + */ + boolean useCoupon(Long userCouponId, Integer orderId, String orderNo); + + /** + * 退还优惠券(订单取消时) + * + * @param orderId 订单ID + * @return 是否成功 + */ + boolean returnCoupon(Integer orderId); + + /** + * 批量更新过期优惠券状态 + * + * @return 更新的数量 + */ + int updateExpiredCoupons(); + + /** + * 检查并更新单个优惠券状态 + * + * @param userCoupon 用户优惠券 + * @return 是否状态发生变化 + */ + boolean checkAndUpdateCouponStatus(ShopUserCoupon userCoupon); + + /** + * 验证优惠券是否可用于指定订单 + * + * @param userCouponId 用户优惠券ID + * @param totalAmount 订单总金额 + * @param goodsIds 商品ID列表 + * @return 验证结果 + */ + CouponValidationResult validateCouponForOrder(Long userCouponId, + java.math.BigDecimal totalAmount, + List goodsIds); + + /** + * 优惠券状态分类结果 + */ + class CouponStatusResult { + private List availableCoupons; // 可用优惠券 + private List usedCoupons; // 已使用优惠券 + private List expiredCoupons; // 已过期优惠券 + private int totalCount; // 总数量 + + // 构造函数 + public CouponStatusResult(List availableCoupons, + List usedCoupons, + List expiredCoupons) { + this.availableCoupons = availableCoupons; + this.usedCoupons = usedCoupons; + this.expiredCoupons = expiredCoupons; + this.totalCount = availableCoupons.size() + usedCoupons.size() + expiredCoupons.size(); + } + + // Getters and Setters + public List getAvailableCoupons() { return availableCoupons; } + public void setAvailableCoupons(List availableCoupons) { this.availableCoupons = availableCoupons; } + + public List getUsedCoupons() { return usedCoupons; } + public void setUsedCoupons(List usedCoupons) { this.usedCoupons = usedCoupons; } + + public List getExpiredCoupons() { return expiredCoupons; } + public void setExpiredCoupons(List expiredCoupons) { this.expiredCoupons = expiredCoupons; } + + public int getTotalCount() { return totalCount; } + public void setTotalCount(int totalCount) { this.totalCount = totalCount; } + } + + /** + * 优惠券验证结果 + */ + class CouponValidationResult { + private boolean valid; // 是否有效 + private String message; // 验证消息 + private java.math.BigDecimal discountAmount; // 优惠金额 + + public CouponValidationResult(boolean valid, String message) { + this.valid = valid; + this.message = message; + } + + public CouponValidationResult(boolean valid, String message, java.math.BigDecimal discountAmount) { + this.valid = valid; + this.message = message; + this.discountAmount = discountAmount; + } + + // Getters and Setters + public boolean isValid() { return valid; } + public void setValid(boolean valid) { this.valid = valid; } + + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + + public java.math.BigDecimal getDiscountAmount() { return discountAmount; } + public void setDiscountAmount(java.math.BigDecimal discountAmount) { this.discountAmount = discountAmount; } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/KuaiDi100.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/KuaiDi100.java new file mode 100644 index 0000000..6905f53 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/KuaiDi100.java @@ -0,0 +1,16 @@ +package com.gxwebsoft.shop.service; + +import com.kuaidi100.sdk.pojo.HttpResult; +import com.kuaidi100.sdk.request.BOrderReq; + +public interface KuaiDi100 { + /** + * 商家寄件 + * @param bOrderReq + * @return + * @throws Exception + */ + HttpResult border(BOrderReq bOrderReq) throws Exception; + + String pollList(String com, String num, String phone) throws Exception; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java new file mode 100644 index 0000000..9037b8a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java @@ -0,0 +1,691 @@ +package com.gxwebsoft.shop.service; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import com.gxwebsoft.common.core.exception.BusinessException; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.config.OrderConfigProperties; +import com.gxwebsoft.shop.dto.OrderCreateRequest; +import com.gxwebsoft.shop.entity.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 订单业务服务类 + * 处理订单创建的核心业务逻辑 + * + * @author 科技小王子 + * @since 2025-01-26 + */ +@Slf4j +@Service +public class OrderBusinessService { + + @Resource + private ShopOrderService shopOrderService; + + @Resource + private ShopOrderGoodsService shopOrderGoodsService; + + @Resource + private ShopGoodsService shopGoodsService; + + @Resource + private ShopGoodsSkuService shopGoodsSkuService; + + @Resource + private OrderConfigProperties orderConfig; + + @Resource + private ShopUserAddressService shopUserAddressService; + @Resource + private ShopUserCouponService shopUserCouponService; + + /** + * 创建订单 + * + * @param request 订单创建请求 + * @param loginUser 当前登录用户 + * @return 微信支付订单信息 + */ + @Transactional(rollbackFor = Exception.class) + public Map createOrder(OrderCreateRequest request, User loginUser) { + + // 1. 参数校验 + validateOrderRequest(request, loginUser); + + // 2. 构建订单对象 + ShopOrder shopOrder = buildShopOrder(request, loginUser); + + // 3. 处理收货地址信息 + processDeliveryAddress(shopOrder, request, loginUser); + + // 4. 应用业务规则 + applyBusinessRules(shopOrder, loginUser); + + // 5. 保存订单 + boolean saved = shopOrderService.save(shopOrder); + if (!saved) { + throw new BusinessException("订单保存失败"); + } + + // 6. 保存订单商品 + saveOrderGoods(request, shopOrder); + + // 7. 标记优惠券为已使用 + if (shopOrder.getCouponId() != null && shopOrder.getCouponId() > 0) { + markCouponAsUsed(shopOrder.getCouponId(), shopOrder.getOrderId()); + } + + // 8. 创建微信支付订单 + try { + return shopOrderService.createWxOrder(shopOrder); + } catch (Exception e) { + log.error("创建微信支付订单失败,订单号:{}", shopOrder.getOrderNo(), e); + throw new BusinessException("创建支付订单失败:" + e.getMessage()); + } + } + + /** + * 校验订单请求参数 + */ + private void validateOrderRequest(OrderCreateRequest request, User loginUser) { + if (loginUser == null) { + throw new BusinessException("用户未登录"); + } + + // 检查是否为测试账号 + boolean isTestAccount = orderConfig.isTestAccount(loginUser.getPhone()); + + if (isTestAccount) { + // 测试账号:直接使用测试金额,跳过金额验证 + BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount(); + request.setTotalPrice(testAmount); + log.info("测试账号订单,用户:{},使用测试金额:{}", loginUser.getPhone(), testAmount); + return; // 测试账号跳过后续验证 + } + + // 非测试账号:正常验证流程 + // 验证商品信息并计算总金额 + BigDecimal calculatedTotal = validateAndCalculateTotal(request); + + if (calculatedTotal.compareTo(BigDecimal.ZERO) <= 0) { + throw new BusinessException("商品金额不能为0"); + } + + // 检查前端传入的总金额是否正确(允许小的误差,比如0.01) + if (request.getTotalPrice() != null && + request.getTotalPrice().subtract(calculatedTotal).abs().compareTo(new BigDecimal("0.01")) > 0) { + log.warn("订单金额计算不一致,前端传入:{},后台计算:{}", request.getTotalPrice(), calculatedTotal); +// throw new BusinessException("订单金额计算错误,请刷新重试"); + } + + // 使用后台计算的金额 + request.setTotalPrice(calculatedTotal); + + // 检查租户特殊规则 + OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(request.getTenantId()); + if (tenantRule != null && tenantRule.getMinAmount() != null) { + if (calculatedTotal.compareTo(tenantRule.getMinAmount()) < 0) { + throw new BusinessException(tenantRule.getMinAmountMessage()); + } + } + } + + /** + * 验证商品信息并计算总金额 + */ + private BigDecimal validateAndCalculateTotal(OrderCreateRequest request) { + if (CollectionUtils.isEmpty(request.getGoodsItems())) { + throw new BusinessException("订单商品列表不能为空"); + } + + BigDecimal total = BigDecimal.ZERO; + + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 验证商品ID + if (item.getGoodsId() == null) { + throw new BusinessException("商品ID不能为空"); + } + + // 验证购买数量 + if (item.getQuantity() == null || item.getQuantity() <= 0) { + throw new BusinessException("商品购买数量必须大于0"); + } + + // 获取商品信息 + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + if (goods == null) { + throw new BusinessException("商品不存在,商品ID:" + item.getGoodsId()); + } + + // 验证商品状态 + if (goods.getStatus() == null || goods.getStatus() != 0) { + throw new BusinessException("商品已下架:" + goods.getName()); + } + + // 处理多规格商品价格和库存验证 + BigDecimal actualPrice = goods.getPrice(); // 默认使用商品价格 + Integer actualStock = goods.getStock(); // 默认使用商品库存 + String productName = goods.getName(); + + if (item.getSkuId() != null) { + // 多规格商品,获取SKU信息 + ShopGoodsSku sku = shopGoodsSkuService.getById(item.getSkuId()); + if (sku == null) { + throw new BusinessException("商品规格不存在,SKU ID:" + item.getSkuId()); + } + + // 验证SKU是否属于该商品 + if (!sku.getGoodsId().equals(item.getGoodsId())) { + throw new BusinessException("商品规格不匹配"); + } + + // 验证SKU状态 + if (sku.getStatus() == null || sku.getStatus() != 0) { + throw new BusinessException("商品规格已下架"); + } + + // 使用SKU的价格和库存 + actualPrice = sku.getPrice(); + actualStock = sku.getStock(); + productName = goods.getName() + "(" + (item.getSpecInfo() != null ? item.getSpecInfo() : sku.getSku()) + ")"; + } + + // 验证实际价格 + if (actualPrice == null || actualPrice.compareTo(BigDecimal.ZERO) <= 0) { + throw new BusinessException("商品价格异常:" + productName); + } + + // 验证库存 + if (actualStock != null && actualStock < item.getQuantity()) { + throw new BusinessException("商品库存不足:" + productName + ",当前库存:" + actualStock); + } + + // 验证购买数量限制(使用商品级别的限制) + if (goods.getCanBuyNumber() != null && goods.getCanBuyNumber() > 0 && + item.getQuantity() > goods.getCanBuyNumber()) { + throw new BusinessException("商品购买数量超过限制:" + productName + ",最大购买数量:" + goods.getCanBuyNumber()); + } + + // 计算商品小计(使用实际价格) + BigDecimal itemTotal = actualPrice.multiply(new BigDecimal(item.getQuantity())); + total = total.add(itemTotal); + + log.debug("商品验证通过 - ID:{},SKU ID:{},名称:{},单价:{},数量:{},小计:{}", + goods.getGoodsId(), item.getSkuId(), productName, actualPrice, item.getQuantity(), itemTotal); + } + + log.info("订单商品验证完成,总金额:{}", total); + return total; + } + + /** + * 构建订单对象 + */ + private ShopOrder buildShopOrder(OrderCreateRequest request, User loginUser) { + ShopOrder shopOrder = new ShopOrder(); + + // 复制请求参数到订单对象 + BeanUtils.copyProperties(request, shopOrder); + + // 确保租户ID正确设置(关键字段,影响微信支付证书路径) + shopOrder.setTenantId(loginUser.getTenantId()); + + // 验证关键字段 + if (shopOrder.getTenantId() == null) { + throw new BusinessException("租户ID不能为空,这会导致微信支付证书路径错误"); + } + + // 设置用户相关信息 + shopOrder.setUserId(loginUser.getUserId()); + shopOrder.setOpenid(loginUser.getOpenid()); + shopOrder.setPayUserId(loginUser.getUserId()); + + log.debug("构建订单对象 - 租户ID:{},用户ID:{}", shopOrder.getTenantId(), shopOrder.getUserId()); + + // 生成订单号(如果请求中没有提供) + if (shopOrder.getOrderNo() == null || shopOrder.getOrderNo().trim().isEmpty()) { + String generatedOrderNo = Long.toString(IdUtil.getSnowflakeNextId()); + shopOrder.setOrderNo(generatedOrderNo); + log.info("生成新订单号: {}", generatedOrderNo); + } else { + log.info("使用请求中的订单号: {}", shopOrder.getOrderNo()); + } + + // 设置默认备注 + if (shopOrder.getComments() == null) { + shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments()); + } + + // 设置价格相关字段(解决数据库字段没有默认值的问题) + if (shopOrder.getPayPrice() == null) { + shopOrder.setPayPrice(shopOrder.getTotalPrice()); // 实际付款默认等于订单总额 + } + + if (shopOrder.getPrice() == null) { + shopOrder.setPrice(shopOrder.getTotalPrice()); // 用于统计的价格默认等于订单总额 + } + + if (shopOrder.getReducePrice() == null) { + shopOrder.setReducePrice(BigDecimal.ZERO); // 减少金额默认为0 + } + + if (shopOrder.getMoney() == null) { + shopOrder.setMoney(shopOrder.getTotalPrice()); // 用于积分赠送的价格默认等于订单总额 + } + + // 设置默认状态 + shopOrder.setPayStatus(false); // 未付款 + shopOrder.setOrderStatus(0); // 未使用 + shopOrder.setDeliveryStatus(10); // 未发货 + shopOrder.setIsInvoice(0); // 未开发票 + shopOrder.setIsSettled(0); // 未结算 + shopOrder.setCheckBill(0); // 未对账 + shopOrder.setVersion(0); // 当前版本 + + // 设置默认支付类型(如果没有指定) + if (shopOrder.getPayType() == null) { + shopOrder.setPayType(1); // 默认微信支付 + } + + // 优惠券处理 + if (shopOrder.getCouponId() != null && shopOrder.getCouponId() > 0) { + processCoupon(shopOrder, loginUser); + } + + return shopOrder; + } + + /** + * 处理优惠券 + */ + private void processCoupon(ShopOrder shopOrder, User loginUser) { + ShopUserCoupon coupon = shopUserCouponService.getById(shopOrder.getCouponId()); + if (coupon == null) { + throw new BusinessException("优惠券不存在"); + } + + // 验证优惠券是否属于当前用户 + if (!coupon.getUserId().equals(loginUser.getUserId())) { + throw new BusinessException("优惠券不属于当前用户"); + } + + // 验证优惠券是否已使用 + if (coupon.getIsUse() != null && coupon.getIsUse().equals(1)) { + throw new BusinessException("优惠券已使用"); + } + + // 验证优惠券是否过期 + if (coupon.getIsExpire() != null && coupon.getIsExpire().equals(1)) { + throw new BusinessException("优惠券已过期"); + } + + // 计算优惠金额 + BigDecimal reducePrice = BigDecimal.ZERO; + boolean canUse = true; + + if (coupon.getType().equals(10)) { + // 满减券 + reducePrice = coupon.getReducePrice() != null ? coupon.getReducePrice() : BigDecimal.ZERO; + BigDecimal minPrice = coupon.getMinPrice() != null ? coupon.getMinPrice() : BigDecimal.ZERO; + if (shopOrder.getTotalPrice().compareTo(minPrice) < 0) { + canUse = false; + throw new BusinessException("订单金额不满足优惠券使用条件,最低消费:" + minPrice + "元"); + } + } else if (coupon.getType().equals(20)) { + // 折扣券 - 计算减免金额(不是折扣后金额) + Integer discount = coupon.getDiscount() != null ? coupon.getDiscount() : 100; + if (discount < 0 || discount > 100) { + throw new BusinessException("优惠券折扣率异常"); + } + // 减免金额 = 原价 * (100 - 折扣率) / 100 + reducePrice = shopOrder.getTotalPrice() + .multiply(new BigDecimal(100 - discount)) + .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP); + } else if (coupon.getType().equals(30)) { + // 免费券 + reducePrice = shopOrder.getTotalPrice(); + } else { + throw new BusinessException("不支持的优惠券类型"); + } + + if (canUse && reducePrice.compareTo(BigDecimal.ZERO) > 0) { + // 确保减免金额不超过订单总额 + if (reducePrice.compareTo(shopOrder.getTotalPrice()) > 0) { + reducePrice = shopOrder.getTotalPrice(); + } + + // 应用优惠 + shopOrder.setReducePrice(shopOrder.getReducePrice().add(reducePrice)); + shopOrder.setPayPrice(shopOrder.getPayPrice().subtract(reducePrice)); + + // 确保实付金额不为负数 + if (shopOrder.getPayPrice().compareTo(BigDecimal.ZERO) < 0) { + shopOrder.setPayPrice(BigDecimal.ZERO); + } + + log.info("应用优惠券成功 - 优惠券ID:{},类型:{},减免金额:{},实付金额:{}", + coupon.getId(), coupon.getType(), reducePrice, shopOrder.getPayPrice()); + } + } + + /** + * 处理收货地址信息 + * 优先级:前端传入地址 > 指定地址ID > 用户默认地址 + */ + private void processDeliveryAddress(ShopOrder shopOrder, OrderCreateRequest request, User loginUser) { + try { + // 1. 如果前端已经传入了完整的收货地址信息,直接使用 + if (isAddressInfoComplete(request)) { + log.info("使用前端传入的收货地址信息,用户ID:{}", loginUser.getUserId()); + return; + } + + // 2. 如果指定了地址ID,获取该地址信息 + if (request.getAddressId() != null) { + ShopUserAddress userAddress = shopUserAddressService.getById(request.getAddressId()); + if (userAddress != null && userAddress.getUserId().equals(loginUser.getUserId())) { + copyAddressToOrder(userAddress, shopOrder, request); + log.info("使用指定地址ID:{},用户ID:{}", request.getAddressId(), loginUser.getUserId()); + return; + } + log.warn("指定的地址ID不存在或不属于当前用户,地址ID:{},用户ID:{}", + request.getAddressId(), loginUser.getUserId()); + } + + // 3. 获取用户默认收货地址 + ShopUserAddress defaultAddress = shopUserAddressService.getDefaultAddress(loginUser.getUserId()); + if (defaultAddress != null) { + copyAddressToOrder(defaultAddress, shopOrder, request); + log.info("使用用户默认收货地址,地址ID:{},用户ID:{}", defaultAddress.getId(), loginUser.getUserId()); + return; + } + + // 4. 如果没有默认地址,获取用户的第一个地址 + List userAddresses = shopUserAddressService.getUserAddresses(loginUser.getUserId()); + if (!userAddresses.isEmpty()) { + ShopUserAddress firstAddress = userAddresses.get(0); + copyAddressToOrder(firstAddress, shopOrder, request); + log.info("使用用户第一个收货地址,地址ID:{},用户ID:{}", firstAddress.getId(), loginUser.getUserId()); + return; + } + // 5. 如果用户没有任何收货地址,抛出异常 + throw new BusinessException("请先添加收货地址"); + + } catch (BusinessException e) { + throw e; + } catch (Exception e) { + log.error("处理收货地址信息失败,用户ID:{}", loginUser.getUserId(), e); + throw new BusinessException("处理收货地址信息失败:" + e.getMessage()); + } + } + + /** + * 检查前端传入的地址信息是否完整 + */ + private boolean isAddressInfoComplete(OrderCreateRequest request) { + return request.getAddress() != null && !request.getAddress().trim().isEmpty() && + request.getRealName() != null && !request.getRealName().trim().isEmpty(); + } + + /** + * 将用户地址信息复制到订单中(创建快照) + */ + private void copyAddressToOrder(ShopUserAddress userAddress, ShopOrder shopOrder, OrderCreateRequest request) { + // 保存地址ID引用关系 + shopOrder.setAddressId(userAddress.getId()); + request.setAddressId(userAddress.getId()); + + // 创建地址信息快照 + if (request.getAddress() == null || request.getAddress().trim().isEmpty()) { + // 构建完整地址 + StringBuilder fullAddress = new StringBuilder(); + if (userAddress.getProvince() != null) fullAddress.append(userAddress.getProvince()); + if (userAddress.getCity() != null) fullAddress.append(userAddress.getCity()); + if (userAddress.getRegion() != null) fullAddress.append(userAddress.getRegion()); + if (userAddress.getAddress() != null) fullAddress.append(userAddress.getAddress()); + + shopOrder.setAddress(fullAddress.toString()); + request.setAddress(fullAddress.toString()); + } + + // 复制收货人信息 + if (request.getRealName() == null || request.getRealName().trim().isEmpty()) { + shopOrder.setRealName(userAddress.getName()); + request.setRealName(userAddress.getName()); + } + + // 复制经纬度信息 + if (request.getAddressLat() == null && userAddress.getLat() != null) { + shopOrder.setAddressLat(userAddress.getLat()); + request.setAddressLat(userAddress.getLat()); + } + if (request.getAddressLng() == null && userAddress.getLng() != null) { + shopOrder.setAddressLng(userAddress.getLng()); + request.setAddressLng(userAddress.getLng()); + } + + log.debug("地址信息快照创建完成 - 地址ID:{},收货人:{},地址:{}", + userAddress.getId(), userAddress.getName(), shopOrder.getAddress()); + } + + /** + * 应用业务规则 + */ + private void applyBusinessRules(ShopOrder shopOrder, User loginUser) { + // 测试账号处理 + if (orderConfig.isTestAccount(loginUser.getPhone())) { + BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount(); + shopOrder.setPrice(testAmount); + shopOrder.setTotalPrice(testAmount); + shopOrder.setPayPrice(testAmount); // 确保实际付款也设置为测试金额 + shopOrder.setMoney(testAmount); // 确保积分计算金额也设置为测试金额 + log.info("应用测试账号规则,用户:{},测试金额:{}", loginUser.getPhone(), testAmount); + } + + // 其他业务规则可以在这里添加 + // 例如:VIP折扣、优惠券处理等 + } + + /** + * 校验订单金额 + */ + public void validateOrderAmount(BigDecimal amount, Integer tenantId) { + if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) { + throw new BusinessException("订单金额必须大于0"); + } + + OrderConfigProperties.TenantRule tenantRule = orderConfig.getTenantRule(tenantId); + if (tenantRule != null && tenantRule.getMinAmount() != null) { + if (amount.compareTo(tenantRule.getMinAmount()) < 0) { + throw new BusinessException(tenantRule.getMinAmountMessage()); + } + } + } + + /** + * 保存订单商品 + */ + private void saveOrderGoods(OrderCreateRequest request, ShopOrder shopOrder) { + if (CollectionUtils.isEmpty(request.getGoodsItems())) { + log.warn("订单商品列表为空,订单号:{}", shopOrder.getOrderNo()); + return; + } + + List orderGoodsList = new ArrayList<>(); + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 重新获取商品信息(确保数据一致性) + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + if (goods == null) { + throw new BusinessException("商品不存在,商品ID:" + item.getGoodsId()); + } + + // 再次验证商品状态(防止并发问题) + if (goods.getStatus() == null || goods.getStatus() != 0) { + throw new BusinessException("商品已下架:" + goods.getName()); + } + + // 处理多规格商品 + ShopGoodsSku sku = null; + BigDecimal actualPrice = goods.getPrice(); // 默认使用商品价格 + Integer actualStock = goods.getStock(); // 默认使用商品库存 + String specInfo = item.getSpecInfo(); // 规格信息 + + if (item.getSkuId() != null) { + // 多规格商品,获取SKU信息 + sku = shopGoodsSkuService.getById(item.getSkuId()); + if (sku == null) { + throw new BusinessException("商品规格不存在,SKU ID:" + item.getSkuId()); + } + + // 验证SKU是否属于该商品 + if (!sku.getGoodsId().equals(item.getGoodsId())) { + throw new BusinessException("商品规格不匹配"); + } + + // 验证SKU状态 + if (sku.getStatus() == null || sku.getStatus() != 0) { + throw new BusinessException("商品规格已下架"); + } + + // 使用SKU的价格和库存 + actualPrice = sku.getPrice(); + actualStock = sku.getStock(); + + // 如果前端没有传规格信息,使用SKU的规格信息 + if (specInfo == null || specInfo.trim().isEmpty()) { + specInfo = sku.getSku(); // 使用SKU的规格描述 + } + } + + // 验证库存 + if (actualStock == null || actualStock < item.getQuantity()) { + String stockMsg = sku != null ? "商品规格库存不足" : "商品库存不足"; + throw new BusinessException(stockMsg + ",当前库存:" + (actualStock != null ? actualStock : 0)); + } + + ShopOrderGoods orderGoods = new ShopOrderGoods(); + + // 设置订单关联信息 + orderGoods.setOrderId(shopOrder.getOrderId()); + orderGoods.setOrderCode(shopOrder.getOrderNo()); + + // 设置商户信息 + orderGoods.setMerchantId(shopOrder.getMerchantId()); + orderGoods.setMerchantName(shopOrder.getMerchantName()); + + // 设置商品信息(使用后台查询的真实数据) + orderGoods.setGoodsId(item.getGoodsId()); + orderGoods.setSkuId(item.getSkuId()); // 设置SKU ID + orderGoods.setGoodsName(goods.getName()); + orderGoods.setImage(sku != null && sku.getImage() != null ? sku.getImage() : goods.getImage()); // 优先使用SKU图片 + orderGoods.setPrice(actualPrice); // 使用实际价格(SKU价格或商品价格) + orderGoods.setTotalNum(item.getQuantity()); + + // 计算商品小计(用于日志记录) + BigDecimal itemTotal = actualPrice.multiply(new BigDecimal(item.getQuantity())); + + // 设置商品规格信息 + orderGoods.setSpec(specInfo); + + // 设置支付相关信息 + orderGoods.setPayStatus(0); // 0 未付款 + orderGoods.setOrderStatus(0); // 0 未使用 + orderGoods.setIsFree(false); // 默认收费 + orderGoods.setVersion(0); // 当前版本 + + // 设置其他信息 + orderGoods.setComments(request.getComments()); + orderGoods.setUserId(shopOrder.getUserId()); + orderGoods.setTenantId(shopOrder.getTenantId()); + + orderGoodsList.add(orderGoods); + + log.debug("准备保存订单商品 - 商品ID:{},名称:{},单价:{},数量:{},小计:{}", + goods.getGoodsId(), goods.getName(), goods.getPrice(), item.getQuantity(), itemTotal); + } + + // 批量保存订单商品 + boolean saved = shopOrderGoodsService.saveBatch(orderGoodsList); + if (!saved) { + throw new BusinessException("保存订单商品失败"); + } + + // 扣减库存 + deductStock(request); + + log.info("成功保存订单商品,订单号:{},商品数量:{}", shopOrder.getOrderNo(), orderGoodsList.size()); + } + + /** + * 扣减库存 + */ + private void deductStock(OrderCreateRequest request) { + for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + if (item.getSkuId() != null) { + // 多规格商品,扣减SKU库存 + ShopGoodsSku sku = shopGoodsSkuService.getById(item.getSkuId()); + if (sku != null && sku.getStock() != null) { + int newStock = sku.getStock() - item.getQuantity(); + if (newStock < 0) { + throw new BusinessException("SKU库存不足,无法完成扣减"); + } + sku.setStock(newStock); + shopGoodsSkuService.updateById(sku); + log.debug("扣减SKU库存 - SKU ID:{},扣减数量:{},剩余库存:{}", + item.getSkuId(), item.getQuantity(), newStock); + } + } else { + // 单规格商品,扣减商品库存 + ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); + if (goods != null && goods.getStock() != null) { + int newStock = goods.getStock() - item.getQuantity(); + if (newStock < 0) { + throw new BusinessException("商品库存不足,无法完成扣减"); + } + goods.setStock(newStock); + shopGoodsService.updateById(goods); + log.debug("扣减商品库存 - 商品ID:{},扣减数量:{},剩余库存:{}", + item.getGoodsId(), item.getQuantity(), newStock); + } + } + } + log.info("库存扣减完成"); + } + + /** + * 标记优惠券为已使用 + */ + private void markCouponAsUsed(Integer couponId, Integer orderId) { + try { + ShopUserCoupon coupon = shopUserCouponService.getById(couponId); + if (coupon != null) { + // 使用实体类提供的方法标记为已使用 + coupon.markAsUsed(orderId, null); // orderNo 在这里可以为null,因为已经有orderId了 + shopUserCouponService.updateById(coupon); + log.info("优惠券标记为已使用 - 优惠券ID:{},订单ID:{}", couponId, orderId); + } + } catch (Exception e) { + log.error("标记优惠券为已使用失败 - 优惠券ID:{},订单ID:{}", couponId, orderId, e); + // 不抛出异常,避免影响订单创建流程 + } + } + + /** + * 检查是否为测试账号11 + */ + public boolean isTestAccount(String phone) { + return orderConfig.isTestAccount(phone); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/OrderCancelService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/OrderCancelService.java new file mode 100644 index 0000000..da40112 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/OrderCancelService.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.shop.service; + +import com.gxwebsoft.shop.entity.ShopOrder; + +import java.util.List; + +/** + * 订单取消服务接口 + * + * @author WebSoft + * @since 2025-01-26 + */ +public interface OrderCancelService { + + /** + * 取消单个订单 + * + * @param order 订单对象 + * @return 是否取消成功 + */ + boolean cancelOrder(ShopOrder order); + + /** + * 批量取消订单 + * + * @param orders 订单列表 + * @return 成功取消的订单数量 + */ + int batchCancelOrders(List orders); + + /** + * 查找超时的待付款订单 + * + * @param timeoutMinutes 超时时间(分钟) + * @param batchSize 批量大小 + * @return 超时订单列表 + */ + List findExpiredUnpaidOrders(Integer timeoutMinutes, Integer batchSize); + + /** + * 查找指定租户的超时订单 + * + * @param tenantId 租户ID + * @param timeoutMinutes 超时时间(分钟) + * @param batchSize 批量大小 + * @return 超时订单列表 + */ + List findExpiredUnpaidOrdersByTenant(Integer tenantId, Integer timeoutMinutes, Integer batchSize); + + /** + * 回退订单库存 + * + * @param order 订单对象 + * @return 是否回退成功 + */ + boolean restoreOrderStock(ShopOrder order); + + /** + * 退还订单优惠券 + * + * @param order 订单对象 + * @return 是否退还成功 + */ + boolean returnOrderCoupon(ShopOrder order); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java new file mode 100644 index 0000000..da3c943 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; + +import java.util.List; + +/** + * 商品文章Service + * + * @author 科技小王子 + * @since 2025-08-13 05:14:53 + */ +public interface ShopArticleService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopArticleParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopArticleParam param); + + /** + * 根据id查询 + * + * @param articleId 文章ID + * @return ShopArticle + */ + ShopArticle getByIdRel(Integer articleId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopBrandService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopBrandService.java new file mode 100644 index 0000000..294a1f5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopBrandService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopBrand; +import com.gxwebsoft.shop.param.ShopBrandParam; + +import java.util.List; + +/** + * 品牌Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopBrandService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopBrandParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopBrandParam param); + + /** + * 根据id查询 + * + * @param brandId ID + * @return ShopBrand + */ + ShopBrand getByIdRel(Integer brandId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCartService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCartService.java new file mode 100644 index 0000000..18d4979 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCartService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCart; +import com.gxwebsoft.shop.param.ShopCartParam; + +import java.util.List; + +/** + * 购物车Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopCartService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCartParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCartParam param); + + /** + * 根据id查询 + * + * @param id 购物车表ID + * @return ShopCart + */ + ShopCart getByIdRel(Long id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCategoryService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCategoryService.java new file mode 100644 index 0000000..5ac828e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCategoryService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCategory; +import com.gxwebsoft.shop.param.ShopCategoryParam; + +import java.util.List; + +/** + * 商品分类Service + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +public interface ShopCategoryService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCategoryParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCategoryParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return ShopCategory + */ + ShopCategory getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopChatConversationService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopChatConversationService.java new file mode 100644 index 0000000..32eeac3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopChatConversationService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopChatConversation; +import com.gxwebsoft.shop.param.ShopChatConversationParam; + +import java.util.List; + +/** + * 聊天消息表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopChatConversationService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopChatConversationParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopChatConversationParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return ShopChatConversation + */ + ShopChatConversation getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopChatMessageService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopChatMessageService.java new file mode 100644 index 0000000..c1b40a8 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopChatMessageService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopChatMessage; +import com.gxwebsoft.shop.param.ShopChatMessageParam; + +import java.util.List; + +/** + * 聊天消息表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopChatMessageService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopChatMessageParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopChatMessageParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return ShopChatMessage + */ + ShopChatMessage getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCommissionRoleService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCommissionRoleService.java new file mode 100644 index 0000000..e9ef11e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCommissionRoleService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCommissionRole; +import com.gxwebsoft.shop.param.ShopCommissionRoleParam; + +import java.util.List; + +/** + * 分红角色Service + * + * @author 科技小王子 + * @since 2025-05-01 10:01:15 + */ +public interface ShopCommissionRoleService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCommissionRoleParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCommissionRoleParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopCommissionRole + */ + ShopCommissionRole getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCountService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCountService.java new file mode 100644 index 0000000..65af394 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCountService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCount; +import com.gxwebsoft.shop.param.ShopCountParam; + +import java.util.List; + +/** + * 商城销售统计表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopCountService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCountParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCountParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return ShopCount + */ + ShopCount getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponApplyCateService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponApplyCateService.java new file mode 100644 index 0000000..f247bf7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponApplyCateService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCouponApplyCate; +import com.gxwebsoft.shop.param.ShopCouponApplyCateParam; + +import java.util.List; + +/** + * 优惠券可用分类Service + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +public interface ShopCouponApplyCateService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCouponApplyCateParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCouponApplyCateParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopCouponApplyCate + */ + ShopCouponApplyCate getByIdRel(Integer id); + + void removeByCouponId(Integer couponId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponApplyItemService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponApplyItemService.java new file mode 100644 index 0000000..bcca01d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponApplyItemService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.param.ShopCouponApplyItemParam; + +import java.util.List; + +/** + * 优惠券可用分类Service + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +public interface ShopCouponApplyItemService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCouponApplyItemParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCouponApplyItemParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopCouponApplyItem + */ + ShopCouponApplyItem getByIdRel(Integer id); + + void removeByCouponId(Integer couponId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponService.java new file mode 100644 index 0000000..074b62c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopCouponService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.param.ShopCouponParam; + +import java.util.List; + +/** + * 优惠券Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:23 + */ +public interface ShopCouponService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopCouponParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopCouponParam param); + + /** + * 根据id查询 + * + * @param id id + * @return ShopCoupon + */ + ShopCoupon getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerApplyService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerApplyService.java new file mode 100644 index 0000000..9ea4d40 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerApplyService.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerApply; +import com.gxwebsoft.shop.param.ShopDealerApplyParam; + +import java.util.List; + +/** + * 分销商申请记录表Service + * + * @author 科技小王子 + * @since 2025-08-11 23:50:18 + */ +public interface ShopDealerApplyService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerApplyParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerApplyParam param); + + /** + * 根据id查询 + * + * @param applyId 主键ID + * @return ShopDealerApply + */ + ShopDealerApply getByIdRel(Integer applyId); + + ShopDealerApply getByUserIdRel(Integer userId); + + ShopDealerApply getByDealerNameRel(String dealerName); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerBankService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerBankService.java new file mode 100644 index 0000000..aba0ab0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerBankService.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerBank; +import com.gxwebsoft.shop.param.ShopDealerBankParam; + +import java.util.List; + +/** + * 分销商提现银行卡Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerBankService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerBankParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerBankParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopDealerBank + */ + ShopDealerBank getByIdRel(Integer id); + + /** + * 获取默认银行卡 + * @return List + */ + ShopDealerBank getDefaultBank(Integer userId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerCapitalService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerCapitalService.java new file mode 100644 index 0000000..67fb29c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerCapitalService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerCapital; +import com.gxwebsoft.shop.param.ShopDealerCapitalParam; + +import java.util.List; + +/** + * 分销商资金明细表Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerCapitalService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerCapitalParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerCapitalParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopDealerCapital + */ + ShopDealerCapital getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerOrderService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerOrderService.java new file mode 100644 index 0000000..8390e29 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerOrderService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerOrder; +import com.gxwebsoft.shop.param.ShopDealerOrderParam; + +import java.util.List; + +/** + * 分销商订单记录表Service + * + * @author 科技小王子 + * @since 2025-08-12 11:55:18 + */ +public interface ShopDealerOrderService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerOrderParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerOrderParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopDealerOrder + */ + ShopDealerOrder getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerRecordService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerRecordService.java new file mode 100644 index 0000000..d27357b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerRecordService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerRecord; +import com.gxwebsoft.shop.param.ShopDealerRecordParam; + +import java.util.List; + +/** + * 客户跟进情况Service + * + * @author 科技小王子 + * @since 2025-10-02 12:21:50 + */ +public interface ShopDealerRecordService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerRecordParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerRecordParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return ShopDealerRecord + */ + ShopDealerRecord getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerRefereeService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerRefereeService.java new file mode 100644 index 0000000..87bacd1 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerRefereeService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerReferee; +import com.gxwebsoft.shop.param.ShopDealerRefereeParam; + +import java.util.List; + +/** + * 分销商推荐关系表Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerRefereeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerRefereeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerRefereeParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopDealerReferee + */ + ShopDealerReferee getByIdRel(Integer id); + + ShopDealerReferee getByUserIdRel(Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerSettingService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerSettingService.java new file mode 100644 index 0000000..b9b1c7b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerSettingService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerSetting; +import com.gxwebsoft.shop.param.ShopDealerSettingParam; + +import java.util.List; + +/** + * 分销商设置表Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerSettingService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerSettingParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerSettingParam param); + + /** + * 根据id查询 + * + * @param key 设置项标示 + * @return ShopDealerSetting + */ + ShopDealerSetting getByIdRel(String key); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerUserService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerUserService.java new file mode 100644 index 0000000..8e86728 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerUserService.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerUser; +import com.gxwebsoft.shop.param.ShopDealerUserParam; + +import java.util.List; + +/** + * 分销商用户记录表Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerUserService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerUserParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerUserParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopDealerUser + */ + ShopDealerUser getByIdRel(Integer id); + + ShopDealerUser getByUserIdRel(Integer userId); + + boolean updateByUserId(ShopDealerUser shopDealerUser); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerWithdrawService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerWithdrawService.java new file mode 100644 index 0000000..61731e3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopDealerWithdrawService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerWithdraw; +import com.gxwebsoft.shop.param.ShopDealerWithdrawParam; + +import java.util.List; + +/** + * 分销商提现明细表Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopDealerWithdrawService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopDealerWithdrawParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopDealerWithdrawParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopDealerWithdraw + */ + ShopDealerWithdraw getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressService.java new file mode 100644 index 0000000..92dae06 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopExpress; +import com.gxwebsoft.shop.param.ShopExpressParam; + +import java.util.List; + +/** + * 物流公司Service + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +public interface ShopExpressService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopExpressParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopExpressParam param); + + /** + * 根据id查询 + * + * @param expressId 物流公司ID + * @return ShopExpress + */ + ShopExpress getByIdRel(Integer expressId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressTemplateDetailService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressTemplateDetailService.java new file mode 100644 index 0000000..b63be6f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressTemplateDetailService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopExpressTemplateDetail; +import com.gxwebsoft.shop.param.ShopExpressTemplateDetailParam; + +import java.util.List; + +/** + * 运费模板Service + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +public interface ShopExpressTemplateDetailService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopExpressTemplateDetailParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopExpressTemplateDetailParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopExpressTemplateDetail + */ + ShopExpressTemplateDetail getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressTemplateService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressTemplateService.java new file mode 100644 index 0000000..0c8c003 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopExpressTemplateService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopExpressTemplate; +import com.gxwebsoft.shop.param.ShopExpressTemplateParam; + +import java.util.List; + +/** + * 运费模板Service + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +public interface ShopExpressTemplateService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopExpressTemplateParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopExpressTemplateParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopExpressTemplate + */ + ShopExpressTemplate getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGiftService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGiftService.java new file mode 100644 index 0000000..5ff156d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGiftService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGift; +import com.gxwebsoft.shop.param.ShopGiftParam; + +import java.util.List; + +/** + * 礼品卡Service + * + * @author 科技小王子 + * @since 2025-08-11 18:07:31 + */ +public interface ShopGiftService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGiftParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGiftParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopGift + */ + ShopGift getByIdRel(Integer id); + + ShopGift getByCode(String code); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsCategoryService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsCategoryService.java new file mode 100644 index 0000000..5dbed7e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsCategoryService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsCategory; +import com.gxwebsoft.shop.param.ShopGoodsCategoryParam; + +import java.util.List; + +/** + * 商品分类Service + * + * @author 科技小王子 + * @since 2025-05-01 00:36:45 + */ +public interface ShopGoodsCategoryService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsCategoryParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsCategoryParam param); + + /** + * 根据id查询 + * + * @param categoryId 商品分类ID + * @return ShopGoodsCategory + */ + ShopGoodsCategory getByIdRel(Integer categoryId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsCommentService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsCommentService.java new file mode 100644 index 0000000..6fc33d4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsCommentService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsComment; +import com.gxwebsoft.shop.param.ShopGoodsCommentParam; + +import java.util.List; + +/** + * 评论表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsCommentService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsCommentParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsCommentParam param); + + /** + * 根据id查询 + * + * @param id 评论ID + * @return ShopGoodsComment + */ + ShopGoodsComment getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsIncomeConfigService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsIncomeConfigService.java new file mode 100644 index 0000000..5784743 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsIncomeConfigService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsIncomeConfig; +import com.gxwebsoft.shop.param.ShopGoodsIncomeConfigParam; + +import java.util.List; + +/** + * 分润配置Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsIncomeConfigService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsIncomeConfigParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsIncomeConfigParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopGoodsIncomeConfig + */ + ShopGoodsIncomeConfig getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsLogService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsLogService.java new file mode 100644 index 0000000..0c8d53b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsLogService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsLog; +import com.gxwebsoft.shop.param.ShopGoodsLogParam; + +import java.util.List; + +/** + * 商品日志表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsLogService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsLogParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsLogParam param); + + /** + * 根据id查询 + * + * @param id 统计ID + * @return ShopGoodsLog + */ + ShopGoodsLog getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsRelationService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsRelationService.java new file mode 100644 index 0000000..9c43aa9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsRelationService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsRelation; +import com.gxwebsoft.shop.param.ShopGoodsRelationParam; + +import java.util.List; + +/** + * 商品点赞和收藏表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopGoodsRelationService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsRelationParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsRelationParam param); + + /** + * 根据id查询 + * + * @param id id + * @return ShopGoodsRelation + */ + ShopGoodsRelation getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsRoleCommissionService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsRoleCommissionService.java new file mode 100644 index 0000000..6ff923f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsRoleCommissionService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsRoleCommission; +import com.gxwebsoft.shop.param.ShopGoodsRoleCommissionParam; + +import java.util.List; + +/** + * 商品绑定角色的分润金额Service + * + * @author 科技小王子 + * @since 2025-05-01 09:53:38 + */ +public interface ShopGoodsRoleCommissionService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsRoleCommissionParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsRoleCommissionParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopGoodsRoleCommission + */ + ShopGoodsRoleCommission getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsService.java new file mode 100644 index 0000000..115cf42 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsService.java @@ -0,0 +1,52 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.param.ShopGoodsParam; + +import java.util.List; + +/** + * 商品Service + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +public interface ShopGoodsService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsParam param); + + /** + * 根据id查询 + * + * @param goodsId 自增ID + * @return ShopGoods + */ + ShopGoods getByIdRel(Integer goodsId); + + /** + * 累加商品销售数量 + * 忽略租户隔离,确保能更新成功 + * + * @param goodsId 商品ID + * @param saleCount 累加的销售数量 + * @return 是否更新成功 + */ + boolean addSaleCount(Integer goodsId, Integer saleCount); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsSkuService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsSkuService.java new file mode 100644 index 0000000..1431347 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsSkuService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsSku; +import com.gxwebsoft.shop.param.ShopGoodsSkuParam; + +import java.util.List; + +/** + * 商品sku列表Service + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +public interface ShopGoodsSkuService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsSkuParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsSkuParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopGoodsSku + */ + ShopGoodsSku getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsSpecService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsSpecService.java new file mode 100644 index 0000000..32250e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopGoodsSpecService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopGoodsSpec; +import com.gxwebsoft.shop.param.ShopGoodsSpecParam; + +import java.util.List; + +/** + * 商品多规格Service + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +public interface ShopGoodsSpecService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopGoodsSpecParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopGoodsSpecParam param); + + /** + * 根据id查询 + * + * @param id 主键 + * @return ShopGoodsSpec + */ + ShopGoodsSpec getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantAccountService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantAccountService.java new file mode 100644 index 0000000..127420f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantAccountService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopMerchantAccount; +import com.gxwebsoft.shop.param.ShopMerchantAccountParam; + +import java.util.List; + +/** + * 商户账号Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopMerchantAccountService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopMerchantAccountParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopMerchantAccountParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return ShopMerchantAccount + */ + ShopMerchantAccount getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantApplyService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantApplyService.java new file mode 100644 index 0000000..7eeaf21 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantApplyService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopMerchantApply; +import com.gxwebsoft.shop.param.ShopMerchantApplyParam; + +import java.util.List; + +/** + * 商户入驻申请Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopMerchantApplyService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopMerchantApplyParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopMerchantApplyParam param); + + /** + * 根据id查询 + * + * @param applyId ID + * @return ShopMerchantApply + */ + ShopMerchantApply getByIdRel(Integer applyId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantService.java new file mode 100644 index 0000000..f3fb956 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopMerchant; +import com.gxwebsoft.shop.param.ShopMerchantParam; + +import java.util.List; + +/** + * 商户Service + * + * @author 科技小王子 + * @since 2025-08-10 20:43:33 + */ +public interface ShopMerchantService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopMerchantParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopMerchantParam param); + + /** + * 根据id查询 + * + * @param merchantId ID + * @return ShopMerchant + */ + ShopMerchant getByIdRel(Long merchantId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantTypeService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantTypeService.java new file mode 100644 index 0000000..e0922d2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopMerchantTypeService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopMerchantType; +import com.gxwebsoft.shop.param.ShopMerchantTypeParam; + +import java.util.List; + +/** + * 商户类型Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopMerchantTypeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopMerchantTypeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopMerchantTypeParam param); + + /** + * 根据id查询 + * + * @param id ID + * @return ShopMerchantType + */ + ShopMerchantType getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderDeliveryGoodsService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderDeliveryGoodsService.java new file mode 100644 index 0000000..55699ac --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderDeliveryGoodsService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopOrderDeliveryGoods; +import com.gxwebsoft.shop.param.ShopOrderDeliveryGoodsParam; + +import java.util.List; + +/** + * 发货单商品Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderDeliveryGoodsService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopOrderDeliveryGoodsParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopOrderDeliveryGoodsParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopOrderDeliveryGoods + */ + ShopOrderDeliveryGoods getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderDeliveryService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderDeliveryService.java new file mode 100644 index 0000000..1253f5b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderDeliveryService.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.entity.ShopOrderDelivery; +import com.gxwebsoft.shop.param.ShopOrderDeliveryParam; + +import java.util.List; +import java.util.Map; + +/** + * 发货单Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderDeliveryService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopOrderDeliveryParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopOrderDeliveryParam param); + + /** + * 根据id查询 + * + * @param deliveryId 发货单ID + * @return ShopOrderDelivery + */ + ShopOrderDelivery getByIdRel(Integer deliveryId); + + ShopOrderDelivery getByOrderId(Integer orderId); + + Map setExpress(User user, ShopOrderDelivery orderDelivery, ShopOrder order) throws Exception; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderExtractService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderExtractService.java new file mode 100644 index 0000000..d0a3bd6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderExtractService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopOrderExtract; +import com.gxwebsoft.shop.param.ShopOrderExtractParam; + +import java.util.List; + +/** + * 自提订单联系方式Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderExtractService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopOrderExtractParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopOrderExtractParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopOrderExtract + */ + ShopOrderExtract getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderGoodsService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderGoodsService.java new file mode 100644 index 0000000..d9a7e9a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderGoodsService.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopOrderGoods; +import com.gxwebsoft.shop.param.ShopOrderGoodsParam; + +import java.util.List; + +/** + * 商品信息Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderGoodsService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopOrderGoodsParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopOrderGoodsParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return ShopOrderGoods + */ + ShopOrderGoods getByIdRel(Integer id); + + List getListByOrderId(Integer orderId); + + /** + * 根据订单ID查询订单商品列表(忽略租户隔离) + * @param orderId 订单ID + * @return List + */ + List getListByOrderIdIgnoreTenant(Integer orderId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderInfoLogService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderInfoLogService.java new file mode 100644 index 0000000..9ede6f7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderInfoLogService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopOrderInfoLog; +import com.gxwebsoft.shop.param.ShopOrderInfoLogParam; + +import java.util.List; + +/** + * 订单核销Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderInfoLogService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopOrderInfoLogParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopOrderInfoLogParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopOrderInfoLog + */ + ShopOrderInfoLog getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderInfoService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderInfoService.java new file mode 100644 index 0000000..f5a53fa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderInfoService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopOrderInfo; +import com.gxwebsoft.shop.param.ShopOrderInfoParam; + +import java.util.List; + +/** + * 场地Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderInfoService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopOrderInfoParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopOrderInfoParam param); + + /** + * 根据id查询 + * + * @param id 自增ID + * @return ShopOrderInfo + */ + ShopOrderInfo getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderService.java new file mode 100644 index 0000000..8644e62 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderService.java @@ -0,0 +1,79 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.param.ShopOrderParam; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; + +/** + * 订单Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopOrderParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopOrderParam param); + + /** + * 根据id查询 + * + * @param orderId 订单号 + * @return ShopOrder + */ + ShopOrder getByIdRel(Integer orderId); + + HashMap createWxOrder(ShopOrder shopOrder); + + ShopOrder getByOutTradeNo(String outTradeNo); + + Boolean queryOrderByOutTradeNo(ShopOrder shopOrder); + + void updateByOutTradeNo(ShopOrder order); + + /** + * 统计订单总金额 + * + * @return 订单总金额 + */ + BigDecimal total(); + + /** + * 根据订单号查询订单 + * + * @param orderNo 订单号 + * @param tenantId 租户ID + * @return ShopOrder + */ + ShopOrder getByOrderNo(String orderNo, Integer tenantId); + + /** + * 同步支付状态 + * + * @param orderNo 订单号 + * @param paymentStatus 支付状态:1=支付成功,0=支付失败 + * @param transactionId 微信交易号 + * @param payTime 支付时间 + * @param tenantId 租户ID + * @return 是否更新成功 + */ + boolean syncPaymentStatus(String orderNo, Integer paymentStatus, String transactionId, String payTime, Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderUpdate10550Service.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderUpdate10550Service.java new file mode 100644 index 0000000..2399a6d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopOrderUpdate10550Service.java @@ -0,0 +1,21 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.entity.ShopOrderDelivery; +import com.gxwebsoft.shop.param.ShopOrderDeliveryParam; + +import java.util.List; + +/** + * 发货单Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopOrderUpdate10550Service { + + + void update(ShopOrder shopOrder); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopRechargeOrderService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopRechargeOrderService.java new file mode 100644 index 0000000..dcb936a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopRechargeOrderService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopRechargeOrder; +import com.gxwebsoft.shop.param.ShopRechargeOrderParam; + +import java.util.List; + +/** + * 会员充值订单表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +public interface ShopRechargeOrderService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopRechargeOrderParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopRechargeOrderParam param); + + /** + * 根据id查询 + * + * @param orderId 订单ID + * @return ShopRechargeOrder + */ + ShopRechargeOrder getByIdRel(Integer orderId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSpecService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSpecService.java new file mode 100644 index 0000000..2db6368 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSpecService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopSpec; +import com.gxwebsoft.shop.param.ShopSpecParam; + +import java.util.List; + +/** + * 规格Service + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +public interface ShopSpecService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopSpecParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopSpecParam param); + + /** + * 根据id查询 + * + * @param specId 规格ID + * @return ShopSpec + */ + ShopSpec getByIdRel(Integer specId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSpecValueService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSpecValueService.java new file mode 100644 index 0000000..f16f347 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSpecValueService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopSpecValue; +import com.gxwebsoft.shop.param.ShopSpecValueParam; + +import java.util.List; + +/** + * 规格值Service + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +public interface ShopSpecValueService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopSpecValueParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopSpecValueParam param); + + /** + * 根据id查询 + * + * @param specValueId 规格值ID + * @return ShopSpecValue + */ + ShopSpecValue getByIdRel(Integer specValueId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSplashService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSplashService.java new file mode 100644 index 0000000..0087a1e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopSplashService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopSplash; +import com.gxwebsoft.shop.param.ShopSplashParam; + +import java.util.List; + +/** + * 开屏广告Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopSplashService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopSplashParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopSplashParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopSplash + */ + ShopSplash getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserAddressService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserAddressService.java new file mode 100644 index 0000000..70880e4 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserAddressService.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUserAddress; +import com.gxwebsoft.shop.param.ShopUserAddressParam; + +import java.util.List; + +/** + * 收货地址Service + * + * @author 科技小王子 + * @since 2025-07-22 23:06:40 + */ +public interface ShopUserAddressService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopUserAddressParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopUserAddressParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopUserAddress + */ + ShopUserAddress getByIdRel(Integer id); + + /** + * 获取用户默认收货地址 + * + * @param userId 用户ID + * @return ShopUserAddress + */ + ShopUserAddress getDefaultAddress(Integer userId); + + /** + * 获取用户所有收货地址 + * + * @param userId 用户ID + * @return List + */ + List getUserAddresses(Integer userId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserBalanceLogService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserBalanceLogService.java new file mode 100644 index 0000000..08e4087 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserBalanceLogService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUserBalanceLog; +import com.gxwebsoft.shop.param.ShopUserBalanceLogParam; + +import java.util.List; + +/** + * 用户余额变动明细表Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopUserBalanceLogService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopUserBalanceLogParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopUserBalanceLogParam param); + + /** + * 根据id查询 + * + * @param logId 主键ID + * @return ShopUserBalanceLog + */ + ShopUserBalanceLog getByIdRel(Integer logId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserCollectionService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserCollectionService.java new file mode 100644 index 0000000..bc74a59 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserCollectionService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUserCollection; +import com.gxwebsoft.shop.param.ShopUserCollectionParam; + +import java.util.List; + +/** + * 我的收藏Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopUserCollectionService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopUserCollectionParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopUserCollectionParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopUserCollection + */ + ShopUserCollection getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserCouponService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserCouponService.java new file mode 100644 index 0000000..e237cca --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserCouponService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.param.ShopUserCouponParam; + +import java.util.List; + +/** + * 用户优惠券Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopUserCouponService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopUserCouponParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopUserCouponParam param); + + /** + * 根据id查询 + * + * @param id id + * @return ShopUserCoupon + */ + ShopUserCoupon getByIdRel(Integer id); + + List userList(Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserRefereeService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserRefereeService.java new file mode 100644 index 0000000..624627f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserRefereeService.java @@ -0,0 +1,43 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUserReferee; +import com.gxwebsoft.shop.param.ShopUserRefereeParam; + +import java.util.List; + +/** + * 用户推荐关系表Service + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +public interface ShopUserRefereeService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopUserRefereeParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopUserRefereeParam param); + + /** + * 根据id查询 + * + * @param id 主键ID + * @return ShopUserReferee + */ + ShopUserReferee getByIdRel(Integer id); + + ShopUserReferee getByUserIdRel(Integer userId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserService.java new file mode 100644 index 0000000..52d8fba --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopUserService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUser; +import com.gxwebsoft.shop.param.ShopUserParam; + +import java.util.List; + +/** + * 用户记录表Service + * + * @author 科技小王子 + * @since 2025-10-03 13:41:09 + */ +public interface ShopUserService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopUserParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopUserParam param); + + /** + * 根据id查询 + * + * @param userId 用户id + * @return ShopUser + */ + ShopUser getByIdRel(Integer userId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopWebsiteService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopWebsiteService.java new file mode 100644 index 0000000..6b9bef6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopWebsiteService.java @@ -0,0 +1,27 @@ +package com.gxwebsoft.shop.service; + +import com.gxwebsoft.shop.vo.ShopVo; + +/** + * 商城网站服务接口 + * + * @author 科技小王子 + * @since 2025-08-13 + */ +public interface ShopWebsiteService { + + /** + * 获取商城基本信息(VO格式) + * + * @param tenantId 租户ID + * @return 商城信息VO + */ + ShopVo getShopInfo(Integer tenantId); + + /** + * 清除商城信息缓存 + * + * @param tenantId 租户ID + */ + void clearShopInfoCache(Integer tenantId); +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopWechatDepositService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopWechatDepositService.java new file mode 100644 index 0000000..9c4b0ad --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/ShopWechatDepositService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopWechatDeposit; +import com.gxwebsoft.shop.param.ShopWechatDepositParam; + +import java.util.List; + +/** + * 押金Service + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +public interface ShopWechatDepositService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopWechatDepositParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopWechatDepositParam param); + + /** + * 根据id查询 + * + * @param id + * @return ShopWechatDeposit + */ + ShopWechatDeposit getByIdRel(Integer id); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/UserBalanceLogService.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/UserBalanceLogService.java new file mode 100644 index 0000000..af7a18a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/UserBalanceLogService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.UserBalanceLog; +import com.gxwebsoft.common.system.param.UserBalanceLogParam; + +import java.util.List; + +/** + * 用户余额变动明细表Service + * + * @author 科技小王子 + * @since 2023-04-21 15:59:09 + */ +public interface UserBalanceLogService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(UserBalanceLogParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(UserBalanceLogParam param); + + /** + * 根据id查询 + * + * @param logId 主键ID + * @return UserBalanceLog + */ + UserBalanceLog getByIdRel(Integer logId); + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/CouponStatusServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/CouponStatusServiceImpl.java new file mode 100644 index 0000000..1700188 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/CouponStatusServiceImpl.java @@ -0,0 +1,339 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.service.CouponStatusService; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.service.ShopCouponApplyItemService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 优惠券状态管理服务实现 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +@Service +public class CouponStatusServiceImpl implements CouponStatusService { + + @Autowired + private ShopUserCouponService shopUserCouponService; + + @Autowired + private ShopCouponService shopCouponService; + + @Autowired + private ShopCouponApplyItemService shopCouponApplyItemService; + + @Override + public List getAvailableCoupons(Integer userId) { + List allCoupons = getUserCoupons(userId); + return allCoupons.stream() + .filter(ShopUserCoupon::isAvailable) + .collect(Collectors.toList()); + } + + @Override + public List getUsedCoupons(Integer userId) { + return shopUserCouponService.list( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getUserId, userId) + .eq(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_USED) + .orderByDesc(ShopUserCoupon::getUseTime) + ); + } + + @Override + public List getExpiredCoupons(Integer userId) { + // 先更新过期状态 + updateExpiredCouponsForUser(userId); + + return shopUserCouponService.list( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getUserId, userId) + .eq(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_EXPIRED) + .orderByDesc(ShopUserCoupon::getEndTime) + ); + } + + @Override + public CouponStatusResult getUserCouponsGroupByStatus(Integer userId) { + List availableCoupons = getAvailableCoupons(userId); + List usedCoupons = getUsedCoupons(userId); + List expiredCoupons = getExpiredCoupons(userId); + + return new CouponStatusResult(availableCoupons, usedCoupons, expiredCoupons); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean useCoupon(Long userCouponId, Integer orderId, String orderNo) { + try { + ShopUserCoupon userCoupon = shopUserCouponService.getById(userCouponId); + if (userCoupon == null) { + log.warn("优惠券不存在: {}", userCouponId); + return false; + } + + if (!userCoupon.isAvailable()) { + log.warn("优惠券不可用: {}, 状态: {}", userCouponId, userCoupon.getStatusDesc()); + return false; + } + + // 标记为已使用 + userCoupon.markAsUsed(orderId, orderNo); + + return shopUserCouponService.updateById(userCoupon); + } catch (Exception e) { + log.error("使用优惠券失败: {}", userCouponId, e); + return false; + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean returnCoupon(Integer orderId) { + try { + ShopUserCoupon userCoupon = shopUserCouponService.getOne( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getOrderId, orderId) + .eq(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_USED) + ); + + if (userCoupon == null) { + log.info("订单没有使用优惠券: {}", orderId); + return true; + } + + // 检查是否已过期 + if (userCoupon.isExpired()) { + log.warn("优惠券已过期,无法退还: {}", userCoupon.getId()); + return false; + } + + // 恢复为未使用状态 + userCoupon.setStatus(ShopUserCoupon.STATUS_UNUSED); + userCoupon.setIsUse(0); + userCoupon.setUseTime(null); + userCoupon.setOrderId(null); + userCoupon.setOrderNo(null); + + return shopUserCouponService.updateById(userCoupon); + } catch (Exception e) { + log.error("退还优惠券失败, 订单ID: {}", orderId, e); + return false; + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int updateExpiredCoupons() { + try { + // 查询所有未使用且已过期的优惠券 + List expiredCoupons = shopUserCouponService.list( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_UNUSED) + .lt(ShopUserCoupon::getEndTime, LocalDateTime.now()) + ); + + if (expiredCoupons.isEmpty()) { + return 0; + } + + // 批量更新状态 + List expiredIds = expiredCoupons.stream() + .map(ShopUserCoupon::getId) + .collect(Collectors.toList()); + + boolean success = shopUserCouponService.update( + new LambdaUpdateWrapper() + .in(ShopUserCoupon::getId, expiredIds) + .set(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_EXPIRED) + .set(ShopUserCoupon::getIsExpire, 1) + ); + + int updatedCount = success ? expiredIds.size() : 0; + log.info("批量更新过期优惠券状态完成,更新数量: {}", updatedCount); + return updatedCount; + } catch (Exception e) { + log.error("批量更新过期优惠券状态失败", e); + return 0; + } + } + + @Override + public boolean checkAndUpdateCouponStatus(ShopUserCoupon userCoupon) { + if (userCoupon == null) { + return false; + } + + boolean statusChanged = false; + + // 检查是否过期 + if (userCoupon.getStatus() == ShopUserCoupon.STATUS_UNUSED && userCoupon.isExpired()) { + userCoupon.markAsExpired(); + statusChanged = true; + } + + // 如果状态发生变化,更新数据库 + if (statusChanged) { + try { + shopUserCouponService.updateById(userCoupon); + log.debug("更新优惠券状态: {} -> {}", userCoupon.getId(), userCoupon.getStatusDesc()); + } catch (Exception e) { + log.error("更新优惠券状态失败: {}", userCoupon.getId(), e); + return false; + } + } + + return statusChanged; + } + + @Override + public CouponValidationResult validateCouponForOrder(Long userCouponId, + BigDecimal totalAmount, + List goodsIds) { + try { + ShopUserCoupon userCoupon = shopUserCouponService.getById(userCouponId); + if (userCoupon == null) { + return new CouponValidationResult(false, "优惠券不存在"); + } + + // 检查优惠券状态 + if (!userCoupon.isAvailable()) { + return new CouponValidationResult(false, "优惠券" + userCoupon.getStatusDesc()); + } + + // 检查最低消费金额 + if (userCoupon.getMinPrice() != null && + totalAmount.compareTo(userCoupon.getMinPrice()) < 0) { + return new CouponValidationResult(false, + String.format("订单金额不满足最低消费要求,需满%s元", userCoupon.getMinPrice())); + } + + // 检查适用范围 + if (!validateApplyRange(userCoupon, goodsIds)) { + return new CouponValidationResult(false, "优惠券不适用于当前商品"); + } + + // 计算优惠金额 + BigDecimal discountAmount = calculateDiscountAmount(userCoupon, totalAmount); + + return new CouponValidationResult(true, "优惠券可用", discountAmount); + } catch (Exception e) { + log.error("验证优惠券失败: {}", userCouponId, e); + return new CouponValidationResult(false, "验证优惠券时发生错误"); + } + } + + /** + * 获取用户所有优惠券 + */ + private List getUserCoupons(Integer userId) { + List coupons = shopUserCouponService.list( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getUserId, userId) + .orderByAsc(ShopUserCoupon::getEndTime) + ); + + // 检查并更新状态 + coupons.forEach(this::checkAndUpdateCouponStatus); + + return coupons; + } + + /** + * 更新指定用户的过期优惠券 + */ + private void updateExpiredCouponsForUser(Integer userId) { + try { + shopUserCouponService.update( + new LambdaUpdateWrapper() + .eq(ShopUserCoupon::getUserId, userId) + .eq(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_UNUSED) + .lt(ShopUserCoupon::getEndTime, LocalDateTime.now()) + .set(ShopUserCoupon::getStatus, ShopUserCoupon.STATUS_EXPIRED) + .set(ShopUserCoupon::getIsExpire, 1) + ); + } catch (Exception e) { + log.error("更新用户过期优惠券失败, userId: {}", userId, e); + } + } + + /** + * 验证优惠券适用范围 + */ + private boolean validateApplyRange(ShopUserCoupon userCoupon, List goodsIds) { + if (userCoupon.getApplyRange() == null || userCoupon.getApplyRange() == ShopUserCoupon.APPLY_ALL) { + return true; // 全部商品适用 + } + + if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_GOODS) { + // 指定商品适用 + try { + List applyItems = shopCouponApplyItemService.list( + new LambdaQueryWrapper() + .eq(ShopCouponApplyItem::getCouponId, userCoupon.getCouponId()) + .eq(ShopCouponApplyItem::getType, 1) // 类型1表示商品 + ); + + // 如果数据库中还没有 goods_id 字段,暂时使用 pk 字段作为商品ID + List applicableGoodsIds = applyItems.stream() + .map(item -> { + if (item.getGoodsId() != null) { + return item.getGoodsId(); + } else if (item.getPk() != null) { + // 临时方案:使用 pk 字段作为商品ID + return item.getPk(); + } + return null; + }) + .filter(goodsId -> goodsId != null) + .collect(Collectors.toList()); + + return goodsIds.stream().anyMatch(applicableGoodsIds::contains); + } catch (Exception e) { + log.warn("查询优惠券适用商品失败,可能是数据库字段不存在: {}", e.getMessage()); + // 如果查询失败,默认返回true(允许使用) + return true; + } + } + + if (userCoupon.getApplyRange() == ShopUserCoupon.APPLY_CATEGORY) { + // 指定分类适用 - 这里需要根据商品ID查询分类ID,然后验证 + // 暂时返回true,实际项目中需要实现商品分类查询逻辑 + log.debug("分类适用范围验证暂未实现,默认通过"); + return true; + } + + return true; + } + + /** + * 计算优惠金额 + */ + private BigDecimal calculateDiscountAmount(ShopUserCoupon userCoupon, BigDecimal totalAmount) { + if (userCoupon.getType() == ShopUserCoupon.TYPE_REDUCE) { + // 满减券 + return userCoupon.getReducePrice(); + } else if (userCoupon.getType() == ShopUserCoupon.TYPE_DISCOUNT) { + // 折扣券 + BigDecimal discountRate = BigDecimal.valueOf(userCoupon.getDiscount()).divide(BigDecimal.valueOf(100)); + return totalAmount.multiply(BigDecimal.ONE.subtract(discountRate)); + } + return BigDecimal.ZERO; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/KuaiDi100Impl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/KuaiDi100Impl.java new file mode 100644 index 0000000..62bfe6b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/KuaiDi100Impl.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.shop.service.impl; + +import com.google.gson.Gson; +import com.gxwebsoft.shop.service.KuaiDi100; +import com.kuaidi100.sdk.api.QueryTrack; +import com.kuaidi100.sdk.contant.ApiInfoConstant; +import com.kuaidi100.sdk.core.BaseClient; +import com.kuaidi100.sdk.core.IBaseClient; +import com.kuaidi100.sdk.pojo.HttpResult; +import com.kuaidi100.sdk.request.*; +import com.kuaidi100.sdk.utils.SignUtils; +import org.springframework.stereotype.Service; + +@Service +public class KuaiDi100Impl implements KuaiDi100 { + private String key = "bekcrvqy1510"; + private String secret = "8c9dd34b6ff34cad9dd6a239bd0c4d26"; + private String customer = "2E5DE2DB6B39822D793FE45EDDFB00B1"; + + @Override + public HttpResult border(BOrderReq bOrderReq) throws Exception { + PrintReq printReq = new PrintReq(); + + String t = String.valueOf(System.currentTimeMillis()); + String param = new Gson().toJson(bOrderReq); + + printReq.setKey(key); + printReq.setSign(SignUtils.printSign(param, t, key, secret)); + printReq.setT(t); + printReq.setParam(param); + printReq.setMethod(ApiInfoConstant.B_ORDER_OFFICIAL_ORDER_METHOD); + System.out.println(printReq); +// IBaseClient bOrder = new BOrderOfficial(); + IBaseClient bOrder = new BaseClient() { + @Override + public String getApiUrl(BaseRequest baseRequest) { + return "https://api.kuaidi100.com/apiMock/border"; + } + }; + return bOrder.execute(printReq); + } + + @Override + public String pollList(String com, String num, String phone) throws Exception { + QueryTrackReq queryTrackReq = new QueryTrackReq(); + QueryTrackParam queryTrackParam = new QueryTrackParam(); + queryTrackParam.setCom(com); + queryTrackParam.setNum(num); + queryTrackParam.setPhone(phone); + String param = new Gson().toJson(queryTrackParam); + queryTrackReq.setSign(SignUtils.querySign(param, key, customer)); + queryTrackReq.setCustomer(customer); + queryTrackReq.setParam(param); + IBaseClient baseClient = new QueryTrack(); + return baseClient.execute(queryTrackReq).getBody(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java new file mode 100644 index 0000000..825afbb --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java @@ -0,0 +1,231 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.annotation.IgnoreTenant; +import com.gxwebsoft.shop.entity.*; +import com.gxwebsoft.shop.service.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * 订单取消服务实现 + * + * @author WebSoft + * @since 2025-01-26 + */ +@Slf4j +@Service +public class OrderCancelServiceImpl implements OrderCancelService { + + @Autowired + private ShopOrderService shopOrderService; + + @Autowired + private ShopOrderGoodsService shopOrderGoodsService; + + @Autowired + private ShopGoodsService shopGoodsService; + + @Autowired + private ShopGoodsSkuService shopGoodsSkuService; + + @Autowired + private CouponStatusService couponStatusService; + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelOrder(ShopOrder order) { + try { + log.info("开始取消订单,订单号:{},订单ID:{}", order.getOrderNo(), order.getOrderId()); + + // 1. 检查订单状态 + if (order.getPayStatus() != null && order.getPayStatus()) { + log.warn("订单已支付,无法取消,订单号:{}", order.getOrderNo()); + return false; + } + + if (order.getOrderStatus() != null && order.getOrderStatus() != 0) { + log.warn("订单状态不是待支付,无法取消,订单号:{},当前状态:{}", order.getOrderNo(), order.getOrderStatus()); + return false; + } + + // 2. 更新订单状态为已取消 + order.setOrderStatus(2); // 2表示已取消 + order.setCancelTime(LocalDateTime.now()); + order.setCancelReason("系统自动取消(超时未支付)"); + + boolean updateSuccess = shopOrderService.updateById(order); + if (!updateSuccess) { + log.error("更新订单状态失败,订单号:{}", order.getOrderNo()); + return false; + } + + // 3. 回退库存 + boolean stockRestored = restoreOrderStock(order); + if (!stockRestored) { + log.error("回退库存失败,订单号:{}", order.getOrderNo()); + // 注意:这里不直接返回false,因为订单状态已经更新,需要记录错误但继续处理 + } + + // 4. 退还优惠券 + boolean couponReturned = returnOrderCoupon(order); + if (!couponReturned) { + log.error("退还优惠券失败,订单号:{}", order.getOrderNo()); + // 同样不直接返回false + } + + log.info("订单取消成功,订单号:{},库存回退:{},优惠券退还:{}", + order.getOrderNo(), stockRestored, couponReturned); + return true; + + } catch (Exception e) { + log.error("取消订单失败,订单号:{}", order.getOrderNo(), e); + throw e; // 重新抛出异常,触发事务回滚 + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchCancelOrders(List orders) { + if (orders == null || orders.isEmpty()) { + return 0; + } + + int successCount = 0; + for (ShopOrder order : orders) { + try { + if (cancelOrder(order)) { + successCount++; + } + } catch (Exception e) { + log.error("批量取消订单时发生错误,订单号:{}", order.getOrderNo(), e); + // 继续处理下一个订单 + } + } + + log.info("批量取消订单完成,总数:{},成功:{}", orders.size(), successCount); + return successCount; + } + + @Override + @IgnoreTenant("定时任务需要查询所有租户的超时订单") + public List findExpiredUnpaidOrders(Integer timeoutMinutes, Integer batchSize) { + LocalDateTime expireTime = LocalDateTime.now().minusMinutes(timeoutMinutes); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(ShopOrder::getPayStatus, false) // 未支付 + .eq(ShopOrder::getOrderStatus, 0) // 待支付状态 + .lt(ShopOrder::getCreateTime, expireTime) // 创建时间小于过期时间 + .orderByAsc(ShopOrder::getCreateTime) + .last("LIMIT " + batchSize); + + final List list = shopOrderService.list(queryWrapper); + System.out.println("定时任务需要查询所有租户的超时订单 list = " + list.size()); + return shopOrderService.list(queryWrapper); + } + + @Override + @IgnoreTenant("定时任务需要查询特定租户的超时订单") + public List findExpiredUnpaidOrdersByTenant(Integer tenantId, Integer timeoutMinutes, Integer batchSize) { + LocalDateTime expireTime = LocalDateTime.now().minusMinutes(timeoutMinutes); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getPayStatus, false) // 未支付 + .eq(ShopOrder::getOrderStatus, 0) // 待支付状态 + .lt(ShopOrder::getCreateTime, expireTime) // 创建时间小于过期时间 + .orderByAsc(ShopOrder::getCreateTime) + .last("LIMIT " + batchSize); + + return shopOrderService.list(queryWrapper); + } + + @Override + public boolean restoreOrderStock(ShopOrder order) { + try { + // 获取订单商品信息 + List orderGoods = shopOrderGoodsService.list( + new LambdaQueryWrapper() + .eq(ShopOrderGoods::getOrderId, order.getOrderId()) + ); + + if (orderGoods == null || orderGoods.isEmpty()) { + log.warn("订单没有商品信息,订单号:{}", order.getOrderNo()); + return true; // 没有商品信息也算成功 + } + + for (ShopOrderGoods orderGood : orderGoods) { + if (orderGood.getSkuId() != null && orderGood.getSkuId() > 0) { + // 多规格商品,恢复SKU库存 + restoreSkuStock(orderGood); + } else { + // 单规格商品,恢复商品库存 + restoreGoodsStock(orderGood); + } + } + + log.info("订单库存回退成功,订单号:{},商品数量:{}", order.getOrderNo(), orderGoods.size()); + return true; + + } catch (Exception e) { + log.error("回退订单库存失败,订单号:{}", order.getOrderNo(), e); + return false; + } + } + + @Override + public boolean returnOrderCoupon(ShopOrder order) { + try { + if (order.getCouponId() == null || order.getCouponId() <= 0) { + log.debug("订单未使用优惠券,订单号:{}", order.getOrderNo()); + return true; // 没有使用优惠券也算成功 + } + + boolean success = couponStatusService.returnCoupon(order.getOrderId()); + if (success) { + log.info("订单优惠券退还成功,订单号:{},优惠券ID:{}", order.getOrderNo(), order.getCouponId()); + } else { + log.warn("订单优惠券退还失败,订单号:{},优惠券ID:{}", order.getOrderNo(), order.getCouponId()); + } + return success; + + } catch (Exception e) { + log.error("退还订单优惠券失败,订单号:{}", order.getOrderNo(), e); + return false; + } + } + + /** + * 恢复SKU库存 + */ + private void restoreSkuStock(ShopOrderGoods orderGoods) { + ShopGoodsSku sku = shopGoodsSkuService.getById(orderGoods.getSkuId()); + if (sku != null) { + int newStock = (sku.getStock() != null ? sku.getStock() : 0) + orderGoods.getTotalNum(); + sku.setStock(newStock); + shopGoodsSkuService.updateById(sku); + log.debug("恢复SKU库存 - SKU ID:{},恢复数量:{},当前库存:{}", + orderGoods.getSkuId(), orderGoods.getTotalNum(), newStock); + } + } + + /** + * 恢复商品库存 + */ + private void restoreGoodsStock(ShopOrderGoods orderGoods) { + ShopGoods goods = shopGoodsService.getById(orderGoods.getGoodsId()); + if (goods != null) { + int newStock = (goods.getStock() != null ? goods.getStock() : 0) + orderGoods.getTotalNum(); + goods.setStock(newStock); + shopGoodsService.updateById(goods); + log.debug("恢复商品库存 - 商品ID:{},恢复数量:{},当前库存:{}", + orderGoods.getGoodsId(), orderGoods.getTotalNum(), newStock); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java new file mode 100644 index 0000000..9e49324 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopArticleMapper; +import com.gxwebsoft.shop.service.ShopArticleService; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品文章Service实现 + * + * @author 科技小王子 + * @since 2025-08-13 05:14:53 + */ +@Service +public class ShopArticleServiceImpl extends ServiceImpl implements ShopArticleService { + + @Override + public PageResult pageRel(ShopArticleParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopArticleParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopArticle getByIdRel(Integer articleId) { + ShopArticleParam param = new ShopArticleParam(); + param.setArticleId(articleId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopBrandServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopBrandServiceImpl.java new file mode 100644 index 0000000..5037b55 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopBrandServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopBrandMapper; +import com.gxwebsoft.shop.service.ShopBrandService; +import com.gxwebsoft.shop.entity.ShopBrand; +import com.gxwebsoft.shop.param.ShopBrandParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 品牌Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopBrandServiceImpl extends ServiceImpl implements ShopBrandService { + + @Override + public PageResult pageRel(ShopBrandParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopBrandParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopBrand getByIdRel(Integer brandId) { + ShopBrandParam param = new ShopBrandParam(); + param.setBrandId(brandId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCartServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCartServiceImpl.java new file mode 100644 index 0000000..12d6b3a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCartServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopCartMapper; +import com.gxwebsoft.shop.service.ShopCartService; +import com.gxwebsoft.shop.entity.ShopCart; +import com.gxwebsoft.shop.param.ShopCartParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 购物车Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopCartServiceImpl extends ServiceImpl implements ShopCartService { + + @Override + public PageResult pageRel(ShopCartParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCartParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCart getByIdRel(Long id) { + ShopCartParam param = new ShopCartParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCategoryServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCategoryServiceImpl.java new file mode 100644 index 0000000..fbe60af --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCategoryServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopCategoryMapper; +import com.gxwebsoft.shop.service.ShopCategoryService; +import com.gxwebsoft.shop.entity.ShopCategory; +import com.gxwebsoft.shop.param.ShopCategoryParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品分类Service实现 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Service +public class ShopCategoryServiceImpl extends ServiceImpl implements ShopCategoryService { + + @Override + public PageResult pageRel(ShopCategoryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCategoryParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCategory getByIdRel(Integer id) { + ShopCategoryParam param = new ShopCategoryParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopChatConversationServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopChatConversationServiceImpl.java new file mode 100644 index 0000000..e482f7e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopChatConversationServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopChatConversationMapper; +import com.gxwebsoft.shop.service.ShopChatConversationService; +import com.gxwebsoft.shop.entity.ShopChatConversation; +import com.gxwebsoft.shop.param.ShopChatConversationParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 聊天消息表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopChatConversationServiceImpl extends ServiceImpl implements ShopChatConversationService { + + @Override + public PageResult pageRel(ShopChatConversationParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopChatConversationParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopChatConversation getByIdRel(Integer id) { + ShopChatConversationParam param = new ShopChatConversationParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopChatMessageServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopChatMessageServiceImpl.java new file mode 100644 index 0000000..ca50663 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopChatMessageServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopChatMessageMapper; +import com.gxwebsoft.shop.service.ShopChatMessageService; +import com.gxwebsoft.shop.entity.ShopChatMessage; +import com.gxwebsoft.shop.param.ShopChatMessageParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 聊天消息表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopChatMessageServiceImpl extends ServiceImpl implements ShopChatMessageService { + + @Override + public PageResult pageRel(ShopChatMessageParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopChatMessageParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopChatMessage getByIdRel(Integer id) { + ShopChatMessageParam param = new ShopChatMessageParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCommissionRoleServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCommissionRoleServiceImpl.java new file mode 100644 index 0000000..26823a0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCommissionRoleServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopCommissionRoleMapper; +import com.gxwebsoft.shop.service.ShopCommissionRoleService; +import com.gxwebsoft.shop.entity.ShopCommissionRole; +import com.gxwebsoft.shop.param.ShopCommissionRoleParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分红角色Service实现 + * + * @author 科技小王子 + * @since 2025-05-01 10:01:15 + */ +@Service +public class ShopCommissionRoleServiceImpl extends ServiceImpl implements ShopCommissionRoleService { + + @Override + public PageResult pageRel(ShopCommissionRoleParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCommissionRoleParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCommissionRole getByIdRel(Integer id) { + ShopCommissionRoleParam param = new ShopCommissionRoleParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCountServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCountServiceImpl.java new file mode 100644 index 0000000..51fa64d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCountServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopCountMapper; +import com.gxwebsoft.shop.service.ShopCountService; +import com.gxwebsoft.shop.entity.ShopCount; +import com.gxwebsoft.shop.param.ShopCountParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商城销售统计表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopCountServiceImpl extends ServiceImpl implements ShopCountService { + + @Override + public PageResult pageRel(ShopCountParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCountParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCount getByIdRel(Integer id) { + ShopCountParam param = new ShopCountParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponApplyCateServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponApplyCateServiceImpl.java new file mode 100644 index 0000000..c613194 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponApplyCateServiceImpl.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopCouponApplyCateMapper; +import com.gxwebsoft.shop.service.ShopCouponApplyCateService; +import com.gxwebsoft.shop.entity.ShopCouponApplyCate; +import com.gxwebsoft.shop.param.ShopCouponApplyCateParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 优惠券可用分类Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +@Service +public class ShopCouponApplyCateServiceImpl extends ServiceImpl implements ShopCouponApplyCateService { + + @Override + public PageResult pageRel(ShopCouponApplyCateParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCouponApplyCateParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCouponApplyCate getByIdRel(Integer id) { + ShopCouponApplyCateParam param = new ShopCouponApplyCateParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public void removeByCouponId(Integer couponId) { + remove( + new LambdaQueryWrapper() + .eq(ShopCouponApplyCate::getCouponId, couponId) + ); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponApplyItemServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponApplyItemServiceImpl.java new file mode 100644 index 0000000..6baa5ea --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponApplyItemServiceImpl.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopCouponApplyItemMapper; +import com.gxwebsoft.shop.service.ShopCouponApplyItemService; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.param.ShopCouponApplyItemParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 优惠券可用分类Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 12:47:49 + */ +@Service +public class ShopCouponApplyItemServiceImpl extends ServiceImpl implements ShopCouponApplyItemService { + + @Override + public PageResult pageRel(ShopCouponApplyItemParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCouponApplyItemParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCouponApplyItem getByIdRel(Integer id) { + ShopCouponApplyItemParam param = new ShopCouponApplyItemParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public void removeByCouponId(Integer couponId) { + remove( + new LambdaQueryWrapper() + .eq(ShopCouponApplyItem::getCouponId, couponId) + ); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponServiceImpl.java new file mode 100644 index 0000000..29a17a3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopCouponServiceImpl.java @@ -0,0 +1,71 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.entity.ShopCouponApplyCate; +import com.gxwebsoft.shop.entity.ShopCouponApplyItem; +import com.gxwebsoft.shop.mapper.ShopCouponMapper; +import com.gxwebsoft.shop.service.ShopCouponApplyCateService; +import com.gxwebsoft.shop.service.ShopCouponApplyItemService; +import com.gxwebsoft.shop.service.ShopCouponService; +import com.gxwebsoft.shop.entity.ShopCoupon; +import com.gxwebsoft.shop.param.ShopCouponParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 优惠券Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:23 + */ +@Service +public class ShopCouponServiceImpl extends ServiceImpl implements ShopCouponService { + @Resource + private ShopCouponApplyItemService couponApplyItemService; + @Resource + private ShopCouponApplyCateService couponApplyCateService; + + @Override + public PageResult pageRel(ShopCouponParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + for (ShopCoupon coupon : list) { + coupon.setCouponApplyCateList( + couponApplyCateService.list( + new LambdaQueryWrapper() + .eq(ShopCouponApplyCate::getCouponId, coupon.getId()) + ) + ); + coupon.setCouponApplyItemList( + couponApplyItemService.list( + new LambdaQueryWrapper() + .eq(ShopCouponApplyItem::getCouponId, coupon.getId()) + ) + ); + } + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopCouponParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopCoupon getByIdRel(Integer id) { + ShopCouponParam param = new ShopCouponParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerApplyServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerApplyServiceImpl.java new file mode 100644 index 0000000..ab445bf --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerApplyServiceImpl.java @@ -0,0 +1,62 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopDealerApplyMapper; +import com.gxwebsoft.shop.service.ShopDealerApplyService; +import com.gxwebsoft.shop.entity.ShopDealerApply; +import com.gxwebsoft.shop.param.ShopDealerApplyParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商申请记录表Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:50:18 + */ +@Service +public class ShopDealerApplyServiceImpl extends ServiceImpl implements ShopDealerApplyService { + + @Override + public PageResult pageRel(ShopDealerApplyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerApplyParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerApply getByIdRel(Integer id) { + ShopDealerApplyParam param = new ShopDealerApplyParam(); + param.setApplyId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopDealerApply getByUserIdRel(Integer userId) { + ShopDealerApplyParam param = new ShopDealerApplyParam(); + param.setUserId(userId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopDealerApply getByDealerNameRel(String dealerName) { + ShopDealerApplyParam param = new ShopDealerApplyParam(); + param.setDealerName(dealerName); + param.setType(4); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerBankServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerBankServiceImpl.java new file mode 100644 index 0000000..edc77c3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerBankServiceImpl.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerBank; +import com.gxwebsoft.shop.mapper.ShopDealerBankMapper; +import com.gxwebsoft.shop.param.ShopDealerBankParam; +import com.gxwebsoft.shop.service.ShopDealerBankService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商提现银行卡Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopDealerBankServiceImpl extends ServiceImpl implements ShopDealerBankService { + + @Override + public PageResult pageRel(ShopDealerBankParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("is_default desc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerBankParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("is_default desc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerBank getByIdRel(Integer id) { + ShopDealerBankParam param = new ShopDealerBankParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopDealerBank getDefaultBank(Integer userId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(ShopDealerBank::getUserId, userId) + .eq(ShopDealerBank::getIsDefault, true) + .orderByDesc(ShopDealerBank::getCreateTime) + .last("LIMIT 1"); + return getOne(wrapper); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerCapitalServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerCapitalServiceImpl.java new file mode 100644 index 0000000..897fbed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerCapitalServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopDealerCapitalMapper; +import com.gxwebsoft.shop.service.ShopDealerCapitalService; +import com.gxwebsoft.shop.entity.ShopDealerCapital; +import com.gxwebsoft.shop.param.ShopDealerCapitalParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商资金明细表Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopDealerCapitalServiceImpl extends ServiceImpl implements ShopDealerCapitalService { + + @Override + public PageResult pageRel(ShopDealerCapitalParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerCapitalParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerCapital getByIdRel(Integer id) { + ShopDealerCapitalParam param = new ShopDealerCapitalParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerOrderServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerOrderServiceImpl.java new file mode 100644 index 0000000..0bab68f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerOrderServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopDealerOrderMapper; +import com.gxwebsoft.shop.service.ShopDealerOrderService; +import com.gxwebsoft.shop.entity.ShopDealerOrder; +import com.gxwebsoft.shop.param.ShopDealerOrderParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商订单记录表Service实现 + * + * @author 科技小王子 + * @since 2025-08-12 11:55:18 + */ +@Service +public class ShopDealerOrderServiceImpl extends ServiceImpl implements ShopDealerOrderService { + + @Override + public PageResult pageRel(ShopDealerOrderParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerOrderParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerOrder getByIdRel(Integer id) { + ShopDealerOrderParam param = new ShopDealerOrderParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerRecordServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerRecordServiceImpl.java new file mode 100644 index 0000000..1b875e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerRecordServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopDealerRecord; +import com.gxwebsoft.shop.mapper.ShopDealerRecordMapper; +import com.gxwebsoft.shop.param.ShopDealerRecordParam; +import com.gxwebsoft.shop.service.ShopDealerRecordService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 客户跟进情况Service实现 + * + * @author 科技小王子 + * @since 2025-10-02 12:21:50 + */ +@Service +public class ShopDealerRecordServiceImpl extends ServiceImpl implements ShopDealerRecordService { + + @Override + public PageResult pageRel(ShopDealerRecordParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerRecordParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerRecord getByIdRel(Integer id) { + ShopDealerRecordParam param = new ShopDealerRecordParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerRefereeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerRefereeServiceImpl.java new file mode 100644 index 0000000..18d5383 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerRefereeServiceImpl.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopDealerRefereeMapper; +import com.gxwebsoft.shop.service.ShopDealerRefereeService; +import com.gxwebsoft.shop.entity.ShopDealerReferee; +import com.gxwebsoft.shop.param.ShopDealerRefereeParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商推荐关系表Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopDealerRefereeServiceImpl extends ServiceImpl implements ShopDealerRefereeService { + + @Override + public PageResult pageRel(ShopDealerRefereeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerRefereeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerReferee getByIdRel(Integer id) { + ShopDealerRefereeParam param = new ShopDealerRefereeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopDealerReferee getByUserIdRel(Integer userId) { + ShopDealerRefereeParam param = new ShopDealerRefereeParam(); + param.setUserId(userId); + param.setLevel(1); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerSettingServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerSettingServiceImpl.java new file mode 100644 index 0000000..336fd7a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerSettingServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopDealerSettingMapper; +import com.gxwebsoft.shop.service.ShopDealerSettingService; +import com.gxwebsoft.shop.entity.ShopDealerSetting; +import com.gxwebsoft.shop.param.ShopDealerSettingParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商设置表Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopDealerSettingServiceImpl extends ServiceImpl implements ShopDealerSettingService { + + @Override + public PageResult pageRel(ShopDealerSettingParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerSettingParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerSetting getByIdRel(String key) { + ShopDealerSettingParam param = new ShopDealerSettingParam(); + param.setKey(key); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerUserServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerUserServiceImpl.java new file mode 100644 index 0000000..a5767d3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerUserServiceImpl.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopDealerUserMapper; +import com.gxwebsoft.shop.service.ShopDealerUserService; +import com.gxwebsoft.shop.entity.ShopDealerUser; +import com.gxwebsoft.shop.param.ShopDealerUserParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商用户记录表Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopDealerUserServiceImpl extends ServiceImpl implements ShopDealerUserService { + + @Override + public PageResult pageRel(ShopDealerUserParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerUserParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerUser getByIdRel(Integer id) { + ShopDealerUserParam param = new ShopDealerUserParam(); + param.setUserId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopDealerUser getByUserIdRel(Integer userId) { + ShopDealerUserParam param = new ShopDealerUserParam(); + param.setUserId(userId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public boolean updateByUserId(ShopDealerUser shopDealerUser) { + final int update = baseMapper.update(shopDealerUser, new LambdaQueryWrapper().eq(ShopDealerUser::getUserId, shopDealerUser.getUserId())); + return update > 0; + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerWithdrawServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerWithdrawServiceImpl.java new file mode 100644 index 0000000..9748034 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopDealerWithdrawServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopDealerWithdrawMapper; +import com.gxwebsoft.shop.service.ShopDealerWithdrawService; +import com.gxwebsoft.shop.entity.ShopDealerWithdraw; +import com.gxwebsoft.shop.param.ShopDealerWithdrawParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分销商提现明细表Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopDealerWithdrawServiceImpl extends ServiceImpl implements ShopDealerWithdrawService { + + @Override + public PageResult pageRel(ShopDealerWithdrawParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopDealerWithdrawParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopDealerWithdraw getByIdRel(Integer id) { + ShopDealerWithdrawParam param = new ShopDealerWithdrawParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressServiceImpl.java new file mode 100644 index 0000000..1a7cdbc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopExpressMapper; +import com.gxwebsoft.shop.service.ShopExpressService; +import com.gxwebsoft.shop.entity.ShopExpress; +import com.gxwebsoft.shop.param.ShopExpressParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 物流公司Service实现 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Service +public class ShopExpressServiceImpl extends ServiceImpl implements ShopExpressService { + + @Override + public PageResult pageRel(ShopExpressParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopExpressParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopExpress getByIdRel(Integer expressId) { + ShopExpressParam param = new ShopExpressParam(); + param.setExpressId(expressId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressTemplateDetailServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressTemplateDetailServiceImpl.java new file mode 100644 index 0000000..2c5ea8b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressTemplateDetailServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopExpressTemplateDetailMapper; +import com.gxwebsoft.shop.service.ShopExpressTemplateDetailService; +import com.gxwebsoft.shop.entity.ShopExpressTemplateDetail; +import com.gxwebsoft.shop.param.ShopExpressTemplateDetailParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 运费模板Service实现 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Service +public class ShopExpressTemplateDetailServiceImpl extends ServiceImpl implements ShopExpressTemplateDetailService { + + @Override + public PageResult pageRel(ShopExpressTemplateDetailParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopExpressTemplateDetailParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopExpressTemplateDetail getByIdRel(Integer id) { + ShopExpressTemplateDetailParam param = new ShopExpressTemplateDetailParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressTemplateServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressTemplateServiceImpl.java new file mode 100644 index 0000000..1858d49 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopExpressTemplateServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopExpressTemplateMapper; +import com.gxwebsoft.shop.service.ShopExpressTemplateService; +import com.gxwebsoft.shop.entity.ShopExpressTemplate; +import com.gxwebsoft.shop.param.ShopExpressTemplateParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 运费模板Service实现 + * + * @author 科技小王子 + * @since 2025-08-12 12:07:03 + */ +@Service +public class ShopExpressTemplateServiceImpl extends ServiceImpl implements ShopExpressTemplateService { + + @Override + public PageResult pageRel(ShopExpressTemplateParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopExpressTemplateParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopExpressTemplate getByIdRel(Integer id) { + ShopExpressTemplateParam param = new ShopExpressTemplateParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGiftServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGiftServiceImpl.java new file mode 100644 index 0000000..55a067e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGiftServiceImpl.java @@ -0,0 +1,71 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.mapper.ShopGiftMapper; +import com.gxwebsoft.shop.service.ShopGiftService; +import com.gxwebsoft.shop.entity.ShopGift; +import com.gxwebsoft.shop.param.ShopGiftParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.service.ShopGoodsService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 礼品卡Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 18:07:31 + */ +@Service +public class ShopGiftServiceImpl extends ServiceImpl implements ShopGiftService { + @Resource + private ShopGoodsService shopGoodsService; + + @Override + public PageResult pageRel(ShopGiftParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + if (!list.isEmpty()) { + Set goodsIds = list.stream().map(ShopGift::getGoodsId).collect(Collectors.toSet()); + List goodsList = shopGoodsService.listByIds(goodsIds); + for (ShopGift shopGift : list) { + ShopGoods shopGoods = goodsList.stream().filter(sG -> sG.getGoodsId().equals(shopGift.getGoodsId())).findFirst().orElse(null); + if (shopGoods != null) { + shopGift.setGoods(shopGoods); + } + } + } + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGiftParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGift getByIdRel(Integer id) { + ShopGiftParam param = new ShopGiftParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopGift getByCode(String code) { + ShopGiftParam param = new ShopGiftParam(); + param.setCode(code); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsCategoryServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsCategoryServiceImpl.java new file mode 100644 index 0000000..170ab88 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsCategoryServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsCategoryMapper; +import com.gxwebsoft.shop.service.ShopGoodsCategoryService; +import com.gxwebsoft.shop.entity.ShopGoodsCategory; +import com.gxwebsoft.shop.param.ShopGoodsCategoryParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品分类Service实现 + * + * @author 科技小王子 + * @since 2025-05-01 00:36:45 + */ +@Service +public class ShopGoodsCategoryServiceImpl extends ServiceImpl implements ShopGoodsCategoryService { + + @Override + public PageResult pageRel(ShopGoodsCategoryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsCategoryParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsCategory getByIdRel(Integer categoryId) { + ShopGoodsCategoryParam param = new ShopGoodsCategoryParam(); + param.setCategoryId(categoryId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsCommentServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsCommentServiceImpl.java new file mode 100644 index 0000000..7f203bd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsCommentServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsCommentMapper; +import com.gxwebsoft.shop.service.ShopGoodsCommentService; +import com.gxwebsoft.shop.entity.ShopGoodsComment; +import com.gxwebsoft.shop.param.ShopGoodsCommentParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 评论表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopGoodsCommentServiceImpl extends ServiceImpl implements ShopGoodsCommentService { + + @Override + public PageResult pageRel(ShopGoodsCommentParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsCommentParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsComment getByIdRel(Integer id) { + ShopGoodsCommentParam param = new ShopGoodsCommentParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsIncomeConfigServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsIncomeConfigServiceImpl.java new file mode 100644 index 0000000..d4ca36e --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsIncomeConfigServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsIncomeConfigMapper; +import com.gxwebsoft.shop.service.ShopGoodsIncomeConfigService; +import com.gxwebsoft.shop.entity.ShopGoodsIncomeConfig; +import com.gxwebsoft.shop.param.ShopGoodsIncomeConfigParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分润配置Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopGoodsIncomeConfigServiceImpl extends ServiceImpl implements ShopGoodsIncomeConfigService { + + @Override + public PageResult pageRel(ShopGoodsIncomeConfigParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsIncomeConfigParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsIncomeConfig getByIdRel(Integer id) { + ShopGoodsIncomeConfigParam param = new ShopGoodsIncomeConfigParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsLogServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsLogServiceImpl.java new file mode 100644 index 0000000..0e2e46f --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsLogServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsLogMapper; +import com.gxwebsoft.shop.service.ShopGoodsLogService; +import com.gxwebsoft.shop.entity.ShopGoodsLog; +import com.gxwebsoft.shop.param.ShopGoodsLogParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品日志表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopGoodsLogServiceImpl extends ServiceImpl implements ShopGoodsLogService { + + @Override + public PageResult pageRel(ShopGoodsLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsLogParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsLog getByIdRel(Integer id) { + ShopGoodsLogParam param = new ShopGoodsLogParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsRelationServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsRelationServiceImpl.java new file mode 100644 index 0000000..eaf1166 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsRelationServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsRelationMapper; +import com.gxwebsoft.shop.service.ShopGoodsRelationService; +import com.gxwebsoft.shop.entity.ShopGoodsRelation; +import com.gxwebsoft.shop.param.ShopGoodsRelationParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品点赞和收藏表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopGoodsRelationServiceImpl extends ServiceImpl implements ShopGoodsRelationService { + + @Override + public PageResult pageRel(ShopGoodsRelationParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsRelationParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsRelation getByIdRel(Integer id) { + ShopGoodsRelationParam param = new ShopGoodsRelationParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsRoleCommissionServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsRoleCommissionServiceImpl.java new file mode 100644 index 0000000..95a72cc --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsRoleCommissionServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsRoleCommissionMapper; +import com.gxwebsoft.shop.service.ShopGoodsRoleCommissionService; +import com.gxwebsoft.shop.entity.ShopGoodsRoleCommission; +import com.gxwebsoft.shop.param.ShopGoodsRoleCommissionParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品绑定角色的分润金额Service实现 + * + * @author 科技小王子 + * @since 2025-05-01 09:53:38 + */ +@Service +public class ShopGoodsRoleCommissionServiceImpl extends ServiceImpl implements ShopGoodsRoleCommissionService { + + @Override + public PageResult pageRel(ShopGoodsRoleCommissionParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsRoleCommissionParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsRoleCommission getByIdRel(Integer id) { + ShopGoodsRoleCommissionParam param = new ShopGoodsRoleCommissionParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsServiceImpl.java new file mode 100644 index 0000000..4984d72 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsServiceImpl.java @@ -0,0 +1,75 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsMapper; +import com.gxwebsoft.shop.service.ShopGoodsService; +import com.gxwebsoft.shop.entity.ShopGoods; +import com.gxwebsoft.shop.param.ShopGoodsParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 商品Service实现 + * + * @author 科技小王子 + * @since 2025-04-24 20:52:13 + */ +@Slf4j +@Service +public class ShopGoodsServiceImpl extends ServiceImpl implements ShopGoodsService { + + @Override + public PageResult pageRel(ShopGoodsParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoods getByIdRel(Integer goodsId) { + ShopGoodsParam param = new ShopGoodsParam(); + param.setGoodsId(goodsId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @InterceptorIgnore(tenantLine = "true") + @Override + public boolean addSaleCount(Integer goodsId, Integer saleCount) { + try { + if (goodsId == null || saleCount == null || saleCount <= 0) { + log.warn("累加商品销量参数无效 - 商品ID: {}, 销量: {}", goodsId, saleCount); + return false; + } + + int affectedRows = baseMapper.addSaleCount(goodsId, saleCount); + boolean success = affectedRows > 0; + + if (success) { + log.info("商品销量累加成功 - 商品ID: {}, 累加数量: {}, 影响行数: {}", goodsId, saleCount, affectedRows); + } else { + log.warn("商品销量累加失败 - 商品ID: {}, 累加数量: {}, 影响行数: {}", goodsId, saleCount, affectedRows); + } + + return success; + } catch (Exception e) { + log.error("累加商品销量异常 - 商品ID: {}, 累加数量: {}", goodsId, saleCount, e); + return false; + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsSkuServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsSkuServiceImpl.java new file mode 100644 index 0000000..cc1739b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsSkuServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsSkuMapper; +import com.gxwebsoft.shop.service.ShopGoodsSkuService; +import com.gxwebsoft.shop.entity.ShopGoodsSku; +import com.gxwebsoft.shop.param.ShopGoodsSkuParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品sku列表Service实现 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Service +public class ShopGoodsSkuServiceImpl extends ServiceImpl implements ShopGoodsSkuService { + + @Override + public PageResult pageRel(ShopGoodsSkuParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsSkuParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsSku getByIdRel(Integer id) { + ShopGoodsSkuParam param = new ShopGoodsSkuParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsSpecServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsSpecServiceImpl.java new file mode 100644 index 0000000..812a5b3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsSpecServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopGoodsSpecMapper; +import com.gxwebsoft.shop.service.ShopGoodsSpecService; +import com.gxwebsoft.shop.entity.ShopGoodsSpec; +import com.gxwebsoft.shop.param.ShopGoodsSpecParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品多规格Service实现 + * + * @author 科技小王子 + * @since 2025-05-01 09:43:31 + */ +@Service +public class ShopGoodsSpecServiceImpl extends ServiceImpl implements ShopGoodsSpecService { + + @Override + public PageResult pageRel(ShopGoodsSpecParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopGoodsSpecParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopGoodsSpec getByIdRel(Integer id) { + ShopGoodsSpecParam param = new ShopGoodsSpecParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantAccountServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantAccountServiceImpl.java new file mode 100644 index 0000000..6d39658 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantAccountServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopMerchantAccountMapper; +import com.gxwebsoft.shop.service.ShopMerchantAccountService; +import com.gxwebsoft.shop.entity.ShopMerchantAccount; +import com.gxwebsoft.shop.param.ShopMerchantAccountParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户账号Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopMerchantAccountServiceImpl extends ServiceImpl implements ShopMerchantAccountService { + + @Override + public PageResult pageRel(ShopMerchantAccountParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopMerchantAccountParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopMerchantAccount getByIdRel(Integer id) { + ShopMerchantAccountParam param = new ShopMerchantAccountParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantApplyServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantApplyServiceImpl.java new file mode 100644 index 0000000..becb4aa --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantApplyServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopMerchantApplyMapper; +import com.gxwebsoft.shop.service.ShopMerchantApplyService; +import com.gxwebsoft.shop.entity.ShopMerchantApply; +import com.gxwebsoft.shop.param.ShopMerchantApplyParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户入驻申请Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopMerchantApplyServiceImpl extends ServiceImpl implements ShopMerchantApplyService { + + @Override + public PageResult pageRel(ShopMerchantApplyParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopMerchantApplyParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopMerchantApply getByIdRel(Integer applyId) { + ShopMerchantApplyParam param = new ShopMerchantApplyParam(); + param.setApplyId(applyId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantServiceImpl.java new file mode 100644 index 0000000..9fb3e73 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopMerchantMapper; +import com.gxwebsoft.shop.service.ShopMerchantService; +import com.gxwebsoft.shop.entity.ShopMerchant; +import com.gxwebsoft.shop.param.ShopMerchantParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户Service实现 + * + * @author 科技小王子 + * @since 2025-08-10 20:43:33 + */ +@Service +public class ShopMerchantServiceImpl extends ServiceImpl implements ShopMerchantService { + + @Override + public PageResult pageRel(ShopMerchantParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopMerchantParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopMerchant getByIdRel(Long merchantId) { + ShopMerchantParam param = new ShopMerchantParam(); + param.setMerchantId(merchantId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantTypeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantTypeServiceImpl.java new file mode 100644 index 0000000..38c87cd --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopMerchantTypeServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopMerchantTypeMapper; +import com.gxwebsoft.shop.service.ShopMerchantTypeService; +import com.gxwebsoft.shop.entity.ShopMerchantType; +import com.gxwebsoft.shop.param.ShopMerchantTypeParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商户类型Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopMerchantTypeServiceImpl extends ServiceImpl implements ShopMerchantTypeService { + + @Override + public PageResult pageRel(ShopMerchantTypeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopMerchantTypeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopMerchantType getByIdRel(Integer id) { + ShopMerchantTypeParam param = new ShopMerchantTypeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderDeliveryGoodsServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderDeliveryGoodsServiceImpl.java new file mode 100644 index 0000000..c48c23a --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderDeliveryGoodsServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopOrderDeliveryGoodsMapper; +import com.gxwebsoft.shop.service.ShopOrderDeliveryGoodsService; +import com.gxwebsoft.shop.entity.ShopOrderDeliveryGoods; +import com.gxwebsoft.shop.param.ShopOrderDeliveryGoodsParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 发货单商品Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopOrderDeliveryGoodsServiceImpl extends ServiceImpl implements ShopOrderDeliveryGoodsService { + + @Override + public PageResult pageRel(ShopOrderDeliveryGoodsParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopOrderDeliveryGoodsParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopOrderDeliveryGoods getByIdRel(Integer id) { + ShopOrderDeliveryGoodsParam param = new ShopOrderDeliveryGoodsParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderDeliveryServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderDeliveryServiceImpl.java new file mode 100644 index 0000000..41cd996 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderDeliveryServiceImpl.java @@ -0,0 +1,164 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.shop.entity.*; +import com.gxwebsoft.shop.mapper.ShopOrderDeliveryMapper; +import com.gxwebsoft.shop.service.*; +import com.gxwebsoft.shop.param.ShopOrderDeliveryParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.kuaidi100.sdk.pojo.HttpResult; +import com.kuaidi100.sdk.request.BOrderReq; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 发货单Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopOrderDeliveryServiceImpl extends ServiceImpl implements ShopOrderDeliveryService { + @Resource + private ShopExpressService expressService; + @Resource + private KuaiDi100Impl kuaiDi100; + @Resource + private ShopOrderService shopOrderService; + @Resource + private ShopOrderGoodsService shopOrderGoodsService; + @Resource + private ShopGoodsService shopGoodsService; + @Resource + private ShopUserAddressService shopUserAddressService; + + @Override + public PageResult pageRel(ShopOrderDeliveryParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopOrderDeliveryParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopOrderDelivery getByIdRel(Integer deliveryId) { + ShopOrderDeliveryParam param = new ShopOrderDeliveryParam(); + param.setDeliveryId(deliveryId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopOrderDelivery getByOrderId(Integer orderId) { + return getOne( + new LambdaQueryWrapper() + .eq(ShopOrderDelivery::getOrderId, orderId) + .last("limit 1") + ); + } + + @Override + public Map setExpress(User user, ShopOrderDelivery orderDelivery, ShopOrder order) throws Exception { + ShopExpress express = expressService.getByIdRel(orderDelivery.getExpressId()); + ShopUserAddress userAddress = shopUserAddressService.getByIdRel(order.getAddressId()); + + BOrderReq bOrderReq = new BOrderReq(); + bOrderReq.setKuaidicom(express.getKuaidi100Code()); + bOrderReq.setSendManName(orderDelivery.getSendName()); + bOrderReq.setSendManMobile(orderDelivery.getSendPhone()); + bOrderReq.setSendManPrintAddr(order.getSendAddress()); + bOrderReq.setRecManName(userAddress.getName()); + bOrderReq.setRecManMobile(userAddress.getPhone()); + bOrderReq.setRecManPrintAddr(order.getAddress()); + bOrderReq.setCallBackUrl("https://cms-api.websoft.top/api/shop/order-delivery/notify"); + HttpResult res = kuaiDi100.border(bOrderReq); + if (res.getStatus() != 200) return new HashMap<>() {{ + put("res", false); + put("msg", "快递100接口异常"); + }}; + KuaiDi100Resp kuaiDi100Resp = JSONUtil.parseObject(res.getBody(), KuaiDi100Resp.class); + if (kuaiDi100Resp == null) return new HashMap<>() {{ + put("res", false); + put("msg", "快递100接口异常"); + }}; + + if (!kuaiDi100Resp.getResult()) + return new HashMap<>() {{ + put("res", false); + put("msg", kuaiDi100Resp.getMessage()); + }}; + Map bOrderData = (Map) kuaiDi100Resp.getData(); + orderDelivery.setExpressNo((String) bOrderData.get("kuaidinum")); + if (updateById(orderDelivery)) { + order.setDeliveryStatus(20); + order.setDeliveryTime(LocalDateTime.now()); + shopOrderService.updateById(order); + + if (order.getPayType().equals(1)) { + List orderGoodsList = shopOrderGoodsService.getListByOrderId(order.getOrderId()); + // 上传小程序发货信息 +// WxMaOrderShippingInfoUploadRequest uploadRequest = new WxMaOrderShippingInfoUploadRequest(); +// uploadRequest.setLogisticsType(1); +// uploadRequest.setDeliveryMode(1); +// +// OrderKeyBean orderKeyBean = new OrderKeyBean(); +// orderKeyBean.setOrderNumberType(2); +// orderKeyBean.setTransactionId(order.getTransactionId()); +// uploadRequest.setOrderKey(orderKeyBean); +// +// List shippingList = new ArrayList<>(); +// ShippingListBean shippingListBean = new ShippingListBean(); +// shippingListBean.setTrackingNo((String) bOrderData.get("kuaidinum")); +// shippingListBean.setExpressCompany(express.getWxCode()); +// ContactBean contactBean = new ContactBean(); +// contactBean.setReceiverContact(user.getMobile()); +// shippingListBean.setContact(contactBean); +// +// ShopGoods shopGoods = shopGoodsService.getById(orderGoodsList.get(0).getGoodsId()); +// +// String itemDesc = shopGoods.getName(); +// if (orderGoodsList.size() > 1) itemDesc += "等" + orderGoodsList.size() + "件商品"; +// shippingListBean.setItemDesc(itemDesc); +// shippingList.add(shippingListBean); +// uploadRequest.setShippingList(shippingList); +// +// uploadRequest.setUploadTime(new DateTime().toString(DatePattern.UTC_WITH_ZONE_OFFSET_PATTERN)); +// +// PayerBean payerBean = new PayerBean(); +// +// payerBean.setOpenid(user.getOpenid()); +// uploadRequest.setPayer(payerBean); +// +// WxMaService wxMaService = weChatController.wxMaService(); +// WxMaOrderShippingService wxMaOrderShippingService = new WxMaOrderShippingServiceImpl(wxMaService); +// WxMaOrderShippingInfoBaseResponse response = wxMaOrderShippingService.upload(uploadRequest); +// System.out.println("response" + response); + } + return new HashMap<>() {{ + put("res", true); + put("msg", "操作成功"); + }}; + } + return new HashMap<>() {{ + put("res", false); + put("msg", "未知错误"); + }}; + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderExtractServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderExtractServiceImpl.java new file mode 100644 index 0000000..91cfdab --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderExtractServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopOrderExtractMapper; +import com.gxwebsoft.shop.service.ShopOrderExtractService; +import com.gxwebsoft.shop.entity.ShopOrderExtract; +import com.gxwebsoft.shop.param.ShopOrderExtractParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 自提订单联系方式Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopOrderExtractServiceImpl extends ServiceImpl implements ShopOrderExtractService { + + @Override + public PageResult pageRel(ShopOrderExtractParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopOrderExtractParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopOrderExtract getByIdRel(Integer id) { + ShopOrderExtractParam param = new ShopOrderExtractParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderGoodsServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderGoodsServiceImpl.java new file mode 100644 index 0000000..7019db0 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderGoodsServiceImpl.java @@ -0,0 +1,78 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopOrderGoodsMapper; +import com.gxwebsoft.shop.service.ShopOrderGoodsService; +import com.gxwebsoft.shop.entity.ShopOrderGoods; +import com.gxwebsoft.shop.param.ShopOrderGoodsParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 商品信息Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Slf4j +@Service +public class ShopOrderGoodsServiceImpl extends ServiceImpl implements ShopOrderGoodsService { + + @Override + public PageResult pageRel(ShopOrderGoodsParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopOrderGoodsParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopOrderGoods getByIdRel(Integer id) { + ShopOrderGoodsParam param = new ShopOrderGoodsParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public List getListByOrderId(Integer orderId) { + return list( + new LambdaQueryWrapper() + .eq(ShopOrderGoods::getOrderId, orderId) + ); + } + + @Override + public List getListByOrderIdIgnoreTenant(Integer orderId) { + try { + if (orderId == null) { + log.warn("查询订单商品列表参数无效 - 订单ID: {}", orderId); + return List.of(); + } + + List orderGoodsList = baseMapper.selectListByOrderIdIgnoreTenant(orderId); + + log.info("忽略租户隔离查询订单商品成功 - 订单ID: {}, 商品数量: {}", + orderId, orderGoodsList != null ? orderGoodsList.size() : 0); + + return orderGoodsList != null ? orderGoodsList : List.of(); + } catch (Exception e) { + log.error("忽略租户隔离查询订单商品异常 - 订单ID: {}", orderId, e); + return List.of(); + } + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderInfoLogServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderInfoLogServiceImpl.java new file mode 100644 index 0000000..fdd7f54 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderInfoLogServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopOrderInfoLogMapper; +import com.gxwebsoft.shop.service.ShopOrderInfoLogService; +import com.gxwebsoft.shop.entity.ShopOrderInfoLog; +import com.gxwebsoft.shop.param.ShopOrderInfoLogParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 订单核销Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopOrderInfoLogServiceImpl extends ServiceImpl implements ShopOrderInfoLogService { + + @Override + public PageResult pageRel(ShopOrderInfoLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopOrderInfoLogParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopOrderInfoLog getByIdRel(Integer id) { + ShopOrderInfoLogParam param = new ShopOrderInfoLogParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderInfoServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderInfoServiceImpl.java new file mode 100644 index 0000000..6c2681b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderInfoServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopOrderInfoMapper; +import com.gxwebsoft.shop.service.ShopOrderInfoService; +import com.gxwebsoft.shop.entity.ShopOrderInfo; +import com.gxwebsoft.shop.param.ShopOrderInfoParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 场地Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopOrderInfoServiceImpl extends ServiceImpl implements ShopOrderInfoService { + + @Override + public PageResult pageRel(ShopOrderInfoParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopOrderInfoParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopOrderInfo getByIdRel(Integer id) { + ShopOrderInfoParam param = new ShopOrderInfoParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java new file mode 100644 index 0000000..51db11c --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java @@ -0,0 +1,1133 @@ +package com.gxwebsoft.shop.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.config.ConfigProperties; +import com.gxwebsoft.common.core.config.CertificateProperties; +import com.gxwebsoft.common.core.utils.*; +import com.gxwebsoft.common.core.service.PaymentCacheService; +import com.gxwebsoft.common.core.service.EnvironmentAwarePaymentService; +import com.gxwebsoft.common.core.config.SpringContextUtil; +import com.gxwebsoft.common.system.entity.Payment; +import com.gxwebsoft.shop.entity.*; +import com.gxwebsoft.shop.service.*; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import lombok.extern.slf4j.Slf4j; +import com.gxwebsoft.common.system.service.PaymentService; +import com.gxwebsoft.common.system.service.SettingService; +import com.gxwebsoft.payment.constants.WechatPayType; +import com.gxwebsoft.shop.mapper.ShopOrderMapper; +import com.gxwebsoft.shop.param.ShopOrderParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAConfig; +import com.wechat.pay.java.core.RSAPublicKeyConfig; +import com.wechat.pay.java.core.exception.ServiceException; +import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension; +import com.wechat.pay.java.service.payments.jsapi.model.*; +import com.wechat.pay.java.service.payments.nativepay.NativePayService; +// Native支付的类将使用完全限定名避免冲突 +import com.wechat.pay.java.service.payments.model.Transaction; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 订单Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Slf4j +@Service +public class ShopOrderServiceImpl extends ServiceImpl implements ShopOrderService { + @Value("${spring.profiles.active}") + String active; + @Resource + private ConfigProperties config; + @Resource + private RedisUtil redisUtil; + @Resource + private ShopOrderGoodsService shopOrderGoodsService; + @Resource + private ShopGoodsService shopGoodsService; + @Resource + private PaymentService paymentService; + @Resource + private SettingService settingService; + @Resource + private CertificateProperties certConfig; + @Resource + private CertificateLoader certificateLoader; + @Resource + private PaymentCacheService paymentCacheService; + @Resource + private WechatCertAutoConfig wechatCertAutoConfig; + @Resource + private WechatPayDiagnostic wechatPayDiagnostic; + @Resource + private WechatPayCertificateDiagnostic certificateDiagnostic; + @Resource + private ShopOrderUpdate10550Service shopOrderUpdate10550Service; + @Resource + private ShopUserCouponService shopUserCouponService; + @Resource + private ShopOrderDeliveryService shopOrderDeliveryService; + @Resource + private ShopExpressService shopExpressService; + + + @Override + public PageResult pageRel(ShopOrderParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + + // 整理订单数据 + if (!CollectionUtils.isEmpty(list)) { + final Set orderIds = list.stream().map(ShopOrder::getOrderId).collect(Collectors.toSet()); + final List goodsList = shopOrderGoodsService.list(new LambdaQueryWrapper().in(ShopOrderGoods::getOrderId, orderIds)); + final Map> collect = goodsList.stream().collect(Collectors.groupingBy(ShopOrderGoods::getOrderId)); + list.forEach(d -> { + d.setOrderGoods(collect.get(d.getOrderId())); + + // 确保 realName 字段有值,优先使用关联查询的结果,如果为空则使用订单表中的 realName + if (StrUtil.isBlank(d.getRealName())) { + log.debug("订单 {} 的 realName 为空,尝试从其他字段获取", d.getOrderId()); + // 可以根据业务需求添加其他逻辑,比如从 nickname 或其他字段获取 + } + if (d.getDeliveryStatus() > 10 && d.getDeliveryType().equals(0)) { + ShopOrderDelivery shopOrderDelivery = shopOrderDeliveryService.getByOrderId(d.getOrderId()); + if (shopOrderDelivery != null) { + ShopExpress shopExpress = shopExpressService.getById(shopOrderDelivery.getExpressId()); + if (shopExpress != null) { + shopOrderDelivery.setExpressName(shopExpress.getExpressName()); + } + } + d.setShopOrderDelivery(shopOrderDelivery); + } + }); + } + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopOrderParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopOrder getByIdRel(Integer orderId) { + ShopOrderParam param = new ShopOrderParam(); + param.setOrderId(orderId); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public HashMap createWxOrder(ShopOrder order) { + Payment payment = null; // 声明在try块外面,这样catch块也能访问 + try { + System.out.println("=== 开始创建微信支付订单 ==="); + System.out.println("订单号: " + order.getOrderNo()); + System.out.println("租户ID: " + order.getTenantId()); + System.out.println("支付类型: " + order.getPayType()); + System.out.println("订单金额: " + order.getTotalPrice()); + System.out.println("用户OpenID: " + order.getOpenid()); + + // 检查订单基本信息 + if (order.getTenantId() == null) { + throw new RuntimeException("订单租户ID为null"); + } + if (order.getOrderNo() == null || order.getOrderNo().trim().isEmpty()) { + throw new RuntimeException("订单号为空"); + } + if (order.getTotalPrice() == null) { + throw new RuntimeException("订单金额为null"); + } + + // 根据支付类型检查OpenID + if (order.getPayType().equals(1)) { + // JSAPI支付需要OpenID + if (order.getOpenid() == null || order.getOpenid().trim().isEmpty()) { + throw new RuntimeException("JSAPI支付必须传openid"); + } + } + + // 后台微信支付配置信息 + payment = getPayment(order); + System.out.println("支付配置: " + (payment != null ? "已获取" : "未获取")); + + if (payment == null) { + throw new RuntimeException("支付配置为null,租户ID: " + order.getTenantId()); + } + + // 检查支付配置的关键字段 + if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) { + throw new RuntimeException("支付配置中应用ID为null或空"); + } + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + throw new RuntimeException("支付配置中商户号为null或空"); + } + + // 返回的订单数据 + final HashMap orderInfo = new HashMap<>(); + + // 根据支付类型选择不同的处理逻辑 + if (order.getPayType().equals(102)) { + // Native支付处理(兼容旧的102类型) + System.out.println("⚠️ 检测到使用废弃的微信Native支付类型(102),建议升级到微信支付(1)"); + order.setWechatPayType(WechatPayType.NATIVE); + return createNativePayOrder(order, payment); + } else if (order.getPayType().equals(1)) { + // 微信支付处理 - 根据是否有openid判断使用JSAPI还是Native + String wechatType = WechatPayType.getAutoType(order.getOpenid()); + order.setWechatPayType(wechatType); + + if (WechatPayType.JSAPI.equals(wechatType)) { + // 有openid,使用JSAPI支付 + return createJsapiPayOrder(order, payment); + } else { + // 无openid,使用Native支付 + return createNativePayOrder(order, payment); + } + } else { + // 其他支付方式暂时使用JSAPI处理 + return createJsapiPayOrder(order, payment); + } + + } catch (Exception e) { + System.err.println("=== 创建微信支付订单失败 ==="); + System.err.println("错误信息: " + e.getMessage()); + System.err.println("错误类型: " + e.getClass().getName()); + + // 特殊处理签名验证失败的情况 + if (e.getMessage() != null && e.getMessage().contains("signature is incorrect")) { + System.err.println("🔍 签名验证失败诊断:"); + System.err.println("1. 检查商户证书序列号是否正确"); + System.err.println("2. 检查APIv3密钥是否正确"); + System.err.println("3. 检查私钥文件是否正确"); + System.err.println("4. 检查微信支付平台证书是否过期"); + System.err.println("5. 建议使用自动证书配置避免证书管理问题"); + System.err.println("当前支付配置:"); + System.err.println("租户ID: " + order.getTenantId()); + System.err.println("商户号: " + (payment != null ? payment.getMchId() : "null")); + System.err.println("应用ID: " + (payment != null ? payment.getAppId() : "null")); + } + + throw new RuntimeException("创建微信支付订单失败:" + e.getMessage(), e); + } + } + + /** + * 创建Native支付订单 + */ + private HashMap createNativePayOrder(ShopOrder order, Payment payment) throws Exception { + System.out.println("=== 使用Native支付模式 ==="); + + // 构建Native支付服务 + Config wxPayConfig = getWxPayConfig(order); + NativePayService nativeService = new NativePayService.Builder().config(wxPayConfig).build(); + + // 订单金额(转换为分) + BigDecimal decimal = order.getTotalPrice(); + final BigDecimal multiply = decimal.multiply(new BigDecimal(100)); + Integer money = multiply.intValue(); + + // 测试环境使用1分钱 + if (active.equals("dev")) { + money = 1; + } + + // 构建Native支付请求 + com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest request = + new com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest(); + com.wechat.pay.java.service.payments.nativepay.model.Amount amount = + new com.wechat.pay.java.service.payments.nativepay.model.Amount(); + amount.setTotal(money); + amount.setCurrency("CNY"); + request.setAmount(amount); + + request.setAppid(payment.getAppId()); + request.setMchid(payment.getMchId()); + + // 微信支付description字段限制127字节,需要截断处理 + String description = com.gxwebsoft.common.core.utils.WechatPayUtils.processDescription(order.getComments()); + request.setDescription(description); + request.setOutTradeNo(order.getOrderNo()); + request.setAttach(order.getTenantId().toString()); + + System.out.println("=== 关键信息确认 ==="); + System.out.println("发送给微信的订单号(OutTradeNo): " + order.getOrderNo()); + System.out.println("商户号(MchId): " + payment.getMchId()); + System.out.println("应用ID(AppId): " + payment.getAppId()); + + // 设置回调地址 + String notifyUrl = config.getServerUrl() + "/system/wx-pay/notify/" + order.getTenantId(); + if (active.equals("dev")) { + notifyUrl = "http://jimei-api.natapp1.cc/api/shop/wx-pay/notify/" + order.getTenantId(); + } + if (StrUtil.isNotBlank(payment.getNotifyUrl())) { + notifyUrl = payment.getNotifyUrl().concat("/").concat(order.getTenantId().toString()); + } + request.setNotifyUrl(notifyUrl); + + System.out.println("=== 发起Native支付请求 ==="); + System.out.println("请求参数: " + request); + + // 调用Native支付API + com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse response = nativeService.prepay(request); + + System.out.println("=== Native支付响应成功 ==="); + System.out.println("二维码URL: " + response.getCodeUrl()); + + // 构建返回数据 + final HashMap orderInfo = new HashMap<>(); + orderInfo.put("provider", "wxpay"); + orderInfo.put("codeUrl", response.getCodeUrl()); // Native支付返回二维码URL + orderInfo.put("orderNo", order.getOrderNo()); + orderInfo.put("payType", WechatPayType.NATIVE); + orderInfo.put("wechatPayType", WechatPayType.NATIVE); + + return orderInfo; + } + + /** + * 创建JSAPI支付订单(原有逻辑) + */ + private HashMap createJsapiPayOrder(ShopOrder order, Payment payment) throws Exception { + System.out.println("=== 使用JSAPI支付模式 ==="); + + // JSAPI支付必须有OpenID + if (order.getOpenid() == null || order.getOpenid().trim().isEmpty()) { + throw new RuntimeException("JSAPI支付必须传openid"); + } + + // 构建JSAPI支付服务 + JsapiServiceExtension service = getWxService(order); + System.out.println("微信支付服务构建完成"); + + // 订单金额 + BigDecimal decimal = order.getPayPrice(); + final BigDecimal multiply = decimal.multiply(new BigDecimal(100)); + Integer money = multiply.intValue(); + + System.out.println("=== 构建支付请求参数 ==="); + + PrepayRequest request = new PrepayRequest(); + Amount amount = new Amount(); + amount.setTotal(money); + amount.setCurrency("CNY"); + request.setAmount(amount); + + System.out.println("设置应用ID: " + payment.getAppId()); + request.setAppid(payment.getAppId()); + + System.out.println("设置商户号: " + payment.getMchId()); + request.setMchid(payment.getMchId()); + + // 微信支付description字段限制127字节,需要截断处理 + String description = com.gxwebsoft.common.core.utils.WechatPayUtils.processDescription(order.getComments()); + System.out.println("设置描述: " + description); + request.setDescription(description); + + System.out.println("设置订单号: " + order.getOrderNo()); + request.setOutTradeNo(order.getOrderNo()); + + System.out.println("设置附加数据: " + order.getTenantId().toString()); + request.setAttach(order.getTenantId().toString()); + + final Payer payer = new Payer(); + System.out.println("设置用户OpenID: " + order.getOpenid()); + payer.setOpenid(order.getOpenid()); + request.setPayer(payer); + request.setNotifyUrl(config.getServerUrl() + "/system/wx-pay/notify/" + order.getTenantId()); // 默认回调地址 + // 测试环境 + if (active.equals("dev")) { + amount.setTotal(1); + request.setAmount(amount); + request.setNotifyUrl("http://jimei-api.natapp1.cc/api/shop/wx-pay/notify/" + order.getTenantId()); // 默认回调地址 + } + // 后台配置的回调地址 + if (StrUtil.isNotBlank(payment.getNotifyUrl())) { + request.setNotifyUrl(payment.getNotifyUrl().concat("/").concat(order.getTenantId().toString())); + System.out.println("后台配置的回调地址 = " + request.getNotifyUrl()); + } + System.out.println("=== 发起微信支付请求 ==="); + System.out.println("请求参数: " + request); + + PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request); + + System.out.println("=== 微信支付响应成功 ==="); + System.out.println("预支付ID: " + response.getPackageVal()); + + final HashMap orderInfo = new HashMap<>(); + orderInfo.put("provider", "wxpay"); + orderInfo.put("timeStamp", response.getTimeStamp()); + orderInfo.put("nonceStr", response.getNonceStr()); + orderInfo.put("package", response.getPackageVal()); + orderInfo.put("signType", "RSA"); + orderInfo.put("paySign", response.getPaySign()); + orderInfo.put("orderNo", order.getOrderNo()); + orderInfo.put("payType", WechatPayType.JSAPI); + orderInfo.put("wechatPayType", WechatPayType.JSAPI); + return orderInfo; + } + + @Override + public ShopOrder getByOutTradeNo(String outTradeNo) { + return baseMapper.getByOutTradeNo(outTradeNo); + } + + /** + * 修复订单支付状态 + * + * @param shopOrder + */ + @Override + public Boolean queryOrderByOutTradeNo(ShopOrder shopOrder) { + // 后台微信支付配置信息 + final Payment payment = getPayment(shopOrder); + QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest(); + queryRequest.setMchid(payment.getMchId()); + queryRequest.setOutTradeNo(shopOrder.getOrderNo()); + // 构建service + JsapiServiceExtension service = getWxService(shopOrder); + try { + Transaction result = service.queryOrderByOutTradeNo(queryRequest); + if (result.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) { + shopOrder.setPayStatus(true); + shopOrder.setPayTime(LocalDateTime.now()); + shopOrder.setTransactionId(result.getTransactionId()); + updateById(shopOrder); + return true; + } + } catch (ServiceException e) { + // API返回失败, 例如ORDER_NOT_EXISTS + System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage()); + System.out.printf("reponse body=[%s]\n", e.getResponseBody()); + } + return false; + } + + @Override + public void updateByOutTradeNo(ShopOrder order) { + order.setExpirationTime(null); + baseMapper.updateByOutTradeNo(order); + + // 处理支付成功后的业务逻辑 + handlePaymentSuccess(order); + + if (order.getTenantId().equals(10550)) { + shopOrderUpdate10550Service.update(order); + } + } + + /** + * 处理支付成功后的业务逻辑 + */ + private void handlePaymentSuccess(ShopOrder order) { + try { + // 1. 使用优惠券 + if (order.getCouponId() != null && order.getCouponId() > 0) { + markCouponAsUsed(order); + } + + // 2. 累计商品销量 + updateGoodsSales(order); + + log.info("支付成功后业务逻辑处理完成 - 订单号:{}", order.getOrderNo()); + } catch (Exception e) { + log.error("处理支付成功后业务逻辑失败 - 订单号:{}", order.getOrderNo(), e); + // 不抛出异常,避免影响支付回调的成功响应 + } + } + + /** + * 标记优惠券为已使用 + */ + private void markCouponAsUsed(ShopOrder order) { + try { + // 注入 CouponStatusService 并使用其 useCoupon 方法 + // couponStatusService.useCoupon(order.getCouponId().longValue(), order.getOrderId(), order.getOrderNo()); + + // 临时保持原有逻辑,建议后续重构 + ShopUserCoupon coupon = shopUserCouponService.getById(order.getCouponId()); + if (coupon != null) { + coupon.markAsUsed(order.getOrderId(), order.getOrderNo()); + shopUserCouponService.updateById(coupon); + log.info("优惠券标记为已使用 - 优惠券ID:{},订单号:{}", order.getCouponId(), order.getOrderNo()); + } + } catch (Exception e) { + log.error("标记优惠券为已使用失败 - 优惠券ID:{},订单号:{}", order.getCouponId(), order.getOrderNo(), e); + } + } + + /** + * 累计商品销量 + */ + private void updateGoodsSales(ShopOrder order) { + try { + // 获取订单商品列表(忽略租户隔离) + final List orderGoodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId()); + + if (orderGoodsList.isEmpty()) { + log.warn("订单商品列表为空 - 订单号:{}", order.getOrderNo()); + return; + } + + // 累计每个商品的销量 + for (ShopOrderGoods orderGoods : orderGoodsList) { + updateSingleGoodsSales(orderGoods); + } + + log.info("商品销量累计完成 - 订单号:{},商品数量:{}", order.getOrderNo(), orderGoodsList.size()); + } catch (Exception e) { + log.error("累计商品销量失败 - 订单号:{}", order.getOrderNo(), e); + } + } + + /** + * 累计单个商品的销量 + * 使用新的addSaleCount方法,忽略租户隔离确保更新成功 + */ + private void updateSingleGoodsSales(ShopOrderGoods orderGoods) { + try { + if (orderGoods.getGoodsId() == null || orderGoods.getTotalNum() == null || orderGoods.getTotalNum() <= 0) { + log.warn("商品销量累计参数无效 - 商品ID:{},购买数量:{}", + orderGoods.getGoodsId(), orderGoods.getTotalNum()); + return; + } + + // 使用新的addSaleCount方法,忽略租户隔离 + boolean updated = shopGoodsService.addSaleCount(orderGoods.getGoodsId(), orderGoods.getTotalNum()); + + if (updated) { + log.info("商品销量累计成功 - 商品ID:{},商品名称:{},购买数量:{}", + orderGoods.getGoodsId(), orderGoods.getGoodsName(), orderGoods.getTotalNum()); + } else { + log.warn("商品销量累计失败 - 商品ID:{},商品名称:{},购买数量:{}", + orderGoods.getGoodsId(), orderGoods.getGoodsName(), orderGoods.getTotalNum()); + } + } catch (Exception e) { + log.error("累计单个商品销量异常 - 商品ID:{},商品名称:{},购买数量:{}", + orderGoods.getGoodsId(), orderGoods.getGoodsName(), orderGoods.getTotalNum(), e); + } + } + + /** + * 读取微信支付配置 + * 生产环境优先从缓存读取 Payment:1* 格式的商户信息 + * 开发环境自动使用本地回调地址 + * + * @param order + * @return + */ + public Payment getPayment(ShopOrder order) { + // 先清除可能的错误缓存 +// paymentCacheService.removePaymentConfig(order.getPayType().toString(), order.getTenantId()); + + // 使用环境感知的支付配置服务 + Payment payment; + try { + // 尝试使用环境感知服务 + EnvironmentAwarePaymentService envPaymentService = + SpringContextUtil.getBean(EnvironmentAwarePaymentService.class); + payment = envPaymentService.getEnvironmentAwarePaymentConfig(order.getPayType(), order.getTenantId()); + } catch (Exception e) { + // 如果环境感知服务不可用,回退到原有方式 + log.warn("环境感知支付服务不可用,使用原有配置方式: {}", e.getMessage()); + payment = paymentCacheService.getPaymentConfig(order.getPayType(), order.getTenantId()); + } + + // 添加详细的支付配置检查 + System.out.println("=== 支付配置检查 ==="); + System.out.println("订单支付类型: " + order.getPayType()); + System.out.println("租户ID: " + order.getTenantId()); + + if (payment == null) { + throw new RuntimeException("未找到支付配置,支付类型: " + order.getPayType() + ", 租户ID: " + order.getTenantId()); + } + + System.out.println("支付配置ID: " + payment.getId()); + System.out.println("支付方式名称: " + payment.getName()); + System.out.println("支付类型: " + payment.getType()); + System.out.println("支付代码: " + payment.getCode()); + System.out.println("应用ID: " + payment.getAppId()); + System.out.println("商户号: " + payment.getMchId()); + System.out.println("API密钥: " + (payment.getApiKey() != null ? "已配置(长度:" + payment.getApiKey().length() + ")" : "未配置")); + System.out.println("商户证书序列号: " + payment.getMerchantSerialNumber()); + System.out.println("状态: " + payment.getStatus()); + + return payment; + } + + /** + * 构建微信支付 + * + * @param order + * @return + */ + public JsapiServiceExtension getWxService(ShopOrder order) { + try { + final Payment payment = getPayment(order); + + // 提前声明所有需要的变量,避免重复定义 + String privateKey; + String apiclientCert = null; + String pubKey = null; + String tenantCertPath = null; + String privateKeyPath = null; + String pubKeyPath = null; + String apiclientCertPath = null; + String apiclientCertFile = null; + String pubKeyFile = null; + + // 运行配置诊断 + System.out.println("=== 运行微信支付配置诊断 ==="); + wechatPayDiagnostic.diagnosePaymentConfig(payment, null, active); + + // 运行证书诊断 + System.out.println("=== 运行证书诊断 ==="); + WechatPayCertificateDiagnostic.DiagnosticResult diagnosticResult = + certificateDiagnostic.diagnoseCertificateConfig(payment, order.getTenantId(), active); + System.out.println(diagnosticResult.getFullReport()); + + + + // 构建微信支付配置 + Config config = null; + if (active.equals("dev")) { + // 开发环境使用自动证书配置 + // 首先初始化私钥路径 + tenantCertPath = "dev/wechat/" + order.getTenantId(); + privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + privateKey = certificateLoader.loadCertificatePath(privateKeyPath); + System.out.println("开发环境私钥路径: " + privateKeyPath); + System.out.println("开发环境私钥加载成功: " + privateKey); + + // 检查数据库配置是否完整 + if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) { + throw new RuntimeException("数据库中商户号(mchId)未配置"); + } + if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) { + throw new RuntimeException("数据库中商户证书序列号(merchantSerialNumber)未配置"); + } + if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) { + throw new RuntimeException("数据库中API密钥(apiKey)未配置"); + } + + System.out.println("=== 使用数据库支付配置 ==="); + System.out.println("商户号: " + payment.getMchId()); + System.out.println("序列号: " + payment.getMerchantSerialNumber()); + System.out.println("API密钥: 已配置(长度:" + payment.getApiKey().length() + ")"); + + // 临时使用RSA配置替代自动证书配置,避免404错误 + System.out.println("=== 注意:使用RSA配置替代自动证书配置 ==="); + System.out.println("原因:商户平台可能未开启API安全功能或未申请微信支付公钥"); + + // 首先检查是否配置了公钥,如果有则优先使用公钥模式 + if (payment.getPubKey() != null && !payment.getPubKey().isEmpty() && + payment.getPubKeyId() != null && !payment.getPubKeyId().isEmpty()) { + + try { + // 开发环境固定使用 wechatpay_public_key.pem + pubKeyPath = tenantCertPath + "/wechatpay_public_key.pem"; + + System.out.println("开发环境公钥文件路径: " + pubKeyPath); + + // 检查公钥文件是否存在 + if (certificateLoader.certificateExists(pubKeyPath)) { + System.out.println("=== 检测到公钥配置,使用RSA公钥模式 ==="); + System.out.println("公钥文件: " + payment.getPubKey()); + System.out.println("公钥ID: " + payment.getPubKeyId()); + + pubKeyFile = certificateLoader.loadCertificatePath(pubKeyPath); + System.out.println("✅ 开发环境公钥文件加载成功: " + pubKeyFile); + + config = new RSAPublicKeyConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .publicKeyFromPath(pubKeyFile) + .publicKeyId(payment.getPubKeyId()) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(payment.getApiKey()) + .build(); + System.out.println("✅ 开发环境RSA公钥配置成功"); + } else { + System.out.println("⚠️ 开发环境公钥文件不存在,跳过公钥模式: " + pubKeyPath); + // 跳过公钥配置,继续后续的自动证书配置 + } + } catch (Exception e) { + System.err.println("❌ 开发环境公钥配置检查失败: " + e.getMessage()); + // 跳过公钥配置,继续后续的自动证书配置 + } + } + + // 如果没有公钥配置或公钥文件不存在,尝试自动证书配置 + if (config == null) { + // 没有公钥配置,尝试自动证书配置 + try { + System.out.println("=== 尝试创建自动证书配置 ==="); + System.out.println("商户号: " + payment.getMchId()); + System.out.println("私钥路径: " + privateKey); + System.out.println("序列号: " + payment.getMerchantSerialNumber()); + System.out.println("API密钥长度: " + (payment.getApiKey() != null ? payment.getApiKey().length() : 0)); + + config = wechatCertAutoConfig.createAutoConfig( + payment.getMchId(), + privateKey, + payment.getMerchantSerialNumber(), + payment.getApiKey() + ); + System.out.println("✅ 开发环境自动证书配置成功"); + } catch (Exception e) { + System.err.println("❌ 自动证书配置失败: " + e.getMessage()); + System.err.println("错误类型: " + e.getClass().getName()); + e.printStackTrace(); + + // 检查是否是证书相关的错误 + if (e.getMessage() != null && ( + e.getMessage().contains("certificate") || + e.getMessage().contains("X509Certificate") || + e.getMessage().contains("getSerialNumber") || + e.getMessage().contains("404") || + e.getMessage().contains("API安全"))) { + + System.err.println("🔍 证书问题诊断:"); + System.err.println("1. 检查商户平台是否已开启API安全功能"); + System.err.println("2. 检查是否已申请使用微信支付公钥"); + System.err.println("3. 检查网络连接是否正常"); + System.err.println("4. 检查商户证书序列号是否正确"); + System.err.println("5. 参考文档:https://pay.weixin.qq.com/doc/v3/merchant/4012153196"); + + // 开发环境回退到基础RSA配置 + System.err.println("⚠️ 开发环境回退到基础RSA配置..."); + try { + // 方案1:尝试使用RSA证书配置(需要商户证书文件) + apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); + + if (certificateLoader.certificateExists(apiclientCertPath)) { + apiclientCertFile = certificateLoader.loadCertificatePath(apiclientCertPath); + System.out.println("方案1: 使用RSA证书配置作为回退方案"); + System.out.println("商户证书路径: " + apiclientCertFile); + + try { + config = new RSAConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .wechatPayCertificatesFromPath(apiclientCertFile) + .build(); + System.out.println("✅ 开发环境RSA证书配置成功"); + } catch (Exception rsaException) { + System.err.println("RSA证书配置失败: " + rsaException.getMessage()); + throw rsaException; + } + } else { + System.err.println("❌ 商户证书文件不存在: " + apiclientCertPath); + System.err.println("⚠️ 尝试方案2: 使用最小化配置..."); + + // 方案2:使用最小化的RSA配置(仅私钥和序列号) + try { + // 创建一个最基础的配置,不依赖平台证书 + config = new com.wechat.pay.java.core.RSAConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .build(); + System.out.println("✅ 开发环境最小化RSA配置成功"); + } catch (Exception minimalException) { + System.err.println("最小化配置也失败: " + minimalException.getMessage()); + throw new RuntimeException("所有配置方案都失败,请检查私钥文件和商户配置", e); + } + } + } catch (Exception fallbackException) { + System.err.println("❌ 手动证书配置失败: " + fallbackException.getMessage()); + fallbackException.printStackTrace(); + + // 最后的回退:抛出详细错误信息 + System.err.println("=== 最终错误诊断 ==="); + System.err.println("1. 自动证书配置失败原因: " + e.getMessage()); + System.err.println("2. 手动证书配置失败原因: " + fallbackException.getMessage()); + System.err.println("3. 建议解决方案:"); + System.err.println(" - 检查微信商户平台是否开启API安全功能"); + System.err.println(" - 确认已申请使用微信支付公钥"); + System.err.println(" - 验证商户证书序列号是否正确"); + System.err.println(" - 检查私钥文件是否完整且格式正确"); + + throw new RuntimeException("微信支付配置失败,请检查商户平台API安全设置和证书配置。原始错误: " + e.getMessage() + ", 回退错误: " + fallbackException.getMessage(), e); + } + } else { + throw new RuntimeException("微信支付配置失败:" + e.getMessage(), e); + } + } + } + } else { + // 生产环境 - 首先初始化私钥 + final String certRootPath = certConfig.getCertRootPath(); + System.out.println("生产环境证书根路径: " + certRootPath); + + String privateKeyRelativePath = payment.getApiclientKey(); + System.out.println("数据库中的私钥相对路径: " + privateKeyRelativePath); + + // 生产环境已经没有/file目录,所有路径都直接拼接到根路径 + String privateKeyFullPath; + // 处理数据库中可能存在的历史路径格式 + String cleanPath = privateKeyRelativePath; + if (privateKeyRelativePath.startsWith("/file/")) { + // 去掉历史的 /file/ 前缀 + cleanPath = privateKeyRelativePath.substring(6); + } else if (privateKeyRelativePath.startsWith("file/")) { + // 去掉历史的 file/ 前缀 + cleanPath = privateKeyRelativePath.substring(5); + } + // 确保路径以 / 开头 + if (!cleanPath.startsWith("/")) { + cleanPath = "/" + cleanPath; + } + privateKeyFullPath = certRootPath + cleanPath; + + System.out.println("生产环境私钥完整路径: " + privateKeyFullPath); + privateKey = certificateLoader.loadCertificatePath(privateKeyFullPath); + System.out.println("✅ 生产环境私钥加载完成: " + privateKey); + + // 生产环境也优先检查公钥配置 + if (payment.getPubKey() != null && !payment.getPubKey().isEmpty() && + payment.getPubKeyId() != null && !payment.getPubKeyId().isEmpty()) { + + System.out.println("=== 生产环境检测到公钥配置,使用RSA公钥模式 ==="); + System.out.println("公钥文件路径: " + payment.getPubKey()); + System.out.println("公钥ID: " + payment.getPubKeyId()); + + try { + // 生产环境处理公钥路径 + String pubKeyRelativePath = payment.getPubKey(); + System.out.println("数据库中的公钥相对路径: " + pubKeyRelativePath); + + // 生产环境已经没有/file目录,所有路径都直接拼接到根路径 + String pubKeyFullPath; + // 处理数据库中可能存在的历史路径格式 + String cleanPubPath = pubKeyRelativePath; + if (pubKeyRelativePath.startsWith("/file/")) { + // 去掉历史的 /file/ 前缀 + cleanPubPath = pubKeyRelativePath.substring(6); + } else if (pubKeyRelativePath.startsWith("file/")) { + // 去掉历史的 file/ 前缀 + cleanPubPath = pubKeyRelativePath.substring(5); + } + // 确保路径以 / 开头 + if (!cleanPubPath.startsWith("/")) { + cleanPubPath = "/" + cleanPubPath; + } + pubKeyFullPath = certRootPath + cleanPubPath; + + System.out.println("生产环境公钥完整路径: " + pubKeyFullPath); + pubKeyFile = certificateLoader.loadCertificatePath(pubKeyFullPath); + System.out.println("✅ 生产环境公钥文件加载成功: " + pubKeyFile); + + config = new RSAPublicKeyConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .publicKeyFromPath(pubKeyFile) + .publicKeyId(payment.getPubKeyId()) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(payment.getApiKey()) + .build(); + System.out.println("✅ 生产环境RSA公钥配置成功"); + } catch (Exception pubKeyException) { + System.err.println("❌ 生产环境RSA公钥配置失败: " + pubKeyException.getMessage()); + pubKeyException.printStackTrace(); + throw new RuntimeException("生产环境RSA公钥配置失败: " + pubKeyException.getMessage(), pubKeyException); + } + } else { + // 没有公钥配置,使用自动证书配置 + System.out.println("=== 生产环境使用自动证书配置 ==="); + System.out.println("商户号: " + payment.getMchId()); + System.out.println("序列号: " + payment.getMerchantSerialNumber()); + System.out.println("API密钥: 已配置(长度:" + payment.getApiKey().length() + ")"); + + try { + // 优先使用自动证书配置,避免证书过期和序列号不匹配问题 + config = wechatCertAutoConfig.createAutoConfig( + payment.getMchId(), + privateKey, + payment.getMerchantSerialNumber(), + payment.getApiKey() + ); + System.out.println("✅ 生产环境自动证书配置成功"); + } catch (Exception autoConfigException) { + System.err.println("⚠️ 自动证书配置失败,回退到手动证书配置"); + System.err.println("自动配置错误: " + autoConfigException.getMessage()); + System.err.println("错误类型: " + autoConfigException.getClass().getName()); + autoConfigException.printStackTrace(); + + // 检查是否是证书相关的错误 + if (autoConfigException.getMessage() != null && ( + autoConfigException.getMessage().contains("certificate") || + autoConfigException.getMessage().contains("X509Certificate") || + autoConfigException.getMessage().contains("getSerialNumber") || + autoConfigException.getMessage().contains("404") || + autoConfigException.getMessage().contains("API安全"))) { + + System.err.println("🔍 生产环境证书问题诊断:"); + System.err.println("1. 检查商户平台是否已开启API安全功能"); + System.err.println("2. 检查是否已申请使用微信支付公钥"); + System.err.println("3. 检查网络连接是否正常"); + System.err.println("4. 检查商户证书序列号是否正确"); + } + + try { + // 回退到手动证书配置 + if (payment.getPubKey() != null && !payment.getPubKey().isEmpty()) { + System.out.println("使用RSA公钥配置作为回退方案"); + config = new RSAPublicKeyConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .publicKeyFromPath(pubKey) + .publicKeyId(payment.getPubKeyId()) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(payment.getApiKey()) + .build(); + System.out.println("✅ 生产环境RSA公钥配置成功"); + } else if (apiclientCert != null && !apiclientCert.isEmpty()) { + System.out.println("使用RSA证书配置作为回退方案"); + config = new RSAConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .wechatPayCertificatesFromPath(apiclientCert) + .build(); + System.out.println("✅ 生产环境RSA证书配置成功"); + } else { + throw new RuntimeException("生产环境缺少必要的证书文件,无法创建手动证书配置", autoConfigException); + } + } catch (Exception fallbackException) { + System.err.println("❌ 生产环境手动证书配置也失败: " + fallbackException.getMessage()); + throw new RuntimeException("生产环境微信支付配置失败,请检查商户平台API安全设置和证书配置", autoConfigException); + } + } + } + } + + // 构建service + return new JsapiServiceExtension.Builder().config(config).build(); + } catch (Exception e) { + System.err.println("=== 构建微信支付服务失败 ==="); + System.err.println("错误信息: " + e.getMessage()); + System.err.println("错误类型: " + e.getClass().getName()); + e.printStackTrace(); + throw new RuntimeException("构建微信支付服务失败:" + e.getMessage(), e); + } + } + + @Override + public BigDecimal total() { + try { + // 使用数据库聚合查询统计订单总金额,性能更高 + BigDecimal total = baseMapper.selectTotalAmount(); + + if (total == null) { + total = BigDecimal.ZERO; + } + + log.info("统计订单总金额完成,总金额:{}", total); + return total; + + } catch (Exception e) { + log.error("统计订单总金额失败", e); + return BigDecimal.ZERO; + } + } + + /** + * 获取Native支付的微信支付配置 + */ + private Config getWxPayConfig(ShopOrder order) throws Exception { + try { + final Payment payment = getPayment(order); + String privateKey; + String apiclientCert = null; + String pubKey = null; + + // 初始化证书路径 + if (active.equals("dev")) { + // 开发环境 - 构建包含租户号的证书路径 + String tenantCertPath = "dev/wechat/" + order.getTenantId(); + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + + System.out.println("开发环境证书路径 - 租户ID: " + order.getTenantId()); + System.out.println("开发环境证书路径 - 私钥: " + privateKeyPath); + + privateKey = certificateLoader.loadCertificatePath(privateKeyPath); + System.out.println("私钥完整路径: " + privateKey); + + // 尝试加载公钥(如果配置了) + if (StrUtil.isNotBlank(payment.getPubKey()) && StrUtil.isNotBlank(payment.getPubKeyId())) { + try { + String pubKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getWechatpayCertFile(); + pubKey = certificateLoader.loadCertificatePath(pubKeyPath); + System.out.println("✅ 开发环境公钥加载成功"); + } catch (Exception e) { + System.out.println("⚠️ 开发环境公钥加载失败,将使用自动证书配置: " + e.getMessage()); + } + } + } else { + // 生产环境 - 从数据库配置的路径加载 + final String certRootPath = certConfig.getCertRootPath(); + + System.out.println("生产环境证书路径 - 租户ID: " + order.getTenantId()); + System.out.println("生产环境证书根路径: " + certRootPath); + System.out.println("私钥文件名: " + payment.getApiclientKey()); + + String privateKeyRelativePath = payment.getApiclientKey(); + + // 生产环境已经没有/file目录,所有路径都直接拼接到根路径 + String privateKeyFullPath; + // 处理数据库中可能存在的历史路径格式 + String cleanPath2 = privateKeyRelativePath; + if (privateKeyRelativePath.startsWith("/file/")) { + // 去掉历史的 /file/ 前缀 + cleanPath2 = privateKeyRelativePath.substring(6); + } else if (privateKeyRelativePath.startsWith("file/")) { + // 去掉历史的 file/ 前缀 + cleanPath2 = privateKeyRelativePath.substring(5); + } + // 确保路径以 / 开头 + if (!cleanPath2.startsWith("/")) { + cleanPath2 = "/" + cleanPath2; + } + privateKeyFullPath = certRootPath + cleanPath2; + + System.out.println("私钥完整路径: " + privateKeyFullPath); + privateKey = certificateLoader.loadCertificatePath(privateKeyFullPath); + System.out.println("✅ 生产环境私钥加载完成: " + privateKey); + + // 尝试加载公钥(如果配置了) + if (StrUtil.isNotBlank(payment.getPubKey()) && StrUtil.isNotBlank(payment.getPubKeyId())) { + try { + String pubKeyRelativePath = payment.getPubKey(); + System.out.println("数据库中的公钥相对路径: " + pubKeyRelativePath); + + // 生产环境已经没有/file目录,所有路径都直接拼接到根路径 + String pubKeyFullPath; + // 处理数据库中可能存在的历史路径格式 + String cleanPubPath2 = pubKeyRelativePath; + if (pubKeyRelativePath.startsWith("/file/")) { + // 去掉历史的 /file/ 前缀 + cleanPubPath2 = pubKeyRelativePath.substring(6); + } else if (pubKeyRelativePath.startsWith("file/")) { + // 去掉历史的 file/ 前缀 + cleanPubPath2 = pubKeyRelativePath.substring(5); + } + // 确保路径以 / 开头 + if (!cleanPubPath2.startsWith("/")) { + cleanPubPath2 = "/" + cleanPubPath2; + } + pubKeyFullPath = certRootPath + cleanPubPath2; + + System.out.println("生产环境公钥完整路径: " + pubKeyFullPath); + pubKey = certificateLoader.loadCertificatePath(pubKeyFullPath); + System.out.println("✅ 生产环境公钥加载成功"); + } catch (Exception e) { + System.out.println("⚠️ 生产环境公钥加载失败,将使用自动证书配置: " + e.getMessage()); + } + } + } + + // 根据可用的证书类型选择配置方式 + Config config; + if (pubKey != null && StrUtil.isNotBlank(payment.getPubKeyId())) { + // 使用RSA公钥配置(推荐方式) + System.out.println("🔧 使用RSA公钥配置"); + config = new RSAPublicKeyConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .publicKeyFromPath(pubKey) + .publicKeyId(payment.getPubKeyId()) + .apiV3Key(payment.getApiKey()) + .build(); + } else { + // 使用自动证书配置 + System.out.println("🔧 使用RSA自动证书配置"); + config = new RSAAutoCertificateConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(payment.getApiKey()) + .build(); + } + + System.out.println("✅ 微信支付配置构建成功"); + return config; + + } catch (Exception e) { + System.err.println("❌ 构建微信支付服务失败: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("构建微信支付服务失败:" + e.getMessage(), e); + } + } + + @Override + public ShopOrder getByOrderNo(String orderNo, Integer tenantId) { + return this.lambdaQuery() + .eq(ShopOrder::getOrderNo, orderNo) + .eq(ShopOrder::getTenantId, tenantId) + .one(); + } + + @Override + public boolean syncPaymentStatus(String orderNo, Integer paymentStatus, String transactionId, String payTime, Integer tenantId) { + try { + // 查询订单 + ShopOrder order = getByOrderNo(orderNo, tenantId); + if (order == null) { + log.warn("同步支付状态失败:订单不存在, orderNo={}, tenantId={}", orderNo, tenantId); + return false; + } + + // 如果订单已经是支付成功状态,不需要更新 + if (order.getPayStatus() && paymentStatus == 1) { + log.info("订单已经是支付成功状态,无需更新: orderNo={}", orderNo); + return true; + } + + // 更新订单状态 + boolean updated = this.lambdaUpdate() + .eq(ShopOrder::getOrderNo, orderNo) + .eq(ShopOrder::getTenantId, tenantId) + .set(ShopOrder::getPayStatus, paymentStatus == 1) + .set(transactionId != null, ShopOrder::getTransactionId, transactionId) + .set(payTime != null, ShopOrder::getPayTime, payTime) + .set(ShopOrder::getUpdateTime, LocalDateTime.now()) + .update(); + + if (updated) { + log.info("订单支付状态同步成功: orderNo={}, paymentStatus={}, transactionId={}", + orderNo, paymentStatus, transactionId); + } else { + log.warn("订单支付状态同步失败: orderNo={}, paymentStatus={}", orderNo, paymentStatus); + } + + return updated; + + } catch (Exception e) { + log.error("同步订单支付状态异常: orderNo={}, error={}", orderNo, e.getMessage(), e); + return false; + } + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderUpdate10550ServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderUpdate10550ServiceImpl.java new file mode 100644 index 0000000..671ac42 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderUpdate10550ServiceImpl.java @@ -0,0 +1,298 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.system.entity.DictData; +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.entity.UserReferee; +import com.gxwebsoft.common.system.param.DictDataParam; +import com.gxwebsoft.common.system.service.DictDataService; +import com.gxwebsoft.common.system.service.UserRefereeService; +import com.gxwebsoft.common.system.service.UserService; +import com.gxwebsoft.shop.entity.*; +import com.gxwebsoft.shop.service.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 订单更新业务处理Service实现 + * 处理特定租户(10550)的订单相关业务逻辑 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Slf4j +@Service +public class ShopOrderUpdate10550ServiceImpl implements ShopOrderUpdate10550Service { + + @Resource + private UserService userService; + @Resource + private DictDataService dictDataService; + @Resource + private UserRefereeService userRefereeService; + @Resource + private ShopDealerOrderService shopDealerOrderService; + @Resource + private ShopDealerCapitalService shopDealerCapitalService; + @Resource + private ShopOrderGoodsService shopOrderGoodsService; + @Resource + private ShopGoodsService shopGoodsService; + + @Override + public void update(ShopOrder order) { + try { + log.info("开始处理订单更新业务 - 订单ID: {}, 用户ID: {}, 租户ID: {}", + order.getOrderId(), order.getUserId(), order.getTenantId()); + + // 1. 获取合伙人条件配置 + BigDecimal partnerCondition = getPartnerCondition(); + if (partnerCondition == null) { + log.warn("未找到合伙人条件配置,跳过用户等级更新"); + return; + } + + // 2. 更新用户消费金额和等级 + updateUserGradeAndExpendMoney(order, partnerCondition); + + // 3. 处理分销业务(如果需要) + // processDistributionBusiness(order); + + log.info("订单更新业务处理完成 - 订单ID: {}", order.getOrderId()); + } catch (Exception e) { + log.error("处理订单更新业务异常 - 订单ID: {}", order.getOrderId(), e); + } + } + + /** + * 获取合伙人条件配置 + * @return 合伙人条件金额 + */ + private BigDecimal getPartnerCondition() { + try { + // 查询字典ID为1460的配置 + DictDataParam param = new DictDataParam(); + param.setDictId(1460); + List dictDataList = dictDataService.listRel(param); + + if (dictDataList != null && !dictDataList.isEmpty()) { + String dictDataCode = dictDataList.get(0).getDictDataCode(); + BigDecimal partnerCondition = new BigDecimal(dictDataCode); + log.info("获取合伙人条件配置成功 - 金额: {}", partnerCondition); + return partnerCondition; + } + } catch (Exception e) { + log.error("获取合伙人条件配置异常", e); + } + return null; + } + + /** + * 更新用户等级和消费金额 + * @param order 订单信息 + * @param partnerCondition 合伙人条件金额 + */ + private void updateUserGradeAndExpendMoney(ShopOrder order, BigDecimal partnerCondition) { + try { + // 查询用户信息(忽略租户隔离) + User user = userService.getByIdIgnoreTenant(order.getUserId()); + if (user == null) { + log.warn("用户不存在 - 用户ID: {}", order.getUserId()); + return; + } + + // 累加消费金额 + BigDecimal currentExpendMoney = user.getExpendMoney() != null ? user.getExpendMoney() : BigDecimal.ZERO; + BigDecimal newExpendMoney = currentExpendMoney.add(order.getPayPrice()); + user.setExpendMoney(newExpendMoney); + + // 检查是否达到合伙人条件 + boolean shouldUpgrade = newExpendMoney.compareTo(partnerCondition) >= 0 && !Integer.valueOf(3).equals(user.getGradeId()); + if (shouldUpgrade) { + user.setGradeId(3); + log.info("用户等级升级为合伙人 - 用户ID: {}, 消费金额: {}, 条件金额: {}", + user.getUserId(), newExpendMoney, partnerCondition); + } + + // 更新用户信息(使用忽略租户隔离的更新方法) + userService.updateByUserId(user); + + log.info("用户信息更新成功 - 用户ID: {}, 消费金额: {} -> {}, 等级: {}", + user.getUserId(), currentExpendMoney, newExpendMoney, user.getGradeId()); + + } catch (Exception e) { + log.error("更新用户等级和消费金额异常 - 用户ID: {}", order.getUserId(), e); + } + } + + /** + * 处理分销业务(暂时注释,如需启用请取消注释) + * @param order 订单信息 + */ + @SuppressWarnings("unused") + private void processDistributionBusiness(ShopOrder order) { + try { + // 获取推荐人信息 + User parent = getParentUser(order.getUserId()); + if (parent == null) { + log.info("用户无推荐人,跳过分销业务处理 - 用户ID: {}", order.getUserId()); + return; + } + + // 计算佣金 + BigDecimal commission = calculateCommission(order); + if (commission.compareTo(BigDecimal.ZERO) <= 0) { + log.info("佣金为0,跳过分销业务处理 - 订单ID: {}", order.getOrderId()); + return; + } + + // 更新推荐人余额 + updateParentBalance(parent, commission); + + // 创建分销订单记录 + createDealerOrder(parent, order, commission); + + // 创建分销资金明细 + createDealerCapital(parent, order); + + log.info("分销业务处理完成 - 订单ID: {}, 推荐人ID: {}, 佣金: {}", + order.getOrderId(), parent.getUserId(), commission); + + } catch (Exception e) { + log.error("处理分销业务异常 - 订单ID: {}", order.getOrderId(), e); + } + } + + /** + * 获取推荐人信息 + * @param userId 用户ID + * @return 推荐人信息 + */ + private User getParentUser(Integer userId) { + try { + UserReferee userReferee = userRefereeService.getByUserId(userId); + if (userReferee != null && userReferee.getDealerId() != null) { + return userService.getByIdIgnoreTenant(userReferee.getDealerId()); + } + } catch (Exception e) { + log.error("获取推荐人信息异常 - 用户ID: {}", userId, e); + } + return null; + } + + /** + * 计算佣金 + * @param order 订单信息 + * @return 总佣金 + */ + private BigDecimal calculateCommission(ShopOrder order) { + try { + // 获取订单商品列表(忽略租户隔离) + List orderGoodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId()); + if (orderGoodsList.isEmpty()) { + return BigDecimal.ZERO; + } + + // 获取商品信息 + List goodsIds = orderGoodsList.stream() + .map(ShopOrderGoods::getGoodsId) + .toList(); + List goodsList = shopGoodsService.listByIds(goodsIds); + + // 计算总佣金 + BigDecimal totalCommission = BigDecimal.ZERO; + for (ShopOrderGoods orderGoods : orderGoodsList) { + ShopGoods goods = goodsList.stream() + .filter(g -> g.getGoodsId().equals(orderGoods.getGoodsId())) + .findFirst() + .orElse(null); + + if (goods != null && goods.getCommission() != null) { + BigDecimal goodsCommission = goods.getCommission() + .multiply(BigDecimal.valueOf(orderGoods.getTotalNum())); + totalCommission = totalCommission.add(goodsCommission); + } + } + + log.info("佣金计算完成 - 订单ID: {}, 总佣金: {}", order.getOrderId(), totalCommission); + return totalCommission; + + } catch (Exception e) { + log.error("计算佣金异常 - 订单ID: {}", order.getOrderId(), e); + return BigDecimal.ZERO; + } + } + + /** + * 更新推荐人余额 + * @param parent 推荐人信息 + * @param commission 佣金金额 + */ + private void updateParentBalance(User parent, BigDecimal commission) { + try { + BigDecimal currentBalance = parent.getBalance() != null ? parent.getBalance() : BigDecimal.ZERO; + BigDecimal newBalance = currentBalance.add(commission); + parent.setBalance(newBalance); + + userService.updateByUserId(parent); + + log.info("推荐人余额更新成功 - 用户ID: {}, 余额: {} -> {}", + parent.getUserId(), currentBalance, newBalance); + + } catch (Exception e) { + log.error("更新推荐人余额异常 - 用户ID: {}", parent.getUserId(), e); + } + } + + /** + * 创建分销订单记录 + * @param parent 推荐人信息 + * @param order 订单信息 + * @param commission 佣金金额 + */ + private void createDealerOrder(User parent, ShopOrder order, BigDecimal commission) { + try { + ShopDealerOrder dealerOrder = new ShopDealerOrder(); + dealerOrder.setUserId(parent.getUserId()); + dealerOrder.setOrderNo(order.getOrderNo()); + dealerOrder.setOrderPrice(order.getTotalPrice()); + dealerOrder.setFirstUserId(order.getUserId()); + dealerOrder.setFirstMoney(commission); + dealerOrder.setIsSettled(1); + dealerOrder.setSettleTime(LocalDateTime.now()); + + shopDealerOrderService.save(dealerOrder); + + log.info("分销订单记录创建成功 - 推荐人ID: {}, 订单ID: {}", parent.getUserId(), order.getOrderId()); + + } catch (Exception e) { + log.error("创建分销订单记录异常 - 推荐人ID: {}, 订单ID: {}", parent.getUserId(), order.getOrderId(), e); + } + } + + /** + * 创建分销资金明细 + * @param parent 推荐人信息 + * @param order 订单信息 + */ + private void createDealerCapital(User parent, ShopOrder order) { + try { + ShopDealerCapital dealerCapital = new ShopDealerCapital(); + dealerCapital.setUserId(parent.getUserId()); + dealerCapital.setOrderNo(order.getOrderNo()); + dealerCapital.setFlowType(10); // 分销收入 + + shopDealerCapitalService.save(dealerCapital); + + log.info("分销资金明细创建成功 - 推荐人ID: {}, 订单ID: {}", parent.getUserId(), order.getOrderId()); + + } catch (Exception e) { + log.error("创建分销资金明细异常 - 推荐人ID: {}, 订单ID: {}", parent.getUserId(), order.getOrderId(), e); + } + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopRechargeOrderServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopRechargeOrderServiceImpl.java new file mode 100644 index 0000000..ee0d9c3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopRechargeOrderServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopRechargeOrderMapper; +import com.gxwebsoft.shop.service.ShopRechargeOrderService; +import com.gxwebsoft.shop.entity.ShopRechargeOrder; +import com.gxwebsoft.shop.param.ShopRechargeOrderParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 会员充值订单表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:12 + */ +@Service +public class ShopRechargeOrderServiceImpl extends ServiceImpl implements ShopRechargeOrderService { + + @Override + public PageResult pageRel(ShopRechargeOrderParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopRechargeOrderParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopRechargeOrder getByIdRel(Integer orderId) { + ShopRechargeOrderParam param = new ShopRechargeOrderParam(); + param.setOrderId(orderId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSpecServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSpecServiceImpl.java new file mode 100644 index 0000000..708f1c9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSpecServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopSpecMapper; +import com.gxwebsoft.shop.service.ShopSpecService; +import com.gxwebsoft.shop.entity.ShopSpec; +import com.gxwebsoft.shop.param.ShopSpecParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 规格Service实现 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Service +public class ShopSpecServiceImpl extends ServiceImpl implements ShopSpecService { + + @Override + public PageResult pageRel(ShopSpecParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopSpecParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopSpec getByIdRel(Integer specId) { + ShopSpecParam param = new ShopSpecParam(); + param.setSpecId(specId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSpecValueServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSpecValueServiceImpl.java new file mode 100644 index 0000000..9e39e23 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSpecValueServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopSpecValueMapper; +import com.gxwebsoft.shop.service.ShopSpecValueService; +import com.gxwebsoft.shop.entity.ShopSpecValue; +import com.gxwebsoft.shop.param.ShopSpecValueParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 规格值Service实现 + * + * @author 科技小王子 + * @since 2025-05-01 09:44:00 + */ +@Service +public class ShopSpecValueServiceImpl extends ServiceImpl implements ShopSpecValueService { + + @Override + public PageResult pageRel(ShopSpecValueParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopSpecValueParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopSpecValue getByIdRel(Integer specValueId) { + ShopSpecValueParam param = new ShopSpecValueParam(); + param.setSpecValueId(specValueId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSplashServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSplashServiceImpl.java new file mode 100644 index 0000000..b6d3f8d --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopSplashServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopSplashMapper; +import com.gxwebsoft.shop.service.ShopSplashService; +import com.gxwebsoft.shop.entity.ShopSplash; +import com.gxwebsoft.shop.param.ShopSplashParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 开屏广告Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Service +public class ShopSplashServiceImpl extends ServiceImpl implements ShopSplashService { + + @Override + public PageResult pageRel(ShopSplashParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopSplashParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopSplash getByIdRel(Integer id) { + ShopSplashParam param = new ShopSplashParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserAddressServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserAddressServiceImpl.java new file mode 100644 index 0000000..cf599c6 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserAddressServiceImpl.java @@ -0,0 +1,68 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopUserAddressMapper; +import com.gxwebsoft.shop.service.ShopUserAddressService; +import com.gxwebsoft.shop.entity.ShopUserAddress; +import com.gxwebsoft.shop.param.ShopUserAddressParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 收货地址Service实现 + * + * @author 科技小王子 + * @since 2025-07-22 23:06:40 + */ +@Service +public class ShopUserAddressServiceImpl extends ServiceImpl implements ShopUserAddressService { + + @Override + public PageResult pageRel(ShopUserAddressParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopUserAddressParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopUserAddress getByIdRel(Integer id) { + ShopUserAddressParam param = new ShopUserAddressParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopUserAddress getDefaultAddress(Integer userId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(ShopUserAddress::getUserId, userId) + .eq(ShopUserAddress::getIsDefault, true) + .orderByDesc(ShopUserAddress::getCreateTime) + .last("LIMIT 1"); + return getOne(wrapper); + } + + @Override + public List getUserAddresses(Integer userId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(ShopUserAddress::getUserId, userId) + .orderByDesc(ShopUserAddress::getIsDefault) + .orderByAsc(ShopUserAddress::getSortNumber) + .orderByDesc(ShopUserAddress::getCreateTime); + return list(wrapper); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserBalanceLogServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserBalanceLogServiceImpl.java new file mode 100644 index 0000000..483b7b3 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserBalanceLogServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopUserBalanceLogMapper; +import com.gxwebsoft.shop.service.ShopUserBalanceLogService; +import com.gxwebsoft.shop.entity.ShopUserBalanceLog; +import com.gxwebsoft.shop.param.ShopUserBalanceLogParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户余额变动明细表Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Service +public class ShopUserBalanceLogServiceImpl extends ServiceImpl implements ShopUserBalanceLogService { + + @Override + public PageResult pageRel(ShopUserBalanceLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopUserBalanceLogParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopUserBalanceLog getByIdRel(Integer logId) { + ShopUserBalanceLogParam param = new ShopUserBalanceLogParam(); + param.setLogId(logId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCollectionServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCollectionServiceImpl.java new file mode 100644 index 0000000..5d6dd6b --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCollectionServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopUserCollectionMapper; +import com.gxwebsoft.shop.service.ShopUserCollectionService; +import com.gxwebsoft.shop.entity.ShopUserCollection; +import com.gxwebsoft.shop.param.ShopUserCollectionParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 我的收藏Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Service +public class ShopUserCollectionServiceImpl extends ServiceImpl implements ShopUserCollectionService { + + @Override + public PageResult pageRel(ShopUserCollectionParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopUserCollectionParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopUserCollection getByIdRel(Integer id) { + ShopUserCollectionParam param = new ShopUserCollectionParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCouponServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCouponServiceImpl.java new file mode 100644 index 0000000..fb3d5ed --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserCouponServiceImpl.java @@ -0,0 +1,57 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopUserCouponMapper; +import com.gxwebsoft.shop.service.ShopUserCouponService; +import com.gxwebsoft.shop.entity.ShopUserCoupon; +import com.gxwebsoft.shop.param.ShopUserCouponParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户优惠券Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopUserCouponServiceImpl extends ServiceImpl implements ShopUserCouponService { + + @Override + public PageResult pageRel(ShopUserCouponParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopUserCouponParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopUserCoupon getByIdRel(Integer id) { + ShopUserCouponParam param = new ShopUserCouponParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + + @Override + public List userList(Integer userId) { + return list( + new LambdaQueryWrapper() + .eq(ShopUserCoupon::getUserId, userId) + ); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserRefereeServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserRefereeServiceImpl.java new file mode 100644 index 0000000..1d6dae9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserRefereeServiceImpl.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopUserRefereeMapper; +import com.gxwebsoft.shop.service.ShopUserRefereeService; +import com.gxwebsoft.shop.entity.ShopUserReferee; +import com.gxwebsoft.shop.param.ShopUserRefereeParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户推荐关系表Service实现 + * + * @author 科技小王子 + * @since 2025-08-11 23:51:41 + */ +@Service +public class ShopUserRefereeServiceImpl extends ServiceImpl implements ShopUserRefereeService { + + @Override + public PageResult pageRel(ShopUserRefereeParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopUserRefereeParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopUserReferee getByIdRel(Integer id) { + ShopUserRefereeParam param = new ShopUserRefereeParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + + @Override + public ShopUserReferee getByUserIdRel(Integer userId) { + ShopUserRefereeParam param = new ShopUserRefereeParam(); + param.setUserId(userId); + param.setLevel(1); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserServiceImpl.java new file mode 100644 index 0000000..9d7cde5 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopUser; +import com.gxwebsoft.shop.mapper.ShopUserMapper; +import com.gxwebsoft.shop.param.ShopUserParam; +import com.gxwebsoft.shop.service.ShopUserService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 用户记录表Service实现 + * + * @author 科技小王子 + * @since 2025-10-03 13:41:09 + */ +@Service +public class ShopUserServiceImpl extends ServiceImpl implements ShopUserService { + + @Override + public PageResult pageRel(ShopUserParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopUserParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopUser getByIdRel(Integer userId) { + ShopUserParam param = new ShopUserParam(); + param.setUserId(userId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopWebsiteServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopWebsiteServiceImpl.java new file mode 100644 index 0000000..49cfeb9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopWebsiteServiceImpl.java @@ -0,0 +1,83 @@ +package com.gxwebsoft.shop.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.gxwebsoft.cms.service.CmsWebsiteService; +import com.gxwebsoft.common.core.utils.JSONUtil; +import com.gxwebsoft.common.core.utils.RedisUtil; +import com.gxwebsoft.shop.service.ShopWebsiteService; +import com.gxwebsoft.shop.vo.ShopVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +/** + * 商城网站服务实现类 + * + * @author 科技小王子 + * @since 2025-08-13 + */ +@Slf4j +@Service +public class ShopWebsiteServiceImpl implements ShopWebsiteService { + + @Autowired + private CmsWebsiteService cmsWebsiteService; + + @Autowired + private RedisUtil redisUtil; + + /** + * 商城信息缓存键前缀 + */ + private static final String SHOP_INFO_KEY_PREFIX = "ShopInfo:"; + + @Override + public ShopVo getShopInfo(Integer tenantId) { + // 参数验证 + if (ObjectUtil.isEmpty(tenantId)) { + throw new IllegalArgumentException("租户ID不能为空"); + } + + // 商城专用缓存键 + String cacheKey = SHOP_INFO_KEY_PREFIX + tenantId; + String shopInfo = redisUtil.get(cacheKey); + if (StrUtil.isNotBlank(shopInfo)) { + log.info("从缓存获取商城信息,租户ID: {}", tenantId); +// try { +// return JSONUtil.parseObject(shopInfo, ShopVo.class); +// } catch (Exception e) { +// log.warn("商城缓存解析失败,从数据库重新获取: {}", e.getMessage()); +// } + } + + // 直接调用 CMS 服务获取站点信息,然后使用商城专用缓存 + ShopVo shopVO = cmsWebsiteService.getSiteInfo(tenantId); + if (shopVO == null) { + throw new RuntimeException("请先创建商城"); + } + + // 缓存结果(商城信息缓存时间设置为1小时) + try { + redisUtil.set(cacheKey, shopVO, 1L, TimeUnit.HOURS); + } catch (Exception e) { + log.warn("缓存商城信息失败: {}", e.getMessage()); + } + + log.info("获取商城信息成功,租户ID: {}", tenantId); + return shopVO; + } + + @Override + public void clearShopInfoCache(Integer tenantId) { + if (tenantId != null) { + String cacheKey = SHOP_INFO_KEY_PREFIX + tenantId; + redisUtil.delete(cacheKey); + log.info("清除商城信息缓存成功,租户ID: {}", tenantId); + } + } + + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopWechatDepositServiceImpl.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopWechatDepositServiceImpl.java new file mode 100644 index 0000000..9bf85d2 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/service/impl/ShopWechatDepositServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopWechatDepositMapper; +import com.gxwebsoft.shop.service.ShopWechatDepositService; +import com.gxwebsoft.shop.entity.ShopWechatDeposit; +import com.gxwebsoft.shop.param.ShopWechatDepositParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 押金Service实现 + * + * @author 科技小王子 + * @since 2025-01-11 10:45:13 + */ +@Service +public class ShopWechatDepositServiceImpl extends ServiceImpl implements ShopWechatDepositService { + + @Override + public PageResult pageRel(ShopWechatDepositParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopWechatDepositParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopWechatDeposit getByIdRel(Integer id) { + ShopWechatDepositParam param = new ShopWechatDepositParam(); + param.setId(id); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/task/CouponExpireTask.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/task/CouponExpireTask.java new file mode 100644 index 0000000..9781bd9 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/task/CouponExpireTask.java @@ -0,0 +1,86 @@ +package com.gxwebsoft.shop.task; + +import com.gxwebsoft.shop.service.CouponStatusService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * 优惠券过期处理定时任务 + * + * @author WebSoft + * @since 2025-01-15 + */ +@Slf4j +@Component +public class CouponExpireTask { + + @Autowired + private CouponStatusService couponStatusService; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + /** + * 每天凌晨2点执行过期优惠券处理 + * 生产环境:每天凌晨2点执行 + * 开发环境:每10分钟执行一次(用于测试) + */ + @Scheduled(cron = "${coupon.expire.cron:0 0 2 * * ?}") + public void processExpiredCoupons() { + log.info("开始执行过期优惠券处理任务..."); + + try { + long startTime = System.currentTimeMillis(); + + // 批量更新过期优惠券状态 + int updatedCount = couponStatusService.updateExpiredCoupons(); + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + log.info("过期优惠券处理任务完成,更新数量: {},耗时: {}ms", updatedCount, duration); + + // 如果是开发环境,输出更详细的日志 + if ("dev".equals(activeProfile)) { + log.debug("开发环境 - 过期优惠券处理详情: 更新{}张优惠券", updatedCount); + } + + } catch (Exception e) { + log.error("过期优惠券处理任务执行失败", e); + } + } + + /** + * 每小时执行一次优惠券状态检查(可选) + * 用于及时发现和处理刚过期的优惠券 + */ + @Scheduled(cron = "0 0 * * * ?") + public void hourlyExpiredCouponsCheck() { + // 只在生产环境执行 + if (!"prod".equals(activeProfile)) { + return; + } + + log.debug("执行每小时优惠券状态检查..."); + + try { + int updatedCount = couponStatusService.updateExpiredCoupons(); + if (updatedCount > 0) { + log.info("每小时检查发现并更新了 {} 张过期优惠券", updatedCount); + } + } catch (Exception e) { + log.error("每小时优惠券状态检查失败", e); + } + } + + /** + * 手动触发过期优惠券处理(用于测试) + */ + public void manualProcessExpiredCoupons() { + log.info("手动触发过期优惠券处理任务..."); + processExpiredCoupons(); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/task/OrderAutoCancelTask.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/task/OrderAutoCancelTask.java new file mode 100644 index 0000000..d1b71ff --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/task/OrderAutoCancelTask.java @@ -0,0 +1,196 @@ +package com.gxwebsoft.shop.task; + +import com.gxwebsoft.common.core.annotation.IgnoreTenant; +import com.gxwebsoft.shop.config.OrderConfigProperties; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.service.OrderCancelService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 订单自动取消定时任务 + * + * @author WebSoft + * @since 2025-01-26 + */ +@Slf4j +@Component +@ConditionalOnProperty(prefix = "shop.order.auto-cancel", name = "enabled", havingValue = "true", matchIfMissing = true) +public class OrderAutoCancelTask { + + @Autowired + private OrderCancelService orderCancelService; + + @Autowired + private OrderConfigProperties orderConfig; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + /** + * 自动取消超时订单 + * 生产环境:每5分钟执行一次 + * 开发环境:每1分钟执行一次(便于测试) + */ + @Scheduled(cron = "${shop.order.auto-cancel.cron:0 */5 * * * ?}") + @IgnoreTenant("定时任务需要处理所有租户的超时订单") + public void cancelExpiredOrders() { + if (!orderConfig.getAutoCancel().isEnabled()) { + log.debug("订单自动取消功能已禁用"); + return; + } + + log.info("开始执行订单自动取消任务..."); + + try { + long startTime = System.currentTimeMillis(); + int totalCancelledCount = 0; + + // 处理默认配置的订单 + int defaultCancelledCount = processDefaultTimeoutOrders(); + totalCancelledCount += defaultCancelledCount; + + // 处理租户特殊配置的订单 + int tenantCancelledCount = processTenantSpecificOrders(); + totalCancelledCount += tenantCancelledCount; + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + log.info("订单自动取消任务完成,总取消数量: {},默认配置: {},租户配置: {},耗时: {}ms", + totalCancelledCount, defaultCancelledCount, tenantCancelledCount, duration); + + // 开发环境输出更详细的日志 + if ("dev".equals(activeProfile)) { + log.debug("开发环境 - 订单自动取消详情: 总共取消{}个订单", totalCancelledCount); + } + + } catch (Exception e) { + log.error("订单自动取消任务执行失败", e); + } + } + + /** + * 处理使用默认超时配置的订单 + */ + private int processDefaultTimeoutOrders() { + try { + Integer defaultTimeout = orderConfig.getAutoCancel().getDefaultTimeoutMinutes(); + Integer batchSize = orderConfig.getAutoCancel().getBatchSize(); + + log.debug("处理默认超时订单,超时时间: {}分钟,批量大小: {}", defaultTimeout, batchSize); + + List expiredOrders = orderCancelService.findExpiredUnpaidOrders(defaultTimeout, batchSize); + + if (expiredOrders.isEmpty()) { + log.debug("没有找到使用默认配置的超时订单"); + return 0; + } + + // 过滤掉有特殊租户配置的订单 + List ordersToCancel = filterOrdersWithoutTenantConfig(expiredOrders); + + if (ordersToCancel.isEmpty()) { + log.debug("过滤后没有需要使用默认配置取消的订单"); + return 0; + } + + int cancelledCount = orderCancelService.batchCancelOrders(ordersToCancel); + log.info("默认配置取消订单完成,找到: {}个,过滤后: {}个,成功取消: {}个", + expiredOrders.size(), ordersToCancel.size(), cancelledCount); + + return cancelledCount; + + } catch (Exception e) { + log.error("处理默认超时订单失败", e); + return 0; + } + } + + /** + * 处理租户特殊配置的订单 + */ + private int processTenantSpecificOrders() { + try { + List tenantConfigs = orderConfig.getAutoCancel().getTenantConfigs(); + if (tenantConfigs == null || tenantConfigs.isEmpty()) { + log.debug("没有配置租户特殊超时规则"); + return 0; + } + + int totalCancelledCount = 0; + Integer batchSize = orderConfig.getAutoCancel().getBatchSize(); + + for (OrderConfigProperties.TenantCancelConfig tenantConfig : tenantConfigs) { + if (!tenantConfig.isEnabled()) { + log.debug("租户{}的自动取消功能已禁用", tenantConfig.getTenantId()); + continue; + } + + log.debug("处理租户{}的超时订单,超时时间: {}分钟", + tenantConfig.getTenantId(), tenantConfig.getTimeoutMinutes()); + + List tenantExpiredOrders = orderCancelService.findExpiredUnpaidOrdersByTenant( + tenantConfig.getTenantId(), tenantConfig.getTimeoutMinutes(), batchSize); + + if (!tenantExpiredOrders.isEmpty()) { + int cancelledCount = orderCancelService.batchCancelOrders(tenantExpiredOrders); + totalCancelledCount += cancelledCount; + + log.info("租户{}取消订单完成,找到: {}个,成功取消: {}个", + tenantConfig.getTenantId(), tenantExpiredOrders.size(), cancelledCount); + } + } + + return totalCancelledCount; + + } catch (Exception e) { + log.error("处理租户特殊配置订单失败", e); + return 0; + } + } + + /** + * 过滤掉有租户特殊配置的订单 + */ + private List filterOrdersWithoutTenantConfig(List orders) { + List tenantConfigs = orderConfig.getAutoCancel().getTenantConfigs(); + if (tenantConfigs == null || tenantConfigs.isEmpty()) { + return orders; + } + + return orders.stream() + .filter(order -> { + // 检查该订单的租户是否有特殊配置 + return tenantConfigs.stream() + .noneMatch(config -> config.isEnabled() && config.getTenantId().equals(order.getTenantId())); + }) + .collect(java.util.stream.Collectors.toList()); + } + + /** + * 手动触发订单自动取消任务(用于测试) + */ + @IgnoreTenant("手动触发的定时任务需要处理所有租户的超时订单") + public void manualCancelExpiredOrders() { + log.info("手动触发订单自动取消任务..."); + cancelExpiredOrders(); + } + + /** + * 获取任务状态信息 + */ + public String getTaskStatus() { + return String.format("订单自动取消任务状态 - 启用: %s, 默认超时: %d分钟, 检查间隔: %d分钟, 批量大小: %d", + orderConfig.getAutoCancel().isEnabled(), + orderConfig.getAutoCancel().getDefaultTimeoutMinutes(), + orderConfig.getAutoCancel().getCheckIntervalMinutes(), + orderConfig.getAutoCancel().getBatchSize()); + } +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/task/RefundStatusQueryTask.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/task/RefundStatusQueryTask.java new file mode 100644 index 0000000..ecce124 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/task/RefundStatusQueryTask.java @@ -0,0 +1,133 @@ +package com.gxwebsoft.shop.task; + +import com.gxwebsoft.common.core.annotation.IgnoreTenant; +import com.gxwebsoft.payment.dto.PaymentResponse; +import com.gxwebsoft.payment.enums.PaymentType; +import com.gxwebsoft.payment.exception.PaymentException; +import com.gxwebsoft.payment.service.PaymentService; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.service.ShopOrderService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 退款状态查询定时任务 + * 定期查询处理中的退款订单状态,并更新订单状态 + * + * @author WebSoft + * @since 2025-01-26 + */ +@Slf4j +@Component +@ConditionalOnProperty(prefix = "shop.order.refund-query", name = "enabled", havingValue = "true", matchIfMissing = true) +public class RefundStatusQueryTask { + + @Autowired + private ShopOrderService shopOrderService; + + @Autowired + private PaymentService paymentService; + + /** + * 查询退款状态并更新订单 + * 生产环境:每10分钟执行一次 + * 开发环境:每2分钟执行一次(便于测试) + */ + @Scheduled(cron = "${shop.order.refund-query.cron:0 0/10 * * * ?}") + @IgnoreTenant("定时任务需要处理所有租户的退款订单") + public void queryRefundStatusAndUpdateOrders() { + log.info("开始执行退款状态查询任务..."); + + try { + long startTime = System.currentTimeMillis(); + int totalProcessedCount = 0; + + // 查询所有退款处理中的订单(状态为5) + List refundProcessingOrders = shopOrderService.lambdaQuery() + .eq(ShopOrder::getOrderStatus, 5) + .isNotNull(ShopOrder::getRefundOrder) + .list(); + + if (refundProcessingOrders.isEmpty()) { + log.info("没有找到退款处理中的订单"); + return; + } + + log.info("找到 {} 个退款处理中的订单,开始查询退款状态...", refundProcessingOrders.size()); + + int successCount = 0; + int failedCount = 0; + + for (ShopOrder order : refundProcessingOrders) { + try { + // 查询退款状态 + PaymentResponse response = paymentService.queryRefund( + order.getRefundOrder(), // 退款单号 + PaymentType.WECHAT_NATIVE, // 支付类型(这里假设是微信支付) + order.getTenantId() // 租户ID + ); + + if (response != null) { + // 根据退款状态更新订单 + if (response.getSuccess()) { + // 退款成功 + order.setOrderStatus(6); // 退款成功 + shopOrderService.updateById(order); + log.info("订单 {} 退款成功,更新订单状态为退款成功", order.getOrderNo()); + successCount++; + } else if (response.getPaymentStatus() != null) { + // 根据具体的退款状态处理 + switch (response.getPaymentStatus()) { + case REFUND_FAILED: + // 退款失败 + order.setOrderStatus(5); // 退款被拒绝(保持原状态或根据业务需要调整) + shopOrderService.updateById(order); + log.info("订单 {} 退款失败,更新订单状态", order.getOrderNo()); + failedCount++; + break; + case REFUNDING: + // 仍在退款中,无需处理 + log.debug("订单 {} 仍在退款中", order.getOrderNo()); + break; + default: + log.warn("订单 {} 未知的退款状态: {}", order.getOrderNo(), response.getPaymentStatus()); + break; + } + } + } else { + log.warn("订单 {} 退款状态查询返回空结果", order.getOrderNo()); + } + } catch (PaymentException e) { + log.error("查询订单 {} 退款状态时发生支付异常: {}", order.getOrderNo(), e.getMessage(), e); + failedCount++; + } catch (Exception e) { + log.error("查询订单 {} 退款状态时发生系统异常: {}", order.getOrderNo(), e.getMessage(), e); + failedCount++; + } + } + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + log.info("退款状态查询任务完成,总处理数量: {},成功: {},失败: {},耗时: {}ms", + refundProcessingOrders.size(), successCount, failedCount, duration); + + } catch (Exception e) { + log.error("退款状态查询任务执行失败", e); + } + } + + /** + * 手动触发退款状态查询任务(用于测试) + */ + @IgnoreTenant("手动触发的定时任务需要处理所有租户的退款订单") + public void manualQueryRefundStatus() { + log.info("手动触发退款状态查询任务..."); + queryRefundStatusAndUpdateOrders(); + } +} \ No newline at end of file diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/vo/MenuVo.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/vo/MenuVo.java new file mode 100644 index 0000000..5e13bde --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/vo/MenuVo.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.shop.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 导航信息视图对象 + * 专门用于前端展示,只包含前端需要的字段 + * + * @author WebSoft + * @since 2025-01-12 + */ +@Data +@Schema(description = "导航信息视图对象") +public class MenuVo implements Serializable { + + @Schema(description = "导航ID") + private Integer navigationId; + + @Schema(description = "导航名称") + private String title; + + @Schema(description = "导航类型") + private String model; + + @Schema(description = "唯一标识") + private String code; + + @Schema(description = "路由地址") + private String path; + + @Schema(description = "导航图标") + private String icon; + + @Schema(description = "导航颜色") + private String color; + + @Schema(description = "父级ID") + private Integer parentId; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "是否隐藏 0显示 1隐藏") + private Integer hide; + + @Schema(description = "位置 0顶部 1底部") + private Integer top; + + @Schema(description = "打开方式 0当前窗口 1新窗口") + private Integer target; + + @Schema(description = "子导航") + private List children; +} diff --git a/jczxw-java/src/main/java/com/gxwebsoft/shop/vo/ShopVo.java b/jczxw-java/src/main/java/com/gxwebsoft/shop/vo/ShopVo.java new file mode 100644 index 0000000..69885e7 --- /dev/null +++ b/jczxw-java/src/main/java/com/gxwebsoft/shop/vo/ShopVo.java @@ -0,0 +1,107 @@ +package com.gxwebsoft.shop.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; + +/** + * 应用信息 + * 专门用于前端展示,只包含前端需要的字段 + * + * @author WebSoft + * @since 2025-01-12 + */ +@Data +@Schema(description = "应用信息视图对象") +public class ShopVo implements Serializable { + + @Schema(description = "站点ID") + private Integer websiteId; + + @Schema(description = "站点名称") + private String websiteName; + + @Schema(description = "站点编号") + private String websiteCode; + + @Schema(description = "应用介绍") + private String description; + + @Schema(description = "网站关键词") + private String keywords; + + @Schema(description = "小程序二维码") + private String mpQrCode; + + @Schema(description = "标题") + private String title; + + @Schema(description = "LOGO") + private String logo; + + @Schema(description = "图标") + private String icon; + + @Schema(description = "域名") + private String domain; + + @Schema(description = "后台管理地址") + private String adminUrl; + + @Schema(description = "API地址") + private String apiUrl; + + @Schema(description = "运行状态 0未开通 1正常 2维护中 3违规关停") + private Integer running; + + @Schema(description = "应用版本 10免费版 20授权版 30永久授权") + private Integer version; + + @Schema(description = "服务到期时间") + private String expirationTime; + + @Schema(description = "创建时间") + private String createTime; + + @Schema(description = "是否到期 -1已过期 1未过期") + private Integer expired; + + @Schema(description = "剩余天数") + private Long expiredDays; + + @Schema(description = "即将过期 0否 1是") + private Integer soon; + + @Schema(description = "状态图标") + private String statusIcon; + + @Schema(description = "状态文本") + private String statusText; + + @Schema(description = "网站配置") + private Object config; + + @Schema(description = "服务器时间信息") + private HashMap serverTime; + + @Schema(description = "顶部导航") + private List topNavs; + + @Schema(description = "底部导航") + private List bottomNavs; + + @Schema(description = "网站设置") + private Object setting; + + @Schema(description = "应用ID") + private Integer appId; + + @Schema(description = "应用名称") + private String appName; + + @Schema(description = "应用编号") + private String appCode; +} diff --git a/jczxw-java/src/main/java/lib/commons-codec-1.9.jar b/jczxw-java/src/main/java/lib/commons-codec-1.9.jar new file mode 100644 index 0000000..ef35f1c Binary files /dev/null and b/jczxw-java/src/main/java/lib/commons-codec-1.9.jar differ diff --git a/jczxw-java/src/main/java/lib/json-20200518.jar b/jczxw-java/src/main/java/lib/json-20200518.jar new file mode 100644 index 0000000..0b85b0e Binary files /dev/null and b/jczxw-java/src/main/java/lib/json-20200518.jar differ diff --git a/jczxw-java/src/main/resources/application-dev.yml b/jczxw-java/src/main/resources/application-dev.yml new file mode 100644 index 0000000..3f50f78 --- /dev/null +++ b/jczxw-java/src/main/resources/application-dev.yml @@ -0,0 +1,99 @@ +# 开发环境配置 + +# 服务器配置 +server: + port: 9200 + +# 数据源配置 +spring: + datasource: + url: jdbc:mysql://47.119.165.234:13308/db_websopy?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 + username: db_websopy + password: y8HT6pZTSsxZrM8s + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + + # redis + redis: + database: 0 + host: 47.119.165.234 + port: 16379 + password: redis_WSDb88 + + # RabbitMQ 配置 + rabbitmq: + host: 47.119.165.234 + port: 15672 + username: rabbitmq + password: rabbitmq + virtual-host: / + +# 日志配置 +logging: + level: + com.gxwebsoft: DEBUG + com.baomidou.mybatisplus: DEBUG + +socketio: + host: localhost #IP地址 + +# MQTT配置 +mqtt: + enabled: false # 添加开关来禁用MQTT服务 + host: tcp://132.232.214.96:1883 + username: swdev + password: Sw20250523 + client-id-prefix: hjm_car_ + topic: /SW_GPS/# + qos: 2 + connection-timeout: 10 + keep-alive-interval: 20 + auto-reconnect: true + +# 框架配置 +config: + # 开发环境接口 + server-url: https://server.websoft.top/api + upload-path: /Users/gxwebsoft/Documents/uploads/ # window(D:\Temp) + +# 开发环境证书配置 +certificate: + load-mode: CLASSPATH # 开发环境从classpath加载 + wechat-pay: + dev: + private-key-file: "apiclient_key.pem" + apiclient-cert-file: "apiclient_cert.pem" + wechatpay-cert-file: "wechatpay_cert.pem" + +# 应用模块微信支付配置(开发环境)- 商户号 1557418831 +app: + pay: + wx: + enabled: true + # 回调地址 + notify-url: "https://websopy-api.websoft.top/api/app/subscription/wx-notify" + # 商户号 - websopy 平台 + mch-id: "1557418831" + # 商户证书序列号 + merchant-serial-number: "372B29641147684184C840587F38053033F4A5A8" + # APIv3 密钥 + api-v3-key: "zGufUcqa7ovgxRL0kF5OlPr482EZwtn8" + # 微信支付公钥ID(使用公钥模式) + wechatpay-public-key-id: "PUB_KEY_ID_0115574188312026041800292312002000" + # 微信 AppId - 网站应用 + app-id: "wx532fccea54b27411" + # 证书根目录(项目 resources) + cert-root-path: "/Users/gxwebsoft/JAVA/websopy-java/src/main/resources" + # 商户私钥文件相对路径 + private-key-relative-path: "wechat/websopy/apiclient_key.pem" + # 微信平台证书相对路径 + wechatpay-cert-relative-path: "wechat/websopy/pub_key.pem" + # 测试模式 + test-mode: false + +# 阿里云翻译配置 +aliyun: + translate: + access-key-id: LTAI5tEsyhW4GCKbds1qsopg + access-key-secret: zltFlQrYVAoq2KMFDWgLa3GhkMNeyO + endpoint: mt.cn-hangzhou.aliyuncs.com diff --git a/jczxw-java/src/main/resources/application-prod.yml b/jczxw-java/src/main/resources/application-prod.yml new file mode 100644 index 0000000..c384ebe --- /dev/null +++ b/jczxw-java/src/main/resources/application-prod.yml @@ -0,0 +1,130 @@ +# 生产环境配置 +server: + port: 9500 +# 数据源配置 +spring: + datasource: + url: jdbc:mysql://1Panel-mysql-Bqdt:3306/db_websopy?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + username: db_websopy + password: y8HT6pZTSsxZrM8s + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + druid: + remove-abandoned: true + + # redis + redis: + database: 0 + host: 1Panel-redis-Q1LE + port: 6379 + password: redis_WSDb88 + + # RabbitMQ 配置 + rabbitmq: + host: 1Panel-rabbitmq-kvHZ + port: 5672 + username: rabbitmq + password: rabbitmq + virtual-host: / + +# 日志配置 +logging: + file: + name: websoft-modules.log + level: + root: WARN + com.gxwebsoft: ERROR + com.baomidou.mybatisplus: ERROR + +socketio: + host: 0.0.0.0 #IP地址 + +# MQTT配置 +mqtt: + enabled: false # 启用MQTT服务 + host: tcp://132.232.214.96:1883 + username: swdev + password: Sw20250523 + client-id-prefix: hjm_car_ + topic: /SW_GPS/# + qos: 2 + connection-timeout: 10 + keep-alive-interval: 20 + auto-reconnect: true + +# 框架配置 +config: + # 文件服务器 + file-server: https://file-s209.shoplnk.cn + # 生产环境接口 + server-url: https://server.websoft.top/api + upload-path: /www/wwwroot/file.ws + + # 阿里云OSS云存储 + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP + accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM + bucketName: oss-gxwebsoft + bucketDomain: https://oss.wsdns.cn + aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com + +# 应用模块微信支付配置(生产环境) +app: + pay: + wx: + enabled: true + # 回调地址 + notify-url: "https://websopy-api.websoft.top/api/app/subscription/wx-notify" + # 商户号 - websopy 平台 + mch-id: "1557418831" + # 商户证书序列号 + merchant-serial-number: "372B29641147684184C840587F38053033F4A5A8" + # APIv3 密钥 + api-v3-key: "zGufUcqa7ovgxRL0kF5OlPr482EZwtn8" + # 微信支付公钥ID(使用公钥模式) + wechatpay-public-key-id: "PUB_KEY_ID_0115574188312026041800292312002000" + # 微信 AppId - 网站应用 + app-id: "wx532fccea54b27411" + # 证书根目录(项目 resources) + cert-root-path: "/www/wwwroot/file.ws" + # 商户私钥文件相对路径 + private-key-relative-path: "wechat/websopy/apiclient_key.pem" + # 微信平台证书相对路径 + wechatpay-cert-relative-path: "wechat/websopy/pub_key.pem" + # 测试模式 + test-mode: false + +certificate: + load-mode: VOLUME # 生产环境从Docker挂载卷加载 + cert-root-path: /www/wwwroot/file.ws + +# 支付配置缓存 +payment: + cache: + # 支付配置缓存键前缀,生产环境使用 Payment:1* 格式 + key-prefix: "Payment:1" + # 缓存过期时间(小时) + expire-hours: 24 +# 阿里云翻译配置 +aliyun: + translate: + access-key-id: LTAI5tEsyhW4GCKbds1qsopg + access-key-secret: zltFlQrYVAoq2KMFDWgLa3GhkMNeyO + endpoint: mt.cn-hangzhou.aliyuncs.com +# MQ同步配置 +sync: + # 是否启用MQ消费者(设为false则不监听MQ消息) + mq: + enabled: true + # 本租户ID,用于验证同步消息是否属于本租户(0表示不禁用租户验证) + tenant-id: 5 + +# ==================== 阿里云实人认证配置(生产环境)==================== +cloudauth: + # 阿里云 AccessKey + accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP + accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM + # 地域ID + regionId: cn-shenzhen + # 接入点(使用通用接入点) + endpoint: cloudauth.aliyuncs.com diff --git a/jczxw-java/src/main/resources/application-test.yml b/jczxw-java/src/main/resources/application-test.yml new file mode 100644 index 0000000..5c5a2b9 --- /dev/null +++ b/jczxw-java/src/main/resources/application-test.yml @@ -0,0 +1,77 @@ +# 生产环境配置 + +# 服务器配置 +server: + port: 9300 + +# 数据源配置 +spring: + datasource: + url: jdbc:mysql://1Panel-mysql-Bqdt:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + username: modules + password: P7KsAyDXG8YdLnkA + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + druid: + remove-abandoned: true + + # redis + redis: + database: 0 + host: 1Panel-redis-Q1LE + port: 6379 + password: redis_WSDb88 + +# 日志配置 +logging: + file: + name: websoft-modules.log + level: + root: WARN + com.gxwebsoft: ERROR + com.baomidou.mybatisplus: ERROR + +socketio: + host: 0.0.0.0 #IP地址 + +# MQTT配置 +mqtt: + enabled: false # 启用MQTT服务 + host: tcp://132.232.214.96:1883 + username: swdev + password: Sw20250523 + client-id-prefix: hjm_car_ + topic: /SW_GPS/# + qos: 2 + connection-timeout: 10 + keep-alive-interval: 20 + auto-reconnect: true + +# 框架配置 +config: + # 文件服务器 + file-server: https://file-s209.shoplnk.cn + # 生产环境接口 + server-url: https://server.websoft.top/api + upload-path: /www/wwwroot/file.ws + + # 阿里云OSS云存储 + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP + accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM + bucketName: oss-gxwebsoft + bucketDomain: https://oss.wsdns.cn + aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com + +# 生产环境证书配置 +certificate: + load-mode: VOLUME # 生产环境从Docker挂载卷加载 + cert-root-path: /www/wwwroot/file.ws + +# 支付配置缓存 +payment: + cache: + # 支付配置缓存键前缀,生产环境使用 Payment:1* 格式 + key-prefix: "Payment:1" + # 缓存过期时间(小时) + expire-hours: 24 diff --git a/jczxw-java/src/main/resources/application-websopy.yml b/jczxw-java/src/main/resources/application-websopy.yml new file mode 100644 index 0000000..51faad6 --- /dev/null +++ b/jczxw-java/src/main/resources/application-websopy.yml @@ -0,0 +1,85 @@ +# 生产环境配置 + +# 服务器配置 +server: + port: 9500 + +# 数据源配置 +spring: + datasource: + url: jdbc:mysql://47.119.165.234:13308/db_websopy?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + username: db_websopy + password: y8HT6pZTSsxZrM8s + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + druid: + remove-abandoned: true + + # redis + redis: + database: 0 + host: 47.119.165.234 + port: 16379 + password: redis_WSDb88 + + # RabbitMQ 配置 + rabbitmq: + host: 1Panel-rabbitmq-kvHZ + port: 5672 + username: rabbitmq + password: rabbitmq + virtual-host: / + +# 日志配置 +logging: + file: + name: websoft-modules.log + level: + root: WARN + com.gxwebsoft: ERROR + com.baomidou.mybatisplus: ERROR + +socketio: + host: 0.0.0.0 #IP地址 + +# MQTT配置 +mqtt: + enabled: false # 启用MQTT服务 + host: tcp://132.232.214.96:1883 + username: swdev + password: Sw20250523 + client-id-prefix: hjm_car_ + topic: /SW_GPS/# + qos: 2 + connection-timeout: 10 + keep-alive-interval: 20 + auto-reconnect: true + +# 框架配置 +config: + # 文件服务器 + file-server: https://file-s209.shoplnk.cn + # 生产环境接口 + server-url: https://server.websoft.top/api + upload-path: /www/wwwroot/file.ws + + # 阿里云OSS云存储 + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP + accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM + bucketName: oss-gxwebsoft + bucketDomain: https://oss.wsdns.cn + aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com + +# 生产环境证书配置 +certificate: + load-mode: VOLUME # 生产环境从Docker挂载卷加载 + cert-root-path: /www/wwwroot/file.ws + +# 支付配置缓存 +payment: + cache: + # 支付配置缓存键前缀,生产环境使用 Payment:1* 格式 + key-prefix: "Payment:1" + # 缓存过期时间(小时) + expire-hours: 24 diff --git a/jczxw-java/src/main/resources/application.yml b/jczxw-java/src/main/resources/application.yml new file mode 100644 index 0000000..d873577 --- /dev/null +++ b/jczxw-java/src/main/resources/application.yml @@ -0,0 +1,265 @@ +# 端口 +server: + port: 9500 +# 多环境配置 +spring: + profiles: + active: dev + + application: + name: server + + # 允许循环引用(临时解决方案) + main: + allow-circular-references: true + + # 修复 Springfox 与 Spring Boot 2.6+ 兼容性问题 + mvc: + pathmatch: + matching-strategy: ant_path_matcher + + # json时间格式设置 + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + write-dates-as-timestamps: false + deserialization: + fail-on-unknown-properties: false + # 确保启用Java 8时间支持 + modules: + - com.fasterxml.jackson.datatype.jsr310.JavaTimeModule + + # 连接池配置 + datasource: + druid: + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 30000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + test-while-idle: true + test-on-borrow: true + test-on-return: false + remove-abandoned: true + remove-abandoned-timeout: 1800 + #pool-prepared-statements: false + #max-pool-prepared-statement-per-connection-size: 20 + filters: stat, wall + validation-query: SELECT 'x' + aop-patterns: com.gxwebsoft.*.*.service.* + stat-view-servlet: + url-pattern: /druid/* + reset-enable: true + login-username: admin + login-password: admin + + # 设置上传文件大小 + servlet: + multipart: + max-file-size: 100MB + max-request-size: 100MB + + # 邮件服务器配置 + mail: + host: smtp.qq.com + username: 170083662@qq.com + password: mnfokualhfaucaie + default-encoding: UTF-8 + properties: + mail: + smtp: + auth: true + socketFactory: + class: javax.net.ssl.SSLSocketFactory + port: 465 + +# Mybatis-plus配置 +mybatis-plus: + mapper-locations: classpath*:com/gxwebsoft/**/*Mapper.xml + configuration: + map-underscore-to-camel-case: true + cache-enabled: true + global-config: + :banner: false + db-config: + id-type: auto + logic-delete-value: 1 + logic-not-delete-value: 0 + +# 框架配置 +config: + open-office-home: C:/OpenOffice4/ + swagger-base-package: com.gxwebsoft + swagger-title: 网宿软件 API文档 + swagger-description: websoft - 基于java spring、vue3、antd构建的前后端分离快速开发框架 + swagger-version: 2.0 + token-key: WLgNsWJ8rPjRtnjzX/Gx2RGS80Kwnm/ZeLbvIL+NrBs= + # 主服务器 + server-url: https://server.websoft.top/api + # 文件服务器 + file-server: https://file.websoft.top + # 其他 + api-url: https://server.websoft.top/api + upload-path: /Users/gxwebsoft/Documents/uploads + local-upload-path: /Users/gxwebsoft/Documents/uploads + + # 阿里云OSS云存储 + endpoint: https://oss-cn-shenzhen.aliyuncs.com + accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP + accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM + bucketName: oss-gxwebsoft + bucketDomain: https://oss.wsdns.cn + aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com + +# 商城订单配置 +shop: + order: + # 测试账号配置 + test-account: + enabled: true # 禁用测试账号功能 + phone-numbers: + - "19163679581" # 改为其他测试手机号 + test-pay-amount: 0.01 + + # 租户特殊规则配置 + # tenant-rules: + # - tenant-id: 10324 + # tenant-name: "百色中学" + # min-amount: 10 + # min-amount-message: "捐款金额最低不能少于10元,感谢您的爱心捐赠^_^" + # enabled: true + + # 默认配置 + default-config: + default-title: "订单名称" + default-comments: "暂无" + min-order-amount: 0 + order-timeout-minutes: 30 + + # 订单自动取消配置 + auto-cancel: + # 是否启用自动取消功能 + enabled: true + # 默认超时时间(分钟) + default-timeout-minutes: 30 + # 定时任务检查间隔(分钟) + check-interval-minutes: 1 + # 批量处理大小 + batch-size: 100 + # 定时任务执行时间(cron表达式) + # 生产环境:每5分钟执行一次 + cron: "0 */5 * * * ?" + + # 租户特殊配置 + # tenant-configs: + # - tenant-id: 10324 + # tenant-name: "百色中学" + # timeout-minutes: 120 # 捐款订单给更长的支付时间 + # enabled: true + # 可以添加更多租户配置 + # - tenant-id: 10550 + # tenant-name: "其他租户" + # timeout-minutes: 15 + # enabled: true + +# 证书配置 +certificate: + # 证书加载模式: CLASSPATH, FILESYSTEM, VOLUME + load-mode: CLASSPATH + # Docker挂载卷证书路径 + cert-root-path: /app/certs + # 开发环境证书路径前缀 + dev-cert-path: dev + + # 微信支付证书配置 + wechat-pay: + dev: + api-v3-key: "0kF5OlPr482EZwtn9zGufUcqa7ovgxRL" + private-key-file: "apiclient_key.pem" + apiclient-cert-file: "apiclient_cert.pem" + wechatpay-cert-file: "wechatpay_cert.pem" + prod-base-path: "/file" + cert-dir: "wechat" + + # 支付宝证书配置 + alipay: + cert-dir: "alipay" + app-private-key-file: "app_private_key.pem" + app-cert-public-key-file: "appCertPublicKey.crt" + alipay-cert-public-key-file: "alipayCertPublicKey.crt" + alipay-root-cert-file: "alipayRootCert.crt" + +# 启用 SpringDoc OpenAPI +springdoc: + api-docs: + enabled: true + swagger-ui: + enabled: true + +# LED - 排班接口(业务中台)对接配置 +led: + bme: + base-url: ${LED_BME_BASE_URL:http://16.1.4.201:7979} + appid: ${LED_BME_APPID:BQ73n58Lf} + secret-key: ${LED_BME_SECRET_KEY:jk720-DCPnGq@5t8} + mechanism-id: ${LED_BME_MECHANISM_ID:10001} + default-ext-user-id: ${LED_BME_DEFAULT_EXT_USER_ID:txzhyy} + default-hospital-id: ${LED_BME_DEFAULT_HOSPITAL_ID:} + timeout-ms: ${LED_BME_TIMEOUT_MS:10000} + +# 启用 Knife4j +knife4j: + enable: true + +# 优惠券配置 +coupon: + # 过期处理定时任务配置 + expire: + # 定时任务执行时间(cron表达式) + # 生产环境:每天凌晨2点执行 + # 开发环境:每10分钟执行一次 + cron: "0 0 2 * * ?" + # 开发环境可以设置为: "0 */10 * * * ?" + + # 状态管理配置 + status: + # 是否启用自动状态更新 + auto-update: true + # 批量处理大小 + batch-size: 1000 + +# 支付配置 +payment: + # 开发环境配置 + dev: + # 开发环境回调地址(本地调试用) + notify-url: "http://frps-10550.s209.websoft.top/api/shop/shop-order/notify" + # 开发环境是否启用环境感知 + environment-aware: true + + # 生产环境配置 + prod: + # 生产环境回调地址 + notify-url: "https://cms-api.websoft.top/api/shop/shop-order/notify" + # 生产环境是否启用环境感知 + environment-aware: false + +# MQ同步配置 +sync: + # 是否启用MQ消费者(设为false则不监听MQ消息) + mq: + enabled: true + # 本租户ID,用于验证同步消息是否属于本租户(0表示不禁用租户验证) + tenant-id: ${SYNC_TENANT_ID:0} + +# ==================== 阿里云实人认证配置 ==================== +cloudauth: + # 阿里云 AccessKey(建议使用子账号密钥) + accessKeyId: ${CLOUDAUTH_ACCESS_KEY_ID:} + accessKeySecret: ${CLOUDAUTH_ACCESS_KEY_SECRET:} + # 地域ID + regionId: cn-shenzhen + # 接入点(使用通用接入点) + endpoint: cloudauth.aliyuncs.com diff --git a/jczxw-java/src/main/resources/mapper/app_resource_add_port.sql b/jczxw-java/src/main/resources/mapper/app_resource_add_port.sql new file mode 100644 index 0000000..d216cb1 --- /dev/null +++ b/jczxw-java/src/main/resources/mapper/app_resource_add_port.sql @@ -0,0 +1,7 @@ +-- app_resource 表:添加数据库连接端口字段 +-- 时间:2026-04-05 +-- 说明:database 类型资源需要存储连接端口(从关联服务器获取) +-- 注意:port 是 MySQL 保留字,需要用反引号 + +-- 直接执行(如果列已存在会报错,可忽略) +ALTER TABLE `app_resource` ADD COLUMN `port` INT DEFAULT NULL COMMENT '数据库连接端口(数据库资源用)' AFTER `host`; diff --git a/jczxw-java/src/main/resources/mapper/app_resource_ssh_upgrade.sql b/jczxw-java/src/main/resources/mapper/app_resource_ssh_upgrade.sql new file mode 100644 index 0000000..252f981 --- /dev/null +++ b/jczxw-java/src/main/resources/mapper/app_resource_ssh_upgrade.sql @@ -0,0 +1,32 @@ +-- ===================================================== +-- app_resource 表结构变更:添加 SSH 连接字段 +-- 执行时间:2026-04-04 +-- 说明:支持同时存储服务器 SSH 登录信息和 MySQL 连接信息 +-- ===================================================== + +-- 添加 SSH 相关字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `ssh_port` INT DEFAULT 22 COMMENT 'SSH端口(服务器用)' AFTER `ip`, +ADD COLUMN IF NOT EXISTS `ssh_username` VARCHAR(64) DEFAULT NULL COMMENT 'SSH用户名(服务器用)' AFTER `ssh_port`, +ADD COLUMN IF NOT EXISTS `ssh_password` VARCHAR(255) DEFAULT NULL COMMENT 'SSH密码(AES加密,服务器用)' AFTER `ssh_username`; + +-- 添加 MySQL 端口字段(独立存储 MySQL 端口) +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `mysql_port` INT DEFAULT 3306 COMMENT 'MySQL端口(服务器用)' AFTER `ssh_password`; + +-- 如果 port 字段已存在且有数据,可以将现有 port 值迁移到 mysql_port +-- UPDATE `app_resource` SET `mysql_port` = `port` WHERE `resource_type` = 'server' AND `port` IS NOT NULL; + +-- ===================================================== +-- 字段说明: +-- +-- SSH 连接信息(用于登录服务器执行 shell 命令): +-- - ssh_port: SSH 端口,默认 22 +-- - ssh_username: SSH 用户名(如 root/ubuntu/centos) +-- - ssh_password: SSH 密码(AES 加密存储) +-- +-- MySQL 连接信息(用于连接服务器上的 MySQL 数据库): +-- - mysql_port: MySQL 端口,默认 3306 +-- - admin_username: MySQL 管理员用户名(如 root) +-- - admin_password: MySQL 管理员密码(AES 加密存储) +-- ===================================================== diff --git a/jczxw-java/src/main/resources/sql/app_resource_add_admin_fields.sql b/jczxw-java/src/main/resources/sql/app_resource_add_admin_fields.sql new file mode 100644 index 0000000..b92a922 --- /dev/null +++ b/jczxw-java/src/main/resources/sql/app_resource_add_admin_fields.sql @@ -0,0 +1,28 @@ +-- app_resource 表新增字段 +-- 服务器类型新增:管理员用户名、管理员密码、SSH端口、MySQL端口、PostgreSQL端口 +-- 数据库类型新增:serverResourceId(关联服务器资源ID) + +-- 1. 服务器资源:管理员凭据字段 +ALTER TABLE app_resource + ADD COLUMN admin_username VARCHAR(100) DEFAULT NULL COMMENT '管理员用户名(服务器用,用于远程建库)' AFTER ip, + ADD COLUMN admin_password VARCHAR(500) DEFAULT NULL COMMENT '管理员密码(AES加密,服务器用,用于远程建库)' AFTER admin_username; + +-- 2. 数据库资源:关联服务器ID +ALTER TABLE app_resource + ADD COLUMN server_resource_id BIGINT DEFAULT NULL COMMENT '关联服务器资源ID(数据库用,关联到 server 类型资源)' AFTER app_id; + +-- 3. 服务器资源:MySQL 端口(如已执行旧脚本可跳过此步) +ALTER TABLE app_resource + ADD COLUMN mysql_port INT DEFAULT NULL COMMENT 'MySQL端口(服务器用,默认3306)' AFTER ssh_port; + +-- 4. 服务器资源:PostgreSQL 端口 +ALTER TABLE app_resource + ADD COLUMN pg_port INT DEFAULT NULL COMMENT 'PostgreSQL端口(服务器用,默认5432)' AFTER mysql_port; + +-- 5. 服务器资源:1Panel 面板端口 +ALTER TABLE app_resource + ADD COLUMN panel_port INT DEFAULT NULL COMMENT '1Panel面板端口(服务器用,默认8888)' AFTER pg_port; + +-- 6. 服务器资源:1Panel 面板路径前缀 +ALTER TABLE app_resource + ADD COLUMN panel_path VARCHAR(100) DEFAULT NULL COMMENT '1Panel面板路径前缀(服务器用,如 /abc123)' AFTER panel_port; diff --git a/jczxw-java/src/main/resources/sql/app_resource_add_ssl_columns.sql b/jczxw-java/src/main/resources/sql/app_resource_add_ssl_columns.sql new file mode 100644 index 0000000..28b7247 --- /dev/null +++ b/jczxw-java/src/main/resources/sql/app_resource_add_ssl_columns.sql @@ -0,0 +1,79 @@ +-- ===================================================== +-- 修复 app_resource 表缺少 SSL 证书字段的问题 +-- 兼容 MySQL 5.x / 8.x 标准语法 +-- 执行时间: 2026-04-05 +-- ===================================================== + +-- 1. 添加 private_key 字段(使用存储过程防止重复添加报错) +DROP PROCEDURE IF EXISTS add_column_if_not_exists; +DELIMITER // +CREATE PROCEDURE add_column_if_not_exists() +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'app_resource' + AND COLUMN_NAME = 'private_key' + ) THEN + ALTER TABLE app_resource ADD COLUMN private_key TEXT COMMENT '私钥(SSL用,AES加密存储)'; + END IF; + + IF NOT EXISTS ( + SELECT 1 FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'app_resource' + AND COLUMN_NAME = 'public_key' + ) THEN + ALTER TABLE app_resource ADD COLUMN public_key TEXT COMMENT '公钥(SSL用)'; + END IF; + + IF NOT EXISTS ( + SELECT 1 FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'app_resource' + AND COLUMN_NAME = 'certificate' + ) THEN + ALTER TABLE app_resource ADD COLUMN certificate TEXT COMMENT '证书内容(SSL用)'; + END IF; + + IF NOT EXISTS ( + SELECT 1 FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'app_resource' + AND COLUMN_NAME = 'cert_chain' + ) THEN + ALTER TABLE app_resource ADD COLUMN cert_chain TEXT COMMENT '证书链(SSL用,中间证书)'; + END IF; +END // +DELIMITER ; + +CALL add_column_if_not_exists(); +DROP PROCEDURE IF EXISTS add_column_if_not_exists; + +-- 2. 扩展 remark 字段为 TEXT +DROP PROCEDURE IF EXISTS alter_remark_to_text; +DELIMITER // +CREATE PROCEDURE alter_remark_to_text() +BEGIN + DECLARE col_type VARCHAR(100); + SELECT COLUMN_TYPE INTO col_type FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'app_resource' + AND COLUMN_NAME = 'remark'; + + IF col_type != 'text' THEN + ALTER TABLE app_resource MODIFY COLUMN remark TEXT COMMENT '备注'; + END IF; +END // +DELIMITER ; + +CALL alter_remark_to_text(); +DROP PROCEDURE IF EXISTS alter_remark_to_text; + +-- 3. 验证结果 +SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_COMMENT +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'app_resource' + AND COLUMN_NAME IN ('private_key', 'public_key', 'certificate', 'cert_chain', 'remark') +ORDER BY ORDINAL_POSITION; diff --git a/jczxw-java/src/main/resources/sql/app_resource_add_ssl_fields.sql b/jczxw-java/src/main/resources/sql/app_resource_add_ssl_fields.sql new file mode 100644 index 0000000..b58cf91 --- /dev/null +++ b/jczxw-java/src/main/resources/sql/app_resource_add_ssl_fields.sql @@ -0,0 +1,50 @@ +-- 为 app_resource 表添加 SSL 证书相关字段 +-- @author 科技小王子 +-- @since 2026-04-05 + +/** + * SSL 证书需要的字段: + * - private_key:私钥内容(AES加密存储) + * - public_key:公钥内容(从证书提取) + * - certificate:完整的证书文件内容(包含BEGIN/END标记) + * - cert_chain:证书链/中间证书内容 + * - algorithm:加密算法(RSA/ECC) + * - key_bits:密钥长度(2048/4096/256等) + */ + +-- 检查表结构,如果字段不存在则添加 +-- 使用 IF NOT EXISTS 防止重复执行 + +-- 1. 添加私钥字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `private_key` longtext DEFAULT NULL COMMENT '私钥内容(AES加密存储,SSL用)' +AFTER `issuer`; + +-- 2. 添加公钥字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `public_key` longtext DEFAULT NULL COMMENT '公钥内容(从证书提取,SSL用)' +AFTER `private_key`; + +-- 3. 添加证书内容字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `certificate` longtext DEFAULT NULL COMMENT '证书内容/证书文件(SSL用)' +AFTER `public_key`; + +-- 4. 添加证书链字段 +ALTER TABLE `app_resource` +ADD COLUMN IF NOT EXISTS `cert_chain` longtext DEFAULT NULL COMMENT '证书链/中间证书(SSL用)' +AFTER `certificate`; + +-- 检查更新后的表结构 +-- SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_COMMENT, IS_NULLABLE, COLUMN_KEY +-- FROM INFORMATION_SCHEMA.COLUMNS +-- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'app_resource' +-- ORDER BY ORDINAL_POSITION; + +-- 说明: +-- 1. 私钥和证书相关字段使用 longtext 类型,因为证书和密钥文件可能较大 +-- 2. private_key 字段在前端和后端都会进行 AES 加密处理,确保安全存储 +-- 3. certificate 字段存储完整的证书文件内容 +-- 4. cert_chain 字段可选存储中间证书/证书链 +-- 5. 算法和密钥长度等信息可以从证书内容中提取(如果需要) +-- 6. 所有 SSL 相关字段仅在 resource_type = 'ssl' 时使用 \ No newline at end of file diff --git a/jczxw-java/src/main/resources/sql/fix_app_resource_all_columns.sql b/jczxw-java/src/main/resources/sql/fix_app_resource_all_columns.sql new file mode 100644 index 0000000..a11a44e --- /dev/null +++ b/jczxw-java/src/main/resources/sql/fix_app_resource_all_columns.sql @@ -0,0 +1,23 @@ +-- app_resource 表修复脚本 +-- 添加所有新增的字段 +-- 使用前请确保在数据库 db_websopy 中执行 + +-- 1. 应用关联字段 +ALTER TABLE app_resource ADD COLUMN app_name VARCHAR(200) DEFAULT NULL COMMENT '关联应用名称(冗余)' AFTER app_id; + +-- 2. 服务器类型新增字段:SSH相关 +ALTER TABLE app_resource ADD COLUMN ssh_port INT DEFAULT 22 COMMENT 'SSH端口(服务器用,默认22)' AFTER ip; +ALTER TABLE app_resource ADD COLUMN ssh_username VARCHAR(100) DEFAULT NULL COMMENT 'SSH用户名(服务器用,用于远程执行命令)' AFTER ssh_port; +ALTER TABLE app_resource ADD COLUMN ssh_password VARCHAR(500) DEFAULT NULL COMMENT 'SSH密码(AES加密,服务器用,用于远程执行命令)' AFTER ssh_username; +ALTER TABLE app_resource ADD COLUMN mysql_port INT DEFAULT 3306 COMMENT 'MySQL端口(服务器用,默认3306)' AFTER ssh_password; +ALTER TABLE app_resource ADD COLUMN admin_username VARCHAR(100) DEFAULT NULL COMMENT 'MySQL管理员用户名(服务器用,用于远程建库)' AFTER mysql_port; +ALTER TABLE app_resource ADD COLUMN admin_password VARCHAR(500) DEFAULT NULL COMMENT 'MySQL管理员密码(AES加密,服务器用,用于远程建库)' AFTER admin_username; + +-- 3. 数据库类型新增字段 +ALTER TABLE app_resource ADD COLUMN server_resource_id BIGINT DEFAULT NULL COMMENT '关联服务器资源ID(数据库用,关联到 server 类型资源)' AFTER app_id; + +-- 4. 云存储类型新增字段 +ALTER TABLE app_resource ADD COLUMN credential_id BIGINT DEFAULT NULL COMMENT '云账号凭证ID(云存储用,关联app_cloud_credential)' AFTER region; + +-- 5. 域名字段补充 +ALTER TABLE app_resource ADD COLUMN ssl_bound TINYINT(1) DEFAULT 0 COMMENT '是否已绑定SSL(域名用,冗余)' AFTER icp_no; diff --git a/jczxw-java/src/main/resources/sql/fix_app_resource_app_name.sql b/jczxw-java/src/main/resources/sql/fix_app_resource_app_name.sql new file mode 100644 index 0000000..797e527 --- /dev/null +++ b/jczxw-java/src/main/resources/sql/fix_app_resource_app_name.sql @@ -0,0 +1,5 @@ +-- 修复 app_resource 表缺少 app_name 列的问题 +-- 该列用于冗余存储关联的应用名称,避免 JOIN 查询 + +ALTER TABLE app_resource + ADD COLUMN app_name VARCHAR(200) DEFAULT NULL COMMENT '关联应用名称(冗余)' AFTER app_id; diff --git a/jczxw-java/src/main/resources/wechat/10324/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/10324/apiclient_cert.p12 new file mode 100644 index 0000000..8661ab8 Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/10324/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/10324/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/10324/apiclient_cert.pem new file mode 100644 index 0000000..61839fd --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10324/apiclient_cert.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuVtyH2nr8xen7 +QTlPaZOExTNzZcCI3X+jlWwaUwBwn2ltsu/FkF/dgvPdUn4rmI/ZyD/29/nYWcT1 +xrM5Iaj8nd7HpicA98VMfei8nPQR8eJ5nARJHzjcV1xLVne5ZeWPLsYujc5D16BV +eCyxEBquR0g1IIuhUPur/o1L5Q3Maugck97Cbj5MxfgUBhR8twBrL+BG+tduFtNh +r70+rWdYrbfPQwo+aBnK4n0TKWiC2A81rUqybyr5khCzQjVUdOfeSbJP99XE4SAZ +9my3vr/kjwbMLQx/Vk9aa2jVpb03YWdJ0bYQ0GqBKo6Yt6Qtymgi310n9rlbkV6F +X5tzN0wtAgMBAAECggEABb5Iz5Tr/k3K0oMojywsNvCELGYKvLeHT+1JPWjEl/E4 +eOuvKHQEJHj+7aidDXSeMI9/Q/SRX4Y9jdc46kXomkHdJ/iaSlbfQhDXzPbit4Cf +dGAmZ/5GUkPyf2zeztXDhT8GOlxjkiqVVpt55W9hYaJph46F6w+O6vCc2QY3uScy +iPK7KHn3vQeritrnhVItRdn8ChsqvnoEZ7ZOF4GpPnd5GBma4yJXXr3DJqX5uQzC +BqCC9C3xxoJg5ay6LsolYiimgr0ylOYVhCsqnjsAxBhqHZaE+j/BW/BffGYeZzvv +8VJHQaoaIS7WdcHVgxH01MlEoQ4Cd4Ijk9wUt0XXgQKBgQDUDChXoPkNm4J02z29 +2qqKoV2z4T8rG1dHqjGAmaw3gbVD5DkvWFADBrV/CnGRZwNSWm9SP7OKTpAOU6wt +7yHb5gKyZBuf1q7v8xqB00YCrLBK5RH1LVvTSdR9KXogiI1qAJ35jG5PqipfYfCq +f+Ksyfl8XauBFiOF/IwIxtfgTQKBgQDSeczdML0jh/OlEk/SwK0s3MMgpdtZmeur +ShWPUARMo05aHqdSc6TGmdRP62peKSw8ZVD98G7MIXHGmyeJDcc6ahqS5/tbgb2z +JTyUhiHTQuBAHKAulouqOeKFIjKhnwR3B7kueROD3LI0mQosrWAYdTmpBb3v4UgC +vyxvS+gLYQKBgH3OtMTA4eL759uzFB+nM9XKRZDqzBKkRxVi2bnl8vJ/x27/Yho/ ++EDDYz17kcPl7WeX9kJDPx+I2xlU9WvPXDRedC0pDea4ddQxVQG/uuLtWC8nV48y +mS9zt1mHGUliGxzQPuoHMo+bc0ZiEmrmMzO3JYlu/ck5vFvLab3vU7dlAoGBAMJ8 +Re9FsB/66gpoZ1YpMFw6ChxK5etfrUL0DAQHPlHKvQXNOXOY5HOXhXXr5Lfpd7S/ +Mh3UY61AYi/RArFECApULQX+Umd19WJqUBY181+RdkIHsYQbHCdJoaS/uuVZWPjc +LCNjQcMg1ZKAr8Qk2J0BBSzH34CfPLk9CcQ18c9BAoGAYif+CluaBW/WtptluqNr +/waw3E7aDXg/bDiwX4ApyiO+dJ9GNa82aQhN7OiWCs/cie0mJkXEjLKXbAbaQwsz +1sM2SLZzN1iKfjCqqMAzxp4ONeuoht11tacF6KqDLQRm46E1glbBROa0qNli4Uex +BgCD0YTwT/Z2TcazY/uzBHE= +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10324/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/10324/apiclient_key.pem new file mode 100644 index 0000000..61839fd --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10324/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuVtyH2nr8xen7 +QTlPaZOExTNzZcCI3X+jlWwaUwBwn2ltsu/FkF/dgvPdUn4rmI/ZyD/29/nYWcT1 +xrM5Iaj8nd7HpicA98VMfei8nPQR8eJ5nARJHzjcV1xLVne5ZeWPLsYujc5D16BV +eCyxEBquR0g1IIuhUPur/o1L5Q3Maugck97Cbj5MxfgUBhR8twBrL+BG+tduFtNh +r70+rWdYrbfPQwo+aBnK4n0TKWiC2A81rUqybyr5khCzQjVUdOfeSbJP99XE4SAZ +9my3vr/kjwbMLQx/Vk9aa2jVpb03YWdJ0bYQ0GqBKo6Yt6Qtymgi310n9rlbkV6F +X5tzN0wtAgMBAAECggEABb5Iz5Tr/k3K0oMojywsNvCELGYKvLeHT+1JPWjEl/E4 +eOuvKHQEJHj+7aidDXSeMI9/Q/SRX4Y9jdc46kXomkHdJ/iaSlbfQhDXzPbit4Cf +dGAmZ/5GUkPyf2zeztXDhT8GOlxjkiqVVpt55W9hYaJph46F6w+O6vCc2QY3uScy +iPK7KHn3vQeritrnhVItRdn8ChsqvnoEZ7ZOF4GpPnd5GBma4yJXXr3DJqX5uQzC +BqCC9C3xxoJg5ay6LsolYiimgr0ylOYVhCsqnjsAxBhqHZaE+j/BW/BffGYeZzvv +8VJHQaoaIS7WdcHVgxH01MlEoQ4Cd4Ijk9wUt0XXgQKBgQDUDChXoPkNm4J02z29 +2qqKoV2z4T8rG1dHqjGAmaw3gbVD5DkvWFADBrV/CnGRZwNSWm9SP7OKTpAOU6wt +7yHb5gKyZBuf1q7v8xqB00YCrLBK5RH1LVvTSdR9KXogiI1qAJ35jG5PqipfYfCq +f+Ksyfl8XauBFiOF/IwIxtfgTQKBgQDSeczdML0jh/OlEk/SwK0s3MMgpdtZmeur +ShWPUARMo05aHqdSc6TGmdRP62peKSw8ZVD98G7MIXHGmyeJDcc6ahqS5/tbgb2z +JTyUhiHTQuBAHKAulouqOeKFIjKhnwR3B7kueROD3LI0mQosrWAYdTmpBb3v4UgC +vyxvS+gLYQKBgH3OtMTA4eL759uzFB+nM9XKRZDqzBKkRxVi2bnl8vJ/x27/Yho/ ++EDDYz17kcPl7WeX9kJDPx+I2xlU9WvPXDRedC0pDea4ddQxVQG/uuLtWC8nV48y +mS9zt1mHGUliGxzQPuoHMo+bc0ZiEmrmMzO3JYlu/ck5vFvLab3vU7dlAoGBAMJ8 +Re9FsB/66gpoZ1YpMFw6ChxK5etfrUL0DAQHPlHKvQXNOXOY5HOXhXXr5Lfpd7S/ +Mh3UY61AYi/RArFECApULQX+Umd19WJqUBY181+RdkIHsYQbHCdJoaS/uuVZWPjc +LCNjQcMg1ZKAr8Qk2J0BBSzH34CfPLk9CcQ18c9BAoGAYif+CluaBW/WtptluqNr +/waw3E7aDXg/bDiwX4ApyiO+dJ9GNa82aQhN7OiWCs/cie0mJkXEjLKXbAbaQwsz +1sM2SLZzN1iKfjCqqMAzxp4ONeuoht11tacF6KqDLQRm46E1glbBROa0qNli4Uex +BgCD0YTwT/Z2TcazY/uzBHE= +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10324/wechatpay_public_key.pem b/jczxw-java/src/main/resources/wechat/10324/wechatpay_public_key.pem new file mode 100644 index 0000000..9ac19ef --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10324/wechatpay_public_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs8s1pSfG3cxMxJbFEK0t +8Y2b2xy30NbmqtT1DRqjr8EIRA3MMkvHl1TSxN4a+9sdKmQWYT2/uvoD3BnwdR1J +9gzu4GkB9uZtyxio/J14OWVA1ytLBp8McfZU3DpF97+hwDGkt0S9QE8a6fPo9TH1 +Squ6fgcNTbkyjlQidSI3aQkCo18o7VBYCNRBLe0nd90AvREyfOQHdE1k3u0bQR2I +ZvEoIIiXqVYOHn+aR080gmL6IkAltgdOhmVMAMF49Totancpqt5tb9uY5BnPM4Cp +gRhJQw3Y1PeHyRC4PVDWRuUuZVV8HE4ZlrXuAhYLvjunapmEQr5lKmzLv+cMxBZA +KQIDAQAB +-----END PUBLIC KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10398/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/10398/apiclient_cert.p12 new file mode 100644 index 0000000..b5842c0 Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/10398/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/10398/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/10398/apiclient_cert.pem new file mode 100644 index 0000000..1fcd156 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10398/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIUSHSWE7QKqPHXaFg/w1I1jhPrWvAwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjQwNTExMDk0MzIzWhcNMjkwNTEwMDk0MzIzWjCBhDETMBEGA1UEAwwK +MTI0NjYxMDEwMTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL +DCfljZflroHluILnvZHlrr/kv6Hmga/np5HmioDmnInpmZDlhazlj7gxCzAJBgNV +BAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAJSGQstwTNKfEUWGGNRdzAG691PKkpa78IV7SNAaAWdBUohvSGQB +Hxg2JcTjnNifqxWAVj302u0+OEPETQ+teTLeLgRfGp4b8WBKdibn9RzZD964xGhM +NkcMEwUxdqfBK28kGaKYW0zBifkzS1LDGuEVmUo9jE7pAuzDz5mJwcd1fZs4NsjD +7O60QLw4SZCXINW6IYVc41Ln+RlY2XPkm/keBydjrfvMI7Z+DqW/TEWOWshNycYr +3hqVeipz2FnUwK4ruGxEOqTXhYtn0QtvYaMcrfcXJ1U+zuwtZf+kh3RI/Lk+y2rJ +kfnuxZZ+P5K2oG+hcBapYS3q15kmf9RpMH0CAwEAAaOBuTCBtjAJBgNVHRMEAjAA +MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2 +Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD +MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC +MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQCK +sgR2Wgb9wyyLX7ltlGXDqT44aMc3n5KI02LXv0mBD1aR4m5TFjlMzJIW2DIe01LF +yxVsUsoGIpjnAkmQOdNPL3tnCfl3bWqdNDDH9B711llNe5y1i4IYOcObhX08dEQd +vBnzuZ7/kH/t2h8q7rd7hqpQ5ZtU2xEY6ZlnohGyzNgVsDkLJI4b9iKRqOxRPVhs +GGbGKrv3JAYiFouSeH/m04xMWARFKhPoWduIeSWEJZmszWfkUBvPXo26+0YOKBVN +5gSkjioeXEX2T4/9K1SHx/iTzWvgN9MjlIJNujbg3Vz4PFU6aw2b8eK3Y0juto96 +2uoUN1fLIqxNOz2E4iSJ +-----END CERTIFICATE----- diff --git a/jczxw-java/src/main/resources/wechat/10398/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/10398/apiclient_key.pem new file mode 100644 index 0000000..a08bc93 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10398/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCUhkLLcEzSnxFF +hhjUXcwBuvdTypKWu/CFe0jQGgFnQVKIb0hkAR8YNiXE45zYn6sVgFY99NrtPjhD +xE0PrXky3i4EXxqeG/FgSnYm5/Uc2Q/euMRoTDZHDBMFMXanwStvJBmimFtMwYn5 +M0tSwxrhFZlKPYxO6QLsw8+ZicHHdX2bODbIw+zutEC8OEmQlyDVuiGFXONS5/kZ +WNlz5Jv5HgcnY637zCO2fg6lv0xFjlrITcnGK94alXoqc9hZ1MCuK7hsRDqk14WL +Z9ELb2GjHK33FydVPs7sLWX/pId0SPy5PstqyZH57sWWfj+StqBvoXAWqWEt6teZ +Jn/UaTB9AgMBAAECggEAb1Nvj5OeUaUfShBoXg3sU0O0DR9i3w8CCttMyYcklCO3 +XEKlbSgWCYzUpI7DSu/rSdOHUStOSdOAUvM5m824cbNtpKMwjWB+fWFyzFjDNhtR +NO0jctXlPT3Ep/jaaoV1K/pQKLqwfIj5BUw4YlGRvTL2Ulpt59vp8FQZMIm8MOcw +rNwYcUbMPaNKk4q3GF0LGvzW8k+S6wAWcAbx1KINRsLE0127o+shjGIlBiZgMJGZ +nTMz4xdvVbojsMhdM8aEhq6GtmSHgBFKjETQPXiOjRDCGOM5yC/9R/9WsMGJmJ4m +6Ec/RM4k9TZlnMZFsOZYO8S/kM+xgQUcAD8uGT1UgQKBgQDDGVZiqsDjudFcRkG/ +5pJN9PAC/Dk0Wzt6uRPZIhyFo2tDC/uL210Z5QR4hhB2nUSK8ANfAnepTotNzPHO +DC/sO2NzLuZz5EZTLeg9ij9BZDK+0/6AiBT2XdBKR/uGZAffjFCDh+ujm44lbrRK +7MUb9LtvDjPru1WVR0WhpFIwXQKBgQDC4xTQv6x3cPSW2SEglLVrl9CA68yO1g4T +MphCav64Cl9UDk1ov5C2SCvshFbWlIBv2g7tqb/bUk8nj42GuZWBu1spkUt2y7HS +eO89BmnaRNkVtWT8GtSMYYrYYAd23IGiOHPQqMnw/6HXkpjonpBa9c9CfEPwNtdq +84pgqed+oQKBgC6rV/PAPuX6pC87iyzZffPx/JvqM9DnZgIEVdAiDcqV/emK60BY +WBwCoaAnCbcmBahqo5PNpkw0wrP4q3sLhUcwKaj69huQ5pWtLJnUAS+mRVFKqt2a +L9GDPXkXYP6T3SJHkVb1Y5O+eTFRGwW1P61hTJjTP+5K4L0V0H1LLnHtAoGAEDBU +1lJVvUZAyxcWTWKM/3cI9uyffW4ClU2qoDnLFvalnJHjlEP1fW7ZVzhXDlQfpyrx ++oQTT+CyepLOKtbXuIMbu4Q6RI//IYCyPtt9h4gYkFkVHmwMI+0mX3r6o8EFc7hE +xpx+yeoyQ3oGAazKSQQKR3eTHS0xD81TPVxfwoECgYEAvBi3fPvIQ08pxk6kxj+S +bypHo06JHT1Fi8pmKtKCGLduK85dCeBZqHmsorWC/qg4RgCFWFFKfrFTGTxC4nf8 +MRQHmKxq+SAh4SvFgRDA0lyaUWmw7H/JpolbBDIGnXhoDI0CmQU3s2xsQdJnNPIL +azgaJXtOu+wr1MPR7Ij5OTU= +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10547/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/10547/apiclient_cert.p12 new file mode 100644 index 0000000..8661ab8 Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/10547/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/10547/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/10547/apiclient_cert.pem new file mode 100644 index 0000000..61839fd --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10547/apiclient_cert.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuVtyH2nr8xen7 +QTlPaZOExTNzZcCI3X+jlWwaUwBwn2ltsu/FkF/dgvPdUn4rmI/ZyD/29/nYWcT1 +xrM5Iaj8nd7HpicA98VMfei8nPQR8eJ5nARJHzjcV1xLVne5ZeWPLsYujc5D16BV +eCyxEBquR0g1IIuhUPur/o1L5Q3Maugck97Cbj5MxfgUBhR8twBrL+BG+tduFtNh +r70+rWdYrbfPQwo+aBnK4n0TKWiC2A81rUqybyr5khCzQjVUdOfeSbJP99XE4SAZ +9my3vr/kjwbMLQx/Vk9aa2jVpb03YWdJ0bYQ0GqBKo6Yt6Qtymgi310n9rlbkV6F +X5tzN0wtAgMBAAECggEABb5Iz5Tr/k3K0oMojywsNvCELGYKvLeHT+1JPWjEl/E4 +eOuvKHQEJHj+7aidDXSeMI9/Q/SRX4Y9jdc46kXomkHdJ/iaSlbfQhDXzPbit4Cf +dGAmZ/5GUkPyf2zeztXDhT8GOlxjkiqVVpt55W9hYaJph46F6w+O6vCc2QY3uScy +iPK7KHn3vQeritrnhVItRdn8ChsqvnoEZ7ZOF4GpPnd5GBma4yJXXr3DJqX5uQzC +BqCC9C3xxoJg5ay6LsolYiimgr0ylOYVhCsqnjsAxBhqHZaE+j/BW/BffGYeZzvv +8VJHQaoaIS7WdcHVgxH01MlEoQ4Cd4Ijk9wUt0XXgQKBgQDUDChXoPkNm4J02z29 +2qqKoV2z4T8rG1dHqjGAmaw3gbVD5DkvWFADBrV/CnGRZwNSWm9SP7OKTpAOU6wt +7yHb5gKyZBuf1q7v8xqB00YCrLBK5RH1LVvTSdR9KXogiI1qAJ35jG5PqipfYfCq +f+Ksyfl8XauBFiOF/IwIxtfgTQKBgQDSeczdML0jh/OlEk/SwK0s3MMgpdtZmeur +ShWPUARMo05aHqdSc6TGmdRP62peKSw8ZVD98G7MIXHGmyeJDcc6ahqS5/tbgb2z +JTyUhiHTQuBAHKAulouqOeKFIjKhnwR3B7kueROD3LI0mQosrWAYdTmpBb3v4UgC +vyxvS+gLYQKBgH3OtMTA4eL759uzFB+nM9XKRZDqzBKkRxVi2bnl8vJ/x27/Yho/ ++EDDYz17kcPl7WeX9kJDPx+I2xlU9WvPXDRedC0pDea4ddQxVQG/uuLtWC8nV48y +mS9zt1mHGUliGxzQPuoHMo+bc0ZiEmrmMzO3JYlu/ck5vFvLab3vU7dlAoGBAMJ8 +Re9FsB/66gpoZ1YpMFw6ChxK5etfrUL0DAQHPlHKvQXNOXOY5HOXhXXr5Lfpd7S/ +Mh3UY61AYi/RArFECApULQX+Umd19WJqUBY181+RdkIHsYQbHCdJoaS/uuVZWPjc +LCNjQcMg1ZKAr8Qk2J0BBSzH34CfPLk9CcQ18c9BAoGAYif+CluaBW/WtptluqNr +/waw3E7aDXg/bDiwX4ApyiO+dJ9GNa82aQhN7OiWCs/cie0mJkXEjLKXbAbaQwsz +1sM2SLZzN1iKfjCqqMAzxp4ONeuoht11tacF6KqDLQRm46E1glbBROa0qNli4Uex +BgCD0YTwT/Z2TcazY/uzBHE= +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10547/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/10547/apiclient_key.pem new file mode 100644 index 0000000..61839fd --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10547/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuVtyH2nr8xen7 +QTlPaZOExTNzZcCI3X+jlWwaUwBwn2ltsu/FkF/dgvPdUn4rmI/ZyD/29/nYWcT1 +xrM5Iaj8nd7HpicA98VMfei8nPQR8eJ5nARJHzjcV1xLVne5ZeWPLsYujc5D16BV +eCyxEBquR0g1IIuhUPur/o1L5Q3Maugck97Cbj5MxfgUBhR8twBrL+BG+tduFtNh +r70+rWdYrbfPQwo+aBnK4n0TKWiC2A81rUqybyr5khCzQjVUdOfeSbJP99XE4SAZ +9my3vr/kjwbMLQx/Vk9aa2jVpb03YWdJ0bYQ0GqBKo6Yt6Qtymgi310n9rlbkV6F +X5tzN0wtAgMBAAECggEABb5Iz5Tr/k3K0oMojywsNvCELGYKvLeHT+1JPWjEl/E4 +eOuvKHQEJHj+7aidDXSeMI9/Q/SRX4Y9jdc46kXomkHdJ/iaSlbfQhDXzPbit4Cf +dGAmZ/5GUkPyf2zeztXDhT8GOlxjkiqVVpt55W9hYaJph46F6w+O6vCc2QY3uScy +iPK7KHn3vQeritrnhVItRdn8ChsqvnoEZ7ZOF4GpPnd5GBma4yJXXr3DJqX5uQzC +BqCC9C3xxoJg5ay6LsolYiimgr0ylOYVhCsqnjsAxBhqHZaE+j/BW/BffGYeZzvv +8VJHQaoaIS7WdcHVgxH01MlEoQ4Cd4Ijk9wUt0XXgQKBgQDUDChXoPkNm4J02z29 +2qqKoV2z4T8rG1dHqjGAmaw3gbVD5DkvWFADBrV/CnGRZwNSWm9SP7OKTpAOU6wt +7yHb5gKyZBuf1q7v8xqB00YCrLBK5RH1LVvTSdR9KXogiI1qAJ35jG5PqipfYfCq +f+Ksyfl8XauBFiOF/IwIxtfgTQKBgQDSeczdML0jh/OlEk/SwK0s3MMgpdtZmeur +ShWPUARMo05aHqdSc6TGmdRP62peKSw8ZVD98G7MIXHGmyeJDcc6ahqS5/tbgb2z +JTyUhiHTQuBAHKAulouqOeKFIjKhnwR3B7kueROD3LI0mQosrWAYdTmpBb3v4UgC +vyxvS+gLYQKBgH3OtMTA4eL759uzFB+nM9XKRZDqzBKkRxVi2bnl8vJ/x27/Yho/ ++EDDYz17kcPl7WeX9kJDPx+I2xlU9WvPXDRedC0pDea4ddQxVQG/uuLtWC8nV48y +mS9zt1mHGUliGxzQPuoHMo+bc0ZiEmrmMzO3JYlu/ck5vFvLab3vU7dlAoGBAMJ8 +Re9FsB/66gpoZ1YpMFw6ChxK5etfrUL0DAQHPlHKvQXNOXOY5HOXhXXr5Lfpd7S/ +Mh3UY61AYi/RArFECApULQX+Umd19WJqUBY181+RdkIHsYQbHCdJoaS/uuVZWPjc +LCNjQcMg1ZKAr8Qk2J0BBSzH34CfPLk9CcQ18c9BAoGAYif+CluaBW/WtptluqNr +/waw3E7aDXg/bDiwX4ApyiO+dJ9GNa82aQhN7OiWCs/cie0mJkXEjLKXbAbaQwsz +1sM2SLZzN1iKfjCqqMAzxp4ONeuoht11tacF6KqDLQRm46E1glbBROa0qNli4Uex +BgCD0YTwT/Z2TcazY/uzBHE= +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10547/wechatpay_public_key.pem b/jczxw-java/src/main/resources/wechat/10547/wechatpay_public_key.pem new file mode 100644 index 0000000..9ac19ef --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10547/wechatpay_public_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs8s1pSfG3cxMxJbFEK0t +8Y2b2xy30NbmqtT1DRqjr8EIRA3MMkvHl1TSxN4a+9sdKmQWYT2/uvoD3BnwdR1J +9gzu4GkB9uZtyxio/J14OWVA1ytLBp8McfZU3DpF97+hwDGkt0S9QE8a6fPo9TH1 +Squ6fgcNTbkyjlQidSI3aQkCo18o7VBYCNRBLe0nd90AvREyfOQHdE1k3u0bQR2I +ZvEoIIiXqVYOHn+aR080gmL6IkAltgdOhmVMAMF49Totancpqt5tb9uY5BnPM4Cp +gRhJQw3Y1PeHyRC4PVDWRuUuZVV8HE4ZlrXuAhYLvjunapmEQr5lKmzLv+cMxBZA +KQIDAQAB +-----END PUBLIC KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10549/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/10549/apiclient_cert.p12 new file mode 100644 index 0000000..22cfee1 Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/10549/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/10549/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/10549/apiclient_cert.pem new file mode 100644 index 0000000..76d4639 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10549/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEJDCCAwygAwIBAgIUXW8Bc+pFR2mC1I6lqchsrQ3cwRQwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjUwNzI5MDQ1NDM0WhcNMzAwNzI4MDQ1NDM0WjB+MRMwEQYDVQQDDAox +NzIzNTcwMjgyMRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xKjAoBgNVBAsM +IeW5v+ilv+i9u+Wwj+eZvemjn+WTgeaciemZkOWFrOWPuDELMAkGA1UEBhMCQ04x +ETAPBgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAlrrUX3VA317YFRuVaHC9B40xxxMlqUox3d4H6bBSV6wjpPHkN2Pjj8V+Ep5N +VqFnyeI0tuqvR8RcKAV4nSiiRh/cfqwXivSlKXynFxMFbjChvgTlyXhIw33Qj7Pu +AUIKlksmCl2qsC9YIvbhIwILY21Nh7DAuIBGcquM+OkQZTXhwjmaAPItIBIUWRzt +WRz+kEPwmsdrkXHJV4NWU6druyxsNIVlCnY/kFbySedYpjx4CvbGMIeVpTMY5z6m +GapyzmTfmH5DrdK6XLZHTGtCDoGv8jeWwqYVwnAKEh4+6gyeMYvPQXE/Vu2za3Et +CT6Eo6DK+zQMEfIM+gNLB2sYGwIDAQABo4G5MIG2MAkGA1UdEwQCMAAwCwYDVR0P +BAQDAgP4MIGbBgNVHR8EgZMwgZAwgY2ggYqggYeGgYRodHRwOi8vZXZjYS5pdHJ1 +cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFE +Mzk3NTQ5ODQ2QzAxQzNFOEVCRDImc2c9SEFDQzQ3MUI2NTQyMkUxMkIyN0E5RDMz +QTg3QUQxQ0RGNTkyNkUxNDAzNzEwDQYJKoZIhvcNAQELBQADggEBAF3cOpy0zEDj +90x2+0Pflu97PJ93CwvY6Ys45w5wLlv/8TepgwXu+Fz9EVg30kCk9mUiuR9lPUeS +hPXNozGjEffuApfkJ5WBiIw7LIOf//3YXCJZd4CdlJ391NazvrjdASGbP2WfSXsF +isdbbVsV34aHZNJTy0ATfB1J791UEqp0VNNR9FqG16OtoIv7ku6CpMnrRtTaY0QL +gYbEl4k973IPmcW6mgy+AGeMnd9jOFkACfu1ZxtDhP/G/WM3TX5izeNSQDizxETp +hJts08esR+FnWZheoEuc1ByWXYAzabPqfq6vR+h5s6taCSmnA/YVXcWTjeLjBMfN +m9z8Mhd4ZCQ= +-----END CERTIFICATE----- diff --git a/jczxw-java/src/main/resources/wechat/10549/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/10549/apiclient_key.pem new file mode 100644 index 0000000..ed74038 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10549/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCWutRfdUDfXtgV +G5VocL0HjTHHEyWpSjHd3gfpsFJXrCOk8eQ3Y+OPxX4Snk1WoWfJ4jS26q9HxFwo +BXidKKJGH9x+rBeK9KUpfKcXEwVuMKG+BOXJeEjDfdCPs+4BQgqWSyYKXaqwL1gi +9uEjAgtjbU2HsMC4gEZyq4z46RBlNeHCOZoA8i0gEhRZHO1ZHP6QQ/Cax2uRcclX +g1ZTp2u7LGw0hWUKdj+QVvJJ51imPHgK9sYwh5WlMxjnPqYZqnLOZN+YfkOt0rpc +tkdMa0IOga/yN5bCphXCcAoSHj7qDJ4xi89BcT9W7bNrcS0JPoSjoMr7NAwR8gz6 +A0sHaxgbAgMBAAECggEAZFRR3oRmvQgdntcweUdpm6gxNQiarfez/7G15Kg39yGe +zEEynmf/5ggYJf53Di37rtbCLetC5uteSEl0AnA0q6azlyGnvhegBGBzvBkuKS13 +y8roxVUqYe3SMIUc7HtwHqBA3u+AGSw6Z3ObYjkPKYxs6eAOOAEyY0urV1eTUTop +2JZSAFdnhLCRpWZKCSZqjVSr5rRlEWDfwdLZc2f7RCCyVZt6Zb7tkC6kbeDTDgYJ +3MCBNWzTaf6Jw1mEunAKqHiRRWUUWQdGvzDGJPuJ8QCLtT5ushpE4UVsv42qFbbc +fQyNdKRrMKNMQWe9X9JkhRdiOgbKEqGuPrqTIxt1uQKBgQDGlzgTG5jHIg54HBIL +M2KhBA4nimwGvNjH8JkUF+37IcZlhkLssVCkwPBhDyQgENB4MRGFrGwBzEV164vW +89v6bOQLgSAHwJAsxFdVUcAr6aRDpyJfcHjg+Mq4L3YNevjYHEzCxiyE2PuMO9XK +sTsnxLaR4jLn/x1N8hdzd2SALQKBgQDCTaWDB9L1ZjtM0Jl8CJUhu1+mUIPjOg1R +UI17iY+nBdARB+hLlpB3t1I2PegWTQ6rBJMfgyCjGD5P1WYzqDkF++CyfRoLRs8f +KmMOm2JIZHnpxiZMr1gy3BIrA0cB8a4i+zaqZpa3wEY4LUn45VzBTQIEjg6Gu1Dq +8rg0yndeZwKBgE4c2O+bIULigHJ6CBbjxV20LKUc61TTHym112Bx8Segp1rzrotP +S3sicOqcfAco1fcQxeWgZnNml8PEPKL2FIayIhjsV171PUB+kiN7Hm2nXvdFXF3R +7ZoAAizkbjjrL8pBh2ftb0Fp37fPKU6q26vO0kkbgg6C6FHqcZL3WU6ZAoGAaKdv +xXKaYsjsmcQlV1Q8Fw4YR7lIQERNVgXgHrEKKbkMx4+Nw+DV8VVRN5wCfLiGdQCi +ya9UDeSJ83AKezpZdGqlLR4KwBYkizHGZuC0gC92Jr8uc9Fh3QsB0h8SyO5Gj9rl +J8TX2yL571odZK0NV6RFuPRWyKTtwY54Px7qSnMCgYBM929xu50eyI9sQMLiEo4L +ZTGiy2x6J7SKhCHSrWiuALWx9CF+c+ma/BxWMEHl5NixANijBfg4hil0D0zm6IRh +UVuOP/vq1Z5B3ycbTNoCmE29n9pfNaWJFEK3FVM4yJyvziKWOdZQH6u7RRK/ScyD +hK83SCqrIpUTbbytgkqYzA== +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10550/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/10550/apiclient_cert.p12 new file mode 100644 index 0000000..bde6b5e Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/10550/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/10550/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/10550/apiclient_cert.pem new file mode 100644 index 0000000..e3b8be8 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10550/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEQDCCAyigAwIBAgIUK5M/fDUBShw2NkJiPkpiNks0xOswDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjUwNzI2MTI1MjMyWhcNMzAwNzI1MTI1MjMyWjCBmTETMBEGA1UEAwwK +MTcyMzMyMTMzODEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMUUwQwYDVQQL +DDzmnZzlsJTkvK/nibnokpnlj6Tml4/oh6rmsrvljr/ml7bph4zlhpzkuJrnp5Hm +ioDmnInpmZDlhazlj7gxCzAJBgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANO4sq8tWbg5Zg6ioIltG8ME +8D1V3w4SXcsqBm5ilyCBVflQTHLqTUIKtU9BeR7+SQpeArDDFEVaMfn4ZuHlHPkY +Eic7YvuHMxH82IBAt9Ryz1m9ULTvae9Z3JGWEhIPiG/FmXjrak4LUlPoHDi22pVy +XLallAacP/1O8UKFg3KaGNi5/ZrTgoDr/hHkdW1CR12PlqxAV3fSShqAhwEemHav +msRptybIJND7K97XA3UPBxP84f2FuHwlj0c1sCqwI/C4R4hDZI7ShG+BEnNcUuDD +plk3qjj3igHUX6KfZZ5V6/MWUw02inV+SH72dDKdhItLFdZlT8bpvxjjb9UYr4MC +AwEAAaOBuTCBtjAJBgNVHRMEAjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQ +MIGNoIGKoIGHhoGEaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1 +c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQy +JnNnPUhBQ0M0NzFCNjU0MjJFMTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcx +MA0GCSqGSIb3DQEBCwUAA4IBAQAzIMqiMPT8gsJo3eEkppJPwOcA8SrPxrSJ0qV4 +/kZlu1ceClIy2aOPXDjf/LjB0I4YabU7/J8pLnXbKPKe2fSG1AycjrLEsZTOJ51M +Yahvj6sRJoC5aa+xQOj17VAVqySEg0JyK/5k6kvAulPO1dG6/YGoycAdDflJOjyd +mIHWQzlEJb5+LWQFCwskMTWy3CUF9Edw7jhgJwkl24CztocGrJ+AfJzoBTkfZmNO +TxD5gVSK00B1r7+ipS+iLXxWeHCpaRsG3PSsByWDA6pphlwr5IMghqne465gavWi +muwrpaGPdVi6+vz/QFyMelj4GT8g77VGVRCOa8DUvu0QxjTk +-----END CERTIFICATE----- diff --git a/jczxw-java/src/main/resources/wechat/10550/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/10550/apiclient_key.pem new file mode 100644 index 0000000..d3c1495 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10550/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDTuLKvLVm4OWYO +oqCJbRvDBPA9Vd8OEl3LKgZuYpcggVX5UExy6k1CCrVPQXke/kkKXgKwwxRFWjH5 ++Gbh5Rz5GBInO2L7hzMR/NiAQLfUcs9ZvVC072nvWdyRlhISD4hvxZl462pOC1JT +6Bw4ttqVcly2pZQGnD/9TvFChYNymhjYuf2a04KA6/4R5HVtQkddj5asQFd30koa +gIcBHph2r5rEabcmyCTQ+yve1wN1DwcT/OH9hbh8JY9HNbAqsCPwuEeIQ2SO0oRv +gRJzXFLgw6ZZN6o494oB1F+in2WeVevzFlMNNop1fkh+9nQynYSLSxXWZU/G6b8Y +42/VGK+DAgMBAAECggEAIgBuid2RpBlrv3v0pj1kkPxRDLimut7OO1uDbuTcenbq +9MAllurz/2Ay4AiWyBh0aHrSmcqqjby/e/KdqzedYI+yEqTh75014XSm3GoIW9EY +ZcQWmwg8DhlzZ9ofCtF9yt2EGTxNdT0yOpFzPtR25DtakmajEDC1whuUeWdxxcyY +2fDnIDeyaYfWSD0MWBYCa3+8TcvM/gCYzamr/Tfj59VwsznPNr5ehkQdCCRWVMAr +gg+h6ZOta8fSPwY11T6B743f5uyUUatKH90Yvg8OgbNqoqWyuPSoXM+VF0YOQk2N +0Q0gKnQ4ReDPFPBDXLfzQ4Q7g+N+S2u12r1u6z/E6QKBgQDsAvEO4l22pV6pltX9 +DDu6qyjPrRE7wadahFDWE7Rm3ENp69Ha1DqaNMYzGzSjcVZX0eoXsBw/cfyhjlML +vxw72SRS4XdZSJ+pfrtLw8n1XcuW8xOupVD0s9oLLB2dBXcJeytCM5UITZZHbJei +Y90Rlg88Ud7evO9kaENIouYc/QKBgQDlpx1t2qmjQcaXS1Ohe09ovCzxIr3jv8LQ +TQkM3wS9RdfOqX3MynnCopBlEYgxJFORQx2pzT1TmGtg5UOGP6Reck64oI8C+Vjt +AkFlODk1JCjeSgoR1zw1+KEwOZ9x2jswC1E3oZsFU+FdbrdyBiCyHRAXfWX3QW8y +CQIu6gnmfwKBgEALLE7Vroh5p45tl/Pq9epZt+FjHWIR0tAFR8pP3oxrCQAdNf0j +yiM+XupPX6FaiAucsuFqsL+mtt9AN9jgK1EyQ2EaPcDErE7aTQjqQEuNAEod/CFQ +Sv+cLncJqZ+KdBrmiX6VcMOoCjeniB5Q6xRym//KV6gprOyaPmffjIIhAoGAc1qQ +7rgyE34bma1NkcRVq98xl+ICjd6ppWW8kQmI4OWvM/Bw7ygZJwnvC8VVqpF7pHCY ++szL7CyYazBdzZY0Ivi50AVeMHk9ELfcT1KBcc769EUub620YcvEc2vOSir7JfPZ +VN9I9dEfV4YggRbQ34a3qYTkbeEhUHmz7grC9FMCgYBOanMGgmxLyRkrJdFvSgr5 +cBFeUxyr2jqgNrNbE77d5yB1lbgtWKQuokszSaxdnxGnsANSYdeF1FVI9zhcaqJf +xB2xOMesrNksZ4C+fKkSgmeofXi+D5aWYIZVuj73KInzJsvpci7z8qLK6/RjZsyF +TomCc7Iv0ufa1OirExFaNA== +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10559/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/10559/apiclient_cert.p12 new file mode 100644 index 0000000..1b7380f Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/10559/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/10559/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/10559/apiclient_cert.pem new file mode 100644 index 0000000..b13a8bf --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10559/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIUbc4rg9befsnIOtb3ugTd8RSdeaEwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjUxMDExMDM0ODIxWhcNMzAxMDEwMDM0ODIxWjCBhDETMBEGA1UEAwwK +MTcyOTQwNzM0ODEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL +DCflub/opb/pgJrmupDloILlgaXlurfnp5HmioDmnInpmZDlhazlj7gxCzAJBgNV +BAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL+FkdsAH+wYMS42h5oWHN+rYVRNtrzqOwn3aFgoN/hkURhGaZ0i +RXctbKSounAVCTcxo+wBj7jI8jpwZ//y4m8+m92LdMKYRVGtX7YRTP0BPTyjOeXR +v5r2UIu+A2ZTAQVfOfBKzHpLQUZUGxftFEr2/yCrtyOFL+Mb+q3jjY6ix0JXBxUJ +3TnoI/13ntSvz0EWzbWMCmGXaeBrHOwuv58sghPIs5t+C6/u/KxxcuGvOTrFoqLi +lxbnsMgKoDBGH9TINlkBvBLtMUrSNC5wbvGakCjNf/XoEBarRqcBn5d1LC7h3D4y +S57XPBShMbPqAUT21lkFAYacwOTC+p2LNKMCAwEAAaOBuTCBtjAJBgNVHRMEAjAA +MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2 +Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD +MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC +MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQBr +myrwxAhjX2RO0+a7l2d6P1YjPvwc01Q41eoyDbbdS4dM3FjsZMk2YIaDTjMz9syR +GkmkYeA/PgsOs3RVOpF9zpiFb1d+5C4Mej1ijQ4T2gN5BUCXIB5izGjLEWt2FaQi +SpWJBLBobxGuRwF00rk/uVskduJ017m4Vm20b4oOiQHC2KVQ5BcBIsQ9N6zMKHo7 +FrLzWPVwzDRkG9PnexdFAjtZlepsE07JovLe2WDa6HSGmIIHg0bZvHRGFW4i4BRq +CRoLuLwoQsodq7xA/caNvqVfRbhTN8fj7tjKP4rFM9v+RJHm0VdMiu3AXmewTjwh +e+sSKsRmRCdGMdByTI6b +-----END CERTIFICATE----- diff --git a/jczxw-java/src/main/resources/wechat/10559/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/10559/apiclient_key.pem new file mode 100644 index 0000000..9b1d18d --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10559/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC/hZHbAB/sGDEu +NoeaFhzfq2FUTba86jsJ92hYKDf4ZFEYRmmdIkV3LWykqLpwFQk3MaPsAY+4yPI6 +cGf/8uJvPpvdi3TCmEVRrV+2EUz9AT08oznl0b+a9lCLvgNmUwEFXznwSsx6S0FG +VBsX7RRK9v8gq7cjhS/jG/qt442OosdCVwcVCd056CP9d57Ur89BFs21jAphl2ng +axzsLr+fLIITyLObfguv7vyscXLhrzk6xaKi4pcW57DICqAwRh/UyDZZAbwS7TFK +0jQucG7xmpAozX/16BAWq0anAZ+XdSwu4dw+Mkue1zwUoTGz6gFE9tZZBQGGnMDk +wvqdizSjAgMBAAECggEBAL3ANXEYH4iHs3pI1nLIg9Tq9GRVFr73BoVqVTw6pLF5 +mosFgDAJu29HVwOQlB7mCJphmToDlgSLOsrBgZipaMS08DJAr+74dH1m25QEchWd +O7GvOnbDKCX88nJxUOb5R+KtpTa4tPxZQRPP0oQTBO785mrVFn6fv4EwwF22PRLZ +5cETTBuysL/K4R4RUxAQWK4CzFKnBUVjijHAsnmiUfRV8XF4U79S0o4gxNivyAP4 +/QzVUZHJMmEC1CCZx8B2tW+oIRKIfivF0FfttisJ15NPhS/mjLDIRePSrN+c6fBG +RT0nzHwZPk0Ptbmb0zBflPuAehqEyeQT+p+Exf2d2PECgYEA7mibGjwl+JdcX3qy +bbdzCapBEuWf/LqjLoLmCWvU/JsXTl6Pf3gzMa/aAO33H4cGdCwfk/yChvDfcCuS +D3fUFTn8QfQcsRmjQalVUWR1bkWoqIvZfL4RvB9XBVrucMjgbZvqqMlJglV2Al3s +6iNkUInKbpmB6gVM8eyciESysAkCgYEAzadMrsQuJq4ljgsZ8EOXABS1utqR35u6 +5UfI0V25IdB2T2xPHbSgwB/7C3gvlACwI3LmnM8722s1h3mDCh8bMnejTJWms/FY +LSstOnBfOOev/1ul8R++bM3u2/lU2XGn7WUw/GDYpLyyvpRin8rUuCSbHMZVUeyB +RCaVyfiJEksCgYBeVa3pt5sevmWish4gI9K1JFUTcSDZE9C1+r2jRLPGMGgMboZB +XgKDyp1seLysEPWQylTEbcoIMw92hwcIb9XPgF48iqc/vHFI7gQAbMu6kn2mE5A/ +N8Y0tgHs8IogvptvQ56aousfU0mariesjcyHwb4D/WHWg7pqj8Fweh5qYQKBgQCS +434YDjPQmO5mCHPccsp12lT7Q4aRqo/RmHZNZJ4JEvaOQBQ6aXuv/qe3R37kPaGR +kE47jqF4VZkETLxWDGXGpEFVQEaznByZFo/Vf9HjuUiyIeni0gOXf3euUuZR8aY6 +H97fROU4tTcOfLn83EkXxb2szdS/ESg7Xzv56LUvBQKBgQCDJScukz9lDZ8Ej4aY +gORLhd+mDAsIozQuBXrocSq+8p2gYNN1iDUfvrmYJnQElpTNWtwzYll/I9x+TGdd +qV8GlEENxGILgwgC2Y6fiuvW4KJQD+GIFJOCMVJbI/FHwbfWcgXj4JIkBWPkP5zc +N81uLUlOZZ6T1Vu64cP145Qb3A== +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/10584/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/10584/apiclient_cert.p12 new file mode 100644 index 0000000..12a8815 Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/10584/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/10584/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/10584/apiclient_cert.pem new file mode 100644 index 0000000..e2375aa --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10584/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKDCCAxCgAwIBAgIUUisXtVfIYqUelps2dgzNls4s1hMwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjYwMTE1MDYxNzIyWhcNMzEwMTE0MDYxNzIyWjCBgTETMBEGA1UEAwwK +MTczNzkxMDY5NTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMS0wKwYDVQQL +DCTlub/opb/ojonpppnllYbotLjmnInpmZDotKPku7vlhazlj7gxCzAJBgNVBAYT +AkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAODqyiexyXEDBUjD5g6ssIZf7I+b44IBw2M9tB9cJYuJJqAKk+Zt1hWm +C2kQsgztka0+Ptk3cbBKkmyo8DZQNdg49GXB56mwtCOgqiayXJzdHbu/DhCkhjfO +xTEa0fh+LH1ZMr40OLAUdtKBgjQcSOOqPAH7s12DP26eYR7dI8YCovvrSgdHVivd +AtFn0Ecuo0Z7EjzU4oISW15l8RGB1KC4keYTKDlh2CxsGjG1LzOkMMCjakhwBqHk +PVBIDmHeb5uukhAM3rrWD4K8/5qOfaIVt4PVagpOsDSKCEKGMo7udEBR8fusx3CK +RKzyQ2JDWCJr8gtK2cMi45m5fM92kYUCAwEAAaOBuTCBtjAJBgNVHRMEAjAAMAsG +A1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2Y2Eu +aXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRC +MDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJCMjdB +OUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQCPgKC3 +xjmbMLkFCvqJ0YTIxzP2MJlUTD6Rda1Otvqg89M/XQMbmIQl3aWmJAK508PnRVDB +lTwEJO0oXuRS3163uOw/fNl4F1jHO9ulkpIKqGzuARSmciV8zgHSnTjBEYHQpUXk +s2GIhRTpuysYgF+OeNbl0nZGzF7IChlo3Asw0Il5rH1yrleb7+SaaSyK3OCTgXe4 +n6duk1uYsw5aZupdOnKe4POvzGQrumGuA/Yuwq2H4bFGoNxYyHkcdZKR/t9Aa1G6 +1domZv4xJNDOppkvNuy+hcLUZ/R1xf05XgqckzYFnKRJn2TZaHluoUumcR6VtI22 +6YjKJAPEWS/8WFsJ +-----END CERTIFICATE----- diff --git a/jczxw-java/src/main/resources/wechat/10584/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/10584/apiclient_key.pem new file mode 100644 index 0000000..da7395d --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/10584/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDg6sonsclxAwVI +w+YOrLCGX+yPm+OCAcNjPbQfXCWLiSagCpPmbdYVpgtpELIM7ZGtPj7ZN3GwSpJs +qPA2UDXYOPRlweepsLQjoKomslyc3R27vw4QpIY3zsUxGtH4fix9WTK+NDiwFHbS +gYI0HEjjqjwB+7Ndgz9unmEe3SPGAqL760oHR1Yr3QLRZ9BHLqNGexI81OKCElte +ZfERgdSguJHmEyg5YdgsbBoxtS8zpDDAo2pIcAah5D1QSA5h3m+brpIQDN661g+C +vP+ajn2iFbeD1WoKTrA0ighChjKO7nRAUfH7rMdwikSs8kNiQ1gia/ILStnDIuOZ +uXzPdpGFAgMBAAECggEAcQzysYMGWpyHEm0M/MFGNTSP5hsX/qe+Ouqv17dsU7eL +R5QphQAeRGFiiNvQcvkSaP7JfksFBPRmpuE/ZD1q4xS1m1Qcikl8MhA2lh6+uEXY +BR9iBXF82R5ANY9ijMF2wUaNX9dFyxNuKh7YgDLbXDubz+9g15b50jMfY/EJYyPM +j/dQgqBvOp9xaao9PcOsME7lo69lnT15pH4DAKpKaGfqwJB9t63hdNRkXugrZRz6 +76709ijG54hgZwa+IXtSKYMPthWtU6rL//UuS1veudOvlKhQp8hSDy6ef2pArtW2 +UHD5AUrcWvOSMcoDr6+m7+/HrBqZuIqJrZJPIWmoHQKBgQD9NvBxEPiQGKfF8znG +YGqvpm7Nj4M6WKVfQcYfUVmOalSqA7wfDKCxTMG567LFAAjVqOrTIX8y5bUq9vzi +mdijlC/jzNivmezQg7KpM1ZHfojxOTuWBgxf3Ir0MjBisars8gXFneohCCyxkVD6 +UrSkrtLJu1+jarneBeaKApgTPwKBgQDjZCnyWhv+/ipViKBdka0gkVf4dyjIzghU +Y2Dh0xQdUEZFnq/8Y7GzfDMdED/+XshAUJXyrv911Huq9Dt4r6Hb0H6R9ygwhFib +Jvn/+vI4kOAwvAy0ISlMeDoo2iuE1ICUfirmcbvsNGfyy5UOox6VvJUUmsl6SkuU +7dtKH2deOwKBgBuq+iDQouhT2Vk213RGqsGgpPDPIp6oewFqlXRsliWKls+w8shN +v+0/ntdq2rDN7SkzeN0zBswP73jPXhiAiPxuv8DbbD3bytWJ3mbAlkffmqUJBOrC +pG2BEqnWJhVSpoOXemv6ck/DreaFI10G1ng8Jgom8C9SBRcue99Oo0FPAoGAMg9v +HKex2iVidIoro+3aS30z/MNe+zZApzNptM2fdASkM9eHruzTxkvlhNR7AikjtOUI +3fCg1PP+ddhm717bJ2VzN/dNpcC9MQsXpr88bC+Y66G6uj1Ctk8RnsTJJ+kQlaBh +GXKYiJvQ9qbTHfHTXeuydmLNUFri4NqsmFjpjNkCgYEA5jMAgVfy/IiW75+O+gKk +vJePA0yD+C3Sdsx6bWfBFsUrhOIOdKZ/lVpTe2R8TOi69IVe/7Ro318zvek4sEXL +eP968JMwas9q0Jemeq8lXryj9W9hnC3LGTfDyniGcU0azRjddf/87nBf6denow7s +t1/5GxlhAkgJQIO/lKOLmBU= +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/5/01ac632fea184e248d0375e9917063a4.pem b/jczxw-java/src/main/resources/wechat/5/01ac632fea184e248d0375e9917063a4.pem new file mode 100644 index 0000000..a08bc93 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/5/01ac632fea184e248d0375e9917063a4.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCUhkLLcEzSnxFF +hhjUXcwBuvdTypKWu/CFe0jQGgFnQVKIb0hkAR8YNiXE45zYn6sVgFY99NrtPjhD +xE0PrXky3i4EXxqeG/FgSnYm5/Uc2Q/euMRoTDZHDBMFMXanwStvJBmimFtMwYn5 +M0tSwxrhFZlKPYxO6QLsw8+ZicHHdX2bODbIw+zutEC8OEmQlyDVuiGFXONS5/kZ +WNlz5Jv5HgcnY637zCO2fg6lv0xFjlrITcnGK94alXoqc9hZ1MCuK7hsRDqk14WL +Z9ELb2GjHK33FydVPs7sLWX/pId0SPy5PstqyZH57sWWfj+StqBvoXAWqWEt6teZ +Jn/UaTB9AgMBAAECggEAb1Nvj5OeUaUfShBoXg3sU0O0DR9i3w8CCttMyYcklCO3 +XEKlbSgWCYzUpI7DSu/rSdOHUStOSdOAUvM5m824cbNtpKMwjWB+fWFyzFjDNhtR +NO0jctXlPT3Ep/jaaoV1K/pQKLqwfIj5BUw4YlGRvTL2Ulpt59vp8FQZMIm8MOcw +rNwYcUbMPaNKk4q3GF0LGvzW8k+S6wAWcAbx1KINRsLE0127o+shjGIlBiZgMJGZ +nTMz4xdvVbojsMhdM8aEhq6GtmSHgBFKjETQPXiOjRDCGOM5yC/9R/9WsMGJmJ4m +6Ec/RM4k9TZlnMZFsOZYO8S/kM+xgQUcAD8uGT1UgQKBgQDDGVZiqsDjudFcRkG/ +5pJN9PAC/Dk0Wzt6uRPZIhyFo2tDC/uL210Z5QR4hhB2nUSK8ANfAnepTotNzPHO +DC/sO2NzLuZz5EZTLeg9ij9BZDK+0/6AiBT2XdBKR/uGZAffjFCDh+ujm44lbrRK +7MUb9LtvDjPru1WVR0WhpFIwXQKBgQDC4xTQv6x3cPSW2SEglLVrl9CA68yO1g4T +MphCav64Cl9UDk1ov5C2SCvshFbWlIBv2g7tqb/bUk8nj42GuZWBu1spkUt2y7HS +eO89BmnaRNkVtWT8GtSMYYrYYAd23IGiOHPQqMnw/6HXkpjonpBa9c9CfEPwNtdq +84pgqed+oQKBgC6rV/PAPuX6pC87iyzZffPx/JvqM9DnZgIEVdAiDcqV/emK60BY +WBwCoaAnCbcmBahqo5PNpkw0wrP4q3sLhUcwKaj69huQ5pWtLJnUAS+mRVFKqt2a +L9GDPXkXYP6T3SJHkVb1Y5O+eTFRGwW1P61hTJjTP+5K4L0V0H1LLnHtAoGAEDBU +1lJVvUZAyxcWTWKM/3cI9uyffW4ClU2qoDnLFvalnJHjlEP1fW7ZVzhXDlQfpyrx ++oQTT+CyepLOKtbXuIMbu4Q6RI//IYCyPtt9h4gYkFkVHmwMI+0mX3r6o8EFc7hE +xpx+yeoyQ3oGAazKSQQKR3eTHS0xD81TPVxfwoECgYEAvBi3fPvIQ08pxk6kxj+S +bypHo06JHT1Fi8pmKtKCGLduK85dCeBZqHmsorWC/qg4RgCFWFFKfrFTGTxC4nf8 +MRQHmKxq+SAh4SvFgRDA0lyaUWmw7H/JpolbBDIGnXhoDI0CmQU3s2xsQdJnNPIL +azgaJXtOu+wr1MPR7Ij5OTU= +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/5/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/5/apiclient_cert.p12 new file mode 100644 index 0000000..a40e998 Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/5/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/5/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/5/apiclient_cert.pem new file mode 100644 index 0000000..b1a923d --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/5/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIUdUuXP1bAz547IdlQ7Kte2ZBjBX0wDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjYwNDE4MDUxNjQ5WhcNMzEwNDE3MDUxNjQ5WjCBhDETMBEGA1UEAwwK +MTI0NjYxMDEwMTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL +DCfljZflroHluILnvZHlrr/kv6Hmga/np5HmioDmnInpmZDlhazlj7gxCzAJBgNV +BAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKaMSBp/wBh5H0VZ6ZZJKwv6ta/uBlkhVMF6ooFb7LddGT3TrjRo +p6oC3DKTtLX2qBLWwGFYeiVeTY1n7sAvWXW5UxWfiSazfOpznrPFR+WMBxh1PNyr +IPrsx8hGHNiO6x2yxOFvqFqprEhYADc+Xm52dEWybBys+ChzGgVyHpA5FfUd9gpH +7LcDzn2K6t1wmyR5X+8KW/WUHejPIPH7GC/o6VfS/Efx+XmQeIc7d8yS67YXHwjP +PPlcsFa0qMWpCd84dZ8sOdTjSspIy8PDorYfYXoPh/KDEx9Iu5amDoe5a1XI8qWr +rsLU8FDDa8SjZEgdlAPeV+POARUTQBve35ECAwEAAaOBuTCBtjAJBgNVHRMEAjAA +MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2 +Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD +MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC +MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQAk +mahXnU+WbNUlujABMkcLGm5NlFEBvHPcb623UzoAc+1brOqHUq+eKN9m90l//zvB +NMUvUj5aBYWewIrYoPs41ScF3vzGGSkly8yq5pm/frut+aVeLKRKZEA0vWfMCIbJ +rZSsKwLW2ibv1P0PnfzCDSKnq2IBnHqCJxTr3lTZm0V2AXEPc0RDdQKLbwpXQHdJ +NqFugB6+eDPofHMwvrA0ywPt2Aw68dS1IrxkQRnRZrkKpIaddgm5KqvWaKTA5WhB +MvjgcCHjGoNoefN2bvrQG/YMXYONRaH42uWt+p8piedce3lUVxJHhCCmpkYYOXkQ +Hge+ts203j8pI1m82cHJ +-----END CERTIFICATE----- diff --git a/jczxw-java/src/main/resources/wechat/5/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/5/apiclient_key.pem new file mode 100644 index 0000000..541b1f7 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/5/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmjEgaf8AYeR9F +WemWSSsL+rWv7gZZIVTBeqKBW+y3XRk90640aKeqAtwyk7S19qgS1sBhWHolXk2N +Z+7AL1l1uVMVn4kms3zqc56zxUfljAcYdTzcqyD67MfIRhzYjusdssThb6haqaxI +WAA3Pl5udnRFsmwcrPgocxoFch6QORX1HfYKR+y3A859iurdcJskeV/vClv1lB3o +zyDx+xgv6OlX0vxH8fl5kHiHO3fMkuu2Fx8Izzz5XLBWtKjFqQnfOHWfLDnU40rK +SMvDw6K2H2F6D4fygxMfSLuWpg6HuWtVyPKlq67C1PBQw2vEo2RIHZQD3lfjzgEV +E0Ab3t+RAgMBAAECggEBAIDyedzybhNEq/5w59aw3cBPox4MZyPZF5sZTPpk5rjt +Pt7MpsLzCGUsA7qw+6gqyeSUGq0D6MZH5jmGb6aiwlvQWdCTDYhGTX/kdspvAwRp +zxCTrMSZRlagvumDx0+wD7+VqrN0VN+lILt+TuR2yHw0AD/6LZRiI1yGCW6P9bPp +DuWFCjZcB39fzBQ7e1YbJ++bxZDaR6ukpKkASS6HYQIH+jMtR4isdhKCOydYRTZI +HnF88zYGIPD2t2u+txz/hRcDkwg7PXt4JuQa4XErRUrL+IieSynGPGyPtaAjbPaS +u761hqkCw2AFAQXrEi03zWy9gkbQt0Da5msAy4xEWcUCgYEA1t2CQy70hjIQ80Af +u764B7ob8YmuZKbwmvKYq0IaoaHbJtKEqEoaGdiUGW1S2R+UjrwV+zE8jKpJq+Yt +CyOhMhQqJw0kBAZAX09p2twfJpUcenR2SBakBGVnAeVL6qL8G/y+NBY9GoKnAeUv +xMxpqzEDA7WX9NgJoCaoyOmkbgsCgYEAxm7BOKylZrv3JH8a0NOlP1KiONkG5pzn +Xk4Pf+Ea9wJpdfVmAb6WEJphTZI4WhFkWpjjCBahsYJZxlXj52Ad1vaMJlxmYDQl +9TDUBoNpD1FxuB+c2lQNPZUJJyPEf4j6d3SFn8bQ+/8x6CEUE/xJeJGxbl1n12qW +HM0PkBv21lMCgYAPrmTmYFPqQ1cnWaO3QQkPT07gxuqaX/CpblEkFpP4/eYPpEeY +PKhBAKR2YpssS3i9Hg8AoSxJG9h6mjbpXDVUgVI+PWBGhupFynbwSSZg23sTmNJV +Gonn5DqrUb/DpRd/N2fuRz04ZRapNb/RvhVsMAyHRcaMUQQK0yd4Wkzs1wKBgFJR +2C7e0K9SAzFM2Z8QbllaupnCzy4UoZdp4tw2Uq1ufrnE2FCY9EBnCz7XDjGvTWaY +TncojGPLo9q3/xgZs8dd+L5hTsdSWvzhCNS653bHXtn3o2afv+5wSZ/HItmVxfKQ +kG68WC5yrA2Uy3OPEhvGtUkHzvB681N3bqFmOHypAoGBAKx/8xmIEolMLIentjoa +N7Hcy6I2qNMHCE4xcQXzPMukobgQCCWf5dJDPmHbhg3aymZ55PWU7IiGijpBlxH6 +VT6Nkp4T9OR5VjSSH1k611XZ8ORSV6jHKqLtAxV4xXusXFDa56uukH+hm2s0jYug +1Q3QuHTZ0hDU0aIqOBNhRzzp +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/5/bac91dfb3ef143328dde489004c6d002.pem b/jczxw-java/src/main/resources/wechat/5/bac91dfb3ef143328dde489004c6d002.pem new file mode 100644 index 0000000..50afe22 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/5/bac91dfb3ef143328dde489004c6d002.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIUSjIxWE6Ttq53ggB00H6t6sy34iMwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMwOTE5MTUxNTQ4WhcNMjgwOTE3MTUxNTQ4WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5AOeoNuRReVPfOodE +TTE/wq96OK/7MI1lkwgtRlOIqwFGbGPxPx+wiLweWOWAeGrd0h+YuktIZezLhMhB +8pkJBzxz4U+zoQ9n3yY4CgDUBeAO8eNHhEQTTOTFUIvIlRxyr0EVuTHNP7pIkxA6 +gUvajWjJFbvU393vDHA9RflWrBNw1qVjkPPUx6axizD3wS8f77bwuspEWGTza/pS +g96HWUwFh9OSlQNPOjPG4km2YRQwGhoRMlLeZsUB+a0PtV0HI/B0TbY5u2EmPt0R +uNZLmcwImtiANYmySww6gp5uo4+im0P/kHKynPrW1SkS+8M9JP5T7Xck3bnHNv4S +9UOPAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAHd42YyvxvvjYEIkCURHweCSQpWQrdsnP +AU2rcVzOx0kDxjq7+W2HkIkYeAZfE8pyBs5c39tgK+qospiDsKa9WYeBNyIRcCvN +q9ObLqSV4Cy/8lQMNh4Q37cdc3X+pAlTr7MtKka8ZcXYvbMBqus0dfJZayZvW7Ak +nnaXXJ4k7urgHOGYsZlZ+HC+DC/sYoN3DXzvg3XPlL0SNEQH0cWrRbaQnpOKVMk5 +TptbeNHKJfUxVW5jh4GtBFqvLeiOruY+gFYg7UkCKWo9ZIYe7/mEvJeHYh3acTTl +DOl3L0fR5KR7vqFMwZEUZxVOs6K2ANSCr57OQPBV++MG4DPr3yOhCQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/jczxw-java/src/main/resources/wechat/websopy/apiclient_cert.p12 b/jczxw-java/src/main/resources/wechat/websopy/apiclient_cert.p12 new file mode 100644 index 0000000..4a512ab Binary files /dev/null and b/jczxw-java/src/main/resources/wechat/websopy/apiclient_cert.p12 differ diff --git a/jczxw-java/src/main/resources/wechat/websopy/apiclient_cert.pem b/jczxw-java/src/main/resources/wechat/websopy/apiclient_cert.pem new file mode 100644 index 0000000..559b855 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/websopy/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIUNyspZBFHaEGEyEBYfzgFMDP0pagwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjYwNDE4MDUzODEyWhcNMzEwNDE3MDUzODEyWjCBhDETMBEGA1UEAwwK +MTU1NzQxODgzMTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL +DCfljZflroHluILnvZHlrr/kv6Hmga/np5HmioDmnInpmZDlhazlj7gxCzAJBgNV +BAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKH3662EqIe0VUxqnkFInlrOVvsFbRheAiX3iSenEJVBINHlJnMg +9j8xjfacokl9SGmJUxqrcKTwczCK8Ceomv8cNW/I+8xCHPocDGP26wyXm/RaSqsy +glHupXPp7zonp1n80Z0ijJd9djVvrWPxvEno/yjJv60AF0jXw+AWKNjnz7vsb5v6 +wIycbb/Fq6uOQoDl+zx9FP6XaR8FZbVv+l/rCggPkkn49gTnkAg8I0Y0BhJuWh/B +VTErZ0+nZ4REgVDqNWCTYYNWT0rGm1+K+eANNBDmD5v65O6EDGdLiAk4VfYlHuTx +oXA7yjDXrKGHGoj9ITqNXlW/OE4gREXEaCMCAwEAAaOBuTCBtjAJBgNVHRMEAjAA +MAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2 +Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJD +MDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJC +MjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQAP +wn3a0o0yHIOORKwWqcejvD9XogOfrDEC9Uj7NiiVE0LCUskR1xlhFQrzbEN6rcGN +40uPtnvflANJblclxS+5zdZjWP8y3Nc971jg7m4APbEbmesicaNwzjfr8va/W37q +YQlSs+Zth543GLNrGyXavqnXGFXSrf7GXzsu/xD5Jsu17Ig6EAo8Pf0SBi/0KPao +m+T0GoIp59J1K+cgMGmx/d+Zl1avUsFWhkgxYKTFyxfIYovr67rRHnkvu2pGjWGP +MGIVHR19ZhcoQAweGKG2cBMD/69kNYFgVpM5ul+lFi9QJvHWooU49eR+uWnH44ml +Wxj2ukuTWvGHo4ibovgR +-----END CERTIFICATE----- diff --git a/jczxw-java/src/main/resources/wechat/websopy/apiclient_key.pem b/jczxw-java/src/main/resources/wechat/websopy/apiclient_key.pem new file mode 100644 index 0000000..c991b03 --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/websopy/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCh9+uthKiHtFVM +ap5BSJ5azlb7BW0YXgIl94knpxCVQSDR5SZzIPY/MY32nKJJfUhpiVMaq3Ck8HMw +ivAnqJr/HDVvyPvMQhz6HAxj9usMl5v0WkqrMoJR7qVz6e86J6dZ/NGdIoyXfXY1 +b61j8bxJ6P8oyb+tABdI18PgFijY58+77G+b+sCMnG2/xaurjkKA5fs8fRT+l2kf +BWW1b/pf6woID5JJ+PYE55AIPCNGNAYSblofwVUxK2dPp2eERIFQ6jVgk2GDVk9K +xptfivngDTQQ5g+b+uTuhAxnS4gJOFX2JR7k8aFwO8ow16yhhxqI/SE6jV5VvzhO +IERFxGgjAgMBAAECggEAZ1+4h9K3TYWHO3KA9uHGT+aKFURtULQPYvQOEcTLDLe4 +nr5GQAy1nbefB9sIqSbQ5KrE46ywBFWC72R9ypIN+uyiHmqEauV3YRotvk+FzU+m +Ndq69XETQ/+wkb6o9NECOqjlkAjQ+o8Utx5D6BoNNo8C66F4OI5qTg+H8Km0AFtP +XU2kAZD0txYK7scnCy85hf6Bw6zzd2S1Sek03m+DTY+l5JtIr5qVFTkOl9mwk01G +NAo4CzD5UOhCmn51Th9gplXABymBqQ8QLG5VN+xjnWi3A1ssHoPHuZ8/cpJR0Ekl +OZNiM2ew8P+nPQAe7q6JRTPX21skzypIHgw+8NA9YQKBgQDTJOxC/VpFBUZSE8qS +3vjWBYBBAhkyGw5qLbgJYFlgu43rAZyORrqMjjSE0q4zZeTI3jvnd+N9Rgub7NVA +LceYBYci5m9mRL+0FHe37wG0O081ZIfse5cY9SIye08Wo5K3xwgUvdl4TTQYJ2/a +NP6XGh66T6JhjoCrkch04yXFhwKBgQDEYJKjKZnPR1NalV82v/ZEX9TTHLPMVun8 +enrH4WmIJ+hfp241nk/vsgEXTB/XqIFqlYHdSYjEo+YSHq7m5lXYyJ5A1sSfQLz8 +O/jzBTNlEP79ZlzRhTQ9lTYfC62vPsCvVCZYCOwE2fl4ba8767qHYEut/dLSzan6 +SX/a9VcvhQKBgQC/3/nkFqAFwPladSnNtlqjA3S9ns6Ovg+nZcysmKYgRdB+E4TV +tmioekI3wc0UYDA8adg+TLCqkxDRrbNNE00iVUOs74OkiC091KvGtqfxxUQB3U24 +FcgFoh5libEhfZxC7dfmIXCS5nXEzXHT9fy2C8KIxP1ncjxzrZNgxVr52QKBgBsT +ZaRxe++EWg3HQpV96iqLPADPmEq4QRK6oGsmvTI0rmlh4GQsK8FUvanEqS9G4HEd +pAYquVzDbFlbOapEX9m/73HpKrr6ZhQxAKYhNXDd4wp1Lp8EyqsjA49MQOpEsLR7 +2b2RnVkd5LOiC+MrIVDBCi43LPY7vQ/xSluaMCcxAoGBAMJ/4bRiJdMbuZj7ykFM +2B8fc5BpubOshB657i7Orq5ONnHfqS/gcVu9DW9A1l2eeyMKQawluE9eJaoGVOvA +UgurPUIFWEeJ28473Nk34RrbJz8+eayMDBZb76qVqSKIER7jnu++C1IxUfe2Q+y/ +ljJUMYCj9U8DoYp1Hh3Kp5G3 +-----END PRIVATE KEY----- diff --git a/jczxw-java/src/main/resources/wechat/websopy/pub_key.pem b/jczxw-java/src/main/resources/wechat/websopy/pub_key.pem new file mode 100644 index 0000000..692966b --- /dev/null +++ b/jczxw-java/src/main/resources/wechat/websopy/pub_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoJqqGvFY0OeOyuleq85w +Vl+Nqdz+NmkAvC1he1jjjwM6WM0CXzzZNBjKf0yQR7sBDcyU1uB8k7D9O9luyP7a +c0TdcIxw9AEwzYOqyqZ9crL2rNQY0Bc7Zot35yPf1yLX2pXVNasdgYkeTJsta/d+ +YRaJUanVIfTT9kdwSt6ebtgjor/rcLSEjNk4POFlC+U8QtvA5V+hV3pjcerHS+nm +GmDph/GGajN2V6CAdJIPSP1NWfLeKTeFxSg2HD93LpBLfwBV2a+9y8J3i+r+lHvQ +riZs3jFTKukqi7YrOfrXxcQ8jnJ8m4MrwlUoaD0mwzuN47yJmaEns4sd6rnYRePk +HQIDAQAB +-----END PUBLIC KEY----- diff --git a/jczxw-java/src/test/java/com/gxwebsoft/RedisTest.java b/jczxw-java/src/test/java/com/gxwebsoft/RedisTest.java new file mode 100644 index 0000000..1f9a53c --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/RedisTest.java @@ -0,0 +1,29 @@ +package com.gxwebsoft; + +import com.gxwebsoft.common.core.utils.JSONUtil; +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.redis.core.StringRedisTemplate; + +import javax.annotation.Resource; +import java.util.HashMap; + +@SpringBootTest +public class RedisTest { + @Resource + private StringRedisTemplate stringRedisTemplate; + @Test + public void test(){ + HashMap map = new HashMap<>(); + map.put("name","李四"); + map.put("phone","13800138001"); + HashMap map2 = new HashMap<>(); + map2.put("name","赵六"); + map2.put("phone","13800138001"); + HashMap map3 = new HashMap<>(); + map3.put("name","张三"); + map3.put("phone","13800138001"); + System.out.printf("%s\n",JSONUtil.toJSONString(map)); +// stringRedisTemplate.opsForSet().add("test:set:2", JSONUtil.toJSONString(map),JSONUtil.toJSONString(map2),JSONUtil.toJSONString(map3)); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/WebSoftApplicationTests.java b/jczxw-java/src/test/java/com/gxwebsoft/WebSoftApplicationTests.java new file mode 100644 index 0000000..5a024f5 --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/WebSoftApplicationTests.java @@ -0,0 +1,13 @@ +package com.gxwebsoft; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class WebSoftApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/WxDev.java b/jczxw-java/src/test/java/com/gxwebsoft/WxDev.java new file mode 100644 index 0000000..110a008 --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/WxDev.java @@ -0,0 +1,110 @@ +package com.gxwebsoft; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.*; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.time.Instant; +import java.util.concurrent.atomic.AtomicReference; + +@Service +public class WxDev { + + @Value("${wechat.appid}") + private String appId; + @Value("${wechat.secret}") + private String secret; + + private final StringRedisTemplate redisTemplate; + + private final OkHttpClient http = new OkHttpClient(); + private final ObjectMapper om = new ObjectMapper(); + + /** 简单本地缓存 access_token(生产建议放 Redis) */ + private final AtomicReference cachedToken = new AtomicReference<>(); + private volatile long tokenExpireEpoch = 0L; // 过期的 epoch 秒 + + public WxDev(StringRedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + /** 获取/刷新 access_token */ + public String getAccessToken() throws IOException { + long now = Instant.now().getEpochSecond(); + System.out.println("cachedToken.get = " + cachedToken.get()); + if (cachedToken.get() != null && now < tokenExpireEpoch - 60) { + return cachedToken.get(); + } + HttpUrl url = HttpUrl.parse("https://api.weixin.qq.com/cgi-bin/token") + .newBuilder() + .addQueryParameter("grant_type", "client_credential") + .addQueryParameter("appid", "wx51962d6ac21f2ed2") + .addQueryParameter("secret", "d821f98de8a6c1ba7bc7e0ee84bcbc8e") + .build(); + Request req = new Request.Builder().url(url).get().build(); + try (Response resp = http.newCall(req).execute()) { + String body = resp.body().string(); + JsonNode json = om.readTree(body); + if (json.has("access_token")) { + String token = json.get("access_token").asText(); + int expiresIn = json.get("expires_in").asInt(7200); + System.out.println("token1 = " + token); + cachedToken.set(token); + tokenExpireEpoch = now + expiresIn; + return token; + } else { + throw new IOException("Get access_token failed: " + body); + } + } + } + + /** 调用 getwxacodeunlimit,返回图片二进制 */ + public byte[] getUnlimitedCode(String scene, String page, Integer width, + Boolean isHyaline, String envVersion) throws IOException { + String accessToken = getAccessToken(); + System.out.println("accessToken = " + accessToken); + HttpUrl url = HttpUrl.parse("https://api.weixin.qq.com/wxa/getwxacodeunlimit") + .newBuilder() + .addQueryParameter("access_token", accessToken) + .build(); + + // 构造请求 JSON + // 注意:scene 仅支持可见字符,长度上限 32,尽量 URL-safe(字母数字下划线等) + // page 必须是已发布小程序内的路径(不带开头斜杠也可) + var root = om.createObjectNode(); + root.put("scene", scene); + if (page != null) root.put("page", page); + if (width != null) root.put("width", width); // 默认 430,建议 280~1280 + if (isHyaline != null) root.put("is_hyaline", isHyaline); + if (envVersion != null) root.put("env_version", envVersion); // release/trial/develop + + RequestBody reqBody = RequestBody.create( + root.toString(), MediaType.parse("application/json; charset=utf-8")); + Request req = new Request.Builder().url(url).post(reqBody).build(); + + try (Response resp = http.newCall(req).execute()) { + if (!resp.isSuccessful()) { + throw new IOException("HTTP " + resp.code() + " calling getwxacodeunlimit"); + } + MediaType ct = resp.body().contentType(); + byte[] bytes = resp.body().bytes(); + // 微信出错时返回 JSON,需要识别一下 + if (ct != null && ct.subtype() != null && ct.subtype().contains("json")) { + String err = new String(bytes); + throw new IOException("WeChat error: " + err); + } + return bytes; // 成功就是图片二进制(PNG) + } + } + + @Test + public void getQrCode() throws IOException { + final byte[] test = getUnlimitedCode("register", "pages/index/index",180,false,"develop"); + System.out.println("test = " + test); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/common/core/controller/QrCodeControllerTest.java b/jczxw-java/src/test/java/com/gxwebsoft/common/core/controller/QrCodeControllerTest.java new file mode 100644 index 0000000..9677d80 --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/common/core/controller/QrCodeControllerTest.java @@ -0,0 +1,102 @@ +package com.gxwebsoft.common.core.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gxwebsoft.common.core.dto.qr.CreateEncryptedQrCodeRequest; +import com.gxwebsoft.common.core.utils.EncryptedQrCodeUtil; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * QR码控制器测试 + * + * @author WebSoft + * @since 2025-08-18 + */ +@WebMvcTest(QrCodeController.class) +public class QrCodeControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private EncryptedQrCodeUtil encryptedQrCodeUtil; + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void testCreateEncryptedQrCodeWithValidRequest() throws Exception { + // 准备测试数据 + CreateEncryptedQrCodeRequest request = new CreateEncryptedQrCodeRequest(); + request.setData("test data"); + request.setWidth(200); + request.setHeight(200); + request.setExpireMinutes(30L); + request.setBusinessType("TEST"); + + Map mockResult = new HashMap<>(); + mockResult.put("qrCodeBase64", "base64_encoded_image"); + mockResult.put("token", "test_token"); + + when(encryptedQrCodeUtil.generateEncryptedQrCode(anyString(), anyInt(), anyInt(), anyLong(), anyString())) + .thenReturn(mockResult); + + // 执行测试 + mockMvc.perform(post("/api/qr-code/create-encrypted-qr-code") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.message").value("生成加密二维码成功")) + .andExpect(jsonPath("$.data.qrCodeBase64").value("base64_encoded_image")) + .andExpect(jsonPath("$.data.token").value("test_token")); + } + + @Test + public void testCreateEncryptedQrCodeWithInvalidRequest() throws Exception { + // 准备无效的测试数据(data为空) + CreateEncryptedQrCodeRequest request = new CreateEncryptedQrCodeRequest(); + request.setData(""); // 空字符串,应该触发验证失败 + request.setWidth(200); + request.setHeight(200); + request.setExpireMinutes(30L); + + // 执行测试 + mockMvc.perform(post("/api/qr-code/create-encrypted-qr-code") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(500)) + .andExpect(jsonPath("$.message").value("数据不能为空")); + } + + @Test + public void testCreateEncryptedQrCodeWithInvalidSize() throws Exception { + // 准备无效的测试数据(尺寸超出范围) + CreateEncryptedQrCodeRequest request = new CreateEncryptedQrCodeRequest(); + request.setData("test data"); + request.setWidth(2000); // 超出最大值1000 + request.setHeight(200); + request.setExpireMinutes(30L); + + // 执行测试 + mockMvc.perform(post("/api/qr-code/create-encrypted-qr-code") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(500)) + .andExpect(jsonPath("$.message").value("宽度不能大于1000像素")); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtilTest.java b/jczxw-java/src/test/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtilTest.java new file mode 100644 index 0000000..bb0ebcd --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/common/core/utils/EncryptedQrCodeUtilTest.java @@ -0,0 +1,136 @@ +package com.gxwebsoft.common.core.utils; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.annotation.Resource; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 加密二维码工具类测试 + * + * @author WebSoft + * @since 2025-08-18 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class EncryptedQrCodeUtilTest { + + @Resource + private EncryptedQrCodeUtil encryptedQrCodeUtil; + + @Test + public void testGenerateAndDecryptData() { + // 测试数据 + String originalData = "https://www.example.com/user/123"; + Long expireMinutes = 30L; + + // 生成加密数据 + Map encryptedInfo = encryptedQrCodeUtil.generateEncryptedData(originalData, expireMinutes); + + assertNotNull(encryptedInfo); + assertNotNull(encryptedInfo.get("token")); + assertNotNull(encryptedInfo.get("encryptedData")); + assertEquals(expireMinutes.toString(), encryptedInfo.get("expireMinutes")); + + // 解密数据 + String decryptedData = encryptedQrCodeUtil.decryptData( + encryptedInfo.get("token"), + encryptedInfo.get("encryptedData") + ); + + assertEquals(originalData, decryptedData); + } + + @Test + public void testGenerateEncryptedQrCode() { + // 测试数据 + String originalData = "测试二维码数据"; + int width = 300; + int height = 300; + Long expireMinutes = 60L; + + // 生成加密二维码 + Map result = encryptedQrCodeUtil.generateEncryptedQrCode( + originalData, width, height, expireMinutes + ); + + assertNotNull(result); + assertNotNull(result.get("qrCodeBase64")); + assertNotNull(result.get("token")); + assertEquals(originalData, result.get("originalData")); + assertEquals(expireMinutes.toString(), result.get("expireMinutes")); + } + + @Test + public void testTokenValidation() { + // 生成测试数据 + String originalData = "token验证测试"; + Map encryptedInfo = encryptedQrCodeUtil.generateEncryptedData(originalData, 30L); + String token = encryptedInfo.get("token"); + + // 验证token有效性 + assertTrue(encryptedQrCodeUtil.isTokenValid(token)); + + // 使token失效 + encryptedQrCodeUtil.invalidateToken(token); + + // 再次验证token应该无效 + assertFalse(encryptedQrCodeUtil.isTokenValid(token)); + } + + @Test + public void testInvalidToken() { + // 测试无效token + assertFalse(encryptedQrCodeUtil.isTokenValid("invalid_token")); + assertFalse(encryptedQrCodeUtil.isTokenValid("")); + assertFalse(encryptedQrCodeUtil.isTokenValid(null)); + } + + @Test + public void testDecryptWithInvalidToken() { + // 测试用无效token解密 + assertThrows(RuntimeException.class, () -> { + encryptedQrCodeUtil.decryptData("invalid_token", "encrypted_data"); + }); + } + + @Test + public void testGenerateEncryptedQrCodeWithBusinessType() { + // 测试数据 + String originalData = "用户登录数据"; + int width = 200; + int height = 200; + Long expireMinutes = 30L; + String businessType = "LOGIN"; + + // 生成带业务类型的加密二维码 + Map result = encryptedQrCodeUtil.generateEncryptedQrCode( + originalData, width, height, expireMinutes, businessType + ); + + assertNotNull(result); + assertNotNull(result.get("qrCodeBase64")); + assertNotNull(result.get("token")); + assertEquals(originalData, result.get("originalData")); + assertEquals(expireMinutes.toString(), result.get("expireMinutes")); + assertEquals(businessType, result.get("businessType")); + + System.out.println("=== 带BusinessType的二维码生成测试 ==="); + System.out.println("原始数据: " + originalData); + System.out.println("业务类型: " + businessType); + System.out.println("Token: " + result.get("token")); + System.out.println("二维码Base64长度: " + ((String)result.get("qrCodeBase64")).length()); + + // 验证不传businessType的情况 + Map resultWithoutType = encryptedQrCodeUtil.generateEncryptedQrCode( + originalData, width, height, expireMinutes + ); + + assertNull(resultWithoutType.get("businessType")); + System.out.println("不传BusinessType时的结果: " + resultWithoutType.get("businessType")); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/common/system/controller/WxLoginControllerTest.java b/jczxw-java/src/test/java/com/gxwebsoft/common/system/controller/WxLoginControllerTest.java new file mode 100644 index 0000000..e879925 --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/common/system/controller/WxLoginControllerTest.java @@ -0,0 +1,136 @@ +package com.gxwebsoft.common.system.controller; + +import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.common.system.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.annotation.Resource; + +/** + * 微信登录控制器测试 + * + * @author WebSoft + * @since 2025-08-23 + */ +@Slf4j +@SpringBootTest +@ActiveProfiles("dev") +public class WxLoginControllerTest { + + @Resource + private UserService userService; + + /** + * 测试从scene参数解析租户ID的逻辑 + */ + @Test + public void testExtractTenantIdFromScene() { + log.info("=== 开始测试scene参数解析 ==="); + + // 测试用户ID 33103 + Integer testUserId = 33103; + + // 查询用户信息 + User user = userService.getByIdIgnoreTenant(testUserId); + if (user != null) { + log.info("用户ID {} 对应的租户ID: {}", testUserId, user.getTenantId()); + log.info("用户信息 - 用户名: {}, 手机: {}", user.getUsername(), user.getPhone()); + } else { + log.warn("未找到用户ID: {}", testUserId); + } + + // 测试不同的scene格式 + String[] testScenes = { + "uid_33103", + "uid_1", + "uid_999999", + "invalid_scene", + null + }; + + for (String scene : testScenes) { + log.info("测试scene: {} -> 预期解析结果", scene); + // 这里模拟解析逻辑 + if (scene != null && scene.startsWith("uid_")) { + try { + String userIdStr = scene.substring(4); + Integer userId = Integer.parseInt(userIdStr); + User testUser = userService.getByIdIgnoreTenant(userId); + if (testUser != null) { + log.info(" 解析成功: 用户ID {} -> 租户ID {}", userId, testUser.getTenantId()); + } else { + log.info(" 用户不存在: 用户ID {} -> 默认租户ID 10550", userId); + } + } catch (Exception e) { + log.info(" 解析异常: {} -> 默认租户ID 10550", e.getMessage()); + } + } else { + log.info(" 无效格式 -> 默认租户ID 10550"); + } + } + + log.info("=== scene参数解析测试完成 ==="); + } + + /** + * 测试查找特定用户 + */ + @Test + public void testFindSpecificUsers() { + log.info("=== 开始查找特定用户 ==="); + + // 查找租户10550的用户 + Integer[] testUserIds = {1, 2, 3, 33103, 10001, 10002}; + + for (Integer userId : testUserIds) { + User user = userService.getByIdIgnoreTenant(userId); + if (user != null) { + log.info("用户ID: {}, 租户ID: {}, 用户名: {}, 手机: {}", + userId, user.getTenantId(), user.getUsername(), user.getPhone()); + } else { + log.info("用户ID: {} - 不存在", userId); + } + } + + log.info("=== 特定用户查找完成 ==="); + } + + /** + * 测试URL解析 + */ + @Test + public void testUrlParsing() { + log.info("=== 开始测试URL解析 ==="); + + String testUrl = "127.0.0.1:9200/api/wx-login/getOrderQRCodeUnlimited/uid_33103"; + log.info("测试URL: {}", testUrl); + + // 提取scene部分 + String[] parts = testUrl.split("/"); + String scene = parts[parts.length - 1]; // 最后一部分 + log.info("提取的scene: {}", scene); + + // 解析用户ID + if (scene.startsWith("uid_")) { + String userIdStr = scene.substring(4); + try { + Integer userId = Integer.parseInt(userIdStr); + log.info("解析的用户ID: {}", userId); + + User user = userService.getByIdIgnoreTenant(userId); + if (user != null) { + log.info("对应的租户ID: {}", user.getTenantId()); + } else { + log.warn("用户不存在"); + } + } catch (NumberFormatException e) { + log.error("用户ID格式错误: {}", userIdStr); + } + } + + log.info("=== URL解析测试完成 ==="); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/common/system/service/UserIgnoreTenantTest.java b/jczxw-java/src/test/java/com/gxwebsoft/common/system/service/UserIgnoreTenantTest.java new file mode 100644 index 0000000..d24bc1d --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/common/system/service/UserIgnoreTenantTest.java @@ -0,0 +1,100 @@ +package com.gxwebsoft.common.system.service; + +import com.gxwebsoft.common.system.entity.User; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.annotation.Resource; + +/** + * 用户忽略租户隔离功能测试 + * + * @author WebSoft + * @since 2025-08-23 + */ +@Slf4j +@SpringBootTest +@ActiveProfiles("dev") +public class UserIgnoreTenantTest { + + @Resource + private UserService userService; + + /** + * 测试忽略租户隔离查询用户 + */ + @Test + public void testGetByIdIgnoreTenant() { + // 测试用户ID(请根据实际数据库中的用户ID进行调整) + Integer testUserId = 1; + + log.info("=== 开始测试忽略租户隔离查询用户功能 ==="); + + // 1. 使用普通方法查询用户(受租户隔离影响) + User userNormal = userService.getById(testUserId); + log.info("普通查询结果 - 用户ID: {}, 用户信息: {}", testUserId, + userNormal != null ? userNormal.getUsername() : "null"); + + // 2. 使用忽略租户隔离方法查询用户 + User userIgnoreTenant = userService.getByIdIgnoreTenant(testUserId); + log.info("忽略租户隔离查询结果 - 用户ID: {}, 用户信息: {}", testUserId, + userIgnoreTenant != null ? userIgnoreTenant.getUsername() : "null"); + + // 3. 验证结果 + if (userIgnoreTenant != null) { + log.info("✅ 忽略租户隔离查询成功!"); + log.info("用户详情 - ID: {}, 用户名: {}, 昵称: {}, 租户ID: {}", + userIgnoreTenant.getUserId(), + userIgnoreTenant.getUsername(), + userIgnoreTenant.getNickname(), + userIgnoreTenant.getTenantId()); + } else { + log.error("❌ 忽略租户隔离查询失败!"); + } + + log.info("=== 忽略租户隔离查询用户功能测试完成 ==="); + } + + /** + * 测试参数验证 + */ + @Test + public void testGetByIdIgnoreTenantValidation() { + log.info("=== 开始测试参数验证 ==="); + + // 测试null用户ID + User result1 = userService.getByIdIgnoreTenant(null); + log.info("null用户ID测试结果: {}", result1 == null ? "成功(返回null)" : "失败"); + + // 测试不存在的用户ID + User result2 = userService.getByIdIgnoreTenant(999999); + log.info("不存在用户ID测试结果: {}", result2 == null ? "成功(返回null)" : "失败"); + + log.info("=== 参数验证测试完成 ==="); + } + + /** + * 测试跨租户查询 + */ + @Test + public void testCrossTenantQuery() { + log.info("=== 开始测试跨租户查询 ==="); + + // 查询不同租户的用户(请根据实际数据调整) + Integer[] testUserIds = {1, 2, 3, 4, 5}; + + for (Integer userId : testUserIds) { + User user = userService.getByIdIgnoreTenant(userId); + if (user != null) { + log.info("用户ID: {}, 用户名: {}, 租户ID: {}", + user.getUserId(), user.getUsername(), user.getTenantId()); + } else { + log.info("用户ID: {} - 不存在", userId); + } + } + + log.info("=== 跨租户查询测试完成 ==="); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/common/system/service/WeixinConfigTest.java b/jczxw-java/src/test/java/com/gxwebsoft/common/system/service/WeixinConfigTest.java new file mode 100644 index 0000000..1b915d0 --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/common/system/service/WeixinConfigTest.java @@ -0,0 +1,174 @@ +package com.gxwebsoft.common.system.service; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.cms.entity.CmsWebsiteField; +import com.gxwebsoft.cms.service.CmsWebsiteFieldService; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 微信小程序配置测试 + * + * @author WebSoft + * @since 2025-08-23 + */ +@Slf4j +@SpringBootTest +@ActiveProfiles("dev") +public class WeixinConfigTest { + + @Resource + private SettingService settingService; + + @Resource + private CmsWebsiteFieldService cmsWebsiteFieldService; + + /** + * 测试从cms_website_field表获取微信小程序配置 + */ + @Test + public void testGetWeixinConfigFromWebsiteField() { + Integer tenantId = 10550; + + log.info("=== 开始测试从cms_website_field表获取微信小程序配置 ==="); + + // 1. 查看cms_website_field表中的所有配置 + List allFields = cmsWebsiteFieldService.list( + new LambdaQueryWrapper() + .eq(CmsWebsiteField::getTenantId, tenantId) + .eq(CmsWebsiteField::getDeleted, 0) + ); + + log.info("租户{}的所有cms_website_field配置:", tenantId); + for (CmsWebsiteField field : allFields) { + log.info(" - ID: {}, Name: {}, Value: {}", field.getId(), field.getName(), field.getValue()); + } + + // 2. 查找AppID配置 + CmsWebsiteField appIdField = cmsWebsiteFieldService.getOne( + new LambdaQueryWrapper() + .eq(CmsWebsiteField::getName, "AppID") + .eq(CmsWebsiteField::getTenantId, tenantId) + .eq(CmsWebsiteField::getDeleted, 0) + ); + + log.info("AppID配置: {}", appIdField); + + // 3. 查找AppSecret配置 + CmsWebsiteField appSecretField = cmsWebsiteFieldService.getOne( + new LambdaQueryWrapper() + .eq(CmsWebsiteField::getName, "AppSecret") + .eq(CmsWebsiteField::getTenantId, tenantId) + .eq(CmsWebsiteField::getDeleted, 0) + ); + + log.info("AppSecret配置: {}", appSecretField); + + // 4. 测试获取微信小程序配置 + try { + JSONObject config = settingService.getBySettingKeyIgnoreTenant("mp-weixin", tenantId); + log.info("✅ 成功获取微信小程序配置: {}", config); + } catch (Exception e) { + log.error("❌ 获取微信小程序配置失败: {}", e.getMessage()); + } + + log.info("=== 微信小程序配置测试完成 ==="); + } + + /** + * 测试不同name的查询 + */ + @Test + public void testDifferentNameQueries() { + Integer tenantId = 10550; + + log.info("=== 开始测试不同name的查询 ==="); + + String[] nameVariations = {"AppID", "appId", "APPID", "app_id", "AppSecret", "appSecret", "APPSECRET", "app_secret"}; + + for (String name : nameVariations) { + CmsWebsiteField field = cmsWebsiteFieldService.getOne( + new LambdaQueryWrapper() + .eq(CmsWebsiteField::getName, name) + .eq(CmsWebsiteField::getTenantId, tenantId) + .eq(CmsWebsiteField::getDeleted, 0) + ); + + if (field != null) { + log.info("找到配置 - Name: {}, Value: {}", name, field.getValue()); + } else { + log.info("未找到配置 - Name: {}", name); + } + } + + log.info("=== 不同name查询测试完成 ==="); + } + + /** + * 测试创建测试配置 + */ + @Test + public void testCreateTestConfig() { + Integer tenantId = 10550; + + log.info("=== 开始创建测试配置 ==="); + + // 创建AppID配置 + CmsWebsiteField appIdField = new CmsWebsiteField(); + appIdField.setName("AppID"); + appIdField.setValue("wx1234567890abcdef"); // 测试AppID + appIdField.setTenantId(tenantId); + appIdField.setType(0); // 文本类型 + appIdField.setComments("微信小程序AppID"); + appIdField.setDeleted(0); + + // 创建AppSecret配置 + CmsWebsiteField appSecretField = new CmsWebsiteField(); + appSecretField.setName("AppSecret"); + appSecretField.setValue("abcdef1234567890abcdef1234567890"); // 测试AppSecret + appSecretField.setTenantId(tenantId); + appSecretField.setType(0); // 文本类型 + appSecretField.setComments("微信小程序AppSecret"); + appSecretField.setDeleted(0); + + try { + // 检查是否已存在 + CmsWebsiteField existingAppId = cmsWebsiteFieldService.getOne( + new LambdaQueryWrapper() + .eq(CmsWebsiteField::getName, "AppID") + .eq(CmsWebsiteField::getTenantId, tenantId) + ); + + if (existingAppId == null) { + cmsWebsiteFieldService.save(appIdField); + log.info("✅ 创建AppID配置成功"); + } else { + log.info("AppID配置已存在,跳过创建"); + } + + CmsWebsiteField existingAppSecret = cmsWebsiteFieldService.getOne( + new LambdaQueryWrapper() + .eq(CmsWebsiteField::getName, "AppSecret") + .eq(CmsWebsiteField::getTenantId, tenantId) + ); + + if (existingAppSecret == null) { + cmsWebsiteFieldService.save(appSecretField); + log.info("✅ 创建AppSecret配置成功"); + } else { + log.info("AppSecret配置已存在,跳过创建"); + } + + } catch (Exception e) { + log.error("❌ 创建测试配置失败: {}", e.getMessage()); + } + + log.info("=== 创建测试配置完成 ==="); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/config/MqttPropertiesTest.java b/jczxw-java/src/test/java/com/gxwebsoft/config/MqttPropertiesTest.java new file mode 100644 index 0000000..7570f9a --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/config/MqttPropertiesTest.java @@ -0,0 +1,44 @@ +package com.gxwebsoft.config; + +import com.gxwebsoft.common.core.config.MqttProperties; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import javax.annotation.Resource; + +/** + * MQTT配置属性测试类 + * + * @author 科技小王子 + * @since 2025-07-02 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class MqttPropertiesTest { + + @Resource + private MqttProperties mqttProperties; + + @Test + public void testMqttPropertiesLoading() { + System.out.println("=== MQTT配置属性测试 ==="); + System.out.println("Host: " + mqttProperties.getHost()); + System.out.println("Username: " + mqttProperties.getUsername()); + System.out.println("Password: " + (mqttProperties.getPassword() != null ? "***" : "null")); + System.out.println("ClientIdPrefix: " + mqttProperties.getClientIdPrefix()); + System.out.println("Topic: " + mqttProperties.getTopic()); + System.out.println("QoS: " + mqttProperties.getQos()); + System.out.println("ConnectionTimeout: " + mqttProperties.getConnectionTimeout()); + System.out.println("KeepAliveInterval: " + mqttProperties.getKeepAliveInterval()); + System.out.println("AutoReconnect: " + mqttProperties.isAutoReconnect()); + System.out.println("CleanSession: " + mqttProperties.isCleanSession()); + + // 验证关键配置不为空 + assert mqttProperties.getHost() != null : "Host不能为空"; + assert mqttProperties.getClientIdPrefix() != null : "ClientIdPrefix不能为空"; + assert mqttProperties.getTopic() != null : "Topic不能为空"; + + System.out.println("MQTT配置属性测试通过!"); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java b/jczxw-java/src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java new file mode 100644 index 0000000..a85bbb9 --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.config; + +import com.gxwebsoft.common.core.config.ConfigProperties; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 服务器URL配置测试 + * 验证server-url配置是否正确从配置文件读取 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class ServerUrlConfigTest { + + @Autowired + private ConfigProperties configProperties; + + @Test + public void testServerUrlConfiguration() { + // 验证配置属性不为空 + assertNotNull(configProperties, "ConfigProperties should not be null"); + + // 验证server-url配置正确读取 + String serverUrl = configProperties.getServerUrl(); + assertNotNull(serverUrl, "Server URL should not be null"); + assertFalse(serverUrl.isEmpty(), "Server URL should not be empty"); + + // 在开发环境下,应该是本地地址 + assertTrue(serverUrl.contains("127.0.0.1") || serverUrl.contains("localhost"), + "In dev environment, server URL should contain localhost or 127.0.0.1"); + + System.out.println("当前配置的服务器URL: " + serverUrl); + } + + @Test + public void testServerUrlFormat() { + String serverUrl = configProperties.getServerUrl(); + + // 验证URL格式 + assertTrue(serverUrl.startsWith("http://") || serverUrl.startsWith("https://"), + "Server URL should start with http:// or https://"); + assertTrue(serverUrl.endsWith("/api"), + "Server URL should end with /api"); + + System.out.println("服务器URL格式验证通过: " + serverUrl); + } +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/generator/ShopGenerator.java b/jczxw-java/src/test/java/com/gxwebsoft/generator/ShopGenerator.java new file mode 100644 index 0000000..9d1224c --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/generator/ShopGenerator.java @@ -0,0 +1,435 @@ +package com.gxwebsoft.generator; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.InjectionConfig; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.gxwebsoft.generator.engine.BeetlTemplateEnginePlus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * CMS模块-代码生成工具 + * + * @author WebSoft + * @since 2021-09-05 00:31:14 + */ +public class ShopGenerator { + // 输出位置 + private static final String OUTPUT_LOCATION = System.getProperty("user.dir"); + //private static final String OUTPUT_LOCATION = "D:/codegen"; // 不想生成到项目中可以写磁盘路径 + // JAVA输出目录 + private static final String OUTPUT_DIR = "/src/main/java"; + // Vue文件输出位置 + private static final String OUTPUT_LOCATION_VUE = "/Users/gxwebsoft/VUE/mp-vue"; + // UniApp文件输出目录 + private static final String OUTPUT_LOCATION_UNIAPP = "/Users/gxwebsoft/VUE/template-10550"; + // Vue文件输出目录 + private static final String OUTPUT_DIR_VUE = "/src"; + // 作者名称 + private static final String AUTHOR = "科技小王子"; + // 是否在xml中添加二级缓存配置 + private static final boolean ENABLE_CACHE = false; + // 数据库连接配置 + private static final String DB_URL = "jdbc:mysql://8.134.169.209:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"; + private static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver"; + private static final String DB_USERNAME = "modules"; + private static final String DB_PASSWORD = "8YdLnk7KsPAyDXGA"; + // 包名 + private static final String PACKAGE_NAME = "com.gxwebsoft"; + // 模块名 + private static final String MODULE_NAME = "shop"; + // 需要生成的表 + private static final String[] TABLE_NAMES = new String[]{ +// "shop_spec", +// "shop_spec_value", +// "shop_goods", +// "shop_category", +// "shop_goods_spec", +// "shop_goods_sku", +// "shop_goods_category", +// "shop_coupon", +// "shop_goods_description", +// "shop_goods_log", +// "shop_goods_relation", +// "shop_goods_comment", +// "shop_goods_rule", +// "shop_brand", +// "shop_merchant", +// "shop_merchant_type", +// "shop_merchant_apply", +// "shop_merchant_account", +// "shop_chat_message", +// "shop_chat_conversation", +// "shop_user_collection", +// "shop_goods_role_commission" +// "shop_commission_role" +// "shop_order", +// "shop_order_info", +// "shop_order_info_log", +// "shop_order_goods", +// "shop_wechat_deposit", +// "shop_users", +// "shop_user_address", +// "shop_user_balance_log", +// "shop_recharge_order", + // 经销商表 +// "shop_dealer_apply", +// "shop_dealer_capital", +// "shop_dealer_order", +// "shop_dealer_referee", +// "shop_dealer_setting", +// "shop_dealer_user", +// "shop_user_referee", +// "shop_dealer_withdraw", +// "shop_user_coupon", +// "shop_cart", +// "shop_count", +// "shop_order_delivery", +// "shop_order_delivery_goods", +// "shop_order_extract", +// "shop_splash", +// "shop_goods_income_config" +// "shop_express", +// "shop_express_template", +// "shop_express_template_detail", +// "shop_gift" + "shop_article" + }; + // 需要去除的表前缀 + private static final String[] TABLE_PREFIX = new String[]{ + "tb_" + }; + // 不需要作为查询参数的字段 + private static final String[] PARAM_EXCLUDE_FIELDS = new String[]{ + "tenant_id", + "create_time", + "update_time" + }; + // 查询参数使用String的类型 + private static final String[] PARAM_TO_STRING_TYPE = new String[]{ + "Date", + "LocalDate", + "LocalTime", + "LocalDateTime" + }; + // 查询参数使用EQ的类型 + private static final String[] PARAM_EQ_TYPE = new String[]{ + "Integer", + "Boolean", + "BigDecimal" + }; + // 是否添加权限注解 + private static final boolean AUTH_ANNOTATION = true; + // 是否添加日志注解 + private static final boolean LOG_ANNOTATION = true; + // controller的mapping前缀 + private static final String CONTROLLER_MAPPING_PREFIX = "/api"; + // 模板所在位置 + private static final String TEMPLATES_DIR = "/src/test/java/com/gxwebsoft/generator/templates"; + + public static void main(String[] args) { + // 代码生成器 + AutoGenerator mpg = new AutoGenerator(); + + // 全局配置 + GlobalConfig gc = new GlobalConfig(); + gc.setOutputDir(OUTPUT_LOCATION + OUTPUT_DIR); + gc.setAuthor(AUTHOR); + gc.setOpen(false); + gc.setFileOverride(true); + gc.setEnableCache(ENABLE_CACHE); + gc.setSwagger2(true); + gc.setIdType(IdType.AUTO); + gc.setServiceName("%sService"); + mpg.setGlobalConfig(gc); + + // 数据源配置 + DataSourceConfig dsc = new DataSourceConfig(); + dsc.setUrl(DB_URL); + // dsc.setSchemaName("public"); + dsc.setDriverName(DB_DRIVER); + dsc.setUsername(DB_USERNAME); + dsc.setPassword(DB_PASSWORD); + mpg.setDataSource(dsc); + + // 包配置 + PackageConfig pc = new PackageConfig(); + pc.setModuleName(MODULE_NAME); + pc.setParent(PACKAGE_NAME); + mpg.setPackageInfo(pc); + + // 策略配置 + StrategyConfig strategy = new StrategyConfig(); + strategy.setNaming(NamingStrategy.underline_to_camel); + strategy.setColumnNaming(NamingStrategy.underline_to_camel); + strategy.setInclude(TABLE_NAMES); + strategy.setTablePrefix(TABLE_PREFIX); + strategy.setSuperControllerClass(PACKAGE_NAME + ".common.core.web.BaseController"); + strategy.setEntityLombokModel(true); + strategy.setRestControllerStyle(true); + strategy.setControllerMappingHyphenStyle(true); + strategy.setLogicDeleteFieldName("deleted"); + mpg.setStrategy(strategy); + + // 模板配置 + TemplateConfig templateConfig = new TemplateConfig(); + templateConfig.setController(TEMPLATES_DIR + "/controller.java"); + templateConfig.setEntity(TEMPLATES_DIR + "/entity.java"); + templateConfig.setMapper(TEMPLATES_DIR + "/mapper.java"); + templateConfig.setXml(TEMPLATES_DIR + "/mapper.xml"); + templateConfig.setService(TEMPLATES_DIR + "/service.java"); + templateConfig.setServiceImpl(TEMPLATES_DIR + "/serviceImpl.java"); + mpg.setTemplate(templateConfig); + mpg.setTemplateEngine(new BeetlTemplateEnginePlus()); + + // 自定义模板配置 + InjectionConfig cfg = new InjectionConfig() { + @Override + public void initMap() { + Map map = new HashMap<>(); + map.put("packageName", PACKAGE_NAME); + map.put("paramExcludeFields", PARAM_EXCLUDE_FIELDS); + map.put("paramToStringType", PARAM_TO_STRING_TYPE); + map.put("paramEqType", PARAM_EQ_TYPE); + map.put("authAnnotation", AUTH_ANNOTATION); + map.put("logAnnotation", LOG_ANNOTATION); + map.put("controllerMappingPrefix", CONTROLLER_MAPPING_PREFIX); + // 添加项目类型标识,用于模板中的条件判断 + map.put("isUniApp", false); // Vue 项目 + map.put("isVueAdmin", true); // 后台管理项目 + this.setMap(map); + } + }; + String templatePath = TEMPLATES_DIR + "/param.java.btl"; + List focList = new ArrayList<>(); + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION + OUTPUT_DIR + "/" + + PACKAGE_NAME.replace(".", "/") + + "/" + pc.getModuleName() + "/param/" + + tableInfo.getEntityName() + "Param" + StringPool.DOT_JAVA; + } + }); + /** + * 以下是生成VUE项目代码 + * 生成文件的路径 /api/shop/goods/index.ts + */ + templatePath = TEMPLATES_DIR + "/index.ts.btl"; + + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.ts"; + } + }); + // UniApp 使用专门的模板 + String uniappTemplatePath = TEMPLATES_DIR + "/index.ts.uniapp.btl"; + focList.add(new FileOutConfig(uniappTemplatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.ts"; + } + }); + // 生成TS文件 (/api/shop/goods/model/index.ts) + templatePath = TEMPLATES_DIR + "/model.ts.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/model/" + "index.ts"; + } + }); + // UniApp 使用专门的 model 模板 + String uniappModelTemplatePath = TEMPLATES_DIR + "/model.ts.uniapp.btl"; + focList.add(new FileOutConfig(uniappModelTemplatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/api/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/model/" + "index.ts"; + } + }); + // 生成Vue文件(/views/shop/goods/index.vue) + templatePath = TEMPLATES_DIR + "/index.vue.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/views/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.vue"; + } + }); + + // 生成components文件(/views/shop/goods/components/edit.vue) + templatePath = TEMPLATES_DIR + "/components.edit.vue.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/views/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/components/" + tableInfo.getEntityPath() + "Edit.vue"; + } + }); + + // 生成components文件(/views/shop/goods/components/search.vue) + templatePath = TEMPLATES_DIR + "/components.search.vue.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE + + "/views/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/components/" + "search.vue"; + } + }); + + // ========== 移动端页面文件生成 ========== + // 生成移动端列表页面配置文件 (/src/shop/goods/index.config.ts) + templatePath = TEMPLATES_DIR + "/index.config.ts.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.config.ts"; + } + }); + + // 生成移动端列表页面组件文件 (/src/shop/goods/index.tsx) + templatePath = TEMPLATES_DIR + "/index.tsx.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "index.tsx"; + } + }); + + // 生成移动端新增/编辑页面配置文件 (/src/shop/goods/add.config.ts) + templatePath = TEMPLATES_DIR + "/add.config.ts.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "add.config.ts"; + } + }); + + // 生成移动端新增/编辑页面组件文件 (/src/shop/goods/add.tsx) + templatePath = TEMPLATES_DIR + "/add.tsx.btl"; + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + + "/" + pc.getModuleName() + "/" + + tableInfo.getEntityPath() + "/" + "add.tsx"; + } + }); + + cfg.setFileOutConfigList(focList); + mpg.setCfg(cfg); + + mpg.execute(); + + // 自动更新 app.config.ts + updateAppConfig(TABLE_NAMES, MODULE_NAME); + } + + /** + * 自动更新 app.config.ts 文件,添加新生成的页面路径 + */ + private static void updateAppConfig(String[] tableNames, String moduleName) { + String appConfigPath = OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + "/app.config.ts"; + + try { + // 读取原文件内容 + String content = new String(Files.readAllBytes(Paths.get(appConfigPath))); + + // 为每个表生成页面路径 + StringBuilder newPages = new StringBuilder(); + for (String tableName : tableNames) { + String entityPath = tableName.replaceAll("_", ""); + // 转换为驼峰命名 + String[] parts = tableName.split("_"); + StringBuilder camelCase = new StringBuilder(parts[0]); + for (int i = 1; i < parts.length; i++) { + camelCase.append(parts[i].substring(0, 1).toUpperCase()).append(parts[i].substring(1)); + } + entityPath = camelCase.toString(); + + newPages.append(" '").append(entityPath).append("/index',\n"); + newPages.append(" '").append(entityPath).append("/add',\n"); + } + + // 查找对应模块的子包配置 + String modulePattern = "\"root\":\\s*\"" + moduleName + "\",\\s*\"pages\":\\s*\\[([^\\]]*)]"; + Pattern pattern = Pattern.compile(modulePattern, Pattern.DOTALL); + Matcher matcher = pattern.matcher(content); + + if (matcher.find()) { + String existingPages = matcher.group(1); + + // 检查页面是否已存在,避免重复添加 + boolean needUpdate = false; + String[] newPageArray = newPages.toString().split("\n"); + for (String newPage : newPageArray) { + if (!newPage.trim().isEmpty() && !existingPages.contains(newPage.trim().replace(" ", "").replace(",", ""))) { + needUpdate = true; + break; + } + } + + if (needUpdate) { + // 备份原文件 + String backupPath = appConfigPath + ".backup." + System.currentTimeMillis(); + Files.copy(Paths.get(appConfigPath), Paths.get(backupPath)); + System.out.println("已备份原文件到: " + backupPath); + + // 在现有页面列表末尾添加新页面 + String updatedPages = existingPages.trim(); + if (!updatedPages.endsWith(",")) { + updatedPages += ","; + } + updatedPages += "\n" + newPages.toString().trim(); + + // 替换内容 + String updatedContent = content.replace(matcher.group(1), updatedPages); + + // 写入更新后的内容 + Files.write(Paths.get(appConfigPath), updatedContent.getBytes()); + + System.out.println("✅ 已自动更新 app.config.ts,添加了以下页面路径:"); + System.out.println(newPages.toString()); + } else { + System.out.println("ℹ️ app.config.ts 中已包含所有页面路径,无需更新"); + } + } else { + System.out.println("⚠️ 未找到 " + moduleName + " 模块的子包配置,请手动添加页面路径"); + } + + } catch (Exception e) { + System.err.println("❌ 更新 app.config.ts 失败: " + e.getMessage()); + e.printStackTrace(); + } + } + +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/generator/engine/BeetlTemplateEnginePlus.java b/jczxw-java/src/test/java/com/gxwebsoft/generator/engine/BeetlTemplateEnginePlus.java new file mode 100644 index 0000000..1a73826 --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/generator/engine/BeetlTemplateEnginePlus.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.generator.engine; + +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder; +import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine; +import org.beetl.core.Configuration; +import org.beetl.core.GroupTemplate; +import org.beetl.core.Template; +import org.beetl.core.resource.FileResourceLoader; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Map; + +/** + * Beetl模板引擎实现文件输出 + * + * @author WebSoft + * @since 2021-09-05 00:30:28 + */ +public class BeetlTemplateEnginePlus extends AbstractTemplateEngine { + private GroupTemplate groupTemplate; + + @Override + public AbstractTemplateEngine init(ConfigBuilder configBuilder) { + super.init(configBuilder); + try { + Configuration cfg = Configuration.defaultConfiguration(); + groupTemplate = new GroupTemplate(new FileResourceLoader(), cfg); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return this; + } + + @Override + public void writer(Map objectMap, String templatePath, String outputFile) throws Exception { + Template template = groupTemplate.getTemplate(templatePath); + try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) { + template.binding(objectMap); + template.renderTo(fileOutputStream); + } + logger.debug("模板:" + templatePath + "; 文件:" + outputFile); + } + + @Override + public String templateFilePath(String filePath) { + return filePath + ".btl"; + } + +} diff --git a/jczxw-java/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl b/jczxw-java/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl new file mode 100644 index 0000000..a93cafd --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '新增${table.comment!'数据'}', + navigationBarTextStyle: 'black' +}) diff --git a/jczxw-java/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl b/jczxw-java/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl new file mode 100644 index 0000000..73055da --- /dev/null +++ b/jczxw-java/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl @@ -0,0 +1,115 @@ +import {useEffect, useState, useRef} from "react"; +import {useRouter} from '@tarojs/taro' +import {Button, Loading, CellGroup, Input, TextArea, Form} from '@nutui/nutui-react-taro' +import Taro from '@tarojs/taro' +import {View} from '@tarojs/components' +import {${entity}} from "@/api/${package.ModuleName}/${table.entityPath}/model"; +import {get${entity}, list${entity}, update${entity}, add${entity}} from "@/api/${package.ModuleName}/${table.entityPath}"; + +const Add${entity} = () => { + const {params} = useRouter(); + const [loading, setLoading] = useState(true) + const [FormData, setFormData] = useState<${entity}>({}) + const formRef = useRef(null) + + const reload = async () => { + if (params.id) { + const data = await get${entity}(Number(params.id)) + setFormData(data) + } else { + setFormData({}) + } + } + + // 提交表单 + const submitSucceed = async (values: any) => { + try { + if (params.id) { + // 编辑模式 + await update${entity}({ + ...values, + id: Number(params.id) + }) + } else { + // 新增模式 + await add${entity}(values) + } + + Taro.showToast({ + title: `操作成功`, + icon: 'success' + }) + + setTimeout(() => { + return Taro.navigateBack() + }, 1000) + } catch (error) { + Taro.showToast({ + title: `操作失败`, + icon: 'error' + }); + } + } + + const submitFailed = (error: any) => { + console.log(error, 'err...') + } + + useEffect(() => { + reload().then(() => { + setLoading(false) + }) + }, []); + + if (loading) { + return 加载中 + } + + return ( + <> +
submitSucceed(values)} + onFinishFailed={(errors) => submitFailed(errors)} + footer={ +
+ +
+ } + > + +<% for(field in table.fields){ %> +<% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime'){ %> + +<% if(field.propertyType == 'String' && field.comment?? && (field.comment?contains('描述') || field.comment?contains('备注') || field.comment?contains('内容'))){ %> +