完成问题反馈
This commit is contained in:
298
docs/API接口说明-反馈功能.md
Normal file
298
docs/API接口说明-反馈功能.md
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
# API 接口说明 - 问题反馈功能
|
||||||
|
|
||||||
|
## 问题反馈相关接口
|
||||||
|
|
||||||
|
### 1. 创建反馈
|
||||||
|
|
||||||
|
**接口地址:** `POST /feedback`
|
||||||
|
|
||||||
|
**请求头:**
|
||||||
|
```
|
||||||
|
Authorization: your-token(可选,支持匿名提交)
|
||||||
|
```
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"feedbackType": "功能建议", // 问题类型(必填)
|
||||||
|
"title": "希望增加夜间模式", // 问题标题(必填)
|
||||||
|
"content": "详细描述...", // 问题描述(可选)
|
||||||
|
"contact": "user@example.com" // 联系方式(可选)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "反馈提交成功",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:**
|
||||||
|
- 支持匿名提交,如果已登录会自动关联用户ID
|
||||||
|
- 问题类型建议:功能建议、Bug反馈、使用问题、其他
|
||||||
|
- 联系方式用于后续沟通,建议填写邮箱或手机号
|
||||||
|
- 反馈默认状态为"待处理"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 查询当前用户的反馈列表
|
||||||
|
|
||||||
|
**接口地址:** `GET /feedback/my`
|
||||||
|
|
||||||
|
**请求头:**
|
||||||
|
```
|
||||||
|
Authorization: your-token
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "success",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"userId": 1,
|
||||||
|
"feedbackType": "功能建议",
|
||||||
|
"title": "希望增加夜间模式",
|
||||||
|
"content": "详细描述...",
|
||||||
|
"contact": "user@example.com",
|
||||||
|
"status": 0,
|
||||||
|
"createTime": "2025-01-01T12:00:00",
|
||||||
|
"updateTime": "2025-01-01T12:00:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:**
|
||||||
|
- 需要登录
|
||||||
|
- 返回当前用户提交的所有反馈
|
||||||
|
- 按创建时间倒序排序
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 根据ID查询反馈详情
|
||||||
|
|
||||||
|
**接口地址:** `GET /feedback/{id}`
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "success",
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"userId": 1,
|
||||||
|
"feedbackType": "功能建议",
|
||||||
|
"title": "希望增加夜间模式",
|
||||||
|
"content": "详细描述...",
|
||||||
|
"contact": "user@example.com",
|
||||||
|
"status": 0,
|
||||||
|
"createTime": "2025-01-01T12:00:00",
|
||||||
|
"updateTime": "2025-01-01T12:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:**
|
||||||
|
- 不需要登录
|
||||||
|
- 根据反馈ID查询详情
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. 分页查询反馈列表
|
||||||
|
|
||||||
|
**接口地址:** `GET /feedback/page`
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
```
|
||||||
|
current: 当前页码(默认1)
|
||||||
|
size: 每页数量(默认10)
|
||||||
|
userId: 用户ID(可选,用于筛选指定用户的反馈)
|
||||||
|
feedbackType: 问题类型(可选,用于筛选指定类型的反馈)
|
||||||
|
status: 状态(可选,用于筛选指定状态的反馈)
|
||||||
|
```
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```
|
||||||
|
GET /feedback/page?current=1&size=10&feedbackType=功能建议&status=0
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "success",
|
||||||
|
"data": {
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"userId": 1,
|
||||||
|
"feedbackType": "功能建议",
|
||||||
|
"title": "希望增加夜间模式",
|
||||||
|
"content": "详细描述...",
|
||||||
|
"contact": "user@example.com",
|
||||||
|
"status": 0,
|
||||||
|
"createTime": "2025-01-01T12:00:00",
|
||||||
|
"updateTime": "2025-01-01T12:00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 100,
|
||||||
|
"size": 10,
|
||||||
|
"current": 1,
|
||||||
|
"pages": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:**
|
||||||
|
- 不需要登录
|
||||||
|
- 支持分页和多条件筛选
|
||||||
|
- 按创建时间倒序排序
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. 更新反馈状态
|
||||||
|
|
||||||
|
**接口地址:** `PUT /feedback/{id}/status`
|
||||||
|
|
||||||
|
**请求参数:**
|
||||||
|
```
|
||||||
|
status: 状态值(0-待处理 1-处理中 2-已完成 3-已关闭)
|
||||||
|
```
|
||||||
|
|
||||||
|
**请求示例:**
|
||||||
|
```
|
||||||
|
PUT /feedback/1/status?status=1
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "状态更新成功",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:**
|
||||||
|
- 不需要登录
|
||||||
|
- 用于管理员更新反馈处理状态
|
||||||
|
- 状态说明:
|
||||||
|
- 0: 待处理
|
||||||
|
- 1: 处理中
|
||||||
|
- 2: 已完成
|
||||||
|
- 3: 已关闭
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. 删除反馈
|
||||||
|
|
||||||
|
**接口地址:** `DELETE /feedback/{id}`
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "删除成功",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**说明:**
|
||||||
|
- 不需要登录
|
||||||
|
- 用于管理员删除反馈
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据库说明
|
||||||
|
|
||||||
|
### 反馈表结构
|
||||||
|
|
||||||
|
**建表 SQL:** `src/main/resources/db/feedback.sql`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `app_feedback` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '反馈ID',
|
||||||
|
`user_id` BIGINT(20) DEFAULT NULL COMMENT '用户ID',
|
||||||
|
`feedback_type` VARCHAR(50) NOT NULL COMMENT '问题类型',
|
||||||
|
`title` VARCHAR(200) NOT NULL COMMENT '问题标题',
|
||||||
|
`content` TEXT DEFAULT NULL COMMENT '问题描述',
|
||||||
|
`contact` VARCHAR(100) DEFAULT NULL COMMENT '联系方式',
|
||||||
|
`status` TINYINT(1) DEFAULT 0 COMMENT '处理状态:0-待处理 1-处理中 2-已完成 3-已关闭',
|
||||||
|
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_create_time` (`create_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='问题反馈表';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 错误码说明
|
||||||
|
|
||||||
|
| 错误码 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| 200 | 成功 |
|
||||||
|
| 500 | 失败 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 开发说明
|
||||||
|
|
||||||
|
### 代码结构
|
||||||
|
|
||||||
|
```
|
||||||
|
com.corewing.app/
|
||||||
|
├── controller/
|
||||||
|
│ └── AppFeedbackController.java # 反馈控制器
|
||||||
|
├── dto/
|
||||||
|
│ └── FeedbackRequest.java # 反馈请求参数
|
||||||
|
├── entity/
|
||||||
|
│ └── AppFeedback.java # 反馈实体类
|
||||||
|
├── mapper/
|
||||||
|
│ └── AppFeedbackMapper.java # 反馈Mapper接口
|
||||||
|
└── service/
|
||||||
|
├── AppFeedbackService.java # 反馈服务接口
|
||||||
|
└── impl/
|
||||||
|
└── AppFeedbackServiceImpl.java # 反馈服务实现
|
||||||
|
```
|
||||||
|
|
||||||
|
### 功能特性
|
||||||
|
|
||||||
|
1. **匿名提交** - 支持匿名用户提交反馈,不需要登录
|
||||||
|
2. **自动关联** - 已登录用户提交反馈时自动关联用户ID
|
||||||
|
3. **状态管理** - 完整的反馈状态流转:待处理 → 处理中 → 已完成/已关闭
|
||||||
|
4. **分页查询** - 支持分页和多条件筛选
|
||||||
|
5. **MyBatis Plus** - 使用 MyBatis Plus 实现数据持久化
|
||||||
|
6. **自动填充** - 创建时间和更新时间自动填充
|
||||||
|
|
||||||
|
### 权限说明
|
||||||
|
|
||||||
|
- 所有反馈接口都不需要身份认证
|
||||||
|
- `/feedback` 和 `/feedback/**` 已在 Sa-Token 配置中加入白名单
|
||||||
|
- 管理员可以通过状态更新和删除接口管理反馈
|
||||||
|
|
||||||
|
### 使用流程
|
||||||
|
|
||||||
|
1. **用户提交反馈**
|
||||||
|
- 访问 `POST /feedback` 接口
|
||||||
|
- 填写问题类型、标题、描述、联系方式
|
||||||
|
- 系统自动创建反馈记录
|
||||||
|
|
||||||
|
2. **查看反馈列表**
|
||||||
|
- 已登录用户:访问 `GET /feedback/my` 查看自己的反馈
|
||||||
|
- 管理员:访问 `GET /feedback/page` 查看所有反馈
|
||||||
|
|
||||||
|
3. **处理反馈**
|
||||||
|
- 管理员通过 `PUT /feedback/{id}/status` 更新反馈状态
|
||||||
|
- 状态流转:待处理 → 处理中 → 已完成
|
||||||
|
|
||||||
|
4. **查看详情**
|
||||||
|
- 通过 `GET /feedback/{id}` 查看反馈详情
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# API 接口说明
|
# API 接口说明
|
||||||
|
|
||||||
## 用户相关接
|
## 用户相关接口
|
||||||
|
|
||||||
### 1. 发送验证码
|
### 1. 发送验证码
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ public class SaTokenConfig implements WebMvcConfigurer {
|
|||||||
.addPathPatterns("/**")
|
.addPathPatterns("/**")
|
||||||
// 排除登录、注册、发送验证码接口
|
// 排除登录、注册、发送验证码接口
|
||||||
.excludePathPatterns("/user/login", "/user/register", "/user/sendCode")
|
.excludePathPatterns("/user/login", "/user/register", "/user/sendCode")
|
||||||
|
// 排除反馈接口(支持匿名提交)
|
||||||
|
.excludePathPatterns("/feedback", "/feedback/**")
|
||||||
// 排除静态资源
|
// 排除静态资源
|
||||||
.excludePathPatterns("/", "/index.html", "/*.html", "/*.css", "/*.js", "/*.ico", "/static/**")
|
.excludePathPatterns("/", "/index.html", "/*.html", "/*.css", "/*.js", "/*.ico", "/static/**")
|
||||||
// 排除 Druid 监控
|
// 排除 Druid 监控
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
package com.corewing.app.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.corewing.app.common.Result;
|
||||||
|
import com.corewing.app.dto.FeedbackRequest;
|
||||||
|
import com.corewing.app.entity.AppFeedback;
|
||||||
|
import com.corewing.app.service.AppFeedbackService;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题反馈 Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/feedback")
|
||||||
|
public class AppFeedbackController {
|
||||||
|
|
||||||
|
private final AppFeedbackService feedbackService;
|
||||||
|
|
||||||
|
public AppFeedbackController(AppFeedbackService feedbackService) {
|
||||||
|
this.feedbackService = feedbackService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建反馈(支持匿名提交)
|
||||||
|
*/
|
||||||
|
@PostMapping
|
||||||
|
public Result<String> create(@RequestBody FeedbackRequest request) {
|
||||||
|
try {
|
||||||
|
// 尝试获取当前登录用户ID(如果未登录则为null)
|
||||||
|
Long userId = null;
|
||||||
|
try {
|
||||||
|
userId = StpUtil.getLoginIdAsLong();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 未登录,userId 保持为 null
|
||||||
|
}
|
||||||
|
|
||||||
|
AppFeedback feedback = new AppFeedback();
|
||||||
|
feedback.setUserId(userId);
|
||||||
|
feedback.setFeedbackType(request.getFeedbackType());
|
||||||
|
feedback.setTitle(request.getTitle());
|
||||||
|
feedback.setContent(request.getContent());
|
||||||
|
feedback.setContact(request.getContact());
|
||||||
|
|
||||||
|
boolean success = feedbackService.createFeedback(feedback);
|
||||||
|
if (success) {
|
||||||
|
return Result.success("反馈提交成功");
|
||||||
|
}
|
||||||
|
return Result.error("反馈提交失败");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询当前用户的反馈列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/my")
|
||||||
|
public Result<List<AppFeedback>> getMyFeedbackList() {
|
||||||
|
try {
|
||||||
|
// 获取当前登录用户ID
|
||||||
|
Long userId = StpUtil.getLoginIdAsLong();
|
||||||
|
List<AppFeedback> feedbackList = feedbackService.listByUserId(userId);
|
||||||
|
return Result.success(feedbackList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询反馈详情
|
||||||
|
*/
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Result<AppFeedback> getById(@PathVariable Long id) {
|
||||||
|
try {
|
||||||
|
AppFeedback feedback = feedbackService.getById(id);
|
||||||
|
if (feedback != null) {
|
||||||
|
return Result.success(feedback);
|
||||||
|
}
|
||||||
|
return Result.error("反馈不存在");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询反馈列表
|
||||||
|
*
|
||||||
|
* @param current 当前页码
|
||||||
|
* @param size 每页数量
|
||||||
|
* @param userId 用户ID(可选)
|
||||||
|
* @param feedbackType 问题类型(可选)
|
||||||
|
* @param status 状态(可选)
|
||||||
|
*/
|
||||||
|
@GetMapping("/page")
|
||||||
|
public Result<IPage<AppFeedback>> getPageList(
|
||||||
|
@RequestParam(defaultValue = "1") Long current,
|
||||||
|
@RequestParam(defaultValue = "10") Long size,
|
||||||
|
@RequestParam(required = false) Long userId,
|
||||||
|
@RequestParam(required = false) String feedbackType,
|
||||||
|
@RequestParam(required = false) Integer status) {
|
||||||
|
try {
|
||||||
|
Page<AppFeedback> page = new Page<>(current, size);
|
||||||
|
IPage<AppFeedback> pageResult = feedbackService.pageList(page, userId, feedbackType, status);
|
||||||
|
return Result.success(pageResult);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新反馈状态
|
||||||
|
*/
|
||||||
|
@PutMapping("/{id}/status")
|
||||||
|
public Result<String> updateStatus(@PathVariable Long id, @RequestParam Integer status) {
|
||||||
|
try {
|
||||||
|
boolean success = feedbackService.updateStatus(id, status);
|
||||||
|
if (success) {
|
||||||
|
return Result.success("状态更新成功");
|
||||||
|
}
|
||||||
|
return Result.error("状态更新失败");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除反馈
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result<String> delete(@PathVariable Long id) {
|
||||||
|
try {
|
||||||
|
boolean success = feedbackService.removeById(id);
|
||||||
|
if (success) {
|
||||||
|
return Result.success("删除成功");
|
||||||
|
}
|
||||||
|
return Result.error("删除失败");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/main/java/com/corewing/app/dto/FeedbackRequest.java
Normal file
34
src/main/java/com/corewing/app/dto/FeedbackRequest.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package com.corewing.app.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建反馈请求
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FeedbackRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题类型
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "问题类型不能为空")
|
||||||
|
private String feedbackType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题标题
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "问题标题不能为空")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题描述
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系方式
|
||||||
|
*/
|
||||||
|
private String contact;
|
||||||
|
}
|
||||||
69
src/main/java/com/corewing/app/entity/AppFeedback.java
Normal file
69
src/main/java/com/corewing/app/entity/AppFeedback.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package com.corewing.app.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题反馈实体类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("app_feedback")
|
||||||
|
public class AppFeedback implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反馈ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题类型
|
||||||
|
*/
|
||||||
|
private String feedbackType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题标题
|
||||||
|
*/
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题描述
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系方式
|
||||||
|
*/
|
||||||
|
private String contact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理状态:0-待处理 1-处理中 2-已完成 3-已关闭
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.corewing.app.handler;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.exception.NotLoginException;
|
||||||
|
import com.corewing.app.common.Result;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理器
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
@Slf4j
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 Sa-Token 未登录异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(NotLoginException.class)
|
||||||
|
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||||
|
public Result<String> handleNotLoginException(NotLoginException e) {
|
||||||
|
// 根据不同的场景返回不同的提示
|
||||||
|
String message;
|
||||||
|
switch (e.getType()) {
|
||||||
|
case NotLoginException.NOT_TOKEN:
|
||||||
|
message = "未提供登录凭证";
|
||||||
|
break;
|
||||||
|
case NotLoginException.INVALID_TOKEN:
|
||||||
|
message = "登录凭证无效";
|
||||||
|
break;
|
||||||
|
case NotLoginException.TOKEN_TIMEOUT:
|
||||||
|
message = "登录已过期,请重新登录";
|
||||||
|
break;
|
||||||
|
case NotLoginException.BE_REPLACED:
|
||||||
|
message = "账号已在其他地方登录";
|
||||||
|
break;
|
||||||
|
case NotLoginException.KICK_OUT:
|
||||||
|
message = "账号已被踢下线";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = "未登录,请先登录";
|
||||||
|
}
|
||||||
|
return Result.error(HttpStatus.UNAUTHORIZED.value(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理其他异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
public Result<String> handleException(Exception e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器内部错误:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/main/java/com/corewing/app/mapper/AppFeedbackMapper.java
Normal file
13
src/main/java/com/corewing/app/mapper/AppFeedbackMapper.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package com.corewing.app.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.corewing.app.entity.AppFeedback;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题反馈 Mapper 接口
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface AppFeedbackMapper extends BaseMapper<AppFeedback> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.corewing.app.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.corewing.app.entity.AppFeedback;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题反馈 Service 接口
|
||||||
|
*/
|
||||||
|
public interface AppFeedbackService extends IService<AppFeedback> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建反馈
|
||||||
|
*
|
||||||
|
* @param feedback 反馈信息
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean createFeedback(AppFeedback feedback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询反馈列表
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 反馈列表
|
||||||
|
*/
|
||||||
|
List<AppFeedback> listByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询反馈列表
|
||||||
|
*
|
||||||
|
* @param page 分页参数
|
||||||
|
* @param userId 用户ID(可选)
|
||||||
|
* @param feedbackType 问题类型(可选)
|
||||||
|
* @param status 状态(可选)
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
IPage<AppFeedback> pageList(Page<AppFeedback> page, Long userId, String feedbackType, Integer status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新反馈状态
|
||||||
|
*
|
||||||
|
* @param id 反馈ID
|
||||||
|
* @param status 状态
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean updateStatus(Long id, Integer status);
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.corewing.app.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.corewing.app.entity.AppFeedback;
|
||||||
|
import com.corewing.app.mapper.AppFeedbackMapper;
|
||||||
|
import com.corewing.app.service.AppFeedbackService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题反馈 Service 实现类
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class AppFeedbackServiceImpl extends ServiceImpl<AppFeedbackMapper, AppFeedback> implements AppFeedbackService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createFeedback(AppFeedback feedback) {
|
||||||
|
// 设置默认状态为待处理
|
||||||
|
if (feedback.getStatus() == null) {
|
||||||
|
feedback.setStatus(0);
|
||||||
|
}
|
||||||
|
return this.save(feedback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AppFeedback> listByUserId(Long userId) {
|
||||||
|
if (userId == null) {
|
||||||
|
throw new RuntimeException("用户ID不能为空");
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<AppFeedback> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(AppFeedback::getUserId, userId)
|
||||||
|
.orderByDesc(AppFeedback::getCreateTime);
|
||||||
|
return this.list(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IPage<AppFeedback> pageList(Page<AppFeedback> page, Long userId, String feedbackType, Integer status) {
|
||||||
|
LambdaQueryWrapper<AppFeedback> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
|
||||||
|
// 条件查询
|
||||||
|
if (userId != null) {
|
||||||
|
wrapper.eq(AppFeedback::getUserId, userId);
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(feedbackType)) {
|
||||||
|
wrapper.eq(AppFeedback::getFeedbackType, feedbackType);
|
||||||
|
}
|
||||||
|
if (status != null) {
|
||||||
|
wrapper.eq(AppFeedback::getStatus, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按创建时间倒序排序
|
||||||
|
wrapper.orderByDesc(AppFeedback::getCreateTime);
|
||||||
|
|
||||||
|
return this.page(page, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateStatus(Long id, Integer status) {
|
||||||
|
if (id == null) {
|
||||||
|
throw new RuntimeException("反馈ID不能为空");
|
||||||
|
}
|
||||||
|
if (status == null) {
|
||||||
|
throw new RuntimeException("状态不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppFeedback feedback = new AppFeedback();
|
||||||
|
feedback.setId(id);
|
||||||
|
feedback.setStatus(status);
|
||||||
|
|
||||||
|
return this.updateById(feedback);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/resources/db/feedback.sql
Normal file
18
src/main/resources/db/feedback.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
-- 问题反馈表
|
||||||
|
DROP TABLE IF EXISTS `app_feedback`;
|
||||||
|
|
||||||
|
CREATE TABLE `app_feedback` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '反馈ID',
|
||||||
|
`user_id` BIGINT(20) DEFAULT NULL COMMENT '用户ID',
|
||||||
|
`feedback_type` VARCHAR(50) NOT NULL COMMENT '问题类型',
|
||||||
|
`title` VARCHAR(200) NOT NULL COMMENT '问题标题',
|
||||||
|
`content` TEXT DEFAULT NULL COMMENT '问题描述',
|
||||||
|
`contact` VARCHAR(100) DEFAULT NULL COMMENT '联系方式',
|
||||||
|
`status` TINYINT(1) DEFAULT 0 COMMENT '处理状态:0-待处理 1-处理中 2-已完成 3-已关闭',
|
||||||
|
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_create_time` (`create_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='问题反馈表';
|
||||||
Reference in New Issue
Block a user