Compare commits

...

68 Commits
master ... dev

Author SHA1 Message Date
cb 57bc8ab4c9 no message 2025-12-23 10:53:19 +08:00
cb a6c588d411 no message 2025-11-17 16:28:30 +08:00
cb 92c566bf57 增加点击次数 2025-11-14 17:57:15 +08:00
clunt a02a50cc3c Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	ruoyi-admin/src/main/resources/templates/customer/service/index.html
2025-11-14 16:25:06 +08:00
clunt 607b254b53 feat: 修复bug 2025-11-14 16:24:42 +08:00
cb cb6c71cad1 no message 2025-11-03 11:45:00 +08:00
clunt 238d17802d feat: 线索分配需求 2025-10-28 09:40:09 +08:00
cb 0a9480d6e6 no message 2025-09-24 15:25:03 +08:00
cb 8f04c30b2e no message 2025-09-24 12:03:00 +08:00
cb ea9d926a27 no message 2025-09-24 11:35:49 +08:00
cb 4d49e11023 no message 2025-09-23 18:46:32 +08:00
cb a4a0e8df26 no message 2025-09-23 12:22:32 +08:00
cb a13c5a0ff1 新增 后台的客户对话页面 2025-09-22 17:27:11 +08:00
clunt 9b1abac458 feat: 分配线索后的短信通知 2025-07-31 14:59:19 +08:00
cb 943b447d99 no message 2025-07-25 16:13:55 +08:00
cb a25e34794f no message 2025-07-23 17:21:46 +08:00
cb 9b611ab46f no message 2025-07-07 14:41:01 +08:00
cb 6fb9d84448 no message 2025-07-07 10:03:10 +08:00
cb 235892ea63 no message 2025-07-07 09:01:41 +08:00
cb 664dc61687 no message 2025-07-03 17:53:55 +08:00
cb 6539679a67 no message 2025-07-03 16:21:53 +08:00
cb d3fd5b956a no message 2025-07-03 10:46:42 +08:00
cb 4012aa1887 增加捞取线索池 2025-07-02 16:43:15 +08:00
cb b1439322ac no message 2025-06-05 17:30:17 +08:00
cb cde30ab1f9 增加归因数据回传 2025-05-24 16:30:16 +08:00
YiFei Kuang b2dc343c93 公海池和现有销售需要展示原始的 2025-03-22 10:17:26 +08:00
YiFei Kuang 2b3270107e 完成 vivo的新版本对接 2025-03-22 09:59:53 +08:00
Yifei Kuang 8b14c4479b 线索问题 2025-01-19 11:39:25 +08:00
Gavin Tigano b02c9b41a7 feat: 销售二次分配时,需要记录原是销售是谁 2024-07-14 08:55:57 +08:00
Gavin Tigano 76fc495423 feat: 销售二次分配时,需要记录原是销售是谁 2024-07-11 10:38:10 +08:00
kuang.yife 278bf616af 百度线索新增设置 2024-07-11 00:54:19 +08:00
kuang.yife 60ab287cd2 百度线索新增设置 2024-06-04 09:21:20 +08:00
kuang.yife c661c14985 权限过滤问题 2024-05-29 14:16:30 +08:00
kuang.yife 057e19109a 运营角色增加,以及权限过滤 2024-05-29 13:44:51 +08:00
kuang.yife 5a2e981c41 调转调用顺序,优化 2024-02-23 11:55:50 +08:00
kuang.yife 31e8ac48bc 成交金额字段 2024-01-03 13:50:09 +08:00
kuang.yife 46ea5e5046 成交金额字段 2023-12-11 18:21:45 +08:00
kuang.yife 6d61bd057a 初始线索增加时间+来源搜索 2023-12-11 10:13:30 +08:00
kuang.yife 198561f8f1 修改手机号 2023-12-10 12:03:57 +08:00
kuang.yife fe9c9aed30 修改手机号 2023-12-04 09:36:57 +08:00
kuang.yife 7f2af57d39 vivo付费 2023-11-20 17:51:02 +08:00
kuang.yife 61d7556e6d vivo归因使用oaid 2023-11-13 14:30:32 +08:00
kuang.yife 0570995736 线索相关修改 2023-11-11 10:42:12 +08:00
kuang.yife 72aba428d5 视频素材+图片素材 2023-11-06 11:39:11 +08:00
kuang.yife 64c8599c57 华为广告回归数据查询 2023-10-30 23:36:29 +08:00
kuang.yife bd1ce64bfa 新增华为数据归因分析 2023-10-30 17:40:59 +08:00
kuang.yife 97aa4d579c 新增华为数据归因分析 2023-10-29 22:59:33 +08:00
kuang.yife 1e0e6c8f6b 密码 2023-10-24 16:03:39 +08:00
kuang.yife c0cc5157f0 vivo归因 2023-10-24 16:00:58 +08:00
kuang.yife 801df735c0 记录来源 2023-10-18 23:32:21 +08:00
kuang.yife ae384e80ff 回调数据类型修改 2023-10-16 18:23:35 +08:00
kuang.yife 91963f6860 oppo回调广告接口 2023-10-16 14:08:13 +08:00
kuang.yife ea767b5971 oppo回调广告接口 2023-10-15 13:36:49 +08:00
kuang.yife 9fcd15ccdd ads回调 2023-10-11 10:04:43 +08:00
kuang.yife 9ef81801e6 修复bug 2023-10-08 22:22:35 +08:00
kuang.yife 9ac3b60ad2 素材列表+minio初版+七牛云 2023-10-07 16:40:46 +08:00
kuang.yife 399e1cdc27 一大堆需求开发完成 2023-08-29 17:48:49 +08:00
kuang.yife 7658598075 迁移回调广告接口到短信注册 2023-08-10 11:24:15 +08:00
kuang.yife 882e8a477b 广告回调参数修复 2023-08-09 22:47:28 +08:00
kuang.yife 3528bb88b3 广告回调调通/http工具类优化 2023-07-31 11:49:29 +08:00
kuang.yife e1d90b795a 页面修复/短信验证/回调新增 2023-07-29 10:48:15 +08:00
kuang.yife 40043859df 注销/短信验证码/线索 2023-05-19 15:06:07 +08:00
kuang.yife aea8f82331 短信验证码模版+签名使用不对的问题 2023-05-16 10:48:03 +08:00
kuang.yife fe64a32608 短信验证码 2023-05-15 16:44:50 +08:00
kuang.yife 47976b80de 阿里云短信接口 2023-05-15 14:57:49 +08:00
kuang.yife 9d6356a286 app增加图片/视频素材 2023-05-15 14:02:06 +08:00
kuang.yife afc4a7ba19 保无忧PC版本 2023-05-15 11:46:15 +08:00
kuang.yife 8a79fccffa 保无忧初始版本 2023-05-11 10:55:04 +08:00
406 changed files with 20055 additions and 10237 deletions

2
.gitignore vendored
View File

@ -44,3 +44,5 @@ nbdist/
!*/build/*.java
!*/build/*.html
!*/build/*.xml
/get-pip.py
sql/database_update.sql

View File

@ -0,0 +1,264 @@
# 线索值班配置系统技术架构文档
## 1. 架构设计
```mermaid
graph TD
A[用户浏览器] --> B[Spring Boot Web层]
B --> C[Service业务层]
C --> D[MyBatis数据访问层]
D --> E[MySQL数据库]
B --> F[Thymeleaf模板引擎]
C --> G[定时任务调度]
C --> H[缓存层Redis]
subgraph "前端层"
B
F
end
subgraph "业务层"
C
G
H
end
subgraph "数据层"
D
E
end
```
## 2. 技术描述
- **前端**Thymeleaf@3.0 + Bootstrap@4.6 + jQuery@3.6 + LayUI@2.6
- **后端**Spring Boot@2.5.14 + MyBatis@3.5 + Apache Shiro@1.10.1
- **数据库**MySQL@8.0
- **缓存**Redis@6.2(可选,用于分配算法优化)
## 3. 路由定义
| 路由 | 用途 |
|------|------|
| /system/dutyConfig | 值班配置管理主页面 |
| /system/dutyConfig/list | 获取值班配置列表数据 |
| /system/dutyConfig/add | 新增值班配置页面 |
| /system/dutyConfig/edit/{id} | 编辑值班配置页面 |
| /system/dutyConfig/save | 保存值班配置 |
| /system/dutyConfig/update | 更新值班配置 |
| /system/dutyConfig/remove/{ids} | 删除值班配置 |
| /system/dutyConfig/changeStatus | 修改配置状态 |
| /system/dutyConfig/getAvailableUsers | 获取可用用户列表 |
| /system/dutyConfig/statistics | 分配统计页面 |
## 4. API定义
### 4.1 核心API
值班配置管理相关接口
```
GET /system/dutyConfig/list
```
请求参数:
| 参数名称 | 参数类型 | 是否必填 | 描述 |
|----------|----------|----------|------|
| pageNum | int | false | 页码默认1 |
| pageSize | int | false | 每页大小默认10 |
| configName | string | false | 配置名称(模糊查询) |
| status | string | false | 状态0-禁用1-启用 |
响应数据:
| 参数名称 | 参数类型 | 描述 |
|----------|----------|------|
| code | int | 响应状态码 |
| msg | string | 响应消息 |
| rows | array | 配置列表数据 |
| total | int | 总记录数 |
```
POST /system/dutyConfig/save
```
请求参数:
| 参数名称 | 参数类型 | 是否必填 | 描述 |
|----------|----------|----------|------|
| configName | string | true | 配置名称 |
| startTime | string | true | 开始时间HH:mm格式 |
| endTime | string | true | 结束时间HH:mm格式 |
| userIds | string | true | 值班用户ID列表逗号分隔 |
| status | string | true | 状态0-禁用1-启用 |
| remark | string | false | 备注信息 |
响应数据:
| 参数名称 | 参数类型 | 描述 |
|----------|----------|------|
| code | int | 响应状态码 |
| msg | string | 响应消息 |
示例请求:
```json
{
"configName": "工作日白班",
"startTime": "09:00",
"endTime": "18:00",
"userIds": "1,2,3,4",
"status": "1",
"remark": "工作日白班值班安排"
}
```
```
GET /system/dutyConfig/getAvailableUsers
```
响应数据:
| 参数名称 | 参数类型 | 描述 |
|----------|----------|------|
| code | int | 响应状态码 |
| data | array | 可用用户列表 |
用户对象结构:
| 参数名称 | 参数类型 | 描述 |
|----------|----------|------|
| userId | long | 用户ID |
| userName | string | 用户姓名 |
| loginName | string | 登录名 |
| status | string | 用户状态 |
## 5. 服务器架构图
```mermaid
graph TD
A[Controller层] --> B[Service层]
B --> C[Mapper层]
C --> D[(MySQL数据库)]
B --> E[分配算法服务]
B --> F[缓存服务]
E --> G[轮询分配器]
E --> H[时间匹配器]
subgraph "Web层"
A
end
subgraph "业务层"
B
E
F
end
subgraph "数据访问层"
C
end
subgraph "算法组件"
G
H
end
```
## 6. 数据模型
### 6.1 数据模型定义
```mermaid
erDiagram
DUTY_CONFIG ||--o{ DUTY_CONFIG_USER : contains
SYS_USER ||--o{ DUTY_CONFIG_USER : assigned
DUTY_CONFIG ||--o{ CLEW_ASSIGN_LOG : generates
SYS_USER ||--o{ CLEW_ASSIGN_LOG : receives
DUTY_CONFIG {
bigint id PK
string config_name
string start_time
string end_time
string status
string remark
datetime create_time
datetime update_time
string create_by
string update_by
}
DUTY_CONFIG_USER {
bigint id PK
bigint config_id FK
bigint user_id FK
int sort_order
datetime create_time
}
SYS_USER {
bigint user_id PK
string user_name
string login_name
string status
datetime create_time
}
CLEW_ASSIGN_LOG {
bigint id PK
bigint clew_id
bigint config_id FK
bigint assigned_user_id FK
datetime assign_time
string assign_type
}
```
### 6.2 数据定义语言
值班配置表duty_config
```sql
-- 创建值班配置表
CREATE TABLE duty_config (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
config_name VARCHAR(100) NOT NULL COMMENT '配置名称',
start_time VARCHAR(5) NOT NULL COMMENT '开始时间HH:mm',
end_time VARCHAR(5) NOT NULL COMMENT '结束时间HH:mm',
status CHAR(1) DEFAULT '1' COMMENT '状态0-禁用1-启用)',
remark VARCHAR(500) COMMENT '备注',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
create_by VARCHAR(64) COMMENT '创建者',
update_by VARCHAR(64) COMMENT '更新者',
del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志0-正常1-删除)'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='值班配置表';
-- 创建值班配置用户关联表
CREATE TABLE duty_config_user (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
config_id BIGINT NOT NULL COMMENT '配置ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
sort_order INT DEFAULT 0 COMMENT '排序顺序',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
INDEX idx_config_id (config_id),
INDEX idx_user_id (user_id),
FOREIGN KEY (config_id) REFERENCES duty_config(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='值班配置用户关联表';
-- 创建线索分配日志表
CREATE TABLE clew_assign_log (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
clew_id BIGINT COMMENT '线索ID',
config_id BIGINT COMMENT '使用的配置ID',
assigned_user_id BIGINT NOT NULL COMMENT '分配的用户ID',
assign_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '分配时间',
assign_type VARCHAR(20) DEFAULT 'AUTO' COMMENT '分配类型AUTO-自动MANUAL-手动)',
remark VARCHAR(200) COMMENT '备注',
INDEX idx_clew_id (clew_id),
INDEX idx_assigned_user (assigned_user_id),
INDEX idx_assign_time (assign_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='线索分配日志表';
-- 创建索引
CREATE INDEX idx_duty_config_time ON duty_config(start_time, end_time, status);
CREATE INDEX idx_duty_config_status ON duty_config(status, del_flag);
-- 插入初始数据
INSERT INTO duty_config (config_name, start_time, end_time,{"file_path": "/Users/clunt/java/RuoYi/.trae/documents/线索值班配置系统技术架构文档.md", "content":

View File

@ -0,0 +1,95 @@
# 线索值班配置系统需求文档
## 1. 产品概述
线索值班配置系统是基于若依框架开发的线索自动分配管理模块,旨在解决当前线索只能固定分配给特定用户的问题。通过配置值班时间段和值班人员,实现线索的智能轮流分配,提高线索处理效率和公平性。
- 解决线索分配不均衡的问题,提升销售团队工作效率
- 支持灵活的时间段配置和多用户轮班管理
- 为线索跟踪系统提供智能化的分配策略
## 2. 核心功能
### 2.1 用户角色
| 角色 | 权限说明 | 核心权限 |
|------|----------|----------|
| 系统管理员 | 完整的值班配置管理权限 | 可以创建、修改、删除值班配置,管理所有用户的值班安排 |
| 部门主管 | 部门内值班配置管理 | 可以管理本部门用户的值班配置,查看分配统计 |
| 普通销售 | 查看权限 | 可以查看自己的值班安排和线索分配情况 |
### 2.2 功能模块
本系统包含以下核心页面:
1. **值班配置管理页面**:值班规则列表、配置表单、状态管理
2. **值班人员管理页面**:人员选择、轮班顺序设置、人员状态管理
3. **线索分配统计页面**:分配记录查看、统计报表、分配日志
### 2.3 页面详情
| 页面名称 | 模块名称 | 功能描述 |
|----------|----------|----------|
| 值班配置管理页面 | 配置列表 | 显示所有值班配置,支持搜索、筛选、分页查看 |
| 值班配置管理页面 | 新增配置 | 创建新的值班配置,设置时间段、选择值班人员、设置状态 |
| 值班配置管理页面 | 编辑配置 | 修改现有配置的时间段、人员安排、启用状态 |
| 值班配置管理页面 | 删除配置 | 删除不需要的值班配置,支持批量删除 |
| 值班人员管理页面 | 人员选择 | 从sys_user表获取可用用户支持多选和搜索 |
| 值班人员管理页面 | 轮班设置 | 设置人员轮班顺序,支持拖拽排序 |
| 线索分配统计页面 | 分配记录 | 查看线索分配历史记录,包括分配时间、分配人员、线索信息 |
| 线索分配统计页面 | 统计报表 | 显示各时间段的分配统计,人员工作量分析 |
## 3. 核心流程
### 管理员配置流程
1. 管理员登录系统 → 进入值班配置管理页面
2. 创建新的值班配置 → 设置时间段(开始时间-结束时间,精确到分钟)
3. 选择值班人员 → 从可用用户列表中多选值班人员
4. 设置配置状态 → 启用或禁用该配置
5. 保存配置 → 系统验证配置有效性并保存
### 线索自动分配流程
1. APP端提交新线索 → 调用appAddSave接口
2. 系统获取当前时间 → 查询匹配的值班配置
3. 获取当前值班人员列表 → 按轮流规则选择下一个分配人员
4. 分配线索给选中人员 → 更新线索记录和分配日志
5. 返回分配结果 → 记录分配统计信息
```mermaid
graph TD
A[APP提交线索] --> B[获取当前时间]
B --> C[查询值班配置]
C --> D{是否有匹配配置?}
D -->|是| E[获取值班人员列表]
D -->|否| F[分配给默认用户]
E --> G[按轮流规则选择人员]
G --> H[分配线索]
H --> I[记录分配日志]
F --> I
I --> J[返回结果]
```
## 4. 用户界面设计
### 4.1 设计风格
- **主色调**#409EFF蓝色、#67C23A绿色
- **辅助色**#E6A23C橙色、#F56C6C红色
- **按钮样式**:圆角按钮,支持悬停效果
- **字体**微软雅黑主要字号14px标题16px
- **布局风格**:卡片式布局,顶部导航栏
- **图标风格**使用FontAwesome图标库简洁现代
### 4.2 页面设计概览
| 页面名称 | 模块名称 | UI元素 |
|----------|----------|---------|
| 值班配置管理页面 | 配置列表 | 表格布局,蓝色标题栏,白色背景,分页组件,搜索框使用圆角设计 |
| 值班配置管理页面 | 配置表单 | 模态框弹窗,表单使用栅格布局,时间选择器精确到分钟,多选下拉框 |
| 值班人员管理页面 | 人员选择 | 穿梭框组件,左侧可选人员,右侧已选人员,支持搜索和批量操作 |
| 线索分配统计页面 | 统计图表 | ECharts图表组件柱状图和饼图展示响应式设计 |
### 4.3 响应式设计
- 采用桌面优先设计支持1920x1080及以上分辨率
- 表格在小屏幕下支持横向滚动
- 表单在移动端自动调整为单列布局
- 支持触摸操作优化,按钮间距适配手指点击

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"java.compile.nullAnalysis.mode": "automatic"
}

20
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,20 @@
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'echo build'
}
}
stage('Test'){
steps {
sh 'echo test'
}
}
stage('Deploy') {
steps {
sh 'echo publish'
}
}
}
}

View File

@ -1,11 +1,11 @@
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-dd77653d7c9f197dd9d93684f3c8dcfbab6.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v4.7.8</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v4.7.7</h1>
<h4 align="center">基于SpringBoot开发的轻量级Java快速开发框架</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi/stargazers"><img src="https://gitee.com/y_project/RuoYi/badge/star.svg?theme=gvp"></a>
<a href="https://gitee.com/y_project/RuoYi"><img src="https://img.shields.io/badge/RuoYi-v4.7.8-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi"><img src="https://img.shields.io/badge/RuoYi-v4.7.7-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>
@ -99,4 +99,4 @@
## 若依交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/已满-339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc) [![加入QQ群](https://img.shields.io/badge/已满-130035985-blue.svg)](https://jq.qq.com/?_wv=1027&k=qPIKBb7s) [![加入QQ群](https://img.shields.io/badge/已满-143151071-blue.svg)](https://jq.qq.com/?_wv=1027&k=4NsjKbtU) [![加入QQ群](https://img.shields.io/badge/已满-158781320-blue.svg)](https://jq.qq.com/?_wv=1027&k=VD2pkz2G) [![加入QQ群](https://img.shields.io/badge/已满-201531282-blue.svg)](https://jq.qq.com/?_wv=1027&k=HlshFwkJ) [![加入QQ群](https://img.shields.io/badge/已满-101526938-blue.svg)](https://jq.qq.com/?_wv=1027&k=0ARRrO9V) [![加入QQ群](https://img.shields.io/badge/已满-264355400-blue.svg)](https://jq.qq.com/?_wv=1027&k=up9k3ZXJ) [![加入QQ群](https://img.shields.io/badge/已满-298522656-blue.svg)](https://jq.qq.com/?_wv=1027&k=540WfdEr) [![加入QQ群](https://img.shields.io/badge/已满-139845794-blue.svg)](https://jq.qq.com/?_wv=1027&k=ss91fC4t) [![加入QQ群](https://img.shields.io/badge/已满-185760789-blue.svg)](https://jq.qq.com/?_wv=1027&k=Cqd66IKe) [![加入QQ群](https://img.shields.io/badge/已满-175104288-blue.svg)](https://jq.qq.com/?_wv=1027&k=7FplYUnR) [![加入QQ群](https://img.shields.io/badge/174942938-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=lqMHu_5Fskm7H2S1vNAQTtzAUokVydwc&authKey=ptw0Fpch5pbNocML3CIJKKqZBaq2DI7cusKuzIgfMNiY3t9Pvd9hP%2BA8WYx3yaY1&noverify=0&group_code=174942938)
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/已满-339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc) [![加入QQ群](https://img.shields.io/badge/已满-130035985-blue.svg)](https://jq.qq.com/?_wv=1027&k=qPIKBb7s) [![加入QQ群](https://img.shields.io/badge/已满-143151071-blue.svg)](https://jq.qq.com/?_wv=1027&k=4NsjKbtU) [![加入QQ群](https://img.shields.io/badge/已满-158781320-blue.svg)](https://jq.qq.com/?_wv=1027&k=VD2pkz2G) [![加入QQ群](https://img.shields.io/badge/已满-201531282-blue.svg)](https://jq.qq.com/?_wv=1027&k=HlshFwkJ) [![加入QQ群](https://img.shields.io/badge/已满-101526938-blue.svg)](https://jq.qq.com/?_wv=1027&k=0ARRrO9V) [![加入QQ群](https://img.shields.io/badge/已满-264355400-blue.svg)](https://jq.qq.com/?_wv=1027&k=up9k3ZXJ) [![加入QQ群](https://img.shields.io/badge/已满-298522656-blue.svg)](https://jq.qq.com/?_wv=1027&k=540WfdEr) [![加入QQ群](https://img.shields.io/badge/已满-139845794-blue.svg)](https://jq.qq.com/?_wv=1027&k=ss91fC4t) [![加入QQ群](https://img.shields.io/badge/已满-185760789-blue.svg)](https://jq.qq.com/?_wv=1027&k=Cqd66IKe) [![加入QQ群](https://img.shields.io/badge/175104288-blue.svg)](https://jq.qq.com/?_wv=1027&k=7FplYUnR)

101
pom.xml
View File

@ -5,74 +5,39 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>4.7.8</version>
<version>4.7.7</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依管理系统</description>
<properties>
<ruoyi.version>4.7.8</ruoyi.version>
<ruoyi.version>4.7.7</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<shiro.version>1.13.0</shiro.version>
<shiro.version>1.10.1</shiro.version>
<thymeleaf.extras.shiro.version>2.1.0</thymeleaf.extras.shiro.version>
<druid.version>1.2.20</druid.version>
<druid.version>1.2.16</druid.version>
<bitwalker.version>1.21</bitwalker.version>
<kaptcha.version>2.3.3</kaptcha.version>
<swagger.version>3.0.0</swagger.version>
<pagehelper.boot.version>1.4.7</pagehelper.boot.version>
<mybatis-plus.boot.version>3.5.2</mybatis-plus.boot.version>
<lombok.version>1.18.24</lombok.version>
<pagehelper.boot.version>1.4.6</pagehelper.boot.version>
<fastjson.version>1.2.83</fastjson.version>
<oshi.version>6.4.8</oshi.version>
<commons.io.version>2.13.0</commons.io.version>
<oshi.version>6.4.1</oshi.version>
<commons.io.version>2.11.0</commons.io.version>
<poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version>
<lombok.version>1.18.12</lombok.version>
<minio.version>8.5.5</minio.version>
<qiniu.version>7.4.0</qiniu.version>
<hutool.version>5.8.22</hutool.version>
<knife4j.version>3.0.3</knife4j.version>
<ali-sdk.version>4.5.3</ali-sdk.version>
<ali-sms.version>2.0.1</ali-sms.version>
<ali-oss.version>3.10.2</ali-oss.version>
<adapay.version>1.2.10</adapay.version>
</properties>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.huifu.adapay.core/adapay-core-sdk -->
<dependency>
<groupId>com.huifu.adapay.core</groupId>
<artifactId>adapay-core-sdk</artifactId>
<version>${adapay.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.huifu.adapay/adapay-java-sdk -->
<dependency>
<groupId>com.huifu.adapay</groupId>
<artifactId>adapay-java-sdk</artifactId>
<version>${adapay.version}</version>
</dependency>
<!--阿里云核心API-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>${ali-sdk.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>${ali-sms.version}</version>
</dependency>
<!--阿里云oss存储API-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${ali-oss.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
@ -80,24 +45,41 @@
<version>${hutool.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
<exclusions>
<exclusion>
<artifactId>okhttp</artifactId>
<groupId>com.squareup.okhttp3</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>${qiniu.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- SpringBoot的依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.15</version>
<version>2.5.14</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -158,19 +140,6 @@
<version>${pagehelper.boot.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.boot.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.7.8</version>
<version>4.7.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
@ -16,31 +16,15 @@
</description>
<dependencies>
<dependency>
<groupId>com.huifu.adapay.core</groupId>
<artifactId>adapay-core-sdk</artifactId>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.huifu.adapay/adapay-java-sdk -->
<dependency>
<groupId>com.huifu.adapay</groupId>
<artifactId>adapay-java-sdk</artifactId>
</dependency>
<!--阿里云核心API-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
</dependency>
<!--阿里云oss存储API-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
<!-- SpringBoot集成thymeleaf模板 -->
@ -49,11 +33,6 @@
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
@ -98,6 +77,12 @@
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- WebSocket支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
<build>
@ -105,7 +90,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.15</version>
<version>2.1.1.RELEASE</version>
<configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration>

View File

@ -1,12 +1,8 @@
package com.ruoyi;
import com.aliyun.oss.OSSClient;
import com.ruoyi.web.core.config.OssConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;
/**
* 启动程序
@ -16,9 +12,6 @@ import org.springframework.context.annotation.Bean;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class RuoYiApplication
{
@Autowired
private OssConfig ossConfig;
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
@ -34,10 +27,4 @@ public class RuoYiApplication
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
@Bean
public OSSClient OssClient() {
return new OSSClient(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
}
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.web.config;
import com.ruoyi.customer.service.ICustomerServiceService;
import com.ruoyi.web.websocket.CustomerServiceWebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.context.annotation.Bean;
import javax.annotation.PostConstruct;
/**
* WebSocket配置类
* 用于注入服务到WebSocket端点
*
* @author ruoyi
* @date 2024-01-01
*/
@Configuration
public class WebSocketConfig {
@Autowired
private ICustomerServiceService customerServiceService;
/**
* 注入ServerEndpointExporter这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
/**
* 初始化时将服务注入到WebSocket中
*/
@PostConstruct
public void init() {
CustomerServiceWebSocket customerServiceWebSocket = new CustomerServiceWebSocket();
customerServiceWebSocket.setCustomerServiceService(customerServiceService);
}
}

View File

@ -1,70 +0,0 @@
package com.ruoyi.web.controller.app;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.web.request.LoginReq;
import com.ruoyi.web.response.LoginResp;
import com.ruoyi.web.service.LoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
/**
* <p>登陆相关接口</p>
* @author clunt
*/
@Api(tags = "App*登陆接口")
@RestController
@RequestMapping(value = "/app/login")
public class LoginController {
@Autowired
private LoginService loginService;
//密码登陆
@ResponseBody
@PostMapping(value = "/loginByPhone")
@ApiOperation(value = "手机验证码登陆", response = LoginReq.class)
public Result<LoginResp> loginByPhone(@RequestBody @NotNull LoginReq loginReq){
try {
return Result.success(loginService.loginByPhone(loginReq));
}catch (Exception e){
return Result.error(e.getMessage());
}
}
//密码登陆
@ResponseBody
@PostMapping(value = "/updatePasswordByPhone")
@ApiOperation(value = "验证码找回密码", response = LoginReq.class)
public Result<String> updatePasswordByPhone(@RequestBody @NotNull LoginReq loginReq){
try {
loginService.updatePasswordByPhone(loginReq);
return Result.success();
}catch (Exception e){
return Result.error(e.getMessage());
}
}
// 手机号验证码登陆
@ResponseBody
@PostMapping(value = "/loginByPassword")
@ApiOperation(value = "密码登陆", response = LoginReq.class)
public Result<LoginResp> loginByPassword(@RequestBody @NotNull LoginReq loginReq){
try {
return Result.success(loginService.loginByPassword(loginReq));
}catch (Exception e){
return Result.error(e.getMessage());
}
}
public static void main(String[] args) {
System.out.println(DigestUtils.md5Hex("123456"));
}
}

View File

@ -1,51 +0,0 @@
package com.ruoyi.web.controller.app;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.TbMatchSingleSay;
import com.ruoyi.system.service.ITbMatchSingleSayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>媒婆说</p>
* @author clunt
*/
@Slf4j
@Api(tags = "App*媒婆说")
@RestController
@RequestMapping(value = "/app/say")
public class TbMatchSingleAppController {
@Autowired
private ITbMatchSingleSayService tbMatchSingleSayService;
@ResponseBody
@PostMapping("/edit")
@ApiOperation(value = "更新媒婆说", httpMethod = "POST")
public Result<String> edit(@RequestBody TbMatchSingleSay tbMatchSingleSay)
{
int effectiveRows = tbMatchSingleSayService.updateTbMatchSingleSay(tbMatchSingleSay);
if(effectiveRows > 0){
return Result.success("更新媒婆说成功!");
}else {
return Result.error("更新媒婆说失败!");
}
}
@ResponseBody
@PostMapping("/add")
@ApiOperation(value = "创建媒婆说", httpMethod = "POST")
public Result<String> addSave(@RequestBody TbMatchSingleSay tbMatchSingleSay)
{
int effectiveRows = tbMatchSingleSayService.insertTbMatchSingleSay(tbMatchSingleSay);
if(effectiveRows > 0){
return Result.success("创建媒婆说成功!");
}else {
return Result.error("创建媒婆说失败!");
}
}
}

View File

@ -1,141 +0,0 @@
package com.ruoyi.web.controller.app;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.TbUser;
import com.ruoyi.system.domain.TbUserImg;
import com.ruoyi.system.domain.TbUserSingle;
import com.ruoyi.system.service.ITbUserImgService;
import com.ruoyi.system.service.ITbUserService;
import com.ruoyi.system.service.ITbUserSingleService;
import com.ruoyi.web.service.HxService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@Slf4j
@Api(tags = "App*用户信息")
@RestController
@RequestMapping(value = "/app/user")
@CrossOrigin(origins = "*")
public class TbUserAppController {
@Autowired
private ITbUserService tbUserService;
@Autowired
private ITbUserSingleService tbUserSingleService;
@Autowired
private ITbUserImgService tbUserImgService;
@Autowired
private HxService hxService;
private final static String SZ_URL_PREFIX = "https://www.7799520.com/api/recommend/pc/luck/list?token=&page=";
@ResponseBody
@PostMapping("/draw")
@ApiOperation(value = "爬取数据", httpMethod = "POST")
@Transactional(rollbackFor = Exception.class)
public Result<String> drawData()
{
for (int i = 101; i< 150; i++){
try {
Thread.sleep(3000L);
log.info("请求的url路径:{}", SZ_URL_PREFIX + i);
String result = HttpUtil.get(SZ_URL_PREFIX + i);
JSONObject resultJson = JSONObject.parseObject(result);
JSONArray resultArray = resultJson.getJSONObject("data").getJSONArray("list");
for (int index =0; index < resultArray.size(); index++){
JSONObject json = resultArray.getJSONObject(index);
TbUser tbUser = new TbUser();
tbUser.setId(json.getLong("userid"));
tbUser.setMobile("13888888888");
tbUser.setPassword("123456");
tbUserService.save(tbUser);
TbUserSingle userSingle = new TbUserSingle();
userSingle.setUserId(tbUser.getId());
userSingle.setStatus(1);
userSingle.setBirthday(DateUtil.parse(json.getString("birthdayyear"),"yyyy"));
userSingle.setSex(json.getLong("gender"));
userSingle.setCreateTime(new Date());
userSingle.setNickName(json.getString("username"));
tbUserSingleService.save(userSingle);
TbUserImg tbUserImg = new TbUserImg();
tbUserImg.setUserId(tbUser.getId());
tbUserImg.setType(0L);
tbUserImg.setImgUrl(json.getString("avatar"));
tbUserImgService.save(tbUserImg);
log.info("用户:{}", tbUser);
log.info("单身信息:{}", userSingle);
log.info("图片:{}", tbUserImg);
}
}catch (Exception e){
log.error("单次请求失败,失败url是:{}", SZ_URL_PREFIX + i);
}
}
return Result.success();
}
@ResponseBody
@PostMapping("/add")
@ApiOperation(value = "注册用户", httpMethod = "POST")
@Transactional(rollbackFor = Exception.class)
public Result<TbUser> addSave(@RequestBody TbUser tbUser)
{
TbUser registerUser = tbUserService.lambdaQuery().eq(TbUser::getMobile, tbUser.getMobile()).one();
if(registerUser != null ){
return Result.error("用户已注册,请直接登陆!");
}
tbUser.setPassword(DigestUtils.md5Hex(tbUser.getPassword()));
int effectiveRows = tbUserService.insertTbUser(tbUser);
if(effectiveRows > 0){
// 注册环信
hxService.register(tbUser);
return Result.success(tbUser);
}else {
return Result.error("注册用户失败!");
}
}
@PostMapping("/register")
@ApiOperation(value = "邀请用户", httpMethod = "POST")
@Transactional(rollbackFor = Exception.class)
public Result<TbUser> register(@RequestBody TbUser tbUser)
{
TbUser registerUser = tbUserService.lambdaQuery().eq(TbUser::getMobile, tbUser.getMobile()).one();
if(registerUser != null ){
return Result.error("用户已注册,请直接登陆!");
}
if(StringUtils.isEmpty(tbUser.getPassword())){
tbUser.setPassword("123456");
}
tbUser.setPassword(DigestUtils.md5Hex(tbUser.getPassword()));
int effectiveRows = tbUserService.insertTbUser(tbUser);
if(effectiveRows > 0){
// 注册环信
hxService.register(tbUser);
return Result.success(tbUser);
}else {
return Result.error("邀请用户失败!");
}
}
}

View File

@ -1,28 +0,0 @@
package com.ruoyi.web.controller.app;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.TbUserBlock;
import com.ruoyi.system.service.ITbUserBlockService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Api(tags = "App*不喜欢列表")
@RestController
@RequestMapping(value = "/app/block")
public class TbUserBlockAppController {
@Autowired
private ITbUserBlockService tbUserBlockService;
@PostMapping("/add")
@ResponseBody
@ApiOperation(value = "新增不喜欢", httpMethod = "POST")
public Result<String> addSave(@RequestBody TbUserBlock tbUserBlock)
{
tbUserBlockService.insertTbUserBlock(tbUserBlock);
return Result.success();
}
}

View File

@ -1,81 +0,0 @@
package com.ruoyi.web.controller.app;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.TbUserFollow;
import com.ruoyi.system.service.ITbUserFollowService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>用户关注</p>
* @author clunt
*/
@Api(tags = "App*关注列表")
@RestController
@RequestMapping(value = "/app/follow")
public class TbUserFollowAppController {
@Autowired
private ITbUserFollowService tbUserFollowService;
@ResponseBody
@PostMapping("/add")
@ApiOperation(value = "关注用户", httpMethod = "POST")
public Result<String> addSave(@RequestBody TbUserFollow tbUserFollow)
{
// 判断用户是否也关注自己
TbUserFollow followUser = tbUserFollowService.lambdaQuery()
.eq(TbUserFollow::getFollowUserId, tbUserFollow.getUserId())
.eq(TbUserFollow::getUserId, tbUserFollow.getFollowUserId())
.one();
if(followUser != null){
followUser.setFollowTogether(1L);
tbUserFollowService.updateById(followUser);
tbUserFollow.setFollowTogether(1L);
}
// 更新目标用户为已关注自己
int effectiveRows = tbUserFollowService.insertTbUserFollow(tbUserFollow);
if(effectiveRows > 0){
return Result.success("关注成功");
}else {
return Result.error("关注失败!");
}
}
@ResponseBody
@PostMapping("/getFollowByUserId")
@ApiOperation(value = "查询我关注的用户", httpMethod = "POST")
public Result<List<TbUserFollow>> getFollowByUserId(@RequestBody TbUserFollow tbUserFollow)
{
return Result.success(tbUserFollowService.selectTbUserFollowList(tbUserFollow));
}
@ResponseBody
@PostMapping("/getFollowByFollowUserId")
@ApiOperation(value = "查询关注我的用户", httpMethod = "POST")
public Result<List<TbUserFollow>> getFollowByFollowUserId(@RequestBody TbUserFollow tbUserFollow)
{
return Result.success(tbUserFollowService.selectTbUserFollowList(tbUserFollow));
}
@ResponseBody
@PostMapping("/getTogetherFollowByUserId")
@ApiOperation(value = "查询互相关注的用户", httpMethod = "POST")
public Result<List<TbUserFollow>> getTogetherFollowByUserId(@RequestBody TbUserFollow tbUserFollow)
{
tbUserFollow.setFollowTogether(1L);
return Result.success(tbUserFollowService.selectTbUserFollowList(tbUserFollow));
}
}

View File

@ -1,77 +0,0 @@
package com.ruoyi.web.controller.app;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.TbUserImg;
import com.ruoyi.system.service.ITbUserImgService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "App*单身用户图片附件")
@RestController
@RequestMapping(value = "/app/img")
public class TbUserImgAppController {
@Autowired
private ITbUserImgService tbUserImgService;
@ResponseBody
@PostMapping("/getByUserId")
@ApiOperation(value = "通过userId获取用户所有图片附件", httpMethod = "POST")
public Result<List<TbUserImg>> getByUserId(@RequestBody TbUserImg tbUserImg)
{
return Result.success(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, tbUserImg.getUserId()).list());
}
@ResponseBody
@PostMapping("/add")
@ApiOperation(value = "上传用户附件", httpMethod = "POST")
public Result<String> addSave(@RequestBody TbUserImg tbUserImg)
{
int effectiveRows = tbUserImgService.insertTbUserImg(tbUserImg);
if(effectiveRows > 0){
return Result.success("上传用户附件成功");
}
return Result.error("上传用户附件失败");
}
@ResponseBody
@PostMapping("/addBatch")
@ApiOperation(value = "批量保存用户附件", httpMethod = "POST")
public Result<String> addBatch(@RequestBody List<TbUserImg> tbUserImg)
{
if(tbUserImgService.saveBatch(tbUserImg)){
return Result.success("上传用户附件成功");
}
return Result.error("上传用户附件失败");
}
@ResponseBody
@PostMapping("/edit")
@ApiOperation(value = "更新用户附件", httpMethod = "POST")
public Result<String> editSave(@RequestBody TbUserImg tbUserImg)
{
int effectiveRows = tbUserImgService.updateTbUserImg(tbUserImg);
if(effectiveRows > 0){
return Result.success("修改用户附件成功");
}
return Result.error("修改用户附件失败");
}
@ResponseBody
@PostMapping("/remove")
@ApiOperation(value = "删除用户附件", httpMethod = "POST")
public Result<String> delete(@RequestBody TbUserImg tbUserImg)
{
int effectiveRows = tbUserImgService.deleteTbUserImgById(tbUserImg.getId());
if(effectiveRows > 0){
return Result.success("删除用户附件成功");
}
return Result.error("删除用户附件失败");
}
}

View File

@ -1,163 +0,0 @@
package com.ruoyi.web.controller.app;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import com.ruoyi.web.request.MatchRegisterReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>登陆相关接口</p>
* @author clunt
*/
@Api(tags = "App*合伙人接口")
@RestController
@RequestMapping(value = "/app/match")
public class TbUserMatchAppController {
@Autowired
private ITbUserService tbUserService;
@Autowired
private ITbUserMatchService tbUserMatchService;
@Autowired
private ITbUserImgService tbUserImgService;
@Autowired
private ITbMatchSingleSayService tbMatchSingleSayService;
@ResponseBody
@PostMapping("/registerSingleList")
@ApiOperation(value = "我的单身团", httpMethod = "POST")
@ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "当前页码", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示的条数", required = true, dataType = "int") })
public Result<PageInfo<TbUserSingle>> registerSingleList(@RequestBody MatchRegisterReq registerReq,
@RequestParam("pageNum") int pageNum,
@RequestParam("pageSize") int pageSize)
{
List<Long> ids = new ArrayList<>();
List<TbUser> tbUsers = tbUserService.lambdaQuery().eq(TbUser::getRegisterUserId, registerReq.getMatchUserId()).list();
if(CollectionUtil.isNotEmpty(tbUsers)){
ids = tbUsers.stream().map(TbUser::getId).collect(Collectors.toList());
}
if(CollectionUtil.isEmpty(ids)){
return Result.success(PageInfo.of(new ArrayList<>()));
}
PageHelper.startPage(pageNum, pageSize);
List<TbUserSingle> list = tbUserSingleService.lambdaQuery()
.eq(registerReq.getSex() != null, TbUserSingle::getSex, registerReq.getSex())
.in(TbUserSingle::getUserId, ids)
.list();
list.forEach(model->{
if(model.getBirthday() != null){
model.setAge(DateUtil.ageOfNow(model.getBirthday()));
}
model.setMatchSay(tbMatchSingleSayService.lambdaQuery().eq(TbMatchSingleSay::getSingleId, model.getId()).one());
model.setTbUserImgList(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, model.getUserId()).list());
});
return Result.success(PageInfo.of(list));
}
@Autowired
private ITbUserSingleService tbUserSingleService;
@ResponseBody
@PostMapping("/registerMatchList")
@ApiOperation(value = "我的代理团", httpMethod = "POST")
@ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "当前页码", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示的条数", required = true, dataType = "int") })
public Result<PageInfo<TbUserMatch>> registerMatchList(@RequestBody MatchRegisterReq registerReq,
@RequestParam("pageNum") int pageNum,
@RequestParam("pageSize") int pageSize)
{
List<Long> ids = new ArrayList<>();
List<TbUser> tbUsers = tbUserService.lambdaQuery().eq(TbUser::getRegisterUserId, registerReq.getMatchUserId()).list();
if(CollectionUtil.isNotEmpty(tbUsers)){
ids = tbUsers.stream().map(TbUser::getId).collect(Collectors.toList());
}
if(CollectionUtil.isEmpty(ids)){
return Result.success(PageInfo.of(new ArrayList<>()));
}
PageHelper.startPage(pageNum, pageSize);
List<TbUserMatch> list = tbUserMatchService.lambdaQuery()
.in(TbUserMatch::getUserId, ids)
.list();
list.forEach(model->{
model.setTbUserImgList(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, model.getUserId()).list());
});
return Result.success(PageInfo.of(list));
}
@ResponseBody
@PostMapping("/add")
@ApiOperation(value = "填写合伙人信息", httpMethod = "POST")
public Result<String> addSave(@RequestBody TbUserMatch tbUserMatch)
{
int effectiveRows = tbUserMatchService.insertTbUserMatch(tbUserMatch);
if(effectiveRows > 0){
return Result.success("填写合伙人信息成功!");
}else {
return Result.error("填写合伙人信息失败!");
}
}
@ResponseBody
@PostMapping("/edit")
@ApiOperation(value = "更新合伙人信息", httpMethod = "POST")
public Result<String> editSave(@RequestBody TbUserMatch tbUserMatch)
{
int effectiveRows = tbUserMatchService.updateTbUserMatch(tbUserMatch);
if(effectiveRows > 0){
return Result.success("更新合伙人信息成功!");
}else {
return Result.error("更新合伙人信息失败!");
}
}
@ResponseBody
@PostMapping("/recommend")
@ApiOperation(value = "获取合伙人推荐用户.第一版不排除自己", httpMethod = "POST")
@ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "当前页码", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示的条数", required = true, dataType = "int") })
public Result<PageInfo<TbUserSingle>> recommend(@RequestBody TbUserSingle tbUserSingle,
@RequestParam("pageNum") int pageNum,
@RequestParam("pageSize") int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<TbUserSingle> list = tbUserSingleService.selectTbUserSingleList(tbUserSingle);
list.forEach(model->{
if(model.getBirthday() != null){
model.setAge(DateUtil.ageOfNow(model.getBirthday()));
}
model.setTbUserImgList(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, model.getUserId()).list());
});
return Result.success(PageInfo.of(list));
}
@ResponseBody
@PostMapping("/getByUserId")
@ApiOperation(value = "通过userId获取合伙人信息", httpMethod = "POST")
public Result<TbUserMatch> getByUserId(@RequestBody TbUserMatch tbUserMatch)
{
TbUserMatch userMatch = tbUserMatchService.lambdaQuery().eq(TbUserMatch::getUserId, tbUserMatch.getUserId()).one();
if(userMatch != null){
userMatch.setTbUserImgList(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, tbUserMatch.getUserId()).list());
}
return Result.success(userMatch);
}
}

View File

@ -1,71 +0,0 @@
package com.ruoyi.web.controller.app;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.TbUserMatchGroup;
import com.ruoyi.system.service.ITbUserMatchGroupService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>合伙人创建活动团</p>
* @author clunt
*/
@Slf4j
@Api(tags = "App*合伙人创建活动团")
@RestController
@RequestMapping(value = "/app/matchGroup")
public class TbUserMatchGroupAppController {
@Autowired
private ITbUserMatchGroupService tbUserMatchGroupService;
@ResponseBody
@PostMapping("/getByMatchId")
@ApiOperation(value = "获取我的活动团", httpMethod = "POST")
@ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "当前页码", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示的条数", required = true, dataType = "int") })
public Result<PageInfo<TbUserMatchGroup>> getByMatchId(@RequestBody TbUserMatchGroup tbUserMatchGroup,
@RequestParam("pageNum") int pageNum,
@RequestParam("pageSize") int pageSize)
{
PageHelper.startPage(pageNum, pageSize);
List<TbUserMatchGroup> list = tbUserMatchGroupService.selectTbUserMatchGroupList(tbUserMatchGroup);
return Result.success(PageInfo.of(list));
}
@ResponseBody
@PostMapping("/edit")
@ApiOperation(value = "更新活动团", httpMethod = "POST")
public Result<String> edit(@RequestBody TbUserMatchGroup tbUserMatchGroup)
{
int effectiveRows = tbUserMatchGroupService.updateTbUserMatchGroup(tbUserMatchGroup);
if(effectiveRows > 0){
return Result.success("更新活动团成功!");
}else {
return Result.error("更新活动团成功失败!");
}
}
@ResponseBody
@PostMapping("/add")
@ApiOperation(value = "创建活动团", httpMethod = "POST")
public Result<String> addSave(@RequestBody TbUserMatchGroup tbUserMatchGroup)
{
int effectiveRows = tbUserMatchGroupService.insertTbUserMatchGroup(tbUserMatchGroup);
if(effectiveRows > 0){
return Result.success("创建活动团成功!");
}else {
return Result.error("创建活动团成功失败!");
}
}
}

View File

@ -1,108 +0,0 @@
package com.ruoyi.web.controller.app;
import com.huifu.adapay.core.AdapayCore;
import com.huifu.adapay.core.util.AdapaySign;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.TbUserMatchOrder;
import com.ruoyi.web.request.AdapayReq;
import com.ruoyi.web.request.Event;
import com.ruoyi.web.response.AdapayResp;
import com.ruoyi.web.service.AdapayService;
import com.ruoyi.web.service.CallBackService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
/**
* <p>开通合伙人相关接口</p>
* @author clunt
*/
@Slf4j
@Api(tags = "App*开通合伙人相关接口")
@RestController
@RequestMapping(value = "/app/matchOrder")
public class TbUserMatchOrderAppController {
@Autowired
private AdapayService adapayService;
@Autowired
private CallBackService callBackService;
@ResponseBody
@PostMapping(value = "/checkPayResult")
@ApiOperation(value = "查询用户开通结果,无返回则证明没有开通记录", response = TbUserMatchOrder.class)
public Result<TbUserMatchOrder> checkPayResult(@RequestBody @NotNull AdapayReq adapayReq){
try {
return Result.success(adapayService.checkPayResult(adapayReq));
}catch (Exception e){
return Result.error(e.getMessage());
}
}
@ResponseBody
@PostMapping(value = "/pay")
@ApiOperation(value = "支付接口", response = AdapayResp.class)
public Result<AdapayResp> loginByPhone(@RequestBody @NotNull AdapayReq adapayReq){
try {
return Result.success(adapayService.pay(adapayReq));
}catch (Exception e){
return Result.error(e.getMessage());
}
}
@PostMapping("/callback")
public String callback(Event event) {
log.info(" 收单返回消息event" + event);
//验签请参data
String data = event.getData();
log.info(" 收单返回消息data" + data);
//验签请参sign
String sign = event.getSign();
boolean verifySign = false;
try {
verifySign = verifySign(data, sign);
} catch (Exception e) {
log.error("签名验证失败 {}", e.getMessage());
}
if (verifySign) {
//Event事件类型
String type = event.getType();
if("payment.succeeded".equals(type) || "payment.failed".equals(type)){
callBackService.onCallback(event);
}else{
return "NG";
}
return "OK";
}
log.warn("签名验证失败 data=[{}], sign=[{}]", data, sign);
return "NG";
}
/**
* 校验签名
*
* @param data AdapayCallback.data
* @param sign AdapayCallback.sign
* @return TRUE=校验成功
*/
private boolean verifySign(String data, String sign) throws Exception {
Assert.hasText(data, "data is blank!");
Assert.hasText(sign, "sign is blank!");
//验签请参publicKey
String publicKey = AdapayCore.PUBLIC_KEY;
log.debug("验签请参data={}sign={}", data, sign);
//验签
return AdapaySign.verifySign(data, sign, publicKey);
}
}

View File

@ -1,173 +0,0 @@
package com.ruoyi.web.controller.app;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import com.ruoyi.web.request.UserSingleRecommendReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>登陆相关接口</p>
* @author clunt
*/
@Api(tags = "App*单身信息")
@RestController
@RequestMapping(value = "/app/single")
public class TbUserSingleAppController {
@Autowired
private ITbUserSingleService tbUserSingleService;
@Autowired
private ITbUserImgService tbUserImgService;
@Autowired
private ITbUserFollowService tbUserFollowService;
@Autowired
private ITbMatchSingleSayService tbMatchSingleSayService;
@Autowired
private ITbUserBlockService tbUserBlockService;
@ResponseBody
@PostMapping("/add")
@ApiOperation(value = "填写用户信息", httpMethod = "POST")
public Result<String> addSave(@RequestBody TbUserSingle tbUserSingle)
{
int effectiveRows = tbUserSingleService.insertTbUserSingle(tbUserSingle);
if(effectiveRows > 0){
return Result.success("填写用户信息成功!");
}else {
return Result.error("填写用户信息失败!");
}
}
@ResponseBody
@PostMapping("/getByUserId")
@ApiOperation(value = "通过userId获取用户信息", httpMethod = "POST")
public Result<TbUserSingle> getByUserId(@RequestBody TbUserSingle tbUserSingle)
{
TbUserSingle userSingle = tbUserSingleService.lambdaQuery().eq(TbUserSingle::getUserId, tbUserSingle.getUserId()).one();
if(userSingle != null){
if(userSingle.getBirthday() != null){
userSingle.setAge(DateUtil.ageOfNow(userSingle.getBirthday()));
}
userSingle.setTbUserImgList(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, userSingle.getUserId()).list());
}
return Result.success(userSingle);
}
@ResponseBody
@PostMapping("/edit")
@ApiOperation(value = "更新用户信息", httpMethod = "POST")
public Result<String> editSave(@RequestBody TbUserSingle tbUserSingle)
{
int effectiveRows = tbUserSingleService.updateTbUserSingle(tbUserSingle);
if(effectiveRows > 0){
return Result.success("更新用户信息成功!");
}else {
return Result.error("更新用户信息失败!");
}
}
@ResponseBody
@PostMapping("/recommend")
@ApiOperation(value = "获取推荐用户.第一版不排除自己", httpMethod = "POST")
@ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "当前页码", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示的条数", required = true, dataType = "int") })
public Result<PageInfo<TbUserSingle>> recommend(@RequestBody TbUserSingle tbUserSingle,
@RequestParam("pageNum") int pageNum,
@RequestParam("pageSize") int pageSize) {
PageHelper.startPage(pageNum, pageSize);
// 18
if(tbUserSingle.getAgeStart() != null){
Calendar calendar = DateUtil.calendar(new Date());
calendar.add(Calendar.YEAR, -1 * tbUserSingle.getAgeStart());
// 2006
tbUserSingle.setBirthdayEnd(calendar.getTime());
}
// 30
if(tbUserSingle.getAgeEnd() != null){
Calendar calendar = DateUtil.calendar(new Date());
calendar.add(Calendar.YEAR, -1 * tbUserSingle.getAgeEnd());
// 1994
tbUserSingle.setBirthdayStart(calendar.getTime());
}
List<TbUserSingle> list = tbUserSingleService.selectTbUserSingleList(tbUserSingle);
list.forEach(model->{
if(model.getBirthday() != null){
model.setAge(DateUtil.ageOfNow(model.getBirthday()));
}
model.setMatchSay(tbMatchSingleSayService.lambdaQuery().eq(TbMatchSingleSay::getSingleId, model.getId()).one());
model.setTbUserImgList(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, model.getUserId()).list());
});
return Result.success(PageInfo.of(list));
}
@ResponseBody
@PostMapping("/recommendForSingle")
@ApiOperation(value = "单身获取推荐用户", httpMethod = "POST")
@ApiImplicitParams({ @ApiImplicitParam(name = "pageNum", value = "当前页码", required = true, dataType = "int"),
@ApiImplicitParam(name = "pageSize", value = "每页显示的条数", required = true, dataType = "int") })
public Result<PageInfo<TbUserSingle>> recommendForSingle(@RequestBody UserSingleRecommendReq recommendReq,
@RequestParam("pageNum") int pageNum,
@RequestParam("pageSize") int pageSize) {
Long notExcludeSex = null;
// 获取当前登陆人信息
TbUserSingle userSingle = tbUserSingleService.lambdaQuery().eq(TbUserSingle::getUserId, recommendReq.getUserId()).one();
if(userSingle != null){
notExcludeSex = userSingle.getSex();
}else {
notExcludeSex = recommendReq.getSex();
}
// 查询当前人的不喜欢列表
List<TbUserBlock> tbUserBlocks = tbUserBlockService.lambdaQuery()
.eq(TbUserBlock::getTbUserId, userSingle.getUserId()).list();
List<Long> blockIds = tbUserBlocks.stream().map(TbUserBlock::getBlockUserId).collect(Collectors.toList());
int randomPageNum = 1 + (int) (18 * Math.random());
PageHelper.startPage(randomPageNum, pageSize);
List<TbUserSingle> list = tbUserSingleService.lambdaQuery()
.ne(ObjectUtil.isNotEmpty(notExcludeSex), TbUserSingle::getSex, notExcludeSex)
.notIn(CollectionUtil.isNotEmpty(blockIds), TbUserSingle::getUserId, blockIds)
.orderByDesc(TbUserSingle::getStatus)
.list();
list.forEach(model->{
//填充年纪
if(model.getBirthday() != null){
model.setAge(DateUtil.ageOfNow(model.getBirthday()));
}
// 填充用户图片
model.setTbUserImgList(tbUserImgService.lambdaQuery().eq(TbUserImg::getUserId, model.getUserId()).list());
// 填充是否已经关注
if(ObjectUtil.isNotEmpty(userSingle)){
long count = tbUserFollowService.lambdaQuery().eq(TbUserFollow::getFollowUserId, model.getUserId())
.eq(TbUserFollow::getUserId, userSingle.getUserId()).count();
if(count > 0){
model.setIsLike(true);
}
}
});
return Result.success(PageInfo.of(list));
}
}

View File

@ -0,0 +1,514 @@
package com.ruoyi.web.controller.customer;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.UserSessions;
import com.ruoyi.system.domain.ManualServiceSessions;
import com.ruoyi.customer.service.ICustomerServiceService;
import com.ruoyi.system.domain.ChatHistory;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.web.controller.customer.dto.TransferToManualRequest;
import com.ruoyi.web.websocket.CustomerServiceWebSocket;
/**
* 客服系统Controller
*
* @author ruoyi
* @date 2024-01-01
*/
@Controller
@RequestMapping("/customer/service")
public class CustomerServiceController extends BaseController
{
private String prefix = "customer/service";
@Autowired
private ICustomerServiceService customerServiceService;
@RequiresPermissions("customer:service:view")
@GetMapping()
public String service()
{
return prefix + "/index";
}
/**
* 查询会话列表
*/
@RequiresPermissions("customer:service:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(UserSessions userSessions)
{
startPage();
List<UserSessions> list = customerServiceService.selectUserSessionsList(userSessions);
return getDataTable(list);
}
/**
* 获取所有活跃会话
*/
@GetMapping("/sessions")
@ResponseBody
public AjaxResult getSessions()
{
try {
List<UserSessions> sessions = customerServiceService.getActiveSessions();
return AjaxResult.success(sessions);
} catch (Exception e) {
logger.error("获取会话列表失败", e);
return AjaxResult.error("获取会话列表失败");
}
}
/**
* 获取指定会话信息
*/
@GetMapping("/sessions/{sessionId}")
@ResponseBody
public AjaxResult getSession(@PathVariable String sessionId)
{
try {
UserSessions session = customerServiceService.selectUserSessionsById(sessionId);
return AjaxResult.success(session);
} catch (Exception e) {
logger.error("获取会话信息失败", e);
return AjaxResult.error("获取会话信息失败");
}
}
/**
* 获取会话聊天记录
*/
@GetMapping("/messages/{sessionId}")
@ResponseBody
public AjaxResult getChatHistory(@PathVariable String sessionId)
{
try {
List<ChatHistory> messages = customerServiceService.getChatHistoryBySessionId(sessionId);
return AjaxResult.success(messages);
} catch (Exception e) {
logger.error("获取聊天记录失败", e);
return AjaxResult.error("获取聊天记录失败");
}
}
/**
* 发送消息
*/
@PostMapping("/send")
@ResponseBody
public AjaxResult sendMessage(@RequestParam String sessionId, @RequestParam String content, @RequestParam String senderType) {
try {
// 根据sessionId查找对应的用户ID
UserSessions userSession = customerServiceService.selectUserSessionsById(sessionId);
if (userSession == null) {
return AjaxResult.error("会话不存在");
}
// 创建聊天记录
ChatHistory chatHistory = new ChatHistory();
chatHistory.setSessionId(sessionId);
chatHistory.setContent(content);
chatHistory.setUserId(userSession.getUserId().toString()); // 设置为客户的userId
chatHistory.setSenderId(getUserId()); // 发送者ID为当前登录的客服ID
chatHistory.setSenderType("SERVICE"); // 发送者类型为客服
chatHistory.setMessageType("service"); // 消息类型为客服消息
chatHistory.setCreateTime(new java.util.Date());
// 保存聊天记录
customerServiceService.insertChatHistory(chatHistory);
// 通过WebSocket发送消息给客户端
// 创建JSON格式的WebSocket消息
com.alibaba.fastjson.JSONObject wsMessage = new com.alibaba.fastjson.JSONObject();
wsMessage.put("type", "message");
wsMessage.put("content", content);
// 发送JSON格式的WebSocket消息给客户端
CustomerServiceWebSocket.sendInfo(wsMessage.toJSONString(), userSession.getUserId().toString());
logger.info("[发送消息] WebSocket消息已发送 - userId: {}, sessionId: {}, content: {}, messageFormat: JSON",
userSession.getUserId(), sessionId, content);
return AjaxResult.success();
} catch (Exception e) {
logger.error("发送消息失败", e);
return AjaxResult.error("发送消息失败: " + e.getMessage());
}
}
/**
* 转人工服务
*/
@PostMapping("/transfer")
@ResponseBody
public AjaxResult transferToManual(@RequestBody TransferToManualRequest request, HttpServletRequest httpRequest)
{
logger.info("[转人工服务] 收到转人工请求 - 原始请求: {}", request);
logger.info("[转人工服务] 请求头信息 - Authorization: {}, Content-Type: {}",
httpRequest.getHeader("Authorization"), httpRequest.getHeader("Content-Type"));
// 解析参数
Long userId = request.getUserIdAsLong();
String reason = request.getReasonAsString();
logger.info("[转人工服务] 解析后参数 - userId: {}, reason: {}", userId, reason);
logger.info("[转人工服务] 请求参数验证 - userId是否为空: {}, reason是否为空: {}",
userId == null, reason == null || reason.trim().isEmpty());
// 参数验证
if (userId == null) {
logger.error("[转人工服务] 参数验证失败 - userId为空或格式错误原始值: {}", request.getUserId());
return AjaxResult.error("用户ID不能为空或格式错误");
}
if (reason == null || reason.trim().isEmpty()) {
logger.error("[转人工服务] 参数验证失败 - reason为空");
return AjaxResult.error("转人工原因不能为空");
}
try {
// 生成或查找SessionId
String sessionId = generateOrFindSessionId(userId);
logger.info("[转人工服务] SessionId生成结果 - userId: {}, sessionId: {}", userId, sessionId);
// 防重复提交检查是否已有待处理的转人工记录
List<ManualServiceSessions> existingRequests = customerServiceService.getPendingManualRequestsByUserId(userId);
if (existingRequests != null && !existingRequests.isEmpty()) {
logger.warn("[转人工服务] 该用户已有待处理的转人工记录 - userId: {}, 数量: {}", userId, existingRequests.size());
return AjaxResult.error("您已提交转人工请求,请等待客服处理");
}
ManualServiceSessions manualSession = new ManualServiceSessions();
manualSession.setUserId(userId);
// 设置会话ID为字符串类型的UUID
manualSession.setSessionId(sessionId);
manualSession.setReason(reason.trim());
manualSession.setStatus("0"); // 0-待处理
manualSession.setRequestTime(new java.util.Date());
manualSession.setCreateBy(userId.toString());
logger.info("[转人工服务] 准备插入数据库 - 转人工会话对象: userId={}, sessionId={}, reason={}, status={}",
manualSession.getUserId(), manualSession.getSessionId(),
manualSession.getReason(), manualSession.getStatus());
int result = customerServiceService.createManualServiceRequest(manualSession);
logger.info("[转人工服务] 数据库插入结果: {}", result);
if (result > 0) {
logger.info("[转人工服务] 转人工请求提交成功 - userId: {}, sessionId: {}", userId, sessionId);
// 返回sessionId给前端
Map<String, Object> responseData = new HashMap<>();
responseData.put("sessionId", sessionId);
responseData.put("message", "转人工请求已提交,请等待客服接听");
return AjaxResult.success(responseData);
} else {
logger.error("[转人工服务] 转人工请求提交失败 - 数据库插入返回0");
return AjaxResult.error("转人工请求提交失败");
}
} catch (Exception e) {
logger.error("[转人工服务] 转人工服务异常 - userId: {}, reason: {}", userId, reason, e);
return AjaxResult.error("转人工服务失败: " + e.getMessage());
}
}
/**
* 生成或查找SessionId
* 方案1在转人工接口中按需生成SessionId
*/
private String generateOrFindSessionId(Long userId) {
try {
// 1. 先查找用户是否有活跃的会话
String existingSessionId = customerServiceService.findActiveSessionByUserId(userId);
if (existingSessionId != null && !existingSessionId.trim().isEmpty()) {
logger.info("[SessionId生成] 找到用户活跃会话 - userId: {}, sessionId: {}", userId, existingSessionId);
return existingSessionId;
}
// 2. 如果没有活跃会话生成新的SessionId
String newSessionId = java.util.UUID.randomUUID().toString().replace("-", "");
logger.info("[SessionId生成] 生成新的SessionId - userId: {}, newSessionId: {}", userId, newSessionId);
// 3. 可选将新的SessionId保存到用户会话表中
// customerServiceService.createUserSession(userId, newSessionId);
return newSessionId;
} catch (Exception e) {
logger.error("[SessionId生成] 生成SessionId异常 - userId: {}", userId, e);
// 异常情况下返回基于userId的默认SessionId
return "session_" + userId + "_" + System.currentTimeMillis();
}
}
/**
* 获取转人工请求列表
*/
@GetMapping("/manual-requests")
@ResponseBody
public AjaxResult getManualRequests()
{
try {
List<ManualServiceSessions> requests = customerServiceService.getPendingManualRequests();
return AjaxResult.success(requests);
} catch (Exception e) {
logger.error("获取转人工请求失败", e);
return AjaxResult.error("获取转人工请求失败");
}
}
/**
* 获取单个转人工请求详情
*/
@GetMapping("/manual-requests/{requestId}")
@ResponseBody
public AjaxResult getManualRequestById(@PathVariable Long requestId)
{
try {
logger.info("[获取转人工请求详情] 开始处理请求 - requestId: {}", requestId);
ManualServiceSessions request = customerServiceService.getManualRequestById(requestId);
if (request == null) {
logger.error("[获取转人工请求详情] 未找到转人工记录 - requestId: {}", requestId);
return AjaxResult.error("未找到转人工记录");
}
logger.info("[获取转人工请求详情] 成功获取记录 - userId: {}, sessionId: {}, status: {}",
request.getUserId(), request.getSessionId(), request.getStatus());
return AjaxResult.success(request);
} catch (Exception e) {
logger.error("[获取转人工请求详情] 获取转人工请求详情失败 - requestId: {}", requestId, e);
return AjaxResult.error("获取转人工请求详情失败: " + e.getMessage());
}
}
/**
* 接受转人工请求
*/
@PostMapping("/manual-requests/{requestId}/accept")
@ResponseBody
public AjaxResult acceptManualRequest(@PathVariable Long requestId)
{
try {
logger.info("[接受转人工] 开始处理请求 - requestId: {}, serviceId: {}", requestId, getUserId());
// 先获取原始记录
ManualServiceSessions originalRequest = customerServiceService.getManualRequestById(requestId);
if (originalRequest == null) {
logger.error("[接受转人工] 未找到转人工记录 - requestId: {}", requestId);
return AjaxResult.error("未找到转人工记录");
}
logger.info("[接受转人工] 原始记录 - userId: {}, sessionId: {}, status: {}",
originalRequest.getUserId(), originalRequest.getSessionId(), originalRequest.getStatus());
// 检查状态是否为待处理
if (!"0".equals(originalRequest.getStatus())) {
logger.warn("[接受转人工] 记录状态不是待处理 - status: {}", originalRequest.getStatus());
return AjaxResult.error("该请求已被处理");
}
// 更新记录状态
ManualServiceSessions manualSession = new ManualServiceSessions();
manualSession.setManualSessionId(requestId); // 设置主键ID
manualSession.setStatus("1"); // 1-已接受
manualSession.setServiceId(getUserId());
manualSession.setAcceptTime(new java.util.Date());
manualSession.setUpdateBy(requestId+"");
int result = customerServiceService.updateManualServiceRequest(manualSession);
logger.info("[接受转人工] 数据库更新结果: {}", result);
if (result > 0) {
// 创建或更新UserSessions记录
try {
String sessionId = originalRequest.getSessionId();
boolean sessionExists = customerServiceService.isSessionIdExists(sessionId);
UserSessions userSession = new UserSessions();
userSession.setSessionId(sessionId);
userSession.setUserId(originalRequest.getUserId());
userSession.setSessionStart(new java.util.Date());
userSession.setStatus("active");
userSession.setLastActivity(new java.util.Date());
userSession.setSessionToken(sessionId);
int sessionResult;
if (sessionExists) {
// 如果会话已存在则更新记录
sessionResult = customerServiceService.updateUserSessions(userSession);
logger.info("[接受转人工] 更新UserSessions记录结果: {}", sessionResult);
} else {
// 如果会话不存在则插入新记录
sessionResult = customerServiceService.insertUserSessions(userSession);
logger.info("[接受转人工] 创建UserSessions记录结果: {}", sessionResult);
}
} catch (Exception e) {
logger.error("[接受转人工] 处理UserSessions记录失败", e);
}
// 通知用户转人工请求被接受
if (originalRequest.getUserId() != null) {
logger.info("[接受转人工] 发送用户通知 - userId: {}", originalRequest.getUserId());
customerServiceService.notifyUserManualRequestAccepted(
originalRequest.getUserId(), requestId, getUserId());
} else {
logger.warn("[接受转人工] 原始记录中userId为空无法发送用户通知");
}
logger.info("[接受转人工] 处理完成 - 成功接受转人工请求");
return AjaxResult.success("已接受转人工请求");
} else {
logger.error("[接受转人工] 数据库更新失败");
return AjaxResult.error("操作失败");
}
} catch (Exception e) {
logger.error("[接受转人工] 处理异常", e);
return AjaxResult.error("操作失败: " + e.getMessage());
}
}
/**
* 拒绝转人工请求
*/
@PostMapping("/manual-requests/{requestId}/reject")
@ResponseBody
public AjaxResult rejectManualRequest(@PathVariable Long requestId)
{
try {
ManualServiceSessions manualSession = new ManualServiceSessions();
manualSession.setManualSessionId(requestId); // 设置主键ID
manualSession.setStatus("2"); // 2-已拒绝
manualSession.setServiceId(getUserId());
manualSession.setUpdateBy(requestId+"");
int result = customerServiceService.updateManualServiceRequest(manualSession);
if (result > 0) {
return AjaxResult.success("已拒绝转人工请求");
} else {
return AjaxResult.error("操作失败");
}
} catch (Exception e) {
logger.error("拒绝转人工请求失败", e);
return AjaxResult.error("操作失败: " + e.getMessage());
}
}
/**
* 更新客服状态
*/
@PostMapping("/status")
@ResponseBody
public AjaxResult updateServiceStatus(@RequestParam String status)
{
try {
logger.info("[更新客服状态] 收到请求参数 - serviceId: {}, status: {}", getUserId(), status);
int result = customerServiceService.updateServiceStatus(getUserId(), status);
if (result > 0) {
logger.info("[更新客服状态] 状态更新成功");
return AjaxResult.success("状态更新成功");
} else {
logger.error("[更新客服状态] 状态更新失败 - 数据库返回0");
return AjaxResult.error("状态更新失败");
}
} catch (Exception e) {
logger.error("[更新客服状态] 更新客服状态异常", e);
return AjaxResult.error("状态更新失败: " + e.getMessage());
}
}
/**
* 导出会话列表
*/
@RequiresPermissions("customer:service:export")
@Log(title = "客服会话", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(@RequestBody UserSessions userSessions)
{
try {
logger.info("[导出会话] 收到导出请求 - 查询条件: {}", userSessions);
List<UserSessions> list = customerServiceService.selectUserSessionsList(userSessions);
logger.info("[导出会话] 查询到数据条数: {}", list != null ? list.size() : 0);
ExcelUtil<UserSessions> util = new ExcelUtil<UserSessions>(UserSessions.class);
AjaxResult result = util.exportExcel(list, "会话数据");
logger.info("[导出会话] 导出完成");
return result;
} catch (Exception e) {
logger.error("[导出会话] 导出会话列表异常", e);
return AjaxResult.error("导出失败: " + e.getMessage());
}
}
/**
* 获取当前登录用户信息
*/
@GetMapping("/current-user")
@ResponseBody
public AjaxResult getCurrentUser()
{
try {
Long userId = getUserId();
String loginName = getLoginName();
AjaxResult result = AjaxResult.success();
result.put("userId", userId);
result.put("loginName", loginName);
return result;
} catch (Exception e) {
logger.error("获取当前用户信息失败", e);
return AjaxResult.error("获取当前用户信息失败");
}
}
/**
* 获取客服统计信息
*/
@GetMapping("/statistics")
@ResponseBody
public AjaxResult getStatistics()
{
try {
// 获取今日统计数据
int todaySessions = customerServiceService.getTodaySessionCount();
int todayMessages = customerServiceService.getTodayMessageCount();
int pendingRequests = customerServiceService.getPendingRequestCount();
int onlineServices = customerServiceService.getOnlineServiceCount();
AjaxResult result = AjaxResult.success();
result.put("todaySessions", todaySessions);
result.put("todayMessages", todayMessages);
result.put("pendingRequests", pendingRequests);
result.put("onlineServices", onlineServices);
return result;
} catch (Exception e) {
logger.error("获取统计信息失败", e);
return AjaxResult.error("获取统计信息失败");
}
}
}

View File

@ -0,0 +1,101 @@
package com.ruoyi.web.controller.customer.dto;
import java.util.List;
/**
* 转人工服务请求DTO
*
* @author ruoyi
*/
public class TransferToManualRequest
{
/** 用户ID */
private String userId;
/** 转人工原因 */
private Object reason;
public TransferToManualRequest()
{
}
public TransferToManualRequest(String userId, Object reason)
{
this.userId = userId;
this.reason = reason;
}
public String getUserId()
{
return userId;
}
public void setUserId(String userId)
{
this.userId = userId;
}
public Object getReason()
{
return reason;
}
public void setReason(Object reason)
{
this.reason = reason;
}
/**
* 获取转换后的用户IDLong类型
*/
public Long getUserIdAsLong()
{
if (userId == null || userId.trim().isEmpty())
{
return null;
}
try
{
return Long.parseLong(userId.trim());
}
catch (NumberFormatException e)
{
return null;
}
}
/**
* 获取转换后的原因String类型
*/
public String getReasonAsString()
{
if (reason == null)
{
return null;
}
if (reason instanceof String)
{
return (String) reason;
}
else if (reason instanceof List)
{
// 如果是消息列表转换为字符串描述
List<?> messageList = (List<?>) reason;
return "用户最近" + messageList.size() + "条消息记录";
}
else
{
return reason.toString();
}
}
@Override
public String toString()
{
return "TransferToManualRequest{" +
"userId='" + userId + '\'' +
", reason=" + reason +
'}';
}
}

View File

@ -0,0 +1,181 @@
package com.ruoyi.web.controller.system;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.domain.ChatHistory;
import com.ruoyi.system.service.IChatHistoryService;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 聊天记录App接口Controller
*
* @author ruoyi
* @date 2024-01-01
*/
@RestController
@RequestMapping("/system/chatHistory/app")
public class ChatHistoryAppController extends BaseController
{
@Autowired
private IChatHistoryService chatHistoryService;
/**
* 根据会话ID查询聊天记录
*/
@GetMapping("/session/{sessionId}")
public AjaxResult getChatHistoryBySession(@PathVariable("sessionId") String sessionId)
{
try {
List<ChatHistory> list = chatHistoryService.selectChatHistoryBySessionId(sessionId);
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询聊天记录失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 根据用户ID查询聊天记录
*/
@GetMapping("/user/{userId}")
public AjaxResult getChatHistoryByUser(@PathVariable("userId") String userId)
{
try {
List<ChatHistory> list = chatHistoryService.selectChatHistoryByUserId(userId);
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询聊天记录失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 新增聊天记录
*/
@PostMapping
public AjaxResult add(@RequestBody ChatHistory chatHistory)
{
try {
int result = chatHistoryService.insertChatHistory(chatHistory);
chatHistory.setCreateTime(new Date());
return toAjax(result);
} catch (Exception e) {
logger.error("新增聊天记录失败", e);
return AjaxResult.error("新增失败:" + e.getMessage());
}
}
/**
* 批量新增聊天记录
*/
@PostMapping("/batch")
public AjaxResult batchAdd(@RequestBody List<ChatHistory> chatHistoryList)
{
try {
int result = chatHistoryService.batchInsertChatHistory(chatHistoryList);
return toAjax(result);
} catch (Exception e) {
logger.error("批量新增聊天记录失败", e);
return AjaxResult.error("批量新增失败:" + e.getMessage());
}
}
/**
* 修改聊天记录
*/
@PutMapping
public AjaxResult edit(@RequestBody ChatHistory chatHistory)
{
try {
int result = chatHistoryService.updateChatHistory(chatHistory);
return toAjax(result);
} catch (Exception e) {
logger.error("修改聊天记录失败", e);
return AjaxResult.error("修改失败:" + e.getMessage());
}
}
/**
* 删除指定会话的聊天记录
*/
@DeleteMapping("/session/{sessionId}")
public AjaxResult removeBySession(@PathVariable("sessionId") String sessionId)
{
try {
int result = chatHistoryService.deleteChatHistoryBySessionId(sessionId);
return toAjax(result);
} catch (Exception e) {
logger.error("删除聊天记录失败", e);
return AjaxResult.error("删除失败:" + e.getMessage());
}
}
/**
* 删除指定用户的聊天记录
*/
@DeleteMapping("/user/{userId}")
public AjaxResult removeByUser(@PathVariable("userId") String userId)
{
try {
int result = chatHistoryService.deleteChatHistoryByUserId(userId);
return toAjax(result);
} catch (Exception e) {
logger.error("删除聊天记录失败", e);
return AjaxResult.error("删除失败:" + e.getMessage());
}
}
/**
* 保存用户聊天记录包含用户消息和客服回复
*/
@PostMapping("/saveChat")
public AjaxResult saveChat(@RequestBody List<ChatHistory> chatHistoryList)
{
try {
if (chatHistoryList == null || chatHistoryList.isEmpty()) {
return AjaxResult.error("聊天记录不能为空");
}
int result = chatHistoryService.batchInsertChatHistory(chatHistoryList);
return toAjax(result);
} catch (Exception e) {
logger.error("保存聊天记录失败", e);
return AjaxResult.error("保存失败:" + e.getMessage());
}
}
/**
* 获取用户最新的聊天记录
*/
@GetMapping("/latest/{userId}")
public AjaxResult getLatestChatHistory(@PathVariable("userId") String userId,
@RequestParam(value = "limit", defaultValue = "20") Integer limit)
{
try {
ChatHistory query = new ChatHistory();
query.setUserId(userId);
List<ChatHistory> list = chatHistoryService.selectChatHistoryList(query);
// 限制返回数量
if (limit != null && limit > 0 && list.size() > limit) {
list = list.subList(list.size() - limit, list.size());
}
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询最新聊天记录失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
}

View File

@ -0,0 +1,618 @@
package com.ruoyi.web.controller.system;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.util.*;
import java.util.stream.Collectors;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.security.Md5Utils;
import com.ruoyi.system.domain.ClewPhone;
import com.ruoyi.system.domain.CompanyApp;
import com.ruoyi.system.domain.OppoCheck;
import com.ruoyi.system.service.IClewPhoneService;
import com.ruoyi.system.service.ICompanyAppService;
import com.ruoyi.system.service.IDutyConfigService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.core.config.GlobalLogHelper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.Clew;
import com.ruoyi.system.service.IClewService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/**
* 线索Controller
*
* @author ruoyi
* @date 2023-05-15
*/
@Slf4j
@Controller
@RequestMapping("/system/clew")
public class ClewController extends BaseController
{
private String prefix = "system/clew";
@Autowired
private IClewService clewService;
@Autowired
private ISysUserService sysUserService;
@Autowired
private IClewPhoneService clewPhoneService;
@Autowired
private ICompanyAppService companyAppService;
@Autowired
private IDutyConfigService dutyConfigService;
@RequiresPermissions("system:clew:view")
@GetMapping()
public String clew(ModelMap modelMap)
{
List<SysUser> users = sysUserService.selectUserList(new SysUser());
modelMap.put("users", users);
return prefix + "/clew";
}
@RequiresPermissions("system:clew:view")
@GetMapping("publicClew")
public String publicClew(ModelMap modelMap)
{
return prefix + "/publicClew";
}
@RequiresPermissions("system:clew:view")
@GetMapping("qualityClew")
public String qualityClew(ModelMap modelMap)
{
return prefix + "/qualityClew";
}
/**
* 查询线索列表
*/
@RequiresPermissions("system:clew:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(Clew clew)
{
startPage();
if(!"admin".equals(getSysUser().getLoginName())){
clew.setSaleId(getSysUser().getUserId());
}
long isSubAdmin = getSysUser().getRoles().stream().filter(x->x.getRoleKey().equals("subAdmin")).count();
if(isSubAdmin > 0 && !"admin".equals(getSysUser().getLoginName())){
clew.setSaleId(null);
clew.setRemark("baidu");
}
List<Clew> list = clewService.selectClewList(clew);
list.forEach(model->{
if(model.getSaleId() != null){
SysUser user = sysUserService.selectUserById(model.getSaleId());
if(user != null){
model.setSaleName(user.getUserName());
}
SysUser sourceUser = sysUserService.selectUserById(model.getSourceSaleId());
if(sourceUser != null){
model.setSourceSaleName(sourceUser.getUserName());
}
}
if(model.getSourceApp() != null){
CompanyApp param = new CompanyApp();
param.setCompanyId(model.getSourceApp());
List<CompanyApp> result = companyAppService.selectCompanyAppList(param);
model.setSourceAppName(result.get(0).getAppName());
}else {
model.setSourceAppName("黑猫APP");
}
});
return getDataTable(list);
}
@RequiresPermissions("system:clew:list")
@PostMapping("/listPublic")
@ResponseBody
public TableDataInfo listPublic(Clew clew)
{
startPage();
clew.setSaleId(2L);
clew.setPoolStatus("01"); // 只显示公海池状态的线索
List<Clew> list = clewService.selectClewPublicList(clew);
list.forEach(model->{
if(model.getSaleId() != null){
SysUser user = sysUserService.selectUserById(model.getSaleId());
if(user != null){
model.setSaleName(user.getUserName());
}
SysUser sourceUser = sysUserService.selectUserById(model.getSourceSaleId());
if(sourceUser != null){
model.setSourceSaleName(sourceUser.getUserName());
}
}
if(model.getSourceApp() != null){
CompanyApp param = new CompanyApp();
param.setCompanyId(model.getSourceApp());
List<CompanyApp> result = companyAppService.selectCompanyAppList(param);
model.setSourceAppName(result.get(0).getAppName());
}else {
model.setSourceAppName("黑猫APP");
}
});
return getDataTable(list);
}
@RequiresPermissions("system:clew:list")
@PostMapping("/listQuality")
@ResponseBody
public TableDataInfo listQuality(Clew clew)
{
SysUser sysUser=getSysUser();
startPage();
// clew.setSaleId(2L);
clew.setPoolStatus("02"); // 只显示优质线索池状态的线索
if (!Objects.equals(sysUser.getLoginName(), "admin")){
clew.setSaleId(sysUser.getUserId());
}
List<Clew> list = clewService.selectClewQualityList(clew);
list.forEach(model->{
if(model.getSaleId() != null){
SysUser user = sysUserService.selectUserById(model.getSaleId());
if(user != null){
model.setSaleName(user.getUserName());
}
SysUser sourceUser = sysUserService.selectUserById(model.getSourceSaleId());
if(sourceUser != null){
model.setSourceSaleName(sourceUser.getUserName());
}
}
if(model.getSourceApp() != null){
CompanyApp param = new CompanyApp();
param.setCompanyId(model.getSourceApp());
List<CompanyApp> result = companyAppService.selectCompanyAppList(param);
model.setSourceAppName(result.get(0).getAppName());
}else {
model.setSourceAppName("黑猫APP");
}
});
return getDataTable(list);
}
/**
* 导出线索列表
*/
@RequiresPermissions("system:clew:export")
@Log(title = "线索", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(Clew clew)
{
List<Clew> list = clewService.selectClewList(clew);
ExcelUtil<Clew> util = new ExcelUtil<Clew>(Clew.class);
return util.exportExcel(list, "线索数据");
}
/**
* 新增线索
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存线索
*/
@RequiresPermissions("system:clew:add")
@Log(title = "线索", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(Clew clew)
{
return toAjax(clewService.insertClew(clew));
}
@PostMapping("/app/add")
@ResponseBody
public AjaxResult appAddSave(@RequestBody Clew clew)
{
Clew param = new Clew();
param.setPhone(clew.getPhone());
List<Clew> result = clewService.selectClewList(param);
if (CollectionUtils.isNotEmpty(result)){
return AjaxResult.success();
}
// 根据值班配置自动分配客服
Long assignedUserId = null;
try {
assignedUserId = dutyConfigService.getNextDutyUserId();
if (assignedUserId != null) {
clew.setSaleId(assignedUserId);
clew.setSourceSaleId(assignedUserId); // 记录初始分配的销售
clew.setAssignTimes("01"); // 标记为首次分配
log.info("线索自动分配给值班用户, 手机号:{}, 用户ID:{}", clew.getPhone(), assignedUserId);
} else {
// 如果没有值班配置使用默认逻辑可以设置为公海或默认用户
clew.setSaleId(1L); // 默认分配给默认用户-保无忧
clew.setPoolStatus("01"); // 设置为公海池状态
log.info("未找到值班配置, 线索分配到公海, 手机号:{}", clew.getPhone());
}
} catch (Exception e) {
log.error("获取值班用户失败, 线索分配到公海, 手机号:{}, 错误:{}", clew.getPhone(), e.getMessage());
clew.setSaleId(1L); // 异常时分配给公海
clew.setPoolStatus("01"); // 设置为公海池状态
}
// 不存在手机号则入库线索
clewService.insertClew(clew);
// 如果分配给了具体客服发送短信通知
if (assignedUserId != null && assignedUserId != 2L) {
sendSmsNotification(assignedUserId, clew);
}
// 将初始线索设置成已跟踪
ClewPhone model = new ClewPhone();
model.setPhone(clew.getPhone());
List<ClewPhone> clewPhoneList = clewPhoneService.selectClewPhoneList(model);
clewPhoneList.forEach(x->{
x.setStatus("1");
x.setSourceApp(clew.getSourceApp());
clewPhoneService.updateClewPhone(x);
});
// 调用oppo的统计接口
try {
// 回调
if("oppo".equalsIgnoreCase(clew.getRemark())){
OppoCheck oppoCheck = new OppoCheck();
oppoCheck.setDataType(7);
oppoCheck.setTimestamp(System.currentTimeMillis());
if(StringUtils.isNotEmpty(clew.getImei())){
oppoCheck.setImei(encode(clew.getImei().getBytes()));
}
if(StringUtils.isNotEmpty(clew.getOaid())){
oppoCheck.setOuId(encode(clew.getOaid().getBytes()));
}
String content = JSONObject.toJSONString(oppoCheck) + oppoCheck.getTimestamp() + "e0u6fnlag06lc3pl";
log.info("请求的content加密前属性{}", content);
Map<String, String> headerMap = new HashMap<>();
headerMap.put("signature", Md5Utils.hash(content));
headerMap.put("timestamp", String.valueOf(oppoCheck.getTimestamp()));
headerMap.put("Content-Type", "application/json");
log.info("请求https://api.ads.heytapmobi.com/api/uploadActiveData的属性{}", JSONObject.toJSONString(oppoCheck));
String s = HttpUtils.sendPost("https://api.ads.heytapmobi.com/api/uploadActiveData", JSONObject.toJSONString(oppoCheck), headerMap);
log.info("请求https://api.ads.heytapmobi.com/api/uploadActiveData的响应{}", s);
}else if("vivo".equalsIgnoreCase(clew.getRemark())){
String token = "9cd4cddcfc7c9f81fdaf4c94e826926bf0f84259462a57dbfc448f29cc8815c3";
String timeStamp = System.currentTimeMillis() + "";
String notice = "VIVO"+ (long)((Math.random()+1) * 10000000);
String url = "https://marketing-api.vivo.com.cn/openapi/v1/advertiser/behavior/upload?access_token="+token+"&timestamp="+timeStamp+"&nonce="+notice;
String content = "{\"dataList\":[{\"cvTime\":"+timeStamp+",\"cvType\":\"PAY\",\"userId\":\""+ clew.getOaid() +"\",\"userIdType\":\"OAID\"}],\"pkgName\":\"com.yinliu.loan\",\"srcId\":\"ds-202502072511\",\"srcType\":\"app\"}";
if(clew.getSourceApp() != null && clew.getSourceApp() == 2L){
content = "{\"dataList\":[{\"cvTime\":"+timeStamp+",\"cvType\":\"PAY\",\"userId\":\""+ clew.getOaid() +"\",\"userIdType\":\"OAID\"}],\"pkgName\":\"com.zh.gdyq\",\"srcId\":\"ds-202404185034\",\"srcType\":\"app\"}";
}
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Content-Type", "application/json");
log.info("请求{}的属性{}", url, content);
String s = HttpUtils.sendPost(url, content, headerMap);
log.info("请求{}的响应{}", url, s);
}else if("xiaomi".equalsIgnoreCase(clew.getRemark())){
log.info("oaid : {}, imei:{}", clew.getOaid(), clew.getImei());
// String imei = clew.getImei();
String oaid = clew.getOaid();
// String ua = "Dalvik/2.1.0 (Linux; U; Android 11; M2012K11AC Build/RKQ1.200826.002)";
String clientIp = "58.49.150.163";
long convTime = System.currentTimeMillis();
String convType = "APP_PAY";
long appId = 1545362;
int customerId = 445972;
String singKey = "FkqMqeKVbCaeSGBI";
String encryptKey = "IIUWoEaMXlzctOqk";
if(clew.getSourceApp() != null && clew.getSourceApp() == 2L){
customerId = 593022;
appId = 1585622;
singKey = "lNebrbVaMMubMqUr";
encryptKey = "hZdCGTMvrOAdVeUq";
}
GlobalLogHelper.UploadInfo uploadInfo = GlobalLogHelper.UploadInfo.builder()
// .imei(imei)
.oaid(oaid)
// .ua(ua)
.clientIp(clientIp)
.convTime(convTime).convType(convType)
.appId(appId).customerId(customerId).signKey(singKey).encryptKey(encryptKey).build().genInfo();
log.info("请求xiaomi的属性{}", uploadInfo.getFinalUrl());
String s = HttpUtils.sendGet(uploadInfo.getFinalUrl());
log.info("请求xiaomi的响应{}", s);
}
}catch (Exception e){
e.printStackTrace();
log.error("回调oppo报错:{}", e.getMessage());
}
return AjaxResult.success();
}
//huawei-归因
public String getHuaWeiToken(){
return null;
}
public String send() throws Exception{
JSONObject vivoJson = new JSONObject();
vivoJson.put("srcType", "APP");
vivoJson.put("pkgName", "");
vivoJson.put("pageUrl", "");
vivoJson.put("srcId", "");
vivoJson.put("dataFrom", "0");
String url = "https://sandbox-marketing-api.vivo.com.cn/openapi/v1/advertiser/behavior/upload";
String advertiserId = "XX";
String nonce = "XX";
String accessToken = "595a46633e3f8162363a37092037a436f62e4d462102ddbf3eb503fa52017b93";
String timestamp = String.valueOf(System.currentTimeMillis());
OkHttpClient client = new OkHttpClient().newBuilder().build();
MediaType mediaType = MediaType.parse("application/json");
String jsonStr = "XX"; //使用请求参数的json串替换格式如下方示例
okhttp3.RequestBody body = okhttp3.RequestBody.create(mediaType, jsonStr);
Request request = new Request.Builder()
.url(url + "?access_token=" + accessToken + "&timestamp=" + timestamp + "&nonce=" + nonce + "&advertiser_id=" + advertiserId)
.method("POST", body)
.addHeader("Content-Type", "application/json")
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
public static String encode(byte[] data) throws GeneralSecurityException {
final Key dataKey = new SecretKeySpec(Base64.decodeBase64("XGAXicVG5GMBsx5bueOe4w=="), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, dataKey);
byte[] encryptData = cipher.doFinal(data);
return Base64.encodeBase64String(encryptData).replaceAll("\r", "").replaceAll("\n", "");
}
/**
* 修改线索
*/
@RequiresPermissions("system:clew:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
Clew clew = clewService.selectClewById(id);
mmap.put("clew", clew);
return prefix + "/edit";
}
/**
* 修改保存线索
*/
@RequiresPermissions("system:clew:edit")
@Log(title = "线索", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(Clew clew)
{
return toAjax(clewService.updateClew(clew));
}
/**
* 删除线索
*/
@RequiresPermissions("system:clew:remove")
@Log(title = "线索", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(clewService.deleteClewByIds(ids));
}
@PostMapping("/changeUser")
@ResponseBody
public AjaxResult changeUser(Clew clew)
{
Clew sourceClew = clewService.selectClewById(clew.getId());
if(!ObjectUtil.equals(sourceClew.getSaleId(), 1L)){
clew.setAssignTimes("02");
}
clew.setUpdateTime(DateUtils.getNowDate());
// 线索短信通知
try {
// 查询销售手机号
SysUser sysUser = sysUserService.selectUserById(clew.getSaleId());
JSONObject smsContent = new JSONObject();
smsContent.put("uid", "12347");
smsContent.put("pwd", "wJgzaC0u");
smsContent.put("mobile", sysUser.getLoginName());
// 证明是普通的手机号
boolean flag = sysUser.getLoginName().length() > 10;
if(sourceClew.getSourceApp() != null && sourceClew.getSourceApp() == 2L){
smsContent.put("content", "你有一条来自大象,新线索生成,客户电话:" + sourceClew.getPhone() + "(请注意及时跟进)");
}else {
smsContent.put("content", "你有一条来自黑猫,新线索生成,客户电话:" + sourceClew.getPhone() + "(请注意及时跟进)");
}
if(!ObjectUtil.equals(sourceClew.getSourceApp(), 8L) && flag){
log.info("请求傲众短信入参:{}", smsContent.toJSONString());
String s = HttpUtils.sendPost("http://www.aozhongyun.com/Admin/index.php/Message/send", smsContent.toJSONString());
log.info("请求傲众短信url:{}, 响应:{}", "http://www.aozhongyun.com/Admin/index.php/Message/send", s);
}
}catch (Exception e){
log.error("请求傲众短信url:{}, 报错:{}","http://www.aozhongyun.com/Admin/index.php/Message/send", e.getMessage());
}
return toAjax(clewService.updateClew(clew));
}
@PostMapping("/getBackClew")
@ResponseBody
public AjaxResult getBackClew(Clew clew)
{
Clew sourceClew = clewService.selectClewById(clew.getId());
if(sourceClew.getSaleId() != 2L){
return AjaxResult.error("该线索已被人取走!");
}
sourceClew.setSaleId(getSysUser().getUserId());
sourceClew.setUpdateTime(new Date());
return toAjax(clewService.updateClew(sourceClew));
}
@PostMapping("/addPublicClew")
@ResponseBody
public AjaxResult addPublicClew(Clew clew)
{
Clew sourceClew = clewService.selectClewById(clew.getId());
sourceClew.setSaleId(2L);
clew.setUpdateTime(DateUtils.getNowDate());
return toAjax(clewService.updateClew(sourceClew));
}
@GetMapping("/changeUser/{clewId}")
public String changeUser(@PathVariable("clewId") String id, ModelMap mmap)
{
mmap.put("clewId", id);
mmap.put("users", sysUserService.selectUserList(new SysUser()));
return "system/clew/changeUser";
}
@PostMapping("/changeBatchUser")
@ResponseBody
public AjaxResult changeBatchUser(Clew clew)
{
if(StringUtils.isEmpty(clew.getIds())){
return AjaxResult.error("请选择线索!");
}
Clew sourceClew = clewService.selectClewById(Long.parseLong(clew.getIds().split(",")[0]));
if(!ObjectUtil.equals(sourceClew.getSaleId(), 1L)){
clew.setAssignTimes("02");
}
clew.setUpdateTime(DateUtils.getNowDate());
clew.setIdList(Arrays.stream(clew.getIds().split(",")).map(Long::parseLong).collect(Collectors.toList()));
// 线索短信通知
try {
// 查询销售手机号
SysUser sysUser = sysUserService.selectUserById(clew.getSaleId());
JSONObject smsContent = new JSONObject();
smsContent.put("uid", "12347");
smsContent.put("pwd", "wJgzaC0u");
smsContent.put("mobile", sysUser.getLoginName());
// 证明是普通的手机号
boolean flag = sysUser.getLoginName().length() > 10;
if(sourceClew.getSourceApp() != null && sourceClew.getSourceApp() == 2L){
smsContent.put("content", "你有多条来自大象,新线索生成(请注意及时跟进)");
}else {
smsContent.put("content", "你有一条来自黑猫,新线索生成(请注意及时跟进)");
}
if(!ObjectUtil.equals(sourceClew.getSourceApp(), 8L) && flag){
log.info("请求傲众短信入参:{}", smsContent.toJSONString());
String s = HttpUtils.sendPost("http://www.aozhongyun.com/Admin/index.php/Message/send", smsContent.toJSONString());
log.info("请求傲众短信url:{}, 响应:{}", "http://www.aozhongyun.com/Admin/index.php/Message/send", s);
}
}catch (Exception e){
log.error("请求傲众短信url:{}, 报错:{}","http://www.aozhongyun.com/Admin/index.php/Message/send", e.getMessage());
}
return toAjax(clewService.updateBatchClew(clew));
}
@GetMapping("/changeBatchUser/{clewIds}")
public String changeBatchUser(@PathVariable("clewIds") String ids, ModelMap mmap)
{
mmap.put("clewIds", ids);
mmap.put("users", sysUserService.selectUserList(new SysUser()));
return "system/clew/changeBatchUser";
}
/**
* 捞取线索到优质线索池
*/
@PostMapping("/catchClew")
@ResponseBody
public AjaxResult catchClew(Clew clew)
{
Clew sourceClew = clewService.selectClewById(clew.getId());
if(!"01".equals(sourceClew.getPoolStatus())){
return AjaxResult.error("该线索不在公海池中!");
}
sourceClew.setSaleId(getUserId());
sourceClew.setPoolStatus("02");
sourceClew.setCatchTime(new Date());
sourceClew.setUpdateTime(new Date());
return toAjax(clewService.catchClewToQuality(sourceClew));
}
/**
* 发送短信通知给值班客服
*/
private void sendSmsNotification(Long userId, Clew clew) {
try {
// 查询客服手机号
SysUser sysUser = sysUserService.selectUserById(userId);
if (sysUser == null || StringUtils.isEmpty(sysUser.getLoginName())) {
log.warn("未找到用户信息或手机号为空, 用户ID:{}", userId);
return;
}
// 检查是否是手机号长度大于10位
boolean isPhone = sysUser.getLoginName().length() > 10;
if (!isPhone) {
log.info("用户登录名不是手机号,跳过短信通知, 用户ID:{}, 登录名:{}", userId, sysUser.getLoginName());
return;
}
// 排除特定来源sourceApp == 8
if (ObjectUtil.equals(clew.getSourceApp(), 8L)) {
log.info("线索来源为8跳过短信通知, 用户ID:{}", userId);
return;
}
JSONObject smsContent = new JSONObject();
smsContent.put("uid", "12347");
smsContent.put("pwd", "wJgzaC0u");
smsContent.put("mobile", sysUser.getLoginName());
// 根据来源设置短信内容
if (clew.getSourceApp() != null && clew.getSourceApp() == 2L) {
smsContent.put("content", "【值班分配】你有一条来自大象,新线索生成,客户电话:" + clew.getPhone() + "(请注意及时跟进)");
} else {
smsContent.put("content", "【值班分配】你有一条来自黑猫,新线索生成,客户电话:" + clew.getPhone() + "(请注意及时跟进)");
}
log.info("值班分配短信通知, 用户ID:{}, 手机号:{}, 请求参数:{}", userId, sysUser.getLoginName(), smsContent.toJSONString());
String response = HttpUtils.sendPost("http://www.aozhongyun.com/Admin/index.php/Message/send", smsContent.toJSONString());
log.info("值班分配短信通知响应:{}", response);
} catch (Exception e) {
log.error("发送值班分配短信通知失败, 用户ID:{}, 错误:{}", userId, e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,139 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.ClewImg;
import com.ruoyi.system.service.IClewImgService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 线索图片Controller
*
* @author ruoyi
* @date 2023-11-06
*/
@Controller
@RequestMapping("/system/img")
public class ClewImgController extends BaseController
{
private String prefix = "system/img";
@Autowired
private IClewImgService clewImgService;
@RequiresPermissions("system:img:view")
@GetMapping()
public String img()
{
return prefix + "/img";
}
/**
* 查询线索图片列表
*/
@RequiresPermissions("system:img:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(ClewImg clewImg)
{
startPage();
List<ClewImg> list = clewImgService.selectClewImgList(clewImg);
return getDataTable(list);
}
@GetMapping("/app/list")
@ResponseBody
public AjaxResult getAppList(@RequestParam(value = "sourceApp", required = false) Long sourceApp)
{
if(sourceApp == null){
sourceApp = 1L;
}
ClewImg param = new ClewImg();
param.setSourceApp(sourceApp);
List<ClewImg> list = clewImgService.selectClewImgList(param);
List<String> imgList = list.stream().map(ClewImg::getImgUrl).collect(Collectors.toList());
return AjaxResult.success(imgList);
}
/**
* 导出线索图片列表
*/
@RequiresPermissions("system:img:export")
@Log(title = "线索图片", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(ClewImg clewImg)
{
List<ClewImg> list = clewImgService.selectClewImgList(clewImg);
ExcelUtil<ClewImg> util = new ExcelUtil<ClewImg>(ClewImg.class);
return util.exportExcel(list, "线索图片数据");
}
/**
* 新增线索图片
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存线索图片
*/
@RequiresPermissions("system:img:add")
@Log(title = "线索图片", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(ClewImg clewImg)
{
return toAjax(clewImgService.insertClewImg(clewImg));
}
/**
* 修改线索图片
*/
@RequiresPermissions("system:img:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
ClewImg clewImg = clewImgService.selectClewImgById(id);
mmap.put("clewImg", clewImg);
return prefix + "/edit";
}
/**
* 修改保存线索图片
*/
@RequiresPermissions("system:img:edit")
@Log(title = "线索图片", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(ClewImg clewImg)
{
return toAjax(clewImgService.updateClewImg(clewImg));
}
/**
* 删除线索图片
*/
@RequiresPermissions("system:img:remove")
@Log(title = "线索图片", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(clewImgService.deleteClewImgByIds(ids));
}
}

View File

@ -0,0 +1,186 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.ClewMaterial;
import com.ruoyi.system.service.IClewMaterialService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.mapper.MaterialStatsDailyMapper;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* 素材Controller
*
* @author ruoyi
* @date 2023-10-07
*/
@Controller
@RequestMapping("/system/material")
public class ClewMaterialController extends BaseController
{
private String prefix = "system/material";
@Autowired
private IClewMaterialService clewMaterialService;
@Autowired
private MaterialStatsDailyMapper materialStatsDailyMapper;
@RequiresPermissions("system:material:view")
@GetMapping()
public String material()
{
return prefix + "/material";
}
/**
* 查询素材列表
*/
@RequiresPermissions("system:material:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(ClewMaterial clewMaterial)
{
startPage();
List<ClewMaterial> list = clewMaterialService.selectClewMaterialList(clewMaterial);
return getDataTable(list);
}
@PostMapping("/app/list")
@ResponseBody
public TableDataInfo appList(@RequestParam(value = "sourceApp", required = false) Long sourceApp, ClewMaterial clewMaterial)
{
startPage();
if(sourceApp == null){
clewMaterial.setSourceApp(1L);
}
List<ClewMaterial> list = clewMaterialService.selectClewMaterialList(clewMaterial);
return getDataTable(list);
}
/**
* 导出素材列表
*/
@RequiresPermissions("system:material:export")
@Log(title = "素材", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(ClewMaterial clewMaterial)
{
List<ClewMaterial> list = clewMaterialService.selectClewMaterialList(clewMaterial);
ExcelUtil<ClewMaterial> util = new ExcelUtil<ClewMaterial>(ClewMaterial.class);
return util.exportExcel(list, "素材数据");
}
/**
* 新增素材
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存素材
*/
@RequiresPermissions("system:material:add")
@Log(title = "素材", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(ClewMaterial clewMaterial)
{
return toAjax(clewMaterialService.insertClewMaterial(clewMaterial));
}
/**
* 修改素材
*/
@RequiresPermissions("system:material:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
ClewMaterial clewMaterial = clewMaterialService.selectClewMaterialById(id);
mmap.put("clewMaterial", clewMaterial);
return prefix + "/edit";
}
/**
* 修改保存素材
*/
@RequiresPermissions("system:material:edit")
@Log(title = "素材", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(ClewMaterial clewMaterial)
{
return toAjax(clewMaterialService.updateClewMaterial(clewMaterial));
}
/**
* 删除素材
*/
@RequiresPermissions("system:material:remove")
@Log(title = "素材", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(clewMaterialService.deleteClewMaterialByIds(ids));
}
/**
* 素材点击统计APP端调用无需权限校验
*/
@PostMapping("/app/click/{id}")
@ResponseBody
public AjaxResult incrementClickCount(@PathVariable("id") Long id, HttpServletRequest request)
{
System.out.println("点击统计接口被调用素材ID: " + id);
String appName = "黑猫搞定逾期";
String statDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
ClewMaterial material = clewMaterialService.selectClewMaterialById(id);
String title = material != null ? material.getTitle() : null;
String labels = material != null ? material.getLabels() : null;
String appSource = material != null && material.getSourceApp() != null ? String.valueOf(material.getSourceApp()) : "unknown";
materialStatsDailyMapper.incrClick(id, appName, appSource, statDate, title, labels);
int result = clewMaterialService.incrementClickCount(id);
System.out.println("点击统计结果: " + result);
return toAjax(result);
}
/**
* 素材提交统计APP端调用无需权限校验
*/
@PostMapping("/app/submit/{id}")
@ResponseBody
public AjaxResult incrementSubmitCount(@PathVariable("id") Long id, HttpServletRequest request)
{
System.out.println("提交统计接口被调用素材ID: " + id);
String appName = "黑猫搞定逾期";
String statDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
ClewMaterial material = clewMaterialService.selectClewMaterialById(id);
String title = material != null ? material.getTitle() : null;
String labels = material != null ? material.getLabels() : null;
String appSource = material != null && material.getSourceApp() != null ? String.valueOf(material.getSourceApp()) : "unknown";
materialStatsDailyMapper.incrSubmit(id, appName, appSource, statDate, title, labels);
int result = clewMaterialService.incrementSubmitCount(id);
System.out.println("提交统计结果: " + result);
return toAjax(result);
}
private String defaultString(String val, String def) {
return (val == null || val.trim().isEmpty()) ? def : val.trim();
}
}

View File

@ -0,0 +1,134 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.ClewPhone;
import com.ruoyi.system.service.IClewPhoneService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 线索手机号Controller
*
* @author ruoyi
* @date 2023-07-19
*/
@Controller
@RequestMapping("/system/phone")
public class ClewPhoneController extends BaseController
{
private String prefix = "system/phone";
@Autowired
private IClewPhoneService clewPhoneService;
@RequiresPermissions("system:phone:view")
@GetMapping()
public String phone()
{
return prefix + "/phone";
}
/**
* 查询线索手机号列表
*/
@RequiresPermissions("system:phone:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(ClewPhone clewPhone)
{
startPage();
List<ClewPhone> list = clewPhoneService.selectClewPhoneList(clewPhone);
list.forEach(model->{
if(model.getSourceApp() != null && model.getSourceApp() == 2L){
model.setSourceAppName("大象处理逾期");
}else {
model.setSourceAppName("黑猫搞定逾期");
}
});
return getDataTable(list);
}
/**
* 导出线索手机号列表
*/
@RequiresPermissions("system:phone:export")
@Log(title = "线索手机号", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(ClewPhone clewPhone)
{
List<ClewPhone> list = clewPhoneService.selectClewPhoneList(clewPhone);
ExcelUtil<ClewPhone> util = new ExcelUtil<ClewPhone>(ClewPhone.class);
return util.exportExcel(list, "线索手机号数据");
}
/**
* 新增线索手机号
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存线索手机号
*/
@RequiresPermissions("system:phone:add")
@Log(title = "线索手机号", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(ClewPhone clewPhone)
{
return toAjax(clewPhoneService.insertClewPhone(clewPhone));
}
/**
* 修改线索手机号
*/
@RequiresPermissions("system:phone:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
ClewPhone clewPhone = clewPhoneService.selectClewPhoneById(id);
mmap.put("clewPhone", clewPhone);
return prefix + "/edit";
}
/**
* 修改保存线索手机号
*/
@RequiresPermissions("system:phone:edit")
@Log(title = "线索手机号", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(ClewPhone clewPhone)
{
return toAjax(clewPhoneService.updateClewPhone(clewPhone));
}
/**
* 删除线索手机号
*/
@RequiresPermissions("system:phone:remove")
@Log(title = "线索手机号", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(clewPhoneService.deleteClewPhoneByIds(ids));
}
}

View File

@ -0,0 +1,136 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.ClewVideo;
import com.ruoyi.system.service.IClewVideoService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 线索视频Controller
*
* @author ruoyi
* @date 2023-11-06
*/
@Controller
@RequestMapping("/system/video")
public class ClewVideoController extends BaseController
{
private String prefix = "system/video";
@Autowired
private IClewVideoService clewVideoService;
@RequiresPermissions("system:video:view")
@GetMapping()
public String video()
{
return prefix + "/video";
}
/**
* 查询线索视频列表
*/
@RequiresPermissions("system:video:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(ClewVideo clewVideo)
{
startPage();
List<ClewVideo> list = clewVideoService.selectClewVideoList(clewVideo);
return getDataTable(list);
}
@GetMapping("/app/list")
@ResponseBody
public AjaxResult getAppList(@RequestParam(value = "sourceApp", required = false) Long sourceApp)
{
if(sourceApp == null){
sourceApp = 1L;
}
ClewVideo param = new ClewVideo();
param.setSourceApp(sourceApp);
List<ClewVideo> list = clewVideoService.selectClewVideoList(param);
return AjaxResult.success(list);
}
/**
* 导出线索视频列表
*/
@RequiresPermissions("system:video:export")
@Log(title = "线索视频", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(ClewVideo clewVideo)
{
List<ClewVideo> list = clewVideoService.selectClewVideoList(clewVideo);
ExcelUtil<ClewVideo> util = new ExcelUtil<ClewVideo>(ClewVideo.class);
return util.exportExcel(list, "线索视频数据");
}
/**
* 新增线索视频
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存线索视频
*/
@RequiresPermissions("system:video:add")
@Log(title = "线索视频", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(ClewVideo clewVideo)
{
return toAjax(clewVideoService.insertClewVideo(clewVideo));
}
/**
* 修改线索视频
*/
@RequiresPermissions("system:video:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
ClewVideo clewVideo = clewVideoService.selectClewVideoById(id);
mmap.put("clewVideo", clewVideo);
return prefix + "/edit";
}
/**
* 修改保存线索视频
*/
@RequiresPermissions("system:video:edit")
@Log(title = "线索视频", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(ClewVideo clewVideo)
{
return toAjax(clewVideoService.updateClewVideo(clewVideo));
}
/**
* 删除线索视频
*/
@RequiresPermissions("system:video:remove")
@Log(title = "线索视频", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(clewVideoService.deleteClewVideoByIds(ids));
}
}

View File

@ -0,0 +1,133 @@
package com.ruoyi.web.controller.system;
import java.util.Collection;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.CompanyApp;
import com.ruoyi.system.service.ICompanyAppService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 客户端Controller
*
* @author ruoyi
* @date 2023-05-15
*/
@Controller
@RequestMapping("/system/app")
public class CompanyAppController extends BaseController
{
private String prefix = "system/app";
@Autowired
private ICompanyAppService companyAppService;
@RequiresPermissions("system:app:view")
@GetMapping()
public String app()
{
return prefix + "/app";
}
/**
* 查询客户端列表
*/
@RequiresPermissions("system:app:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(CompanyApp companyApp)
{
startPage();
List<CompanyApp> list = companyAppService.selectCompanyAppList(companyApp);
return getDataTable(list);
}
@PostMapping("/app/getById")
@ResponseBody
public AjaxResult getById(@RequestBody CompanyApp companyApp)
{
return AjaxResult.success(companyAppService.selectCompanyAppById(companyApp.getId()));
}
/**
* 导出客户端列表
*/
@RequiresPermissions("system:app:export")
@Log(title = "客户端", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(CompanyApp companyApp)
{
List<CompanyApp> list = companyAppService.selectCompanyAppList(companyApp);
ExcelUtil<CompanyApp> util = new ExcelUtil<CompanyApp>(CompanyApp.class);
return util.exportExcel(list, "客户端数据");
}
/**
* 新增客户端
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存客户端
*/
@RequiresPermissions("system:app:add")
@Log(title = "客户端", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(CompanyApp companyApp)
{
return toAjax(companyAppService.insertCompanyApp(companyApp));
}
/**
* 修改客户端
*/
@RequiresPermissions("system:app:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
CompanyApp companyApp = companyAppService.selectCompanyAppById(id);
mmap.put("companyApp", companyApp);
return prefix + "/edit";
}
/**
* 修改保存客户端
*/
@RequiresPermissions("system:app:edit")
@Log(title = "客户端", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(CompanyApp companyApp)
{
return toAjax(companyAppService.updateCompanyApp(companyApp));
}
/**
* 删除客户端
*/
@RequiresPermissions("system:app:remove")
@Log(title = "客户端", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(companyAppService.deleteCompanyAppByIds(ids));
}
}

View File

@ -0,0 +1,127 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.Company;
import com.ruoyi.system.service.ICompanyService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 广告主Controller
*
* @author ruoyi
* @date 2023-05-15
*/
@Controller
@RequestMapping("/system/company")
public class CompanyController extends BaseController
{
private String prefix = "system/company";
@Autowired
private ICompanyService companyService;
@RequiresPermissions("system:company:view")
@GetMapping()
public String company()
{
return prefix + "/company";
}
/**
* 查询广告主列表
*/
@RequiresPermissions("system:company:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(Company company)
{
startPage();
List<Company> list = companyService.selectCompanyList(company);
return getDataTable(list);
}
/**
* 导出广告主列表
*/
@RequiresPermissions("system:company:export")
@Log(title = "广告主", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(Company company)
{
List<Company> list = companyService.selectCompanyList(company);
ExcelUtil<Company> util = new ExcelUtil<Company>(Company.class);
return util.exportExcel(list, "广告主数据");
}
/**
* 新增广告主
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存广告主
*/
@RequiresPermissions("system:company:add")
@Log(title = "广告主", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(Company company)
{
return toAjax(companyService.insertCompany(company));
}
/**
* 修改广告主
*/
@RequiresPermissions("system:company:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") String id, ModelMap mmap)
{
Company company = companyService.selectCompanyById(id);
mmap.put("company", company);
return prefix + "/edit";
}
/**
* 修改保存广告主
*/
@RequiresPermissions("system:company:edit")
@Log(title = "广告主", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(Company company)
{
return toAjax(companyService.updateCompany(company));
}
/**
* 删除广告主
*/
@RequiresPermissions("system:company:remove")
@Log(title = "广告主", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(companyService.deleteCompanyByIds(ids));
}
}

View File

@ -0,0 +1,127 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.CompanySale;
import com.ruoyi.system.service.ICompanySaleService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 广告主销售Controller
*
* @author ruoyi
* @date 2023-05-15
*/
@Controller
@RequestMapping("/system/sale")
public class CompanySaleController extends BaseController
{
private String prefix = "system/sale";
@Autowired
private ICompanySaleService companySaleService;
@RequiresPermissions("system:sale:view")
@GetMapping()
public String sale()
{
return prefix + "/sale";
}
/**
* 查询广告主销售列表
*/
@RequiresPermissions("system:sale:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(CompanySale companySale)
{
startPage();
List<CompanySale> list = companySaleService.selectCompanySaleList(companySale);
return getDataTable(list);
}
/**
* 导出广告主销售列表
*/
@RequiresPermissions("system:sale:export")
@Log(title = "广告主销售", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(CompanySale companySale)
{
List<CompanySale> list = companySaleService.selectCompanySaleList(companySale);
ExcelUtil<CompanySale> util = new ExcelUtil<CompanySale>(CompanySale.class);
return util.exportExcel(list, "广告主销售数据");
}
/**
* 新增广告主销售
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存广告主销售
*/
@RequiresPermissions("system:sale:add")
@Log(title = "广告主销售", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(CompanySale companySale)
{
return toAjax(companySaleService.insertCompanySale(companySale));
}
/**
* 修改广告主销售
*/
@RequiresPermissions("system:sale:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
CompanySale companySale = companySaleService.selectCompanySaleById(id);
mmap.put("companySale", companySale);
return prefix + "/edit";
}
/**
* 修改保存广告主销售
*/
@RequiresPermissions("system:sale:edit")
@Log(title = "广告主销售", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(CompanySale companySale)
{
return toAjax(companySaleService.updateCompanySale(companySale));
}
/**
* 删除广告主销售
*/
@RequiresPermissions("system:sale:remove")
@Log(title = "广告主销售", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(companySaleService.deleteCompanySaleByIds(ids));
}
}

View File

@ -0,0 +1,163 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.domain.CustomerServiceReply;
import com.ruoyi.system.service.ICustomerServiceReplyService;
/**
* 客服回复规则App接口Controller
*
* @author ruoyi
* @date 2024-01-01
*/
@RestController
@RequestMapping("/system/customerServiceReply/app")
public class CustomerServiceReplyAppController extends BaseController
{
@Autowired
private ICustomerServiceReplyService customerServiceReplyService;
/**
* 根据用户输入获取最佳回复
*/
@PostMapping("/getReply")
public AjaxResult getReply(@RequestBody CustomerServiceReply customerServiceReply)
{
try {
String userInput = customerServiceReply.getKeyword();
if (userInput == null || userInput.trim().isEmpty()) {
return AjaxResult.error("用户输入不能为空");
}
CustomerServiceReply reply = customerServiceReplyService.getBestReply(userInput.trim());
return AjaxResult.success(reply);
} catch (Exception e) {
logger.error("获取回复失败", e);
return AjaxResult.error("获取回复失败:" + e.getMessage());
}
}
/**
* 根据用户输入获取最佳回复GET方式
*/
@GetMapping("/getReply")
public AjaxResult getReplyGet(@RequestParam("keyword") String keyword)
{
try {
if (keyword == null || keyword.trim().isEmpty()) {
return AjaxResult.error("用户输入不能为空");
}
CustomerServiceReply reply = customerServiceReplyService.getBestReply(keyword.trim());
return AjaxResult.success(reply);
} catch (Exception e) {
logger.error("获取回复失败", e);
return AjaxResult.error("获取回复失败:" + e.getMessage());
}
}
/**
* 根据关键字查询回复列表
*/
@PostMapping("/getReplyList")
public AjaxResult getReplyList(@RequestBody CustomerServiceReply customerServiceReply)
{
try {
String keyword = customerServiceReply.getKeyword();
if (keyword == null || keyword.trim().isEmpty()) {
return AjaxResult.error("关键字不能为空");
}
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyByKeyword(keyword.trim());
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询回复列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 根据关键字查询回复列表GET方式
*/
@GetMapping("/getReplyList")
public AjaxResult getReplyListGet(@RequestParam("keyword") String keyword,
@RequestParam(value = "limit", defaultValue = "10") Integer limit)
{
try {
if (keyword == null || keyword.trim().isEmpty()) {
return AjaxResult.error("关键字不能为空");
}
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyByKeyword(keyword.trim());
// 限制返回数量
if (limit != null && limit > 0 && list.size() > limit) {
list = list.subList(0, limit);
}
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询回复列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 获取所有客服回复规则列表
*/
@GetMapping("/list")
public AjaxResult list()
{
try {
CustomerServiceReply query = new CustomerServiceReply();
query.setIsActive(1); // 只查询启用状态的数据
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyList(query);
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询客服回复规则列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 根据分类获取客服回复规则列表
*/
@GetMapping("/listByCategory")
public AjaxResult listByCategory(@RequestParam("category") String category)
{
try {
CustomerServiceReply query = new CustomerServiceReply();
query.setIsActive(1); // 只查询启用状态的数据
query.setCategory(category);
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyList(query);
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("根据分类查询客服回复规则列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 获取默认回复
*/
@GetMapping("/getDefaultReply")
public AjaxResult getDefaultReply()
{
try {
CustomerServiceReply reply = customerServiceReplyService.selectDefaultReply();
return AjaxResult.success(reply);
} catch (Exception e) {
logger.error("获取默认回复失败", e);
return AjaxResult.error("获取默认回复失败:" + e.getMessage());
}
}
}

View File

@ -0,0 +1,253 @@
package com.ruoyi.web.controller.system;
import java.util.Date;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestParam;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.DutyConfig;
import com.ruoyi.system.service.IDutyConfigService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.entity.SysUser;
/**
* 值班配置Controller
*
* @author ruoyi
* @date 2024-12-19
*/
@Controller
@RequestMapping("/system/dutyConfig")
public class DutyConfigController extends BaseController
{
private String prefix = "system/dutyConfig";
@Autowired
private IDutyConfigService dutyConfigService;
@Autowired
private ISysUserService userService;
@RequiresPermissions("system:dutyConfig:view")
@GetMapping()
public String dutyConfig()
{
return prefix + "/dutyConfig";
}
/**
* 查询值班配置列表
*/
@RequiresPermissions("system:dutyConfig:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(DutyConfig dutyConfig)
{
startPage();
List<DutyConfig> list = dutyConfigService.selectDutyConfigList(dutyConfig);
return getDataTable(list);
}
/**
* 导出值班配置列表
*/
@RequiresPermissions("system:dutyConfig:export")
@Log(title = "值班配置", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(DutyConfig dutyConfig)
{
List<DutyConfig> list = dutyConfigService.selectDutyConfigList(dutyConfig);
ExcelUtil<DutyConfig> util = new ExcelUtil<DutyConfig>(DutyConfig.class);
return util.exportExcel(list, "值班配置数据");
}
/**
* 新增值班配置
*/
@GetMapping("/add")
public String add(ModelMap mmap)
{
// 获取所有可用用户
SysUser user = new SysUser();
user.setStatus("0"); // 正常状态
List<SysUser> users = userService.selectUserList(user);
mmap.put("users", users);
return prefix + "/add";
}
/**
* 新增保存值班配置
*/
@RequiresPermissions("system:dutyConfig:add")
@Log(title = "值班配置", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(DutyConfig dutyConfig, @RequestParam("dutyUserIds") String dutyUserIds)
{
// 验证时间范围
if (dutyConfig.getStartTime() == null || dutyConfig.getEndTime() == null) {
return error("开始时间和结束时间不能为空");
}
if (dutyConfig.getStartTime().compareTo(dutyConfig.getEndTime()) >= 0) {
return error("开始时间必须早于结束时间");
}
// 检查时间段是否冲突
if (dutyConfigService.checkTimeConflict(dutyConfig.getStartTime(), dutyConfig.getEndTime(), null)) {
return error("该时间段与现有配置冲突,请重新选择时间");
}
// 验证值班用户
if (dutyUserIds == null || dutyUserIds.trim().isEmpty()) {
return error("值班用户不能为空");
}
dutyConfig.setCreateBy(getLoginName());
// Service层会处理dutyUserIds参数
return toAjax(dutyConfigService.insertDutyConfig(dutyConfig, dutyUserIds));
}
/**
* 修改值班配置
*/
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
DutyConfig dutyConfig = dutyConfigService.selectDutyConfigById(id);
mmap.put("dutyConfig", dutyConfig);
// 获取所有可用用户
SysUser user = new SysUser();
user.setStatus("0"); // 正常状态
List<SysUser> users = userService.selectUserList(user);
mmap.put("users", users);
return prefix + "/edit";
}
/**
* 修改保存值班配置
*/
@RequiresPermissions("system:dutyConfig:edit")
@Log(title = "值班配置", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(DutyConfig dutyConfig, @RequestParam("dutyUserIds") String dutyUserIds)
{
// 验证时间范围
if (dutyConfig.getStartTime() == null || dutyConfig.getEndTime() == null) {
return error("开始时间和结束时间不能为空");
}
if (dutyConfig.getStartTime().compareTo(dutyConfig.getEndTime()) >= 0) {
return error("开始时间必须早于结束时间");
}
// 检查时间段是否冲突排除自己
if (dutyConfigService.checkTimeConflict(dutyConfig.getStartTime(), dutyConfig.getEndTime(), dutyConfig.getId())) {
return error("该时间段与现有配置冲突,请重新选择时间");
}
// 验证值班用户
if (dutyUserIds == null || dutyUserIds.trim().isEmpty()) {
return error("值班用户不能为空");
}
dutyConfig.setUpdateBy(getLoginName());
// Service层会处理dutyUserIds参数
return toAjax(dutyConfigService.updateDutyConfig(dutyConfig, dutyUserIds));
}
/**
* 删除值班配置
*/
@RequiresPermissions("system:dutyConfig:remove")
@Log(title = "值班配置", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(dutyConfigService.deleteDutyConfigByIds(ids));
}
/**
* 修改值班配置状态
*/
@RequiresPermissions("system:dutyConfig:edit")
@Log(title = "值班配置", businessType = BusinessType.UPDATE)
@PostMapping("/changeStatus")
@ResponseBody
public AjaxResult changeStatus(DutyConfig dutyConfig)
{
dutyConfig.setUpdateBy(getLoginName());
return toAjax(dutyConfigService.changeStatus(dutyConfig));
}
/**
* 获取可用用户列表
*/
@GetMapping("/getAvailableUsers")
@ResponseBody
public AjaxResult getAvailableUsers()
{
SysUser user = new SysUser();
user.setStatus("0"); // 正常状态
List<SysUser> users = userService.selectUserList(user);
return AjaxResult.success(users);
}
/**
* 获取当前值班用户
*/
@GetMapping("/getCurrentDutyUser")
@ResponseBody
public AjaxResult getCurrentDutyUser()
{
Long dutyUserId = dutyConfigService.getNextDutyUserId();
if (dutyUserId != null) {
SysUser user = userService.selectUserById(dutyUserId);
return AjaxResult.success(user);
}
return AjaxResult.error("当前没有值班配置");
}
/**
* 查看值班配置详情
*/
@RequiresPermissions("system:dutyConfig:view")
@GetMapping("/detail/{id}")
public String detail(@PathVariable("id") Long id, ModelMap mmap)
{
DutyConfig dutyConfig = dutyConfigService.selectDutyConfigById(id);
// 设置是否在当前时间范围内
if (dutyConfig != null) {
Date now = new Date();
if ("1".equals(dutyConfig.getStatus()) &&
dutyConfig.getStartTime() != null && dutyConfig.getEndTime() != null) {
dutyConfig.setIsActive(now.compareTo(dutyConfig.getStartTime()) >= 0 &&
now.compareTo(dutyConfig.getEndTime()) <= 0);
} else {
dutyConfig.setIsActive(false);
}
}
mmap.put("dutyConfig", dutyConfig);
return prefix + "/detail";
}
}

View File

@ -0,0 +1,48 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import com.ruoyi.system.domain.MaterialStatsDaily;
import com.ruoyi.system.service.IMaterialStatsDailyService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/system/material/stats")
public class MaterialStatsDailyController extends BaseController
{
@Autowired
private IMaterialStatsDailyService statsService;
/**
* 分页查询素材转化统计
*/
@PostMapping("/list")
public TableDataInfo list(@RequestParam(value = "appName", required = false) String appName,
@RequestParam(value = "appSource", required = false) String appSource,
@RequestParam(value = "startDate", required = false) String startDate,
@RequestParam(value = "endDate", required = false) String endDate)
{
startPage();
List<MaterialStatsDaily> list = statsService.selectStats(appName, appSource, startDate, endDate);
for (MaterialStatsDaily item : list) {
item.setAppSource(mapSource(item.getAppSource()));
}
return getDataTable(list);
}
private String mapSource(String code) {
if (code == null || code.trim().isEmpty()) return "未知";
switch (code.trim()) {
case "1": return "OPPO";
case "2": return "vivo";
case "3": return "华为";
case "4": return "小米";
case "5": return "应用宝";
case "6": return "百度";
default: return code;
}
}
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.web.controller.system;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/system/material")
public class MaterialStatsDailyViewController {
@GetMapping("/statsPage")
public String statsPage() {
return "system/material/stats";
}
}

View File

@ -162,20 +162,6 @@ public class SysUserController extends BaseController
return prefix + "/edit";
}
/**
* 查询用户详细
*/
@RequiresPermissions("system:user:list")
@GetMapping("/view/{userId}")
public String view(@PathVariable("userId") Long userId, ModelMap mmap)
{
userService.checkUserDataScope(userId);
mmap.put("user", userService.selectUserById(userId));
mmap.put("roleGroup", userService.selectUserRoleGroup(userId));
mmap.put("postGroup", userService.selectUserPostGroup(userId));
return prefix + "/view";
}
/**
* 修改保存用户
*/

View File

@ -0,0 +1,127 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TaskData;
import com.ruoyi.system.service.ITaskDataService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 归因数据回传Controller
*
* @author ruoyi
* @date 2023-10-29
*/
@Controller
@RequestMapping("/system/data")
public class TaskDataController extends BaseController
{
private String prefix = "system/data";
@Autowired
private ITaskDataService taskDataService;
@RequiresPermissions("system:data:view")
@GetMapping()
public String data()
{
return prefix + "/data";
}
/**
* 查询归因数据回传列表
*/
@RequiresPermissions("system:data:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TaskData taskData)
{
startPage();
List<TaskData> list = taskDataService.selectTaskDataList(taskData);
return getDataTable(list);
}
/**
* 导出归因数据回传列表
*/
@RequiresPermissions("system:data:export")
@Log(title = "归因数据回传", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TaskData taskData)
{
List<TaskData> list = taskDataService.selectTaskDataList(taskData);
ExcelUtil<TaskData> util = new ExcelUtil<TaskData>(TaskData.class);
return util.exportExcel(list, "归因数据回传数据");
}
/**
* 新增归因数据回传
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存归因数据回传
*/
@RequiresPermissions("system:data:add")
@Log(title = "归因数据回传", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TaskData taskData)
{
return toAjax(taskDataService.insertTaskData(taskData));
}
/**
* 修改归因数据回传
*/
@RequiresPermissions("system:data:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TaskData taskData = taskDataService.selectTaskDataById(id);
mmap.put("taskData", taskData);
return prefix + "/edit";
}
/**
* 修改保存归因数据回传
*/
@RequiresPermissions("system:data:edit")
@Log(title = "归因数据回传", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TaskData taskData)
{
return toAjax(taskDataService.updateTaskData(taskData));
}
/**
* 删除归因数据回传
*/
@RequiresPermissions("system:data:remove")
@Log(title = "归因数据回传", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(taskDataService.deleteTaskDataByIds(ids));
}
}

View File

@ -1,127 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbMatchSingleSay;
import com.ruoyi.system.service.ITbMatchSingleSayService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 媒婆说Controller
*
* @author ruoyi
* @date 2023-12-26
*/
@Controller
@RequestMapping("/system/say")
public class TbMatchSingleSayController extends BaseController
{
private String prefix = "system/say";
@Autowired
private ITbMatchSingleSayService tbMatchSingleSayService;
@RequiresPermissions("system:say:view")
@GetMapping()
public String say()
{
return prefix + "/say";
}
/**
* 查询媒婆说列表
*/
@RequiresPermissions("system:say:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbMatchSingleSay tbMatchSingleSay)
{
startPage();
List<TbMatchSingleSay> list = tbMatchSingleSayService.selectTbMatchSingleSayList(tbMatchSingleSay);
return getDataTable(list);
}
/**
* 导出媒婆说列表
*/
@RequiresPermissions("system:say:export")
@Log(title = "媒婆说", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbMatchSingleSay tbMatchSingleSay)
{
List<TbMatchSingleSay> list = tbMatchSingleSayService.selectTbMatchSingleSayList(tbMatchSingleSay);
ExcelUtil<TbMatchSingleSay> util = new ExcelUtil<TbMatchSingleSay>(TbMatchSingleSay.class);
return util.exportExcel(list, "媒婆说数据");
}
/**
* 新增媒婆说
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存媒婆说
*/
@RequiresPermissions("system:say:add")
@Log(title = "媒婆说", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbMatchSingleSay tbMatchSingleSay)
{
return toAjax(tbMatchSingleSayService.insertTbMatchSingleSay(tbMatchSingleSay));
}
/**
* 修改媒婆说
*/
@RequiresPermissions("system:say:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbMatchSingleSay tbMatchSingleSay = tbMatchSingleSayService.selectTbMatchSingleSayById(id);
mmap.put("tbMatchSingleSay", tbMatchSingleSay);
return prefix + "/edit";
}
/**
* 修改保存媒婆说
*/
@RequiresPermissions("system:say:edit")
@Log(title = "媒婆说", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbMatchSingleSay tbMatchSingleSay)
{
return toAjax(tbMatchSingleSayService.updateTbMatchSingleSay(tbMatchSingleSay));
}
/**
* 删除媒婆说
*/
@RequiresPermissions("system:say:remove")
@Log(title = "媒婆说", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbMatchSingleSayService.deleteTbMatchSingleSayByIds(ids));
}
}

View File

@ -1,127 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbUserBlock;
import com.ruoyi.system.service.ITbUserBlockService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 单身用户不喜欢列Controller
*
* @author ruoyi
* @date 2024-02-18
*/
@Controller
@RequestMapping("/system/block")
public class TbUserBlockController extends BaseController
{
private String prefix = "system/block";
@Autowired
private ITbUserBlockService tbUserBlockService;
@RequiresPermissions("system:block:view")
@GetMapping()
public String block()
{
return prefix + "/block";
}
/**
* 查询单身用户不喜欢列列表
*/
@RequiresPermissions("system:block:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbUserBlock tbUserBlock)
{
startPage();
List<TbUserBlock> list = tbUserBlockService.selectTbUserBlockList(tbUserBlock);
return getDataTable(list);
}
/**
* 导出单身用户不喜欢列列表
*/
@RequiresPermissions("system:block:export")
@Log(title = "单身用户不喜欢列", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbUserBlock tbUserBlock)
{
List<TbUserBlock> list = tbUserBlockService.selectTbUserBlockList(tbUserBlock);
ExcelUtil<TbUserBlock> util = new ExcelUtil<TbUserBlock>(TbUserBlock.class);
return util.exportExcel(list, "单身用户不喜欢列数据");
}
/**
* 新增单身用户不喜欢列
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存单身用户不喜欢列
*/
@RequiresPermissions("system:block:add")
@Log(title = "单身用户不喜欢列", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbUserBlock tbUserBlock)
{
return toAjax(tbUserBlockService.insertTbUserBlock(tbUserBlock));
}
/**
* 修改单身用户不喜欢列
*/
@RequiresPermissions("system:block:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbUserBlock tbUserBlock = tbUserBlockService.selectTbUserBlockById(id);
mmap.put("tbUserBlock", tbUserBlock);
return prefix + "/edit";
}
/**
* 修改保存单身用户不喜欢列
*/
@RequiresPermissions("system:block:edit")
@Log(title = "单身用户不喜欢列", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbUserBlock tbUserBlock)
{
return toAjax(tbUserBlockService.updateTbUserBlock(tbUserBlock));
}
/**
* 删除单身用户不喜欢列
*/
@RequiresPermissions("system:block:remove")
@Log(title = "单身用户不喜欢列", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbUserBlockService.deleteTbUserBlockByIds(ids));
}
}

View File

@ -1,127 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbUserFollow;
import com.ruoyi.system.service.ITbUserFollowService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 用户关注列Controller
*
* @author ruoyi
* @date 2023-12-13
*/
@Controller
@RequestMapping("/system/follow")
public class TbUserFollowController extends BaseController
{
private String prefix = "system/follow";
@Autowired
private ITbUserFollowService tbUserFollowService;
@RequiresPermissions("system:follow:view")
@GetMapping()
public String follow()
{
return prefix + "/follow";
}
/**
* 查询用户关注列列表
*/
@RequiresPermissions("system:follow:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbUserFollow tbUserFollow)
{
startPage();
List<TbUserFollow> list = tbUserFollowService.selectTbUserFollowList(tbUserFollow);
return getDataTable(list);
}
/**
* 导出用户关注列列表
*/
@RequiresPermissions("system:follow:export")
@Log(title = "用户关注列", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbUserFollow tbUserFollow)
{
List<TbUserFollow> list = tbUserFollowService.selectTbUserFollowList(tbUserFollow);
ExcelUtil<TbUserFollow> util = new ExcelUtil<TbUserFollow>(TbUserFollow.class);
return util.exportExcel(list, "用户关注列数据");
}
/**
* 新增用户关注列
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存用户关注列
*/
@RequiresPermissions("system:follow:add")
@Log(title = "用户关注列", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbUserFollow tbUserFollow)
{
return toAjax(tbUserFollowService.insertTbUserFollow(tbUserFollow));
}
/**
* 修改用户关注列
*/
@RequiresPermissions("system:follow:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbUserFollow tbUserFollow = tbUserFollowService.selectTbUserFollowById(id);
mmap.put("tbUserFollow", tbUserFollow);
return prefix + "/edit";
}
/**
* 修改保存用户关注列
*/
@RequiresPermissions("system:follow:edit")
@Log(title = "用户关注列", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbUserFollow tbUserFollow)
{
return toAjax(tbUserFollowService.updateTbUserFollow(tbUserFollow));
}
/**
* 删除用户关注列
*/
@RequiresPermissions("system:follow:remove")
@Log(title = "用户关注列", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbUserFollowService.deleteTbUserFollowByIds(ids));
}
}

View File

@ -1,127 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbUserImg;
import com.ruoyi.system.service.ITbUserImgService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 用户图片附件Controller
*
* @author ruoyi
* @date 2023-12-11
*/
@Controller
@RequestMapping("/system/img")
public class TbUserImgController extends BaseController
{
private String prefix = "system/img";
@Autowired
private ITbUserImgService tbUserImgService;
@RequiresPermissions("system:img:view")
@GetMapping()
public String img()
{
return prefix + "/img";
}
/**
* 查询用户图片附件列表
*/
@RequiresPermissions("system:img:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbUserImg tbUserImg)
{
startPage();
List<TbUserImg> list = tbUserImgService.selectTbUserImgList(tbUserImg);
return getDataTable(list);
}
/**
* 导出用户图片附件列表
*/
@RequiresPermissions("system:img:export")
@Log(title = "用户图片附件", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbUserImg tbUserImg)
{
List<TbUserImg> list = tbUserImgService.selectTbUserImgList(tbUserImg);
ExcelUtil<TbUserImg> util = new ExcelUtil<TbUserImg>(TbUserImg.class);
return util.exportExcel(list, "用户图片附件数据");
}
/**
* 新增用户图片附件
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存用户图片附件
*/
@RequiresPermissions("system:img:add")
@Log(title = "用户图片附件", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbUserImg tbUserImg)
{
return toAjax(tbUserImgService.insertTbUserImg(tbUserImg));
}
/**
* 修改用户图片附件
*/
@RequiresPermissions("system:img:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbUserImg tbUserImg = tbUserImgService.selectTbUserImgById(id);
mmap.put("tbUserImg", tbUserImg);
return prefix + "/edit";
}
/**
* 修改保存用户图片附件
*/
@RequiresPermissions("system:img:edit")
@Log(title = "用户图片附件", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbUserImg tbUserImg)
{
return toAjax(tbUserImgService.updateTbUserImg(tbUserImg));
}
/**
* 删除用户图片附件
*/
@RequiresPermissions("system:img:remove")
@Log(title = "用户图片附件", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbUserImgService.deleteTbUserImgByIds(ids));
}
}

View File

@ -1,139 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import com.ruoyi.system.domain.TbUser;
import com.ruoyi.system.service.ITbUserService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbUserMatch;
import com.ruoyi.system.service.ITbUserMatchService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 合伙人信息Controller
*
* @author ruoyi
* @date 2023-12-15
*/
@Controller
@RequestMapping("/system/match")
public class TbUserMatchController extends BaseController
{
private String prefix = "system/match";
@Autowired
private ITbUserMatchService tbUserMatchService;
@Autowired
private ITbUserService tbUserService;
@RequiresPermissions("system:match:view")
@GetMapping()
public String match()
{
return prefix + "/match";
}
/**
* 查询合伙人信息列表
*/
@RequiresPermissions("system:match:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbUserMatch tbUserMatch)
{
startPage();
List<TbUserMatch> list = tbUserMatchService.selectTbUserMatchList(tbUserMatch);
list.forEach(model->{
TbUser user = tbUserService.getById(model.getUserId());
if(user != null){
model.setMobile(user.getMobile());
}
});
return getDataTable(list);
}
/**
* 导出合伙人信息列表
*/
@RequiresPermissions("system:match:export")
@Log(title = "合伙人信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbUserMatch tbUserMatch)
{
List<TbUserMatch> list = tbUserMatchService.selectTbUserMatchList(tbUserMatch);
ExcelUtil<TbUserMatch> util = new ExcelUtil<TbUserMatch>(TbUserMatch.class);
return util.exportExcel(list, "合伙人信息数据");
}
/**
* 新增合伙人信息
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存合伙人信息
*/
@RequiresPermissions("system:match:add")
@Log(title = "合伙人信息", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbUserMatch tbUserMatch)
{
return toAjax(tbUserMatchService.insertTbUserMatch(tbUserMatch));
}
/**
* 修改合伙人信息
*/
@RequiresPermissions("system:match:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbUserMatch tbUserMatch = tbUserMatchService.selectTbUserMatchById(id);
mmap.put("tbUserMatch", tbUserMatch);
return prefix + "/edit";
}
/**
* 修改保存合伙人信息
*/
@RequiresPermissions("system:match:edit")
@Log(title = "合伙人信息", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbUserMatch tbUserMatch)
{
return toAjax(tbUserMatchService.updateTbUserMatch(tbUserMatch));
}
/**
* 删除合伙人信息
*/
@RequiresPermissions("system:match:remove")
@Log(title = "合伙人信息", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbUserMatchService.deleteTbUserMatchByIds(ids));
}
}

View File

@ -1,127 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbUserMatchGroup;
import com.ruoyi.system.service.ITbUserMatchGroupService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 媒婆团Controller
*
* @author ruoyi
* @date 2023-12-16
*/
@Controller
@RequestMapping("/system/group")
public class TbUserMatchGroupController extends BaseController
{
private String prefix = "system/group";
@Autowired
private ITbUserMatchGroupService tbUserMatchGroupService;
@RequiresPermissions("system:group:view")
@GetMapping()
public String group()
{
return prefix + "/group";
}
/**
* 查询媒婆团列表
*/
@RequiresPermissions("system:group:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbUserMatchGroup tbUserMatchGroup)
{
startPage();
List<TbUserMatchGroup> list = tbUserMatchGroupService.selectTbUserMatchGroupList(tbUserMatchGroup);
return getDataTable(list);
}
/**
* 导出媒婆团列表
*/
@RequiresPermissions("system:group:export")
@Log(title = "媒婆团", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbUserMatchGroup tbUserMatchGroup)
{
List<TbUserMatchGroup> list = tbUserMatchGroupService.selectTbUserMatchGroupList(tbUserMatchGroup);
ExcelUtil<TbUserMatchGroup> util = new ExcelUtil<TbUserMatchGroup>(TbUserMatchGroup.class);
return util.exportExcel(list, "媒婆团数据");
}
/**
* 新增媒婆团
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存媒婆团
*/
@RequiresPermissions("system:group:add")
@Log(title = "媒婆团", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbUserMatchGroup tbUserMatchGroup)
{
return toAjax(tbUserMatchGroupService.insertTbUserMatchGroup(tbUserMatchGroup));
}
/**
* 修改媒婆团
*/
@RequiresPermissions("system:group:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbUserMatchGroup tbUserMatchGroup = tbUserMatchGroupService.selectTbUserMatchGroupById(id);
mmap.put("tbUserMatchGroup", tbUserMatchGroup);
return prefix + "/edit";
}
/**
* 修改保存媒婆团
*/
@RequiresPermissions("system:group:edit")
@Log(title = "媒婆团", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbUserMatchGroup tbUserMatchGroup)
{
return toAjax(tbUserMatchGroupService.updateTbUserMatchGroup(tbUserMatchGroup));
}
/**
* 删除媒婆团
*/
@RequiresPermissions("system:group:remove")
@Log(title = "媒婆团", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbUserMatchGroupService.deleteTbUserMatchGroupByIds(ids));
}
}

View File

@ -1,151 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import com.ruoyi.system.domain.TbUserMatch;
import com.ruoyi.system.domain.TbUserSingle;
import com.ruoyi.system.service.ITbUserMatchService;
import com.ruoyi.system.service.ITbUserSingleService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbUserMatchOrder;
import com.ruoyi.system.service.ITbUserMatchOrderService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 合伙人开通订单Controller
*
* @author ruoyi
* @date 2023-12-14
*/
@Controller
@RequestMapping("/system/order")
public class TbUserMatchOrderController extends BaseController
{
private String prefix = "system/order";
@Autowired
private ITbUserMatchOrderService tbUserMatchOrderService;
@Autowired
private ITbUserSingleService tbUserSingleService;
@Autowired
private ITbUserMatchService tbUserMatchService;
@RequiresPermissions("system:order:view")
@GetMapping()
public String order()
{
return prefix + "/order";
}
/**
* 查询合伙人开通订单列表
*/
@RequiresPermissions("system:order:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbUserMatchOrder tbUserMatchOrder)
{
startPage();
List<TbUserMatchOrder> list = tbUserMatchOrderService.selectTbUserMatchOrderList(tbUserMatchOrder);
list.forEach(order->{
if(order.getOrderType() == 6){
TbUserMatch tbUserMatch = tbUserMatchService.lambdaQuery().eq(TbUserMatch::getUserId, order.getUserId()).one();
if(tbUserMatch!=null){
order.setUserName(tbUserMatch.getNickName());
}
}else {
TbUserSingle tbUserSingle = tbUserSingleService.lambdaQuery().eq(TbUserSingle::getUserId, order.getUserId()).one();
if(tbUserSingle!=null){
order.setUserName(tbUserSingle.getNickName());
}
}
});
return getDataTable(list);
}
/**
* 导出合伙人开通订单列表
*/
@RequiresPermissions("system:order:export")
@Log(title = "合伙人开通订单", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbUserMatchOrder tbUserMatchOrder)
{
List<TbUserMatchOrder> list = tbUserMatchOrderService.selectTbUserMatchOrderList(tbUserMatchOrder);
ExcelUtil<TbUserMatchOrder> util = new ExcelUtil<TbUserMatchOrder>(TbUserMatchOrder.class);
return util.exportExcel(list, "合伙人开通订单数据");
}
/**
* 新增合伙人开通订单
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存合伙人开通订单
*/
@RequiresPermissions("system:order:add")
@Log(title = "合伙人开通订单", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbUserMatchOrder tbUserMatchOrder)
{
return toAjax(tbUserMatchOrderService.insertTbUserMatchOrder(tbUserMatchOrder));
}
/**
* 修改合伙人开通订单
*/
@RequiresPermissions("system:order:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbUserMatchOrder tbUserMatchOrder = tbUserMatchOrderService.selectTbUserMatchOrderById(id);
mmap.put("tbUserMatchOrder", tbUserMatchOrder);
return prefix + "/edit";
}
/**
* 修改保存合伙人开通订单
*/
@RequiresPermissions("system:order:edit")
@Log(title = "合伙人开通订单", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbUserMatchOrder tbUserMatchOrder)
{
return toAjax(tbUserMatchOrderService.updateTbUserMatchOrder(tbUserMatchOrder));
}
/**
* 删除合伙人开通订单
*/
@RequiresPermissions("system:order:remove")
@Log(title = "合伙人开通订单", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbUserMatchOrderService.deleteTbUserMatchOrderByIds(ids));
}
}

View File

@ -1,169 +0,0 @@
package com.ruoyi.web.controller.system;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.ruoyi.system.domain.TbUser;
import com.ruoyi.system.service.ITbUserService;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.TbUserSingle;
import com.ruoyi.system.service.ITbUserSingleService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 用户单身信息Controller
*
* @author ruoyi
* @date 2023-12-08
*/
@Controller
@RequestMapping("/system/single")
public class TbUserSingleController extends BaseController
{
private String prefix = "system/single";
@Autowired
private ITbUserSingleService tbUserSingleService;
@Autowired
private ITbUserService tbUserService;
@RequiresPermissions("system:single:view")
@GetMapping()
public String single()
{
return prefix + "/single";
}
/**
* 查询用户单身信息列表
*/
@RequiresPermissions("system:single:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(TbUserSingle tbUserSingle)
{
startPage();
List<TbUserSingle> list = tbUserSingleService.selectTbUserSingleList(tbUserSingle);
list.forEach(model->{
TbUser user = tbUserService.getById(model.getUserId());
if(user != null){
model.setMobile(user.getMobile());
}
});
return getDataTable(list);
}
/**
* 导出用户单身信息列表
*/
@RequiresPermissions("system:single:export")
@Log(title = "用户单身信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ResponseBody
public AjaxResult export(TbUserSingle tbUserSingle)
{
List<TbUserSingle> list = tbUserSingleService.selectTbUserSingleList(tbUserSingle);
ExcelUtil<TbUserSingle> util = new ExcelUtil<TbUserSingle>(TbUserSingle.class);
return util.exportExcel(list, "用户单身信息数据");
}
/**
* 查询字典详细
*/
@GetMapping("/detail/{userId}")
public String detail(@PathVariable("userId") Long userId, ModelMap mmap)
{
mmap.put("userId", userId);
return "system/single/singleImg";
}
@PostMapping("/audit")
@ResponseBody
public AjaxResult audit(String ids, Long status){
try {
List<Long> idList = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
List<TbUserSingle> userSingles = this.tbUserSingleService.lambdaQuery().in(TbUserSingle::getId, idList).list();
userSingles.forEach(single->{
single.setStatus(status.intValue());
});
return toAjax(tbUserSingleService.updateBatchById(userSingles));
}catch (Exception e){
logger.error(ExceptionUtils.getStackTrace(e));
return AjaxResult.error(ExceptionUtils.getMessage(e));
}
}
/**
* 新增用户单身信息
*/
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 新增保存用户单身信息
*/
@RequiresPermissions("system:single:add")
@Log(title = "用户单身信息", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(TbUserSingle tbUserSingle)
{
return toAjax(tbUserSingleService.insertTbUserSingle(tbUserSingle));
}
/**
* 修改用户单身信息
*/
@RequiresPermissions("system:single:edit")
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap)
{
TbUserSingle tbUserSingle = tbUserSingleService.selectTbUserSingleById(id);
mmap.put("tbUserSingle", tbUserSingle);
return prefix + "/edit";
}
/**
* 修改保存用户单身信息
*/
@RequiresPermissions("system:single:edit")
@Log(title = "用户单身信息", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(TbUserSingle tbUserSingle)
{
return toAjax(tbUserSingleService.updateTbUserSingle(tbUserSingle));
}
/**
* 删除用户单身信息
*/
@RequiresPermissions("system:single:remove")
@Log(title = "用户单身信息", businessType = BusinessType.DELETE)
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(tbUserSingleService.deleteTbUserSingleByIds(ids));
}
}

View File

@ -1,42 +0,0 @@
package com.ruoyi.web.controller.tool;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.system.domain.TbUser;
import com.ruoyi.system.service.ITbUserService;
import com.ruoyi.web.request.CommonReq;
import com.ruoyi.web.response.HxResp;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>环信接口</p>
* @author clunt
*/
@RestController
@Api(tags = "App*环信接口")
@RequestMapping(value = "/tool/hx")
public class HxController {
private static final String HX_END_STRING = "_pingban_youban";
@Autowired
private ITbUserService tbUserService;
@ResponseBody
@ApiOperation(value = "通过用户id,获取环信账号密码,只需要传id即可")
@PostMapping("/getByUserId")
public Result<HxResp> getByUserId(@RequestBody CommonReq commonReq){
TbUser user = tbUserService.getById(commonReq.getId());
if(user == null){
return Result.error("用户不存在!");
}
HxResp hxResp = new HxResp();
hxResp.setUsername(String.valueOf(user.getId()));
hxResp.setPassword(DigestUtils.md5Hex(user.getId() + HX_END_STRING));
return Result.success(hxResp);
}
}

View File

@ -0,0 +1,339 @@
package com.ruoyi.web.controller.tool;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.google.gson.Gson;
import com.ruoyi.common.config.BaiduConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.CacheUtils;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.security.Md5Utils;
import com.ruoyi.system.domain.ClewPhone;
import com.ruoyi.system.domain.NoticeRequest;
import com.ruoyi.system.domain.OppoCheck;
import com.ruoyi.system.service.IClewPhoneService;
import com.ruoyi.web.core.config.GlobalLogHelper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.security.GeneralSecurityException;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import javax.validation.Valid;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.ruoyi.common.utils.http.HttpUtils.sendPost;
/**
* @author clunt
* 通知模块
*/
@Slf4j
@Controller
@RequestMapping("/tool/notice")
public class NoticeController {
@Autowired
private BaiduConfig baiduConfig;
@Autowired
private IClewPhoneService clewPhoneService;
@PostMapping("/logout")
@ResponseBody
public AjaxResult logout(@RequestBody NoticeRequest request){
return AjaxResult.success("注销成功!");
}
@GetMapping("/exposure")
@ResponseBody
public AjaxResult exposure(){
return AjaxResult.success("曝光成功!");
}
@GetMapping("/click")
@ResponseBody
public AjaxResult click(){
return AjaxResult.success("点击成功!");
}
@GetMapping("/download")
@ResponseBody
public AjaxResult download(@RequestParam("aid")String aid,
@RequestParam("appId")String appId,
@RequestParam("oaid")String oaid,
@RequestParam("idType")String idType,
@RequestParam("uniqueId")String uniqueId,
@RequestParam("actionType")String actionType,
@RequestParam("callBack")String callBack){
log.info("归因转化回调内容,{},{},{},{},{},{},{}", aid, appId, oaid, idType, uniqueId, actionType, callBack);
String token= getToken();
if (StringUtils.isEmpty(token)){
token="eyJraWQiOiJ1MUFEcW95T21wT1ZHcXh6VzNnaWtPNER3UmJDZ2RNRCIsInR5cCI6IkpXVCIsImFsZyI6IkhTMjU2In0.eyJzdWIiOiIxMjczODgzNzQ1NTQ3NDkzODI0IiwiZG4iOjEsImNsaWVudF90eXBlIjoxLCJleHAiOjE3NDk2MjUyNDEsImlhdCI6MTc0OTQ1MjQ0MX0.yZnwxuUVxA8dC1TnMtKfnOKB3Cd4s4afujPs5F8pcX0";
}
HuaweiRequest huaweiRequest=new HuaweiRequest();
huaweiRequest.setActionType("4");
huaweiRequest.setActionTime(System.currentTimeMillis());
huaweiRequest.setDeviceIdType("OAID");
huaweiRequest.setAppId(appId);
huaweiRequest.setCallBack(callBack);
huaweiRequest.setDeviceId(oaid);
huaweiRequest.setActionParam("[{'name':'付费金额','value':8}]"); // 根据业务需要调整
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Content-Type", "application/json");
headerMap.put("client_id", "1273883745547493824");
headerMap.put("Authorization", "Bearer "+token);
log.info("请求https://connect-api.cloud.huawei.com/api/datasource/v1/track/activate的属性{},headermap{}", JSONObject.toJSONString(huaweiRequest),headerMap);
String s = sendPost("https://connect-api.cloud.huawei.com/api/datasource/v1/track/activate", JSONObject.toJSONString(huaweiRequest), headerMap);
log.info("请求https://connect-api.cloud.huawei.com/api/datasource/v1/track/activate的响应{}", s);
return AjaxResult.success("下载成功!");
}
@GetMapping("/install")
@ResponseBody
public AjaxResult install(){
return AjaxResult.success("安装成功!");
}
@PostMapping("/getLocation")
@ResponseBody
public AjaxResult getLocationByLot(@RequestBody JSONObject jsonObject){
try {
String location = jsonObject.getString("location");
String url = baiduConfig.getUrl().replace("#AK#", baiduConfig.getAk()) + location;
String result = HttpUtils.sendGet(url);
result = result.replaceAll("\n", "").replaceAll("\t", "");
JSONObject resultJson = JSONObject.parseObject(result);
if("0".equals(resultJson.getString("status"))){
return AjaxResult.success(resultJson.getJSONObject("result").getJSONObject("addressComponent"));
}else {
return AjaxResult.error("Api服务异常!");
}
}catch (Exception e){
e.printStackTrace();
log.error(e.getMessage());
return AjaxResult.error(ExceptionUtil.getExceptionMessage(e));
}
}
@PostMapping("/sendSms")
@ResponseBody
public AjaxResult sendMsg(@RequestBody @Valid NoticeRequest request){
try {
// 短信验证码
String code = String.valueOf((int)((Math.random() * 9 + 1) * Math.pow(10,5)));
// 工程代码泄露可能会导致AccessKey泄露并威胁账号下所有资源的安全性以下代码示例仅供参考建议使用更安全的 STS 方式更多鉴权访问方式请参见https://help.aliyun.com/document_detail/378657.html
Client client = createClient("LTAI5tLDuQRdfyHASSxehs9m", "CraRUliWZNMJhhSRIZ0nVWrxFkGTOH");
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setSignName("保无忧法律咨询")
.setTemplateCode("SMS_268511098")
.setPhoneNumbers(request.getPhone())
.setTemplateParam("{\"code\":"+ code +"}");
RuntimeOptions runtime = new RuntimeOptions();
// 复制代码运行请自行打印 API 的返回值
SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
log.info("发送给{}短信响应为{}", request.getPhone(), sendSmsResponse);
CacheUtils.put(request.getPhone(), code);
// 请求次数入库
try {
ClewPhone param = new ClewPhone();
param.setPhone(request.getPhone());
List<ClewPhone> clewPhones = clewPhoneService.selectClewPhoneList(param);
if(CollectionUtils.isEmpty(clewPhones)){
ClewPhone model = new ClewPhone();
model.setPhone(request.getPhone());
model.setCreateTime(new Date());
model.setRemark(request.getFrom());
if(StringUtils.isNotEmpty(request.getSourceApp())){
model.setSourceApp(Long.valueOf(request.getSourceApp()));
}else {
model.setSourceApp(1L);
}
clewPhoneService.insertClewPhone(model);
}
}catch (Exception e){
e.printStackTrace();
log.error("手机号入库失败!,原因:{}", e.getMessage());
}
// 调用oppo的统计接口
try {
if("oppo".equalsIgnoreCase(request.getFrom())){
// 回调
OppoCheck model = new OppoCheck();
model.setDataType(2);
model.setTimestamp(System.currentTimeMillis());
if(StringUtils.isNotEmpty(request.getImei())){
model.setImei(encode(request.getImei().getBytes()));
}
if(StringUtils.isNotEmpty(request.getOaid())){
model.setOuId(encode(request.getOaid().getBytes()));
}
String content = JSONObject.toJSONString(model) + model.getTimestamp() + "e0u6fnlag06lc3pl";
log.info("请求的content加密前属性{}", content);
Map<String, String> headerMap = new HashMap<>();
headerMap.put("signature", Md5Utils.hash(content));
headerMap.put("timestamp", String.valueOf(model.getTimestamp()));
headerMap.put("Content-Type", "application/json");
log.info("请求https://api.ads.heytapmobi.com/api/uploadActiveData的属性{}", JSONObject.toJSONString(model));
String s = sendPost("https://api.ads.heytapmobi.com/api/uploadActiveData", JSONObject.toJSONString(model), headerMap);
log.info("请求https://api.ads.heytapmobi.com/api/uploadActiveData的响应{}", s);
}else if("vivo".equalsIgnoreCase(request.getFrom())){
String token = "9cd4cddcfc7c9f81fdaf4c94e826926bf0f84259462a57dbfc448f29cc8815c3";
String timeStamp = System.currentTimeMillis() + "";
String notice = "VIVO"+ (long)((Math.random()+1) * 10000000);
String url = "https://marketing-api.vivo.com.cn/openapi/v1/advertiser/behavior/upload?access_token="+token+"&timestamp="+timeStamp+"&nonce="+notice;
String content = "{\"dataList\":[{\"cvTime\":"+timeStamp+",\"cvType\":\"REGISTER\",\"userId\":\""+ request.getOaid() +"\",\"userIdType\":\"OAID\"}],\"pkgName\":\"com.yinliu.loan\",\"srcId\":\"ds-202502072511\",\"srcType\":\"app\"}";
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Content-Type", "application/json");
log.info("请求{}的属性{}", url, content);
String s = sendPost(url, content, headerMap);
log.info("请求{}的响应{}", url, s);
}else if("xiaomi".equalsIgnoreCase(request.getFrom())){
log.info("oaid : {}, imei:{}", request.getOaid(), request.getImei());
String imei = request.getImei();
String oaid = request.getOaid();
// String ua = "Dalvik/2.1.0 (Linux; U; Android 11; M2012K11AC Build/RKQ1.200826.002)";
String clientIp = "58.49.150.163";
long convTime = System.currentTimeMillis();
String convType = "APP_REGISTER";
int customerId = 445972;
long appId = 1545362;
String singKey = "rEQNdyVQxHlayYzw";
String encryptKey = "RPeKBIdybnbMAVlK";
if(request.getSourceApp() != null && "2".equals(request.getSourceApp())){
customerId = 593022;
appId = 1585622;
singKey = "WJzbmmPPufjyKESi";
encryptKey = "sTrlawivcqdHzUDB";
}
GlobalLogHelper.UploadInfo uploadInfo = GlobalLogHelper.UploadInfo.builder()
// .imei(imei)
.oaid(oaid)
// .ua(ua)
.clientIp(clientIp)
.convTime(convTime).convType(convType)
.appId(appId).customerId(customerId).signKey(singKey).encryptKey(encryptKey).build().genInfo();
log.info("请求xiaomi的属性{}", uploadInfo.getFinalUrl());
String s = HttpUtils.sendGet(uploadInfo.getFinalUrl());
log.info("请求xiaomi的响应{}", s);
}else {
log.info("短信请求接口入参:{}", request);
}
}catch (Exception e){
e.printStackTrace();
log.error("回调oppo报错:{}", e.getMessage());
}
}catch (Exception e){
log.error("给 {} 发送短信失败 {}", request.getPhone(), ExceptionUtil.getExceptionMessage(e));
return AjaxResult.error(e.getMessage());
}
return AjaxResult.success("操作成功!");
}
@PostMapping("/checkSms")
@ResponseBody
public AjaxResult checkSms(@RequestBody @Valid NoticeRequest request){
if(StringUtils.isNotEmpty(request.getCode())){
Object obj = CacheUtils.get(request.getPhone());
if(obj != null && request.getCode().equals(obj.toString())){
CacheUtils.remove(request.getPhone());
return AjaxResult.success("操作成功!");
}
}
return AjaxResult.error("操作失败!");
}
public static String encode(byte[] data) throws GeneralSecurityException {
final Key dataKey = new SecretKeySpec(Base64.decodeBase64("XGAXicVG5GMBsx5bueOe4w=="), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, dataKey);
byte[] encryptData = cipher.doFinal(data);
return Base64.encodeBase64String(encryptData).replaceAll("\r", "").replaceAll("\n", "");
}
/**
* 使用AK&SK初始化账号Client
* @param accessKeyId
* @param accessKeySecret
* @return Client
* @throws Exception
*/
public static Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
Config config = new Config()
// 必填您的 AccessKey ID
.setAccessKeyId(accessKeyId)
// 必填您的 AccessKey Secret
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dysmsapi.aliyuncs.com";
return new Client(config);
}
@Data
static class HuaweiRequest {
private String actionType;
private long actionTime;
private String deviceIdType;
private String appId;
private String callBack;
private String deviceId;
private String actionParam;
}
public static String getToken(){
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
Map<String,String> params=new HashMap<>();
params.put("grant_type", "client_credentials");
params.put("client_id", "1273883745547493824"); // 从配置读取
params.put("client_secret", "BBA385787FE8D5CA4F0C889915C6FBA752F7B18C19E99FFE6B09ACCC92C60181"); // 从配置读取
String s;
try {
s= sendPost(
"https://connect-api.cloud.huawei.com/api/oauth2/v1/token",
JSONObject.toJSONString(params),
headers
);
} catch (Exception e) {
log.error("华为API调用失败", e);
return "ERROR: " + e.getMessage();
}
if (StringUtils.isNotEmpty(s)){
Gson gson = new Gson();
Map<String, String> map = gson.fromJson(s, Map.class);
String token=map.get("access_token");
return token;
}
return s;
}
}

View File

@ -1,34 +0,0 @@
package com.ruoyi.web.controller.tool;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.web.service.OssService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
* <p>文件上传</p>
* @author clunt
*/
@RestController
@Api(tags = "App*文件上传")
@RequestMapping(value = "/tool/oss")
public class OssFileController {
@Autowired
private OssService ossService;
@ResponseBody
@PostMapping(value = "/upload")
@ApiOperation(value = "文件上传接口,返回文件的url地址")
public Result<String> upload(@RequestPart @RequestParam("file") MultipartFile multipartFile) {
try {
return Result.success(ossService.upload(multipartFile));
}catch (Exception e){
return Result.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,72 @@
package com.ruoyi.web.controller.tool;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.QiniuUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
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.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 七牛云
*
* @author clunt
*/
@Api
@Controller
@RequestMapping("/tool/qiniu")
public class QiniuController {
private static final Logger logger = LoggerFactory.getLogger(QiniuController.class);
/**
* 七牛云上传单个
*/
@PostMapping(value = "/upload")
@ResponseBody
@ApiOperation("七牛云上传接口")
public AjaxResult uploadFile(HttpServletRequest request, HttpServletResponse response) {
try {
String name = request.getParameter("name");
// 转型为MultipartHttpRequest
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
// 获得实际
MultipartFile file= multipartRequest.getFile(name);
// 上传后返回的文件路径
String fileUrl = QiniuUtils.upload(file.getBytes());
logger.info("upload return url is : " + fileUrl);
AjaxResult ajax = AjaxResult.success();
ajax.put("url", fileUrl);
return ajax;
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
@PostMapping(value = "/app/upload")
@ResponseBody
@ApiOperation("app七牛云上传接口")
public AjaxResult uploadFile(@RequestParam(value = "uploadFile", required = false) MultipartFile file) {
try {
// 上传后返回的文件路径
String fileUrl = QiniuUtils.upload(file.getBytes());
logger.info("upload return url is : " + fileUrl);
AjaxResult ajax = AjaxResult.success();
ajax.put("url", fileUrl);
return ajax;
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
}

View File

@ -1,58 +0,0 @@
package com.ruoyi.web.controller.tool;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.web.request.CommonReq;
import com.ruoyi.web.service.SmsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Random;
/**
* <p>短信接口</p>
* @author clunt
*/
@Api(tags = "App**短信工具类")
@RestController
@RequestMapping(("/tool/sms"))
public class SmsController {
private static final String BASIC = "1234567890";
@Autowired
private SmsService smsService;
@ApiOperation(value = "发送短信验证码(60s有效期)")
@PostMapping(value = "/sendAuthCode")
public Result<String> sendAuthCode(@RequestBody CommonReq commonReq){
try {
if(smsService.sendSms(commonReq.getMobile(), generateAuthCode())){
return Result.success("验证码发送成功");
}else {
return Result.error("验证码发送失败");
}
}catch (Exception e){
return Result.error(e.getMessage());
}
}
/**
* @return 随机6位验证码
*/
private String generateAuthCode(){
char[] basicArray = BASIC.toCharArray();
Random random = new Random();
char[] result = new char[6];
for (int i = 0; i < result.length; i++) {
int index = random.nextInt(100) % (basicArray.length);
result[i] = basicArray[index];
}
return new String(result);
}
}

View File

@ -15,9 +15,10 @@ import com.ruoyi.common.core.controller.BaseController;
@RequestMapping("/tool/swagger")
public class SwaggerController extends BaseController
{
@RequiresPermissions("tool:swagger:view")
@GetMapping()
public String index()
{
return redirect("/doc.html");
return redirect("/swagger-ui/index.html");
}
}

View File

@ -0,0 +1,183 @@
package com.ruoyi.web.controller.tool;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
/**
* swagger 用户测试方法
*
* @author ruoyi
*/
@Api("用户信息管理")
@RestController
@RequestMapping("/test/user")
public class TestController extends BaseController
{
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
{
users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
}
@ApiOperation("获取用户列表")
@GetMapping("/list")
public R<List<UserEntity>> userList()
{
List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
return R.ok(userList);
}
@ApiOperation("获取用户详细")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
@GetMapping("/{userId}")
public R<UserEntity> getUser(@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
return R.ok(users.get(userId));
}
else
{
return R.fail("用户不存在");
}
}
@ApiOperation("新增用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
@ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
@ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
@ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
})
@PostMapping("/save")
public R<String> save(UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
users.put(user.getUserId(), user);
return R.ok();
}
@ApiOperation("更新用户")
@PutMapping("/update")
public R<String> update(@RequestBody UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
if (users.isEmpty() || !users.containsKey(user.getUserId()))
{
return R.fail("用户不存在");
}
users.remove(user.getUserId());
users.put(user.getUserId(), user);
return R.ok();
}
@ApiOperation("删除用户信息")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
@DeleteMapping("/{userId}")
public R<String> delete(@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
users.remove(userId);
return R.ok();
}
else
{
return R.fail("用户不存在");
}
}
}
@ApiModel(value = "UserEntity", description = "用户实体")
class UserEntity
{
@ApiModelProperty("用户ID")
private Integer userId;
@ApiModelProperty("用户名称")
private String username;
@ApiModelProperty("用户密码")
private String password;
@ApiModelProperty("用户手机")
private String mobile;
public UserEntity()
{
}
public UserEntity(Integer userId, String username, String password, String mobile)
{
this.userId = userId;
this.username = username;
this.password = password;
this.mobile = mobile;
}
public Integer getUserId()
{
return userId;
}
public void setUserId(Integer userId)
{
this.userId = userId;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getMobile()
{
return mobile;
}
public void setMobile(String mobile)
{
this.mobile = mobile;
}
}

View File

@ -1,44 +0,0 @@
package com.ruoyi.web.core.config;
import com.huifu.adapay.Adapay;
import com.huifu.adapay.model.MerConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Data
@Configuration
@ConfigurationProperties("adapay")
public class AdapayConfig {
/**
* 是否打印调用日志默认不打印
*/
private boolean debug = false;
/**
* 是否是prod_mode 默认为 true
*/
private boolean prodMode = true;
private String notifyUrl;
private String appId;
private String apiKey;
private String mockApiKey;
private String rsaPrivateKey;
@PostConstruct
public void initAdapay() throws Exception{
MerConfig merConfig = new MerConfig();
merConfig.setApiKey(apiKey);
merConfig.setApiMockKey(mockApiKey);
merConfig.setRSAPrivateKey(rsaPrivateKey);
Adapay.initWithMerConfig(merConfig);
}
}

View File

@ -0,0 +1,131 @@
package com.ruoyi.web.core.config;
import cn.hutool.core.codec.Base64;
import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
/**
* lombok 1.16.16.
*/
public class GlobalLogHelper {
@Data
@Builder
public static class UploadInfo {
//info设备信息
private String imei;
private String oaid;
private long convTime;
private String clientIp;
private String ua;
private long adId;
//conversion转化信息
private long appId;
private int customerId;
private String convType;
private String signKey;
private String encryptKey;
//生成的信息
//最终url
private String finalUrl;
//最终生成的info
private String finalInfo;
//queryString 设备信息
private String queryString;
private String property;
private String baseData;
//md5后的sign值
private String signature;
private final static String HOST = "http://trail.e.mi.com";
private final static String PATH = "/global/log";
@SneakyThrows
public UploadInfo genInfo() {
List<String> kvParam = new ArrayList<>();
if (StringUtils.isNotBlank(this.imei)) {
kvParam.add("imei=" + URLEncoder.encode(this.imei, "UTF-8"));
}
if (StringUtils.isNotBlank(this.oaid)) {
kvParam.add("oaid=" + URLEncoder.encode(this.oaid, "UTF-8"));
}
if (this.convTime > 0) {
kvParam.add("conv_time=" + URLEncoder.encode(String.valueOf(this.convTime), "UTF-8"));
}
if (StringUtils.isNotBlank(this.clientIp)) {
kvParam.add("client_ip=" + URLEncoder.encode(this.clientIp, "UTF-8"));
}
if (StringUtils.isNotBlank(this.ua)) {
kvParam.add("ua=" + URLEncoder.encode(this.ua, "UTF-8"));
}
if (this.adId > 0) {
kvParam.add("ad_id=" + URLEncoder.encode(String.valueOf(this.adId), "UTF-8"));
}
try {
//1.按照顺序使用 & 拼接key=urlEncode(value),queryString
this.queryString = String.join("&", kvParam);
//2.按照顺序使用 & 拼接签名密钥signKey urlEncode(queryString),得到property
this.property = this.signKey + "&" + URLEncoder.encode(this.queryString, "UTF-8");
//3. 将字符串(property) 进行md5(property)加密,得到32位小写字符串signature
this.signature = getMd5Digest(this.property);
} catch (Exception ignored) {
}
//4.按照顺序使用 & 拼接 queryString(注意是第一个步骤生成的) sign=signature
this.baseData = this.queryString + "&sign=" + this.signature;
//5.baseData进行加密 Base64(simple_xor{base_data, encrypt_key}),得到info信息
this.finalInfo = encrypt(this.baseData, this.encryptKey);
this.finalUrl = HOST + PATH
+ "?appId=" + URLEncoder.encode(String.valueOf(this.appId), "UTF-8")
+ "&info=" + URLEncoder.encode(this.finalInfo, "UTF-8")
+ "&conv_type=" + URLEncoder.encode(this.convType, "UTF-8")
+ "&customer_id=" + URLEncoder.encode(String.valueOf(this.customerId), "UTF-8");
return this;
}
//对baseData进行加密 Base64(simple_xor{base_data, encrypt_key})
public static String encrypt(String info, String key) {
try {
if (StringUtils.isEmpty(info) || StringUtils.isEmpty(key)) {
return null;
}
//6.1 base_data, encrypt_key 异或加密
char[] infoChar = info.toCharArray();
char[] keyChar = key.toCharArray();
byte[] resultChar = new byte[infoChar.length];
for (int i = 0; i < infoChar.length; i++) {
resultChar[i] = (byte) ((infoChar[i] ^ keyChar[i % keyChar.length]) & 0xFF);
}
//6.2 Base64 编码
return Base64.encode(resultChar);
} catch (Exception e) {
return null;
}
}
//md5 加密得到32位小写字符串.
public static String getMd5Digest(String pInput) {
try {
MessageDigest lDigest = MessageDigest.getInstance("MD5");
lDigest.update(pInput.getBytes("UTF-8"));
BigInteger lHashInt = new BigInteger(1, lDigest.digest());
return String.format("%1$032x", lHashInt);
} catch (Exception e) {
}
return "";
}
}
}

View File

@ -1,18 +0,0 @@
package com.ruoyi.web.core.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "hx")
public class HxConfig {
private String url;
private String orgName;
private String appName;
private String clientId;
private String clientSecret;
}

View File

@ -1,22 +0,0 @@
package com.ruoyi.web.core.config;
import com.aliyun.oss.OSSClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "aliyun")
@Data
public class OssConfig {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
private String urlPrefix;
}

View File

@ -1,15 +0,0 @@
package com.ruoyi.web.core.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "youban.sms")
public class SmsConfig {
private String signName;
private String templateCode;
private String accessKey;
private String secret;
}

View File

@ -55,13 +55,13 @@ public class SwaggerConfig
// 用ApiInfoBuilder进行定制
return new ApiInfoBuilder()
// 设置标题
.title("标题:全民脱单_接口文档")
.title("标题:若依管理系统_接口文档")
// 描述
.description("描述:全民脱单接口对接...")
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
// 作者信息
.contact(new Contact(RuoYiConfig.getName(), null, null))
// 版本
.version("版本号:v1.0.0")
.version("版本号:" + RuoYiConfig.getVersion())
.build();
}
}

View File

@ -1,21 +0,0 @@
package com.ruoyi.web.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "支付请求对象")
public class AdapayReq {
@NotNull
@ApiModelProperty(value = "用户id")
private Long userId;
@NotNull
@ApiModelProperty(value = "1:1999合伙人开通,6:9.9 户外运动交友团,7:99 本硕博学历的团,8:199 深圳有房有车的团,9:699元人工牵线")
private Long orderType;
}

View File

@ -1,27 +0,0 @@
package com.ruoyi.web.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>通用参数接口</p>
* @author clunt
*/
@Data
@ApiModel(value = "App*通用入参")
public class CommonReq {
@ApiModelProperty(value = "主键id")
private Long id;
@ApiModelProperty(value = "编码")
private String code;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "名称")
private String name;
}

View File

@ -1,35 +0,0 @@
package com.ruoyi.web.request;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
@Data
public class Event {
/**
* Adapay 生成的支付对象 id id Adapay 系统内唯一
*/
private String id;
/**
* 签名
*/
private String sign;
/**
* 支付创建时的 10 位时间戳
*/
@JSONField(name = "created_time")
private Long createdTime;
/**
* 是否 prod模式true prod模式false mock模式
*/
@JSONField(name = "created_time")
private String prodMode;
/**
* Event 事件类型
*/
private String type;
/**
* Adapay回调接口传过来的数据内容为JSON字符串
* 不同的Event事件有不同的data
*/
private String data;
}

View File

@ -1,15 +0,0 @@
package com.ruoyi.web.request;
import lombok.Data;
/**
* <p>环信注册对象</p>
* @author clunt
*/
@Data
public class HxRegister {
private String username;
private String password;
}

View File

@ -1,24 +0,0 @@
package com.ruoyi.web.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>登陆相关需要的参数</p>
* @author clunt
*/
@Data
@ApiModel(value = "App*登陆入参")
public class LoginReq {
@ApiModelProperty(value = "手机号", required = true)
private String mobile;
@ApiModelProperty(value = "验证码")
private String authCode;
@ApiModelProperty(value = "密码")
private String password;
}

View File

@ -1,21 +0,0 @@
package com.ruoyi.web.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>代理团/单身团</p>
* @author clunt
*/
@Data
@ApiModel(value = "媒婆代理和单身团请求对象")
public class MatchRegisterReq {
@ApiModelProperty(value = "媒婆用户id")
private Long matchUserId;
@ApiModelProperty(value = "性别,单身团使用")
private Integer sex;
}

View File

@ -1,21 +0,0 @@
package com.ruoyi.web.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <P>单身用户推荐入参</P>
* @author clunt
*/
@Data
@ApiModel(value = "单身用户推荐入参")
public class UserSingleRecommendReq {
@ApiModelProperty(value = "当前登陆用户userId")
private Long userId;
@ApiModelProperty(value = "性别,当用户没有保存性别时使用")
private Long sex;
}

View File

@ -1,20 +0,0 @@
package com.ruoyi.web.response;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "App*支付响应参数")
public class AdapayResp {
@ApiModelProperty(value = "支付订单号")
private String orderNo;
@ApiModelProperty(value = "二维码url")
private String qrcodeUrl;
@ApiModelProperty(value = "查询url")
private String queryUrl;
}

View File

@ -1,17 +0,0 @@
package com.ruoyi.web.response;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "环信加密后对象")
public class HxResp {
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
}

View File

@ -1,102 +0,0 @@
package com.ruoyi.web.response;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
@ApiModel(value = "App*登陆响应参数")
public class LoginResp {
@ApiModelProperty(value = "用户id*妥善存储,后续调用需要传递")
private Long userId;
@ApiModelProperty(value = "用户手机号")
private String mobile;
/** 昵称 */
@ApiModelProperty(value = "昵称")
private String nickName;
/** 真实姓名 */
@ApiModelProperty(value = "真实姓名")
private String realName;
/** 性别: 0.未知 1.男 2.女 */
@ApiModelProperty(value = "性别: 0.未知 1.男 2.女")
private Long sex;
/** 出生年月 */
@JsonFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty(value = "出生年月日")
private Date birthday;
/** 身高(单位cm) */
@ApiModelProperty(value = "身高(单位cm)")
private Long height;
/** 体重(单位KG) */
@ApiModelProperty(value = "体重(单位KG)")
private Long weight;
/** 学历 0.大专以下 1.大专 2.本科 3.研究生 4.博士 */
@ApiModelProperty(value = "学历 0.大专以下 1.大专 2.本科 3.研究生 4.博士")
private Long education;
/** 毕业院校 */
@ApiModelProperty(value = "毕业院校")
private String school;
/** 婚姻状况 0.未婚 1.离异 */
@ApiModelProperty(value = "婚姻状况 0.未婚 1.离异")
private Long marriage;
/** 职业 */
@ApiModelProperty(value = "职业")
private String job;
/** 收入(元/年) */
@ApiModelProperty(value = "收入(元/年)")
private Long income;
/** 籍贯 */
@ApiModelProperty(value = "籍贯")
private String nativePlace;
/** 省份 */
@ApiModelProperty(value = "省份")
private Long provinceId;
/** 城市 */
@ApiModelProperty(value = "城市")
private Long cityId;
/** 是否有房产 0.无房 1.有房 */
@ApiModelProperty(value = "是否有房产 0.无房 1.有房")
private Long houseProperty;
/** 是否有车 0.无车 1.有车 */
@ApiModelProperty(value = "是否有车 0.无车 1.有车")
private Long carProperty;
/** 自我介绍 */
@ApiModelProperty(value = "自我介绍")
private String selfIntroduce;
/** 家庭背景 */
@ApiModelProperty(value = "家庭背景")
private String familyBackground;
/** 业务爱好 */
@ApiModelProperty(value = "业务爱好")
private String hobby;
/** 择偶标准 */
@ApiModelProperty(value = "择偶标准")
private String choosingStandard;
}

View File

@ -1,25 +0,0 @@
package com.ruoyi.web.service;
import com.ruoyi.system.domain.TbUserMatchOrder;
import com.ruoyi.web.request.AdapayReq;
import com.ruoyi.web.response.AdapayResp;
import java.util.Map;
public interface AdapayService {
/**
* <P>发起支付</P>
* @param adapayReq 支付对象
* @return 响应对象
*/
public AdapayResp pay(AdapayReq adapayReq) throws Exception;
/**
* @param adapayReq 支付查询
* @return 支付结果
* @throws Exception
*/
TbUserMatchOrder checkPayResult(AdapayReq adapayReq) throws Exception;
}

View File

@ -1,15 +0,0 @@
package com.ruoyi.web.service;
import com.ruoyi.web.request.Event;
/**
* <p>adapy支付回调</p>
* @author clunt
*/
public interface CallBackService {
/**
* @param event 回调
*/
void onCallback(Event event);
}

View File

@ -1,18 +0,0 @@
package com.ruoyi.web.service;
import com.ruoyi.system.domain.TbUser;
/**
* <p>环信接口</p>
*/
public interface HxService {
/**
* <p>注册环信</p>
* @param tbUser 用户信息
*/
void register(TbUser tbUser);
String getToken();
}

View File

@ -1,14 +0,0 @@
package com.ruoyi.web.service;
import com.ruoyi.web.request.LoginReq;
import com.ruoyi.web.response.LoginResp;
public interface LoginService {
LoginResp loginByPhone(LoginReq loginReq) throws Exception;
LoginResp loginByPassword(LoginReq loginReq) throws Exception;
void updatePasswordByPhone(LoginReq loginReq) throws Exception;
}

View File

@ -1,9 +0,0 @@
package com.ruoyi.web.service;
import org.springframework.web.multipart.MultipartFile;
public interface OssService {
String upload(MultipartFile multipartFile) throws Exception;
}

View File

@ -1,8 +0,0 @@
package com.ruoyi.web.service;
public interface SmsService {
Boolean sendSms(String mobile, String code);
}

View File

@ -1,112 +0,0 @@
package com.ruoyi.web.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.Payment;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.system.domain.TbUserMatchOrder;
import com.ruoyi.system.service.ITbUserMatchOrderService;
import com.ruoyi.web.core.config.AdapayConfig;
import com.ruoyi.web.request.AdapayReq;
import com.ruoyi.web.response.AdapayResp;
import com.ruoyi.web.service.AdapayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Service
public class AdapayServiceImpl implements AdapayService {
@Autowired
private AdapayConfig adapayConfig;
@Autowired
private ITbUserMatchOrderService tbUserMatchOrderService;
@Override
public AdapayResp pay(AdapayReq adapayReq) throws Exception{
AdapayResp resp = new AdapayResp();
String orderNo = "match_order_" + adapayReq.getUserId() + "_" + adapayReq.getOrderType() + "_" + System.currentTimeMillis();
Map<String, Object> paymentParams = new HashMap<>(10);
paymentParams.put("adapay_connection_request_timeout", 10000);
paymentParams.put("adapay_connect_timeout", 30000);
paymentParams.put("adapay_socket_timeout", 30000);
paymentParams.put("notify_url", "http://www.quanmingtuodan.xyz:18000/app/matchOrder/callback");
paymentParams.put("app_id", adapayConfig.getAppId());
paymentParams.put("order_no", orderNo);
paymentParams.put("pay_channel", "alipay");
if(adapayReq.getOrderType() == 6L){
paymentParams.put("pay_amt", "9.90");
// paymentParams.put("pay_amt", "0.01");
}else if(adapayReq.getOrderType() == 1L){
paymentParams.put("pay_amt", "1999.00");
}else if(adapayReq.getOrderType() == 7L){
paymentParams.put("pay_amt", "99.90");
// paymentParams.put("pay_amt", "0.01");
}else if(adapayReq.getOrderType() == 8L){
paymentParams.put("pay_amt", "199.00");
// paymentParams.put("pay_amt", "0.01");
}else if(adapayReq.getOrderType() == 9L){
paymentParams.put("pay_amt", "699.00");
// paymentParams.put("pay_amt", "0.01");
}
paymentParams.put("goods_title", "全民脱单合伙人开通");
paymentParams.put("goods_desc", "全民脱单合伙人资格开通");
paymentParams.put("div_members", "");
//调用sdk方法创建支付得到支付对象
Map<String, Object> payment = new HashMap<>();
try {
log.info("调用第三方支付,入参:{}", JSONObject.toJSONString(paymentParams));
payment = Payment.create(paymentParams);
log.info("调用第三方支付, 响应:{}", JSONObject.toJSONString(payment));
} catch (BaseAdaPayException e) {
log.error("调用第三方支付报错: {}", ExceptionUtil.getExceptionMessage(e));
throw new Exception("调用支付失败");
}
if("succeeded".equals(String.valueOf(payment.get("status")))){
resp.setOrderNo(String.valueOf(payment.get("order_no")));
JSONObject expendJson = JSONObject.parseObject(String.valueOf(payment.get("expend")));
resp.setQrcodeUrl(expendJson.getString("pay_info"));
resp.setQueryUrl(expendJson.getString("query_url"));
}else {
throw new Exception("调用支付失败");
}
// 入库生成支付记录
TbUserMatchOrder tbUserMatchOrder = new TbUserMatchOrder();
tbUserMatchOrder.setUserId(adapayReq.getUserId());
tbUserMatchOrder.setOrderType(adapayReq.getOrderType());
tbUserMatchOrder.setOrderNo(orderNo);
tbUserMatchOrder.setPayStatus("Paying");
// 测试订单,目前均为0.01元
if(adapayReq.getOrderType() == 6L){
tbUserMatchOrder.setOrderMoney(BigDecimal.valueOf(9.90));
}else if(adapayReq.getOrderType() == 1L){
tbUserMatchOrder.setOrderMoney(BigDecimal.valueOf(1999));
}else if(adapayReq.getOrderType() == 7L){
tbUserMatchOrder.setOrderMoney(BigDecimal.valueOf(99));
}else if(adapayReq.getOrderType() == 8L){
tbUserMatchOrder.setOrderMoney(BigDecimal.valueOf(199));
}else if(adapayReq.getOrderType() == 9L){
tbUserMatchOrder.setOrderMoney(BigDecimal.valueOf(699));
tbUserMatchOrder.setServTime(3);
}
tbUserMatchOrderService.insertTbUserMatchOrder(tbUserMatchOrder);
return resp;
}
@Override
public TbUserMatchOrder checkPayResult(AdapayReq adapayReq) {
return tbUserMatchOrderService.lambdaQuery()
.eq(TbUserMatchOrder::getUserId, adapayReq.getUserId())
.eq(TbUserMatchOrder::getOrderType, adapayReq.getOrderType())
.eq(TbUserMatchOrder::getPayStatus, "succeeded")
.one();
}
}

View File

@ -1,40 +0,0 @@
package com.ruoyi.web.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.TbUserMatchOrder;
import com.ruoyi.system.service.ITbUserMatchOrderService;
import com.ruoyi.web.request.Event;
import com.ruoyi.web.service.CallBackService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Slf4j
@Service
public class CallBackServiceImpl implements CallBackService {
@Autowired
private ITbUserMatchOrderService userMatchOrderService;
@Override
public void onCallback(Event event) {
log.info("支付回调: {}", event);
String data = event.getData();
JSONObject payment = JSON.parseObject(data);
TbUserMatchOrder tbUserMatchOrder = userMatchOrderService.lambdaQuery().eq(TbUserMatchOrder::getOrderNo, payment.getString("order_no"))
.one();
// 校验是否是本系统发出去的支付请求
if (tbUserMatchOrder != null && StringUtils.isNotEmpty(payment.getString("status"))) {
// 更新交易记录
tbUserMatchOrder.setPayStatus(payment.getString("status"));
userMatchOrderService.updateById(tbUserMatchOrder);
} else {
log.warn("系统中不存在这条交易记录: {}", event);
}
}
}

View File

@ -1,88 +0,0 @@
package com.ruoyi.web.service.impl;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.TbUser;
import com.ruoyi.web.core.config.HxConfig;
import com.ruoyi.web.request.HxRegister;
import com.ruoyi.web.service.HxService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class HxServiceImpl implements HxService {
private final static String HX_TOKEN_KEY = "hx_token";
private static final String HX_END_STRING = "_pingban_youban";
@Autowired
private HxConfig hxConfig;
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public void register(TbUser tbUser) {
String token = getToken();
String registerUrl = hxConfig.getUrl() + hxConfig.getOrgName() + "/" + hxConfig.getAppName() + "/users";
// header
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Content-Type", "application/json");
headerMap.put("Authorization", "Bearer " + token);
// body
List<HxRegister> registers = new ArrayList<>();
HxRegister register = new HxRegister();
register.setPassword(DigestUtils.md5Hex(tbUser.getId() + HX_END_STRING));
register.setUsername(String.valueOf(tbUser.getId()));
registers.add(register);
log.info("注册环信入参:{}", JSONArray.toJSON(registers));
String result = HttpUtil.createPost(registerUrl).addHeaders(headerMap).body(JSONArray.toJSONString(registers)).execute().body();
log.info("注册环信返回结果:{}", result);
}
@Override
public String getToken() {
// 未失效
String token = redisTemplate.opsForValue().get(HX_TOKEN_KEY);
if(StringUtils.isNotEmpty(token)){
return token;
}
// 失效重新获取
String tokenUrl = hxConfig.getUrl() + hxConfig.getOrgName() + "/" + hxConfig.getAppName() + "/token";
JSONObject tokenJson = new JSONObject();
tokenJson.put("grant_type", "client_credentials");
tokenJson.put("client_id", hxConfig.getClientId());
tokenJson.put("client_secret", hxConfig.getClientSecret());
log.info("请求地址:{}, 请求内容:{}", tokenUrl, tokenJson);
// headerMap
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Content-Type", "application/json");
String result = HttpUtil.createPost(tokenUrl).addHeaders(headerMap).body(JSONObject.toJSONString(tokenJson)).execute().body();
log.info("返回内容:{}", result);
if(StringUtils.isNotEmpty(result)){
JSONObject resultJson = JSONObject.parseObject(result);
String newToken = resultJson.getString("access_token");
Long expireTime = resultJson.getLong("expires_in") - 3600L;
// 获取到token
if(StringUtils.isNotEmpty(newToken)){
redisTemplate.opsForValue().set(HX_TOKEN_KEY, newToken, expireTime, TimeUnit.SECONDS);
return newToken;
}
}
return null;
}
}

View File

@ -1,125 +0,0 @@
package com.ruoyi.web.service.impl;
import com.ruoyi.common.constant.RedisConstants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.TbUser;
import com.ruoyi.system.domain.TbUserSingle;
import com.ruoyi.system.service.ITbUserService;
import com.ruoyi.system.service.ITbUserSingleService;
import com.ruoyi.web.request.LoginReq;
import com.ruoyi.web.response.LoginResp;
import com.ruoyi.web.service.HxService;
import com.ruoyi.web.service.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {
private static final String DEFAULT_PASSWORD = "123456";
private static final String DEFAULT_CREATE_BY = "手机用户";
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private ITbUserService tbUserService;
@Autowired
private ITbUserSingleService tbUserSingleService;
@Autowired
private HxService hxService;
@Override
@Transactional(rollbackFor = Exception.class)
public LoginResp loginByPhone(LoginReq loginReq) throws Exception{
LoginResp resp = new LoginResp();
String alreadyCode = stringRedisTemplate.opsForValue().get(RedisConstants.SMS_CODE_PREFIX+loginReq.getMobile());
if(StringUtils.isEmpty(alreadyCode)){
throw new Exception("验证码已过期!");
}
if(!alreadyCode.equals(loginReq.getAuthCode())){
throw new Exception("短信验证码错误!");
}
TbUser tbUser = tbUserService.lambdaQuery().eq(TbUser::getMobile, loginReq.getMobile()).one();
//如果用户-- 则注册新用户,只带入用户的手机号+默认密码123456
if(tbUser == null){
tbUser = new TbUser();
tbUser.setMobile(loginReq.getMobile());
if(StringUtils.isEmpty(loginReq.getPassword())){
tbUser.setPassword(DigestUtils.md5Hex(DEFAULT_PASSWORD));
}else {
tbUser.setPassword(DigestUtils.md5Hex(loginReq.getPassword()));
}
tbUser.setCreateTime(new Date());
tbUser.setCreateBy(DEFAULT_CREATE_BY);
int index = tbUserService.insertTbUser(tbUser);
if(index > 0){
// 注册环信
hxService.register(tbUser);
}
BeanUtils.copyProperties(tbUser, resp);
resp.setUserId(tbUser.getId());
}else {
BeanUtils.copyProperties(tbUser, resp);
resp.setUserId(tbUser.getId());
// 用户存在,如果已填充用户信息
TbUserSingle tbUserSingle = tbUserSingleService.lambdaQuery().eq(TbUserSingle::getUserId, tbUser.getId()).one();
if(tbUserSingle != null){
BeanUtils.copyProperties(tbUserSingle, resp);
}
}
return resp;
}
@Override
public void updatePasswordByPhone(LoginReq loginReq) throws Exception {
String alreadyCode = stringRedisTemplate.opsForValue().get(RedisConstants.SMS_CODE_PREFIX+loginReq.getMobile());
if(StringUtils.isEmpty(alreadyCode)){
throw new Exception("验证码已过期!");
}
if(!alreadyCode.equals(loginReq.getAuthCode())){
throw new Exception("短信验证码错误!");
}
TbUser tbUser = tbUserService.lambdaQuery().eq(TbUser::getMobile, loginReq.getMobile()).one();
//如果用户-- 则注册新用户,只带入用户的手机号+默认密码123456
if(tbUser != null){
if(StringUtils.isNotEmpty(loginReq.getPassword())){
tbUser.setPassword(DigestUtils.md5Hex(loginReq.getPassword()));
}
tbUserService.updateById(tbUser);
}
}
@Override
public LoginResp loginByPassword(LoginReq loginReq) throws Exception{
LoginResp resp = new LoginResp();
TbUser tbUser = tbUserService.lambdaQuery()
.eq(TbUser::getMobile, loginReq.getMobile())
.eq(TbUser::getPassword, DigestUtils.md5Hex(loginReq.getPassword()))
.one();
//如果用户-- 则注册新用户,只带入用户的手机号+默认密码123456
if(tbUser == null){
throw new Exception("账号或密码错误!");
}else {
BeanUtils.copyProperties(tbUser, resp);
resp.setUserId(tbUser.getId());
// 用户存在,如果已填充用户信息
TbUserSingle tbUserSingle = tbUserSingleService.lambdaQuery().eq(TbUserSingle::getUserId, tbUser.getId()).one();
if(tbUserSingle != null){
BeanUtils.copyProperties(tbUserSingle, resp);
}
}
return resp;
}
}

View File

@ -1,51 +0,0 @@
package com.ruoyi.web.service.impl;
import cn.hutool.core.date.DateTime;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.PutObjectResult;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.web.core.config.OssConfig;
import com.ruoyi.web.service.OssService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
@Slf4j
@Service
public class OssServiceImpl implements OssService {
@Autowired
private OSSClient ossClient;
@Autowired
private OssConfig ossConfig;
@Override
public String upload(MultipartFile multipartFile) throws Exception{
String filePath = getFilePath(multipartFile.getOriginalFilename());
// 上传到阿里云
try {
PutObjectResult ossResult = ossClient.putObject(ossConfig.getBucketName(), filePath, new
ByteArrayInputStream(multipartFile.getBytes()));
log.info("上传文件到OSS结果:{}", ossResult.getResponse());
} catch (Exception e) {
log.error(ExceptionUtil.getExceptionMessage(e));
throw new Exception(e.getMessage());
}
return ossConfig.getUrlPrefix() + filePath;
}
private String getFilePath(String sourceFileName) {
DateTime dateTime = new DateTime();
return "images/" + dateTime.toString("yyyy")
+ "/" + dateTime.toString("MM") + "/"
+ dateTime.toString("dd") + "/" + System.currentTimeMillis() +
RandomUtils.nextInt(100, 9999) + "." +
StringUtils.substringAfterLast(sourceFileName, ".");
}
}

View File

@ -1,62 +0,0 @@
package com.ruoyi.web.service.impl;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.ruoyi.common.constant.RedisConstants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.core.config.SmsConfig;
import com.ruoyi.web.service.SmsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class SmsServiceImpl implements SmsService {
@Autowired
private SmsConfig smsConfig;
@Autowired
private StringRedisTemplate stringRedisTemplate;
private final static String ALI_SMS_URL = "dysmsapi.aliyuncs.com";
@Override
public Boolean sendSms(String mobile, String code) {
try {
String alreadyCode = stringRedisTemplate.opsForValue().get(RedisConstants.SMS_CODE_PREFIX + mobile);
if(StringUtils.isNotEmpty(alreadyCode)){
throw new Exception("已发的验证码还在有效期");
}
//配置阿里云
Config config = new Config()
// 您的AccessKey ID
.setAccessKeyId(smsConfig.getAccessKey())
// 您的AccessKey Secret
.setAccessKeySecret(smsConfig.getSecret());
// 访问的域名
config.endpoint = ALI_SMS_URL;
Client client = new Client(config);
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setPhoneNumbers(mobile)
.setSignName(smsConfig.getSignName())
.setTemplateCode(smsConfig.getTemplateCode())
.setTemplateParam("{\"code\":\""+code+"\"}");
// 复制代码运行请自行打印 API 的返回值
SendSmsResponse response = client.sendSms(sendSmsRequest);
log.info("调用阿里云成功状态:{}, 内容:{}", response.body.code, response.body.getMessage());
stringRedisTemplate.opsForValue().set(RedisConstants.SMS_CODE_PREFIX + mobile, code, 60, TimeUnit.SECONDS);
}catch (Exception e) {
log.error("调用阿里云短信异常:{}", e.getMessage());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}

View File

@ -0,0 +1,377 @@
package com.ruoyi.web.websocket;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.nio.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.ruoyi.customer.service.ICustomerServiceService;
import com.ruoyi.system.domain.ManualServiceSessions;
/**
* 客服系统WebSocket服务
*
* @author ruoyi
*/
@ServerEndpoint("/websocket/customer/{userId}")
@Component
public class CustomerServiceWebSocket {
private static final Logger log = LoggerFactory.getLogger(CustomerServiceWebSocket.class);
/** 客服服务 - 使用静态变量以便在WebSocket中使用 */
private static ICustomerServiceService customerServiceService;
/** 静态变量,用来记录当前在线连接数 */
private static final AtomicInteger onlineCount = new AtomicInteger(0);
/** concurrent包的线程安全Set用来存放每个客户端对应的WebSocket对象 */
private static final ConcurrentHashMap<String, CustomerServiceWebSocket> webSocketMap = new ConcurrentHashMap<>();
/** 心跳定时器 */
private static final ScheduledExecutorService heartbeatExecutor = Executors.newScheduledThreadPool(10);
/** 心跳间隔时间(秒) */
private static final int HEARTBEAT_INTERVAL = 30;
/** 连接超时时间(毫秒) */
private static final long SESSION_TIMEOUT = 300000; // 5分钟
/** 与某个客户端的连接会话,需要通过它来给客户端发送数据 */
private Session session;
/** 接收userId */
private String userId = "";
/** 心跳任务 */
private java.util.concurrent.ScheduledFuture<?> heartbeatTask;
/**
* 注入客服服务
*/
@Autowired
public void setCustomerServiceService(ICustomerServiceService customerServiceService) {
CustomerServiceWebSocket.customerServiceService = customerServiceService;
}
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
// 设置session超时时间
session.setMaxIdleTimeout(SESSION_TIMEOUT);
if (webSocketMap.containsKey(userId)) {
// 如果已存在连接先清理旧的心跳任务
CustomerServiceWebSocket oldWebSocket = webSocketMap.get(userId);
if (oldWebSocket != null && oldWebSocket.heartbeatTask != null) {
oldWebSocket.heartbeatTask.cancel(true);
}
webSocketMap.remove(userId);
webSocketMap.put(userId, this);
} else {
webSocketMap.put(userId, this);
addOnlineCount();
}
// 启动心跳机制
startHeartbeat();
log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount() + ",连接超时设置为:" + SESSION_TIMEOUT + "ms");
try {
sendMessage("连接成功");
} catch (IOException e) {
log.error("用户:" + userId + ",网络异常!!!!!!");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
// 停止心跳任务
stopHeartbeat();
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
subOnlineCount();
}
// 清理该用户的待处理转人工记录
try {
if (customerServiceService != null && userId != null && !userId.isEmpty()) {
Long userIdLong = Long.valueOf(userId);
int cleanedCount = customerServiceService.cleanupPendingManualRequests(userIdLong);
if (cleanedCount > 0) {
log.info("WebSocket断开已清理用户{}的{}条待处理转人工记录", userId, cleanedCount);
}
}
} catch (Exception e) {
log.error("清理用户{}的转人工记录失败", userId, e);
}
log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
}
/**
* 处理Pong消息
*/
@OnMessage
public void onPong(PongMessage pongMessage, Session session) {
log.debug("收到用户{}的pong消息连接正常", this.userId);
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:" + userId + ",报文:" + message);
// 解析消息
if (message != null && !message.isEmpty()) {
try {
com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(message);
String toUserId = jsonObject.getString("toUserId");
String messageContent = jsonObject.getString("message");
String messageType = jsonObject.getString("type");
// 处理消息路由
if ("service".equals(toUserId)) {
// 当toUserId为'service'根据发送者userId查找对应的客服人员
log.info("收到发送给客服的消息发送者userId: {}", this.userId);
// 检查customerServiceService是否为null
if (customerServiceService == null) {
log.error("customerServiceService为null无法处理消息路由");
return;
}
log.info("customerServiceService检查通过开始处理消息路由");
try {
Long senderUserId = Long.valueOf(this.userId);
log.info("准备查询用户{}的已接受转人工会话", senderUserId);
// 查找该用户对应的已接受状态的转人工记录
ManualServiceSessions acceptedSession = customerServiceService.getAcceptedManualSessionByUserId(senderUserId);
log.info("查询已接受转人工会话完成,结果: {}", acceptedSession != null ? "找到会话" : "未找到会话");
if (acceptedSession != null) {
log.info("已接受会话详情 - manualSessionId: {}, sessionId: {}, userId: {}, serviceId: {}, status: {}",
acceptedSession.getManualSessionId(),
acceptedSession.getSessionId(),
acceptedSession.getUserId(),
acceptedSession.getServiceId(),
acceptedSession.getStatus());
if (acceptedSession.getServiceId() != null) {
String serviceUserId = acceptedSession.getServiceId().toString();
log.info("目标客服ID: {}", serviceUserId);
// 检查对应的客服是否在线
log.info("当前在线用户列表: {}", webSocketMap.keySet());
if (webSocketMap.containsKey(serviceUserId)) {
log.info("客服{}在线,准备转发消息", serviceUserId);
webSocketMap.get(serviceUserId).sendMessage(JSON.toJSONString(jsonObject));
log.info("消息已成功转发给对应的客服人员: serviceId={}", serviceUserId);
} else {
log.warn("对应的客服人员不在线: serviceId={}, 当前在线用户: {}", serviceUserId, webSocketMap.keySet());
}
} else {
log.warn("已接受会话的serviceId为null");
}
} else {
log.warn("未找到用户{}对应的已接受状态的转人工记录", this.userId);
}
} catch (NumberFormatException e) {
log.error("用户ID格式错误: {}", this.userId, e);
} catch (Exception e) {
log.error("查找对应客服人员失败,异常详情: ", e);
}
} else if (toUserId != null && webSocketMap.containsKey(toUserId)) {
// 正常的点对点消息转发
webSocketMap.get(toUserId).sendMessage(JSON.toJSONString(jsonObject));
log.info("消息已转发给指定用户: {}", toUserId);
} else {
log.error("请求的userId:" + toUserId + "不在该服务器上");
}
} catch (Exception e) {
log.error("消息解析异常", e);
}
}
}
/**
* 发生错误时调用
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 发送自定义消息
*/
public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
log.info("[WebSocket调试] 开始发送消息到用户: {}, 报文: {}", userId, message);
// 打印当前在线用户列表和数量
log.info("[WebSocket调试] 当前在线用户数量: {}", webSocketMap.size());
log.info("[WebSocket调试] 当前在线用户列表: {}", webSocketMap.keySet());
// 检查目标用户是否在线
if (userId != null && webSocketMap.containsKey(userId)) {
CustomerServiceWebSocket targetWebSocket = webSocketMap.get(userId);
// 检查WebSocket连接状态
if (targetWebSocket != null && targetWebSocket.session != null) {
log.info("[WebSocket调试] 用户{}的WebSocket连接状态: isOpen={}, id={}",
userId, targetWebSocket.session.isOpen(), targetWebSocket.session.getId());
try {
targetWebSocket.sendMessage(message);
log.info("[WebSocket调试] 消息发送成功到用户: {}", userId);
} catch (IOException e) {
log.error("[WebSocket调试] 消息发送失败到用户: {}, 错误: {}", userId, e.getMessage());
throw e;
}
} else {
log.error("[WebSocket调试] 用户{}的WebSocket连接为空或session为空", userId);
}
} else {
log.error("[WebSocket调试] 用户{}不在线!在线用户列表: {}", userId, webSocketMap.keySet());
}
}
/**
* 获得此时的在线人数
*/
public static synchronized int getOnlineCount() {
return onlineCount.get();
}
/**
* 在线人数加1
*/
public static synchronized void addOnlineCount() {
onlineCount.incrementAndGet();
}
/**
* 在线人数减1
*/
public static synchronized void subOnlineCount() {
onlineCount.decrementAndGet();
}
/**
* 获取在线用户列表
*/
public static ConcurrentHashMap<String, CustomerServiceWebSocket> getWebSocketMap() {
return webSocketMap;
}
/**
* 发送消息给指定用户
*/
public static void sendMessageToUser(String userId, String message) {
try {
if (userId != null && webSocketMap.containsKey(userId)) {
webSocketMap.get(userId).sendMessage(message);
log.info("已发送消息给用户: userId={}", userId);
} else {
log.warn("用户{}不在线,无法发送消息", userId);
}
} catch (Exception e) {
log.error("发送消息给用户{}失败", userId, e);
}
}
/**
* 启动心跳机制
*/
private void startHeartbeat() {
if (heartbeatTask != null) {
heartbeatTask.cancel(true);
}
heartbeatTask = heartbeatExecutor.scheduleWithFixedDelay(() -> {
try {
if (session != null && session.isOpen()) {
// 发送ping消息
ByteBuffer pingData = ByteBuffer.wrap("ping".getBytes());
session.getBasicRemote().sendPing(pingData);
log.debug("向用户{}发送ping消息", userId);
} else {
log.warn("用户{}的session已关闭停止心跳", userId);
stopHeartbeat();
}
} catch (Exception e) {
log.error("发送心跳消息失败,用户: {}, 错误: {}", userId, e.getMessage());
stopHeartbeat();
}
}, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
log.info("用户{}启动心跳机制,间隔{}秒", userId, HEARTBEAT_INTERVAL);
}
/**
* 停止心跳机制
*/
private void stopHeartbeat() {
if (heartbeatTask != null && !heartbeatTask.isCancelled()) {
heartbeatTask.cancel(true);
log.info("用户{}停止心跳机制", userId);
}
}
/**
* 发送ping消息保持连接活跃
*/
public void sendPing() {
try {
if (session != null && session.isOpen()) {
ByteBuffer pingData = ByteBuffer.wrap("heartbeat".getBytes());
session.getBasicRemote().sendPing(pingData);
log.debug("向用户{}发送ping消息", userId);
}
} catch (Exception e) {
log.error("发送ping消息失败用户: {}", userId, e);
}
}
}

View File

@ -6,8 +6,8 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://121.62.23.77:3306/youban?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: youban
url: jdbc:mysql://58.49.150.163:3306/bwy?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Clunt@12345
# 从库数据源
slave:

View File

@ -3,20 +3,20 @@ ruoyi:
# 名称
name: RuoYi
# 版本
version: 4.7.8
version: 4.7.7
# 版权年份
copyrightYear: 2023
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: /home/ruoyi/uploadPath
profile: D:/ruoyi/uploadPath
# 获取ip地址开关
addressEnabled: false
# 开发环境配置
server:
# 服务器的HTTP端口默认为80
port: 18000
port: 19002
servlet:
# 应用的访问路径
context-path: /
@ -34,7 +34,7 @@ server:
# 日志配置
logging:
level:
com.ruoyi: info
com.ruoyi: debug
org.springframework: warn
# 用户配置
@ -45,20 +45,6 @@ user:
# Spring配置
spring:
# redis配置
redis:
database: 0
host: 121.62.23.77
port: 6379
password: Clunt@12345
timeout: 6000ms # 连接超时时长(毫秒)
lettuce:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
# 模板引擎
thymeleaf:
mode: HTML
@ -76,37 +62,25 @@ spring:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
# 热部署开关
enabled: false
enabled: true
# MyBatis
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
mybatis-plus:
mapper-locations: classpath*:mapper/**/*Mapper.xml
type-aliases-package: com.ruoyi.**.domain
configuration:
cache-enabled: true
use-generated-keys: true
default-executor-type: simple
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
global-config:
db-config:
id-type: auto
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
@ -125,7 +99,7 @@ shiro:
indexUrl: /index
# 验证码开关
captchaEnabled: true
# 验证码类型 math 数字计算 char 字符验证
# 验证码类型 math 数组计算 char 字符
captchaType: math
cookie:
# 设置Cookie的域名 默认空,即当前访问的域名
@ -140,7 +114,7 @@ shiro:
cipherKey:
session:
# Session超时时间-1代表永不过期默认30分钟
expireTime: 30
expireTime: 360
# 同步session到数据库的周期默认1分钟
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性默认就是10分钟
@ -167,34 +141,7 @@ swagger:
# 是否开启swagger
enabled: true
#阿里云短信
youban:
sms:
sign-name: 深圳市有伴文化传媒
template-code: SMS_463638490
access-key: LTAI5tSVfRSePk9cfLUT5y5f
secret: qlpXG6usf0zPgQQECDAlrfYoMRHxgM
#阿里云OSS
aliyun:
access-key-id: LTAI5tSVfRSePk9cfLUT5y5f
access-key-secret: qlpXG6usf0zPgQQECDAlrfYoMRHxgM
bucket-name: youban2023
endpoint: http://oss-cn-shenzhen.aliyuncs.com
url-prefix: http://quanmingtuodan.xyz/
#Adapay第三方支付
adapay:
app-id: app_77b944f9-99f5-4e62-94c1-ce1cc1ead4bc
rsa-private-key: MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALGI62YjX8UbBiupWPLYeck9TMNZVSLE09M8ZoSfe7yC3ZHO0S3Vq+q9aRsk9hOiOxiTA1tMtp5+5MvZyVK7mIC8FkTbSk3r4sJ+WtPkogOgFJ2xSljS4fu2wIVPYeGyOuWbB6npzJ121vFE91uhNIbK4K2QfJUqMYnWwYCCqyQHAgMBAAECgYBRUmqhyqpf21UkQtpfwxFmQRIcmZsJ5icxp4U+Ut+XJkrgM2BWIn4xdLnkmTWvIKz5QL5U3/r29yFOz2AM6amc6nHUuf9ArFqMFZ/2FgXu1y7UGU2cKq+ZZ2afyuG3EuxTycxxXEw/pekO94mSvjuGLxX/XzS+zb4Uzb9/J3xKwQJBAOk+pzsfdUR9dK1hrDZkgVmvq9tEi9yn0rteT5UW66lVOcypa3k9eZ6cTCv4CGJpl1wktr0l6pLi3JU27VNfZ28CQQDC2uW8pl9B9RxJR+s4QGaiySI0J0AmmRbPPol9kCegSPpg+Tcq9bYGNEI9dPy+EvkqejZLixPEU2V9IUSRigDpAkEAppls46sNnPUrUOhyFIvnZIM48q5cZCivOcwcdfZgL5xDY68jp/7EDwm+0q0geALJ7TQAHsylZ3OJcT9BdwqvGwJBAK+GuETEKjMkNaLdoko92TbysFkCsosShLWTxA7T+J4unz0Twlp0lM/p63GpHLOsK7/T720Fj3zfEyExAq+H/WECQQDc9MLEjO3CuEZ8PBPtC3krKglBK3XzXjqelb95bI+6YrI7I65V5sPYWYJBiOONczuWaD+SzEWMq2pIIustO2zW
api-key: api_live_759f9dbb-1048-4816-bb67-93281a6b2dd7
mock-api-key: api_test_e016292e-2b66-4891-8353-7e640407fe15
notify-url: http://www.quanmingtuodan.xyz:18000
#环信聊天
hx:
url: http://a1.easemob.com/
app-name: youban
org-name: 1198231130162318
client-id: YXA6vEylcIavRGCeXZVRkgq3eA
client-secret: YXA6i-kpSfafuseuVLMDdLLtOSgT8eQ
# 百度地图应用api
baidu:
ak: 'ZQTgMW7W0GTuE7Ripb0HDp5TqRaOI6PZ'
url: 'https://api.map.baidu.com/reverse_geocoding/v3/?ak=#AK#&output=json&coordtype=wgs84ll&location='

View File

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- logback-spring加载早于application.yml如果直接通过${参数key}的形式是无法获取到对应的参数值-->
<!-- source指定的是application.yml配置文件中key其它地方直接用${log.path}引用这个值 -->
<!-- 解决在相对路径下生成log.path_IS_UNDEFINED的问题增加defaultValue -->
<springProperty scope="context" name="base.path" source="logging.file.path" defaultValue=""/>
<!-- app.name根据你的应用名称修改 -->
<springProperty scope="context" name="app.name" source="spring.application.name" defaultValue="applog"/>
<property name="log.path" value="./logs/"/>
<!--格式化输出:%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度,%msg日志消息%n是换行符-->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - [%tid] - %msg%n"/>
<!-- 控制台日志输出配置 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${log.pattern}</pattern>
</layout>
</encoder>
</appender>
<appender name="GRPC" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${log.pattern}</pattern>
</layout>
</encoder>
</appender>
<!-- 文件输出日志配置,按照每天生成日志文件 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件输出的文件名称 -->
<FileNamePattern>${log.path}-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!-- 日志保留天数 -->
<MaxHistory>30</MaxHistory>
<MaxFileSize>10MB</MaxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<!--格式化输出:%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符-->
<pattern>${log.pattern}</pattern>
</layout>
</encoder>
</appender>
<!-- mybatis日志配置 -->
<!-- <logger name="java.sql.Connection" level="DEBUG"/>-->
<!-- <logger name="java.sql.Statement" level="DEBUG"/>-->
<!-- <logger name="java.sql.PreparedStatement" level="DEBUG"/>-->
<!-- 配置开发环境,多个使用逗号隔开(例如dev,sit) -->
<springProfile name="druid">
<!--定义日志输出级别-->
<root level="INFO">
<appender-ref ref="file"/>
<appender-ref ref="stdout"/>
<appender-ref ref="GRPC"/>
</root>
</springProfile>
<!-- 配置测试环境,多个使用逗号隔开 -->
<springProfile name="sit">
<!--定义日志输出级别-->
<root level="INFO">
<appender-ref ref="stdout"/>
<appender-ref ref="file"/>
</root>
</springProfile>
<!-- 配置生产环境,多个使用逗号隔开 -->
<springProfile name="prod">
<!--定义日志输出级别-->
<root level="INFO">
<appender-ref ref="stdout"/>
<appender-ref ref="file"/>
</root>
</springProfile>
</configuration>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="./logs" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 用户访问日志输出 -->
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.ruoyi" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>
</configuration>

View File

@ -1,7 +1,7 @@
/*! X-editable - v1.5.3
/*! X-editable - v1.5.1
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable
* Copyright (c) 2019 Vitaliy Potapov; Licensed MIT */
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
.editableform {
margin-bottom: 0; /* overwrites bootstrap margin */
}
@ -12,16 +12,6 @@
line-height: 20px; /* overwriting bootstrap line-height. See #133 */
}
/*
BS3 fix: stop css from breaking when the form is inside a popup and inside a form with the class .form-horizontal
See: https://github.com/vitalets/x-editable/issues/682
*/
.form-horizontal .editable-popup .editableform .form-group {
margin-left:0;
margin-right:0;
}
/*
BS3 width:1005 for inputs breaks editable form in popup
See: https://github.com/vitalets/x-editable/issues/393
@ -155,7 +145,6 @@
.editable-pre-wrapped {
white-space: pre-wrap;
}
.editable-container.editable-popup {
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
}

View File

@ -26,7 +26,7 @@ $.extend($.fn.bootstrapTable.columnDefaults, {
alwaysUseFormatter: false
})
$.extend($.fn.bootstrapTable.events, {
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'editable-init.bs.table': 'onEditableInit',
'editable-save.bs.table': 'onEditableSave',
'editable-shown.bs.table': 'onEditableShown',
@ -63,7 +63,7 @@ $.BootstrapTable = class extends $.BootstrapTable {
column.formatter = column.formatter || (value => value)
column._formatter = column._formatter ? column._formatter : column.formatter
column.formatter = (value, row, index, field) => {
column.formatter = (value, row, index) => {
let result = Utils.calculateObjectValue(column, column._formatter, [value, row, index], value)
result = typeof result === 'undefined' || result === null ? this.options.undefinedText : result
@ -86,7 +86,7 @@ $.BootstrapTable = class extends $.BootstrapTable {
column.editable, [index, row], {})
if (editableOpts.hasOwnProperty('noEditFormatter')) {
noEditFormatter = editableOpts.noEditFormatter(value, row, index, field)
noEditFormatter = editableOpts.noEditFormatter(value, row, index)
}
if (noEditFormatter === false) {
@ -177,9 +177,7 @@ $.BootstrapTable = class extends $.BootstrapTable {
if (params && params.escape) {
for (const row of data) {
for (const [key, value] of Object.entries(row)) {
if (typeof(value) !== "number") {
row[key] = Utils.unescapeHTML(value)
}
row[key] = Utils.unescapeHTML(value)
}
}
}

View File

@ -217,8 +217,6 @@
if (!data || data.length <= 0) {
var _empty = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">没有找到匹配的记录</div></td></tr>'
$tbody.html(_empty);
options.pageNumber = 1;
initPagination(0, 0);
return;
}
// 缓存并格式化数据
@ -274,9 +272,6 @@
if (pageTo > target.totalRows) {
pageTo = target.totalRows;
}
if (pageFrom > pageTo) {
pageFrom = pageTo;
}
html.push('<div class="pull-left pagination-detail">');
html.push('<span class="pagination-info">' + formatShowingRows(pageFrom, pageTo, target.totalRows) + '</span>');
var pageList = false;

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,3 +1,4 @@
/* *html{background-image: url(about:blank); background-attachment: fixed;} */
html #layuicss-layer{display: none; position: absolute; width: 1989px;}
/* common */
@ -8,8 +9,11 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
.layui-layer-close{position:absolute;}
.layui-layer-content{position:relative;}
.layui-layer-border{border: 1px solid #B2B2B2; border: 1px solid rgba(0,0,0,.1); box-shadow: 1px 1px 5px rgba(0,0,0,.2);}
.layui-layer-setwin span,
.layui-layer-btn a{display: inline-block; vertical-align: middle; *display: inline; *zoom:1; }
.layui-layer-load{background:url(loading-1.gif) #eee center center no-repeat;}
.layui-layer-ico{ background:url(icon.png) no-repeat;}
.layui-layer-dialog .layui-layer-ico,
.layui-layer-setwin a,
.layui-layer-btn a{display:inline-block; *display:inline; *zoom:1; vertical-align:top;}
.layui-layer-move{display: none; position: fixed; *position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; cursor: move; opacity: 0; filter:alpha(opacity=0); background-color: #fff; z-index: 2147483647;}
.layui-layer-resize{position: absolute; width: 15px; height: 15px; right: 0; bottom: 0; cursor: se-resize;}
@ -39,139 +43,54 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}
/* 从上往下 */
@keyframes layer-slide-down {
from {
transform: translate3d(0,-100%,0);
} to {
transform: translate3d(0,0,0);
}
}
@keyframes layer-slide-down-out {
from {
transform: translate3d(0,0,0);
} to {
transform: translate3d(0,-100%,0);
}
}
.layer-anim-slide-down{animation-name: layer-slide-down}
.layer-anim-slide-down-out{animation-name: layer-slide-down-out}
/* 从右往左 */
@keyframes layer-slide-left {
from {
transform: translate3d(100%,0,0);
} to {
transform: translate3d(0,0,0);
}
}
@keyframes layer-slide-left-out {
from {
transform: translate3d(0,0,0);
} to {
transform: translate3d(100%,0,0);
}
}
.layer-anim-slide-left{animation-name: layer-slide-left}
.layer-anim-slide-left-out{animation-name: layer-slide-left-out}
/* 从下往上 */
@keyframes layer-slide-up {
from {
transform: translate3d(0,100%,0);
} to {
transform: translate3d(0,0,0);
}
}
@keyframes layer-slide-up-out {
from {
transform: translate3d(0,0,0);
} to {
transform: translate3d(0,100%,0);
}
}
.layer-anim-slide-up{animation-name: layer-slide-up}
.layer-anim-slide-up-out{animation-name: layer-slide-up-out}
/* 从左往右 */
@keyframes layer-slide-right {
from {
transform: translate3d(-100%,0,0);
} to {
transform: translate3d(0,0,0);
}
}
@keyframes layer-slide-right-out {
from {
transform: translate3d(0,0,0);
} to {
transform: translate3d(-100%,0,0);
}
}
.layer-anim-slide-right{animation-name: layer-slide-right;}
.layer-anim-slide-right-out{animation-name: layer-slide-right-out;}
/* 标题栏 */
.layui-layer-title{padding: 0 81px 0 16px; height: 50px; line-height: 50px; border-bottom:1px solid #F0F0F0; font-size: 14px; color:#333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: 2px 2px 0 0;}
.layui-layer-setwin{position:absolute; right: 15px; *right:0; top: 16px; font-size:0; line-height: initial;}
.layui-layer-setwin span{position:relative; width: 16px; height: 16px; line-height: 18px; margin-left: 10px; text-align: center; font-size: 16px; cursor: pointer; color: #000; _overflow: hidden; box-sizing: border-box;}
.layui-layer-setwin .layui-layer-min:before{content: ''; position: absolute; width: 12px; border-bottom: 1px solid #2E2D3C; left: 50%; top: 50%; margin: -0.5px 0 0 -6px; cursor: pointer; _overflow:hidden;}
.layui-layer-setwin .layui-layer-min:hover:before{background-color: #2D93CA}
.layui-layer-setwin .layui-layer-max:hover:before,
.layui-layer-setwin .layui-layer-max:hover:after{border-color: #2D93CA;}
.layui-layer-setwin .layui-layer-min:hover:before{background-color: #2D93CA}
.layui-layer-setwin .layui-layer-maxmin:before,
.layui-layer-setwin .layui-layer-maxmin:after{width: 7px; height: 7px; margin: -3px 0 0 -3px; background-color: #fff;}
.layui-layer-setwin .layui-layer-maxmin:after{z-index: 0; margin: -5px 0 0 -1px;}
.layui-layer-setwin .layui-layer-close{cursor: pointer;}
.layui-layer-setwin .layui-layer-close:hover{opacity:0.7;}
.layui-layer-setwin .layui-layer-close2{position:absolute; right: -28px; top: -28px; color: #fff; background-color: #787878; padding: 3px; width: 16px; height: 20px; font-size: 16px; font-weight: bolder; border-radius: 50%; margin-left: 0; *right:-18px; _display:none;}
.layui-layer-setwin .layui-layer-close2:hover{opacity: unset; background-color: #3888f6;}
.layui-layer-title{padding:0 80px 0 20px; height: 50px; line-height: 50px; border-bottom:1px solid #F0F0F0; font-size: 14px; color:#333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: 2px 2px 0 0;}
.layui-layer-setwin{position:absolute; right: 15px; *right:0; top: 17px; font-size:0; line-height: initial;}
.layui-layer-setwin a{position:relative; width: 16px; height:16px; margin-left:10px; font-size:12px; _overflow:hidden;}
.layui-layer-setwin .layui-layer-min cite{position:absolute; width:14px; height:2px; left:0; top:50%; margin-top:-1px; background-color:#2E2D3C; cursor:pointer; _overflow:hidden;}
.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA; }
.layui-layer-setwin .layui-layer-max{background-position:-32px -40px;}
.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px;}
.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px;}
.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px;}
.layui-layer-setwin .layui-layer-close1{background-position: 1px -40px; cursor: pointer;}
.layui-layer-setwin .layui-layer-close1:hover{opacity:0.7;}
.layui-layer-setwin .layui-layer-close2{position:absolute; right:-28px; top:-28px; width:30px; height:30px; margin-left:0; background-position:-149px -31px; *right:-18px; _display:none;}
.layui-layer-setwin .layui-layer-close2:hover{ background-position:-180px -31px;}
/* 按钮栏 */
.layui-layer-btn{text-align: right; padding: 0 15px 12px; pointer-events: auto; user-select: none; -webkit-user-select: none;}
.layui-layer-btn a{height: 30px; line-height: 30px; margin: 5px 5px 0; padding: 0 16px; border: 1px solid #dedede; background-color: #fff; color: #333; border-radius: 2px; font-weight: 400; cursor: pointer; text-decoration: none; box-sizing: border-box;}
.layui-layer-btn a{height: 28px; line-height: 28px; margin: 5px 5px 0; padding: 0 15px; border: 1px solid #dedede; background-color:#fff; color: #333; border-radius: 2px; font-weight:400; cursor:pointer; text-decoration: none;}
.layui-layer-btn a:hover{opacity: 0.9; text-decoration: none;}
.layui-layer-btn a:active{opacity: 0.8;}
.layui-layer-btn .layui-layer-btn0{border-color: transparent; background-color: #1E9FFF; color:#fff;}
.layui-layer-btn .layui-layer-btn0{border-color: #1E9FFF; background-color: #1E9FFF; color:#fff;}
.layui-layer-btn-l{text-align: left;}
.layui-layer-btn-c{text-align: center;}
/* 定制化 */
.layui-layer-dialog{min-width: 240px;}
.layui-layer-dialog .layui-layer-content{position: relative; padding: 16px; line-height: 24px; word-break: break-all; overflow:hidden; font-size:14px; overflow-x: hidden; overflow-y:auto;}
.layui-layer-dialog .layui-layer-content .layui-layer-face{position: absolute; top: 18px; left: 16px; color: #959595; font-size: 32px; _left: -40px;}
.layui-layer-dialog .layui-layer-content .layui-icon-tips{color: #F39B12;}
.layui-layer-dialog .layui-layer-content .layui-icon-success{color: #16b777;}
.layui-layer-dialog .layui-layer-content .layui-icon-error{top: 19px; color: #FF5722;}
.layui-layer-dialog .layui-layer-content .layui-icon-question{color: #FFB800;}
.layui-layer-dialog .layui-layer-content .layui-icon-lock{color: #787878;}
.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color: #FF5722;}
.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color: #16b777;}
.layui-layer-dialog{min-width: 300px;}
.layui-layer-dialog .layui-layer-content{position: relative; padding:20px; line-height:24px; word-break: break-all; overflow:hidden; font-size:14px; overflow-x: hidden; overflow-y:auto;}
.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute; top:16px; left:15px; _left:-40px; width:30px; height:30px;}
.layui-layer-ico1{background-position:-30px 0 }
.layui-layer-ico2{background-position:-60px 0;}
.layui-layer-ico3{background-position:-90px 0;}
.layui-layer-ico4{background-position:-120px 0;}
.layui-layer-ico5{background-position:-150px 0;}
.layui-layer-ico6{background-position:-180px 0;}
.layui-layer-rim{border:6px solid #8D8D8D; border:6px solid rgba(0,0,0,.3); border-radius:5px; box-shadow: none;}
.layui-layer-msg{min-width:180px; border:1px solid #D3D4D3; box-shadow: none;}
.layui-layer-hui{min-width:100px; background-color: #000; filter:alpha(opacity=60); background-color: rgba(0,0,0,0.6); color: #fff; border:none;}
.layui-layer-hui .layui-layer-close{color: #fff;}
.layui-layer-hui .layui-layer-content{padding: 11px 24px; text-align: center;}
.layui-layer-dialog .layui-layer-padding{padding: 18px 24px 18px 58px; text-align: left;}
.layui-layer-hui .layui-layer-content{padding:12px 25px; text-align:center;}
.layui-layer-dialog .layui-layer-padding{padding: 20px 20px 20px 55px; text-align: left;}
.layui-layer-page .layui-layer-content{position:relative; overflow:auto;}
.layui-layer-page .layui-layer-btn,.layui-layer-iframe .layui-layer-btn{padding-top:10px;}
.layui-layer-nobg{background:none;}
.layui-layer-iframe iframe{display: block; width: 100%;}
.layui-layer-loading{border-radius:100%; background:none; box-shadow:none; border:none;}
.layui-layer-loading .layui-layer-content{width: 76px; height: 38px; line-height: 38px; text-align: center;}
.layui-layer-loading-icon{font-size: 38px; color: #959595;}
.layui-layer-loading2{text-align: center;}
.layui-layer-loading-2{position: relative; height: 38px;}
.layui-layer-loading-2:before,
.layui-layer-loading-2:after{content: ''; position: absolute; left: 50%; top: 50%; width: 38px; height: 38px; margin: -19px 0 0 -19px; border-radius: 50%; border: 3px solid #d2d2d2; box-sizing: border-box;}
.layui-layer-loading-2:after{border-color: transparent; border-left-color: #1E9FFF;}
.layui-layer-loading .layui-layer-content{width:60px; height:24px; background:url(loading-0.gif) no-repeat;}
.layui-layer-loading .layui-layer-loading1{width:37px; height:37px; background:url(loading-1.gif) no-repeat;}
.layui-layer-loading .layui-layer-loading2, .layui-layer-ico16{width:32px; height:32px; background:url(loading-2.gif) no-repeat;}
.layui-layer-tips{background: none; box-shadow:none; border:none;}
.layui-layer-tips .layui-layer-content{position: relative; line-height: 22px; min-width: 12px; padding: 8px 15px; font-size: 12px; _float:left; border-radius: 2px; box-shadow: 1px 1px 3px rgba(0,0,0,.2); background-color: #000; color: #fff;}
.layui-layer-tips .layui-layer-close{right:-2px; top:-1px;}
@ -183,31 +102,15 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
.layui-layer-tips i.layui-layer-TipsR{left:-8px;}
.layui-layer-tips i.layui-layer-TipsL{right:-8px;}
/* 内置 skin */
/* skin */
.layui-layer-lan[type="dialog"]{min-width:280px;}
.layui-layer-lan .layui-layer-title{background:#4476A7; color:#fff; border: none;}
.layui-layer-lan .layui-layer-btn{padding: 5px 10px 10px; border-top:1px solid #E9E7E7}
.layui-layer-lan .layui-layer-btn{padding: 5px 10px 10px; text-align: right; border-top:1px solid #E9E7E7}
.layui-layer-lan .layui-layer-btn a{background: #fff; border-color: #E9E7E7; color: #333;}
.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5;}
.layui-layer-molv .layui-layer-title{background: #009f95; color:#fff; border: none;}
.layui-layer-molv .layui-layer-btn a{background: #009f95; border-color: #009f95;}
.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1;}
.layui-layer-lan .layui-layer-setwin .layui-icon,
.layui-layer-molv .layui-layer-setwin .layui-icon{color: #fff;}
/* Windows 10 风格主题 */
.layui-layer-win10{border: 1px solid #aaa; box-shadow: 1px 1px 6px rgba(0,0,0,.3); border-radius: none;}
.layui-layer-win10 .layui-layer-title{height: 32px; line-height: 32px; padding-left: 8px; border-bottom: none; font-size: 12px;}
.layui-layer-win10 .layui-layer-setwin{right: 0; top: 0;}
.layui-layer-win10 .layui-layer-setwin span{margin-left: 0; width: 32px; height: 32px; padding: 8px;}
.layui-layer-win10.layui-layer-page .layui-layer-setwin span{width: 38px;}
.layui-layer-win10 .layui-layer-setwin span:hover{background-color: #E5E5E5;}
.layui-layer-win10 .layui-layer-setwin span.layui-icon-close:hover{background-color: #E81123; color: #fff;}
.layui-layer-win10.layui-layer-dialog .layui-layer-content{padding: 8px 16px 32px; color: #0033BC;}
.layui-layer-win10.layui-layer-dialog .layui-layer-padding{padding-top: 18px; padding-left: 58px;}
.layui-layer-win10 .layui-layer-btn{padding: 5px 5px 10px; border-top:1px solid #DFDFDF; background-color: #F0F0F0;}
.layui-layer-win10 .layui-layer-btn a{height: 20px; line-height: 18px; background-color: #E1E1E1; border-color: #ADADAD; color: #000; font-size: 12px; transition: all .3s;}
.layui-layer-win10 .layui-layer-btn a:hover{border-color: #2A8EDD; background-color: #E5F1FB;}
.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color: #0078D7;}
/**
@ -216,44 +119,39 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
*/
.layui-layer-iconext{background:url(icon-ext.png) no-repeat;}
/* prompt模式 */
.layui-layer-prompt .layui-layer-input{display: block; width: 260px; height: 36px; margin: 0 auto; line-height: 30px; padding-left: 10px; border: 1px solid #e6e6e6; color: #333;}
.layui-layer-prompt textarea.layui-layer-input{width: 300px; height: 100px; line-height: 20px; padding: 6px 10px;}
.layui-layer-prompt .layui-layer-content{padding: 16px;}
.layui-layer-prompt .layui-layer-content{padding: 20px;}
.layui-layer-prompt .layui-layer-btn{padding-top: 0;}
/* tab模式 */
.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4);}
.layui-layer-tab .layui-layer-title{padding-left:0; overflow: visible;}
.layui-layer-tab .layui-layer-title span{position:relative; display: inline-block; vertical-align: top; border-left: 1px solid transparent; border-right: 1px solid transparent; min-width:80px; max-width: 300px; padding:0 16px; text-align:center; cursor:default; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; cursor: pointer;}
.layui-layer-tab .layui-layer-title span.layui-this{height: 51px; border-left-color: #eee; border-right-color: #eee; background-color: #fff; z-index: 10;}
.layui-layer-tab .layui-layer-title span:first-child{border-left-color: transparent;}
.layui-layer-tabmain{line-height:24px; clear: both;}
.layui-layer-tab .layui-layer-title span{position:relative; float:left; min-width:80px; max-width: 300px; padding:0 20px; text-align:center; cursor:default; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; cursor: pointer;}
.layui-layer-tab .layui-layer-title span.layui-this{height: 51px; border-left: 1px solid #eee; border-right: 1px solid #eee; background-color: #fff; z-index: 10;}
.layui-layer-tab .layui-layer-title span:first-child{border-left:none;}
.layui-layer-tabmain{line-height:24px; clear:both;}
.layui-layer-tabmain .layui-layer-tabli{display:none;}
.layui-layer-tabmain .layui-layer-tabli.layui-this{display: block;}
/* photos */
/* photo模式 */
.layui-layer-photos{background: none; box-shadow: none;}
.layui-layer-photos .layui-layer-content{overflow: visible; text-align: center;}
.layui-layer-photos .layer-layer-photos-main img{position: relative; width:100%; display: inline-block; *display:inline; *zoom:1; vertical-align:top;}
.layui-layer-photos-prev,
.layui-layer-photos-next{position: fixed; top: 50%; width: 52px; height: 52px; line-height: 52px; margin-top: -26px; cursor: pointer; font-size: 52px; color: #717171;}
.layui-layer-photos-prev{left: 32px;}
.layui-layer-photos-next{right: 32px;}
.layui-layer-photos-prev:hover,
.layui-layer-photos-next:hover{color: #959595;}
.layui-layer-photos-toolbar{position: fixed; left: 0; right: 0; bottom: 0; width: 100%; height: 52px; line-height: 52px; background-color: #000\9; filter: Alpha(opacity=60); background-color: rgba(0,0,0,.32); color: #fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;}
.layui-layer-photos-toolbar > *{display:inline-block; vertical-align: top; padding: 0 16px; font-size: 12px; color: #fff; *display:inline; *zoom: 1;}
.layui-layer-photos-toolbar *{font-size: 12px;}
.layui-layer-photos-header{top: 0; bottom: auto;}
.layui-layer-photos-header > span{cursor: pointer;}
.layui-layer-photos-header > span:hover{background-color: rgba(51,51,51,.32);}
.layui-layer-photos-header .layui-icon{font-size: 18px;}
.layui-layer-photos-footer > h3{max-width: 65%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;}
.layui-layer-photos-footer a:hover{text-decoration: underline;}
.layui-layer-photos-footer em{font-style: normal;}
.layui-layer-photos .layui-layer-content{overflow:hidden; text-align: center;}
.layui-layer-photos .layui-layer-phimg img{position: relative; width:100%; display: inline-block; *display:inline; *zoom:1; vertical-align:top;}
.layui-layer-imgprev, .layui-layer-imgnext{position: fixed; top: 50%; width: 27px; _width: 44px; height: 44px; margin-top:-22px; outline:none;blr:expression(this.onFocus=this.blur());}
.layui-layer-imgprev{left: 30px; background-position:-5px -5px; _background-position:-70px -5px;}
.layui-layer-imgprev:hover{background-position:-33px -5px; _background-position:-120px -5px;}
.layui-layer-imgnext{right: 30px; _right:8px; background-position:-5px -50px; _background-position:-70px -50px;}
.layui-layer-imgnext:hover{background-position: -33px -50px; _background-position: -120px -50px;}
.layui-layer-imgbar{position: fixed; left:0; right: 0; bottom:0; width:100%; height: 40px; line-height: 40px; background-color:#000\9; filter:Alpha(opacity=60); background-color: rgba(2,0,0,.35); color: #fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;}
.layui-layer-imgtit{/*position:absolute; left:20px;*/}
.layui-layer-imgtit *{display:inline-block; *display:inline; *zoom:1; vertical-align:top; font-size:12px;}
.layui-layer-imgtit a{max-width:65%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; color:#fff;}
.layui-layer-imgtit a:hover{color:#fff; text-decoration:underline;}
.layui-layer-imgtit em{padding-left:10px; font-style: normal;}
/* 关闭动画 */
@-webkit-keyframes layer-bounceOut {

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -21,33 +21,35 @@ body .layer-ext-moon .layui-layer-title {
border: none;
}
body .layer-ext-moon .layui-layer-content .layui-layer-face {
body .layer-ext-moon .layui-layer-content .layui-layer-ico {
height: 32px;
width: 32px;
top:18.5px;
}
body .layer-ext-moon .layui-icon-tips {
body .layer-ext-moon .layui-layer-ico0 {
background: url(default.png) no-repeat -96px 0;
;
}
body .layer-ext-moon .layui-icon-success {
body .layer-ext-moon .layui-layer-ico1 {
background: url(default.png) no-repeat -224px 0;
;
}
body .layer-ext-moon .layui-icon-error {
body .layer-ext-moon .layui-layer-ico2 {
background: url(default.png) no-repeat -192px 0;
}
body .layer-ext-moon .layui-icon-question {
body .layer-ext-moon .layui-layer-ico3 {
background: url(default.png) no-repeat -160px 0;
}
body .layer-ext-moon .layui-icon-lock {
body .layer-ext-moon .layui-layer-ico4 {
background: url(default.png) no-repeat -320px 0;
}
body .layer-ext-moon .layui-icon-face-cry {
body .layer-ext-moon .layui-layer-ico5 {
background: url(default.png) no-repeat -288px 0;
}
body .layer-ext-moon .layui-icon-face-smile {
body .layer-ext-moon .layui-layer-ico6 {
background: url(default.png) -256px 0;
}
body .layer-ext-moon .layui-layer-download {
body .layer-ext-moon .layui-layer-ico7 {
background: url(default.png) no-repeat -128px 0;
}
body .layer-ext-moon .layui-layer-setwin {
@ -73,10 +75,10 @@ body .layer-ext-moon .layui-layer-setwin .layui-layer-maxmin {
body .layer-ext-moon .layui-layer-setwin .layui-layer-maxmin:hover {
background: url(default.png) no-repeat -16px 0;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-close1,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2, body .layui-layer-tab .layui-layer-setwin .layui-layer-close1,body .layui-layer-tab .layui-layer-setwin .layui-layer-close2 {
body .layer-ext-moon .layui-layer-setwin .layui-layer-close1,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2 {
background: url(default.png) 0 0;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-close1:hover,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2:hover, body .layui-layer-tab .layui-layer-setwin .layui-layer-close1:hover,body .layui-layer-tab .layui-layer-setwin .layui-layer-close2:hover {
body .layer-ext-moon .layui-layer-setwin .layui-layer-close1:hover,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2:hover {
background: url(default.png) -48px 0;
}
body .layer-ext-moon .layui-layer-padding{padding-top: 24px;}
@ -134,36 +136,3 @@ body .layer-ext-moon .layui-layer-btn .layui-layer-btn3 {
body .layer-ext-moon .layui-layer-title span.layui-layer-tabnow{
height:47px;
}
/** 图标字体 **/
@font-face {
font-family: 'layui-icon';
src: url('../../../../../fonts/iconfont.woff?v=282') format('woff');
}
.layui-icon{
font-family:"layui-icon" !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* font-class */
.layui-icon-left:before{content:"\e603"}
.layui-icon-right:before{content:"\e602"}
.layui-icon-refresh:before{content:"\e669"}
.layui-icon-slider:before{content:"\e714"}
.layui-icon-add-circle:before{content:"\e61f"}
.layui-icon-reduce-circle:before{content:"\e616"}
.layui-icon-refresh-1:before{content:"\e666"}
.layui-icon-loading:before{content:"\e63d"}
.layui-icon-loading-1:before{content:"\e63e"}
/** 循环旋转动画 **/
.layui-anim{-webkit-animation-duration: 0.3s; -webkit-animation-fill-mode: both; animation-duration: 0.3s; animation-fill-mode: both;}
.layui-anim.layui-icon{display: inline-block;}
.layui-anim-loop{-webkit-animation-iteration-count: infinite; animation-iteration-count: infinite;}
.layui-trans,
.layui-trans a{transition: all .2s; -webkit-transition: all .2s;}
@-webkit-keyframes layui-rotate{from {-webkit-transform: rotate(0deg);} to {-webkit-transform: rotate(360deg);}}
@keyframes layui-rotate{from {transform: rotate(0deg);} to {transform: rotate(360deg);}}
.layui-anim-rotate{-webkit-animation-name: layui-rotate; animation-name: layui-rotate; -webkit-animation-duration: 1s; animation-duration: 1s; -webkit-animation-timing-function: linear; animation-timing-function: linear;}

File diff suppressed because one or more lines are too long

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