Compare commits

4 Commits

Author SHA1 Message Date
6b2bce2b61 ---------- 2025-08-15 08:22:49 +08:00
f38160c3f6 ---------- 2025-08-15 08:21:27 +08:00
6e31701403 添加了轮播图 2025-08-15 08:18:57 +08:00
1ad79f600d 修改禅道bug 2025-08-14 22:21:33 +08:00
6 changed files with 227 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.greenorange.promotion.annotation.RequiresPermission; import com.greenorange.promotion.annotation.RequiresPermission;
import com.greenorange.promotion.common.ErrorCode; import com.greenorange.promotion.common.ErrorCode;
import com.greenorange.promotion.exception.BusinessException;
import com.greenorange.promotion.exception.ThrowUtils; import com.greenorange.promotion.exception.ThrowUtils;
import com.greenorange.promotion.model.entity.UserInfo; import com.greenorange.promotion.model.entity.UserInfo;
import com.greenorange.promotion.model.enums.UserRoleEnum; import com.greenorange.promotion.model.enums.UserRoleEnum;
@ -57,9 +58,14 @@ public class PermissionCheck {
ThrowUtils.throwIf(interfaceRoleEnum == null, ErrorCode.NO_AUTH_ERROR); ThrowUtils.throwIf(interfaceRoleEnum == null, ErrorCode.NO_AUTH_ERROR);
// 获取用户权限 // 获取用户权限
String token = request.getHeader("Authorization"); String token = request.getHeader("Authorization");
ThrowUtils.throwIf(StringUtils.isBlank(token), ErrorCode.NO_AUTH_ERROR, "JWT为空"); ThrowUtils.throwIf(StringUtils.isBlank(token), ErrorCode.NO_AUTH_ERROR, "token为空");
// 解析token // 解析token
DecodedJWT decodedJWT = jwtUtils.verify(token); DecodedJWT decodedJWT;
try {
decodedJWT = jwtUtils.verify(token);
} catch (Exception e) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "token已过期");
}
String userAccount = decodedJWT.getClaim("userAccount").asString(); String userAccount = decodedJWT.getClaim("userAccount").asString();
String userPassword = decodedJWT.getClaim("userPassword").asString(); String userPassword = decodedJWT.getClaim("userPassword").asString();
String userRole = decodedJWT.getClaim("userRole").asString(); String userRole = decodedJWT.getClaim("userRole").asString();

View File

@ -59,7 +59,12 @@ public interface UserConstant {
String STAFF_ROLE = "staff"; String STAFF_ROLE = "staff";
/** /**
* 申请 * 员工申请
*/ */
String APPLY_NOTICE_KEY = "applyNotice"; String APPLY_NOTICE_KEY = "applyNotice";
/**
* 课程购买须知
*/
String COURSE_DESC_KEY = "courseDesc";
} }

View File

@ -0,0 +1,149 @@
package com.greenorange.promotion.controller.course;
import com.greenorange.promotion.annotation.RequiresPermission;
import com.greenorange.promotion.common.BaseResponse;
import com.greenorange.promotion.common.ErrorCode;
import com.greenorange.promotion.common.ResultUtils;
import com.greenorange.promotion.constant.UserConstant;
import com.greenorange.promotion.exception.BusinessException;
import com.greenorange.promotion.model.dto.CommonStringRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 轮播图 控制器
*/
@RestController
@RequestMapping("banner")
@Slf4j
@Tag(name = "轮播图模块")
@Transactional
public class BannerController {
@Resource
private RedisTemplate<String, String> redisTemplate;
private static final String BANNER_KEY = "banners:list";
private static final String TOMBSTONE = "\u0000__DEL__\u0000"; // 删除占位符,极低冲突
/**
* web端管理员添加轮播图
* @param commonStringRequest 图片view值
* @return 是否添加成功
*/
@PostMapping("add")
@Operation(summary = "web端管理员添加轮播图", description = "参数图片view值权限管理员方法名addBanner")
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> addBanner(@Valid @RequestBody CommonStringRequest commonStringRequest) {
String view = commonStringRequest.getTemplateString();
redisTemplate.opsForList().rightPush(BANNER_KEY, view);
return ResultUtils.success(true);
}
/**
* 删除轮播图(根据索引)
* @param index 索引
* @return 是否添加成功
*/
@PostMapping("del")
@Operation(summary = "删除轮播图(根据索引)", description = "参数图片view值权限管理员方法名delBanner")
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> delBanner(@RequestParam long index) {
long len = getLenOrThrow();
long idx = normalizeIndex(index, len);
try {
// 先把该位置设置为占位符
redisTemplate.opsForList().set(BANNER_KEY, idx, TOMBSTONE);
// 再删除第一个占位符
Long removed = redisTemplate.opsForList().remove(BANNER_KEY, 1, TOMBSTONE);
boolean ok = removed != null && removed > 0;
log.info("按索引删除轮播图index={}, removed={}", idx, ok);
return ResultUtils.success(ok);
} catch (Exception e) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "索引越界或参数错误");
}
}
/**
* 修改轮播图(根据索引)
* @param index 索引
* @param newView 新的图片view值
* @return 是否添加成功
*/
@PostMapping("modify")
@Operation(summary = "修改轮播图(根据索引)", description = "参数图片view值权限管理员方法名delBanner")
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> modifyBanner(@RequestParam long index, @RequestParam String newView) {
long len = getLenOrThrow();
long idx = normalizeIndex(index, len); // 支持 -1
try {
redisTemplate.opsForList().set(BANNER_KEY, idx, newView);
log.info("更新轮播图index={} -> {}", idx, newView);
return ResultUtils.success(true);
} catch (Exception e) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "索引越界或参数错误");
}
}
/**
* web端获取所有轮播图按添加顺序
*/
@GetMapping("web/list")
@Operation(summary = "web端获取所有轮播图按添加顺序", description = "按添加顺序返回")
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<List<String>> webListBanners() {
List<String> banners = redisTemplate.opsForList().range(BANNER_KEY, 0, -1);
return ResultUtils.success(banners);
}
/**
* 小程序端获取所有轮播图(按添加顺序)
*/
@GetMapping("mini/list")
@Operation(summary = "小程序端获取所有轮播图(按添加顺序)", description = "按添加顺序返回")
@RequiresPermission(mustRole = UserConstant.DEFAULT_ROLE)
public BaseResponse<List<String>> miniListBanners() {
List<String> banners = redisTemplate.opsForList().range(BANNER_KEY, 0, -1);
return ResultUtils.success(banners);
}
/* ===== 工具方法 ===== */
/** 获取列表长度,不存在或为空时抛错 */
private long getLenOrThrow() {
Long len = redisTemplate.opsForList().size(BANNER_KEY);
if (len == null || len == 0) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "轮播图列表为空");
}
return len;
}
/** 归一化索引(支持负索引),并做范围校验 */
private long normalizeIndex(long index, long len) {
long idx = index < 0 ? len + index : index; // -1 -> len-1
if (idx < 0 || idx >= len) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "索引越界:" + index);
}
return idx;
}
}

View File

@ -103,6 +103,17 @@ public class UserInfoController {
// } // }
/**
* 小程序端用户校验token
* @return 是否校验成功
*/
@PostMapping("verify/token")
@Operation(summary = "小程序端用户校验token", description = "参数token, 权限管理员boss, admin)方法名verifyToken")
@RequiresPermission(mustRole = UserConstant.DEFAULT_ROLE)
public BaseResponse<Boolean> verifyToken() {
return ResultUtils.success(true);
}
/** /**
* web端修改员工申请须知 * web端修改员工申请须知
@ -110,7 +121,7 @@ public class UserInfoController {
* @return 是否修改成功 * @return 是否修改成功
*/ */
@PostMapping("modify/applyNotice") @PostMapping("modify/applyNotice")
@Operation(summary = "web端用户修改用户昵称", description = "参数:昵称权限管理员boss, admin)方法名modifyApplyNotice") @Operation(summary = "web端修改员工申请须知", description = "参数:修改内容权限管理员boss, admin)方法名modifyApplyNotice")
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> modifyApplyNotice(@Valid @RequestBody CommonStringRequest commonStringRequest) { public BaseResponse<Boolean> modifyApplyNotice(@Valid @RequestBody CommonStringRequest commonStringRequest) {
String applyNotice = commonStringRequest.getTemplateString(); String applyNotice = commonStringRequest.getTemplateString();
@ -120,18 +131,46 @@ public class UserInfoController {
/** /**
* 小程序端查询员工申请须知 * Web端小程序端查询员工申请须知
* @return 是否修改成功 * @return 是否修改成功
*/ */
@PostMapping("query/applyNotice") @PostMapping("query/applyNotice")
@Operation(summary = "小程序端查询员工申请须知", description = "参数权限管理员boss, admin)方法名queryApplyNotice") @Operation(summary = "Web端小程序端查询员工申请须知", description = "参数权限管理员boss, admin)方法名queryApplyNotice")
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<String> queryApplyNotice() { public BaseResponse<String> queryApplyNotice() {
String applyNotice = redisTemplate.opsForValue().get(UserConstant.APPLY_NOTICE_KEY); String applyNotice = redisTemplate.opsForValue().get(UserConstant.APPLY_NOTICE_KEY);
return ResultUtils.success(applyNotice); return ResultUtils.success(applyNotice);
} }
/**
* web端修改课程购买须知
* @param commonStringRequest 修改内容
* @return 是否修改成功
*/
@PostMapping("modify/courseDesc")
@Operation(summary = "web端修改课程购买须知", description = "参数修改内容权限管理员boss, admin)方法名modifyCourseDesc")
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> modifyCourseDesc(@Valid @RequestBody CommonStringRequest commonStringRequest) {
String courseDesc = commonStringRequest.getTemplateString();
redisTemplate.opsForValue().set(UserConstant.COURSE_DESC_KEY, courseDesc);
return ResultUtils.success(true);
}
/**
* Web端小程序端查询课程购买须知
* @return 是否修改成功
*/
@PostMapping("query/courseDesc")
@Operation(summary = "Web端小程序端查询课程购买须知", description = "参数权限管理员boss, admin)方法名queryApplyNotice")
public BaseResponse<String> queryCourseDesc() {
String courseDesc = redisTemplate.opsForValue().get(UserConstant.COURSE_DESC_KEY);
return ResultUtils.success(courseDesc);
}
/** /**
* 小程序端用户修改用户昵称 * 小程序端用户修改用户昵称
* @param commonStringRequest 昵称 * @param commonStringRequest 昵称
@ -143,6 +182,11 @@ public class UserInfoController {
public BaseResponse<Boolean> modifyNickname(@Valid @RequestBody CommonStringRequest commonStringRequest, HttpServletRequest request) { public BaseResponse<Boolean> modifyNickname(@Valid @RequestBody CommonStringRequest commonStringRequest, HttpServletRequest request) {
Long userId = (Long) request.getAttribute("userId"); Long userId = (Long) request.getAttribute("userId");
String nickName = commonStringRequest.getTemplateString(); String nickName = commonStringRequest.getTemplateString();
LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserInfo::getNickName, nickName);
queryWrapper.ne(UserInfo::getId, userId);
ThrowUtils.throwIf(userInfoService.count(queryWrapper) > 0, ErrorCode.PARAMS_ERROR, "昵称已存在");
LambdaUpdateWrapper<UserInfo> updateWrapper = new LambdaUpdateWrapper<>(); LambdaUpdateWrapper<UserInfo> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(UserInfo::getId, userId).set(UserInfo::getNickName, nickName); updateWrapper.eq(UserInfo::getId, userId).set(UserInfo::getNickName, nickName);
userInfoService.update(updateWrapper); userInfoService.update(updateWrapper);

View File

@ -101,4 +101,6 @@ public interface UserInfoService extends IService<UserInfo> {
* 查询当前用户的所有下级用户(包括间接) * 查询当前用户的所有下级用户(包括间接)
*/ */
List<Long> findAllSubUser(Long userId); List<Long> findAllSubUser(Long userId);
} }

View File

@ -348,7 +348,13 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
// 判断手机号是否已注册 // 判断手机号是否已注册
LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber).eq(UserInfo::getUserRole, userRole); UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(userRole);
if (userRoleEnum == UserRoleEnum.USER) {
lambdaQueryWrapper.eq(UserInfo::getUserRole, UserConstant.DEFAULT_ROLE);
} else {
lambdaQueryWrapper.in(UserInfo::getUserRole, UserConstant.STAFF_ROLE, UserConstant.SUPERVISOR_ROLE, UserConstant.MANAGER_ROLE);
}
lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber);
UserInfo userInfo = this.getOne(lambdaQueryWrapper); UserInfo userInfo = this.getOne(lambdaQueryWrapper);
ThrowUtils.throwIf(userInfo != null, ErrorCode.OPERATION_ERROR, "手机号已注册"); ThrowUtils.throwIf(userInfo != null, ErrorCode.OPERATION_ERROR, "手机号已注册");
@ -359,6 +365,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
} }
/** /**
* 校验用户手机号和验证码 * 校验用户手机号和验证码
*/ */
@ -408,6 +415,11 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
AdvancementApply advancementApply = advancementApplyService.getById(applyId); AdvancementApply advancementApply = advancementApplyService.getById(applyId);
String phoneNumber = advancementApply.getPhone(); String phoneNumber = advancementApply.getPhone();
ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效"); ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效");
LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber)
.in(UserInfo::getUserRole, UserConstant.STAFF_ROLE, UserConstant.SUPERVISOR_ROLE, UserConstant.MANAGER_ROLE);
UserInfo userInfo = this.getOne(lambdaQueryWrapper);
ThrowUtils.throwIf(userInfo != null, ErrorCode.OPERATION_ERROR, "手机号已注册");
// 根据邀请码获得上级用户信息 // 根据邀请码获得上级用户信息
Long userId = advancementApplyApproveRequest.getUserId(); Long userId = advancementApplyApproveRequest.getUserId();
@ -594,6 +606,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
} }