【新增】反馈管理
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package com.corewing.app.dto.biz.feedback;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class FeedbackBatchDeleteRequest {
|
||||
|
||||
private List<Long> ids;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.corewing.app.dto.biz.feedback;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class FeedbackBatchStatusRequest {
|
||||
|
||||
private List<Long> ids;
|
||||
|
||||
private Integer status;
|
||||
}
|
||||
@@ -66,4 +66,34 @@ public class Feedback implements Serializable {
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String username;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String statusName;
|
||||
|
||||
public String getStatusName() {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return "待处理";
|
||||
case 1:
|
||||
return "处理中";
|
||||
case 2:
|
||||
return "已完成";
|
||||
case 3:
|
||||
return "已关闭";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.corewing.app.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.corewing.app.entity.Feedback;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 问题反馈 Mapper 接口
|
||||
@@ -10,4 +12,5 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
@Mapper
|
||||
public interface FeedbackMapper extends BaseMapper<Feedback> {
|
||||
|
||||
Page<Feedback> page(Page<Feedback> page, @Param("feedback") Feedback feedback);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.corewing.app.modules.admin.biz;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.corewing.app.common.Result;
|
||||
import com.corewing.app.dto.biz.feedback.FeedbackBatchDeleteRequest;
|
||||
import com.corewing.app.dto.biz.feedback.FeedbackBatchStatusRequest;
|
||||
import com.corewing.app.entity.Feedback;
|
||||
import com.corewing.app.service.FeedbackService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户反馈
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/biz/feedback")
|
||||
public class BizFeedBackController {
|
||||
|
||||
@Resource
|
||||
private FeedbackService feedbackService;
|
||||
|
||||
/**
|
||||
* 反馈管理首页
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/index")
|
||||
public String index() {
|
||||
return "admin/biz/feedback/index";
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询反馈数据分页
|
||||
* @param feedback
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
@ResponseBody
|
||||
public Result<Page<Feedback>> page(Feedback feedback) {
|
||||
return Result.success(feedbackService.page(feedback));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增反馈
|
||||
* @param feedback
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/save")
|
||||
@ResponseBody
|
||||
public Result<String> save(@RequestBody Feedback feedback) {
|
||||
return Result.isBool(feedbackService.save(feedback));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑反馈
|
||||
* @param feedback
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
@ResponseBody
|
||||
public Result<String> update(@RequestBody Feedback feedback) {
|
||||
return Result.isBool(feedbackService.updateById(feedback));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除反馈
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping("/delete")
|
||||
@ResponseBody
|
||||
public Result<String> delete(Long id) {
|
||||
return Result.isBool(feedbackService.removeById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除反馈
|
||||
* @param feedbackBatchDeleteRequest
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/batchDelete")
|
||||
@ResponseBody
|
||||
public Result<String> batchDelete(@RequestBody FeedbackBatchDeleteRequest feedbackBatchDeleteRequest) {
|
||||
return Result.isBool(feedbackService.removeBatchByIds(feedbackBatchDeleteRequest.getIds()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更改状态
|
||||
* @param feedbackBatchStatusRequest
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/batchStatus")
|
||||
@ResponseBody
|
||||
public Result<String> batchStatus(@RequestBody FeedbackBatchStatusRequest feedbackBatchStatusRequest) {
|
||||
return Result.isBool(feedbackService.batchStatus(feedbackBatchStatusRequest));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@ 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.dto.biz.feedback.FeedbackBatchStatusRequest;
|
||||
import com.corewing.app.entity.Feedback;
|
||||
|
||||
import java.util.List;
|
||||
@@ -12,6 +13,9 @@ import java.util.List;
|
||||
*/
|
||||
public interface FeedbackService extends IService<Feedback> {
|
||||
|
||||
Page<Feedback> page(Feedback feedback);
|
||||
|
||||
|
||||
/**
|
||||
* 创建反馈
|
||||
*
|
||||
@@ -47,4 +51,11 @@ public interface FeedbackService extends IService<Feedback> {
|
||||
* @return 是否成功
|
||||
*/
|
||||
boolean updateStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 批量修改状态
|
||||
* @param feedbackBatchStatusRequest
|
||||
* @return
|
||||
*/
|
||||
boolean batchStatus(FeedbackBatchStatusRequest feedbackBatchStatusRequest);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,44 @@
|
||||
package com.corewing.app.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
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.common.page.PageContext;
|
||||
import com.corewing.app.dto.biz.feedback.FeedbackBatchStatusRequest;
|
||||
import com.corewing.app.entity.Feedback;
|
||||
import com.corewing.app.mapper.FeedbackMapper;
|
||||
import com.corewing.app.service.FeedbackService;
|
||||
import com.corewing.app.util.I18nUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static io.lettuce.core.GeoArgs.Unit.m;
|
||||
|
||||
/**
|
||||
* 问题反馈 Service 实现类
|
||||
*/
|
||||
@Service
|
||||
public class FeedbackServiceImpl extends ServiceImpl<FeedbackMapper, Feedback> implements FeedbackService {
|
||||
|
||||
@Resource
|
||||
private FeedbackMapper feedbackMapper;
|
||||
|
||||
@Override
|
||||
public Page<Feedback> page(Feedback feedback) {
|
||||
Page<Feedback> page = PageContext.getPage(Feedback.class);
|
||||
// LambdaQueryWrapper<Feedback> wrapper = new LambdaQueryWrapper<>();
|
||||
// wrapper.eq(feedback.getStatus() != null, Feedback::getStatus, feedback.getStatus());
|
||||
// wrapper.like(StringUtils.hasText(feedback.getTitle()), Feedback::getTitle, feedback.getTitle());
|
||||
// wrapper.eq(StringUtils.hasText(feedback.getFeedbackType()), Feedback::getFeedbackType, feedback.getFeedbackType());
|
||||
return feedbackMapper.page(page, feedback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createFeedback(Feedback feedback) {
|
||||
// 设置默认状态为待处理
|
||||
@@ -75,4 +95,16 @@ public class FeedbackServiceImpl extends ServiceImpl<FeedbackMapper, Feedback> i
|
||||
|
||||
return this.updateById(feedback);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean batchStatus(FeedbackBatchStatusRequest feedbackBatchStatusRequest) {
|
||||
feedbackBatchStatusRequest.getIds().forEach(id -> {
|
||||
LambdaUpdateWrapper<Feedback> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(Feedback::getId, id);
|
||||
wrapper.set(Feedback::getStatus, feedbackBatchStatusRequest.getStatus());
|
||||
update(wrapper);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
42
src/main/resources/mapper/FeedbackMapper.xml
Normal file
42
src/main/resources/mapper/FeedbackMapper.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.corewing.app.mapper.FeedbackMapper">
|
||||
|
||||
<!-- 结果映射 -->
|
||||
<resultMap id="VOResultMap" type="com.corewing.app.entity.Feedback">
|
||||
<id column="id" property="id"/>
|
||||
<result column="feedback_type" property="feedbackType"/>
|
||||
<result column="title" property="title"/>
|
||||
<result column="content" property="content"/>
|
||||
<result column="contact" property="contact"/>
|
||||
<result column="status" property="status"/>
|
||||
<result column="nick_name" property="nickName"/>
|
||||
<result column="username" property="username"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 基础查询SQL片段 -->
|
||||
<sql id="selectVOSql">
|
||||
select f.*,u.nick_name, u.username
|
||||
from app_feedback f
|
||||
left join app_user u on f.user_id = u.id
|
||||
</sql>
|
||||
|
||||
<!-- 分页查询 -->
|
||||
<select id="page" resultMap="VOResultMap">
|
||||
<include refid="selectVOSql"/>
|
||||
<where>
|
||||
<if test="feedback.status != null">
|
||||
AND f.status = #{feedback.status}
|
||||
</if>
|
||||
<if test="feedback.title != null and feedback.title != ''">
|
||||
AND f.title like CONCAT('%', #{feedback.title}, '%')
|
||||
</if>
|
||||
<if test="feedback.feedbackType != null and feedback.feedbackType != ''">
|
||||
AND f.feedbackType like CONCAT('%', #{feedback.feedbackType}, '%')
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -42,8 +42,10 @@
|
||||
@change="fetchData()"
|
||||
>
|
||||
<option value="">全部</option>
|
||||
<option value="1">显示</option>
|
||||
<option value="2">隐藏</option>
|
||||
<option value="0">待处理</option>
|
||||
<option value="1">处理中</option>
|
||||
<option value="2">已完成</option>
|
||||
<option value="3">已关闭</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -77,8 +79,11 @@
|
||||
@change="toggleSelectAll()"
|
||||
>
|
||||
</th>
|
||||
<th>名称</th>
|
||||
<th>是否显示</th>
|
||||
<th>反馈问题</th>
|
||||
<th>反馈详情</th>
|
||||
<th>反馈用户</th>
|
||||
<th>联系方式</th>
|
||||
<th>流程</th>
|
||||
<th>创建时间</th>
|
||||
<th style="width: 120px;">操作</th>
|
||||
</tr>
|
||||
@@ -120,9 +125,12 @@
|
||||
>
|
||||
</td>
|
||||
<td>{{ item.title }}</td>
|
||||
<td class="ellipsis-single">{{ item.content }}</td>
|
||||
<td>{{ item.nickName }}</td>
|
||||
<td>{{ item.contact }}</td>
|
||||
<td>
|
||||
<span class="badge" :class="item.status === 0 ? 'bg-warning' : 'bg-success'">
|
||||
{{ item.status === 0 ? '待处理' : '已处理' }}
|
||||
<span class="badge" :class="item.status === 0 ? 'bg-warning' : (item.status === 2 ? 'bg-success': (item.status === 3 ? 'bg-dark':'bg-info'))">
|
||||
{{ item.statusName }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ formatTime(item.createTime) }}</td>
|
||||
@@ -208,35 +216,44 @@
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3 row">
|
||||
<label class="col-sm-3 col-form-label">名称</label>
|
||||
<label class="col-sm-3 col-form-label">反馈标题</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" v-model="addOrEditDto.title"
|
||||
placeholder="请输入名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 row">
|
||||
<label class="col-sm-3 col-form-label">内容</label>
|
||||
<label class="col-sm-3 col-form-label">联系方式</label>
|
||||
<div class="col-sm-9">
|
||||
<!-- 富文本编辑器容器 -->
|
||||
<div id="contentEditor" style="border: 1px solid #dee2e6; border-radius: 0.375rem;"></div>
|
||||
<!-- 错误提示 -->
|
||||
<div class="invalid-feedback" id="contentError" style="display: none; margin-top: 0.25rem;"></div>
|
||||
<input type="text" class="form-control" v-model="addOrEditDto.contact"
|
||||
placeholder="请输入联系方式">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 row">
|
||||
<label class="col-sm-3 col-form-label">反馈内容</label>
|
||||
<div class="col-sm-9">
|
||||
<!-- <!– 富文本编辑器容器 –>-->
|
||||
<!-- <div id="contentEditor" style="border: 1px solid #dee2e6; border-radius: 0.375rem;"></div>-->
|
||||
<!-- <!– 错误提示 –>-->
|
||||
<!-- <div class="invalid-feedback" id="contentError" style="display: none; margin-top: 0.25rem;"></div>-->
|
||||
<textarea class="form-control" v-model="addOrEditDto.content"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 row">
|
||||
<label class="col-sm-3 col-form-label">流程</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control" v-model="addOrEditDto.status">
|
||||
<option value=1>显示</option>
|
||||
<option value=2>隐藏</option>
|
||||
<option value="0">待处理</option>
|
||||
<option value="1">处理中</option>
|
||||
<option value="2">已完成</option>
|
||||
<option value="3">已关闭</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 row">
|
||||
<label class="col-sm-3 col-form-label">序号</label>
|
||||
<label class="col-sm-3 col-form-label">反馈用户</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="number" class="form-control" v-model="addOrEditDto.sort"
|
||||
placeholder="请输入序号">
|
||||
<input type="text" class="form-control" readonly v-model="addOrEditDto.nickName">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -283,19 +300,14 @@
|
||||
batchAction: '', // 批量操作选择
|
||||
pageRange: 5,
|
||||
modalInstances: {},
|
||||
resetPasswordDto: {
|
||||
userId: null,
|
||||
nickName: null,
|
||||
username: null,
|
||||
password: null,
|
||||
},
|
||||
addOrEditTitle: '',
|
||||
addOrEditDto: {
|
||||
id: null,
|
||||
title: null,
|
||||
content: null,
|
||||
visible: 1,
|
||||
sort: 99
|
||||
contact: null,
|
||||
status: 0,
|
||||
nickName: 0,
|
||||
},
|
||||
editor: null, // WangEditor 实例
|
||||
}
|
||||
@@ -430,7 +442,7 @@
|
||||
content: `确定要删除选中的 ${this.selectedIds.length} 条数据吗?`,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
const response = await request.post('/biz/privacy_policy/batchDelete', {ids: this.selectedIds});
|
||||
const response = await request.post('/biz/feedback/batchDelete', {ids: this.selectedIds});
|
||||
if (response.code === 200) {
|
||||
$message.success("删除成功");
|
||||
this.fetchData();
|
||||
@@ -450,7 +462,7 @@
|
||||
content: '确定要删除这条数据吗?',
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
const response = await request.delete('/biz/privacy_policy/delete', {id});
|
||||
const response = await request.delete('/biz/feedback/delete', {id});
|
||||
if (response.code === 200) {
|
||||
$message.success("删除成功");
|
||||
this.fetchData(); // 重新加载数据
|
||||
@@ -480,17 +492,18 @@
|
||||
this.modalInstances['addOrEditModel'].show();
|
||||
},
|
||||
saveEntity() {
|
||||
let url = (this.addOrEditDto === null || this.addOrEditDto.id === null) ? '/biz/privacy_policy/save' : '/biz/privacy_policy/update';
|
||||
let url = (this.addOrEditDto === null || this.addOrEditDto.id === null) ? '/biz/feedback/save' : '/biz/feedback/update';
|
||||
request.post(url, this.addOrEditDto)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
$message.success('保存成功!', 500);
|
||||
this.fetchData();
|
||||
this.clearForm();
|
||||
this.modalInstances['addOrEditModel'].hide();
|
||||
} else {
|
||||
$message.error('保存失败!', 500);
|
||||
}
|
||||
this.clearForm();
|
||||
|
||||
|
||||
}).catch(() => {
|
||||
|
||||
@@ -502,8 +515,9 @@
|
||||
id: null,
|
||||
title: null,
|
||||
content: null,
|
||||
visible: 1,
|
||||
sort: 99
|
||||
contact: null,
|
||||
status: 0,
|
||||
nickName: 0,
|
||||
};
|
||||
},
|
||||
// 初始化 WangEditor
|
||||
@@ -558,20 +572,20 @@
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化 WangEditor(延迟初始化,确保DOM加载完成)
|
||||
setTimeout(() => {
|
||||
this.initWangEditor();
|
||||
}, 500);
|
||||
|
||||
// 监听模态框关闭事件,避免内存泄漏
|
||||
const modal = document.getElementById('addOrEditModel');
|
||||
modal.addEventListener('hidden.bs.modal', () => {
|
||||
if (this.editor) {
|
||||
this.editor.txt.clear(); // 清空内容
|
||||
document.getElementById('contentEditor').style.borderColor = '#dee2e6';
|
||||
document.getElementById('contentError').style.display = 'none';
|
||||
}
|
||||
});
|
||||
// // 初始化 WangEditor(延迟初始化,确保DOM加载完成)
|
||||
// setTimeout(() => {
|
||||
// this.initWangEditor();
|
||||
// }, 500);
|
||||
//
|
||||
// // 监听模态框关闭事件,避免内存泄漏
|
||||
// const modal = document.getElementById('addOrEditModel');
|
||||
// modal.addEventListener('hidden.bs.modal', () => {
|
||||
// if (this.editor) {
|
||||
// this.editor.txt.clear(); // 清空内容
|
||||
// document.getElementById('contentEditor').style.borderColor = '#dee2e6';
|
||||
// document.getElementById('contentError').style.display = 'none';
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}).mount('#app');
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user