master:意见反馈功能 完善;

pull/1121/head
liujiang 2025-07-17 22:37:27 +08:00
parent c5484d608a
commit c72f3b1460
19 changed files with 411 additions and 19 deletions

View File

@ -0,0 +1,58 @@
package com.ruoyi.web.controller.xkt;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.web.controller.xkt.vo.feedback.FeedbackPageVO;
import com.ruoyi.web.controller.xkt.vo.feedback.FeedbackResVO;
import com.ruoyi.web.controller.xkt.vo.feedback.FeedbackVO;
import com.ruoyi.web.controller.xkt.vo.notice.NoticeResVO;
import com.ruoyi.xkt.dto.feedback.FeedbackDTO;
import com.ruoyi.xkt.dto.feedback.FeedbackPageDTO;
import com.ruoyi.xkt.dto.feedback.FeedbackResDTO;
import com.ruoyi.xkt.service.IFeedbackService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* Controller
*
* @author ruoyi
* @date 2025-03-26
*/
@Api(tags = "意见反馈")
@RestController
@RequiredArgsConstructor
@RequestMapping("/rest/v1/feedback")
public class FeedbackController extends XktBaseController {
final IFeedbackService feedbackService;
@ApiOperation(value = "新增意见反馈", httpMethod = "POST", response = R.class)
@Log(title = "新增意见反馈", businessType = BusinessType.INSERT)
@PostMapping("")
public R<Integer> create(@Validated @RequestBody FeedbackVO feedbackVO) {
return success(feedbackService.create(BeanUtil.toBean(feedbackVO, FeedbackDTO.class)));
}
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
@ApiOperation(value = "意见反馈列表", httpMethod = "POST", response = R.class)
@PostMapping("/page")
public R<Page<FeedbackResDTO>> page(@Validated @RequestBody FeedbackPageVO pageVO) {
return R.ok(feedbackService.page(BeanUtil.toBean(pageVO, FeedbackPageDTO.class)));
}
@ApiOperation(value = "意见反馈详情", httpMethod = "PUT", response = R.class)
@GetMapping("/{id}")
public R<FeedbackResVO> getInfo(@PathVariable Long id) {
return R.ok(BeanUtil.toBean(feedbackService.getInfo(id), FeedbackResVO.class));
}
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.web.controller.xkt.vo.feedback;
import com.ruoyi.web.controller.xkt.vo.BasePageVO;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel
public class FeedbackPageVO extends BasePageVO {
}

View File

@ -0,0 +1,25 @@
package com.ruoyi.web.controller.xkt.vo.feedback;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("消息返回数据")
@Data
@Accessors(chain = true)
public class FeedbackResVO {
@ApiModelProperty(value = "ID")
private Long id;
@ApiModelProperty(value = "内容")
private String content;
@ApiModelProperty(value = "联系方式")
private String contract;
}

View File

@ -0,0 +1,32 @@
package com.ruoyi.web.controller.xkt.vo.feedback;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@Data
@ApiModel
@JsonInclude(JsonInclude.Include.NON_NULL)
public class FeedbackVO {
@ApiModelProperty(value = "用户反馈内容", required = true)
@Size(max = 200, message = "反馈内容不能超过200个字!")
@NotBlank(message = "反馈内容不能为空!")
private String content;
@ApiModelProperty(value = "用户反馈联系方式", required = true)
@Size(max = 20, message = "联系方式不能超过20个字!")
@NotBlank(message = "联系方式不能为空!")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系电话格式不正确,请输入有效的中国大陆手机号")
private String contact;
}

View File

@ -22,7 +22,7 @@ import java.util.List;
public class UserFavoritePageVO extends BasePageVO {
@NotNull(message = "商品状态不可为空!")
@ApiModelProperty(value = "商品状态在售传2 已失效传4,5", required = true)
@ApiModelProperty(value = "商品状态在售传2 已失效传4,5 APP 传 2 4 5", required = true)
private List<Integer> statusList;
@ApiModelProperty(value = "商品货号")
private String prodArtNum;

View File

@ -7,6 +7,9 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author liujiang
* @version v1.0
@ -20,5 +23,8 @@ public class UserSubscPageVO extends BasePageVO {
@ApiModelProperty(value = "档口名称")
private String storeName;
@NotNull(message = "查询来源不能为空!")
@ApiModelProperty(value = "查询来源", notes = "1 PC, 2 APP")
private Integer source;
}

View File

@ -1516,7 +1516,7 @@ public class XktTask {
// 新增一条档口消息通知
Notice notice = new Notice().setNoticeTitle(storeName + "商品上新啦!").setNoticeType(NoticeType.NOTICE.getValue())
.setNoticeContent(storeName + "上新了货号为: " + storeProd.getProdArtNum() + " 的商品!请及时关注!")
.setOwnerType(NoticeOwnerType.STORE.getValue()).setStoreId(storeProd.getStoreId())
.setOwnerType(NoticeOwnerType.SYSTEM.getValue()).setStoreId(storeProd.getStoreId())
.setUserId(userId).setPerpetuity(NoticePerpetuityType.PERMANENT.getValue());
this.noticeMapper.insert(notice);
final Date voucherDate = java.sql.Date.valueOf(LocalDate.now());

View File

@ -0,0 +1,34 @@
package com.ruoyi.xkt.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.ruoyi.common.core.domain.XktBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
*
* @author liujiang
* @date 2025-05-03
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class Feedback extends XktBaseEntity {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId
private Long id;
/**
*
*/
private String content;
/**
*
*/
private String contact;
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.xkt.dto.feedback;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@Data
@ApiModel
@JsonInclude(JsonInclude.Include.NON_NULL)
public class FeedbackDTO {
@ApiModelProperty(value = "用户反馈内容")
private String content;
@ApiModelProperty(value = "用户反馈联系方式")
private String contact;
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.xkt.dto.feedback;
import com.ruoyi.xkt.dto.BasePageDTO;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel
public class FeedbackPageDTO extends BasePageDTO {
}

View File

@ -0,0 +1,25 @@
package com.ruoyi.xkt.dto.feedback;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("消息返回数据")
@Data
@Accessors(chain = true)
public class FeedbackResDTO {
@ApiModelProperty(value = "ID")
private Long id;
@ApiModelProperty(value = "内容")
private String content;
@ApiModelProperty(value = "联系方式")
private String contract;
}

View File

@ -6,6 +6,8 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
/**
* @author liujiang
* @version v1.0
@ -18,5 +20,7 @@ public class UserSubscPageDTO extends BasePageDTO {
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "查询来源", notes = "1 PC, 2 APP")
private Integer source;
}

View File

@ -1,11 +1,14 @@
package com.ruoyi.xkt.dto.userSubscriptions;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* @author liujiang
* @version v1.0
@ -33,6 +36,10 @@ public class UserSubscPageResDTO {
private String qqAccount;
@ApiModelProperty(value = "档口地址")
private String storeAddress;
@ApiModelProperty(value = "档口状态")
private Integer storeDelFlag;
@ApiModelProperty(value = "关注日期")
private Long focusDays;
@ApiModelProperty(value = "最近30天销售量")
private Long last30DaysSaleQuantity;
@ApiModelProperty(value = "最近7天新增商品数")

View File

@ -0,0 +1,13 @@
package com.ruoyi.xkt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.Feedback;
/**
*
*
* @author ruoyi
*/
public interface FeedbackMapper extends BaseMapper<Feedback> {
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.xkt.service;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.xkt.dto.feedback.FeedbackDTO;
import com.ruoyi.xkt.dto.feedback.FeedbackPageDTO;
import com.ruoyi.xkt.dto.feedback.FeedbackResDTO;
/**
* Service
*
* @author ruoyi
* @date 2025-03-26
*/
public interface IFeedbackService {
/**
*
*
* @param feedbackDTO
* @return Integer
*/
Integer create(FeedbackDTO feedbackDTO);
/**
*
*
* @param pageDTO
* @return
*/
Page<FeedbackResDTO> page(FeedbackPageDTO pageDTO);
/**
*
*
* @param id ID
* @return FeedbackResDTO
*/
FeedbackResDTO getInfo(Long id);
}

View File

@ -0,0 +1,79 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.xkt.domain.Feedback;
import com.ruoyi.xkt.dto.feedback.FeedbackDTO;
import com.ruoyi.xkt.dto.feedback.FeedbackPageDTO;
import com.ruoyi.xkt.dto.feedback.FeedbackResDTO;
import com.ruoyi.xkt.mapper.FeedbackMapper;
import com.ruoyi.xkt.service.IFeedbackService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
/**
*
*
* @author ruoyi
*/
@Service
@RequiredArgsConstructor
public class FeedbackServiceImpl implements IFeedbackService {
final FeedbackMapper feedbackMapper;
/**
*
*
* @param feedbackDTO
* @return Integer
*/
@Override
@Transactional
public Integer create(FeedbackDTO feedbackDTO) {
Feedback feedback = BeanUtil.toBean(feedbackDTO, Feedback.class);
return this.feedbackMapper.insert(feedback);
}
/**
*
*
* @param pageDTO
* @return
*/
@Override
@Transactional(readOnly = true)
public Page<FeedbackResDTO> page(FeedbackPageDTO pageDTO) {
PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
List<Feedback> feedbackList = this.feedbackMapper.selectList(new LambdaQueryWrapper<Feedback>()
.eq(Feedback::getDelFlag, Constants.UNDELETED));
return CollectionUtils.isEmpty(feedbackList) ? Page.empty(pageDTO.getPageSize(), pageDTO.getPageNum())
: Page.convert(new PageInfo<>(feedbackList), BeanUtil.copyToList(feedbackList, FeedbackResDTO.class));
}
/**
*
*
* @param id ID
* @return FeedbackResDTO
*/
@Override
@Transactional(readOnly = true)
public FeedbackResDTO getInfo(Long id) {
Feedback feedback = Optional.ofNullable(this.feedbackMapper.selectOne(new LambdaQueryWrapper<Feedback>()
.eq(Feedback::getId, id).eq(Feedback::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new RuntimeException("意见反馈不存在!"));
return BeanUtil.toBean(feedback, FeedbackResDTO.class);
}
}

View File

@ -1158,7 +1158,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
// 新增一条档口消息通知
Notice notice = new Notice().setNoticeTitle(storeName + "商品上新啦!").setNoticeType(NoticeType.NOTICE.getValue())
.setNoticeContent(storeName + "上新了货号为: " + storeProd.getProdArtNum() + " 的商品!请及时关注!")
.setOwnerType(NoticeOwnerType.STORE.getValue()).setStoreId(storeProd.getStoreId())
.setOwnerType(NoticeOwnerType.SYSTEM.getValue()).setStoreId(storeProd.getStoreId())
.setUserId(userId).setPerpetuity(NoticePerpetuityType.PERMANENT.getValue());
this.noticeMapper.insert(notice);
final Date voucherDate = java.sql.Date.valueOf(LocalDate.now());
@ -1193,7 +1193,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
// 新增一条档口消息通知
Notice notice = new Notice().setNoticeTitle(storeName + "商品更新啦!").setNoticeType(NoticeType.NOTICE.getValue())
.setNoticeContent(storeName + "更新了货号为: " + storeProd.getProdArtNum() + " 的商品!请及时关注!")
.setOwnerType(NoticeOwnerType.STORE.getValue()).setStoreId(storeProd.getStoreId())
.setOwnerType(NoticeOwnerType.SYSTEM.getValue()).setStoreId(storeProd.getStoreId())
.setUserId(userId).setPerpetuity(NoticePerpetuityType.PERMANENT.getValue());
this.noticeMapper.insert(notice);
final Date voucherDate = java.sql.Date.valueOf(LocalDate.now());
@ -1233,7 +1233,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
// 新增一条档口消息通知
Notice notice = new Notice().setNoticeType(NoticeType.NOTICE.getValue()).setUserId(userId)
.setPerpetuity(NoticePerpetuityType.PERMANENT.getValue())
.setOwnerType(NoticeOwnerType.STORE.getValue()).setStoreId(storeProd.getStoreId())
.setOwnerType(NoticeOwnerType.SYSTEM.getValue()).setStoreId(storeProd.getStoreId())
.setNoticeTitle(ObjectUtils.isNotEmpty(store) ? store.getStoreName() : "" + "商品" + (offSale ? "下架" : "重新上架") + "啦!")
.setNoticeContent(ObjectUtils.isNotEmpty(store) ? store.getStoreName() : "" + (offSale ? "下架" : "重新上架")
+ "了货号为: " + storeProd.getProdArtNum() + " 的商品!请及时关注!");

View File

@ -131,12 +131,19 @@ public class UserSubscriptionsServiceImpl implements IUserSubscriptionsService {
@Transactional(readOnly = true)
public Page<UserSubscPageResDTO> page(UserSubscPageDTO pageDTO) {
// 获取当前登录用户
LoginUser loginUser = SecurityUtils.getLoginUser();
Long userId = SecurityUtils.getUserIdSafe();
if (ObjectUtils.isEmpty(userId)) {
throw new ServiceException("用户未登录,请先登录!", HttpStatus.ERROR);
}
PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
List<UserSubscPageResDTO> list = this.userSubMapper.selectUserSubscPage(loginUser.getUserId(), pageDTO.getStoreName());
List<UserSubscPageResDTO> list = this.userSubMapper.selectUserSubscPage(userId, pageDTO.getStoreName());
if (CollectionUtils.isEmpty(list)) {
return Page.empty(pageDTO.getPageNum(), pageDTO.getPageSize());
}
// APP 查询直接返回数据即可
if (pageDTO.getSource() == 2) {
return Page.convert(new PageInfo<>(list));
}
// 今天
final Date now = java.sql.Date.valueOf(LocalDate.now());
// 30天前

View File

@ -18,20 +18,24 @@
<select id="selectUserSubscPage" resultType="com.ruoyi.xkt.dto.userSubscriptions.UserSubscPageResDTO">
SELECT
us.id AS userSubscId,
us.store_id,
s.store_name,
s.contact_phone,
s.contact_back_phone,
s.wechat_account,
s.qq_account,
s.store_address
us.id AS userSubscId,
us.store_id,
s.store_name,
s.contact_phone,
s.contact_back_phone,
s.wechat_account,
s.qq_account,
s.store_address,
s.del_flag AS storeDelFlag,
DATEDIFF(CURDATE(), DATE(us.create_time)) AS focusDays
FROM
user_subscriptions us
LEFT JOIN store s ON us.store_id = s.id
user_subscriptions us
JOIN store s ON us.store_id = s.id
WHERE
us.del_flag = 0 AND us.user_id = #{userId}
<if test="storeName != null and storeName != ''">and s.store_name = #{storeName}</if>
us.del_flag = 0 AND us.user_id = #{userId}
<if test="storeName != null and storeName != ''">and s.store_name = #{storeName}</if>
ORDER BY
us.create_time DESC
</select>
<select id="selectTop10List" resultType="com.ruoyi.xkt.dto.dailyStoreTag.DailyStoreTagDTO">