29 Commits

Author SHA1 Message Date
MichaelWin
1a726b8b7d 【改进】使用内网环境 2026-03-16 10:08:31 +08:00
8f5f998c3a Merge remote-tracking branch 'origin/main' 2026-03-16 10:03:52 +08:00
37182d7efb 【新增】Sirius固件查询接口及API文档
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 10:02:38 +08:00
MichaelWin
e472a3207f 【改进】查询固件版本增加当前版本参数 2026-03-06 14:58:52 +08:00
MichaelWin
c0896c199d 【新增】根据类型,型号查询固件版本 2026-03-06 14:08:11 +08:00
MichaelWin
ccfac2a9eb Merge remote-tracking branch 'origin/main' 2026-03-06 11:29:30 +08:00
MichaelWin
84594dda48 【新增】固件版本升级校验 2026-03-06 11:28:40 +08:00
MichaelWin
da144b7c6a 【改进】全局异常捕获 2026-03-06 11:28:15 +08:00
306222c55e 新增产品QC 2026-02-28 13:32:29 +08:00
MichaelWin
bd3523fd3d 测试 2026-02-27 18:33:44 +08:00
fa16fec0a0 新增产品QC 2026-02-27 17:41:08 +08:00
MichaelWin
7d5a62f8f2 【改进】不拦截工厂激活接口 2026-02-26 09:12:51 +08:00
MichaelWin
2ac80ae4d0 【新增】活动 2026-02-25 18:52:42 +08:00
MichaelWin
e5e540305d 【新增】用户设备激活,工厂设备激活 2026-02-25 18:52:34 +08:00
MichaelWin
16626af8f2 【改进】产品分页 2026-02-11 15:58:40 +08:00
MichaelWin
70fbd1ad07 【改进】APP登出日志 2026-02-10 15:24:46 +08:00
MichaelWin
bd304cee09 【新增】APP登录登出日志 2026-02-10 15:15:39 +08:00
MichaelWin
0118b5a84e 【改进】获取当前用户数据接口 2026-02-10 09:41:42 +08:00
MichaelWin
db39b2092c 【改进】线上环境 2026-02-09 18:52:24 +08:00
MichaelWin
4928db5287 【新增】接口操作,登录,登出日志 2026-02-09 18:50:29 +08:00
MichaelWin
f6c3326c4a 【新增】使用线上环境 2026-02-09 16:24:32 +08:00
MichaelWin
1c1f407d27 【新增】运行日志 2026-02-09 16:22:19 +08:00
MichaelWin
facff46bb6 【改进】参数中心增加次数下载限制 2026-02-09 12:32:23 +08:00
MichaelWin
71589ab13a 【改进】短信发送增加次数验证 2026-02-09 12:24:31 +08:00
MichaelWin
edbcf2729b 【改进】分页 2026-02-09 09:34:47 +08:00
MichaelWin
476ea60b27 【新增】资源排序 2026-02-05 21:32:00 +08:00
MichaelWin
740a343863 【新增】公开资源接口 2026-02-05 17:58:16 +08:00
MichaelWin
a76d954979 【新增】资源接口 2026-02-05 17:57:50 +08:00
MichaelWin
ecbb2e993c 【新增】资源分类接口 2026-02-05 17:57:39 +08:00
122 changed files with 5104 additions and 187 deletions

2
.gitignore vendored
View File

@@ -16,7 +16,7 @@ build/
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
logs
### IntelliJ IDEA ###
.idea
*.iws

View File

@@ -29,6 +29,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc' // JDBC 支持
implementation 'org.springframework.boot:spring-boot-starter-web' // Web MVC
implementation 'org.springframework.boot:spring-boot-starter-validation' // 参数校验
implementation 'org.springframework.boot:spring-boot-starter-aop' // AOP
implementation 'org.springframework.boot:spring-boot-starter-mail' // 邮件发送
implementation 'com.baomidou:mybatis-plus-boot-starter' // MyBatis Plus
implementation 'com.baomidou:mybatis-plus-generator' // 代码生成器

View File

@@ -0,0 +1,346 @@
# Sirius 固件 API 接口文档
## 基本信息
- **Base URL**: `https://api.corewing.com`
- **接口前缀**: `/sirius_firmware`
## 统一响应格式
```json
{
"code": 200,
"message": "操作成功",
"data": {},
"success": true
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| code | Integer | 状态码200 成功500 失败) |
| message | String | 提示消息 |
| data | Object | 返回数据 |
| success | Boolean | 是否成功 |
## 枚举说明
### 固件类型firmwareType
| 值 | 说明 |
|----|------|
| 1 | 高频头 |
| 2 | 接收机 |
| 3 | 背包 |
### 协议类型protocolType
| 值 | 说明 |
|----|------|
| 1 | ELRS |
| 2 | CWLink |
## 固件对象字段说明
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Integer | 主键ID |
| firmwareType | Integer | 固件类型1-高频头2-接收机3-背包 |
| protocolType | Integer | 协议类型1-ELRS2-CWLink |
| versionNumber | String | 版本号,如 v3.0.1 |
| fileName | String | 文件名 |
| filePath | String | 文件存储路径 |
| fileSize | Long | 文件大小(字节) |
| md5Hash | String | MD5 校验值 |
| releaseNotes | String | 版本更新说明(可能为 null |
| createTime | String | 创建时间 |
| updateTime | String | 更新时间 |
---
## 1. 查询最新固件版本
**接口描述:** 根据固件类型和协议类型查询最新版本,用于设备端检查更新。
**请求方式:** `GET`
**请求路径:** `/sirius_firmware/latest`
**请求参数:**
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| firmwareType | Integer | 是 | 固件类型1-高频头2-接收机3-背包 |
| protocolType | Integer | 是 | 协议类型1-ELRS2-CWLink |
**请求示例:**
```bash
curl -X GET "http://your-server-host:8080/sirius_firmware/latest?firmwareType=1&protocolType=1"
```
**成功响应示例:**
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"firmwareType": 1,
"protocolType": 1,
"versionNumber": "v3.0.1",
"fileName": "sirius_hf_elrs_v3.0.1.bin",
"filePath": "https://oss.corewing.com/sirius_firmware/sirius_hf_elrs_v3.0.1.bin",
"fileSize": 1048576,
"md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
"releaseNotes": "优化信号连接稳定性",
"createTime": "2026-03-10 10:30:00",
"updateTime": "2026-03-10 10:30:00"
},
"success": true
}
```
**失败响应示例:**
```json
{
"code": 500,
"message": "固件不存在",
"data": null,
"success": false
}
```
---
## 2. 根据固件类型查询版本列表
**接口描述:** 查询指定固件类型下所有版本,按时间倒序排列。
**请求方式:** `GET`
**请求路径:** `/sirius_firmware/type/{firmwareType}`
**路径参数:**
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| firmwareType | Integer | 是 | 固件类型1-高频头2-接收机3-背包 |
**请求示例:**
```bash
curl -X GET "http://your-server-host:8080/sirius_firmware/type/1"
```
**成功响应示例:**
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 3,
"firmwareType": 1,
"protocolType": 2,
"versionNumber": "v2.1.0",
"fileName": "sirius_hf_cwlink_v2.1.0.bin",
"filePath": "https://oss.corewing.com/sirius_firmware/sirius_hf_cwlink_v2.1.0.bin",
"fileSize": 2097152,
"md5Hash": "098f6bcd4621d373cade4e832627b4f6",
"releaseNotes": "新增CWLink协议支持",
"createTime": "2026-03-12 14:00:00",
"updateTime": "2026-03-12 14:00:00"
},
{
"id": 1,
"firmwareType": 1,
"protocolType": 1,
"versionNumber": "v3.0.1",
"fileName": "sirius_hf_elrs_v3.0.1.bin",
"filePath": "https://oss.corewing.com/sirius_firmware/sirius_hf_elrs_v3.0.1.bin",
"fileSize": 1048576,
"md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
"releaseNotes": "优化信号连接稳定性",
"createTime": "2026-03-10 10:30:00",
"updateTime": "2026-03-10 10:30:00"
}
],
"success": true
}
```
---
## 3. 根据固件类型和协议类型查询版本列表
**接口描述:** 查询指定固件类型和协议类型下所有版本,按时间倒序排列。
**请求方式:** `GET`
**请求路径:** `/sirius_firmware/type/{firmwareType}/protocol/{protocolType}`
**路径参数:**
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| firmwareType | Integer | 是 | 固件类型1-高频头2-接收机3-背包 |
| protocolType | Integer | 是 | 协议类型1-ELRS2-CWLink |
**请求示例:**
```bash
curl -X GET "http://your-server-host:8080/sirius_firmware/type/1/protocol/1"
```
**成功响应示例:**
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 5,
"firmwareType": 1,
"protocolType": 1,
"versionNumber": "v3.0.1",
"fileName": "sirius_hf_elrs_v3.0.1.bin",
"filePath": "https://oss.corewing.com/sirius_firmware/sirius_hf_elrs_v3.0.1.bin",
"fileSize": 1048576,
"md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
"releaseNotes": "优化信号连接稳定性",
"createTime": "2026-03-12 14:00:00",
"updateTime": "2026-03-12 14:00:00"
},
{
"id": 2,
"firmwareType": 1,
"protocolType": 1,
"versionNumber": "v3.0.0",
"fileName": "sirius_hf_elrs_v3.0.0.bin",
"filePath": "https://oss.corewing.com/sirius_firmware/sirius_hf_elrs_v3.0.0.bin",
"fileSize": 1024000,
"md5Hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
"releaseNotes": null,
"createTime": "2026-03-01 08:00:00",
"updateTime": "2026-03-01 08:00:00"
}
],
"success": true
}
```
---
## 4. 查询所有固件
**接口描述:** 查询所有固件记录。
**请求方式:** `GET`
**请求路径:** `/sirius_firmware/list`
**请求示例:**
```bash
curl -X GET "http://your-server-host:8080/sirius_firmware/list"
```
**成功响应示例:**
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 1,
"firmwareType": 1,
"protocolType": 1,
"versionNumber": "v3.0.1",
"fileName": "sirius_hf_elrs_v3.0.1.bin",
"filePath": "https://oss.corewing.com/sirius_firmware/sirius_hf_elrs_v3.0.1.bin",
"fileSize": 1048576,
"md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
"releaseNotes": "优化信号连接稳定性",
"createTime": "2026-03-10 10:30:00",
"updateTime": "2026-03-10 10:30:00"
}
],
"success": true
}
```
---
## 5. 根据ID查询固件
**接口描述:** 根据固件ID查询详情。
**请求方式:** `GET`
**请求路径:** `/sirius_firmware/{id}`
**路径参数:**
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Integer | 是 | 固件ID |
**请求示例:**
```bash
curl -X GET "http://your-server-host:8080/sirius_firmware/1"
```
**成功响应示例:**
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"firmwareType": 1,
"protocolType": 1,
"versionNumber": "v3.0.1",
"fileName": "sirius_hf_elrs_v3.0.1.bin",
"filePath": "https://oss.corewing.com/sirius_firmware/sirius_hf_elrs_v3.0.1.bin",
"fileSize": 1048576,
"md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
"releaseNotes": "优化信号连接稳定性",
"createTime": "2026-03-10 10:30:00",
"updateTime": "2026-03-10 10:30:00"
},
"success": true
}
```
**失败响应示例:**
```json
{
"code": 500,
"message": "固件不存在",
"data": null,
"success": false
}
```
---
## 接口总览
| 方法 | 路径 | 说明 | 使用场景 |
|------|------|------|----------|
| GET | `/sirius_firmware/latest?firmwareType=&protocolType=` | 查询最新版本 | 设备端检查更新 |
| GET | `/sirius_firmware/type/{firmwareType}` | 按固件类型查版本列表 | 查看某类固件所有版本 |
| GET | `/sirius_firmware/type/{firmwareType}/protocol/{protocolType}` | 按类型+协议查版本列表 | 精确筛选版本列表 |
| GET | `/sirius_firmware/list` | 查询所有固件 | 管理端展示全部数据 |
| GET | `/sirius_firmware/{id}` | 按ID查询固件 | 查看固件详情 |
---

303
docs/backend-api.md Normal file
View File

@@ -0,0 +1,303 @@
# Corewing QC 后端接口文档
> 基础路径: `/api/qc`
## 通用响应结构
所有接口统一返回 `Result<T>`:
```json
{
"code": 200,
"message": "操作成功",
"data": T,
"success": true
}
```
| 字段 | 类型 | 说明 |
|---------|---------|---------------------------|
| code | Integer | 状态码 |
| message | String | 消息内容 |
| data | T | 业务数据 |
| success | Boolean | 是否成功 |
---
## 1. 验证无线板
验证 BLE MAC 地址对应的无线板是否已在系统中注册。
- **URL**: `POST /api/qc/wireless/validate-wireless`
- **Content-Type**: `application/json`
### 请求体
```json
{
"mac": "AA:BB:CC:DD:EE:FF"
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|--------|------|----------------------------------|
| mac | String | 是 | BLE MAC 地址,即设备 SN |
### 响应
```json
{
"code": 200,
"message": "验证通过",
"data": true,
"success": true
}
```
- `data = true` — 设备已注册,允许进行 QC 测试
- `data = false` / `success = false` — 设备未注册或验证失败APP 端将**作废本次测试**
---
## 2. 上传测试记录
上传完整的 QC 测试结果(含所有步骤数据和照片 URL
- **URL**: `POST /api/qc/test/upload`
- **Content-Type**: `application/json`
### 请求体
```json
{
"testNo": "WL-20260227-001",
"productType": "WIRELESS_BOARD",
"sn": "AA:BB:CC:DD:EE:FF",
"operatorId": "OP001",
"operatorName": "张三",
"phoneModel": "Pixel 7",
"appVersion": "1.0.0",
"status": "PASS",
"createTime": "1740000000000",
"updatedAt": "1740001000000",
"uploadTime": "1740002000000",
"steps": [
{
"stepIndex": 1,
"stepName": "BLE连接与特征订阅",
"result": "PASS",
"dataJson": "{\"deviceName\":\"CoreWing-001\",\"deviceMac\":\"AA:BB:CC:DD:EE:FF\",\"validated\":true}",
"duration": 5200,
"completedAt": "1740000500000"
}
],
"photoUrls": [
"https://qc.corewing.com/photos/xxx.jpg"
]
}
```
| 字段 | 类型 | 必填 | 说明 |
|--------------|------------------|------|------------------------------------------------|
| testNo | String | 是 | 测试单号,格式: `WL-yyyyMMdd-NNN``FC-yyyyMMdd-NNN` |
| productType | String | 是 | `WIRELESS_BOARD` / `FLIGHT_CONTROLLER` |
| sn | String | 是 | 产品序列号(无线板为 BLE MAC 地址) |
| operatorId | String | 是 | 测试员 ID |
| operatorName | String | 是 | 测试员姓名 |
| phoneModel | String | 否 | 测试手机型号 |
| appVersion | String | 否 | APP 版本号 |
| status | String | 是 | `PASS` / `FAIL` |
| createTime | String | 是 | 创建时间(毫秒时间戳字符串) |
| updatedAt | String | 否 | 最后更新时间(毫秒时间戳字符串) |
| uploadTime | String | 否 | 上传时间(毫秒时间戳字符串) |
| steps | StepResultData[] | 是 | 步骤结果数组 |
| photoUrls | String[] | 否 | 已上传照片的远程 URL 列表 |
**StepResultData:**
| 字段 | 类型 | 必填 | 说明 |
|-------------|--------|------|--------------------------------------|
| stepIndex | int | 是 | 步骤序号(从 1 开始) |
| stepName | String | 是 | 步骤名称 |
| result | String | 否 | `PASS` / `FAIL` / null未完成 |
| dataJson | String | 否 | 步骤详细数据 JSON 字符串 |
| duration | long | 否 | 步骤耗时(毫秒) |
| completedAt | String | 否 | 完成时间(毫秒时间戳字符串) |
### 响应
```json
{
"code": 200,
"message": "上传成功",
"data": "https://qc.corewing.com/report/WL-20260227-001",
"success": true
}
```
- `data` — 测试报告 URL可为 null
---
## 3. 上传照片
上传测试步骤关联的照片。
- **URL**: `POST /api/qc/test/upload-photo`
- **Content-Type**: `multipart/form-data`
### 请求参数
| 字段 | 类型 | 必填 | 说明 |
|--------|---------------|------|------------------|
| testNo | String (text) | 是 | 测试单号 |
| photo | File | 是 | 照片文件 (JPEG等)|
### 响应
```json
{
"code": 200,
"message": "上传成功",
"data": {
"url": "https://qc.corewing.com/photos/xxx.jpg"
},
"success": true
}
```
---
## 4. 验证 SN
验证序列号是否有效(飞控板扫码流程使用)。
- **URL**: `POST /api/qc/test/validate-sn`
- **Content-Type**: `application/json`
### 请求体
```json
{
"sn": "FC-SN-20260001"
}
```
### 响应
```json
{
"code": 200,
"message": "SN 有效",
"data": true,
"success": true
}
```
---
## 5. 获取测试配置
获取指定产品类型的测试参数/阈值。
- **URL**: `GET /api/qc/config/test-params?productType=WIRELESS_BOARD`
### 响应
```json
{
"code": 200,
"success": true,
"data": { }
}
```
> `data` 结构由后端自定义APP 当前未使用。
---
## 6. 查询 SN 历史记录
- **URL**: `GET /api/qc/test/history?sn=AA:BB:CC:DD:EE:FF`
### 响应
```json
{
"code": 200,
"success": true,
"data": { }
}
```
---
## 7. 获取测试报告
- **URL**: `GET /api/qc/test/report?testNo=WL-20260227-001`
### 响应
```json
{
"code": 200,
"success": true,
"data": "https://qc.corewing.com/report/WL-20260227-001"
}
```
---
## 枚举值参考
### productType产品类型
| 值 | 说明 |
|---------------------|--------|
| WIRELESS_BOARD | 无线板 |
| FLIGHT_CONTROLLER | 飞控板 |
### status测试状态
| 值 | 说明 |
|-------------|----------|
| IN_PROGRESS | 进行中 |
| PASS | 通过 |
| FAIL | 失败 |
| UPLOADED | 已上传 |
### result步骤结果
| 值 | 说明 |
|------|------|
| PASS | 通过 |
| FAIL | 失败 |
### 无线板测试步骤7 步)
| stepIndex | stepName |
|-----------|------------------------|
| 1 | BLE连接与特征订阅 |
| 2 | 安装无线板/外观检查 |
| 3 | 供电测试(4.5V) |
| 4 | Type-C USB测试 |
| 5 | BLE信号质量测试 |
| 6 | MAVLink心跳通信测试 |
| 7 | 激活/入库 |
### 飞控板测试步骤12 步)
| stepIndex | stepName |
|-----------|-----------------|
| 1 | USB串口连接 |
| 2 | 安装SD卡与装夹 |
| 3 | 心跳检测 |
| 4 | IMU测试 |
| 5 | 气压计测试 |
| 6 | GPS模块检测 |
| 7 | RC输入测试 |
| 8 | ADC接口测试 |
| 9 | PWM输出测试 |
| 10 | 图传与OSD检查 |
| 11 | 参数重置 |
| 12 | 数据上传/结束 |

116
docs/schema.sql Normal file
View File

@@ -0,0 +1,116 @@
-- ============================================================
-- Corewing QC 后端数据库建表 SQLMySQL
-- ============================================================
CREATE TABLE `flight_controller` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`sn` VARCHAR(64) NOT NULL COMMENT '序列号',
`model` VARCHAR(64) DEFAULT NULL COMMENT '型号',
`batch_no` VARCHAR(64) DEFAULT NULL COMMENT '批次号',
`status` VARCHAR(32) NOT NULL DEFAULT 'REGISTERED' COMMENT '状态: REGISTERED / QC_PASS / QC_FAIL / ACTIVATED',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_sn` (`sn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='飞控板设备注册表';
CREATE TABLE `qc_test_record` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`test_no` VARCHAR(32) NOT NULL COMMENT '测试单号,格式: WL-yyyyMMdd-NNN / FC-yyyyMMdd-NNN',
`product_type` VARCHAR(32) NOT NULL COMMENT '产品类型: WIRELESS_BOARD / FLIGHT_CONTROLLER',
`sn` VARCHAR(64) NOT NULL COMMENT '产品序列号(无线板为 BLE MAC',
`operator_id` VARCHAR(32) NOT NULL COMMENT '测试员 ID',
`operator_name` VARCHAR(64) NOT NULL COMMENT '测试员姓名',
`phone_model` VARCHAR(64) DEFAULT NULL COMMENT '测试手机型号',
`app_version` VARCHAR(16) DEFAULT NULL COMMENT 'APP 版本',
`status` VARCHAR(16) NOT NULL COMMENT '测试结果: PASS / FAIL',
`create_time` DATETIME NOT NULL COMMENT 'APP 端创建时间',
`updated_at` DATETIME DEFAULT NULL COMMENT 'APP 端最后更新时间',
`upload_time` DATETIME DEFAULT NULL COMMENT 'APP 端上传时间',
`report_url` VARCHAR(512) DEFAULT NULL COMMENT '测试报告 URL',
`server_create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '服务端入库时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_test_no` (`test_no`),
KEY `idx_sn` (`sn`),
KEY `idx_product_type` (`product_type`),
KEY `idx_status` (`status`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='QC 测试记录主表';
CREATE TABLE `qc_step_result` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`test_record_id` BIGINT NOT NULL COMMENT '关联 qc_test_record.id',
`step_index` INT NOT NULL COMMENT '步骤序号(从 1 开始)',
`step_name` VARCHAR(64) NOT NULL COMMENT '步骤名称',
`result` VARCHAR(8) DEFAULT NULL COMMENT '步骤结果: PASS / FAIL / NULL',
`data_json` TEXT DEFAULT NULL COMMENT '步骤详细数据 JSON',
`duration` BIGINT DEFAULT 0 COMMENT '步骤耗时(毫秒)',
`completed_at` DATETIME DEFAULT NULL COMMENT '步骤完成时间',
PRIMARY KEY (`id`),
KEY `idx_test_record_id` (`test_record_id`),
UNIQUE KEY `uk_record_step` (`test_record_id`, `step_index`),
CONSTRAINT `fk_step_record` FOREIGN KEY (`test_record_id`)
REFERENCES `qc_test_record` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='QC 步骤结果表';
CREATE TABLE `qc_photo` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`test_record_id` BIGINT NOT NULL COMMENT '关联 qc_test_record.id',
`test_no` VARCHAR(32) NOT NULL COMMENT '测试单号',
`url` VARCHAR(512) NOT NULL COMMENT '照片远程 URL',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_test_no` (`test_no`),
CONSTRAINT `fk_photo_record` FOREIGN KEY (`test_record_id`)
REFERENCES `qc_test_record` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='QC 测试照片表';
-- ============================================================
-- 固件表
-- ============================================================
CREATE TABLE `app_aat_version` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`firmware_type` VARCHAR(50) NOT NULL COMMENT '固件类型: lb_main / lb_signal_master / lbPro_main / lbPro_signal_master / lbPro_screen_ui',
`firmware_name` VARCHAR(100) NOT NULL COMMENT '固件文件名',
`firmware_version` VARCHAR(20) NOT NULL COMMENT '固件版本号',
`min_hardware_version` VARCHAR(20) NOT NULL DEFAULT '0.0' COMMENT '最低硬件版本',
`download_url` VARCHAR(500) DEFAULT NULL COMMENT '固件下载地址',
`firmware_size` BIGINT DEFAULT NULL COMMENT '固件大小(字节)',
`firmware_description` TEXT 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 '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_type_version` (`firmware_type`, `firmware_version`),
KEY `idx_firmware_type` (`firmware_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AAT固件版本表';
-- 插入固件数据
INSERT INTO `app_aat_version` (`firmware_type`, `firmware_name`, `firmware_version`, `min_hardware_version`)
VALUES
-- lb_main
('lb_main', 'lb_main_2.1.bin', '2.1', '1.0'),
-- lb_signal_master
('lb_signal_master', 'lbsm_1.1.bin', '1.1', '0.0'),
-- lbPro_main
('lbPro_main', 'lbPro_main_2.3.bin', '2.3', '0.0'),
-- lbPro_signal_master
('lbPro_signal_master', 'lbPro_sm_1.4.bin', '1.4', '0.0'),
-- lbPro_screen_ui
('lbPro_screen_ui', 'lbPro_ui_2.7.tft', '2.7', '0.0');
-- ============================================================
-- 示例数据(可选)
-- ============================================================
-- 注册一批无线板
-- INSERT INTO `wireless_board` (`mac`) VALUES
-- ('AA:BB:CC:DD:EE:01'),
-- ('AA:BB:CC:DD:EE:02'),
-- ('AA:BB:CC:DD:EE:03');

View File

@@ -0,0 +1,18 @@
package com.corewing.app.common.annotation;
import java.lang.annotation.*;
/**
* 自定义日志注解
*
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CommonLog {
/**
* 日志的名称,例如:"修改菜单"
*/
String value() default "未命名";
}

View File

@@ -0,0 +1,34 @@
package com.corewing.app.common.aspect;
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.corewing.app.util.CommonTraceIdUtil;
import org.springframework.stereotype.Component;
@Component
public class CustomTraceIdConverter extends ClassicConverter {
// 使用常量避免重复创建字符串
private static final String LEFT_BRACKET = "[";
private static final String RIGHT_BRACKET = "]";
// 缓存StringBuilder以减少对象创建
private static final ThreadLocal<StringBuilder> bufferHolder =
ThreadLocal.withInitial(() -> new StringBuilder(64));
@Override
public String convert(ILoggingEvent event) {
StringBuilder buffer = bufferHolder.get();
buffer.setLength(0);
String traceId = CommonTraceIdUtil.getTraceId();
buffer.append(LEFT_BRACKET);
if (traceId != null && !traceId.isEmpty()) {
buffer.append(traceId);
} else {
buffer.append(event.getThreadName());
}
buffer.append(RIGHT_BRACKET);
return buffer.toString();
}
}

View File

@@ -0,0 +1,104 @@
package com.corewing.app.common.aspect;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.entity.User;
import com.corewing.app.service.UserService;
import com.corewing.app.util.DevLogUtil;
import com.corewing.app.util.RedisUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
/**
* 业务日志aop切面
*
*/
@Aspect
@Order
@Component
public class DevLogAop {
@Resource
private RedisUtil redisUtil;
@Resource
private UserService userService;
/**
* 日志切入点
*
* @author xuyuxiang
* @date 2020/3/23 17:10
*/
@Pointcut("@annotation(com.corewing.app.common.annotation.CommonLog)")
private void getLogPointCut() {
}
/**
* 操作成功返回结果记录日志
*
*/
@AfterReturning(pointcut = "getLogPointCut()", returning = "result")
public void doAfterReturning(JoinPoint joinPoint, Object result) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
CommonLog commonLog = method.getAnnotation(CommonLog.class);
String userName = "未知";
String userId = "-1";
try {
try {
if( StpUtil.isLogin()) {
User user = (User) redisUtil.get("APP_" + StpUtil.getLoginId());
userName = user.getUsername();
userId = user.getId().toString();
}
} catch (Exception e) {
User user = userService.getById(StpUtil.getLoginIdAsLong());
userName = user.getUsername();
userId = user.getId().toString();
}
} catch (Exception ignored) {
}
// 异步记录日志
DevLogUtil.executeOperationLog(commonLog, userName, userId, joinPoint, JSONUtil.toJsonStr(result));
}
/**
* 操作发生异常记录日志
*
*/
@AfterThrowing(pointcut = "getLogPointCut()", throwing = "exception")
public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
CommonLog commonLog = method.getAnnotation(CommonLog.class);
String userName = "未知";
String userId = "-1";
try {
if( StpUtil.isLogin()) {
User user = (User) redisUtil.get("APP_" + StpUtil.getLoginId());
userName = user.getUsername();
userId = user.getId().toString();
}
} catch (Exception e) {
User user = userService.getById(StpUtil.getLoginIdAsLong());
userName = user.getUsername();
userId = user.getId().toString();
}
//异步记录日志
DevLogUtil.executeExceptionLog(commonLog, userName, userId, joinPoint, exception);
}
}

View File

@@ -30,6 +30,8 @@ public class SaTokenConfig implements WebMvcConfigurer {
.excludePathPatterns("/user/login", "/user/register", "/user/sendCode", "/user/forgetPassword", "/user/codeLogin")
// 排除后台管理登录接口
.excludePathPatterns("/sys/user/login")
//排除QC接口
.excludePathPatterns("/api/qc/**")
// 排除反馈接口(支持匿名提交)
.excludePathPatterns("/feedback", "/feedback/**")
// 排除教程接口(支持匿名查询)
@@ -38,12 +40,16 @@ public class SaTokenConfig implements WebMvcConfigurer {
.excludePathPatterns("/privacy_policy", "/privacy_policy/**")
// 排除固件查询接口(不需要登录)
.excludePathPatterns("/firmware/**")
// 排除AAT固件版本接口
.excludePathPatterns("/aat_version/**")
// 排除Sirius固件接口
.excludePathPatterns("/sirius_firmware/**")
// 排除公共固件
.excludePathPatterns("/public_firmware/**")
// 排除系统登录页(不需要登录)
// .excludePathPatterns("/loading.html", "/admin/login.html")
// 排除静态资源
.excludePathPatterns("/", "/*.css", "/*.js", "/*.ico", "/static/**", "/assets/**")
.excludePathPatterns("/", "/*.html", "/*.css", "/*.js", "/*.ico", "/static/**", "/assets/**")
// 排除接口静态资源
.excludePathPatterns("/doc.html", "/webjars/**")
.excludePathPatterns("/v3/api-docs/swagger-config", "/v3/api-docs/**", "/swagger-resources")
@@ -57,6 +63,9 @@ public class SaTokenConfig implements WebMvcConfigurer {
.excludePathPatterns("/api/app", "/api/app/getAppVersion")
.excludePathPatterns("/api/website/**")
.excludePathPatterns("/api/app/access_statistics/accumulate")
.excludePathPatterns("/api/app/resource_category/**")
.excludePathPatterns("/api/app/resource/**")
.excludePathPatterns("/api/app/device/factoryActivation")
// 排除模型接口
.excludePathPatterns("/model/page", "/model/list", "/model/detail/**", "/model/category/**")
// 排除咨询接口

View File

@@ -12,4 +12,11 @@ public class DeviceActivationRequest {
@NotBlank(message = "MAC地址不能为空")
private String mac;
@ApiModelProperty(value = "设备型号", required = true)
@NotBlank(message = "设备型号不能为空")
private String modelId;
@ApiModelProperty(value = "时间戳", required = true)
private String timestamp;
}

View File

@@ -0,0 +1,23 @@
package com.corewing.app.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class FirmwareVersionRequest {
@ApiModelProperty(value = "型号id", required = true)
@NotNull(message = "型号不能为空")
private Integer modelId;
@ApiModelProperty(value = "版本号", required = true)
@NotNull(message = "版本号不能为空")
private String version;
@ApiModelProperty(value = "固件类型", required = true)
@NotNull(message = "固件类型不能为空")
private Integer firmwareType;
}

View File

@@ -0,0 +1,7 @@
package com.corewing.app.dto;
import lombok.Data;
@Data
public class ResourceCategoryTreeRequest {
}

View File

@@ -0,0 +1,14 @@
package com.corewing.app.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class ResourcePageRequest {
@ApiModelProperty(value = "搜索参数")
private String searchKey;
@ApiModelProperty(value = "分类id")
private String categoryId;
}

View File

@@ -0,0 +1,19 @@
package com.corewing.app.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class SubmitActivityRequest {
@ApiModelProperty("活动id")
private String activityId;
/* 创作平台 */
@ApiModelProperty("创作平台")
private String creationPlatform;
/* 提交内容 */
@ApiModelProperty("提交内容")
private String content;
}

View File

@@ -0,0 +1,19 @@
package com.corewing.app.dto.qc;
import lombok.Data;
@Data
public class StepResultData {
private Integer stepIndex;
private String stepName;
private String result;
private String dataJson;
private Long duration;
private String completedAt;
}

View File

@@ -0,0 +1,35 @@
package com.corewing.app.dto.qc;
import lombok.Data;
import java.util.List;
@Data
public class UploadTestRecordRequest {
private String testNo;
private String productType;
private String sn;
private String operatorId;
private String operatorName;
private String phoneModel;
private String appVersion;
private String status;
private String createTime;
private String updatedAt;
private String uploadTime;
private List<StepResultData> steps;
private List<String> photoUrls;
}

View File

@@ -0,0 +1,9 @@
package com.corewing.app.dto.qc;
import lombok.Data;
@Data
public class ValidateSnRequest {
private String sn;
}

View File

@@ -0,0 +1,8 @@
package com.corewing.app.dto.qc;
import lombok.Data;
@Data
public class ValidateWirelessBoardRequest {
private String mac;
}

View File

@@ -0,0 +1,74 @@
package com.corewing.app.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
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 lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* AAT固件版本实体类
*/
@Data
@TableName("app_aat_version")
public class AatVersion implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 固件类型: lb_main / lb_signal_master / lbPro_main / lbPro_signal_master / lbPro_screen_ui
*/
private String firmwareType;
/**
* 固件文件名
*/
private String firmwareName;
/**
* 固件版本号
*/
private String firmwareVersion;
/**
* 最低硬件版本
*/
private String minHardwareVersion;
/**
* 固件下载地址
*/
private String downloadUrl;
/**
* 固件大小(字节)
*/
private Long firmwareSize;
/**
* 固件描述
*/
private String firmwareDescription;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,71 @@
package com.corewing.app.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.corewing.app.common.base.CommonEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
/**
* 活动
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("biz_activity")
public class BizActivity extends CommonEntity {
/* id */
@TableId
private String id;
/* 活动图 */
private String thumbnail;
/* 活动标题 */
private String title;
/* 活动描述 */
private String description;
/* 活动分类 */
private String category;
/* 活动平台 */
private String platformCategory;
/* 活动人数 */
private Integer participationCount;
/* 当前参与人数 */
private Integer currentCount;
/* 活动详情 */
private String content;
/* 活动开始时间 */
private Date startTime;
/* 活动结束时间 */
private Date endTime;
/* 活动状态 */
private String status;
/* 是否开启活动参与人员审核 */
private String personnelReview;
/* 活动排序 */
private Integer sortCode;
/* 备注 */
private String remark;
/* 扩展 */
private String extJson;
}

View File

@@ -0,0 +1,53 @@
package com.corewing.app.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.corewing.app.common.base.CommonEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("biz_activity_lottery")
public class BizActivityLottery extends CommonEntity {
/* id */
@TableId
private String id;
/* 活动id */
private String activityId;
/* 分类 */
private String category;
/* 用户名 */
private String userName;
/* 用户id */
private Long userId;
/* 状态 */
private String status;
/* 提交内容 */
private String content;
/* 审核时间 */
private Date reviewTime;
/* 创作平台 */
private String creationPlatform;
/* 备注 */
private String remark;
/* 排序 */
private Integer sortCode;
/* 扩展字段 */
private String extJson;
}

View File

@@ -11,6 +11,7 @@ import lombok.EqualsAndHashCode;
* 设备表
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("biz_device")
public class BizDevice extends CommonEntity {
@@ -28,6 +29,9 @@ public class BizDevice extends CommonEntity {
@ApiModelProperty("公布状态")
private String publicStatus;
@ApiModelProperty("型号")
private String categoryId;
@ApiModelProperty("排序")
private int sortCode;

View File

@@ -22,6 +22,9 @@ public class BizDeviceCategory extends CommonEntity {
@ApiModelProperty("设备型号缩略图")
private String thumbnail;
@ApiModelProperty("型号id")
private Integer modelId;
@ApiModelProperty("设备型号名称")
private String categoryName;

View File

@@ -0,0 +1,44 @@
package com.corewing.app.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.corewing.app.common.base.CommonEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class BizResource extends CommonEntity {
@TableId
private String id;
private String thumbnail;
private String title;
private String fileName;
private String categoryId;
private String subtitle;
private String content;
private String status;
private String version;
private String downloadUrl;
private Integer sortCode;
private String remark;
private String extJson;
@TableField(exist = false)
private String categoryName;
}

View File

@@ -0,0 +1,25 @@
package com.corewing.app.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.corewing.app.common.base.CommonEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class BizResourceCategory extends CommonEntity {
@TableId
private String id;
private String categoryName;
private String parentId;
private Integer sortCode;
private String remark;
private String extJson;
}

View File

@@ -0,0 +1,89 @@
package com.corewing.app.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/**
* 日志实体
*
*/
@Getter
@Setter
@TableName("DEV_LOG")
public class DevLog {
/** id */
private String id;
/** 日志分类 */
private String category;
/** 日志名称 */
private String name;
/** 执行状态 */
private String exeStatus;
/** 具体消息 */
private String exeMessage;
/** 操作ip */
private String opIp;
/** 操作地址 */
private String opAddress;
/** 操作浏览器 */
private String opBrowser;
/** 操作系统 */
private String opOs;
/** 类名称 */
private String className;
/** 方法名称 */
private String methodName;
/** 请求方式 */
private String reqMethod;
/** 请求地址 */
private String reqUrl;
/** 请求参数 */
private String paramJson;
/** 返回结果 */
private String resultJson;
/** 操作时间 */
private Date opTime;
/** 操作人姓名 */
private String opUser;
/** 签名数据 */
private String signData;
/** 创建时间 */
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/** 创建人 */
@TableField(fill = FieldFill.INSERT)
private String createUser;
/** 更新时间 */
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
/** 更新人 */
@TableField(fill = FieldFill.UPDATE)
private String updateUser;
}

View File

@@ -45,6 +45,21 @@ public class Firmware implements Serializable {
*/
private Integer firmwareType;
/**
* 模型id
*/
private String modelId;
/**
* 版本校验id
*/
private Integer versionId;
/**
* 版本号
*/
private String version;
/**
* 固件下载地址
*/

View File

@@ -0,0 +1,28 @@
package com.corewing.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;
@Data
@TableName("flight_controller")
public class FlightController {
@TableId(type = IdType.AUTO)
private Long id;
private String sn;
private String model;
private String batchNo;
private String status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,24 @@
package com.corewing.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;
@Data
@TableName("qc_photo")
public class QcPhoto {
@TableId(type = IdType.AUTO)
private Long id;
private Long testRecordId;
private String testNo;
private String url;
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,30 @@
package com.corewing.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;
@Data
@TableName("qc_step_result")
public class QcStepResult {
@TableId(type = IdType.AUTO)
private Long id;
private Long testRecordId;
private Integer stepIndex;
private String stepName;
private String result;
private String dataJson;
private Long duration;
private LocalDateTime completedAt;
}

View File

@@ -0,0 +1,42 @@
package com.corewing.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;
@Data
@TableName("qc_test_record")
public class QcTestRecord {
@TableId(type = IdType.AUTO)
private Long id;
private String testNo;
private String productType;
private String sn;
private String operatorId;
private String operatorName;
private String phoneModel;
private String appVersion;
private String status;
private LocalDateTime createTime;
private LocalDateTime updatedAt;
private LocalDateTime uploadTime;
private String reportUrl;
private LocalDateTime serverCreateTime;
}

View File

@@ -0,0 +1,79 @@
package com.corewing.app.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
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 lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* Sirius固件信息实体类
*/
@Data
@TableName("app_sirius_firmware")
public class SiriusFirmware implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 固件类型1-高频头2-接收机3-背包
*/
private Integer firmwareType;
/**
* 协议类型1-ELRS2-CWLink
*/
private Integer protocolType;
/**
* 版本号v3.0.1
*/
private String versionNumber;
/**
* 文件名
*/
private String fileName;
/**
* 文件存储路径
*/
private String filePath;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* MD5校验值
*/
private String md5Hash;
/**
* 版本更新说明
*/
private String releaseNotes;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,29 @@
package com.corewing.app.enums;
import lombok.Getter;
/**
* 日志分类枚举
*
**/
@Getter
public enum DevLogCategoryEnum {
/** APP操作日志 */
APP_OPERATE("APP_OPERATE"),
/** APP异常日志 */
APP_EXCEPTION("APP_EXCEPTION"),
/** APP登录日志 */
APP_LOGIN("APP_LOGIN"),
/** APP登出日志 */
APP_LOGOUT("APP_LOGOUT");
private final String value;
DevLogCategoryEnum(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,19 @@
package com.corewing.app.enums;
import lombok.Getter;
@Getter
public enum DevLogExeStatusEnum {
/** 成功 */
SUCCESS("SUCCESS"),
/** 失败 */
FAIL("FAIL");
private final String value;
DevLogExeStatusEnum(String value) {
this.value = value;
}
}

View File

@@ -57,6 +57,11 @@ public class CustomMetaObjectHandler implements MetaObjectHandler {
// 兼容 Date 和 LocalDateTime 类型的 createTime 填充
fillTimeField(metaObject, CREATE_TIME);
} catch (ReflectionException ignored) { }
try {
// 兼容 Date 和 LocalDateTime 类型的 updateTime 填充
fillTimeField(metaObject, UPDATE_TIME);
} catch (ReflectionException ignored) { }
}
@Override

View File

@@ -5,10 +5,16 @@ import com.corewing.app.common.Result;
import com.corewing.app.util.I18nUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
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.stream.Collectors;
/**
* 全局异常处理器
*/
@@ -46,14 +52,39 @@ public class GlobalExceptionHandler {
return Result.error(HttpStatus.UNAUTHORIZED.value(), message);
}
/**
* 处理 @Valid 参数校验异常RequestBody 参数)
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
// 获取第一个错误信息
String errorMessage = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining("; "));
return Result.error(HttpStatus.BAD_REQUEST.value(), errorMessage);
}
/**
* 处理 @Validated 参数校验异常RequestParam/PathVariable 参数)
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<String> handleConstraintViolationException(ConstraintViolationException e) {
// 获取第一个错误信息
String errorMessage = e.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining("; "));
return Result.error(HttpStatus.BAD_REQUEST.value(), errorMessage);
}
/**
* 处理其他异常
*/
@ExceptionHandler(Exception.class)
// @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<String> handleException(Exception e) {
log.error(e.getMessage());
log.error("系统异常: ", e);
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(),
e.getMessage());
I18nUtil.getMessage("error.system"));
}
}

View File

@@ -0,0 +1,13 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.AatVersion;
import org.apache.ibatis.annotations.Mapper;
/**
* AAT固件版本 Mapper 接口
*/
@Mapper
public interface AatVersionMapper extends BaseMapper<AatVersion> {
}

View File

@@ -0,0 +1,9 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.BizActivityLottery;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BizActivityLotteryMapper extends BaseMapper<BizActivityLottery> {
}

View File

@@ -0,0 +1,9 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.BizActivity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BizActivityMapper extends BaseMapper<BizActivity> {
}

View File

@@ -0,0 +1,10 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.BizResourceCategory;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BizResourceCategoryMapper extends BaseMapper<BizResourceCategory> {
}

View File

@@ -0,0 +1,13 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.corewing.app.dto.ResourcePageRequest;
import com.corewing.app.entity.BizResource;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface BizResourceMapper extends BaseMapper<BizResource> {
Page<BizResource> page(Page<BizResource> page, @Param("resourcePageRequest") ResourcePageRequest resourcePageRequest);
}

View File

@@ -0,0 +1,11 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.DevLog;
/**
* 日志Mapper接口
**/
public interface DevLogMapper extends BaseMapper<DevLog> {
}

View File

@@ -0,0 +1,9 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.FlightController;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface FlightControllerMapper extends BaseMapper<FlightController> {
}

View File

@@ -0,0 +1,9 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.QcPhoto;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface QcPhotoMapper extends BaseMapper<QcPhoto> {
}

View File

@@ -0,0 +1,9 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.QcStepResult;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface QcStepResultMapper extends BaseMapper<QcStepResult> {
}

View File

@@ -0,0 +1,9 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.QcTestRecord;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface QcTestRecordMapper extends BaseMapper<QcTestRecord> {
}

View File

@@ -0,0 +1,13 @@
package com.corewing.app.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.corewing.app.entity.SiriusFirmware;
import org.apache.ibatis.annotations.Mapper;
/**
* Sirius固件信息 Mapper 接口
*/
@Mapper
public interface SiriusFirmwareMapper extends BaseMapper<SiriusFirmware> {
}

View File

@@ -0,0 +1,186 @@
package com.corewing.app.modules.app;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.entity.AatVersion;
import com.corewing.app.service.AatVersionService;
import com.corewing.app.util.I18nUtil;
import com.corewing.app.util.OSSUploadUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* AAT固件版本 Controller
*/
@Api(tags = "AAT固件版本接口")
@RestController
@RequestMapping("/aat_version")
public class AppAatVersionController {
private final AatVersionService aatVersionService;
public AppAatVersionController(AatVersionService aatVersionService) {
this.aatVersionService = aatVersionService;
}
/**
* 查询所有类型的最新固件版本返回与原始JSON结构一致
*/
@CommonLog("查询所有AAT最新固件版本")
@ApiOperation("查询所有AAT最新固件版本")
@GetMapping("/latest")
public Result<Map<String, Object>> getAllLatestVersions() {
return Result.success(aatVersionService.getAllLatestVersions());
}
/**
* 根据固件类型查询最新版本
*/
@CommonLog("根据类型查询AAT最新固件版本")
@ApiOperation("根据类型查询AAT最新固件版本")
@GetMapping("/latest/{firmwareType}")
public Result<AatVersion> getLatestByType(@PathVariable String firmwareType) {
AatVersion version = aatVersionService.getLatestByType(firmwareType);
if (version != null) {
return Result.success(version);
}
return Result.error(I18nUtil.getMessage("firmware.not.found"));
}
/**
* 根据固件类型查询版本列表
*/
@CommonLog("根据类型查询AAT固件版本列表")
@ApiOperation("根据类型查询AAT固件版本列表")
@GetMapping("/type/{firmwareType}")
public Result<List<AatVersion>> listByType(@PathVariable String firmwareType) {
QueryWrapper<AatVersion> wrapper = new QueryWrapper<>();
wrapper.eq("firmware_type", firmwareType);
wrapper.orderByDesc("create_time");
return Result.success(aatVersionService.list(wrapper));
}
/**
* 分页查询固件版本列表
*/
@CommonLog("分页查询AAT固件版本列表")
@ApiOperation("分页查询AAT固件版本列表")
@GetMapping("/page")
public Result<IPage<AatVersion>> page(
@RequestParam(defaultValue = "1") Long current,
@RequestParam(defaultValue = "10") Long size,
@RequestParam(required = false) String firmwareType,
@RequestParam(required = false) String firmwareName) {
Page<AatVersion> page = new Page<>(current, size);
QueryWrapper<AatVersion> wrapper = new QueryWrapper<>();
if (StringUtils.hasText(firmwareType)) {
wrapper.eq("firmware_type", firmwareType);
}
if (StringUtils.hasText(firmwareName)) {
wrapper.like("firmware_name", firmwareName);
}
wrapper.orderByDesc("create_time");
return Result.success(aatVersionService.page(page, wrapper));
}
/**
* 查询所有固件版本
*/
@CommonLog("查询所有AAT固件版本")
@ApiOperation("查询所有AAT固件版本")
@GetMapping("/list")
public Result<List<AatVersion>> list() {
return Result.success(aatVersionService.list());
}
/**
* 根据ID查询固件版本
*/
@CommonLog("根据ID查询AAT固件版本")
@ApiOperation("根据ID查询AAT固件版本")
@GetMapping("/{id}")
public Result<AatVersion> getById(@PathVariable Long id) {
AatVersion version = aatVersionService.getById(id);
if (version != null) {
return Result.success(version);
}
return Result.error(I18nUtil.getMessage("firmware.not.found"));
}
/**
* 新增固件版本
*/
@CommonLog("新增AAT固件版本")
@ApiOperation("新增AAT固件版本")
@PostMapping
public Result<AatVersion> add(@RequestBody AatVersion aatVersion) {
boolean saved = aatVersionService.save(aatVersion);
return saved ? Result.success(aatVersion) : Result.error();
}
/**
* 修改固件版本
*/
@CommonLog("修改AAT固件版本")
@ApiOperation("修改AAT固件版本")
@PutMapping
public Result<Void> update(@RequestBody AatVersion aatVersion) {
return Result.isBool(aatVersionService.updateById(aatVersion));
}
/**
* 删除固件版本
*/
@CommonLog("删除AAT固件版本")
@ApiOperation("删除AAT固件版本")
@DeleteMapping("/{id}")
public Result<Void> delete(@PathVariable Long id) {
AatVersion version = aatVersionService.getById(id);
if (version == null) {
return Result.error(I18nUtil.getMessage("firmware.not.found"));
}
// 删除OSS上的文件
if (StringUtils.hasText(version.getDownloadUrl())) {
String objectName = version.getDownloadUrl().replace("https://oss.corewing.com/", "");
OSSUploadUtil.deleteFile(objectName);
}
return Result.isBool(aatVersionService.removeById(id));
}
/**
* 上传固件文件
*/
@CommonLog("上传AAT固件文件")
@ApiOperation("上传AAT固件文件")
@PostMapping("/upload/{id}")
public Result<AatVersion> upload(@PathVariable Long id, @RequestParam("file") MultipartFile file) {
AatVersion version = aatVersionService.getById(id);
if (version == null) {
return Result.error(I18nUtil.getMessage("firmware.not.found"));
}
try {
String objectName = "aat_firmware/" + file.getOriginalFilename();
String downloadUrl = OSSUploadUtil.uploadFile(file.getInputStream(), objectName);
version.setDownloadUrl(downloadUrl);
version.setFirmwareSize(file.getSize());
version.setFirmwareName(file.getOriginalFilename());
aatVersionService.updateById(version);
return Result.success(version);
} catch (IOException e) {
return Result.error("上传失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,40 @@
package com.corewing.app.modules.app;
import com.corewing.app.common.Result;
import com.corewing.app.dto.SubmitActivityRequest;
import com.corewing.app.service.BizActivityLotteryService;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Api(tags = "活动控制")
@Controller
@RequestMapping("/api/app/activity")
public class AppActivityController {
@Resource
private BizActivityLotteryService bizActivityLotteryService;
/**
* 活动参与地址
* @param activityId
* @return
*/
@GetMapping("/eventVenue/{activityId}")
public String eventVenue(@PathVariable String activityId) {
return "/activity/eventVenue";
}
/**
* 提交活动
* @return
*/
@PostMapping("/submitActivity")
@ResponseBody
public Result<String> submitActivity(SubmitActivityRequest submitActivityRequest) {
return Result.isBool(bizActivityLotteryService.submitActivity(submitActivityRequest));
}
}

View File

@@ -1,6 +1,7 @@
package com.corewing.app.modules.app;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.entity.ContactMsg;
import com.corewing.app.service.ContactMsgService;
import io.swagger.annotations.Api;
@@ -20,6 +21,7 @@ public class AppContactMsgController {
@Resource
private ContactMsgService contactMsgService;
@CommonLog("反馈消息")
@ApiOperation("消息保存接口")
@PostMapping("/save")
public Result<String> save(@RequestBody ContactMsg contactMsg) {

View File

@@ -1,6 +1,7 @@
package com.corewing.app.modules.app;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.DeviceActivationRequest;
import com.corewing.app.service.BizDeviceActivationService;
import io.swagger.annotations.Api;
@@ -23,11 +24,19 @@ public class AppDeviceController {
@Resource
private BizDeviceActivationService activationService;
@CommonLog("激活设备")
@ApiOperation("激活接口")
@PostMapping("activation")
public Result<Boolean> activation(@RequestBody DeviceActivationRequest deviceActivationRequest) {
return Result.success(activationService.activation(deviceActivationRequest));
}
@CommonLog("工厂激活设备")
@ApiOperation("工厂激活设备")
@PostMapping("factoryActivation")
public Result<Boolean> factoryActivation(@RequestBody DeviceActivationRequest deviceActivationRequest) {
return Result.success(activationService.factoryActivation(deviceActivationRequest));
}
}

View File

@@ -4,6 +4,7 @@ import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.FeedbackRequest;
import com.corewing.app.entity.Feedback;
import com.corewing.app.service.FeedbackService;
@@ -39,6 +40,7 @@ public class AppFeedbackController {
/**
* 创建反馈(支持匿名提交)
*/
@CommonLog("创建反馈")
@ApiOperation("创建反馈")
@PostMapping
public Result<String> create(@RequestBody FeedbackRequest request, HttpServletRequest httpRequest) {
@@ -81,6 +83,7 @@ public class AppFeedbackController {
/**
* 查询当前用户的反馈列表
*/
@CommonLog("查询反馈列表")
@ApiOperation("查询当前用户的反馈列表")
@GetMapping("/my")
public Result<List<Feedback>> getMyFeedbackList() {
@@ -97,6 +100,7 @@ public class AppFeedbackController {
/**
* 根据ID查询反馈详情
*/
@CommonLog("查询反馈详情")
@ApiOperation("根据id查询反馈详情")
@GetMapping("/{id}")
public Result<Feedback> getById(@PathVariable Long id) {
@@ -120,6 +124,7 @@ public class AppFeedbackController {
* @param feedbackType 问题类型(可选)
* @param status 状态(可选)
*/
@CommonLog("查询反馈列表分页")
@ApiOperation("分页查询反馈列表")
@GetMapping("/page")
public Result<IPage<Feedback>> getPageList(
@@ -140,6 +145,7 @@ public class AppFeedbackController {
/**
* 更新反馈状态
*/
@CommonLog("更新反馈状态")
@ApiOperation("更新反馈状态")
@PutMapping("/{id}/status")
public Result<String> updateStatus(@PathVariable Long id, @RequestParam Integer status) {
@@ -157,6 +163,7 @@ public class AppFeedbackController {
/**
* 删除反馈
*/
@CommonLog("删除反馈")
@ApiOperation("删除反馈")
@DeleteMapping("/{id}")
public Result<String> delete(@PathVariable Long id) {
@@ -174,6 +181,7 @@ public class AppFeedbackController {
/**
* 测试钉钉推送
*/
@CommonLog("测试钉钉推送")
@ApiOperation("测试钉钉推送")
@GetMapping("/test-dingtalk")
public Result<String> testDingTalk() {
@@ -196,6 +204,7 @@ public class AppFeedbackController {
/**
* 发送反馈信息到钉钉
*/
@CommonLog("发送反馈信息到钉钉")
@ApiOperation("发送反馈信息到钉钉")
private void sendFeedbackToDingTalk(Feedback feedback, String submitIp, String submitRegion) {
try {

View File

@@ -1,6 +1,7 @@
package com.corewing.app.modules.app;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.entity.FeedbackLog;
import com.corewing.app.service.FeedbackLogService;
import io.swagger.annotations.Api;
@@ -28,6 +29,7 @@ public class AppFeedbackLogController {
* @param feedbackLog
* @return
*/
@CommonLog("上传反馈日志")
@ApiOperation("上传日志")
@PostMapping("/uploadFeedbackLog")
public Result<String> uploadFeedbackLog(MultipartFile file, FeedbackLog feedbackLog) {

View File

@@ -1,34 +1,46 @@
package com.corewing.app.modules.app;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.FirmwareVersionRequest;
import com.corewing.app.entity.BizDeviceCategory;
import com.corewing.app.entity.Firmware;
import com.corewing.app.service.BizDeviceCategoryService;
import com.corewing.app.service.FirmwareService;
import com.corewing.app.util.I18nUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
/**
* 固件 Controller
*/
@Api(tags = "固件接口")
@RestController
@RequestMapping("/firmware")
@Validated
public class AppFirmwareController {
private final FirmwareService firmwareService;
@Resource
private FirmwareService firmwareService;
public AppFirmwareController(FirmwareService firmwareService) {
this.firmwareService = firmwareService;
}
@Resource
private BizDeviceCategoryService bizDeviceCategoryService;
/**
* 根据ID查询固件
*/
@CommonLog("根据id查询固件")
@ApiOperation("根据id查询固件")
@GetMapping("/{id}")
public Result<Firmware> getById(@PathVariable Long id) {
@@ -47,6 +59,7 @@ public class AppFirmwareController {
* @param firmwareName 固件名称(可选)
* @param firmwareType 固件类型(可选)
*/
@CommonLog("分页查询固件列表")
@ApiOperation("分页查询固件列表")
@GetMapping("/page")
public Result<IPage<Firmware>> page(
@@ -78,21 +91,23 @@ public class AppFirmwareController {
/**
* 查询所有固件
*/
@CommonLog("查询所有固件集合")
@ApiOperation("查询所有固件集合")
@GetMapping("/list")
public Result<java.util.List<Firmware>> list() {
java.util.List<Firmware> list = firmwareService.list();
public Result<List<Firmware>> list() {
List<Firmware> list = firmwareService.list();
return Result.success(list);
}
/**
* 根据类型查询固件版本
* 根据类型查询固件版本 【兼容旧版APP】
*
* @param firmwareType 固件类型
*/
@CommonLog("根据类型查询固件版本")
@ApiOperation("根据类型查询固件版本")
@GetMapping("/type/{firmwareType}")
public Result<java.util.List<Firmware>> listByType(@PathVariable Integer firmwareType) {
public Result<List<Firmware>> listByType(@PathVariable Integer firmwareType) {
if (firmwareType == null) {
return Result.error(I18nUtil.getMessage("firmware.type.required"));
}
@@ -102,7 +117,49 @@ public class AppFirmwareController {
// 按版本号或创建时间倒序排列,最新版本在前
wrapper.orderByDesc("create_time");
java.util.List<Firmware> list = firmwareService.list(wrapper);
List<Firmware> list = firmwareService.list(wrapper);
return Result.success(list);
}
/**
* 根据类型查询固件版本 【兼容新版APP】
*
* @param firmwareType 固件类型
*/
@CommonLog("根据类型,型号,当前版本查询固件版本")
@ApiOperation("根据类型,当前版本查询固件版本")
@GetMapping("/type/{firmwareType}/{modelId}/{softwareVersion}")
public Result<List<Firmware>> listByType(@PathVariable Integer firmwareType, @PathVariable Integer modelId, @PathVariable Integer softwareVersion) {
if (firmwareType == null && modelId == null) {
return Result.error(I18nUtil.getMessage("firmware.type.or.model.required"));
}
LambdaQueryWrapper<BizDeviceCategory> categoryQueryWrapper = new LambdaQueryWrapper<>();
categoryQueryWrapper.eq(BizDeviceCategory::getModelId, modelId);
BizDeviceCategory bizDeviceCategory = bizDeviceCategoryService.getOne(categoryQueryWrapper);
if(bizDeviceCategory == null) {
return Result.error(I18nUtil.getMessage("firmware.device.not.found"));
}
LambdaQueryWrapper<Firmware> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Firmware::getFirmwareType, firmwareType);
wrapper.eq(Firmware::getModelId, bizDeviceCategory.getId());
wrapper.ge(Firmware::getVersionId, softwareVersion);
// 按版本号或创建时间倒序排列,最新版本在前
wrapper.orderByDesc(Firmware::getCreateTime);
List<Firmware> list = firmwareService.list(wrapper);
return Result.success(list);
}
/**
* 校验是否存在新固件
* @return
*/
@CommonLog("校验是否存在新固件")
@ApiOperation("校验是否存在新固件")
@PostMapping("/checkVersion")
public Result<Firmware> checkVersion(@RequestBody @Valid FirmwareVersionRequest firmwareVersionRequest) {
return Result.success(firmwareService.checkVersion(firmwareVersionRequest));
}
}

View File

@@ -3,6 +3,7 @@ package com.corewing.app.modules.app;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.AppModel.*;
import com.corewing.app.entity.AppModel;
import com.corewing.app.entity.AppModelCategory;
@@ -37,6 +38,7 @@ public class AppModelController {
* @param modelPageRequest
* @return
*/
@CommonLog("模型数据分页")
@ApiOperation("模型数据分页")
@GetMapping("/page")
public Result<Page<AppModel>> page(ModelPageRequest modelPageRequest) {
@@ -48,6 +50,7 @@ public class AppModelController {
* @param modelListRequest
* @return
*/
@CommonLog("模型数据集合")
@ApiOperation("模型数据集合")
@GetMapping("/list")
public Result<List<AppModel>> list(ModelListRequest modelListRequest) {
@@ -60,6 +63,7 @@ public class AppModelController {
* @param modelCategoryPageRequest
* @return
*/
@CommonLog("模型分类数据分页")
@ApiOperation("模型分类数据分页")
@GetMapping("/category/page")
public Result<Page<AppModelCategory>> categoryPage(ModelCategoryPageRequest modelCategoryPageRequest) {
@@ -71,6 +75,7 @@ public class AppModelController {
* @param modelCategoryListRequest
* @return
*/
@CommonLog("模型分类数据集合")
@ApiOperation("模型分类数据集合")
@GetMapping("/category/list")
public Result<List<AppModelCategory>> categoryList(ModelCategoryListRequest modelCategoryListRequest) {
@@ -82,6 +87,7 @@ public class AppModelController {
* @param modelCategoryListRequest
* @return
*/
@CommonLog("模型分类树形集合")
@ApiOperation("模型分类树形集合")
@GetMapping("/category/tree")
public Result<List<Tree<String>>> categoryTree(ModelCategoryListRequest modelCategoryListRequest) {
@@ -93,6 +99,7 @@ public class AppModelController {
* @param modelFavoriteRequest
* @return
*/
@CommonLog("收藏模型")
@ApiOperation("收藏模型")
@PostMapping("/favorite")
public Result<String> favorite(@RequestBody @Valid ModelFavoriteRequest modelFavoriteRequest) {
@@ -104,6 +111,7 @@ public class AppModelController {
* @param modelDownloadRequest
* @return
*/
@CommonLog("增加模型下载记录")
@ApiOperation("增加模型下载记录")
@PostMapping("/download")
public Result<String> download(@RequestBody @Valid ModelDownloadRequest modelDownloadRequest) {
@@ -115,6 +123,7 @@ public class AppModelController {
* @param modelLikeRequest
* @return
*/
@CommonLog("点赞模型")
@ApiOperation("点赞模型")
@PostMapping("/like")
public Result<String> like(@RequestBody @Valid ModelLikeRequest modelLikeRequest) {
@@ -125,6 +134,7 @@ public class AppModelController {
* 模型详情
* @return
*/
@CommonLog("模型详情")
@ApiOperation("模型详情")
@GetMapping("/detail/{modelId}")
public Result<AppModel> detail(@PathVariable String modelId) {
@@ -136,6 +146,7 @@ public class AppModelController {
* @param modelCreateRequest
* @return
*/
@CommonLog("创建模型")
@ApiOperation("创建模型")
@PostMapping("/create")
public Result<String> create(@Valid ModelCreateRequest modelCreateRequest) {
@@ -147,6 +158,7 @@ public class AppModelController {
* @param modelIdRequest
* @return
*/
@CommonLog("提交模型审核")
@ApiOperation("提交模型审核")
@PostMapping("/audit")
public Result<String> audit(@RequestBody @Valid ModelIdRequest modelIdRequest) {
@@ -158,6 +170,7 @@ public class AppModelController {
* @param modelFavoriteListRequest
* @return
*/
@CommonLog("收藏模型列表")
@ApiOperation("收藏模型列表")
@GetMapping("/favorite/list")
public Result<List<AppModel>> favoriteList(ModelFavoriteListRequest modelFavoriteListRequest) {
@@ -169,7 +182,8 @@ public class AppModelController {
* @param modelFavoritePageRequest
* @return
*/
@ApiOperation("收藏模型分页列表")
@CommonLog("收藏模型分页列表分页")
@ApiOperation("收藏模型分页列表分页")
@GetMapping("/favorite/page")
public Result<Page<AppModel>> favoritePage(ModelFavoritePageRequest modelFavoritePageRequest) {
return Result.success(appModelService.favoritePage(modelFavoritePageRequest));
@@ -180,6 +194,7 @@ public class AppModelController {
* @param modelIdRequest
* @return
*/
@CommonLog("模型下架")
@ApiOperation("模型下架")
@PostMapping("/delisted")
public Result<String> delisted(@RequestBody @Valid ModelIdRequest modelIdRequest) {
@@ -192,6 +207,7 @@ public class AppModelController {
* @param modelDownloadLogListRequest
* @return
*/
@CommonLog("模型下载记录列表")
@ApiOperation("模型下载记录列表")
@GetMapping("/download_log/list")
public Result<List<AppModel>> downloadLogList(ModelDownloadLogListRequest modelDownloadLogListRequest) {
@@ -203,7 +219,8 @@ public class AppModelController {
* @param modelDownloadLogPageRequest
* @return
*/
@ApiOperation("模型下载记录分页列表")
@CommonLog("模型下载记录分页列表分页")
@ApiOperation("模型下载记录分页列表分页")
@GetMapping("/download_log/page")
public Result<Page<AppModel>> downloadLogPage(ModelDownloadLogPageRequest modelDownloadLogPageRequest) {
return Result.success(appModelService.downloadLogPage(modelDownloadLogPageRequest));
@@ -213,6 +230,7 @@ public class AppModelController {
* 删除模型
* @return
*/
@CommonLog("删除模型")
@ApiOperation("删除模型")
@DeleteMapping("/delete/{id}")
public Result<String> delete(@PathVariable String id) {

View File

@@ -4,18 +4,22 @@ import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.CreateParamRequest;
import com.corewing.app.dto.UpdateParamRequest;
import com.corewing.app.entity.ParamsCenter;
import com.corewing.app.service.ParamsCenterService;
import com.corewing.app.util.I18nUtil;
import com.corewing.app.util.RedisUtil;
import com.corewing.app.vo.ParamsCenterVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 参数配置中心 Controller
@@ -25,15 +29,16 @@ import java.util.List;
@RequestMapping("/params")
public class AppParamsCenterController {
private final ParamsCenterService paramsService;
@Resource
private ParamsCenterService paramsService;
public AppParamsCenterController(ParamsCenterService paramsService) {
this.paramsService = paramsService;
}
@Resource
private RedisUtil redisUtil;
/**
* 创建参数配置
*/
@CommonLog("创建参数配置接口")
@ApiOperation("创建参数配置接口")
@PostMapping
public Result<String> create(@Valid @RequestBody CreateParamRequest request) {
@@ -66,6 +71,7 @@ public class AppParamsCenterController {
/**
* 更新参数配置
*/
@CommonLog("更新参数配置接口")
@ApiOperation("更新参数配置接口")
@PutMapping
public Result<String> update(@Valid @RequestBody UpdateParamRequest request) {
@@ -104,6 +110,7 @@ public class AppParamsCenterController {
/**
* 删除参数配置
*/
@CommonLog("根据id删除参数配置")
@ApiOperation("根据id删除参数配置")
@DeleteMapping("/{id}")
public Result<String> delete(@PathVariable Long id) {
@@ -132,6 +139,7 @@ public class AppParamsCenterController {
/**
* 根据ID查询参数配置
*/
@CommonLog("根据id查询参数配置")
@ApiOperation("根据id查询参数配置")
@GetMapping("/{id}")
public Result<ParamsCenterVO> getById(@PathVariable Long id) {
@@ -155,6 +163,7 @@ public class AppParamsCenterController {
/**
* 查询所有公共参数列表(公开接口,支持飞控型号过滤)
*/
@CommonLog("获取所有公共参数集合")
@ApiOperation("获取所有公共参数集合")
@GetMapping("/all/list")
public Result<List<ParamsCenterVO>> listAll(@RequestParam(required = false) String fcModel) {
@@ -169,6 +178,7 @@ public class AppParamsCenterController {
/**
* 查询当前用户的参数列表(支持飞控型号过滤)
*/
@CommonLog("获取当前用户的参数列表")
@ApiOperation("获取当前用户的参数列表")
@GetMapping("/my/list")
public Result<List<ParamsCenterVO>> listMy(@RequestParam(required = false) String fcModel) {
@@ -184,6 +194,7 @@ public class AppParamsCenterController {
/**
* 分页查询所有参数列表(公开接口,支持飞控型号过滤)
*/
@CommonLog("分页查询所有公共参数集合")
@ApiOperation("分页查询所有公共参数集合")
@GetMapping("/all/page")
public Result<IPage<ParamsCenterVO>> pageAll(
@@ -202,7 +213,8 @@ public class AppParamsCenterController {
/**
* 分页查询当前用户的参数列表(支持飞控型号过滤)
*/
@ApiOperation("分页查询当前用户参数列表")
@CommonLog("分页查询当前用户参数列表分页")
@ApiOperation("分页查询当前用户参数列表分页")
@GetMapping("/my/page")
public Result<IPage<ParamsCenterVO>> pageMy(
@RequestParam(defaultValue = "1") Long current,
@@ -221,10 +233,20 @@ public class AppParamsCenterController {
/**
* 增加下载次数
*/
@CommonLog("增加参数中心下载次数")
@ApiOperation("增加参数中心下载次数")
@PostMapping("/{id}/download")
public Result<String> incrementDownloadCount(@PathVariable Long id) {
try {
Object loginId = StpUtil.getLoginId();
boolean isNew = redisUtil.setIfAbsent("paramCenter_" + loginId, 1, 1, TimeUnit.DAYS);
// 如果键已存在,递增计数器
long sendCount = isNew ? 1 : redisUtil.incr("paramCenter_" + loginId, 1);
if(sendCount > 3) {
return Result.error(I18nUtil.getMessage("params.download.exceed"));
}
ParamsCenter params = paramsService.getById(id);
if (params == null) {
return Result.error(I18nUtil.getMessage("params.not.found"));
@@ -250,6 +272,7 @@ public class AppParamsCenterController {
* @param id
* @return
*/
@CommonLog("发布公共参数提交审核")
@ApiOperation("发布公共参数提交审核")
@GetMapping("/review/{id}")
public Result<String> review(@PathVariable Long id) {

View File

@@ -2,6 +2,7 @@ package com.corewing.app.modules.app;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.entity.PrivacyPolicy;
import com.corewing.app.service.PrivacyPolicyService;
import io.swagger.annotations.Api;
@@ -31,6 +32,7 @@ public class AppPrivacyPolicyController {
* 隐私政策列表
* @return
*/
@CommonLog("隐私政策列表")
@ApiOperation("隐私政策列表")
@GetMapping("/view_list/{lang}")
public String viewList(@PathVariable String lang, ModelMap modelMap) {
@@ -46,6 +48,7 @@ public class AppPrivacyPolicyController {
* @param category
* @return
*/
@CommonLog("根据类型获取集合数据")
@ApiOperation("根据类型获取集合数据")
@GetMapping("/getListByCategory/{category}")
@ResponseBody

View File

@@ -1,6 +1,7 @@
package com.corewing.app.modules.app;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.publicFirmware.PublicBoardTypeListRequest;
import com.corewing.app.dto.publicFirmware.PublicFirmwareListRequest;
import com.corewing.app.dto.publicFirmware.PublicFirmwareVersionListRequest;
@@ -33,25 +34,28 @@ public class AppPublicFirmwareController {
@Resource
private AppPublicFirmwarePlaneService appPublicFirmwarePlaneService;
@CommonLog("获取固件类型集合")
@ApiOperation("获取固件类型集合")
@GetMapping("/getFirmwareTypeAll")
public Result<List<BizDict>> getFirmwareTypeAll() {
return Result.success(bizDictService.getDataListByKey());
}
@CommonLog("根据固件类型获取版本集合")
@ApiOperation("根据固件类型获取版本集合")
@GetMapping("/getVersionList")
public Result<List<AppPublicFirmwareVersion>> getVersionList(PublicFirmwareVersionListRequest publicFirmwareVersionListRequest) {
return Result.success(appPublicFirmwareVersionService.getVersionList(publicFirmwareVersionListRequest));
}
@CommonLog("根据固件类型&版本获取板载类型集合")
@ApiOperation("根据固件类型&版本获取板载类型集合")
@GetMapping("/getBoardTypeList")
public Result<List<String>> getBoardTypeList(PublicBoardTypeListRequest publicBoardTypeListRequest) {
return Result.success(appPublicFirmwarePlaneService.getBoardTypeList(publicBoardTypeListRequest));
}
@CommonLog("根据固件类型&版本&板载获取固件集合")
@ApiOperation("根据固件类型&版本&板载获取固件集合")
@GetMapping("/getFirmwareList")
public Result<List<AppPublicFirmwarePlane>> getFirmwareList(PublicFirmwareListRequest publicFirmwareListRequest) {

View File

@@ -2,6 +2,7 @@ package com.corewing.app.modules.app;
import cn.dev33.satoken.stp.StpUtil;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.uploadReplaySessionRequest;
import com.corewing.app.entity.ReplaySession;
import com.corewing.app.service.ReplaySessionService;
@@ -24,6 +25,7 @@ public class AppReplaySessionController {
* 获取飞行记录
* @return
*/
@CommonLog("获取当前用户飞行记录")
@ApiOperation("获取当前用户飞行记录")
@GetMapping("/getReplayList")
public Result<List<ReplaySession>> getReplayList() {
@@ -35,6 +37,7 @@ public class AppReplaySessionController {
* @param uploadReplaySessionRequests
* @return
*/
@CommonLog("上传飞行记录")
@ApiOperation("上传飞行记录")
@PostMapping("/uploadReplaySession")
public Result<Boolean> uploadReplaySession(@RequestBody List<uploadReplaySessionRequest> uploadReplaySessionRequests) {
@@ -46,6 +49,7 @@ public class AppReplaySessionController {
* @param syncId
* @return
*/
@CommonLog("根据同步id删除飞行记录")
@ApiOperation("根据同步id删除飞行记录")
@DeleteMapping("/deleteReplaySession/{syncId}")
public Result<Boolean> deleteReplaySession(@PathVariable String syncId) {

View File

@@ -0,0 +1,97 @@
package com.corewing.app.modules.app;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.entity.SiriusFirmware;
import com.corewing.app.service.SiriusFirmwareService;
import com.corewing.app.util.I18nUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* Sirius固件信息 Controller
*/
@Api(tags = "Sirius固件信息接口")
@RestController
@RequestMapping("/sirius_firmware")
public class AppSiriusFirmwareController {
private final SiriusFirmwareService siriusFirmwareService;
public AppSiriusFirmwareController(SiriusFirmwareService siriusFirmwareService) {
this.siriusFirmwareService = siriusFirmwareService;
}
/**
* 根据固件类型和协议类型查询最新版本
*/
@CommonLog("查询Sirius最新固件版本")
@ApiOperation("根据固件类型和协议类型查询最新版本")
@GetMapping("/latest")
public Result<SiriusFirmware> getLatest(
@RequestParam Integer firmwareType,
@RequestParam Integer protocolType) {
SiriusFirmware firmware = siriusFirmwareService.getLatestByTypeAndProtocol(firmwareType, protocolType);
if (firmware != null) {
return Result.success(firmware);
}
return Result.error(I18nUtil.getMessage("firmware.not.found"));
}
/**
* 根据固件类型查询版本列表
*/
@CommonLog("根据类型查询Sirius固件版本列表")
@ApiOperation("根据固件类型查询版本列表")
@GetMapping("/type/{firmwareType}")
public Result<List<SiriusFirmware>> listByType(@PathVariable Integer firmwareType) {
QueryWrapper<SiriusFirmware> wrapper = new QueryWrapper<>();
wrapper.eq("firmware_type", firmwareType);
wrapper.orderByDesc("create_time");
return Result.success(siriusFirmwareService.list(wrapper));
}
/**
* 根据固件类型和协议类型查询版本列表
*/
@CommonLog("根据类型和协议查询Sirius固件版本列表")
@ApiOperation("根据固件类型和协议类型查询版本列表")
@GetMapping("/type/{firmwareType}/protocol/{protocolType}")
public Result<List<SiriusFirmware>> listByTypeAndProtocol(
@PathVariable Integer firmwareType,
@PathVariable Integer protocolType) {
QueryWrapper<SiriusFirmware> wrapper = new QueryWrapper<>();
wrapper.eq("firmware_type", firmwareType);
wrapper.eq("protocol_type", protocolType);
wrapper.orderByDesc("create_time");
return Result.success(siriusFirmwareService.list(wrapper));
}
/**
* 查询所有固件
*/
@CommonLog("查询所有Sirius固件")
@ApiOperation("查询所有固件")
@GetMapping("/list")
public Result<List<SiriusFirmware>> list() {
return Result.success(siriusFirmwareService.list());
}
/**
* 根据ID查询固件
*/
@CommonLog("根据ID查询Sirius固件")
@ApiOperation("根据ID查询固件")
@GetMapping("/{id}")
public Result<SiriusFirmware> getById(@PathVariable Integer id) {
SiriusFirmware firmware = siriusFirmwareService.getById(id);
if (firmware != null) {
return Result.success(firmware);
}
return Result.error(I18nUtil.getMessage("firmware.not.found"));
}
}

View File

@@ -4,6 +4,7 @@ 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.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.entity.Tutorial;
import com.corewing.app.entity.TutorialCategory;
import com.corewing.app.service.TutorialCategoryService;
@@ -41,6 +42,7 @@ public class AppTutorialController {
* @param model 数据模型
* @return 详情页
*/
@CommonLog("跳转到界面查看教程详情")
@ApiOperation("跳转到界面查看教程详情")
@GetMapping("/viewDetail/{tutorialId}")
public String viewDetail(@PathVariable Long tutorialId, ModelMap model) {
@@ -55,6 +57,7 @@ public class AppTutorialController {
* @param tutorialId 教程id
* @return
*/
@CommonLog("添加查看次数")
@ApiOperation("添加查看次数")
@GetMapping("/addViewCount")
@ResponseBody
@@ -74,6 +77,7 @@ public class AppTutorialController {
* @param firstStatus 置首状态(选填)
*
*/
@CommonLog("分类查询集合")
@ApiOperation("分类查询集合")
@GetMapping("/category")
@ResponseBody
@@ -97,6 +101,7 @@ public class AppTutorialController {
* @param tutorialTitle 教程标题(选填)
*
*/
@CommonLog("分页查询教程列表")
@ApiOperation("分页查询教程列表")
@GetMapping("/page")
@ResponseBody

View File

@@ -2,16 +2,21 @@ package com.corewing.app.modules.app;
import cn.dev33.satoken.stp.StpUtil;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.*;
import com.corewing.app.entity.DevLog;
import com.corewing.app.entity.User;
import com.corewing.app.service.UserService;
import com.corewing.app.service.VerifyCodeService;
import com.corewing.app.util.DevLogUtil;
import com.corewing.app.util.I18nUtil;
import com.corewing.app.util.IpUtil;
import com.corewing.app.util.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.HashMap;
@@ -25,17 +30,20 @@ import java.util.Map;
@RequestMapping("/user")
public class AppUserController {
private final UserService userService;
private final VerifyCodeService verifyCodeService;
@Resource
private UserService userService;
@Resource
private VerifyCodeService verifyCodeService;
@Resource
private RedisUtil redisUtil;
public AppUserController(UserService userService, VerifyCodeService verifyCodeService) {
this.userService = userService;
this.verifyCodeService = verifyCodeService;
}
/**
* 发送验证码
*/
@CommonLog("发送验证码接口")
@ApiOperation("发送验证码接口")
@PostMapping("/sendCode")
public Result<String> sendCode(@RequestBody SendCodeRequest request) {
@@ -69,6 +77,8 @@ public class AppUserController {
data.put("userId", user.getId());
data.put("username", user.getUsername());
redisUtil.set("APP_" + user.getId(), user);
DevLogUtil.executeLoginLog(user.getUsername());
return Result.success(I18nUtil.getMessage("user.login.success"), data);
} catch (Exception e) {
return Result.error(e.getMessage());
@@ -104,6 +114,13 @@ public class AppUserController {
@ApiOperation("用户登出接口")
@PostMapping("/logout")
public Result<String> logout() {
Long userId = StpUtil.getLoginIdAsLong();
User user = (User) redisUtil.get("APP_" + userId);
if(user == null) {
user = userService.getById(userId);
}
redisUtil.del("APP_" + userId);
DevLogUtil.executeLogoutLog(user.getUsername());
StpUtil.logout();
return Result.success(I18nUtil.getMessage("user.logout.success"));
}
@@ -111,19 +128,32 @@ public class AppUserController {
/**
* 获取当前登录用户信息
*/
@CommonLog("获取当前登录用户信息")
@ApiOperation("获取当前登录用户信息")
@GetMapping("/info")
public Result<User> getUserInfo() {
Long userId = StpUtil.getLoginIdAsLong();
try {
// 缓存获取
User user = (User) redisUtil.get("APP_" + userId);
if(user == null) {
user = userService.getById(userId);
redisUtil.set("APP_" + user.getId(), user);
}
return Result.success(user);
} catch (Exception e) {
User user = userService.getById(userId);
// 隐藏密码
user.setPassword(null);
return Result.success(user);
}
}
/**
* 根据ID查询用户
*/
@CommonLog("根据id查询用户")
@ApiOperation("根据id查询用户")
@GetMapping("/{id}")
public Result<User> getById(@PathVariable Long id) {
@@ -139,6 +169,7 @@ public class AppUserController {
/**
* 更新用户信息
*/
@CommonLog("更新用户信息")
@ApiOperation("更新用户信息")
@PutMapping("/update")
public Result<String> update(@RequestBody User user) {
@@ -147,6 +178,10 @@ public class AppUserController {
// 不允许通过此接口修改密码
user.setPassword(null);
boolean success = userService.updateById(user);
// 更新缓存
User cacheUser = userService.getById(userId);
redisUtil.set("APP_" + user.getId(), cacheUser);
if (success) {
return Result.success(I18nUtil.getMessage("user.update.success"));
}
@@ -156,6 +191,7 @@ public class AppUserController {
/**
* 修改密码
*/
@CommonLog("用户修改密码")
@ApiOperation("用户修改密码")
@PutMapping("/password")
public Result<String> updatePassword(@RequestBody UpdatePasswordRequest request) {
@@ -189,6 +225,7 @@ public class AppUserController {
* @param request
* @return
*/
@CommonLog("忘记密码")
@ApiOperation("忘记密码")
@PutMapping("/forgetPassword")
public Result<String> forgetPassword(@RequestBody ForgetPasswordRequest request) {
@@ -213,6 +250,8 @@ public class AppUserController {
data.put("token", token);
data.put("userId", user.getId());
data.put("username", user.getUsername());
redisUtil.set("APP_" + user.getId(), user);
DevLogUtil.executeLoginLog(user.getUsername());
return Result.success(I18nUtil.getMessage("user.login.success"), data);
}
@@ -221,6 +260,7 @@ public class AppUserController {
* @param logoffRequest
* @return
*/
@CommonLog("注销用户")
@ApiOperation("注销用户")
@DeleteMapping("/delete")
public Result<String> logoff(@RequestBody @Valid LogoffRequest logoffRequest) {
@@ -231,6 +271,7 @@ public class AppUserController {
* 注销发送验证码
* @return
*/
@CommonLog("发送注销验证码")
@ApiOperation("发送注销验证码")
@PostMapping("/delete/sendCode")
public Result<Map<String, String>> deleteSendCode() {

View File

@@ -1,6 +1,7 @@
package com.corewing.app.modules.app;
import com.corewing.app.common.Result;
import com.corewing.app.common.annotation.CommonLog;
import com.corewing.app.dto.CheckVersionRequest;
import com.corewing.app.entity.AppVersion;
import com.corewing.app.service.AppVersionService;
@@ -28,6 +29,7 @@ public class AppVersionController {
* @param checkVersionRequest
* @return
*/
@CommonLog("校验是否有新版本")
@ApiOperation("校验是否有新版本")
@GetMapping("/checkUpdate")
public Result<Object> checkUpdate(CheckVersionRequest checkVersionRequest) {

View File

@@ -0,0 +1,39 @@
package com.corewing.app.modules.downloadCenter;
import cn.hutool.core.lang.tree.Tree;
import com.corewing.app.common.Result;
import com.corewing.app.dto.ResourceCategoryTreeRequest;
import com.corewing.app.service.BizResourceCategoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
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;
import java.util.List;
/**
* 资源分类接口
*/
@Api(tags = "资源分类接口")
@RestController
@RequestMapping("/api/app/resource_category")
public class BizResourceCategoryController {
@Resource
private BizResourceCategoryService bizResourceCategoryService;
/**
* 获取分类树形集合
* @param resourceCategoryTreeRequest
* @return
*/
@ApiOperation("分类树形集合")
@GetMapping("/tree")
public Result<List<Tree<String>>> categoryTree(ResourceCategoryTreeRequest resourceCategoryTreeRequest) {
return Result.success(bizResourceCategoryService.tree(resourceCategoryTreeRequest));
}
}

View File

@@ -0,0 +1,39 @@
package com.corewing.app.modules.downloadCenter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.corewing.app.common.Result;
import com.corewing.app.dto.ResourcePageRequest;
import com.corewing.app.entity.BizResource;
import com.corewing.app.service.BizResourceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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;
/**
* 资源接口
*/
@Api(tags = "资源接口")
@RestController
@RequestMapping("/api/app/resource")
public class BizResourceController {
@Resource
private BizResourceService bizResourceService;
/**
* 获取资源分页
* @param resourcePageRequest
* @return
*/
@ApiOperation("获取资源分页")
@GetMapping("/page")
public Result<Page<BizResource>> page(ResourcePageRequest resourcePageRequest) {
return Result.success(bizResourceService.page(resourcePageRequest));
}
}

View File

@@ -0,0 +1,27 @@
package com.corewing.app.modules.qc;
import com.corewing.app.common.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@Api(tags = "QC配置")
@RestController
@RequestMapping("/api/qc/config")
public class QcConfigController {
@ApiOperation("获取测试配置")
@GetMapping("/test-params")
public Result<Map<String, Object>> getTestParams(@RequestParam("productType") String productType) {
Map<String, Object> params = new HashMap<>();
// 后续可根据 productType 返回不同的测试参数/阈值
params.put("productType", productType);
return Result.success(params);
}
}

View File

@@ -0,0 +1,57 @@
package com.corewing.app.modules.qc;
import com.corewing.app.common.Result;
import com.corewing.app.dto.qc.UploadTestRecordRequest;
import com.corewing.app.dto.qc.ValidateSnRequest;
import com.corewing.app.entity.QcTestRecord;
import com.corewing.app.service.QcTestService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
@Api(tags = "QC测试")
@RestController
@RequestMapping("/api/qc/test")
public class QcTestController {
private final QcTestService qcTestService;
public QcTestController(QcTestService qcTestService) {
this.qcTestService = qcTestService;
}
@ApiOperation("上传测试记录")
@PostMapping("/upload")
public Result<String> uploadTestRecord(@RequestBody UploadTestRecordRequest request) {
return qcTestService.uploadTestRecord(request);
}
@ApiOperation("上传照片")
@PostMapping("/upload-photo")
public Result<Map<String, String>> uploadPhoto(@RequestParam("testNo") String testNo,
@RequestParam("photo") MultipartFile photo) {
return qcTestService.uploadPhoto(testNo, photo);
}
@ApiOperation("验证SN")
@PostMapping("/validate-sn")
public Result<Boolean> validateSn(@RequestBody ValidateSnRequest request) {
return qcTestService.validateSn(request);
}
@ApiOperation("查询SN历史记录")
@GetMapping("/history")
public Result<List<QcTestRecord>> getHistory(@RequestParam("sn") String sn) {
return qcTestService.getHistory(sn);
}
@ApiOperation("获取测试报告")
@GetMapping("/report")
public Result<String> getReport(@RequestParam("testNo") String testNo) {
return qcTestService.getReport(testNo);
}
}

View File

@@ -0,0 +1,29 @@
package com.corewing.app.modules.qc;
import com.corewing.app.common.Result;
import com.corewing.app.dto.qc.ValidateWirelessBoardRequest;
import com.corewing.app.service.BizDeviceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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;
@Api(tags = "无线版QC")
@RestController
@RequestMapping("/api/qc/wireless")
public class WirelessBoardController {
private final BizDeviceService bizDeviceService;
public WirelessBoardController(BizDeviceService bizDeviceService) {
this.bizDeviceService = bizDeviceService;
}
@ApiOperation("验证已经激活的无线板")
@PostMapping("/validate-wireless")
public Result<Boolean> validateWirelessBoard(@RequestBody ValidateWirelessBoardRequest validateWirelessBoardRequest) {
return bizDeviceService.validateWirelessBoard(validateWirelessBoardRequest);
}
}

View File

@@ -0,0 +1,28 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.entity.AatVersion;
import java.util.List;
import java.util.Map;
/**
* AAT固件版本 Service 接口
*/
public interface AatVersionService extends IService<AatVersion> {
/**
* 根据固件类型查询最新版本
*
* @param firmwareType 固件类型
* @return 最新固件版本
*/
AatVersion getLatestByType(String firmwareType);
/**
* 查询所有类型的最新固件版本返回与原始JSON结构一致的格式
*
* @return 所有类型的最新版本映射
*/
Map<String, Object> getAllLatestVersions();
}

View File

@@ -0,0 +1,11 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.dto.SubmitActivityRequest;
import com.corewing.app.entity.BizActivityLottery;
public interface BizActivityLotteryService extends IService<BizActivityLottery> {
Boolean submitActivity(SubmitActivityRequest submitActivityRequest);
}

View File

@@ -0,0 +1,7 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.entity.BizActivity;
public interface BizActivityService extends IService<BizActivity> {
}

View File

@@ -6,4 +6,6 @@ import com.corewing.app.entity.BizDeviceActivation;
public interface BizDeviceActivationService extends IService<BizDeviceActivation> {
Boolean activation(DeviceActivationRequest deviceActivationRequest);
Boolean factoryActivation(DeviceActivationRequest deviceActivationRequest);
}

View File

@@ -1,7 +1,10 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.common.Result;
import com.corewing.app.dto.qc.ValidateWirelessBoardRequest;
import com.corewing.app.entity.BizDevice;
public interface BizDeviceService extends IService<BizDevice> {
Result<Boolean> validateWirelessBoard(ValidateWirelessBoardRequest validateWirelessBoardRequest);
}

View File

@@ -0,0 +1,13 @@
package com.corewing.app.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.dto.ResourceCategoryTreeRequest;
import com.corewing.app.entity.BizResourceCategory;
import java.util.List;
public interface BizResourceCategoryService extends IService<BizResourceCategory> {
List<Tree<String>> tree(ResourceCategoryTreeRequest resourceCategoryTreeRequest);
}

View File

@@ -0,0 +1,12 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.dto.ResourcePageRequest;
import com.corewing.app.entity.BizResource;
public interface BizResourceService extends IService<BizResource> {
Page<BizResource> page(ResourcePageRequest resourcePageRequest);
}

View File

@@ -0,0 +1,19 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.entity.DevLog;
import java.util.List;
/**
* 日志Service接口
*
* @author xuyuxiang
* @date 2022/9/2 15:04
*/
public interface DevLogService extends IService<DevLog> {
}

View File

@@ -3,6 +3,7 @@ package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.common.Result;
import com.corewing.app.dto.FirmwareVersionRequest;
import com.corewing.app.entity.Firmware;
import org.springframework.web.multipart.MultipartFile;
@@ -40,4 +41,11 @@ public interface FirmwareService extends IService<Firmware> {
* @return
*/
boolean removeData(Long id);
/**
* 校验固件是否有新固件
* @param firmwareVersionRequest
* @return
*/
Firmware checkVersion(FirmwareVersionRequest firmwareVersionRequest);
}

View File

@@ -0,0 +1,24 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.common.Result;
import com.corewing.app.dto.qc.UploadTestRecordRequest;
import com.corewing.app.dto.qc.ValidateSnRequest;
import com.corewing.app.entity.QcTestRecord;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
public interface QcTestService extends IService<QcTestRecord> {
Result<String> uploadTestRecord(UploadTestRecordRequest request);
Result<Map<String, String>> uploadPhoto(String testNo, MultipartFile photo);
Result<Boolean> validateSn(ValidateSnRequest request);
Result<List<QcTestRecord>> getHistory(String sn);
Result<String> getReport(String testNo);
}

View File

@@ -0,0 +1,19 @@
package com.corewing.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.corewing.app.entity.SiriusFirmware;
/**
* Sirius固件信息 Service 接口
*/
public interface SiriusFirmwareService extends IService<SiriusFirmware> {
/**
* 根据固件类型和协议类型查询最新版本
*
* @param firmwareType 固件类型
* @param protocolType 协议类型
* @return 最新固件版本
*/
SiriusFirmware getLatestByTypeAndProtocol(Integer firmwareType, Integer protocolType);
}

View File

@@ -0,0 +1,55 @@
package com.corewing.app.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.entity.AatVersion;
import com.corewing.app.mapper.AatVersionMapper;
import com.corewing.app.service.AatVersionService;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* AAT固件版本 Service 实现类
*/
@Service
public class AatVersionServiceImpl extends ServiceImpl<AatVersionMapper, AatVersion> implements AatVersionService {
@Override
public AatVersion getLatestByType(String firmwareType) {
LambdaQueryWrapper<AatVersion> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(AatVersion::getFirmwareType, firmwareType);
wrapper.orderByDesc(AatVersion::getCreateTime);
wrapper.last("LIMIT 1");
return getOne(wrapper);
}
@Override
public Map<String, Object> getAllLatestVersions() {
// 查询所有固件,按类型分组,每组取最新的一条
List<AatVersion> allVersions = list(
new LambdaQueryWrapper<AatVersion>().orderByDesc(AatVersion::getCreateTime)
);
Map<String, Object> result = new LinkedHashMap<>();
Map<String, List<AatVersion>> grouped = allVersions.stream()
.collect(Collectors.groupingBy(AatVersion::getFirmwareType, LinkedHashMap::new, Collectors.toList()));
for (Map.Entry<String, List<AatVersion>> entry : grouped.entrySet()) {
Map<String, Object> typeInfo = new HashMap<>();
List<Map<String, String>> firmwares = new ArrayList<>();
// 取该类型下最新的一条
AatVersion latest = entry.getValue().get(0);
Map<String, String> firmwareInfo = new HashMap<>();
firmwareInfo.put("firmware_name", latest.getFirmwareName());
firmwareInfo.put("firmware_version", latest.getFirmwareVersion());
firmwareInfo.put("min_hardware_version", latest.getMinHardwareVersion());
firmwares.add(firmwareInfo);
typeInfo.put("firmwares", firmwares);
result.put(entry.getKey(), typeInfo);
}
return result;
}
}

View File

@@ -47,7 +47,7 @@ public class AppModelCategoryServiceImpl extends ServiceImpl<AppModelCategoryMap
@Override
public Page<AppModelCategory> page(ModelCategoryPageRequest modelCategoryPageRequest) {
Page<AppModelCategory> page = PageContext.getPage(AppModelCategory.class);
Page<AppModelCategory> page = PageContext.getDefaultPage(AppModelCategory.class);
return appModelCategoryMapper.page(page, modelCategoryPageRequest);
}

View File

@@ -46,7 +46,7 @@ public class AppModelServiceImpl extends ServiceImpl<AppModelMapper, AppModel> i
@Override
public Page<AppModel> page(ModelPageRequest modelPageRequest) {
Page<AppModel> page = PageContext.getPage(AppModel.class);
Page<AppModel> page = PageContext.getDefaultPage(AppModel.class);
return appModelMapper.page(page, modelPageRequest);
}
@@ -196,7 +196,7 @@ public class AppModelServiceImpl extends ServiceImpl<AppModelMapper, AppModel> i
@Override
public Page<AppModel> favoritePage(ModelFavoritePageRequest modelFavoritePageRequest) {
Page<AppModel> page = PageContext.getPage(AppModel.class);
Page<AppModel> page = PageContext.getDefaultPage(AppModel.class);
return appModelMapper.favoritePage(page, Long.valueOf(StpUtil.getLoginId().toString()), modelFavoritePageRequest);
}
@@ -224,7 +224,7 @@ public class AppModelServiceImpl extends ServiceImpl<AppModelMapper, AppModel> i
@Override
public Page<AppModel> downloadLogPage(ModelDownloadLogPageRequest modelDownloadLogPageRequest) {
Page<AppModel> page = PageContext.getPage(AppModel.class);
Page<AppModel> page = PageContext.getDefaultPage(AppModel.class);
return appModelMapper.downloadLogPage(page, Long.valueOf(StpUtil.getLoginId().toString()), modelDownloadLogPageRequest);
}

View File

@@ -0,0 +1,62 @@
package com.corewing.app.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.dto.SubmitActivityRequest;
import com.corewing.app.entity.BizActivity;
import com.corewing.app.entity.BizActivityLottery;
import com.corewing.app.mapper.BizActivityLotteryMapper;
import com.corewing.app.service.BizActivityLotteryService;
import com.corewing.app.service.BizActivityService;
import com.corewing.app.util.DateUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;
@Service
public class BizActivityLotteryServiceImpl extends ServiceImpl<BizActivityLotteryMapper, BizActivityLottery> implements BizActivityLotteryService {
@Resource
private BizActivityService bizActivityService;
@Override
public Boolean submitActivity(SubmitActivityRequest submitActivityRequest) {
Long userid = StpUtil.getLoginIdAsLong();
BizActivity activity = bizActivityService.getById(submitActivityRequest.getActivityId());
if(activity == null) {
throw new RuntimeException("该活动不存在");
}
// 验证活动是否在有效期内
if(activity.getStartTime() != null && activity.getEndTime() != null) {
if(!DateUtils.isBefore(activity.getStartTime())) {
throw new RuntimeException("活动还未开始");
}
if(!DateUtils.isAfter(activity.getEndTime())) {
throw new RuntimeException("活动已过期");
}
}
// 校验是否参与
LambdaQueryWrapper<BizActivityLottery> checkLotteryWrapper = new LambdaQueryWrapper<>();
checkLotteryWrapper.eq(BizActivityLottery::getUserId, userid);
checkLotteryWrapper.eq(BizActivityLottery::getActivityId, submitActivityRequest.getActivityId());
if(count(checkLotteryWrapper) > 0) {
throw new RuntimeException("该活动你已经参与");
}
BizActivityLottery bizActivityLottery = new BizActivityLottery();
bizActivityLottery.setActivityId(submitActivityRequest.getActivityId());
return null;
}
}

View File

@@ -0,0 +1,11 @@
package com.corewing.app.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.entity.BizActivity;
import com.corewing.app.mapper.BizActivityMapper;
import com.corewing.app.service.BizActivityService;
import org.springframework.stereotype.Service;
@Service
public class BizActivityServiceImpl extends ServiceImpl<BizActivityMapper, BizActivity> implements BizActivityService {
}

View File

@@ -2,17 +2,19 @@ package com.corewing.app.service.impl;
import cn.dev33.satoken.stp.StpUtil;
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.corewing.app.dto.DeviceActivationRequest;
import com.corewing.app.entity.BizDevice;
import com.corewing.app.entity.BizDeviceActivation;
import com.corewing.app.entity.BizDeviceCategory;
import com.corewing.app.mapper.BizDeviceActivationMapper;
import com.corewing.app.service.BizDeviceActivationService;
import com.corewing.app.service.BizDeviceCategoryService;
import com.corewing.app.service.BizDeviceService;
import com.corewing.app.util.CommonServletUtil;
import com.corewing.app.util.IpUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
@@ -24,15 +26,18 @@ public class BizDeviceActivationServiceImpl extends ServiceImpl<BizDeviceActivat
@Resource
private BizDeviceService deviceService;
@Resource
private BizDeviceCategoryService categoryService;
@Override
public Boolean activation(DeviceActivationRequest deviceActivationRequest) {
Object loginId = StpUtil.getLoginId();
LambdaQueryWrapper<BizDeviceActivation> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BizDeviceActivation::getDeviceMac, deviceActivationRequest.getMac());
BizDeviceActivation checkDeviceActivation = getOne(wrapper);
if(checkDeviceActivation != null) {
if (checkDeviceActivation != null) {
// 该用户已经激活过该设备
if(checkDeviceActivation.getUserId().equals(loginId)) {
if (checkDeviceActivation.getUserId().equals(loginId)) {
return true;
}
return updateById(checkDeviceActivation);
@@ -42,7 +47,7 @@ public class BizDeviceActivationServiceImpl extends ServiceImpl<BizDeviceActivat
LambdaQueryWrapper<BizDevice> checkDeviceWrapper = new LambdaQueryWrapper<>();
checkDeviceWrapper.eq(BizDevice::getDeviceMac, deviceActivationRequest.getMac());
List<BizDevice> list = deviceService.list(checkDeviceWrapper);
if(list.isEmpty()) {
if (list.isEmpty()) {
throw new RuntimeException("该设备不是酷翼官方产品");
}
@@ -57,4 +62,36 @@ public class BizDeviceActivationServiceImpl extends ServiceImpl<BizDeviceActivat
deviceActivation.setDeviceId(bizDevice.getId());
return this.saveOrUpdate(deviceActivation);
}
@Transactional(rollbackFor = Exception.class)
@Override
public Boolean factoryActivation(DeviceActivationRequest deviceActivationRequest) {
BizDeviceActivation checkDeviceActivation = getBizDeviceActivationByMac(deviceActivationRequest.getMac());
if (checkDeviceActivation != null) {
return false;
}
LambdaQueryWrapper<BizDeviceCategory> findWrapper = new LambdaQueryWrapper<>();
findWrapper.eq(BizDeviceCategory::getModelId, deviceActivationRequest.getModelId());
BizDeviceCategory deviceCategory = categoryService.getOne(findWrapper);
BizDevice device = new BizDevice();
device.setDeviceMac(deviceActivationRequest.getMac());
device.setStatus("0");
device.setPublicStatus("1");
device.setCategoryId(deviceCategory.getId());
return deviceService.save(device);
}
/**
* 根据mac地址获取激活设备
*
* @param mac mac地址
* @return 激活设备
*/
private BizDeviceActivation getBizDeviceActivationByMac(String mac) {
LambdaQueryWrapper<BizDeviceActivation> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BizDeviceActivation::getDeviceMac, mac);
return getOne(wrapper);
}
}

View File

@@ -1,6 +1,9 @@
package com.corewing.app.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.common.Result;
import com.corewing.app.dto.qc.ValidateWirelessBoardRequest;
import com.corewing.app.entity.BizDevice;
import com.corewing.app.mapper.BizDeviceMapper;
import com.corewing.app.service.BizDeviceService;
@@ -8,4 +11,16 @@ import org.springframework.stereotype.Service;
@Service
public class BizDeviceServiceImpl extends ServiceImpl<BizDeviceMapper, BizDevice> implements BizDeviceService {
@Override
public Result<Boolean> validateWirelessBoard(ValidateWirelessBoardRequest validateWirelessBoardRequest) {
LambdaQueryWrapper<BizDevice> bizDeviceLambdaQueryWrapper = new LambdaQueryWrapper<>();
bizDeviceLambdaQueryWrapper.eq(BizDevice::getDeviceMac, validateWirelessBoardRequest.getMac());
long deviceCount = count(bizDeviceLambdaQueryWrapper);
if (deviceCount > 0) {
return Result.success(true);
}
return Result.error("设备不存在或未激活");
}
}

View File

@@ -0,0 +1,73 @@
package com.corewing.app.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.dto.ResourceCategoryTreeRequest;
import com.corewing.app.entity.AppModelCategory;
import com.corewing.app.entity.BizResourceCategory;
import com.corewing.app.mapper.BizResourceCategoryMapper;
import com.corewing.app.service.BizResourceCategoryService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@Service
public class BizResourceCategoryServiceImpl extends ServiceImpl<BizResourceCategoryMapper, BizResourceCategory> implements BizResourceCategoryService {
@Override
public List<Tree<String>> tree(ResourceCategoryTreeRequest resourceCategoryTreeRequest) {
LambdaQueryWrapper<BizResourceCategory> queryWrapper = new LambdaQueryWrapper<>();
List<BizResourceCategory> resourceList = list(queryWrapper);
// 填充上层的父级菜单
this.fillParentCategoryInfo(resourceList);
List<TreeNode<String>> treeNodeList = resourceList.stream().map(category ->
new TreeNode<>(category.getId(), category.getParentId(),
category.getCategoryName(), category.getSortCode()).setExtra(JSONUtil.parseObj(category)))
.collect(Collectors.toList());
return TreeUtil.build(treeNodeList, "0");
}
private void fillParentCategoryInfo(List<BizResourceCategory> categoryList) {
if(CollUtil.isNotEmpty(categoryList)){
List<BizResourceCategory> parentResourceCategoryList = categoryList.stream().filter(distinctByKey(BizResourceCategory::getParentId)).collect(Collectors.toList());
List<String> parentIds = null;
if(CollUtil.isNotEmpty(parentResourceCategoryList)){
parentIds = CollUtil.newArrayList();
for(BizResourceCategory parentCategory : categoryList){
if(!StrUtil.equals(parentCategory.getParentId(),"0")){
parentIds.add(parentCategory.getParentId());
}
}
}
if(CollUtil.isNotEmpty(parentIds)){
LambdaQueryWrapper<BizResourceCategory> parentCategoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
parentCategoryLambdaQueryWrapper.in(BizResourceCategory::getId,parentIds);
List<BizResourceCategory> parentCategoryList = this.list(parentCategoryLambdaQueryWrapper);
if(CollUtil.isNotEmpty(parentCategoryList)){
this.fillParentCategoryInfo(parentCategoryList);
categoryList.addAll(parentCategoryList);
}
}
}
}
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
}

View File

@@ -0,0 +1,30 @@
package com.corewing.app.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.common.page.PageContext;
import com.corewing.app.dto.ResourcePageRequest;
import com.corewing.app.entity.AppModel;
import com.corewing.app.entity.BizResource;
import com.corewing.app.entity.BizResourceCategory;
import com.corewing.app.mapper.BizResourceCategoryMapper;
import com.corewing.app.mapper.BizResourceMapper;
import com.corewing.app.service.BizProductService;
import com.corewing.app.service.BizResourceCategoryService;
import com.corewing.app.service.BizResourceService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class BizResourceServiceImpl extends ServiceImpl<BizResourceMapper, BizResource> implements BizResourceService {
@Resource
private BizResourceMapper bizResourceMapper;
@Override
public Page<BizResource> page(ResourcePageRequest resourcePageRequest) {
Page<BizResource> page = PageContext.getDefaultPage(BizResource.class);
return bizResourceMapper.page(page, resourcePageRequest);
}
}

View File

@@ -0,0 +1,21 @@
package com.corewing.app.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.entity.DevLog;
import com.corewing.app.mapper.DevLogMapper;
import com.corewing.app.service.DevLogService;
import org.springframework.stereotype.Service;
/**
* 日志Service接口实现类
*
* @author xuyuxiang
* @date 2022/9/2 15:05
*/
@Service
public class DevLogServiceImpl extends ServiceImpl<DevLogMapper, DevLog> implements DevLogService {
}

View File

@@ -30,7 +30,7 @@ public class FeedbackServiceImpl extends ServiceImpl<FeedbackMapper, Feedback> i
@Override
public Page<Feedback> page(Feedback feedback) {
Page<Feedback> page = PageContext.getPage(Feedback.class);
Page<Feedback> page = PageContext.getDefaultPage(Feedback.class);
// LambdaQueryWrapper<Feedback> wrapper = new LambdaQueryWrapper<>();
// wrapper.eq(feedback.getStatus() != null, Feedback::getStatus, feedback.getStatus());
// wrapper.like(StringUtils.hasText(feedback.getTitle()), Feedback::getTitle, feedback.getTitle());

View File

@@ -4,8 +4,11 @@ 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.corewing.app.common.page.PageContext;
import com.corewing.app.dto.FirmwareVersionRequest;
import com.corewing.app.entity.BizDeviceCategory;
import com.corewing.app.entity.Firmware;
import com.corewing.app.mapper.FirmwareMapper;
import com.corewing.app.service.BizDeviceCategoryService;
import com.corewing.app.service.FirmwareService;
import com.corewing.app.util.OSSUploadUtil;
import org.springframework.stereotype.Service;
@@ -13,7 +16,9 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Objects;
/**
* 固件 Service 实现类
@@ -21,9 +26,12 @@ import java.io.IOException;
@Service
public class FirmwareServiceImpl extends ServiceImpl<FirmwareMapper, Firmware> implements FirmwareService {
@Resource
private BizDeviceCategoryService bizDeviceCategoryService;
@Override
public Page<Firmware> page(Firmware firmware) {
Page<Firmware> page = PageContext.getPage(Firmware.class);
Page<Firmware> page = PageContext.getDefaultPage(Firmware.class);
LambdaQueryWrapper<Firmware> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(firmware.getFirmwareName()), Firmware::getFirmwareName, firmware.getFirmwareName());
queryWrapper.eq(firmware.getFirmwareType() != null, Firmware::getFirmwareType, firmware.getFirmwareType());
@@ -63,6 +71,30 @@ public class FirmwareServiceImpl extends ServiceImpl<FirmwareMapper, Firmware> i
return false;
}
@Override
public Firmware checkVersion(FirmwareVersionRequest firmwareVersionRequest) {
// 根据型号id搜索到设备分类id
LambdaQueryWrapper<BizDeviceCategory> categoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
categoryLambdaQueryWrapper.eq(BizDeviceCategory::getModelId, firmwareVersionRequest.getModelId());
BizDeviceCategory deviceCategory = bizDeviceCategoryService.getOne(categoryLambdaQueryWrapper);
if(Objects.isNull(deviceCategory)){
throw new RuntimeException("该设备型号不存在设备");
}
LambdaQueryWrapper<Firmware> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(Firmware::getVersionId, firmwareVersionRequest.getVersion());
wrapper.eq(Firmware::getModelId, deviceCategory.getId());
wrapper.eq(Firmware::getFirmwareType, firmwareVersionRequest.getFirmwareType());
wrapper.orderByDesc(Firmware::getVersionId);
wrapper.last("LIMIT 1");
Firmware firmware = this.getOne(wrapper);
if (firmware == null) {
throw new RuntimeException("未找到匹配的固件版本");
}
return firmware;
}
/**
* 获取 URL 路径的最后一节(忽略查询参数 ? 和锚点 #
* @param urlStr URL字符串

View File

@@ -16,7 +16,7 @@ public class PrivacyPolicyServiceImpl extends ServiceImpl<PrivacyPolicyMapper, P
@Override
public Page<PrivacyPolicy> page(PrivacyPolicy privacyPolicy) {
Page<PrivacyPolicy> page = PageContext.getPage(PrivacyPolicy.class);
Page<PrivacyPolicy> page = PageContext.getDefaultPage(PrivacyPolicy.class);
LambdaQueryWrapper<PrivacyPolicy> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(privacyPolicy.getTitle()), PrivacyPolicy::getTitle, privacyPolicy.getTitle());
queryWrapper.eq(privacyPolicy.getVisible() != null, PrivacyPolicy::getVisible, privacyPolicy.getVisible());

View File

@@ -0,0 +1,241 @@
package com.corewing.app.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.common.Result;
import com.corewing.app.dto.qc.StepResultData;
import com.corewing.app.dto.qc.UploadTestRecordRequest;
import com.corewing.app.dto.qc.ValidateSnRequest;
import com.corewing.app.entity.FlightController;
import com.corewing.app.entity.QcPhoto;
import com.corewing.app.entity.QcStepResult;
import com.corewing.app.entity.QcTestRecord;
import com.corewing.app.mapper.FlightControllerMapper;
import com.corewing.app.mapper.QcPhotoMapper;
import com.corewing.app.mapper.QcStepResultMapper;
import com.corewing.app.mapper.QcTestRecordMapper;
import com.corewing.app.service.QcTestService;
import com.corewing.app.util.OSSUploadUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Service
public class QcTestServiceImpl extends ServiceImpl<QcTestRecordMapper, QcTestRecord> implements QcTestService {
@Resource
private QcStepResultMapper qcStepResultMapper;
@Resource
private QcPhotoMapper qcPhotoMapper;
@Resource
private FlightControllerMapper flightControllerMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Result<String> uploadTestRecord(UploadTestRecordRequest request) {
if (request.getTestNo() == null || request.getTestNo().isEmpty()) {
return Result.error("测试单号不能为空");
}
// 查找是否已存在相同 testNo 的记录
LambdaQueryWrapper<QcTestRecord> testNoQuery = new LambdaQueryWrapper<>();
testNoQuery.eq(QcTestRecord::getTestNo, request.getTestNo());
QcTestRecord existByTestNo = baseMapper.selectOne(testNoQuery);
QcTestRecord record;
if (existByTestNo != null) {
// 相同 testNo 已存在 → 更新APP 重传场景)
record = existByTestNo;
fillRecord(record, request);
baseMapper.updateById(record);
// 清除旧的步骤和照片,后面重新插入
deleteStepsAndPhotos(record.getId());
} else {
// 查找同一 SN 是否已有记录(返修重测场景)
LambdaQueryWrapper<QcTestRecord> snQuery = new LambdaQueryWrapper<>();
snQuery.eq(QcTestRecord::getSn, request.getSn())
.eq(QcTestRecord::getProductType, request.getProductType())
.orderByDesc(QcTestRecord::getCreateTime)
.last("LIMIT 1");
QcTestRecord existBySn = baseMapper.selectOne(snQuery);
if (existBySn != null) {
// 同一 SN 已有记录 → 更新最近一条(返修后重新 QC
record = existBySn;
fillRecord(record, request);
baseMapper.updateById(record);
deleteStepsAndPhotos(record.getId());
} else {
// 全新记录
record = new QcTestRecord();
fillRecord(record, request);
baseMapper.insert(record);
}
}
// 保存步骤结果
if (!CollectionUtils.isEmpty(request.getSteps())) {
for (StepResultData stepData : request.getSteps()) {
QcStepResult step = new QcStepResult();
BeanUtils.copyProperties(stepData, step, "completedAt");
step.setTestRecordId(record.getId());
step.setCompletedAt(parseTimestamp(stepData.getCompletedAt()));
qcStepResultMapper.insert(step);
}
}
// 保存照片 URL
if (!CollectionUtils.isEmpty(request.getPhotoUrls())) {
for (String photoUrl : request.getPhotoUrls()) {
QcPhoto photo = new QcPhoto();
photo.setTestRecordId(record.getId());
photo.setTestNo(request.getTestNo());
photo.setUrl(photoUrl);
qcPhotoMapper.insert(photo);
}
}
// 返回报告 URL可为 null
return Result.success("上传成功", record.getReportUrl());
}
private void fillRecord(QcTestRecord record, UploadTestRecordRequest request) {
// 拷贝同名同类型字段testNo, productType, sn, operatorId, operatorName, phoneModel, appVersion, status
BeanUtils.copyProperties(request, record, "createTime", "updatedAt", "uploadTime");
// 时间戳字符串 → LocalDateTime 需要手动转换
record.setCreateTime(parseTimestamp(request.getCreateTime()));
record.setUpdatedAt(parseTimestamp(request.getUpdatedAt()));
record.setUploadTime(parseTimestamp(request.getUploadTime()));
}
private void deleteStepsAndPhotos(Long recordId) {
LambdaQueryWrapper<QcStepResult> stepDelete = new LambdaQueryWrapper<>();
stepDelete.eq(QcStepResult::getTestRecordId, recordId);
qcStepResultMapper.delete(stepDelete);
LambdaQueryWrapper<QcPhoto> photoDelete = new LambdaQueryWrapper<>();
photoDelete.eq(QcPhoto::getTestRecordId, recordId);
qcPhotoMapper.delete(photoDelete);
}
@Override
public Result<Map<String, String>> uploadPhoto(String testNo, MultipartFile photo) {
if (photo == null || photo.isEmpty()) {
return Result.error("照片文件不能为空");
}
if (testNo == null || testNo.isEmpty()) {
return Result.error("测试单号不能为空");
}
// 查找对应的测试记录
LambdaQueryWrapper<QcTestRecord> query = new LambdaQueryWrapper<>();
query.eq(QcTestRecord::getTestNo, testNo);
QcTestRecord record = baseMapper.selectOne(query);
if (record == null) {
return Result.error("测试记录不存在: " + testNo);
}
try {
// 生成 OSS 存储路径
String originalFilename = photo.getOriginalFilename();
String suffix = "";
if (originalFilename != null && originalFilename.contains(".")) {
suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
}
String objectName = "qc/photos/" + testNo + "/" + UUID.randomUUID().toString().replace("-", "") + suffix;
// 上传到 OSS
String url = OSSUploadUtil.uploadFile(photo.getInputStream(), objectName);
// 保存照片记录
QcPhoto qcPhoto = new QcPhoto();
qcPhoto.setTestRecordId(record.getId());
qcPhoto.setTestNo(testNo);
qcPhoto.setUrl(url);
qcPhotoMapper.insert(qcPhoto);
Map<String, String> result = new HashMap<>();
result.put("url", url);
return Result.success("上传成功", result);
} catch (Exception e) {
log.error("照片上传失败", e);
return Result.error("照片上传失败: " + e.getMessage());
}
}
@Override
public Result<Boolean> validateSn(ValidateSnRequest request) {
if (request.getSn() == null || request.getSn().isEmpty()) {
return Result.error("SN 不能为空");
}
LambdaQueryWrapper<FlightController> query = new LambdaQueryWrapper<>();
query.eq(FlightController::getSn, request.getSn());
Long count = flightControllerMapper.selectCount(query);
if (count > 0) {
return Result.success("SN 有效", true);
}
return Result.error("SN 无效或未注册");
}
@Override
public Result<List<QcTestRecord>> getHistory(String sn) {
if (sn == null || sn.isEmpty()) {
return Result.error("SN 不能为空");
}
LambdaQueryWrapper<QcTestRecord> query = new LambdaQueryWrapper<>();
query.eq(QcTestRecord::getSn, sn)
.orderByDesc(QcTestRecord::getCreateTime);
List<QcTestRecord> records = baseMapper.selectList(query);
return Result.success(records);
}
@Override
public Result<String> getReport(String testNo) {
if (testNo == null || testNo.isEmpty()) {
return Result.error("测试单号不能为空");
}
LambdaQueryWrapper<QcTestRecord> query = new LambdaQueryWrapper<>();
query.eq(QcTestRecord::getTestNo, testNo);
QcTestRecord record = baseMapper.selectOne(query);
if (record == null) {
return Result.error("测试记录不存在");
}
return Result.success(record.getReportUrl());
}
private LocalDateTime parseTimestamp(String timestamp) {
if (timestamp == null || timestamp.isEmpty()) {
return null;
}
try {
long millis = Long.parseLong(timestamp);
if (millis <= 0) {
return null;
}
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault());
} catch (NumberFormatException e) {
return null;
}
}
}

View File

@@ -0,0 +1,25 @@
package com.corewing.app.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.corewing.app.entity.SiriusFirmware;
import com.corewing.app.mapper.SiriusFirmwareMapper;
import com.corewing.app.service.SiriusFirmwareService;
import org.springframework.stereotype.Service;
/**
* Sirius固件信息 Service 实现类
*/
@Service
public class SiriusFirmwareServiceImpl extends ServiceImpl<SiriusFirmwareMapper, SiriusFirmware> implements SiriusFirmwareService {
@Override
public SiriusFirmware getLatestByTypeAndProtocol(Integer firmwareType, Integer protocolType) {
LambdaQueryWrapper<SiriusFirmware> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SiriusFirmware::getFirmwareType, firmwareType);
wrapper.eq(SiriusFirmware::getProtocolType, protocolType);
wrapper.orderByDesc(SiriusFirmware::getCreateTime);
wrapper.last("LIMIT 1");
return getOne(wrapper);
}
}

View File

@@ -23,7 +23,7 @@ import java.time.LocalDateTime;
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
public Page<SysUser> page(SysUser sysUser) {
Page<SysUser> page = PageContext.getPage(SysUser.class);
Page<SysUser> page = PageContext.getDefaultPage(SysUser.class);
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(sysUser.getStatus() != null, SysUser::getStatus, sysUser.getStatus());
queryWrapper.like(StringUtils.hasText(sysUser.getUsername()), SysUser::getUsername, sysUser.getUsername());

View File

@@ -14,7 +14,7 @@ import org.springframework.util.StringUtils;
public class TutorialCategoryServiceImpl extends ServiceImpl<TutorialCategoryMapper, TutorialCategory> implements TutorialCategoryService {
public Page<TutorialCategory> page(TutorialCategory tutorialCategory){
Page<TutorialCategory> page = PageContext.getPage(TutorialCategory.class);
Page<TutorialCategory> page = PageContext.getDefaultPage(TutorialCategory.class);
LambdaQueryWrapper<TutorialCategory> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(tutorialCategory.getCategoryTitle()), TutorialCategory::getCategoryTitle, tutorialCategory.getCategoryTitle());

View File

@@ -24,9 +24,6 @@ public class TutorialServiceImpl extends ServiceImpl<TutorialMapper, Tutorial> i
@Resource
private TutorialCategoryRelationService tutorialCategoryRelationService;
@Resource
private TutorialCategoryService tutorialCategoryService;
@Override
public Page<Tutorial> pageList(Page<Tutorial> page, Long categoryId, String tutorialTitle, String lang) {
return tutorialMapper.pageList(page, categoryId, tutorialTitle, lang);
@@ -34,7 +31,7 @@ public class TutorialServiceImpl extends ServiceImpl<TutorialMapper, Tutorial> i
@Override
public Page<Tutorial> page(Tutorial tutorial) {
Page<Tutorial> page = PageContext.getPage(Tutorial.class);
Page<Tutorial> page = PageContext.getDefaultPage(Tutorial.class);
return tutorialMapper.page(page, tutorial);
}

View File

@@ -25,6 +25,7 @@ import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 应用用户 Service 实现类
@@ -36,9 +37,6 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
@Resource
private VerifyCodeService verifyCodeService;
@Resource
private UserMapper userMapper;
@Resource
private RedisUtil redisUtil;
@@ -51,7 +49,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
@Override
public Page<User> page(User user) {
Page<User> page = PageContext.getPage(User.class);
Page<User> page = PageContext.getDefaultPage(User.class);
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.hasText(user.getNickName()), User::getNickName, user.getNickName());
queryWrapper.like(StringUtils.hasText(user.getUsername()), User::getUsername, user.getUsername());
@@ -295,7 +293,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
throw new RuntimeException(I18nUtil.getMessage("error.verify.code.invalid"));
}
StpUtil.logout();
DevLogUtil.executeLogoutLog(user.getUsername());
// 删除记录
this.removeById(user.getId());
return true;
@@ -318,6 +316,17 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
// 发送验证码
if (StringUtils.hasText(user.getTelephone())) {
// 获取当前ip
String clientIp = IpUtil.getClientIp(CommonServletUtil.getRequest());
clientIp = clientIp.replaceAll(":", "");
// 使用 setIfAbsent 初始化计数器只在键不存在时创建并设置过期时间为1天
boolean isNew = redisUtil.setIfAbsent("exceed_" + clientIp, 1, 1, TimeUnit.DAYS);
// 如果键已存在,递增计数器
long sendCount = isNew ? 1 : redisUtil.incr("exceed_" + clientIp, 1);
if (sendCount <= 4) {
// 发送短信验证码
boolean success = smsBaoUtil.sendVerifyCode(user.getTelephone(), code);
if (!success) {
@@ -326,6 +335,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
Map<String, String> map = new HashMap<>();
map.put("account", user.getTelephone());
return Result.success(map);
}
throw new RuntimeException(I18nUtil.getMessage("error.sms.send.exceed"));
} else {
// 发送邮件验证码
boolean success = emailUtil.sendVerifyCode(user.getEmail(), code);

View File

@@ -6,7 +6,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* 验证码服务实现类
@@ -30,6 +30,7 @@ public class VerifyCodeServiceImpl implements VerifyCodeService {
@Override
public boolean sendCode(String account, String type) {
if (!StringUtils.hasText(account)) {
throw new RuntimeException(I18nUtil.getMessage("error.account.empty"));
}
@@ -53,11 +54,24 @@ public class VerifyCodeServiceImpl implements VerifyCodeService {
// 发送验证码
if (AccountUtil.isPhone(account)) {
// 获取当前ip
String clientIp = IpUtil.getClientIp(CommonServletUtil.getRequest());
clientIp = clientIp.replaceAll(":", "");
// 校验IP发短信次数
// 使用 setIfAbsent 初始化计数器只在键不存在时创建并设置过期时间为1天
boolean isNew = redisUtil.setIfAbsent("exceed_" + clientIp, 1, 1, TimeUnit.DAYS);
// 如果键已存在,递增计数器
long sendCount = isNew ? 1 : redisUtil.incr("exceed_" + clientIp, 1);
if (sendCount <= 4) {
// 发送短信验证码
boolean success = smsBaoUtil.sendVerifyCode(account, code);
if (!success) {
throw new RuntimeException(I18nUtil.getMessage("error.sms.send.failed"));
}
} else {
throw new RuntimeException(I18nUtil.getMessage("error.sms.send.exceed"));
}
} else {
// 发送邮件验证码
boolean success = emailUtil.sendVerifyCode(account, code);

View File

@@ -18,8 +18,6 @@ import java.io.InputStream;
* 根据ip地址定位工具类离线方式
* 参考地址:<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">ip2region</a>
*
* @author xuyuxiang
* @date 2020/3/16 11:25
*/
@Slf4j
public class CommonIpAddressUtil {
@@ -62,8 +60,6 @@ public class CommonIpAddressUtil {
/**
* 获取客户端ip
*
* @author xuyuxiang
* @date 2020/3/19 9:32
*/
public static String getIp(HttpServletRequest request) {
if (ObjectUtil.isEmpty(request)) {
@@ -81,8 +77,6 @@ public class CommonIpAddressUtil {
/**
* 根据IP地址离线获取城市
*
* @author xuyuxiang
* @date 2022/4/27 23:14
*/
public static String getCityInfo(String ip) {
try {

Some files were not shown because too many files have changed in this diff Show More