彩票助手后端1.0
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/mvnw text eol=lf
|
||||
*.cmd text eol=crlf
|
||||
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
19
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
19
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
wrapperVersion=3.3.2
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.10/apache-maven-3.9.10-bin.zip
|
||||
484
Excel导入使用说明.md
Normal file
484
Excel导入使用说明.md
Normal file
@@ -0,0 +1,484 @@
|
||||
# Excel数据导入功能使用说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
本系统提供了Excel数据导入功能,可以将包含T1、T2、T3、T4、T5、T6、T7、T8、T10和T11工作表的Excel文件数据导入到十四个数据库表中:
|
||||
|
||||
### 红球数据(T1 Sheet):
|
||||
- `history_all` - 红球全部历史数据表
|
||||
- `history_100` - 红球最近100期数据表
|
||||
- `history_top` - 红球历史数据排行表
|
||||
- `history_top_100` - 红球100期数据排行表
|
||||
|
||||
### 蓝球数据(T2 Sheet):
|
||||
- `blue_history_all` - 蓝球全部历史数据表
|
||||
- `blue_history_100` - 蓝球最近100期数据表
|
||||
- `blue_history_top` - 蓝球历史数据排行表
|
||||
- `blue_history_top_100` - 蓝球100期数据排行表
|
||||
|
||||
### 红球线系数数据(T3 Sheet):
|
||||
- `t3` - 红球组红球的线系数表
|
||||
|
||||
### 蓝球组红球线系数数据(T4 Sheet):
|
||||
- `t4` - 蓝球组红球的线系数表
|
||||
|
||||
### 蓝球组蓝球线系数数据(T5 Sheet):
|
||||
- `t5` - 蓝球组蓝球的线系数表
|
||||
|
||||
### 红球组蓝球线系数数据(T6 Sheet):
|
||||
- `t6` - 红球组蓝球的线系数表
|
||||
|
||||
### 红球组红球面系数数据(T7 Sheet):
|
||||
- `t7` - 红球组红球的面系数表
|
||||
|
||||
### 红球组蓝球面系数数据(T8 Sheet):
|
||||
- `t8` - 红球组蓝球的面系数表
|
||||
|
||||
### 彩票开奖信息数据(T10 Sheet):
|
||||
- `lottery_draws` - 彩票开奖信息表
|
||||
|
||||
### 蓝球组红球面系数数据(T11 Sheet):
|
||||
- `t11` - 蓝球组红球的面系数表
|
||||
|
||||
## Excel文件格式要求
|
||||
|
||||
### 文件要求
|
||||
- **文件格式**:必须是`.xlsx`格式
|
||||
- **工作表名称**:必须包含名为`T1`、`T2`、`T3`、`T4`、`T5`、`T6`、`T7`、`T8`、`T10`和`T11`的工作表
|
||||
- **编码**:支持中文
|
||||
|
||||
### 数据结构要求
|
||||
|
||||
**T1工作表(红球数据)**的数据结构如下:
|
||||
|
||||
| 列位置 | 列名 | 对应表 | 字段说明 |
|
||||
|--------|------|--------|----------|
|
||||
| A-G | 全部历史数据 | history_all | 球号、出现频次、出现频率%、平均隐现期次、最长隐现期次、最多连出期次、点系数 |
|
||||
| H-M | 最近100期数据 | history_100 | 出现频次、出现频率%、平均隐现期、当前隐现期、最多连出期次、点系数 |
|
||||
| N-P | 历史数据排行 | history_top | 排行、球号、点系数 |
|
||||
| Q-S | 100期数据排行 | history_top_100 | 排行、球号、点系数 |
|
||||
|
||||
**T2工作表(蓝球数据)**的数据结构如下:
|
||||
|
||||
| 列位置 | 列名 | 对应表 | 字段说明 |
|
||||
|--------|------|--------|----------|
|
||||
| A-G | 全部历史数据 | blue_history_all | 球号、出现频次、出现频率%、平均隐现期次、最长隐现期次、最多连出期次、点系数 |
|
||||
| H-M | 最近100期数据 | blue_history_100 | 出现频次、出现频率%、平均隐现期、当前隐现期、最多连出期次、点系数 |
|
||||
| N-P | 历史数据排行 | blue_history_top | 排行、球号、点系数 |
|
||||
| Q-S | 100期数据排行 | blue_history_top_100 | 排行、球号、点系数 |
|
||||
|
||||
**T3工作表(红球线系数数据)**的数据结构如下:
|
||||
|
||||
| 列位置 | 数据组织 | 对应表 | 字段说明 |
|
||||
|--------|----------|--------|----------|
|
||||
| C | 1号组线系数 | t3 | 主球=1,从球=1-33,线系数=C列 |
|
||||
| F | 2号组线系数 | t3 | 主球=2,从球=1-33,线系数=F列 |
|
||||
| I | 3号组线系数 | t3 | 主球=3,从球=1-33,线系数=I列 |
|
||||
| ... | 依此类推 | t3 | 每三列为一组,组号即主球号 |
|
||||
|
||||
**说明**:T3工作表每三列为一组数据,每组有33行数据,从球号固定为1-33(行号),线系数在C、F、I、L...列。
|
||||
|
||||
**T4工作表(蓝球组红球线系数数据)**的数据结构如下:
|
||||
|
||||
| 列位置 | 数据组织 | 对应表 | 字段说明 |
|
||||
|--------|----------|--------|----------|
|
||||
| C | 蓝球1号线系数 | t4 | 主球=1,从球=1-33,线系数=C列 |
|
||||
| F | 蓝球2号线系数 | t4 | 主球=2,从球=1-33,线系数=F列 |
|
||||
| I | 蓝球3号线系数 | t4 | 主球=3,从球=1-33,线系数=I列 |
|
||||
| ... | 依此类推 | t4 | 每三列为一组,最多16组 |
|
||||
|
||||
**说明**:T4工作表每三列为一组数据,每组有33行数据,蓝球号码1-16(主球),红球号码1-33(从球,行号),线系数在C、F、I、L...列。
|
||||
|
||||
**T5工作表(蓝球组蓝球线系数数据)**的数据结构如下:
|
||||
|
||||
| 列位置 | 数据组织 | 对应表 | 字段说明 |
|
||||
|--------|----------|--------|----------|
|
||||
| C | 蓝球1号线系数 | t5 | 主球=1,从球=1-16,线系数=C列 |
|
||||
| F | 蓝球2号线系数 | t5 | 主球=2,从球=1-16,线系数=F列 |
|
||||
| I | 蓝球3号线系数 | t5 | 主球=3,从球=1-16,线系数=I列 |
|
||||
| ... | 依此类推 | t5 | 每三列为一组,最多16组 |
|
||||
|
||||
**说明**:T5工作表每三列为一组数据,每组有16行数据,蓝球号码1-16(主球和从球),线系数在C、F、I、L...列。
|
||||
|
||||
**T6工作表(红球组蓝球线系数数据)**的数据结构如下:
|
||||
|
||||
| 列位置 | 数据组织 | 对应表 | 字段说明 |
|
||||
|--------|----------|--------|----------|
|
||||
| C | 红球1号线系数 | t6 | 主球=1,从球=1-16,线系数=C列 |
|
||||
| F | 红球2号线系数 | t6 | 主球=2,从球=1-16,线系数=F列 |
|
||||
| I | 红球3号线系数 | t6 | 主球=3,从球=1-16,线系数=I列 |
|
||||
| ... | 依此类推 | t6 | 每三列为一组,最多33组 |
|
||||
|
||||
**说明**:T6工作表每三列为一组数据,每组有16行数据,红球号码1-33(主球),蓝球号码1-16(从球,行号),线系数在C、F、I、L...列。
|
||||
|
||||
**T7工作表(红球组红球面系数数据)**的数据结构如下:
|
||||
|
||||
| 列位置 | 数据组织 | 对应表 | 字段说明 |
|
||||
|--------|----------|--------|----------|
|
||||
| C | 红球1号面系数 | t7 | 主球=1,从球=2-33,面系数=C列 |
|
||||
| F | 红球2号面系数 | t7 | 主球=2,从球=1,3-33,面系数=F列 |
|
||||
| I | 红球3号面系数 | t7 | 主球=3,从球=1-2,4-33,面系数=I列 |
|
||||
| ... | 依此类推 | t7 | 每三列为一组,最多33组 |
|
||||
|
||||
**说明**:T7工作表每三列为一组数据,每组有33行数据,红球号码1-33(主球和从球),面系数在C、F、I、L...列。**特殊处理**:排除自己和自己组合的情况。
|
||||
|
||||
**Excel数据结构**:
|
||||
- **第1行**:标题行(1号组、面系数、2号组、面系数...)
|
||||
- **第2行**:从球1号的数据(对应所有主球的面系数)
|
||||
- **第3行**:从球2号的数据(对应所有主球的面系数)
|
||||
- **...**
|
||||
- **第34行**:从球33号的数据(对应所有主球的面系数)
|
||||
|
||||
**处理逻辑**:
|
||||
- **1号组(主球1)**:
|
||||
- 球号列:B列,面系数列:C列
|
||||
- 读取所有行,从B列获取从球号,从C列获取面系数
|
||||
- 排除对角线(主球1=从球1的情况)
|
||||
- **2号组(主球2)**:
|
||||
- 球号列:E列,面系数列:F列
|
||||
- 读取所有行,从E列获取从球号,从F列获取面系数
|
||||
- 排除对角线(主球2=从球2的情况)
|
||||
- **依此类推...**
|
||||
|
||||
**关键改进**:
|
||||
- **动态读取球号**:从Excel的球号列(B、E、H...)读取实际球号,不依赖行号
|
||||
- **完整数据覆盖**:读取到Excel的最后一行,确保包含33号球数据
|
||||
- **不排除对角线**:读取到什么数据就插入什么数据,包括主球=从球的情况
|
||||
- **最终生成**:33×33=1089条记录
|
||||
|
||||
### 具体列映射
|
||||
|
||||
#### 红球表映射(T1 Sheet)
|
||||
|
||||
**history_all 表 (列A-G)**
|
||||
- A列:球号 (ballNumber)
|
||||
- B列:出现频次 (frequencyCount)
|
||||
- C列:出现频率% (frequencyPercentage)
|
||||
- D列:平均隐现期次 (averageInterval)
|
||||
- E列:最长隐现期次 (maxHiddenInterval)
|
||||
- F列:最多连出期次 (maxConsecutiveCount)
|
||||
- G列:点系数 (pointCoefficient)
|
||||
|
||||
**history_100 表 (列H-M,球号使用A列)**
|
||||
- A列:球号 (ballNumber)
|
||||
- H列:出现频次 (frequencyCount)
|
||||
- J列:平均隐现期 (averageInterval)
|
||||
- K列:当前隐现期 (nowInterval)
|
||||
- L列:最多连出期次 (maxConsecutiveCount)
|
||||
- M列:点系数 (pointCoefficient)
|
||||
|
||||
**history_top 表 (列N-P)**
|
||||
- N列:排行 (no)
|
||||
- O列:球号 (ballNumber)
|
||||
- P列:点系数 (pointCoefficient)
|
||||
|
||||
**history_top_100 表 (列Q-S)**
|
||||
- Q列:排行 (no)
|
||||
- R列:球号 (ballNumber)
|
||||
- S列:点系数 (pointCoefficient)
|
||||
|
||||
#### 蓝球表映射(T2 Sheet)
|
||||
|
||||
**blue_history_all 表 (列A-G)**
|
||||
- A列:球号 (ballNumber)
|
||||
- B列:出现频次 (frequencyCount)
|
||||
- C列:出现频率% (frequencyPercentage)
|
||||
- D列:平均隐现期次 (averageInterval)
|
||||
- E列:最长隐现期次 (maxHiddenInterval)
|
||||
- F列:最多连出期次 (maxConsecutiveCount)
|
||||
- G列:点系数 (pointCoefficient)
|
||||
|
||||
**blue_history_100 表 (列H-M,球号使用A列)**
|
||||
- A列:球号 (ballNumber)
|
||||
- H列:出现频次 (frequencyCount)
|
||||
- J列:平均隐现期 (averageInterval)
|
||||
- K列:当前隐现期 (nowInterval)
|
||||
- L列:最多连出期次 (maxConsecutiveCount)
|
||||
- M列:点系数 (pointCoefficient)
|
||||
|
||||
**blue_history_top 表 (列N-P)**
|
||||
- N列:排行 (no)
|
||||
- O列:球号 (ballNumber)
|
||||
- P列:点系数 (pointCoefficient)
|
||||
|
||||
**blue_history_top_100 表 (列Q-S)**
|
||||
- Q列:排行 (no)
|
||||
- R列:球号 (ballNumber)
|
||||
- S列:点系数 (pointCoefficient)
|
||||
|
||||
#### T3表映射(T3 Sheet)
|
||||
|
||||
**t3 表(红球线系数数据)**
|
||||
- 数据组织:每三列为一组,每组33行数据
|
||||
- 红球号码范围:1-33(主球和从球都是)
|
||||
- 线系数位置:C、F、I、L...列
|
||||
|
||||
**数据映射**:
|
||||
- C列:红球1号线系数(主球=1,从球=1-33,线系数=C列)
|
||||
- F列:红球2号线系数(主球=2,从球=1-33,线系数=F列)
|
||||
- I列:红球3号线系数(主球=3,从球=1-33,线系数=I列)
|
||||
- 依此类推...
|
||||
|
||||
**字段映射**:
|
||||
- masterBallNumber:主红球号码(1-33)
|
||||
- slaveBallNumber:从红球号码(固定1-33,对应行号)
|
||||
- lineCoefficient:线系数(每组第三列,保留两位小数)
|
||||
|
||||
#### T4表映射(T4 Sheet)
|
||||
|
||||
**t4 表(蓝球组红球的线系数)**
|
||||
- 数据组织:每三列为一组,每组33行数据
|
||||
- 蓝球号码范围:1-16(主球)
|
||||
- 红球号码范围:1-33(从球,对应行号)
|
||||
- 线系数位置:C、F、I、L...列
|
||||
|
||||
**数据映射**:
|
||||
- C列:蓝球1号线系数(主球=1,从球=1-33,线系数=C列)
|
||||
- F列:蓝球2号线系数(主球=2,从球=1-33,线系数=F列)
|
||||
- I列:蓝球3号线系数(主球=3,从球=1-33,线系数=I列)
|
||||
- 依此类推...
|
||||
|
||||
**字段映射**:
|
||||
- masterBallNumber:蓝球号码(1-16)
|
||||
- slaveBallNumber:红球号码(固定1-33,对应行号)
|
||||
- lineCoefficient:线系数(每组第三列,保留两位小数)
|
||||
|
||||
#### T5表映射(T5 Sheet)
|
||||
|
||||
**t5 表(蓝球组蓝球的线系数)**
|
||||
- 数据组织:每三列为一组,每组16行数据
|
||||
- 蓝球号码范围:1-16(主球和从球都是)
|
||||
- 线系数位置:C、F、I、L...列
|
||||
|
||||
**数据映射**:
|
||||
- C列:蓝球1号线系数(主球=1,从球=1-16,线系数=C列)
|
||||
- F列:蓝球2号线系数(主球=2,从球=1-16,线系数=F列)
|
||||
- I列:蓝球3号线系数(主球=3,从球=1-16,线系数=I列)
|
||||
- 依此类推...
|
||||
|
||||
**字段映射**:
|
||||
- masterBallNumber:主蓝球号码(1-16)
|
||||
- slaveBallNumber:从蓝球号码(固定1-16,对应行号)
|
||||
- lineCoefficient:线系数(每组第三列,保留两位小数)
|
||||
|
||||
#### T6表映射(T6 Sheet)
|
||||
|
||||
**t6 表(红球组蓝球的线系数)**
|
||||
- 数据组织:每三列为一组,每组16行数据
|
||||
- 红球号码范围:1-33(主球)
|
||||
- 蓝球号码范围:1-16(从球)
|
||||
- 线系数位置:C、F、I、L...列
|
||||
|
||||
**数据映射**:
|
||||
- C列:红球1号线系数(主球=1,从球=1-16,线系数=C列)
|
||||
- F列:红球2号线系数(主球=2,从球=1-16,线系数=F列)
|
||||
- I列:红球3号线系数(主球=3,从球=1-16,线系数=I列)
|
||||
- 依此类推...
|
||||
|
||||
**字段映射**:
|
||||
- masterBallNumber:主红球号码(1-33)
|
||||
- slaveBallNumber:从蓝球号码(固定1-16,对应行号)
|
||||
- lineCoefficient:线系数(每组第三列,保留两位小数)
|
||||
|
||||
#### T7表映射(T7 Sheet)
|
||||
|
||||
**t7 表(红球组红球的面系数)**
|
||||
- 数据组织:每三列为一组,每组33行数据
|
||||
- 红球号码范围:1-33(主球和从球都是)
|
||||
- 面系数位置:C、F、I、L...列
|
||||
- 特殊处理:读取到什么数据就插入什么数据,包括对角线
|
||||
|
||||
**数据映射**:
|
||||
- C列:红球1号面系数(主球=1,从球=1-33,面系数=C列)
|
||||
- F列:红球2号面系数(主球=2,从球=1-33,面系数=F列)
|
||||
- I列:红球3号面系数(主球=3,从球=1-33,面系数=I列)
|
||||
- 依此类推...
|
||||
|
||||
**字段映射**:
|
||||
- masterBallNumber:主红球号码(1-33)
|
||||
- slaveBallNumber:从红球号码(1-33,包括与主球相同的号码)
|
||||
- faceCoefficient:面系数(每组第三列,保留两位小数)
|
||||
|
||||
#### T8表映射(T8 Sheet)
|
||||
|
||||
**t8 表(红球组蓝球的面系数)**
|
||||
- 数据组织:每三列为一组,每组16行数据
|
||||
- 红球号码范围:1-33(主球)
|
||||
- 蓝球号码范围:1-16(从球)
|
||||
- 面系数位置:C、F、I、L...列
|
||||
|
||||
**数据映射**:
|
||||
- C列:红球1号面系数(主球=1,从球=1-16,面系数=C列)
|
||||
- F列:红球2号面系数(主球=2,从球=1-16,面系数=F列)
|
||||
- I列:红球3号面系数(主球=3,从球=1-16,面系数=I列)
|
||||
- 依此类推...
|
||||
|
||||
**字段映射**:
|
||||
- masterBallNumber:主红球号码(1-33)
|
||||
- slaveBallNumber:从蓝球号码(固定1-16,对应行号)
|
||||
- faceCoefficient:面系数(每组第三列,保留两位小数)
|
||||
|
||||
#### T10表映射(T10 Sheet)
|
||||
|
||||
**lottery_draws 表(彩票开奖信息)**
|
||||
- 数据组织:标准表格结构,每行一条开奖记录
|
||||
- 开奖期号:Long类型主键
|
||||
- 开奖日期:Date类型,支持多种格式
|
||||
- 红球1-6:Integer类型
|
||||
- 蓝球:Integer类型
|
||||
|
||||
**数据映射**:
|
||||
- A列:开奖期号(drawId)
|
||||
- B列:开奖日期(drawDate)
|
||||
- C列:红球1(redBall1)
|
||||
- D列:红球2(redBall2)
|
||||
- E列:红球3(redBall3)
|
||||
- F列:红球4(redBall4)
|
||||
- G列:红球5(redBall5)
|
||||
- H列:红球6(redBall6)
|
||||
- I列:蓝球(blueBall)
|
||||
|
||||
**字段映射**:
|
||||
- drawId:开奖期号(Long类型,主键)
|
||||
- drawDate:开奖日期(Date类型,支持yyyy-MM-dd、yyyy/MM/dd等格式)
|
||||
- redBall1-redBall6:红球1-6(Integer类型)
|
||||
- blueBall:蓝球(Integer类型)
|
||||
|
||||
**数据特性**:
|
||||
- 所有字段均为必填项
|
||||
- 开奖期号为主键,不能重复
|
||||
- 日期格式自动识别和转换
|
||||
- 数据完整性验证
|
||||
|
||||
#### T11表映射(T11 Sheet)
|
||||
|
||||
**t11 表(蓝球组红球的面系数)**
|
||||
- 数据组织:每三列为一组,每组33行数据
|
||||
- 蓝球号码范围:1-16(主球)
|
||||
- 红球号码范围:1-33(从球)
|
||||
- 面系数位置:C、F、I、L...列
|
||||
|
||||
**数据映射**:
|
||||
- C列:蓝球1号面系数(主球=1,从球=1-33,面系数=C列)
|
||||
- F列:蓝球2号面系数(主球=2,从球=1-33,面系数=F列)
|
||||
- I列:蓝球3号面系数(主球=3,从球=1-33,面系数=I列)
|
||||
- 依此类推...
|
||||
|
||||
**字段映射**:
|
||||
- masterBallNumber:主蓝球号码(1-16)
|
||||
- slaveBallNumber:从红球号码(固定1-33,对应行号)
|
||||
- faceCoefficient:面系数(每组第三列,保留两位小数)
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. API接口方式
|
||||
|
||||
#### 1.1 文件上传导入
|
||||
```http
|
||||
POST /api/excel/upload
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
参数:
|
||||
- file: Excel文件 (.xlsx格式)
|
||||
```
|
||||
|
||||
#### 1.2 文件路径导入
|
||||
```http
|
||||
POST /api/excel/import-by-path
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
参数:
|
||||
- filePath: Excel文件的完整路径 (例如: D:/data/kaifa1.xlsx)
|
||||
```
|
||||
|
||||
#### 1.3 获取导入说明
|
||||
```http
|
||||
GET /api/excel/import-info
|
||||
```
|
||||
|
||||
### 2. 程序调用方式
|
||||
|
||||
```java
|
||||
@Autowired
|
||||
private ExcelImportService excelImportService;
|
||||
|
||||
// 方式1:通过文件路径导入
|
||||
String result = excelImportService.importExcelFileByPath("D:/data/kaifa1.xlsx");
|
||||
|
||||
// 方式2:通过MultipartFile导入
|
||||
String result = excelImportService.importExcelFile(multipartFile);
|
||||
```
|
||||
|
||||
### 3. 测试方式
|
||||
|
||||
运行测试类:
|
||||
```java
|
||||
// 运行 ExcelImportTest 类中的测试方法
|
||||
@Test
|
||||
public void testImportExcelByPath() {
|
||||
// 修改文件路径为实际路径
|
||||
String filePath = "D:/code/xy-ai-cpzs/kaifa1.xlsx";
|
||||
String result = excelImportService.importExcelFileByPath(filePath);
|
||||
System.out.println("导入结果:" + result);
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据清空**:每次导入前会清空现有数据,请谨慎操作
|
||||
2. **数据验证**:系统会验证数据的完整性,球号为空的记录会被跳过
|
||||
3. **错误处理**:导入过程中如有错误会回滚操作并返回错误信息
|
||||
4. **日志记录**:导入过程会记录详细日志,便于问题排查
|
||||
5. **文件大小**:建议文件大小不超过10MB
|
||||
6. **并发限制**:避免同时进行多个导入操作
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 提示"未找到T1/T2/T3/T4/T5/T6/T7/T8/T10/T11工作表"
|
||||
**A**: 请检查Excel文件是否包含名为"T1"(红球数据)、"T2"(蓝球数据)、"T3"(红球线系数)、"T4"(蓝球组红球线系数)、"T5"(蓝球组蓝球线系数)、"T6"(红球组蓝球线系数)、"T7"(红球组红球面系数)、"T8"(红球组蓝球面系数)、"T10"(彩票开奖信息)和"T11"(蓝球组红球面系数)的工作表,注意区分大小写。如果缺少某个工作表,系统会跳过该部分数据并显示警告。
|
||||
|
||||
### Q2: 导入后数据不完整
|
||||
**A**: 请检查Excel数据格式是否正确,确保数值类型的列包含有效数字。
|
||||
|
||||
### Q3: 导入失败提示文件格式错误
|
||||
**A**: 请确保文件是.xlsx格式,不支持.xls格式。
|
||||
|
||||
### Q4: 如何查看导入日志
|
||||
**A**: 导入过程中的日志会输出到控制台,可以通过查看应用日志了解详细信息。
|
||||
|
||||
### Q5: 报错"Cannot get a NUMERIC value from a STRING cell"
|
||||
**A**: 这个错误已经修复。系统现在能够自动处理字符串类型的数值单元格,会尝试将字符串转换为数值。
|
||||
|
||||
### Q6: Excel中有公式单元格怎么办
|
||||
**A**: 系统支持公式单元格,会自动读取公式计算后的结果值。
|
||||
|
||||
### Q7: 单元格为空怎么处理
|
||||
**A**: 空白单元格会被自动跳过,对应的字段值会设为null。
|
||||
|
||||
## 数据类型支持
|
||||
|
||||
系统支持以下类型的Excel单元格:
|
||||
- **数值类型** - 直接读取数值
|
||||
- **字符串类型** - 尝试转换为数值(如果包含数字)
|
||||
- **公式类型** - 读取公式计算结果
|
||||
- **空白类型** - 设为null
|
||||
- **其他类型** - 会记录警告日志并设为null
|
||||
|
||||
## 数据精度处理
|
||||
|
||||
- **浮点数字段**:自动保留两位小数(使用四舍五入)
|
||||
- **整数字段**:直接转换为整数(去除小数部分)
|
||||
- **特殊值处理**:NaN和无穷大值会被设为null
|
||||
|
||||
示例:
|
||||
- `123.456789` → `123.46`
|
||||
- `12.1` → `12.10`
|
||||
- `5` → `5.00`
|
||||
|
||||
## Swagger文档
|
||||
|
||||
启动应用后,可以通过以下地址访问API文档:
|
||||
- Swagger UI: http://localhost:8123/api/swagger-ui.html
|
||||
- Knife4j UI: http://localhost:8123/api/doc.html
|
||||
|
||||
在文档中可以直接测试Excel导入接口。
|
||||
182
VIP兑换记录查询API使用说明.md
Normal file
182
VIP兑换记录查询API使用说明.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# VIP兑换记录查询API使用说明
|
||||
|
||||
## 接口概述
|
||||
|
||||
本文档描述了VIP兑换记录查询相关的API接口,主要用于查询用户的VIP兑换记录信息。
|
||||
|
||||
## 接口列表
|
||||
|
||||
### 1. 获取用户所有兑换记录
|
||||
|
||||
**接口地址:** `GET /vip-exchange-record/user/{userId}`
|
||||
|
||||
**接口描述:** 根据用户ID获取该用户的所有VIP兑换记录
|
||||
|
||||
**请求参数:**
|
||||
- `userId` (必填): 用户ID,路径参数,必须大于0
|
||||
|
||||
**请求示例:**
|
||||
```http
|
||||
GET /vip-exchange-record/user/123
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"userId": 123,
|
||||
"type": "月度会员",
|
||||
"exchangeMode": 1,
|
||||
"orderNo": 1234567890123456,
|
||||
"orderAmount": 0,
|
||||
"isUse": 1,
|
||||
"exchangeTime": "2024-01-15T10:30:00",
|
||||
"updateTime": "2024-01-15T10:30:00"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"userId": 123,
|
||||
"type": "年度会员",
|
||||
"exchangeMode": 1,
|
||||
"orderNo": 1234567890123457,
|
||||
"orderAmount": 0,
|
||||
"isUse": 1,
|
||||
"exchangeTime": "2024-02-15T14:20:00",
|
||||
"updateTime": "2024-02-15T14:20:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 分页获取用户兑换记录
|
||||
|
||||
**接口地址:** `GET /vip-exchange-record/user/{userId}/page`
|
||||
|
||||
**接口描述:** 根据用户ID分页获取该用户的VIP兑换记录
|
||||
|
||||
**请求参数:**
|
||||
- `userId` (必填): 用户ID,路径参数,必须大于0
|
||||
- `page` (可选): 页码,从1开始,默认为1
|
||||
- `size` (可选): 每页大小,默认为10,最大100
|
||||
|
||||
**请求示例:**
|
||||
```http
|
||||
GET /vip-exchange-record/user/123/page?page=1&size=5
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"userId": 123,
|
||||
"type": "月度会员",
|
||||
"exchangeMode": 1,
|
||||
"orderNo": 1234567890123456,
|
||||
"orderAmount": 0,
|
||||
"isUse": 1,
|
||||
"exchangeTime": "2024-01-15T10:30:00",
|
||||
"updateTime": "2024-01-15T10:30:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 获取兑换记录详情
|
||||
|
||||
**接口地址:** `GET /vip-exchange-record/{recordId}`
|
||||
|
||||
**接口描述:** 根据兑换记录ID获取详细信息
|
||||
|
||||
**请求参数:**
|
||||
- `recordId` (必填): 兑换记录ID,路径参数,必须大于0
|
||||
|
||||
**请求示例:**
|
||||
```http
|
||||
GET /vip-exchange-record/1
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"userId": 123,
|
||||
"type": "月度会员",
|
||||
"exchangeMode": 1,
|
||||
"orderNo": 1234567890123456,
|
||||
"orderAmount": 0,
|
||||
"isUse": 1,
|
||||
"exchangeTime": "2024-01-15T10:30:00",
|
||||
"updateTime": "2024-01-15T10:30:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 数据字段说明
|
||||
|
||||
### VipExchangeRecord 字段说明
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| id | Long | 兑换记录唯一标识符 |
|
||||
| userId | Long | 用户ID |
|
||||
| type | String | 会员类型(月度会员/年度会员) |
|
||||
| exchangeMode | Integer | 兑换方式(1-VIP码兑换) |
|
||||
| orderNo | Long | 订单编号(16位随机数字) |
|
||||
| orderAmount | Integer | 订单金额(单位:分) |
|
||||
| isUse | Integer | 是否已兑换(0-未兑换,1-已兑换) |
|
||||
| exchangeTime | Date | 兑换时间 |
|
||||
| updateTime | Date | 更新时间 |
|
||||
|
||||
## 响应状态码
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| 0 | 成功 |
|
||||
| 40000 | 请求参数错误 |
|
||||
| 40400 | 请求数据不存在 |
|
||||
| 50000 | 系统内部异常 |
|
||||
|
||||
## 错误响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 40000,
|
||||
"message": "用户ID不能为空且必须大于0",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 使用说明
|
||||
|
||||
1. **数据排序**: 所有查询结果都按照兑换时间倒序排列(最新的记录在前)
|
||||
|
||||
2. **分页查询**:
|
||||
- 页码从1开始
|
||||
- 每页大小限制在1-100之间
|
||||
- 超出范围会使用默认值
|
||||
|
||||
3. **参数校验**:
|
||||
- 用户ID和记录ID必须为正整数
|
||||
- 参数错误会返回40000状态码
|
||||
|
||||
4. **异常处理**:
|
||||
- 系统异常会返回50000状态码
|
||||
- 详细错误信息会在message字段中说明
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 接口支持Swagger文档,可通过 `/swagger-ui/index.html` 查看详细文档
|
||||
2. 所有接口都有完整的日志记录,便于问题排查
|
||||
3. 建议在生产环境中添加认证和权限控制
|
||||
4. 分页查询采用内存分页,大数据量时建议使用数据库分页优化
|
||||
BIN
kaifa1.xlsx
Normal file
BIN
kaifa1.xlsx
Normal file
Binary file not shown.
259
mvnw
vendored
Normal file
259
mvnw
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
set -euf
|
||||
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||
|
||||
# OS specific support.
|
||||
native_path() { printf %s\\n "$1"; }
|
||||
case "$(uname)" in
|
||||
CYGWIN* | MINGW*)
|
||||
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||
native_path() { cygpath --path --windows "$1"; }
|
||||
;;
|
||||
esac
|
||||
|
||||
# set JAVACMD and JAVACCMD
|
||||
set_java_home() {
|
||||
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||
if [ -n "${JAVA_HOME-}" ]; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||
|
||||
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(
|
||||
'set' +e
|
||||
'unset' -f command 2>/dev/null
|
||||
'command' -v java
|
||||
)" || :
|
||||
JAVACCMD="$(
|
||||
'set' +e
|
||||
'unset' -f command 2>/dev/null
|
||||
'command' -v javac
|
||||
)" || :
|
||||
|
||||
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# hash string like Java String::hashCode
|
||||
hash_string() {
|
||||
str="${1:-}" h=0
|
||||
while [ -n "$str" ]; do
|
||||
char="${str%"${str#?}"}"
|
||||
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||
str="${str#?}"
|
||||
done
|
||||
printf %x\\n $h
|
||||
}
|
||||
|
||||
verbose() { :; }
|
||||
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||
|
||||
die() {
|
||||
printf %s\\n "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
trim() {
|
||||
# MWRAPPER-139:
|
||||
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||
# Needed for removing poorly interpreted newline sequences when running in more
|
||||
# exotic environments such as mingw bash on Windows.
|
||||
printf "%s" "${1}" | tr -d '[:space:]'
|
||||
}
|
||||
|
||||
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||
while IFS="=" read -r key value; do
|
||||
case "${key-}" in
|
||||
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||
esac
|
||||
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||
|
||||
case "${distributionUrl##*/}" in
|
||||
maven-mvnd-*bin.*)
|
||||
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||
*)
|
||||
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||
distributionPlatform=linux-amd64
|
||||
;;
|
||||
esac
|
||||
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||
;;
|
||||
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||
esac
|
||||
|
||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||
distributionUrlName="${distributionUrl##*/}"
|
||||
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||
|
||||
exec_maven() {
|
||||
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||
}
|
||||
|
||||
if [ -d "$MAVEN_HOME" ]; then
|
||||
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||
exec_maven "$@"
|
||||
fi
|
||||
|
||||
case "${distributionUrl-}" in
|
||||
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||
esac
|
||||
|
||||
# prepare tmp dir
|
||||
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||
trap clean HUP INT TERM EXIT
|
||||
else
|
||||
die "cannot create temp dir"
|
||||
fi
|
||||
|
||||
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||
|
||||
# Download and Install Apache Maven
|
||||
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||
verbose "Downloading from: $distributionUrl"
|
||||
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
|
||||
# select .zip or .tar.gz
|
||||
if ! command -v unzip >/dev/null; then
|
||||
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||
distributionUrlName="${distributionUrl##*/}"
|
||||
fi
|
||||
|
||||
# verbose opt
|
||||
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||
|
||||
# normalize http auth
|
||||
case "${MVNW_PASSWORD:+has-password}" in
|
||||
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||
esac
|
||||
|
||||
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||
verbose "Found wget ... using wget"
|
||||
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||
verbose "Found curl ... using curl"
|
||||
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||
elif set_java_home; then
|
||||
verbose "Falling back to use Java to download"
|
||||
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
cat >"$javaSource" <<-END
|
||||
public class Downloader extends java.net.Authenticator
|
||||
{
|
||||
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||
{
|
||||
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||
}
|
||||
public static void main( String[] args ) throws Exception
|
||||
{
|
||||
setDefault( new Downloader() );
|
||||
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||
}
|
||||
}
|
||||
END
|
||||
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||
verbose " - Compiling Downloader.java ..."
|
||||
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||
verbose " - Running Downloader.java ..."
|
||||
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||
fi
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||
if [ -n "${distributionSha256Sum-}" ]; then
|
||||
distributionSha256Result=false
|
||||
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
elif command -v sha256sum >/dev/null; then
|
||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
||||
distributionSha256Result=true
|
||||
fi
|
||||
elif command -v shasum >/dev/null; then
|
||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||
distributionSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ $distributionSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# unzip and move
|
||||
if command -v unzip >/dev/null; then
|
||||
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||
else
|
||||
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||
fi
|
||||
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
||||
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||
|
||||
clean || :
|
||||
exec_maven "$@"
|
||||
149
mvnw.cmd
vendored
Normal file
149
mvnw.cmd
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
<# : batch portion
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||
@SET __MVNW_CMD__=
|
||||
@SET __MVNW_ERROR__=
|
||||
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||
@SET PSModulePath=
|
||||
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||
)
|
||||
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||
@SET __MVNW_PSMODULEP_SAVE=
|
||||
@SET __MVNW_ARG0_NAME__=
|
||||
@SET MVNW_USERNAME=
|
||||
@SET MVNW_PASSWORD=
|
||||
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
||||
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||
@GOTO :EOF
|
||||
: end batch / begin powershell #>
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
if ($env:MVNW_VERBOSE -eq "true") {
|
||||
$VerbosePreference = "Continue"
|
||||
}
|
||||
|
||||
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||
if (!$distributionUrl) {
|
||||
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||
}
|
||||
|
||||
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||
"maven-mvnd-*" {
|
||||
$USE_MVND = $true
|
||||
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||
$MVN_CMD = "mvnd.cmd"
|
||||
break
|
||||
}
|
||||
default {
|
||||
$USE_MVND = $false
|
||||
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||
if ($env:MVNW_REPOURL) {
|
||||
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
||||
}
|
||||
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
||||
if ($env:MAVEN_USER_HOME) {
|
||||
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
||||
}
|
||||
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||
|
||||
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||
exit $?
|
||||
}
|
||||
|
||||
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||
}
|
||||
|
||||
# prepare tmp dir
|
||||
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||
trap {
|
||||
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||
}
|
||||
}
|
||||
|
||||
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||
|
||||
# Download and Install Apache Maven
|
||||
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||
Write-Verbose "Downloading from: $distributionUrl"
|
||||
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
|
||||
$webclient = New-Object System.Net.WebClient
|
||||
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||
}
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||
if ($distributionSha256Sum) {
|
||||
if ($USE_MVND) {
|
||||
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||
}
|
||||
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||
}
|
||||
}
|
||||
|
||||
# unzip and move
|
||||
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||
try {
|
||||
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||
} catch {
|
||||
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||
Write-Error "fail to move MAVEN_HOME"
|
||||
}
|
||||
} finally {
|
||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||
}
|
||||
|
||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||
BIN
nls-sample-16k.wav
Normal file
BIN
nls-sample-16k.wav
Normal file
Binary file not shown.
198
pom.xml
Normal file
198
pom.xml
Normal file
@@ -0,0 +1,198 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.4.6</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.xy</groupId>
|
||||
<artifactId>xy-ai-cpzs</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>xy-ai-cpzs</name>
|
||||
<description>xy-ai-cpzs</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>21</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
<artifactId>tencentcloud-sdk-java-sms</artifactId>
|
||||
<version>3.1.1281</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nls</groupId>
|
||||
<artifactId>nls-sdk-recognizer</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.aliyun</groupId>-->
|
||||
<!-- <artifactId>aliyun-java-sdk-core</artifactId>-->
|
||||
<!-- <version>3.7.1</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <!– http://mvnrepository.com/artifact/com.alibaba/fastjson –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.alibaba</groupId>-->
|
||||
<!-- <artifactId>fastjson</artifactId>-->
|
||||
<!-- <version>1.2.83</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dashscope-sdk-java</artifactId>
|
||||
<!-- 请将 'the-latest-version' 替换为最新版本号:https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
|
||||
<version>2.20.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.36</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.37</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
<version>4.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>3.5.12</version>
|
||||
</dependency>
|
||||
<!-- 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
<version>3.5.12</version> <!-- 确保版本和 MyBatis Plus 主包一致 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<!-- Excel读取依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
<!-- JWT依赖 -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.11.5</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.11.5</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里云短信依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>dysmsapi20170525</artifactId>
|
||||
<version>2.0.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>tea-openapi</artifactId>
|
||||
<version>0.2.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>tea-util</artifactId>
|
||||
<version>0.2.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>credentials-java</artifactId>
|
||||
<version>0.2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>tea</artifactId>
|
||||
<version>1.2.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
272
sql/ddl.sql
Normal file
272
sql/ddl.sql
Normal file
@@ -0,0 +1,272 @@
|
||||
-- 聊天消息表
|
||||
create database if not exists cpzs;
|
||||
|
||||
-- 切换库
|
||||
use cpzs;
|
||||
|
||||
-- 创建历史数据表
|
||||
CREATE TABLE IF NOT EXISTS `history_all` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
frequencyCount INT NULL COMMENT '出现频次',
|
||||
frequencyPercentage FLOAT NULL COMMENT '出现频率百分比',
|
||||
averageInterval FLOAT NULL COMMENT '平均隐现期(次)',
|
||||
maxHiddenInterval INT NULL COMMENT '最长隐现期(次)',
|
||||
maxConsecutiveCount INT NULL COMMENT '最多连出期(次)',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '全部历史数据表';
|
||||
|
||||
|
||||
-- 创建最近100期数据表
|
||||
CREATE TABLE IF NOT EXISTS `history_100` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
frequencyCount INT NULL COMMENT '出现频次',
|
||||
averageInterval FLOAT NULL COMMENT '平均隐现期(次)',
|
||||
nowInterval INT NULL COMMENT '当前隐现期(次)',
|
||||
maxConsecutiveCount INT NULL COMMENT '最多连出期(次)',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '最近100期数据表';
|
||||
|
||||
-- 创建历史数据排行表
|
||||
CREATE TABLE IF NOT EXISTS `history_top` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
no INT NULL COMMENT '排行',
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '历史数据排行表';
|
||||
|
||||
-- 创建100期数据排行表
|
||||
CREATE TABLE IF NOT EXISTS `history_top_100` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
no INT NULL COMMENT '排行',
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '100期数据排行表';
|
||||
|
||||
|
||||
-- 创建蓝球历史数据表
|
||||
CREATE TABLE IF NOT EXISTS `blue_history_all` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
frequencyCount INT NULL COMMENT '出现频次',
|
||||
frequencyPercentage FLOAT NULL COMMENT '出现频率百分比',
|
||||
averageInterval FLOAT NULL COMMENT '平均隐现期(次)',
|
||||
maxHiddenInterval INT NULL COMMENT '最长隐现期(次)',
|
||||
maxConsecutiveCount INT NULL COMMENT '最多连出期(次)',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '蓝球全部历史数据表';
|
||||
|
||||
|
||||
-- 创建蓝球最近100期数据表
|
||||
CREATE TABLE IF NOT EXISTS `blue_history_100` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
frequencyCount INT NULL COMMENT '出现频次',
|
||||
averageInterval FLOAT NULL COMMENT '平均隐现期(次)',
|
||||
nowInterval INT NULL COMMENT '当前隐现期(次)',
|
||||
maxConsecutiveCount INT NULL COMMENT '最多连出期(次)',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '蓝球最近100期数据表';
|
||||
|
||||
-- 创建蓝球历史数据排行表
|
||||
CREATE TABLE IF NOT EXISTS `blue_history_top` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
no INT NULL COMMENT '排行',
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '蓝球历史数据排行表';
|
||||
|
||||
-- 创建蓝球100期数据排行表
|
||||
CREATE TABLE IF NOT EXISTS `blue_history_top_100` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
no INT NULL COMMENT '排行',
|
||||
ballNumber INT NULL COMMENT '球号',
|
||||
pointCoefficient FLOAT NULL COMMENT '点系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '蓝球100期数据排行表';
|
||||
|
||||
-- 创建t3表(红球组红球的线系数)
|
||||
CREATE TABLE IF NOT EXISTS `t3` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
masterBallNumber INT NULL COMMENT '主球',
|
||||
slaveBallNumber INT NULL COMMENT '从球',
|
||||
lineCoefficient FLOAT NULL COMMENT '线系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = 't3表(红球组红球的线系数)';
|
||||
|
||||
|
||||
-- 创建t4表(蓝球组红球的线系数)
|
||||
CREATE TABLE IF NOT EXISTS `t4` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
masterBallNumber INT NULL COMMENT '主球',
|
||||
slaveBallNumber INT NULL COMMENT '从球',
|
||||
lineCoefficient FLOAT NULL COMMENT '线系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = 't4表(蓝球组红球的线系数)';
|
||||
|
||||
-- 创建t5表(蓝球组蓝球的线系数)
|
||||
CREATE TABLE IF NOT EXISTS `t5` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
masterBallNumber INT NULL COMMENT '主球',
|
||||
slaveBallNumber INT NULL COMMENT '从球',
|
||||
lineCoefficient FLOAT NULL COMMENT '线系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = 't5表(蓝球组蓝球的线系数)';
|
||||
|
||||
-- 创建t6表(红球组蓝球的线系数)
|
||||
CREATE TABLE IF NOT EXISTS `t6` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
masterBallNumber INT NULL COMMENT '主球',
|
||||
slaveBallNumber INT NULL COMMENT '从球',
|
||||
lineCoefficient FLOAT NULL COMMENT '线系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = 't6表(红球组蓝球的线系数)';
|
||||
|
||||
-- 创建t7表(红球组红球的面系数)
|
||||
CREATE TABLE IF NOT EXISTS `t7` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
masterBallNumber INT NULL COMMENT '主球',
|
||||
slaveBallNumber INT NULL COMMENT '从球',
|
||||
faceCoefficient FLOAT NULL COMMENT '面系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = 't7表(红球组红球的面系数)';
|
||||
|
||||
-- 创建t8表(红球组蓝球的面系数)
|
||||
CREATE TABLE IF NOT EXISTS `t8` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
masterBallNumber INT NULL COMMENT '主球',
|
||||
slaveBallNumber INT NULL COMMENT '从球',
|
||||
faceCoefficient FLOAT NULL COMMENT '面系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = 't8表(红球组蓝球的面系数)';
|
||||
|
||||
-- 创建t11表(蓝球组红球的面系数)
|
||||
CREATE TABLE IF NOT EXISTS `t11` (
|
||||
id BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
masterBallNumber INT NULL COMMENT '主球',
|
||||
slaveBallNumber INT NULL COMMENT '从球',
|
||||
faceCoefficient FLOAT NULL COMMENT '面系数'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = 't11表(蓝球组红球的面系数)';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lottery_draws` (
|
||||
`drawId` BIGINT NOT NULL COMMENT '开奖期号' PRIMARY KEY,
|
||||
`drawDate` DATE NOT NULL COMMENT '开奖日期',
|
||||
`redBall1` INT NOT NULL COMMENT '红1',
|
||||
`redBall2` INT NOT NULL COMMENT '红2',
|
||||
`redBall3` INT NOT NULL COMMENT '红3',
|
||||
`redBall4` INT NOT NULL COMMENT '红4',
|
||||
`redBall5` INT NOT NULL COMMENT '红5',
|
||||
`redBall6` INT NOT NULL COMMENT '红6',
|
||||
`blueBall` INT NOT NULL COMMENT '蓝球'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '彩票开奖信息表';
|
||||
|
||||
-- 用户表
|
||||
create table if not exists user
|
||||
(
|
||||
id bigint auto_increment comment 'id' primary key,
|
||||
userName varchar(256) null comment '用户昵称',
|
||||
userAccount varchar(256) not null comment '账号',
|
||||
phone varchar(11) null comment '手机号',
|
||||
userAvatar varchar(1024) null comment '用户头像',
|
||||
gender tinyint null comment '性别',
|
||||
userRole varchar(256) default 'user' not null comment '用户角色:user / admin',
|
||||
userPassword varchar(512) not null comment '密码',
|
||||
isVip int default 0 not null comment '是否会员:0-非会员,1-会员',
|
||||
vipExpire datetime null comment '会员到期时间',
|
||||
`status` tinyint DEFAULT '0' COMMENT '状态0正常1不正常',
|
||||
createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
|
||||
updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
|
||||
isDelete tinyint default 0 not null comment '是否删除',
|
||||
constraint uni_userAccount
|
||||
unique (userAccount)
|
||||
) comment '用户';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `predict_record` (
|
||||
`id` BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
`userId` BIGINT NOT NULL COMMENT '用户ID',
|
||||
`drawId` BIGINT NOT NULL COMMENT '开奖期号' ,
|
||||
`drawDate` DATE NOT NULL COMMENT '开奖日期',
|
||||
`redBall1` INT NOT NULL COMMENT '红1',
|
||||
`redBall2` INT NOT NULL COMMENT '红2',
|
||||
`redBall3` INT NOT NULL COMMENT '红3',
|
||||
`redBall4` INT NOT NULL COMMENT '红4',
|
||||
`redBall5` INT NOT NULL COMMENT '红5',
|
||||
`redBall6` INT NOT NULL COMMENT '红6',
|
||||
`blueBall` INT NOT NULL COMMENT '蓝球',
|
||||
`predictStatus` VARCHAR(100) default '待开奖' NOT NULL COMMENT '预测状态(待开奖/已开奖)',
|
||||
`predictResult` VARCHAR(100) default '待开奖' NOT NULL COMMENT '预测结果(未中奖/三等奖/二等奖/一等奖)',
|
||||
`predictTime` datetime default CURRENT_TIMESTAMP not null comment '预测时间',
|
||||
`bonus` BIGINT default 0 NOT NULL COMMENT '奖金'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '彩票开奖信息表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `vip_code` (
|
||||
`id` BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
`code` varchar(36) NOT NULL COMMENT '会员码',
|
||||
`vipExpireTime` int not null COMMENT '会员有效月数(1/12)',
|
||||
`vipNumber` int not NULL COMMENT '会员编号',
|
||||
`isUse` int NOT NULL COMMENT '是否使用',
|
||||
createdUserId bigint null comment '创建人',
|
||||
createdUserName varchar(36) null comment '创建人名称',
|
||||
usedUserId bigint null comment '使用人',
|
||||
usedUserName varchar(36) null comment '使用人名称',
|
||||
`createTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '创建时间',
|
||||
`updateTime` datetime NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `Order_OrderNo_uindex` (`code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员码表';
|
||||
|
||||
INSERT INTO `vip_code` (`id`, `code`, `vipExpireTime`, `vipNumber`, `isUse`, `createTime`, `updateTime`) VALUES
|
||||
(1, 'A3B4C5D6E7F8G9H1', 1, '000001', 0, NOW(), NOW()),
|
||||
(2, 'I2J3K4L5M6N7O8P9', 12, '000002', 0, NOW(), NOW());
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `vip_exchange_record` (
|
||||
`id` BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
`userId` bigint NOT NULL COMMENT '用户ID',
|
||||
`type` varchar(36) NOT NULL COMMENT '月度会员/年度会员',
|
||||
`exchangeMode` int not null COMMENT '兑换方式',
|
||||
`orderNo` bigint not NULL COMMENT '订单编号',
|
||||
`orderAmount` int not NULL COMMENT '订单金额',
|
||||
`isUse` int NOT NULL COMMENT '是否兑换(未兑换/已兑换)',
|
||||
`exchangeTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '兑换时间',
|
||||
`updateTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员兑换表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `operation_history` (
|
||||
`id` BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
|
||||
`userId` BIGINT NOT NULL COMMENT '操作用户ID',
|
||||
`operationType` VARCHAR(50) NOT NULL COMMENT '操作类型(批量生成会员码/获取可用会员码/Excel导入等)',
|
||||
`operationModule` INTEGER NOT NULL COMMENT '操作模块(0-会员码管理/1-Excel导入管理等)',
|
||||
`operationResult` VARCHAR(20) NOT NULL COMMENT '操作结果(成功/失败)',
|
||||
`resultMessage` TEXT COMMENT '结果消息',
|
||||
`operationTime` DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '操作时间',
|
||||
`updateTime` DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='操作历史记录表';
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `chat_message`
|
||||
(
|
||||
id BIGINT AUTO_INCREMENT COMMENT 'id' PRIMARY KEY,
|
||||
`conversationId` varchar(64) NULL COMMENT '会话ID',
|
||||
`studentId` varchar(64) NULL COMMENT '用户ID,关联用户表',
|
||||
`messageType` varchar(64) NULL COMMENT '消息类型(如: 用户提问、AI回答)',
|
||||
`content` varchar(1024) NULL COMMENT '消息内容',
|
||||
`createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`isDelete` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除 0-未删除 1-已删除'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT ='聊天消息表';
|
||||
|
||||
|
||||
|
||||
42
src/main/java/com/xy/xyaicpzs/Main.java
Normal file
42
src/main/java/com/xy/xyaicpzs/Main.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.xy.xyaicpzs;
|
||||
|
||||
import com.alibaba.dashscope.app.*;
|
||||
import com.alibaba.dashscope.exception.ApiException;
|
||||
import com.alibaba.dashscope.exception.InputRequiredException;
|
||||
import com.alibaba.dashscope.exception.NoApiKeyException;
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void streamCall() throws NoApiKeyException, InputRequiredException {
|
||||
ApplicationParam param = ApplicationParam.builder()
|
||||
// 若没有配置环境变量,可用百炼API Key将下行替换为:.apiKey("sk-xxx")。但不建议在生产环境中直接将API Key硬编码到代码中,以减少API Key泄露风险。
|
||||
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
|
||||
// 替换为实际的应用 ID
|
||||
.appId("ec08d5b81ca248e8834228c1133e2c78")
|
||||
.prompt("你是谁")
|
||||
// 增量输出
|
||||
.incrementalOutput(true)
|
||||
.build();
|
||||
Application application = new Application();
|
||||
// .streamCall():流式输出内容
|
||||
Flowable<ApplicationResult> result = application.streamCall(param);
|
||||
result.blockingForEach(data -> {
|
||||
System.out.printf("%s\n",
|
||||
data.getOutput().getText());
|
||||
// System.out.println("session_id: " + data.getOutput().getSessionId());
|
||||
});
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
streamCall();
|
||||
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
|
||||
System.out.printf("Exception: %s", e.getMessage());
|
||||
System.out.println("请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code");
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
54
src/main/java/com/xy/xyaicpzs/Sample.java
Normal file
54
src/main/java/com/xy/xyaicpzs/Sample.java
Normal file
@@ -0,0 +1,54 @@
|
||||
// This file is auto-generated, don't edit it. Thanks.
|
||||
package com.xy.xyaicpzs;
|
||||
|
||||
import com.aliyun.tea.*;
|
||||
|
||||
public class Sample {
|
||||
|
||||
/**
|
||||
* <b>description</b> :
|
||||
* <p>使用凭据初始化账号Client</p>
|
||||
* @return Client
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static com.aliyun.dysmsapi20170525.Client createClient() throws Exception {
|
||||
// 工程代码建议使用更安全的无AK方式,凭据配置方式请参见:https://help.aliyun.com/document_detail/378657.html。
|
||||
com.aliyun.credentials.Client credential = new com.aliyun.credentials.Client();
|
||||
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
|
||||
.setCredential(credential);
|
||||
// Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
|
||||
config.endpoint = "dysmsapi.aliyuncs.com";
|
||||
return new com.aliyun.dysmsapi20170525.Client(config);
|
||||
}
|
||||
|
||||
public static void main(String[] args_) throws Exception {
|
||||
|
||||
com.aliyun.dysmsapi20170525.Client client = Sample.createClient();
|
||||
com.aliyun.dysmsapi20170525.models.SendSmsRequest sendSmsRequest = new com.aliyun.dysmsapi20170525.models.SendSmsRequest()
|
||||
.setSignName("西安精彩数据服务社")
|
||||
.setTemplateCode("SMS_489840017")
|
||||
.setPhoneNumbers("13868246742")
|
||||
.setTemplateParam("{\"code\":\"1234\"}");
|
||||
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
|
||||
try {
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
client.sendSmsWithOptions(sendSmsRequest, runtime);
|
||||
} catch (TeaException error) {
|
||||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||
// 错误 message
|
||||
System.out.println(error.getMessage());
|
||||
// 诊断地址
|
||||
System.out.println(error.getData().get("Recommend"));
|
||||
com.aliyun.teautil.Common.assertAsString(error.message);
|
||||
} catch (Exception _error) {
|
||||
TeaException error = new TeaException(_error.getMessage(), _error);
|
||||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||
// 错误 message
|
||||
System.out.println(error.getMessage());
|
||||
// 诊断地址
|
||||
System.out.println(error.getData().get("Recommend"));
|
||||
com.aliyun.teautil.Common.assertAsString(error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/main/java/com/xy/xyaicpzs/XyAiCpzsApplication.java
Normal file
17
src/main/java/com/xy/xyaicpzs/XyAiCpzsApplication.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.xy.xyaicpzs;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.xy.xyaicpzs.mapper")
|
||||
public class XyAiCpzsApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(XyAiCpzsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
19
src/main/java/com/xy/xyaicpzs/common/DeleteRequest.java
Normal file
19
src/main/java/com/xy/xyaicpzs/common/DeleteRequest.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.xy.xyaicpzs.common;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 删除请求
|
||||
*/
|
||||
@Data
|
||||
public class DeleteRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
private Long id;
|
||||
}
|
||||
39
src/main/java/com/xy/xyaicpzs/common/ErrorCode.java
Normal file
39
src/main/java/com/xy/xyaicpzs/common/ErrorCode.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.xy.xyaicpzs.common;
|
||||
|
||||
/**
|
||||
* 自定义错误码
|
||||
*/
|
||||
public enum ErrorCode {
|
||||
|
||||
SUCCESS(0, "ok"),
|
||||
PARAMS_ERROR(40000, "请求参数错误"),
|
||||
NOT_LOGIN_ERROR(40100, "您还未登录,请登录后操作"),
|
||||
NO_AUTH_ERROR(40101, "无权限"),
|
||||
NOT_FOUND_ERROR(40400, "请求数据不存在"),
|
||||
FORBIDDEN_ERROR(40300, "禁止访问"),
|
||||
SYSTEM_ERROR(50000, "系统内部异常"),
|
||||
OPERATION_ERROR(50001, "操作失败");
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 信息
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
ErrorCode(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
20
src/main/java/com/xy/xyaicpzs/common/PageRequest.java
Normal file
20
src/main/java/com/xy/xyaicpzs/common/PageRequest.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.xy.xyaicpzs.common;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 分页请求
|
||||
*/
|
||||
@Data
|
||||
public class PageRequest {
|
||||
|
||||
/**
|
||||
* 当前页号
|
||||
*/
|
||||
private long current = 1;
|
||||
|
||||
/**
|
||||
* 页面大小
|
||||
*/
|
||||
private long pageSize = 10;
|
||||
}
|
||||
51
src/main/java/com/xy/xyaicpzs/common/ResultUtils.java
Normal file
51
src/main/java/com/xy/xyaicpzs/common/ResultUtils.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package com.xy.xyaicpzs.common;
|
||||
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
|
||||
/**
|
||||
* 返回工具类
|
||||
*/
|
||||
public class ResultUtils {
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*
|
||||
* @param data
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> ApiResponse<T> success(T data) {
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败
|
||||
*
|
||||
* @param errorCode
|
||||
* @return
|
||||
*/
|
||||
public static <T> ApiResponse<T> error(ErrorCode errorCode) {
|
||||
return ApiResponse.error(errorCode.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败
|
||||
*
|
||||
* @param code
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static <T> ApiResponse<T> error(int code, String message) {
|
||||
return ApiResponse.error(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败
|
||||
*
|
||||
* @param errorCode
|
||||
* @return
|
||||
*/
|
||||
public static <T> ApiResponse<T> error(ErrorCode errorCode, String message) {
|
||||
return ApiResponse.error(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.xy.xyaicpzs.common.requset;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 球号分析请求对象
|
||||
*/
|
||||
@Data
|
||||
public class BallAnalysisRequest {
|
||||
private String level;
|
||||
private List<Integer> redBalls;
|
||||
private Integer blueBall;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BallAnalysisRequest{" +
|
||||
"level='" + level + '\'' +
|
||||
", redBalls=" + redBalls +
|
||||
", blueBall=" + blueBall +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.xy.xyaicpzs.common.requset;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 蓝球分析请求对象
|
||||
*/
|
||||
@Data
|
||||
public class BlueBallAnalysisRequest {
|
||||
private String level;
|
||||
private List<Integer> predictedRedBalls;
|
||||
private List<Integer> predictedBlueBalls;
|
||||
private List<Integer> lastRedBalls;
|
||||
private Integer lastBlueBall;
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BlueBallAnalysisRequest{" +
|
||||
"level='" + level + '\'' +
|
||||
", predictedRedBalls=" + predictedRedBalls +
|
||||
", predictedBlueBalls=" + predictedBlueBalls +
|
||||
", lastRedBalls=" + lastRedBalls +
|
||||
", lastBlueBall=" + lastBlueBall +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.xy.xyaicpzs.common.requset;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 跟随球号分析请求对象
|
||||
*/
|
||||
@Data
|
||||
public class FallowBallAnalysisRequest {
|
||||
private String level;
|
||||
private List<Integer> firstThreeRedBalls;
|
||||
private List<Integer> lastSixRedBalls;
|
||||
private Integer blueBall;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FallowBallAnalysisRequest{" +
|
||||
"level='" + level + '\'' +
|
||||
", firstThreeRedBalls=" + firstThreeRedBalls +
|
||||
", lastSixRedBalls=" + lastSixRedBalls +
|
||||
", blueBall=" + blueBall +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.xy.xyaicpzs.common.requset;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 生成会员码请求
|
||||
*/
|
||||
@Data
|
||||
public class GenerateVipCodesRequest {
|
||||
|
||||
/**
|
||||
* 生成数量
|
||||
*/
|
||||
private Integer numCodes;
|
||||
|
||||
/**
|
||||
* 会员有效月数
|
||||
*/
|
||||
private Integer vipExpireTime;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.xy.xyaicpzs.common.requset;
|
||||
|
||||
import com.xy.xyaicpzs.common.PageRequest;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 预测记录查询请求
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PredictRecordQueryRequest extends PageRequest {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 预测状态(待开奖/未中奖/已中奖)
|
||||
*/
|
||||
private String predictStatus;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.xy.xyaicpzs.common.requset;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 会员码激活请求
|
||||
*/
|
||||
@Data
|
||||
public class VipCodeActivateRequest {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 会员码
|
||||
*/
|
||||
private String code;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.xy.xyaicpzs.common.requset;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 会员码查询请求
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "会员码查询请求")
|
||||
public class VipCodeQueryRequest {
|
||||
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
@Schema(description = "当前页码")
|
||||
private long current = 1;
|
||||
|
||||
/**
|
||||
* 页面大小
|
||||
*/
|
||||
@Schema(description = "页面大小")
|
||||
private long pageSize = 10;
|
||||
|
||||
/**
|
||||
* 会员码
|
||||
*/
|
||||
@Schema(description = "会员码")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 会员有效月数(1/12)
|
||||
*/
|
||||
@Schema(description = "会员有效月数")
|
||||
private Integer vipExpireTime;
|
||||
|
||||
/**
|
||||
* 是否使用:0-未使用,1-已使用
|
||||
*/
|
||||
@Schema(description = "是否使用:0-未使用,1-已使用")
|
||||
private Integer isUse;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
*/
|
||||
@Schema(description = "创建人ID")
|
||||
private Long createdUserId;
|
||||
|
||||
/**
|
||||
* 创建人名称
|
||||
*/
|
||||
@Schema(description = "创建人名称")
|
||||
private String createdUserName;
|
||||
|
||||
/**
|
||||
* 使用人ID
|
||||
*/
|
||||
@Schema(description = "使用人ID")
|
||||
private Long usedUserId;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
@Schema(description = "开始时间")
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
@Schema(description = "结束时间")
|
||||
private Date endTime;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.xy.xyaicpzs.common.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* API响应对象
|
||||
*/
|
||||
@Data
|
||||
public class ApiResponse<T> {
|
||||
private boolean success;
|
||||
private String message;
|
||||
private T data;
|
||||
|
||||
public static <T> ApiResponse<T> success(T data) {
|
||||
ApiResponse<T> response = new ApiResponse<>();
|
||||
response.success = true;
|
||||
response.message = "操作成功";
|
||||
response.data = data;
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> ApiResponse<T> error(String message) {
|
||||
ApiResponse<T> response = new ApiResponse<>();
|
||||
response.success = false;
|
||||
response.message = message;
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.xy.xyaicpzs.common.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页响应对象
|
||||
* @param <T> 数据类型
|
||||
*/
|
||||
@Data
|
||||
public class PageResponse<T> {
|
||||
|
||||
/**
|
||||
* 数据列表
|
||||
*/
|
||||
private List<T> records;
|
||||
|
||||
/**
|
||||
* 总记录数
|
||||
*/
|
||||
private Long total;
|
||||
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
private Integer page;
|
||||
|
||||
/**
|
||||
* 每页大小
|
||||
*/
|
||||
private Integer size;
|
||||
|
||||
/**
|
||||
* 总页数
|
||||
*/
|
||||
private Integer totalPages;
|
||||
|
||||
/**
|
||||
* 是否有下一页
|
||||
*/
|
||||
private Boolean hasNext;
|
||||
|
||||
/**
|
||||
* 是否有上一页
|
||||
*/
|
||||
private Boolean hasPrevious;
|
||||
|
||||
public PageResponse() {}
|
||||
|
||||
public PageResponse(List<T> records, Long total, Integer page, Integer size) {
|
||||
this.records = records;
|
||||
this.total = total;
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
this.totalPages = (int) Math.ceil((double) total / size);
|
||||
this.hasNext = page < totalPages;
|
||||
this.hasPrevious = page > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分页响应对象
|
||||
*/
|
||||
public static <T> PageResponse<T> of(List<T> records, Long total, Integer page, Integer size) {
|
||||
return new PageResponse<>(records, total, page, size);
|
||||
}
|
||||
}
|
||||
27
src/main/java/com/xy/xyaicpzs/config/CorsConfig.java
Normal file
27
src/main/java/com/xy/xyaicpzs/config/CorsConfig.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.xy.xyaicpzs.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
// * 全局跨域配置
|
||||
*/
|
||||
@Configuration
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
// 覆盖所有请求
|
||||
registry.addMapping("/**")
|
||||
// 允许发送 Cookie
|
||||
.allowCredentials(true)
|
||||
// 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突)
|
||||
.allowedOriginPatterns("*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
// 确保SSE相关头信息能被客户端访问
|
||||
.exposedHeaders("*", HttpHeaders.CACHE_CONTROL, HttpHeaders.CONTENT_TYPE);
|
||||
}
|
||||
}
|
||||
31
src/main/java/com/xy/xyaicpzs/config/MyBatisPlusConfig.java
Normal file
31
src/main/java/com/xy/xyaicpzs/config/MyBatisPlusConfig.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.xy.xyaicpzs.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* MyBatis Plus 配置
|
||||
*
|
||||
* @author lihanqi
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan("com.xy.xyaicpzs.mapper")
|
||||
public class MyBatisPlusConfig {
|
||||
|
||||
/**
|
||||
* 拦截器配置
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 分页插件
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
22
src/main/java/com/xy/xyaicpzs/config/ObjectMapperConfig.java
Normal file
22
src/main/java/com/xy/xyaicpzs/config/ObjectMapperConfig.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* ObjectMapper配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class ObjectMapperConfig {
|
||||
|
||||
/**
|
||||
* 配置ObjectMapper Bean
|
||||
*
|
||||
* @return ObjectMapper实例
|
||||
*/
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
return new ObjectMapper();
|
||||
}
|
||||
}
|
||||
38
src/main/java/com/xy/xyaicpzs/config/RedisConfig.java
Normal file
38
src/main/java/com/xy/xyaicpzs/config/RedisConfig.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package com.xy.xyaicpzs.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* Redis配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
/**
|
||||
* 自定义RedisTemplate
|
||||
*/
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
|
||||
// 设置连接工厂
|
||||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
|
||||
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
|
||||
// 使用GenericJackson2JsonRedisSerializer来序列化和反序列化redis的value值
|
||||
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
|
||||
redisTemplate.setValueSerializer(jsonSerializer);
|
||||
redisTemplate.setHashValueSerializer(jsonSerializer);
|
||||
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
||||
22
src/main/java/com/xy/xyaicpzs/config/RestTemplateConfig.java
Normal file
22
src/main/java/com/xy/xyaicpzs/config/RestTemplateConfig.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* RestTemplate配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class RestTemplateConfig {
|
||||
|
||||
/**
|
||||
* 配置RestTemplate Bean
|
||||
*
|
||||
* @return RestTemplate实例
|
||||
*/
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
12
src/main/java/com/xy/xyaicpzs/config/ScheduleConfig.java
Normal file
12
src/main/java/com/xy/xyaicpzs/config/ScheduleConfig.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.xy.xyaicpzs.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 定时任务配置类
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
public class ScheduleConfig {
|
||||
}
|
||||
36
src/main/java/com/xy/xyaicpzs/constant/UserConstant.java
Normal file
36
src/main/java/com/xy/xyaicpzs/constant/UserConstant.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.xy.xyaicpzs.constant;
|
||||
|
||||
/**
|
||||
* 用户常量
|
||||
*/
|
||||
public interface UserConstant {
|
||||
|
||||
/**
|
||||
* 用户登录态键
|
||||
*/
|
||||
String USER_LOGIN_STATE = "userLoginState";
|
||||
|
||||
/**
|
||||
* 系统用户 id(虚拟用户)
|
||||
*/
|
||||
long SYSTEM_USER_ID = 0;
|
||||
|
||||
// region 权限
|
||||
|
||||
/**
|
||||
* 默认权限
|
||||
*/
|
||||
String DEFAULT_ROLE = "user";
|
||||
|
||||
/**
|
||||
* 管理员权限
|
||||
*/
|
||||
String ADMIN_ROLE = "admin";
|
||||
|
||||
/**
|
||||
* 超级管理员权限
|
||||
*/
|
||||
String SUPER_ADMIN_ROLE = "superAdmin";
|
||||
|
||||
// endregion
|
||||
}
|
||||
1805
src/main/java/com/xy/xyaicpzs/controller/BallAnalysisController.java
Normal file
1805
src/main/java/com/xy/xyaicpzs/controller/BallAnalysisController.java
Normal file
File diff suppressed because it is too large
Load Diff
126
src/main/java/com/xy/xyaicpzs/controller/ChatController.java
Normal file
126
src/main/java/com/xy/xyaicpzs/controller/ChatController.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.alibaba.dashscope.app.Application;
|
||||
import com.alibaba.dashscope.app.ApplicationParam;
|
||||
import com.alibaba.dashscope.app.ApplicationResult;
|
||||
import com.alibaba.dashscope.exception.ApiException;
|
||||
import com.alibaba.dashscope.exception.InputRequiredException;
|
||||
import com.alibaba.dashscope.exception.NoApiKeyException;
|
||||
import com.xy.xyaicpzs.domain.entity.ChatMessage;
|
||||
import com.xy.xyaicpzs.service.ChatMessageService;
|
||||
import io.reactivex.Flowable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@RestController
|
||||
public class ChatController {
|
||||
|
||||
@Autowired
|
||||
private ChatMessageService chatMessageService;
|
||||
|
||||
@Value("${dashscope.api-key}")
|
||||
private String dashscopeApiKey;
|
||||
|
||||
/**
|
||||
* SSE流式聊天接口
|
||||
* @param message 用户消息
|
||||
* @param conversationId 会话ID
|
||||
* @param userId 用户ID
|
||||
* @return SseEmitter
|
||||
*/
|
||||
@GetMapping("/chat/sse")
|
||||
public SseEmitter chatSseEmitter(
|
||||
@RequestParam String message,
|
||||
@RequestParam(required = false) String conversationId,
|
||||
@RequestParam(required = false) String userId) {
|
||||
|
||||
// 保存用户消息到数据库
|
||||
saveMessage(conversationId, userId, "USER", message);
|
||||
|
||||
// 创建一个超时时间较长的 SseEmitter
|
||||
SseEmitter emitter = new SseEmitter(180000L); // 3分钟超时
|
||||
|
||||
// 用于收集完整的AI回复
|
||||
AtomicReference<StringBuilder> fullResponseRef = new AtomicReference<>(new StringBuilder());
|
||||
|
||||
try {
|
||||
// 设置AI参数
|
||||
ApplicationParam param = ApplicationParam.builder()
|
||||
.apiKey(dashscopeApiKey) // 使用配置文件中的API密钥
|
||||
.appId("ec08d5b81ca248e8834228c1133e2c78")
|
||||
.prompt(message)
|
||||
.incrementalOutput(true)
|
||||
.build();
|
||||
|
||||
Application application = new Application();
|
||||
|
||||
// 流式调用
|
||||
Flowable<ApplicationResult> result = application.streamCall(param);
|
||||
|
||||
result.subscribe(
|
||||
// 处理每条消息
|
||||
data -> {
|
||||
try {
|
||||
String text = data.getOutput().getText();
|
||||
// 发送数据到客户端
|
||||
emitter.send(text);
|
||||
// 收集完整响应
|
||||
fullResponseRef.get().append(text);
|
||||
} catch (IOException e) {
|
||||
emitter.completeWithError(e);
|
||||
}
|
||||
},
|
||||
// 处理错误
|
||||
error -> {
|
||||
emitter.completeWithError(error);
|
||||
System.out.println("错误: " + error.getMessage());
|
||||
},
|
||||
// 处理完成
|
||||
() -> {
|
||||
// 保存AI回复到数据库
|
||||
String fullResponse = fullResponseRef.get().toString();
|
||||
saveMessage(conversationId, userId, "AI", fullResponse);
|
||||
emitter.complete();
|
||||
}
|
||||
);
|
||||
|
||||
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
|
||||
try {
|
||||
emitter.send("错误: " + e.getMessage());
|
||||
emitter.complete();
|
||||
} catch (IOException ex) {
|
||||
emitter.completeWithError(ex);
|
||||
}
|
||||
System.out.println("异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存消息到数据库
|
||||
* @param conversationId 会话ID
|
||||
* @param userId 用户ID
|
||||
* @param messageType 消息类型(USER/AI)
|
||||
* @param content 消息内容
|
||||
*/
|
||||
private void saveMessage(String conversationId, String userId, String messageType, String content) {
|
||||
ChatMessage chatMessage = new ChatMessage();
|
||||
chatMessage.setConversationId(conversationId);
|
||||
chatMessage.setStudentId(userId);
|
||||
chatMessage.setMessageType(messageType);
|
||||
chatMessage.setContent(content);
|
||||
chatMessage.setCreateTime(new Date());
|
||||
chatMessage.setUpdateTime(new Date());
|
||||
chatMessage.setIsDelete(0);
|
||||
chatMessageService.save(chatMessage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.requset.PredictRecordQueryRequest;
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.common.response.PageResponse;
|
||||
import com.xy.xyaicpzs.domain.entity.PredictRecord;
|
||||
import com.xy.xyaicpzs.domain.vo.UserPredictStatVO;
|
||||
import com.xy.xyaicpzs.service.DataAnalysisService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据分析控制器
|
||||
* 提供用户预测数据统计分析的API接口
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/data-analysis")
|
||||
@Tag(name = "数据分析", description = "用户预测数据统计分析API")
|
||||
public class DataAnalysisController {
|
||||
|
||||
@Autowired
|
||||
private DataAnalysisService dataAnalysisService;
|
||||
|
||||
/**
|
||||
* 获取用户预测统计数据
|
||||
* @param userId 用户ID
|
||||
* @return 用户预测统计数据
|
||||
*/
|
||||
@GetMapping("/user-predict-stat/{userId}")
|
||||
@Operation(summary = "获取用户预测统计数据", description = "根据用户ID获取该用户的预测次数、待开奖次数、命中次数、命中率等统计数据")
|
||||
public ApiResponse<UserPredictStatVO> getUserPredictStat(
|
||||
@Parameter(description = "用户ID,例如:1001", required = true)
|
||||
@PathVariable Long userId) {
|
||||
|
||||
try {
|
||||
log.info("接收到获取用户预测统计数据请求:用户ID={}", userId);
|
||||
|
||||
// 调用服务获取用户预测统计数据
|
||||
UserPredictStatVO result = dataAnalysisService.getUserPredictStat(userId);
|
||||
|
||||
log.info("获取用户预测统计数据完成,用户ID:{},预测次数:{},待开奖次数:{},命中次数:{},命中率:{}",
|
||||
userId, result.getPredictCount(), result.getPendingCount(),
|
||||
result.getHitCount(), result.getHitRate());
|
||||
|
||||
return ResultUtils.success(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户预测统计数据失败:{}", e.getMessage(), e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取用户预测统计数据失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发处理待开奖记录
|
||||
* @return 处理结果
|
||||
*/
|
||||
@PostMapping("/process-pending")
|
||||
@Operation(summary = "手动处理待开奖记录", description = "手动触发处理待开奖的预测记录,匹配开奖结果并更新中奖状态")
|
||||
public ApiResponse<String> processPendingPredictions() {
|
||||
|
||||
try {
|
||||
log.info("接收到手动处理待开奖记录请求");
|
||||
|
||||
// 调用服务处理待开奖记录
|
||||
int processedCount = dataAnalysisService.processPendingPredictions();
|
||||
|
||||
String message = String.format("处理完成,共处理%d条待开奖记录", processedCount);
|
||||
log.info("手动处理待开奖记录完成:{}", message);
|
||||
|
||||
return ResultUtils.success(message);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("手动处理待开奖记录失败:{}", e.getMessage(), e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "处理待开奖记录失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按条件查询预测记录
|
||||
* @param request 查询条件
|
||||
* @return 分页预测记录
|
||||
*/
|
||||
@PostMapping("/query-predict-records")
|
||||
@Operation(summary = "按条件查询预测记录", description = "根据用户ID和预测状态(待开奖/未中奖/已中奖)筛选预测记录,支持分页查询")
|
||||
public ApiResponse<PageResponse<PredictRecord>> queryPredictRecords(@RequestBody PredictRecordQueryRequest request) {
|
||||
try {
|
||||
log.info("接收到按条件查询预测记录请求:userId={}, predictStatus={}, current={}, pageSize={}",
|
||||
request.getUserId(), request.getPredictStatus(), request.getCurrent(), request.getPageSize());
|
||||
|
||||
// 调用服务查询预测记录
|
||||
PageResponse<PredictRecord> result = dataAnalysisService.queryPredictRecords(request);
|
||||
|
||||
log.info("按条件查询预测记录完成,总记录数:{}", result.getTotal());
|
||||
|
||||
return ResultUtils.success(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("按条件查询预测记录失败:{}", e.getMessage(), e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "查询预测记录失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有预测记录总数
|
||||
* @return 预测记录总数
|
||||
*/
|
||||
@GetMapping("/total-predict-count")
|
||||
@Operation(summary = "获取预测记录总数", description = "获取系统中所有用户的预测记录总数")
|
||||
public ApiResponse<Map<String, Long>> getTotalPredictCount() {
|
||||
try {
|
||||
log.info("接收到获取预测记录总数请求");
|
||||
|
||||
// 调用服务获取预测记录总数
|
||||
long totalCount = dataAnalysisService.getTotalPredictCount();
|
||||
|
||||
Map<String, Long> result = new HashMap<>();
|
||||
result.put("totalCount", totalCount);
|
||||
|
||||
log.info("获取预测记录总数完成,总数:{}", totalCount);
|
||||
|
||||
return ResultUtils.success(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取预测记录总数失败:{}", e.getMessage(), e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取预测记录总数失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.domain.entity.User;
|
||||
import com.xy.xyaicpzs.service.ExcelImportService;
|
||||
import com.xy.xyaicpzs.service.OperationHistoryService;
|
||||
import com.xy.xyaicpzs.service.UserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* Excel数据导入控制器
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/excel")
|
||||
@Tag(name = "Excel数据导入", description = "Excel数据导入相关接口")
|
||||
public class ExcelImportController {
|
||||
|
||||
@Autowired
|
||||
private ExcelImportService excelImportService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private OperationHistoryService operationHistoryService;
|
||||
|
||||
/**
|
||||
* 上传Excel文件并导入数据
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
@Operation(summary = "上传Excel文件导入数据", description = "上传包含T1、T2、T3、T4、T5、T6和T7 sheet的Excel文件,将红球、蓝球、线系数和面系数数据分别导入到十二个数据库表中")
|
||||
public ApiResponse<String> uploadExcelFile(
|
||||
@Parameter(description = "Excel文件(.xlsx格式)", required = true)
|
||||
@RequestParam("file") MultipartFile file, HttpServletRequest httpServletRequest) {
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)){
|
||||
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "无权限");
|
||||
}
|
||||
Long userId = loginUser.getId();
|
||||
String userName = loginUser.getUserName();
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
log.info("接收到Excel文件上传请求,文件名:{}", fileName);
|
||||
|
||||
try {
|
||||
String message = excelImportService.importExcelFile(file);
|
||||
|
||||
// 记录操作历史 - 成功
|
||||
String resultMessage = String.format("%s成功上传并导入Excel文件:%s,导入结果:%s", userName, fileName, message);
|
||||
operationHistoryService.recordOperation(userId, "Excel数据导入", 1, "成功", resultMessage);
|
||||
|
||||
return ResultUtils.success(message);
|
||||
} catch (Exception e) {
|
||||
log.error("Excel文件导入失败,文件名:{},错误:{}", fileName, e.getMessage(), e);
|
||||
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%sExcel文件导入失败:%s,文件名:%s,错误原因:%s", userName, fileName, fileName, e.getMessage());
|
||||
operationHistoryService.recordOperation(userId, "Excel数据导入", 1, "失败", resultMessage);
|
||||
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "Excel文件导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传Excel文件并导入开奖数据
|
||||
*/
|
||||
@PostMapping("/upload-lottery-draws")
|
||||
@Operation(summary = "上传Excel文件导入开奖数据", description = "上传包含T10工作表的Excel文件,只导入开奖数据到lottery_draws表")
|
||||
public ApiResponse<String> uploadLotteryDrawsFile(
|
||||
@Parameter(description = "包含T10工作表的Excel文件(.xlsx格式)", required = true)
|
||||
@RequestParam("file") MultipartFile file, HttpServletRequest httpServletRequest) {
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)){
|
||||
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "无权限");
|
||||
}
|
||||
Long userId = loginUser.getId();
|
||||
String userName = loginUser.getUserName();
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
log.info("接收到开奖数据上传请求,文件名:{}", fileName);
|
||||
|
||||
try {
|
||||
String message = excelImportService.importLotteryDrawsFile(file);
|
||||
|
||||
// 记录操作历史 - 成功
|
||||
String resultMessage = String.format("%s成功上传并导入开奖数据文件:%s,导入结果:%s", userName, fileName, message);
|
||||
operationHistoryService.recordOperation(userId, "开奖数据导入", 1, "成功", resultMessage);
|
||||
|
||||
return ResultUtils.success(message);
|
||||
} catch (Exception e) {
|
||||
log.error("开奖数据文件导入失败,文件名:{},错误:{}", fileName, e.getMessage(), e);
|
||||
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%s开奖数据文件导入失败:%s,文件名:%s,错误原因:%s", userName, fileName, fileName, e.getMessage());
|
||||
operationHistoryService.recordOperation(userId, "开奖数据导入", 1, "失败", resultMessage);
|
||||
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "开奖数据文件导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传Excel文件并追加导入开奖数据
|
||||
*/
|
||||
@PostMapping("/append-lottery-draws")
|
||||
@Operation(summary = "上传Excel文件追加导入开奖数据", description = "上传包含T10工作表的Excel文件,追加导入开奖数据(不清空现有数据,跳过重复期号)")
|
||||
public ApiResponse<String> appendLotteryDrawsFile(
|
||||
@Parameter(description = "包含T10工作表的Excel文件(.xlsx格式)", required = true)
|
||||
@RequestParam("file") MultipartFile file, HttpServletRequest httpServletRequest) {
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)){
|
||||
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "无权限");
|
||||
}
|
||||
Long userId = loginUser.getId();
|
||||
String userName = loginUser.getUserName();
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
log.info("接收到开奖数据追加上传请求,文件名:{}", fileName);
|
||||
|
||||
try {
|
||||
String message = excelImportService.appendLotteryDrawsFile(file);
|
||||
|
||||
// 记录操作历史 - 成功
|
||||
String resultMessage = String.format("%s成功追加导入开奖数据文件:%s,导入结果:%s", userName, fileName, message);
|
||||
operationHistoryService.recordOperation(userId, "开奖数据追加导入", 1, "成功", resultMessage);
|
||||
|
||||
return ResultUtils.success(message);
|
||||
} catch (Exception e) {
|
||||
log.error("开奖数据追加导入失败,文件名:{},错误:{}", fileName, e.getMessage(), e);
|
||||
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%s开奖数据追加导入失败:%s,文件名:%s,错误原因:%s", userName, fileName, fileName, e.getMessage());
|
||||
operationHistoryService.recordOperation(userId, "开奖数据追加导入", 1, "失败", resultMessage);
|
||||
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "开奖数据追加导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导入说明
|
||||
*/
|
||||
@GetMapping("/import-info")
|
||||
@Operation(summary = "获取导入说明", description = "获取Excel数据导入的详细说明")
|
||||
public String getImportInfo() {
|
||||
return excelImportService.getImportInfo();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/health")
|
||||
public class HealthController {
|
||||
|
||||
@GetMapping
|
||||
public String healthCheck() {
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
108
src/main/java/com/xy/xyaicpzs/controller/JwtController.java
Normal file
108
src/main/java/com/xy/xyaicpzs/controller/JwtController.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.service.CozeAuthService;
|
||||
import com.xy.xyaicpzs.util.JwtUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JWT令牌控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/jwt")
|
||||
@Tag(name = "JWT接口", description = "提供JWT令牌生成功能")
|
||||
public class JwtController {
|
||||
|
||||
@Autowired
|
||||
private JwtUtil jwtUtil;
|
||||
|
||||
@Autowired
|
||||
private CozeAuthService cozeAuthService;
|
||||
|
||||
/**
|
||||
* 生成JWT令牌
|
||||
*
|
||||
* @param expireSeconds 过期时间(秒)
|
||||
* @param sessionName 会话名称(可选)
|
||||
* @param deviceId 设备ID(可选)
|
||||
* @return JWT令牌
|
||||
*/
|
||||
@GetMapping("/token")
|
||||
@Operation(summary = "生成JWT令牌", description = "生成Coze API访问所需的JWT令牌")
|
||||
public ApiResponse<Map<String, String>> generateToken(
|
||||
@Parameter(description = "过期时间(秒)") @RequestParam(defaultValue = "600") int expireSeconds,
|
||||
@Parameter(description = "会话名称(可选)") @RequestParam(required = false) String sessionName,
|
||||
@Parameter(description = "设备ID(可选)") @RequestParam(required = false) String deviceId) {
|
||||
|
||||
try {
|
||||
String token = jwtUtil.generateToken(expireSeconds, sessionName, deviceId);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("token", token);
|
||||
return ResultUtils.success(result);
|
||||
} catch (Exception e) {
|
||||
return ResultUtils.error(50000, "JWT生成失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过JWT获取访问令牌
|
||||
*
|
||||
* @param jwt JWT令牌
|
||||
* @param durationSeconds 访问令牌有效期(秒),默认为86400秒(1天)
|
||||
* @return 包含访问令牌和过期时间的信息
|
||||
*/
|
||||
@PostMapping("/access-token")
|
||||
@Operation(summary = "获取访问令牌", description = "通过JWT获取Coze API的OAuth访问令牌")
|
||||
public ApiResponse<Map<String, Object>> getAccessToken(
|
||||
@Parameter(description = "JWT令牌") @RequestParam String jwt,
|
||||
@Parameter(description = "令牌有效期(秒)") @RequestParam(defaultValue = "86400") Integer durationSeconds) {
|
||||
|
||||
try {
|
||||
Map<String, Object> tokenInfo = cozeAuthService.getAccessToken(jwt, durationSeconds);
|
||||
return ResultUtils.success(tokenInfo);
|
||||
} catch (Exception e) {
|
||||
return ResultUtils.error(50000, "获取访问令牌失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 一站式获取访问令牌(生成JWT并立即获取访问令牌)
|
||||
*
|
||||
* @param jwtExpireSeconds JWT过期时间(秒)
|
||||
* @param sessionName 会话名称(可选)
|
||||
* @param deviceId 设备ID(可选)
|
||||
* @param tokenDurationSeconds 访问令牌有效期(秒)
|
||||
* @return 包含JWT、访问令牌和过期时间的信息
|
||||
*/
|
||||
@PostMapping("/one-step-token")
|
||||
@Operation(summary = "一站式获取访问令牌", description = "生成JWT并立即获取Coze API的OAuth访问令牌")
|
||||
public ApiResponse<Map<String, Object>> getOneStepToken(
|
||||
@Parameter(description = "JWT过期时间(秒)") @RequestParam(defaultValue = "600") int jwtExpireSeconds,
|
||||
@Parameter(description = "会话名称(可选)") @RequestParam(required = false) String sessionName,
|
||||
@Parameter(description = "设备ID(可选)") @RequestParam(required = false) String deviceId,
|
||||
@Parameter(description = "访问令牌有效期(秒)") @RequestParam(defaultValue = "86400") Integer tokenDurationSeconds) {
|
||||
|
||||
try {
|
||||
// 生成JWT令牌
|
||||
String jwt = jwtUtil.generateToken(jwtExpireSeconds, sessionName, deviceId);
|
||||
|
||||
// 获取访问令牌
|
||||
Map<String, Object> tokenInfo = cozeAuthService.getAccessToken(jwt, tokenDurationSeconds);
|
||||
|
||||
// 合并结果
|
||||
tokenInfo.put("jwt", jwt);
|
||||
|
||||
return ResultUtils.success(tokenInfo);
|
||||
} catch (Exception e) {
|
||||
return ResultUtils.error(50000, "获取访问令牌失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.domain.entity.OperationHistory;
|
||||
import com.xy.xyaicpzs.domain.entity.User;
|
||||
import com.xy.xyaicpzs.service.OperationHistoryService;
|
||||
import com.xy.xyaicpzs.service.UserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 操作历史管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/operation-history")
|
||||
@Slf4j
|
||||
@Tag(name = "操作历史管理", description = "操作历史记录相关接口")
|
||||
public class OperationHistoryController {
|
||||
|
||||
@Autowired
|
||||
private OperationHistoryService operationHistoryService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* 获取操作历史记录
|
||||
* 支持按操作模块和操作结果进行筛选
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取操作历史记录", description = "获取操作历史记录,支持按操作模块、操作结果筛选和结果信息模糊搜索")
|
||||
public ApiResponse<List<OperationHistory>> getOperationHistory(
|
||||
@Parameter(description = "操作模块(0-会员码管理/1-Excel导入管理等)")
|
||||
@RequestParam(value = "operationModule", required = false) Integer operationModule,
|
||||
@Parameter(description = "操作结果(成功/失败)")
|
||||
@RequestParam(value = "operationResult", required = false) String operationResult,
|
||||
@Parameter(description = "结果信息关键词(支持模糊搜索)")
|
||||
@RequestParam(value = "keyword", required = false) String keyword,
|
||||
HttpServletRequest httpServletRequest) {
|
||||
|
||||
try {
|
||||
// 权限校验:仅管理员可以查看
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)) {
|
||||
return ResultUtils.error(ErrorCode.NO_AUTH_ERROR, "无权限查看操作历史");
|
||||
}
|
||||
|
||||
log.info("获取操作历史,操作模块:{},操作结果:{},关键词:{}", operationModule, operationResult, keyword);
|
||||
|
||||
// 构建查询条件
|
||||
QueryWrapper<OperationHistory> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
// 添加操作模块筛选条件
|
||||
if (operationModule != null && operationModule >= 0) {
|
||||
queryWrapper.eq("operationModule", operationModule);
|
||||
}
|
||||
|
||||
// 添加操作结果筛选条件
|
||||
if (operationResult != null && !operationResult.trim().isEmpty()) {
|
||||
if (!operationResult.equals("成功") && !operationResult.equals("失败")) {
|
||||
return ResultUtils.error(ErrorCode.PARAMS_ERROR, "操作结果只能是'成功'或'失败'");
|
||||
}
|
||||
queryWrapper.eq("operationResult", operationResult);
|
||||
}
|
||||
|
||||
// 添加结果信息模糊搜索条件
|
||||
if (keyword != null && !keyword.trim().isEmpty()) {
|
||||
queryWrapper.like("resultMessage", keyword.trim());
|
||||
}
|
||||
|
||||
// 按操作时间降序排序
|
||||
queryWrapper.orderByDesc("operationTime");
|
||||
|
||||
// 查询操作历史
|
||||
List<OperationHistory> records = operationHistoryService.list(queryWrapper);
|
||||
|
||||
log.info("操作历史查询成功,共{}条记录", records.size());
|
||||
|
||||
return ResultUtils.success(records);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取操作历史失败", e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取操作历史失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/xy/xyaicpzs/controller/SmsController.java
Normal file
48
src/main/java/com/xy/xyaicpzs/controller/SmsController.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.service.SmsService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 短信控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/sms")
|
||||
@Tag(name = "短信接口", description = "提供短信验证码相关功能")
|
||||
public class SmsController {
|
||||
|
||||
@Autowired
|
||||
private SmsService smsService;
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
*
|
||||
* @param phoneNumber 手机号
|
||||
* @return 发送结果
|
||||
*/
|
||||
@PostMapping("/sendCode")
|
||||
@Operation(summary = "发送短信验证码", description = "向指定手机号发送验证码,每个手机号每天最多发送3次")
|
||||
public ApiResponse<Boolean> sendVerificationCode(
|
||||
@Parameter(description = "手机号码", required = true)
|
||||
@RequestParam String phoneNumber) {
|
||||
try {
|
||||
boolean success = smsService.sendVerificationCode(phoneNumber);
|
||||
if (success) {
|
||||
return ResultUtils.success(true);
|
||||
} else {
|
||||
return ResultUtils.error(40001, "发送验证码失败,请稍后重试或联系客服");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return ResultUtils.error(50000, "发送验证码异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.util.SpeechRecognizerDemo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 语音识别控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/speech")
|
||||
public class SpeechRecognitionController {
|
||||
|
||||
@Autowired
|
||||
private SpeechRecognizerDemo speechRecognizer;
|
||||
|
||||
/**
|
||||
* 识别本地语音文件
|
||||
* @param filePath 文件路径
|
||||
* @param sampleRate 采样率
|
||||
* @return 识别结果
|
||||
*/
|
||||
@GetMapping("/recognize")
|
||||
public ApiResponse<Map<String, String>> recognizeSpeech(
|
||||
@RequestParam("filePath") String filePath,
|
||||
@RequestParam(value = "sampleRate", defaultValue = "16000") int sampleRate) {
|
||||
|
||||
String text = speechRecognizer.speechToText(filePath, sampleRate);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("text", text);
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传并识别语音文件
|
||||
* @param file 上传的语音文件
|
||||
* @param sampleRate 采样率
|
||||
* @return 识别结果
|
||||
*/
|
||||
@PostMapping("/upload-and-recognize")
|
||||
public ApiResponse<Map<String, String>> uploadAndRecognize(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "sampleRate", defaultValue = "16000") int sampleRate) {
|
||||
|
||||
if (file.isEmpty()) {
|
||||
return ResultUtils.error(40001, "上传文件不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建临时目录
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
|
||||
Path filePath = Paths.get(tempDir, fileName);
|
||||
|
||||
// 保存上传的文件
|
||||
file.transferTo(filePath.toFile());
|
||||
|
||||
// 识别语音
|
||||
String text = speechRecognizer.speechToText(filePath.toString(), sampleRate);
|
||||
|
||||
// 删除临时文件
|
||||
Files.deleteIfExists(filePath);
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("text", text);
|
||||
return ResultUtils.success(result);
|
||||
} catch (IOException e) {
|
||||
return ResultUtils.error(50000, "文件处理失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
578
src/main/java/com/xy/xyaicpzs/controller/UserController.java
Normal file
578
src/main/java/com/xy/xyaicpzs/controller/UserController.java
Normal file
@@ -0,0 +1,578 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.xy.xyaicpzs.common.DeleteRequest;
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.requset.VipCodeActivateRequest;
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.domain.dto.user.*;
|
||||
import com.xy.xyaicpzs.domain.entity.User;
|
||||
import com.xy.xyaicpzs.domain.vo.UserVO;
|
||||
import com.xy.xyaicpzs.exception.BusinessException;
|
||||
import com.xy.xyaicpzs.service.UserService;
|
||||
import com.xy.xyaicpzs.service.VipCodeService;
|
||||
import com.xy.xyaicpzs.service.SmsService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 用户接口
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
@Tag(name = "用户管理", description = "用户管理相关接口")
|
||||
public class UserController {
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
@Resource
|
||||
private VipCodeService vipCodeService;
|
||||
|
||||
@Resource
|
||||
private SmsService smsService;
|
||||
|
||||
// region 登录相关
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*
|
||||
* @param userLoginRequest
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
@Operation(summary = "用户登录", description = "用户登录接口")
|
||||
public ApiResponse<UserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
|
||||
if (userLoginRequest == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
String userAccount = userLoginRequest.getUserAccount();
|
||||
String userPassword = userLoginRequest.getUserPassword();
|
||||
if (StringUtils.isAnyBlank(userAccount, userPassword)) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
User user = userService.userLogin(userAccount, userPassword, request);
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return ResultUtils.success(userVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注销
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
@Operation(summary = "用户注销", description = "用户注销接口")
|
||||
public ApiResponse<Boolean> userLogout(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
boolean result = userService.userLogout(request);
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/get/login")
|
||||
@Operation(summary = "获取当前登录用户", description = "获取当前登录用户信息")
|
||||
public ApiResponse<UserVO> getLoginUser(HttpServletRequest request) {
|
||||
User user = userService.getLoginUser(request);
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return ResultUtils.success(userVO);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region 增删改查
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*
|
||||
* @param userAddRequest
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
@Operation(summary = "创建用户", description = "管理员创建用户")
|
||||
public ApiResponse<Long> addUser(@RequestBody UserAddRequest userAddRequest, HttpServletRequest request) {
|
||||
if (userAddRequest == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
|
||||
// 参数校验
|
||||
String userAccount = userAddRequest.getUserAccount();
|
||||
String userPassword = userAddRequest.getUserPassword();
|
||||
String password = userAddRequest.getPassword();
|
||||
String phone = userAddRequest.getPhone();
|
||||
|
||||
// 如果userPassword为空但password不为空,则使用password
|
||||
if (StringUtils.isBlank(userPassword) && StringUtils.isNotBlank(password)) {
|
||||
userAddRequest.setUserPassword(password);
|
||||
userPassword = password;
|
||||
}
|
||||
|
||||
if (StringUtils.isAnyBlank(userAccount, userPassword)) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号或密码不能为空");
|
||||
}
|
||||
|
||||
if (phone != null && !phone.isEmpty()) {
|
||||
// 如果提供了手机号,可以进行手机号格式校验
|
||||
if (phone.length() != 11) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号格式不正确");
|
||||
}
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
BeanUtils.copyProperties(userAddRequest, user);
|
||||
|
||||
// 密码加密,使用Service层的加密方法
|
||||
String encryptPassword = userService.encryptPassword(userPassword);
|
||||
user.setUserPassword(encryptPassword);
|
||||
|
||||
boolean result = userService.save(user);
|
||||
if (!result) {
|
||||
throw new BusinessException(ErrorCode.OPERATION_ERROR);
|
||||
}
|
||||
return ResultUtils.success(user.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户状态
|
||||
*
|
||||
* @param userStatusUpdateRequest 用户状态更新请求
|
||||
* @param request HTTP请求
|
||||
* @return 修改结果
|
||||
*/
|
||||
@PostMapping("/update-status")
|
||||
@Operation(summary = "修改用户状态", description = "管理员修改用户状态(正常/封禁)")
|
||||
public ApiResponse<Boolean> updateUserStatus(@RequestBody UserStatusUpdateRequest userStatusUpdateRequest,
|
||||
HttpServletRequest request) {
|
||||
if (userStatusUpdateRequest == null || userStatusUpdateRequest.getId() == null
|
||||
|| userStatusUpdateRequest.getId() <= 0) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID不正确");
|
||||
}
|
||||
|
||||
Long id = userStatusUpdateRequest.getId();
|
||||
Integer status = userStatusUpdateRequest.getStatus();
|
||||
|
||||
// 校验状态值
|
||||
if (status == null || (status != 0 && status != 1)) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "状态值不正确,应为0(正常)或1(封禁)");
|
||||
}
|
||||
|
||||
// 确认操作人员是否为管理员
|
||||
User loginUser = userService.getLoginUser(request);
|
||||
if (!userService.isAdmin(loginUser)) {
|
||||
throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无管理员权限");
|
||||
}
|
||||
|
||||
// 检查目标用户是否存在
|
||||
User user = userService.getById(id);
|
||||
if (user == null) {
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "用户不存在");
|
||||
}
|
||||
|
||||
// 更新用户状态
|
||||
user.setStatus(status);
|
||||
boolean result = userService.updateById(user);
|
||||
if (!result) {
|
||||
throw new BusinessException(ErrorCode.OPERATION_ERROR, "操作失败");
|
||||
}
|
||||
|
||||
return ResultUtils.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*
|
||||
* @param deleteRequest
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
@Operation(summary = "删除用户", description = "管理员删除用户")
|
||||
public ApiResponse<Boolean> deleteUser(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
|
||||
if (deleteRequest == null || deleteRequest.getId() <= 0) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
boolean b = userService.removeById(deleteRequest.getId());
|
||||
return ResultUtils.success(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*
|
||||
* @param userUpdateRequest
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
@Operation(summary = "更新用户", description = "更新用户信息")
|
||||
public ApiResponse<Boolean> updateUser(@RequestBody UserUpdateRequest userUpdateRequest, HttpServletRequest request) {
|
||||
if (userUpdateRequest == null || userUpdateRequest.getId() == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
|
||||
// 参数校验
|
||||
String userPassword = userUpdateRequest.getUserPassword();
|
||||
String password = userUpdateRequest.getPassword();
|
||||
String phone = userUpdateRequest.getPhone();
|
||||
|
||||
// 如果userPassword为空但password不为空,则使用password
|
||||
if (StringUtils.isBlank(userPassword) && StringUtils.isNotBlank(password)) {
|
||||
userUpdateRequest.setUserPassword(password);
|
||||
userPassword = password;
|
||||
}
|
||||
|
||||
if (phone != null && !phone.isEmpty()) {
|
||||
// 如果提供了手机号,可以进行手机号格式校验
|
||||
if (phone.length() != 11) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号格式不正确");
|
||||
}
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
BeanUtils.copyProperties(userUpdateRequest, user);
|
||||
|
||||
// 如果更新了密码,需要进行加密
|
||||
if (StringUtils.isNotBlank(userPassword)) {
|
||||
String encryptPassword = userService.encryptPassword(userPassword);
|
||||
user.setUserPassword(encryptPassword);
|
||||
}
|
||||
|
||||
boolean result = userService.updateById(user);
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 id 获取用户
|
||||
*
|
||||
* @param id
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "根据ID获取用户", description = "根据用户ID获取用户信息")
|
||||
public ApiResponse<UserVO> getUserById(@RequestParam("id") long id, HttpServletRequest request) {
|
||||
if (id <= 0) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
User user = userService.getById(id);
|
||||
if (user == null) {
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
|
||||
}
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return ResultUtils.success(userVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*
|
||||
* @param userQueryRequest
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取用户列表", description = "获取用户列表,支持用户名/手机号模糊匹配和角色状态筛选")
|
||||
public ApiResponse<List<UserVO>> listUser(UserQueryRequest userQueryRequest, HttpServletRequest request) {
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
if (userQueryRequest != null) {
|
||||
// 用户名模糊匹配
|
||||
if (StringUtils.isNotBlank(userQueryRequest.getUserName())) {
|
||||
queryWrapper.like("userName", userQueryRequest.getUserName());
|
||||
}
|
||||
|
||||
// 手机号模糊匹配
|
||||
if (StringUtils.isNotBlank(userQueryRequest.getPhone())) {
|
||||
queryWrapper.like("phone", userQueryRequest.getPhone());
|
||||
}
|
||||
|
||||
// 账号模糊匹配
|
||||
if (StringUtils.isNotBlank(userQueryRequest.getUserAccount())) {
|
||||
queryWrapper.like("userAccount", userQueryRequest.getUserAccount());
|
||||
}
|
||||
|
||||
// 用户角色精确匹配
|
||||
if (userQueryRequest.getUserRole() != null) {
|
||||
queryWrapper.eq("userRole", userQueryRequest.getUserRole());
|
||||
}
|
||||
|
||||
// 用户状态精确匹配
|
||||
if (userQueryRequest.getStatus() != null) {
|
||||
queryWrapper.eq("status", userQueryRequest.getStatus());
|
||||
}
|
||||
|
||||
// 会员状态匹配
|
||||
if (userQueryRequest.getIsVip() != null) {
|
||||
queryWrapper.eq("isVip", userQueryRequest.getIsVip());
|
||||
}
|
||||
}
|
||||
|
||||
List<User> userList = userService.list(queryWrapper);
|
||||
List<UserVO> userVOList = userList.stream().map(user -> {
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return userVO;
|
||||
}).collect(Collectors.toList());
|
||||
return ResultUtils.success(userVOList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取用户列表
|
||||
*
|
||||
* @param userQueryRequest
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/list/page")
|
||||
@Operation(summary = "分页获取用户列表", description = "分页获取用户列表,支持用户名/手机号模糊匹配和角色状态筛选")
|
||||
public ApiResponse<Page<UserVO>> listUserByPage(UserQueryRequest userQueryRequest, HttpServletRequest request) {
|
||||
long current = 1;
|
||||
long size = 10;
|
||||
|
||||
if (userQueryRequest != null) {
|
||||
current = userQueryRequest.getCurrent();
|
||||
size = userQueryRequest.getPageSize();
|
||||
}
|
||||
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
if (userQueryRequest != null) {
|
||||
// 用户名模糊匹配
|
||||
if (StringUtils.isNotBlank(userQueryRequest.getUserName())) {
|
||||
queryWrapper.like("userName", userQueryRequest.getUserName());
|
||||
}
|
||||
|
||||
// 手机号模糊匹配
|
||||
if (StringUtils.isNotBlank(userQueryRequest.getPhone())) {
|
||||
queryWrapper.like("phone", userQueryRequest.getPhone());
|
||||
}
|
||||
|
||||
// 账号模糊匹配
|
||||
if (StringUtils.isNotBlank(userQueryRequest.getUserAccount())) {
|
||||
queryWrapper.like("userAccount", userQueryRequest.getUserAccount());
|
||||
}
|
||||
|
||||
// 用户角色精确匹配
|
||||
if (userQueryRequest.getUserRole() != null) {
|
||||
queryWrapper.eq("userRole", userQueryRequest.getUserRole());
|
||||
}
|
||||
|
||||
// 用户状态精确匹配
|
||||
if (userQueryRequest.getStatus() != null) {
|
||||
queryWrapper.eq("status", userQueryRequest.getStatus());
|
||||
}
|
||||
|
||||
// 会员状态匹配
|
||||
if (userQueryRequest.getIsVip() != null) {
|
||||
queryWrapper.eq("isVip", userQueryRequest.getIsVip());
|
||||
}
|
||||
}
|
||||
|
||||
Page<User> userPage = userService.page(new Page<>(current, size), queryWrapper);
|
||||
|
||||
// 创建新的Page对象用于返回UserVO
|
||||
Page<UserVO> userVOPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
|
||||
List<UserVO> userVOList = userPage.getRecords().stream().map(user -> {
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return userVO;
|
||||
}).collect(Collectors.toList());
|
||||
userVOPage.setRecords(userVOList);
|
||||
return ResultUtils.success(userVOPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户统计信息
|
||||
*
|
||||
* @return 包含总用户数和会员数的统计信息
|
||||
*/
|
||||
@GetMapping("/count")
|
||||
@Operation(summary = "获取用户统计信息", description = "获取系统中总用户数和会员数量")
|
||||
public ApiResponse<Map<String, Long>> getUserCount() {
|
||||
// 获取总用户数
|
||||
long totalUserCount = userService.count();
|
||||
|
||||
// 获取会员数量(isVip=1)
|
||||
QueryWrapper<User> vipQueryWrapper = new QueryWrapper<>();
|
||||
vipQueryWrapper.eq("isVip", 1);
|
||||
long vipUserCount = userService.count(vipQueryWrapper);
|
||||
|
||||
// 获取正常状态用户数量(status=0)
|
||||
QueryWrapper<User> normalStatusWrapper = new QueryWrapper<>();
|
||||
normalStatusWrapper.eq("status", 0);
|
||||
long normalUserCount = userService.count(normalStatusWrapper);
|
||||
|
||||
// 获取封禁状态用户数量(status=1)
|
||||
QueryWrapper<User> bannedStatusWrapper = new QueryWrapper<>();
|
||||
bannedStatusWrapper.eq("status", 1);
|
||||
long bannedUserCount = userService.count(bannedStatusWrapper);
|
||||
|
||||
// 构造返回结果
|
||||
Map<String, Long> countMap = new HashMap<>();
|
||||
countMap.put("totalUserCount", totalUserCount);
|
||||
countMap.put("vipUserCount", vipUserCount);
|
||||
countMap.put("normalUserCount", normalUserCount);
|
||||
countMap.put("bannedUserCount", bannedUserCount);
|
||||
|
||||
return ResultUtils.success(countMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活会员码
|
||||
*
|
||||
* @param request 会员码激活请求
|
||||
* @return 是否激活成功
|
||||
*/
|
||||
@PostMapping("/activate-vip")
|
||||
@Operation(summary = "激活会员码", description = "用户使用会员码激活会员服务")
|
||||
public ApiResponse<Boolean> activateVipCode(@RequestBody VipCodeActivateRequest request) {
|
||||
if (request == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
|
||||
}
|
||||
if (request.getUserId() == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(request.getCode())) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "会员码不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
boolean result = vipCodeService.activateVipCode(request.getUserId(), request.getCode());
|
||||
return ResultUtils.success(result);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("会员码激活失败:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, e.getMessage());
|
||||
} catch (RuntimeException e) {
|
||||
log.error("会员码激活系统错误:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "会员码激活失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号注册
|
||||
*
|
||||
* @param userPhoneRegisterRequest 手机号注册请求
|
||||
* @return 用户ID
|
||||
*/
|
||||
@PostMapping("/phone/register")
|
||||
@Operation(summary = "手机号注册", description = "使用手机号和验证码注册用户")
|
||||
public ApiResponse<Long> userPhoneRegister(@RequestBody UserPhoneRegisterRequest userPhoneRegisterRequest) {
|
||||
if (userPhoneRegisterRequest == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
long result = userService.userPhoneRegister(userPhoneRegisterRequest);
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号登录
|
||||
*
|
||||
* @param userPhoneLoginRequest 手机号登录请求
|
||||
* @param request HTTP请求
|
||||
* @return 用户信息
|
||||
*/
|
||||
@PostMapping("/phone/login")
|
||||
@Operation(summary = "手机号登录", description = "使用手机号和验证码登录")
|
||||
public ApiResponse<UserVO> userPhoneLogin(@RequestBody UserPhoneLoginRequest userPhoneLoginRequest, HttpServletRequest request) {
|
||||
if (userPhoneLoginRequest == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
||||
}
|
||||
User user = userService.userPhoneLogin(userPhoneLoginRequest, request);
|
||||
UserVO userVO = new UserVO();
|
||||
BeanUtils.copyProperties(user, userVO);
|
||||
return ResultUtils.success(userVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*
|
||||
* @param resetPasswordRequest 重置密码请求
|
||||
* @return 是否重置成功
|
||||
*/
|
||||
@PostMapping("/reset-password")
|
||||
@Operation(summary = "重置密码", description = "使用手机号和验证码重置密码")
|
||||
public ApiResponse<Boolean> resetPassword(@RequestBody ResetPasswordRequest resetPasswordRequest) {
|
||||
if (resetPasswordRequest == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
|
||||
}
|
||||
|
||||
String phone = resetPasswordRequest.getPhone();
|
||||
String code = resetPasswordRequest.getCode();
|
||||
String newPassword = resetPasswordRequest.getNewPassword();
|
||||
String confirmPassword = resetPasswordRequest.getConfirmPassword();
|
||||
|
||||
// 校验参数
|
||||
if (StringUtils.isAnyBlank(phone, code, newPassword, confirmPassword)) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
|
||||
}
|
||||
|
||||
// 校验手机号格式
|
||||
if (phone.length() != 11) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号格式不正确");
|
||||
}
|
||||
|
||||
// 校验两次密码是否一致
|
||||
if (!newPassword.equals(confirmPassword)) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
|
||||
}
|
||||
|
||||
// 密码长度校验
|
||||
if (newPassword.length() < 8) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码长度不能小于8位");
|
||||
}
|
||||
|
||||
// 验证短信验证码
|
||||
boolean isCodeValid = smsService.verifyCode(phone, code);
|
||||
if (!isCodeValid) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "验证码错误或已过期");
|
||||
}
|
||||
|
||||
// 查询用户是否存在
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("phone", phone);
|
||||
User user = userService.getOne(queryWrapper);
|
||||
if (user == null) {
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到该手机号注册的用户");
|
||||
}
|
||||
|
||||
// 更新密码
|
||||
String encryptPassword = userService.encryptPassword(newPassword);
|
||||
user.setUserPassword(encryptPassword);
|
||||
boolean result = userService.updateById(user);
|
||||
|
||||
if (!result) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "密码重置失败,请稍后重试");
|
||||
}
|
||||
|
||||
ApiResponse<Boolean> response = ResultUtils.success(true);
|
||||
response.setMessage("密码重置成功");
|
||||
return response;
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
298
src/main/java/com/xy/xyaicpzs/controller/VipCodeController.java
Normal file
298
src/main/java/com/xy/xyaicpzs/controller/VipCodeController.java
Normal file
@@ -0,0 +1,298 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.requset.GenerateVipCodesRequest;
|
||||
import com.xy.xyaicpzs.common.requset.VipCodeQueryRequest;
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.domain.entity.User;
|
||||
import com.xy.xyaicpzs.domain.entity.VipCode;
|
||||
import com.xy.xyaicpzs.domain.vo.VipCodeVO;
|
||||
import com.xy.xyaicpzs.exception.BusinessException;
|
||||
import com.xy.xyaicpzs.service.OperationHistoryService;
|
||||
import com.xy.xyaicpzs.service.UserService;
|
||||
import com.xy.xyaicpzs.service.VipCodeService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 会员码管理接口
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/vip-code")
|
||||
@Tag(name = "会员码管理", description = "会员码管理相关接口")
|
||||
public class VipCodeController {
|
||||
|
||||
@Resource
|
||||
private VipCodeService vipCodeService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private OperationHistoryService operationHistoryService;
|
||||
|
||||
/**
|
||||
* 批量生成会员码
|
||||
*
|
||||
* @param request 生成会员码请求
|
||||
* @return 生成成功的数量
|
||||
*/
|
||||
@PostMapping("/generate")
|
||||
@Operation(summary = "批量生成会员码", description = "管理员批量生成会员码")
|
||||
public ApiResponse<Integer> generateVipCodes(@RequestBody GenerateVipCodesRequest request,
|
||||
HttpServletRequest httpServletRequest) {
|
||||
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)){
|
||||
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "无权限");
|
||||
}
|
||||
Long userId = loginUser.getId();
|
||||
String userName = loginUser.getUserName();
|
||||
|
||||
if (request == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
|
||||
}
|
||||
if (request.getNumCodes() == null || request.getNumCodes() <= 0) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "生成数量必须大于0");
|
||||
}
|
||||
if (request.getVipExpireTime() == null || request.getVipExpireTime() <= 0) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "会员有效月数必须大于0");
|
||||
}
|
||||
if (request.getNumCodes() > 1000) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "单次生成数量不能超过1000");
|
||||
}
|
||||
|
||||
try {
|
||||
int result = vipCodeService.generateVipCodes(request.getNumCodes(), request.getVipExpireTime(), userId, userName);
|
||||
|
||||
// 记录操作历史 - 成功
|
||||
String resultMessage = String.format("%s成功生成%d个会员码,有效月数:%d", userName, result, request.getVipExpireTime());
|
||||
operationHistoryService.recordOperation(userId, "批量生成会员码", 0, "成功", resultMessage);
|
||||
|
||||
return ResultUtils.success(result);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("生成会员码参数错误:{}", e.getMessage());
|
||||
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%s生成会员码失败:%s,请求数量:%d,有效月数:%d",
|
||||
userName, e.getMessage(), request.getNumCodes(), request.getVipExpireTime());
|
||||
operationHistoryService.recordOperation(userId, "批量生成会员码", 0, "失败", resultMessage);
|
||||
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, e.getMessage());
|
||||
} catch (RuntimeException e) {
|
||||
log.error("生成会员码系统错误:{}", e.getMessage());
|
||||
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%s生成会员码系统错误:%s,请求数量:%d,有效月数:%d",
|
||||
userName, e.getMessage(), request.getNumCodes(), request.getVipExpireTime());
|
||||
operationHistoryService.recordOperation(userId, "批量生成会员码", 0, "失败", resultMessage);
|
||||
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "生成会员码失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个可用的会员码
|
||||
*
|
||||
* @param vipExpireTime 会员有效月数(1或12)
|
||||
* @return 可用的会员码
|
||||
*/
|
||||
@GetMapping("/available")
|
||||
@Operation(summary = "获取可用会员码", description = "根据有效月数获取一个可用的会员码")
|
||||
public ApiResponse<String> getAvailableVipCode(@RequestParam("vipExpireTime") Integer vipExpireTime,
|
||||
HttpServletRequest httpServletRequest) {
|
||||
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)){
|
||||
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "无权限");
|
||||
}
|
||||
Long userId = loginUser.getId();
|
||||
String userName = loginUser.getUserName();
|
||||
|
||||
if (vipExpireTime == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "会员有效月数不能为空");
|
||||
}
|
||||
if (vipExpireTime != 1 && vipExpireTime != 12) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "会员有效月数只能是1或12");
|
||||
}
|
||||
|
||||
try {
|
||||
String code = vipCodeService.getAvailableVipCode(vipExpireTime, userId, userName);
|
||||
if (code == null) {
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%s获取可用会员码失败:没有找到可用的会员码,有效月数:%d", userName, vipExpireTime);
|
||||
operationHistoryService.recordOperation(userId, "获取可用会员码", 0, "失败", resultMessage);
|
||||
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "没有找到可用的会员码");
|
||||
}
|
||||
|
||||
// 记录操作历史 - 成功
|
||||
String resultMessage = String.format("%s成功获取可用会员码:%s,有效月数:%d", userName, code, vipExpireTime);
|
||||
operationHistoryService.recordOperation(userId, "获取可用会员码", 0, "成功", resultMessage);
|
||||
|
||||
return ResultUtils.success(code);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("获取可用会员码参数错误:{}", e.getMessage());
|
||||
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%s获取可用会员码参数错误:%s,有效月数:%d", userName, e.getMessage(), vipExpireTime);
|
||||
operationHistoryService.recordOperation(userId, "获取可用会员码", 0, "失败", resultMessage);
|
||||
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("获取可用会员码系统错误:{}", e.getMessage());
|
||||
|
||||
// 记录操作历史 - 失败
|
||||
String resultMessage = String.format("%s获取可用会员码系统错误:%s,有效月数:%d", userName, e.getMessage(), vipExpireTime);
|
||||
operationHistoryService.recordOperation(userId, "获取可用会员码", 0, "失败", resultMessage);
|
||||
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取可用会员码失败,请生成后获取。");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取会员码列表
|
||||
*
|
||||
* @param vipCodeQueryRequest 会员码查询请求
|
||||
* @param httpServletRequest Http请求
|
||||
* @return 分页会员码列表
|
||||
*/
|
||||
@GetMapping("/list/page")
|
||||
@Operation(summary = "分页获取会员码列表", description = "分页获取会员码列表,支持根据会员码、使用状态和时间筛选")
|
||||
public ApiResponse<Page<VipCodeVO>> listVipCodesByPage(VipCodeQueryRequest vipCodeQueryRequest,
|
||||
HttpServletRequest httpServletRequest) {
|
||||
// 权限校验
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)){
|
||||
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "无权限");
|
||||
}
|
||||
|
||||
if (vipCodeQueryRequest == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
|
||||
}
|
||||
|
||||
long current = vipCodeQueryRequest.getCurrent();
|
||||
long pageSize = vipCodeQueryRequest.getPageSize();
|
||||
|
||||
// 构建查询条件
|
||||
QueryWrapper<VipCode> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
// 根据会员码模糊查询
|
||||
if (StringUtils.isNotBlank(vipCodeQueryRequest.getCode())) {
|
||||
queryWrapper.like("code", vipCodeQueryRequest.getCode());
|
||||
}
|
||||
|
||||
// 根据使用状态筛选
|
||||
if (vipCodeQueryRequest.getIsUse() != null) {
|
||||
queryWrapper.eq("isUse", vipCodeQueryRequest.getIsUse());
|
||||
}
|
||||
|
||||
// 根据会员有效月数筛选
|
||||
if (vipCodeQueryRequest.getVipExpireTime() != null) {
|
||||
queryWrapper.eq("vipExpireTime", vipCodeQueryRequest.getVipExpireTime());
|
||||
}
|
||||
|
||||
// 根据创建人ID筛选
|
||||
if (vipCodeQueryRequest.getCreatedUserId() != null) {
|
||||
queryWrapper.eq("createdUserId", vipCodeQueryRequest.getCreatedUserId());
|
||||
}
|
||||
|
||||
// 根据创建人名称模糊查询
|
||||
if (StringUtils.isNotBlank(vipCodeQueryRequest.getCreatedUserName())) {
|
||||
queryWrapper.like("createdUserName", vipCodeQueryRequest.getCreatedUserName());
|
||||
}
|
||||
|
||||
// 根据使用人ID筛选
|
||||
if (vipCodeQueryRequest.getUsedUserId() != null) {
|
||||
queryWrapper.eq("usedUserId", vipCodeQueryRequest.getUsedUserId());
|
||||
}
|
||||
|
||||
// 根据创建时间范围筛选
|
||||
if (vipCodeQueryRequest.getStartTime() != null && vipCodeQueryRequest.getEndTime() != null) {
|
||||
queryWrapper.between("createTime", vipCodeQueryRequest.getStartTime(), vipCodeQueryRequest.getEndTime());
|
||||
} else if (vipCodeQueryRequest.getStartTime() != null) {
|
||||
queryWrapper.ge("createTime", vipCodeQueryRequest.getStartTime());
|
||||
} else if (vipCodeQueryRequest.getEndTime() != null) {
|
||||
queryWrapper.le("createTime", vipCodeQueryRequest.getEndTime());
|
||||
}
|
||||
|
||||
// 按会员编号升序排序(从小到大)
|
||||
queryWrapper.orderByAsc("vipNumber");
|
||||
|
||||
// 执行分页查询
|
||||
Page<VipCode> vipCodePage = vipCodeService.page(new Page<>(current, pageSize), queryWrapper);
|
||||
|
||||
// 转换为VO对象
|
||||
List<VipCodeVO> vipCodeVOList = vipCodePage.getRecords().stream().map(vipCode -> {
|
||||
VipCodeVO vipCodeVO = new VipCodeVO();
|
||||
BeanUtils.copyProperties(vipCode, vipCodeVO);
|
||||
return vipCodeVO;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 创建VO分页对象,确保正确传递所有分页信息
|
||||
Page<VipCodeVO> vipCodeVOPage = new Page<>(vipCodePage.getCurrent(), vipCodePage.getSize(), vipCodePage.getTotal());
|
||||
vipCodeVOPage.setRecords(vipCodeVOList);
|
||||
// 手动设置pages值
|
||||
vipCodeVOPage.setPages(vipCodePage.getPages());
|
||||
|
||||
return ResultUtils.success(vipCodeVOPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员码统计数量
|
||||
*
|
||||
* @param httpServletRequest Http请求
|
||||
* @return 会员码统计数量
|
||||
*/
|
||||
@GetMapping("/count")
|
||||
@Operation(summary = "获取会员码统计数量", description = "获取系统中会员码总数、可用会员码和已使用会员码的数量")
|
||||
public ApiResponse<Map<String, Long>> getVipCodeCount(HttpServletRequest httpServletRequest) {
|
||||
// 权限校验
|
||||
User loginUser = userService.getLoginUser(httpServletRequest);
|
||||
if (!userService.isAdmin(loginUser)){
|
||||
return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "无权限");
|
||||
}
|
||||
|
||||
try {
|
||||
// 构建查询条件 - 总数
|
||||
long totalCount = vipCodeService.count();
|
||||
|
||||
// 构建查询条件 - 已使用的会员码
|
||||
QueryWrapper<VipCode> usedQueryWrapper = new QueryWrapper<>();
|
||||
usedQueryWrapper.eq("isUse", 1);
|
||||
long usedCount = vipCodeService.count(usedQueryWrapper);
|
||||
|
||||
// 构建查询条件 - 可用的会员码
|
||||
QueryWrapper<VipCode> availableQueryWrapper = new QueryWrapper<>();
|
||||
availableQueryWrapper.eq("isUse", 0);
|
||||
long availableCount = vipCodeService.count(availableQueryWrapper);
|
||||
|
||||
// 构造返回结果
|
||||
Map<String, Long> countMap = new HashMap<>();
|
||||
countMap.put("totalCount", totalCount);
|
||||
countMap.put("availableCount", availableCount);
|
||||
countMap.put("usedCount", usedCount);
|
||||
|
||||
return ResultUtils.success(countMap);
|
||||
} catch (Exception e) {
|
||||
log.error("获取会员码统计数量失败:{}", e.getMessage());
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取会员码统计数量失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.xy.xyaicpzs.controller;
|
||||
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.domain.entity.VipExchangeRecord;
|
||||
import com.xy.xyaicpzs.service.VipExchangeRecordService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* VIP兑换记录控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/vip-exchange-record")
|
||||
@Slf4j
|
||||
@Tag(name = "VIP兑换记录管理", description = "VIP兑换记录相关接口")
|
||||
public class VipExchangeRecordController {
|
||||
|
||||
@Autowired
|
||||
private VipExchangeRecordService vipExchangeRecordService;
|
||||
|
||||
/**
|
||||
* 根据用户ID获取所有兑换记录
|
||||
*/
|
||||
@GetMapping("/user/{userId}")
|
||||
@Operation(summary = "获取用户兑换记录", description = "根据用户ID获取该用户的所有VIP兑换记录")
|
||||
public ApiResponse<List<VipExchangeRecord>> getExchangeRecordsByUserId(
|
||||
@Parameter(description = "用户ID", required = true)
|
||||
@PathVariable("userId") Long userId) {
|
||||
|
||||
try {
|
||||
log.info("获取用户兑换记录,用户ID:{}", userId);
|
||||
|
||||
// 参数校验
|
||||
if (userId == null || userId <= 0) {
|
||||
return ResultUtils.error(ErrorCode.PARAMS_ERROR, "用户ID不能为空且必须大于0");
|
||||
}
|
||||
|
||||
// 查询用户兑换记录
|
||||
List<VipExchangeRecord> records = vipExchangeRecordService.getExchangeRecordsByUserId(userId);
|
||||
|
||||
log.info("用户ID:{} 的兑换记录查询成功,共{}条记录", userId, records.size());
|
||||
|
||||
return ResultUtils.success(records);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户兑换记录失败,用户ID:{}", userId, e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取兑换记录失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取兑换记录(带分页)
|
||||
*/
|
||||
@GetMapping("/user/{userId}/page")
|
||||
@Operation(summary = "分页获取用户兑换记录", description = "根据用户ID分页获取该用户的VIP兑换记录")
|
||||
public ApiResponse<List<VipExchangeRecord>> getExchangeRecordsByUserIdWithPage(
|
||||
@Parameter(description = "用户ID", required = true)
|
||||
@PathVariable("userId") Long userId,
|
||||
@Parameter(description = "页码,从1开始", required = false)
|
||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||
@Parameter(description = "每页大小", required = false)
|
||||
@RequestParam(value = "size", defaultValue = "10") Integer size) {
|
||||
|
||||
try {
|
||||
log.info("分页获取用户兑换记录,用户ID:{},页码:{},每页大小:{}", userId, page, size);
|
||||
|
||||
// 参数校验
|
||||
if (userId == null || userId <= 0) {
|
||||
return ResultUtils.error(ErrorCode.PARAMS_ERROR, "用户ID不能为空且必须大于0");
|
||||
}
|
||||
|
||||
if (page < 1) {
|
||||
page = 1;
|
||||
}
|
||||
if (size < 1 || size > 100) {
|
||||
size = 10;
|
||||
}
|
||||
|
||||
// 查询用户兑换记录
|
||||
List<VipExchangeRecord> allRecords = vipExchangeRecordService.getExchangeRecordsByUserId(userId);
|
||||
|
||||
// 手动分页
|
||||
int start = (page - 1) * size;
|
||||
int end = Math.min(start + size, allRecords.size());
|
||||
List<VipExchangeRecord> pageRecords = allRecords.subList(start, end);
|
||||
|
||||
log.info("用户ID:{} 的兑换记录分页查询成功,总记录数:{},当前页记录数:{}",
|
||||
userId, allRecords.size(), pageRecords.size());
|
||||
|
||||
return ResultUtils.success(pageRecords);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("分页获取用户兑换记录失败,用户ID:{}", userId, e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取兑换记录失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据兑换记录ID获取详情
|
||||
*/
|
||||
@GetMapping("/{recordId}")
|
||||
@Operation(summary = "获取兑换记录详情", description = "根据兑换记录ID获取详细信息")
|
||||
public ApiResponse<VipExchangeRecord> getExchangeRecordById(
|
||||
@Parameter(description = "兑换记录ID", required = true)
|
||||
@PathVariable("recordId") Long recordId) {
|
||||
|
||||
try {
|
||||
log.info("获取兑换记录详情,记录ID:{}", recordId);
|
||||
|
||||
// 参数校验
|
||||
if (recordId == null || recordId <= 0) {
|
||||
return ResultUtils.error(ErrorCode.PARAMS_ERROR, "兑换记录ID不能为空且必须大于0");
|
||||
}
|
||||
|
||||
// 查询兑换记录
|
||||
VipExchangeRecord record = vipExchangeRecordService.getById(recordId);
|
||||
|
||||
if (record == null) {
|
||||
return ResultUtils.error(ErrorCode.NOT_FOUND_ERROR, "兑换记录不存在");
|
||||
}
|
||||
|
||||
log.info("兑换记录详情查询成功,记录ID:{}", recordId);
|
||||
|
||||
return ResultUtils.success(record);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取兑换记录详情失败,记录ID:{}", recordId, e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取兑换记录详情失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 重置密码请求
|
||||
*/
|
||||
@Data
|
||||
public class ResetPasswordRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 短信验证码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 新密码
|
||||
*/
|
||||
private String newPassword;
|
||||
|
||||
/**
|
||||
* 确认新密码
|
||||
*/
|
||||
private String confirmPassword;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户创建请求
|
||||
*/
|
||||
@Data
|
||||
public class UserAddRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
private String userAccount;
|
||||
|
||||
/**
|
||||
* 电话
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String userAvatar;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private Integer gender;
|
||||
|
||||
/**
|
||||
* 用户角色:user / admin
|
||||
*/
|
||||
private String userRole;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String userPassword;
|
||||
|
||||
/**
|
||||
* 密码(兼容格式)
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 是否会员:0-非会员,1-会员
|
||||
*/
|
||||
private Integer isVip;
|
||||
|
||||
/**
|
||||
* 会员到期时间
|
||||
*/
|
||||
private Date vipExpire;
|
||||
|
||||
/**
|
||||
* 状态:0-正常,1-封禁
|
||||
*/
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户登录请求
|
||||
*/
|
||||
@Data
|
||||
public class UserLoginRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3191241716373120793L;
|
||||
|
||||
private String userAccount;
|
||||
|
||||
private String userPassword;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户手机号登录请求
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "用户手机号登录请求")
|
||||
public class UserPhoneLoginRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "手机号")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "验证码")
|
||||
private String code;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户手机号注册请求
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "用户手机号注册请求")
|
||||
public class UserPhoneRegisterRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "用户账号")
|
||||
private String userAccount;
|
||||
|
||||
@Schema(description = "用户名称")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "用户密码")
|
||||
private String userPassword;
|
||||
|
||||
@Schema(description = "确认密码")
|
||||
private String checkPassword;
|
||||
|
||||
@Schema(description = "手机号")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "验证码")
|
||||
private String code;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import com.xy.xyaicpzs.common.PageRequest;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户查询请求
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UserQueryRequest extends PageRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
private String userAccount;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private Integer gender;
|
||||
|
||||
/**
|
||||
* 用户角色:user / admin
|
||||
*/
|
||||
private String userRole;
|
||||
|
||||
/**
|
||||
* 是否会员:0-非会员,1-会员
|
||||
*/
|
||||
private Integer isVip;
|
||||
|
||||
/**
|
||||
* 状态:0-正常,1-封禁
|
||||
*/
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户注册请求
|
||||
*/
|
||||
@Data
|
||||
public class UserRegisterRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3191241716373120793L;
|
||||
|
||||
private String userAccount;
|
||||
|
||||
private String userName;
|
||||
|
||||
private String userPassword;
|
||||
|
||||
private String checkPassword;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户状态更新请求
|
||||
*/
|
||||
@Data
|
||||
public class UserStatusUpdateRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 状态:0-正常,1-封禁
|
||||
*/
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.xy.xyaicpzs.domain.dto.user;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户更新请求
|
||||
*/
|
||||
@Data
|
||||
public class UserUpdateRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
private String userAccount;
|
||||
|
||||
/**
|
||||
* 电话
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String userAvatar;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private Integer gender;
|
||||
|
||||
/**
|
||||
* 用户角色:user / admin
|
||||
*/
|
||||
private String userRole;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String userPassword;
|
||||
|
||||
/**
|
||||
* 密码(兼容格式)
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 是否会员:0-非会员,1-会员
|
||||
*/
|
||||
private Integer isVip;
|
||||
|
||||
/**
|
||||
* 会员到期时间
|
||||
*/
|
||||
private Date vipExpire;
|
||||
|
||||
/**
|
||||
* 状态:0-正常,1-封禁
|
||||
*/
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 蓝球最近100期数据表
|
||||
* @TableName blue_history_100
|
||||
*/
|
||||
@TableName(value ="blue_history_100")
|
||||
@Data
|
||||
public class BlueHistory100 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 出现频次
|
||||
*/
|
||||
private Integer frequencyCount;
|
||||
|
||||
/**
|
||||
* 平均隐现期(次)
|
||||
*/
|
||||
private Double averageInterval;
|
||||
|
||||
/**
|
||||
* 当前隐现期(次)
|
||||
*/
|
||||
private Integer nowInterval;
|
||||
|
||||
/**
|
||||
* 最多连出期(次)
|
||||
*/
|
||||
private Integer maxConsecutiveCount;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 蓝球全部历史数据表
|
||||
* @TableName blue_history_all
|
||||
*/
|
||||
@TableName(value ="blue_history_all")
|
||||
@Data
|
||||
public class BlueHistoryAll {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 出现频次
|
||||
*/
|
||||
private Integer frequencyCount;
|
||||
|
||||
/**
|
||||
* 出现频率百分比
|
||||
*/
|
||||
private Double frequencyPercentage;
|
||||
|
||||
/**
|
||||
* 平均隐现期(次)
|
||||
*/
|
||||
private Double averageInterval;
|
||||
|
||||
/**
|
||||
* 最长隐现期(次)
|
||||
*/
|
||||
private Integer maxHiddenInterval;
|
||||
|
||||
/**
|
||||
* 最多连出期(次)
|
||||
*/
|
||||
private Integer maxConsecutiveCount;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 蓝球历史数据排行表
|
||||
* @TableName blue_history_top
|
||||
*/
|
||||
@TableName(value ="blue_history_top")
|
||||
@Data
|
||||
public class BlueHistoryTop {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 排行
|
||||
*/
|
||||
private Integer no;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 创建蓝球100期数据排行表
|
||||
* @TableName blue_history_top_100
|
||||
*/
|
||||
@TableName(value ="blue_history_top_100")
|
||||
@Data
|
||||
public class BlueHistoryTop100 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 排行
|
||||
*/
|
||||
private Integer no;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
56
src/main/java/com/xy/xyaicpzs/domain/entity/ChatMessage.java
Normal file
56
src/main/java/com/xy/xyaicpzs/domain/entity/ChatMessage.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 聊天消息表
|
||||
* @TableName chat_message
|
||||
*/
|
||||
@TableName(value ="chat_message")
|
||||
@Data
|
||||
public class ChatMessage {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 会话ID
|
||||
*/
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* 用户ID,关联用户表
|
||||
*/
|
||||
private String studentId;
|
||||
|
||||
/**
|
||||
* 消息类型(如: 用户提问、AI回答)
|
||||
*/
|
||||
private String messageType;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除 0-未删除 1-已删除
|
||||
*/
|
||||
private Integer isDelete;
|
||||
}
|
||||
50
src/main/java/com/xy/xyaicpzs/domain/entity/History100.java
Normal file
50
src/main/java/com/xy/xyaicpzs/domain/entity/History100.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 最近100期数据表
|
||||
* @TableName history_100
|
||||
*/
|
||||
@TableName(value ="history_100")
|
||||
@Data
|
||||
public class History100 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 出现频次
|
||||
*/
|
||||
private Integer frequencyCount;
|
||||
|
||||
/**
|
||||
* 平均隐现期(次)
|
||||
*/
|
||||
private Double averageInterval;
|
||||
|
||||
/**
|
||||
* 当前隐现期(次)
|
||||
*/
|
||||
private Integer nowInterval;
|
||||
|
||||
/**
|
||||
* 最多连出期(次)
|
||||
*/
|
||||
private Integer maxConsecutiveCount;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
55
src/main/java/com/xy/xyaicpzs/domain/entity/HistoryAll.java
Normal file
55
src/main/java/com/xy/xyaicpzs/domain/entity/HistoryAll.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 历史数据表
|
||||
* @TableName history_all
|
||||
*/
|
||||
@TableName(value ="history_all")
|
||||
@Data
|
||||
public class HistoryAll {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 出现频次
|
||||
*/
|
||||
private Integer frequencyCount;
|
||||
|
||||
/**
|
||||
* 出现频率百分比
|
||||
*/
|
||||
private Double frequencyPercentage;
|
||||
|
||||
/**
|
||||
* 平均间隔
|
||||
*/
|
||||
private Double averageInterval;
|
||||
|
||||
/**
|
||||
* 最长隐藏间隔
|
||||
*/
|
||||
private Integer maxHiddenInterval;
|
||||
|
||||
/**
|
||||
* 最大连续出现次数
|
||||
*/
|
||||
private Integer maxConsecutiveCount;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/HistoryTop.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/HistoryTop.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 历史数据排行表
|
||||
* @TableName history_top
|
||||
*/
|
||||
@TableName(value ="history_top")
|
||||
@Data
|
||||
public class HistoryTop {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 排行
|
||||
*/
|
||||
private Integer no;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 创建100期数据排行表
|
||||
* @TableName history_top_100
|
||||
*/
|
||||
@TableName(value ="history_top_100")
|
||||
@Data
|
||||
public class HistoryTop100 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 排行
|
||||
*/
|
||||
private Integer no;
|
||||
|
||||
/**
|
||||
* 球号
|
||||
*/
|
||||
private Integer ballNumber;
|
||||
|
||||
/**
|
||||
* 点系数
|
||||
*/
|
||||
private Double pointCoefficient;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 彩票开奖信息表
|
||||
* @TableName lottery_draws
|
||||
*/
|
||||
@TableName(value ="lottery_draws")
|
||||
@Data
|
||||
public class LotteryDraws {
|
||||
/**
|
||||
* 开奖期号
|
||||
*/
|
||||
@TableId
|
||||
private Long drawId;
|
||||
|
||||
/**
|
||||
* 开奖日期
|
||||
*/
|
||||
private Date drawDate;
|
||||
|
||||
/**
|
||||
* 红1
|
||||
*/
|
||||
private Integer redBall1;
|
||||
|
||||
/**
|
||||
* 红2
|
||||
*/
|
||||
private Integer redBall2;
|
||||
|
||||
/**
|
||||
* 红3
|
||||
*/
|
||||
private Integer redBall3;
|
||||
|
||||
/**
|
||||
* 红4
|
||||
*/
|
||||
private Integer redBall4;
|
||||
|
||||
/**
|
||||
* 红5
|
||||
*/
|
||||
private Integer redBall5;
|
||||
|
||||
/**
|
||||
* 红6
|
||||
*/
|
||||
private Integer redBall6;
|
||||
|
||||
/**
|
||||
* 蓝球
|
||||
*/
|
||||
private Integer blueBall;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 操作历史记录表
|
||||
* @TableName operation_history
|
||||
*/
|
||||
@TableName(value ="operation_history")
|
||||
@Data
|
||||
public class OperationHistory {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 操作用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 操作类型(批量生成会员码/获取可用会员码/Excel导入等)
|
||||
*/
|
||||
private String operationType;
|
||||
|
||||
/**
|
||||
* 操作模块(会员码管理/Excel导入管理等)
|
||||
*/
|
||||
private Integer operationModule;
|
||||
|
||||
/**
|
||||
* 操作结果(成功/失败)
|
||||
*/
|
||||
private String operationResult;
|
||||
|
||||
/**
|
||||
* 结果消息
|
||||
*/
|
||||
private String resultMessage;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private Date operationTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 彩票开奖信息表
|
||||
* @TableName predict_record
|
||||
*/
|
||||
@TableName(value ="predict_record")
|
||||
@Data
|
||||
public class PredictRecord {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 开奖期号
|
||||
*/
|
||||
private Long drawId;
|
||||
|
||||
/**
|
||||
* 开奖日期
|
||||
*/
|
||||
private Date drawDate;
|
||||
|
||||
/**
|
||||
* 红1
|
||||
*/
|
||||
private Integer redBall1;
|
||||
|
||||
/**
|
||||
* 红2
|
||||
*/
|
||||
private Integer redBall2;
|
||||
|
||||
/**
|
||||
* 红3
|
||||
*/
|
||||
private Integer redBall3;
|
||||
|
||||
/**
|
||||
* 红4
|
||||
*/
|
||||
private Integer redBall4;
|
||||
|
||||
/**
|
||||
* 红5
|
||||
*/
|
||||
private Integer redBall5;
|
||||
|
||||
/**
|
||||
* 红6
|
||||
*/
|
||||
private Integer redBall6;
|
||||
|
||||
/**
|
||||
* 蓝球
|
||||
*/
|
||||
private Integer blueBall;
|
||||
|
||||
/**
|
||||
* 预测状态(待开奖/已开奖)
|
||||
*/
|
||||
private String predictStatus;
|
||||
|
||||
/**
|
||||
* 预测结果(未中奖/三等奖/二等奖/一等奖)
|
||||
*/
|
||||
private String predictResult;
|
||||
|
||||
/**
|
||||
* 预测时间
|
||||
*/
|
||||
private Date predictTime;
|
||||
|
||||
/**
|
||||
* 奖金
|
||||
*/
|
||||
private Long bonus;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private String type;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/T11.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/T11.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* t11表(蓝球组红球的面系数)
|
||||
* @TableName t11
|
||||
*/
|
||||
@TableName(value ="t11")
|
||||
@Data
|
||||
public class T11 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 主球
|
||||
*/
|
||||
private Integer masterBallNumber;
|
||||
|
||||
/**
|
||||
* 从球
|
||||
*/
|
||||
private Integer slaveBallNumber;
|
||||
|
||||
/**
|
||||
* 面系数
|
||||
*/
|
||||
private Double faceCoefficient;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/T3.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/T3.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* t3表(红球组红球的线系数)
|
||||
* @TableName t3
|
||||
*/
|
||||
@TableName(value ="t3")
|
||||
@Data
|
||||
public class T3 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 主球
|
||||
*/
|
||||
private Integer masterBallNumber;
|
||||
|
||||
/**
|
||||
* 从球
|
||||
*/
|
||||
private Integer slaveBallNumber;
|
||||
|
||||
/**
|
||||
* 线系数
|
||||
*/
|
||||
private Double lineCoefficient;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/T4.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/T4.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* t4表(蓝球组红球的线系数)
|
||||
* @TableName t4
|
||||
*/
|
||||
@TableName(value ="t4")
|
||||
@Data
|
||||
public class T4 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 主球
|
||||
*/
|
||||
private Integer masterBallNumber;
|
||||
|
||||
/**
|
||||
* 从球
|
||||
*/
|
||||
private Integer slaveBallNumber;
|
||||
|
||||
/**
|
||||
* 线系数
|
||||
*/
|
||||
private Double lineCoefficient;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/T5.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/T5.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* t5表(蓝球组蓝球的线系数)
|
||||
* @TableName t5
|
||||
*/
|
||||
@TableName(value ="t5")
|
||||
@Data
|
||||
public class T5 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 主球
|
||||
*/
|
||||
private Integer masterBallNumber;
|
||||
|
||||
/**
|
||||
* 从球
|
||||
*/
|
||||
private Integer slaveBallNumber;
|
||||
|
||||
/**
|
||||
* 线系数
|
||||
*/
|
||||
private Double lineCoefficient;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/T6.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/T6.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* t6表(红球组蓝球的线系数)
|
||||
* @TableName t6
|
||||
*/
|
||||
@TableName(value ="t6")
|
||||
@Data
|
||||
public class T6 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 主球
|
||||
*/
|
||||
private Integer masterBallNumber;
|
||||
|
||||
/**
|
||||
* 从球
|
||||
*/
|
||||
private Integer slaveBallNumber;
|
||||
|
||||
/**
|
||||
* 线系数
|
||||
*/
|
||||
private Double lineCoefficient;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/T7.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/T7.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* t7表(红球组红球的面系数)
|
||||
* @TableName t7
|
||||
*/
|
||||
@TableName(value ="t7")
|
||||
@Data
|
||||
public class T7 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 主球
|
||||
*/
|
||||
private Integer masterBallNumber;
|
||||
|
||||
/**
|
||||
* 从球
|
||||
*/
|
||||
private Integer slaveBallNumber;
|
||||
|
||||
/**
|
||||
* 面系数
|
||||
*/
|
||||
private Double faceCoefficient;
|
||||
}
|
||||
35
src/main/java/com/xy/xyaicpzs/domain/entity/T8.java
Normal file
35
src/main/java/com/xy/xyaicpzs/domain/entity/T8.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* t8表(红球组蓝球的面系数)
|
||||
* @TableName t8
|
||||
*/
|
||||
@TableName(value ="t8")
|
||||
@Data
|
||||
public class T8 {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 主球
|
||||
*/
|
||||
private Integer masterBallNumber;
|
||||
|
||||
/**
|
||||
* 从球
|
||||
*/
|
||||
private Integer slaveBallNumber;
|
||||
|
||||
/**
|
||||
* 面系数
|
||||
*/
|
||||
private Double faceCoefficient;
|
||||
}
|
||||
86
src/main/java/com/xy/xyaicpzs/domain/entity/User.java
Normal file
86
src/main/java/com/xy/xyaicpzs/domain/entity/User.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户
|
||||
* @TableName user
|
||||
*/
|
||||
@TableName(value ="user")
|
||||
@Data
|
||||
public class User {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
private String userAccount;
|
||||
|
||||
/**
|
||||
* 电话
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String userAvatar;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private Integer gender;
|
||||
|
||||
/**
|
||||
* 用户角色:user / admin
|
||||
*/
|
||||
private String userRole;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String userPassword;
|
||||
|
||||
/**
|
||||
* 是否会员:0-非会员,1-会员
|
||||
*/
|
||||
private Integer isVip;
|
||||
|
||||
/**
|
||||
* 会员到期时间
|
||||
*/
|
||||
private Date vipExpire;
|
||||
|
||||
/**
|
||||
* 状态:0-正常,1-封禁
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
private Integer isDelete;
|
||||
}
|
||||
72
src/main/java/com/xy/xyaicpzs/domain/entity/VipCode.java
Normal file
72
src/main/java/com/xy/xyaicpzs/domain/entity/VipCode.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 会员码表
|
||||
* @TableName vip_code
|
||||
*/
|
||||
@TableName(value ="vip_code")
|
||||
@Data
|
||||
public class VipCode {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 会员码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 会员有效月数(1/12)
|
||||
*/
|
||||
private Integer vipExpireTime;
|
||||
|
||||
/**
|
||||
* 会员编号
|
||||
*/
|
||||
private Integer vipNumber;
|
||||
|
||||
/**
|
||||
* 是否使用:0-未使用,1-已使用
|
||||
*/
|
||||
private Integer isUse;
|
||||
|
||||
/**
|
||||
* 创建的用户id
|
||||
*/
|
||||
private Long createdUserId;
|
||||
|
||||
/**
|
||||
* 创建的用户名称
|
||||
*/
|
||||
private String createdUserName;
|
||||
|
||||
|
||||
/**
|
||||
* 使用的用户id
|
||||
*/
|
||||
private Long usedUserId;
|
||||
|
||||
/**
|
||||
* 使用的用户名称
|
||||
*/
|
||||
private String usedUserName;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.xy.xyaicpzs.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 会员兑换表
|
||||
* @TableName vip_exchange_record
|
||||
*/
|
||||
@TableName(value ="vip_exchange_record")
|
||||
@Data
|
||||
public class VipExchangeRecord {
|
||||
/**
|
||||
* 唯一标识符
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 月度会员/年度会员
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 兑换方式
|
||||
*/
|
||||
private Integer exchangeMode;
|
||||
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
private Long orderNo;
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
private Integer orderAmount;
|
||||
|
||||
/**
|
||||
* 是否兑换(未兑换/已兑换)
|
||||
*/
|
||||
private Integer isUse;
|
||||
|
||||
/**
|
||||
* 兑换时间
|
||||
*/
|
||||
private Date exchangeTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 球号组合分析结果VO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "球号组合分析结果")
|
||||
public class BallCombinationAnalysisVO {
|
||||
|
||||
@Schema(description = "当前两个球的组合系数")
|
||||
private Double faceCoefficient;
|
||||
|
||||
@Schema(description = "与主球组合系数最高的球号")
|
||||
private Integer highestBall;
|
||||
|
||||
@Schema(description = "与主球组合系数最高的值")
|
||||
private Double highestCoefficient;
|
||||
|
||||
@Schema(description = "与主球组合系数最低的球号")
|
||||
private Integer lowestBall;
|
||||
|
||||
@Schema(description = "与主球组合系数最低的值")
|
||||
private Double lowestCoefficient;
|
||||
|
||||
@Schema(description = "与主球组合的所有系数平均值")
|
||||
private Double averageCoefficient;
|
||||
|
||||
@Schema(description = "最新开奖期号")
|
||||
private Long latestDrawId;
|
||||
}
|
||||
27
src/main/java/com/xy/xyaicpzs/domain/vo/BallHitRateVO.java
Normal file
27
src/main/java/com/xy/xyaicpzs/domain/vo/BallHitRateVO.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 球号命中率统计VO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "球号命中率统计")
|
||||
public class BallHitRateVO {
|
||||
|
||||
@Schema(description = "命中次数")
|
||||
private Integer hitCount;
|
||||
|
||||
@Schema(description = "总次数")
|
||||
private Integer totalCount;
|
||||
|
||||
@Schema(description = "命中率(百分比)")
|
||||
private Double hitRate;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 球号持续性分析结果VO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "球号持续性分析结果")
|
||||
public class BallPersistenceAnalysisVO {
|
||||
|
||||
@Schema(description = "当前两个球的组合线系数")
|
||||
private Double lineCoefficient;
|
||||
|
||||
@Schema(description = "与主球组合线系数最高的球号")
|
||||
private Integer highestBall;
|
||||
|
||||
@Schema(description = "与主球组合线系数最高的值")
|
||||
private Double highestCoefficient;
|
||||
|
||||
@Schema(description = "与主球组合线系数最低的球号")
|
||||
private Integer lowestBall;
|
||||
|
||||
@Schema(description = "与主球组合线系数最低的值")
|
||||
private Double lowestCoefficient;
|
||||
|
||||
@Schema(description = "与主球组合的所有线系数平均值")
|
||||
private Double averageCoefficient;
|
||||
|
||||
@Schema(description = "最新开奖期号")
|
||||
private Long latestDrawId;
|
||||
}
|
||||
47
src/main/java/com/xy/xyaicpzs/domain/vo/PrizeEstimateVO.java
Normal file
47
src/main/java/com/xy/xyaicpzs/domain/vo/PrizeEstimateVO.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 奖金估算VO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "奖金估算信息")
|
||||
public class PrizeEstimateVO {
|
||||
|
||||
@Schema(description = "总奖金合计")
|
||||
private BigDecimal totalPrize;
|
||||
|
||||
@Schema(description = "奖项明细")
|
||||
private List<PrizeDetailItem> prizeDetails;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "奖项明细项")
|
||||
public static class PrizeDetailItem {
|
||||
|
||||
@Schema(description = "中奖等级,例如:一等奖、二等奖等")
|
||||
private String prizeLevel;
|
||||
|
||||
@Schema(description = "中奖注数")
|
||||
private Integer winningCount;
|
||||
|
||||
@Schema(description = "单注奖金(元)")
|
||||
private BigDecimal singlePrize;
|
||||
|
||||
@Schema(description = "该等级奖金小计(元)")
|
||||
private BigDecimal subtotal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 红球命中率统计VO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "红球命中率统计")
|
||||
public class RedBallHitRateVO {
|
||||
|
||||
@Schema(description = "命中总红球数")
|
||||
private Integer totalHitCount;
|
||||
|
||||
@Schema(description = "总预测红球数")
|
||||
private Integer totalPredictedCount;
|
||||
|
||||
@Schema(description = "红球命中率(百分比)")
|
||||
private Double hitRate;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 用户预测统计数据VO
|
||||
*/
|
||||
@Data
|
||||
public class UserPredictStatVO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 预测次数(总记录数)
|
||||
*/
|
||||
private Long predictCount;
|
||||
|
||||
/**
|
||||
* 待开奖次数
|
||||
*/
|
||||
private Long pendingCount;
|
||||
|
||||
/**
|
||||
* 命中次数
|
||||
*/
|
||||
private Long hitCount;
|
||||
|
||||
/**
|
||||
* 命中率(保留4位小数)
|
||||
*/
|
||||
private BigDecimal hitRate;
|
||||
|
||||
/**
|
||||
* 已开奖次数(总次数 - 待开奖次数)
|
||||
*/
|
||||
private Long drawnCount;
|
||||
|
||||
}
|
||||
78
src/main/java/com/xy/xyaicpzs/domain/vo/UserVO.java
Normal file
78
src/main/java/com/xy/xyaicpzs/domain/vo/UserVO.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户视图(脱敏)
|
||||
*/
|
||||
@Data
|
||||
public class UserVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String userAccount;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String userAvatar;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private Integer gender;
|
||||
|
||||
/**
|
||||
* 用户角色:user / admin
|
||||
*/
|
||||
private String userRole;
|
||||
|
||||
/**
|
||||
* 用户角色:user / admin
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 是否会员:0-非会员,1-会员
|
||||
*/
|
||||
private Integer isVip;
|
||||
|
||||
/**
|
||||
* 会员到期时间
|
||||
*/
|
||||
private Date vipExpire;
|
||||
|
||||
/**
|
||||
* 状态:0-正常,1-封禁
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
||||
74
src/main/java/com/xy/xyaicpzs/domain/vo/VipCodeVO.java
Normal file
74
src/main/java/com/xy/xyaicpzs/domain/vo/VipCodeVO.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package com.xy.xyaicpzs.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 会员码视图对象
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "会员码视图对象")
|
||||
public class VipCodeVO {
|
||||
|
||||
/**
|
||||
* 会员码
|
||||
*/
|
||||
@Schema(description = "会员码")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 会员有效月数(1/12)
|
||||
*/
|
||||
@Schema(description = "会员有效月数")
|
||||
private Integer vipExpireTime;
|
||||
|
||||
/**
|
||||
* 会员编号(6位数,如100001)
|
||||
*/
|
||||
@Schema(description = "会员编号(6位数)")
|
||||
private Integer vipNumber;
|
||||
|
||||
/**
|
||||
* 是否使用:0-未使用,1-已使用
|
||||
*/
|
||||
@Schema(description = "是否使用:0-未使用,1-已使用")
|
||||
private Integer isUse;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
*/
|
||||
@Schema(description = "创建人ID")
|
||||
private Long createdUserId;
|
||||
|
||||
/**
|
||||
* 创建人名称
|
||||
*/
|
||||
@Schema(description = "创建人名称")
|
||||
private String createdUserName;
|
||||
|
||||
/**
|
||||
* 使用人ID
|
||||
*/
|
||||
@Schema(description = "使用人ID")
|
||||
private Long usedUserId;
|
||||
|
||||
/**
|
||||
* 使用人名称
|
||||
*/
|
||||
@Schema(description = "使用人名称")
|
||||
private String usedUserName;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "更新时间")
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.xy.xyaicpzs.exception;
|
||||
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
|
||||
/**
|
||||
* 自定义异常类
|
||||
*/
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
public BusinessException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode) {
|
||||
super(errorCode.getMessage());
|
||||
this.code = errorCode.getCode();
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode, String message) {
|
||||
super(message);
|
||||
this.code = errorCode.getCode();
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.xy.xyaicpzs.exception;
|
||||
|
||||
import com.xy.xyaicpzs.common.ErrorCode;
|
||||
import com.xy.xyaicpzs.common.ResultUtils;
|
||||
import com.xy.xyaicpzs.common.response.ApiResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*/
|
||||
//@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public ApiResponse<?> businessExceptionHandler(BusinessException e) {
|
||||
log.error("businessException: " + e.getMessage(), e);
|
||||
return ResultUtils.error(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ApiResponse<?> runtimeExceptionHandler(RuntimeException e) {
|
||||
log.error("runtimeException", e);
|
||||
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.BlueHistory100;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【blue_history_100(蓝球最近100期数据表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 10:40:04
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.BlueHistory100
|
||||
*/
|
||||
public interface BlueHistory100Mapper extends BaseMapper<BlueHistory100> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.BlueHistoryAll;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【blue_history_all(蓝球全部历史数据表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 10:40:07
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.BlueHistoryAll
|
||||
*/
|
||||
public interface BlueHistoryAllMapper extends BaseMapper<BlueHistoryAll> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.BlueHistoryTop100;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【blue_history_top_100(创建蓝球100期数据排行表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 10:40:13
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.BlueHistoryTop100
|
||||
*/
|
||||
public interface BlueHistoryTop100Mapper extends BaseMapper<BlueHistoryTop100> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.BlueHistoryTop;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【blue_history_top(蓝球历史数据排行表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 10:40:10
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.BlueHistoryTop
|
||||
*/
|
||||
public interface BlueHistoryTopMapper extends BaseMapper<BlueHistoryTop> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
18
src/main/java/com/xy/xyaicpzs/mapper/ChatMessageMapper.java
Normal file
18
src/main/java/com/xy/xyaicpzs/mapper/ChatMessageMapper.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.ChatMessage;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【chat_message(聊天消息表)】的数据库操作Mapper
|
||||
* @createDate 2025-07-07 17:37:15
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.ChatMessage
|
||||
*/
|
||||
public interface ChatMessageMapper extends BaseMapper<ChatMessage> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
18
src/main/java/com/xy/xyaicpzs/mapper/History100Mapper.java
Normal file
18
src/main/java/com/xy/xyaicpzs/mapper/History100Mapper.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.History100;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【history_100(最近100期数据表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 09:48:05
|
||||
* @Entity generator.domain.History100
|
||||
*/
|
||||
public interface History100Mapper extends BaseMapper<History100> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
18
src/main/java/com/xy/xyaicpzs/mapper/HistoryAllMapper.java
Normal file
18
src/main/java/com/xy/xyaicpzs/mapper/HistoryAllMapper.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.HistoryAll;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【history_all(历史数据表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 09:48:10
|
||||
* @Entity generator.domain.HistoryAll
|
||||
*/
|
||||
public interface HistoryAllMapper extends BaseMapper<HistoryAll> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.HistoryTop100;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【history_top_100(创建100期数据排行表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 09:48:16
|
||||
* @Entity generator.domain.HistoryTop100
|
||||
*/
|
||||
public interface HistoryTop100Mapper extends BaseMapper<HistoryTop100> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
18
src/main/java/com/xy/xyaicpzs/mapper/HistoryTopMapper.java
Normal file
18
src/main/java/com/xy/xyaicpzs/mapper/HistoryTopMapper.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.HistoryTop;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【history_top(历史数据排行表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 09:48:13
|
||||
* @Entity generator.domain.HistoryTop
|
||||
*/
|
||||
public interface HistoryTopMapper extends BaseMapper<HistoryTop> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
18
src/main/java/com/xy/xyaicpzs/mapper/LotteryDrawsMapper.java
Normal file
18
src/main/java/com/xy/xyaicpzs/mapper/LotteryDrawsMapper.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.LotteryDraws;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【lottery_draws(彩票开奖信息表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 16:41:29
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.LotteryDraws
|
||||
*/
|
||||
public interface LotteryDrawsMapper extends BaseMapper<LotteryDraws> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.OperationHistory;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【operation_history(操作历史记录表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-19 14:51:51
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.OperationHistory
|
||||
*/
|
||||
public interface OperationHistoryMapper extends BaseMapper<OperationHistory> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.PredictRecord;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【predict_record(彩票开奖信息表)】的数据库操作Mapper
|
||||
* @createDate 2025-06-16 13:17:53
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.PredictRecord
|
||||
*/
|
||||
public interface PredictRecordMapper extends BaseMapper<PredictRecord> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
18
src/main/java/com/xy/xyaicpzs/mapper/T11Mapper.java
Normal file
18
src/main/java/com/xy/xyaicpzs/mapper/T11Mapper.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.xy.xyaicpzs.mapper;
|
||||
|
||||
import com.xy.xyaicpzs.domain.entity.T11;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author XY003
|
||||
* @description 针对表【t11(t11表(蓝球组红球的面系数))】的数据库操作Mapper
|
||||
* @createDate 2025-06-14 16:25:23
|
||||
* @Entity com.xy.xyaicpzs.domain.entity.T11
|
||||
*/
|
||||
public interface T11Mapper extends BaseMapper<T11> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user