forked from Gitlink/microservices
Compare commits
169 Commits
aiResource
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
dcae975112 | |
|
|
c641ae6ab2 | |
|
|
7e5127b078 | |
|
|
0e13149981 | |
|
|
fd0d726a33 | |
|
|
58387872f0 | |
|
|
b62c7a6164 | |
|
|
62d4418679 | |
|
|
ca4c8bb614 | |
|
|
2a0d9c89e7 | |
|
|
bbe9fa517e | |
|
|
3cf58c94d9 | |
|
|
d1040faf52 | |
|
|
49a58bed6c | |
|
|
76f865624e | |
|
|
385dd55c25 | |
|
|
9d1d5527c8 | |
|
|
47e24de4fb | |
|
|
7a44a2113d | |
|
|
1bf9522d8f | |
|
|
5aa499f4de | |
|
|
35d5b1318e | |
|
|
4ccc743bd2 | |
|
|
84f624fdb7 | |
|
|
e43fb391fa | |
|
|
fc9e511aa0 | |
|
|
0abc43f033 | |
|
|
9fe4c69487 | |
|
|
d2d2f7368c | |
|
|
77125630e5 | |
|
|
ab53fa6ee0 | |
|
|
45f77beb73 | |
|
|
62c56097e2 | |
|
|
66c8132fe3 | |
|
|
f0725c78a1 | |
|
|
7093cda7bb | |
|
|
2a075ab571 | |
|
|
eba2082e2b | |
|
|
2cf4762b2c | |
|
|
b43c6384d3 | |
|
|
4d378d560d | |
|
|
6006440878 | |
|
|
4bbd80f739 | |
|
|
06633ff0a8 | |
|
|
6688c1f0e1 | |
|
|
93fb7eacf0 | |
|
|
5d6a64a4cc | |
|
|
887f4d1616 | |
|
|
49576e5ad0 | |
|
|
666c9c7b5e | |
|
|
95e5178de8 | |
|
|
8ce9a96fee | |
|
|
43572e7698 | |
|
|
3a5c9e03cf | |
|
|
bb2f414aa4 | |
|
|
76fa1f5447 | |
|
|
5e20807aed | |
|
|
83566e947a | |
|
|
f3a718d75a | |
|
|
7c6614bddb | |
|
|
c2b992c990 | |
|
|
0e63d5efcd | |
|
|
29c09c7091 | |
|
|
7506ec7cb2 | |
|
|
0132d56eb2 | |
|
|
93edb6b138 | |
|
|
3599ac3d4a | |
|
|
44e7ed5605 | |
|
|
b1d46f9471 | |
|
|
9b0b8c4362 | |
|
|
f9d779704a | |
|
|
2fa5be38b2 | |
|
|
22f3a8dc6b | |
|
|
df594efd9a | |
|
|
d2e0c54cdd | |
|
|
dc65b2d299 | |
|
|
d62d474848 | |
|
|
388423d53c | |
|
|
adbb5d04db | |
|
|
ee2ae04586 | |
|
|
2decec46ee | |
|
|
4402c972c9 | |
|
|
14748b4253 | |
|
|
ac22a5ba15 | |
|
|
f80bc0219c | |
|
|
941f30d6b3 | |
|
|
19dd235a26 | |
|
|
dea2c5e4d6 | |
|
|
5f1e8ddaf9 | |
|
|
1f3f3546a6 | |
|
|
f2d18d8334 | |
|
|
f491cd4753 | |
|
|
7bf2a532b3 | |
|
|
87a79ee7f4 | |
|
|
c358ffcfb7 | |
|
|
3e4f489914 | |
|
|
e559bcc48a | |
|
|
3b599bed3f | |
|
|
8c68611369 | |
|
|
1ef0cdcef2 | |
|
|
75ca1eff4d | |
|
|
8a69939e84 | |
|
|
77e3a9e0d3 | |
|
|
effaebe0d4 | |
|
|
1a8b537dae | |
|
|
86c3f502f1 | |
|
|
0ddac0b423 | |
|
|
9543d7fa38 | |
|
|
e7fcf69c9a | |
|
|
b26081dc17 | |
|
|
21658c6b66 | |
|
|
80e7b1f1b3 | |
|
|
85b19136a8 | |
|
|
e28691709f | |
|
|
2bb93099b5 | |
|
|
d98998422d | |
|
|
e7478556d4 | |
|
|
22ac8bec90 | |
|
|
bd34c5beae | |
|
|
33dd51c5f1 | |
|
|
ebe565af2e | |
|
|
30a3119580 | |
|
|
68673c355a | |
|
|
6c1a4589e7 | |
|
|
bc4d402c88 | |
|
|
21868ae523 | |
|
|
1ac64877f8 | |
|
|
9fa1545e11 | |
|
|
845993f7c8 | |
|
|
2edc3bacc7 | |
|
|
fc08a962ce | |
|
|
541b43d768 | |
|
|
6bb1b3c6eb | |
|
|
b784d44e26 | |
|
|
012ed2b25b | |
|
|
7219a66b5a | |
|
|
24b117a5a2 | |
|
|
590bc076c1 | |
|
|
41baf01039 | |
|
|
e3d33c0507 | |
|
|
3e10ed1b54 | |
|
|
883fdfdb75 | |
|
|
92bea2ec47 | |
|
|
16fc7fd3ee | |
|
|
a00cdb4238 | |
|
|
1ea5e87767 | |
|
|
0f97696614 | |
|
|
e12afda308 | |
|
|
eb22a4ebeb | |
|
|
5b05d90522 | |
|
|
7ffbdad4bc | |
|
|
8f5b4f1882 | |
|
|
a75d2b55fd | |
|
|
94fb839f2c | |
|
|
e2ab5396ea | |
|
|
3b178aa0a6 | |
|
|
215d7b6914 | |
|
|
6c0c459d60 | |
|
|
7930e4a155 | |
|
|
eef0e81d11 | |
|
|
91ce2fff08 | |
|
|
f7229b6d42 | |
|
|
ffc5f2e26e | |
|
|
13d34fb2e9 | |
|
|
b429c568f5 | |
|
|
7dbbbbb090 | |
|
|
6c62ba619b | |
|
|
900dcdf4d7 | |
|
|
d8c951f9e0 |
|
|
@ -9,6 +9,8 @@ import com.microservices.system.api.factory.RemoteCmsFallbackFactory;
|
|||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户服务
|
||||
*
|
||||
|
|
@ -162,4 +164,18 @@ public interface RemoteCmsService {
|
|||
@PutMapping("/project/changeOrgRole/user/{userId}/operate/{operate}")
|
||||
R<Boolean> changeUserOrgRole(@PathVariable("userId") Long userId, @PathVariable("operate") int operate
|
||||
, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 首页文章合并列表(接收置顶文章 docId 有序列表,返回合并去重后的结果)
|
||||
* 供 Zone 服务 /open/getTopDoc 改造后调用
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param topDocIds 置顶文章 docId 有序列表
|
||||
* @param source 来源
|
||||
* @return 合并后的首页文章 JSONObject 列表
|
||||
*/
|
||||
@PostMapping("/doc/homePageDocMergeList/{zoneId}")
|
||||
R<List<JSONObject>> selectHomePageDocMergeList(@PathVariable("zoneId") Long zoneId,
|
||||
@RequestBody List<Long> topDocIds,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,15 @@ public interface RemoteUserService {
|
|||
@GetMapping("/user/getSysUserByUserId/{userId}")
|
||||
public R<SysUser> getSysUserByUserId(@PathVariable("userId") Long userId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 通过用户ID数组批量获取用户信息(POST方法,解决URL长度限制)
|
||||
*
|
||||
* @param userIds 用户ID数组
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/user/getSysUserListByUserIds")
|
||||
R<List<SysUser>> postSysUserListByUserIds(@RequestBody Long[] userIds, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 组织下新增用户身份
|
||||
|
|
@ -64,7 +73,7 @@ public interface RemoteUserService {
|
|||
* @param deptId
|
||||
* @param userId
|
||||
* @param roleKey
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/SysUserDeptRole/dept/{deptId}/user/{userId}/role/{roleKey}")
|
||||
|
|
@ -74,14 +83,13 @@ public interface RemoteUserService {
|
|||
, @PathVariable("roleKey") String roleKey
|
||||
, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 组织下删除用户身份
|
||||
*
|
||||
* @param deptId
|
||||
* @param userId
|
||||
* @param roleKey
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@DeleteMapping("/SysUserDeptRole/dept/{deptId}/user/{userId}/role/{roleKey}")
|
||||
|
|
@ -91,18 +99,16 @@ public interface RemoteUserService {
|
|||
@PathVariable("roleKey") String roleKey,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 注册用户信息
|
||||
*
|
||||
* @param sysUser 用户信息
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/user/register")
|
||||
public R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 通过GitLinkToken获取本系统Token
|
||||
*
|
||||
|
|
@ -123,7 +129,6 @@ public interface RemoteUserService {
|
|||
@GetMapping("/SysUserDeptRole/userByUserName/{userName}/list")
|
||||
public R<List<SysUserDeptRole>> getSysUserDeptRoleListByUserName(@PathVariable("userName") String userName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 通过用户名查询用户下第一个身份
|
||||
*
|
||||
|
|
@ -195,7 +200,7 @@ public interface RemoteUserService {
|
|||
/**
|
||||
* 通过GitLink用户Id创建用户
|
||||
*
|
||||
* @param gitLinkUserId GitLink用户Id
|
||||
* @param gitLinkUserId GitLinkUserId
|
||||
* @param source 请求来源
|
||||
* @return 系统用户
|
||||
*/
|
||||
|
|
@ -206,7 +211,7 @@ public interface RemoteUserService {
|
|||
* 根据角色Key获取菜单权限集合
|
||||
*
|
||||
* @param roleKey 角色Key
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 菜单权限集合
|
||||
*/
|
||||
@GetMapping("/menu/roleMenuPermissionByRoleKey/{roleKey}")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 内容管理服务降级处理
|
||||
*
|
||||
|
|
@ -88,6 +90,11 @@ public class RemoteCmsFallbackFactory implements FallbackFactory<RemoteCmsServic
|
|||
public R<Boolean> changeUserOrgRole(Long userId, int operate, String source) {
|
||||
return R.fail("更新组织权限失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<JSONObject>> selectHomePageDocMergeList(Long zoneId, List<Long> topDocIds, String source) {
|
||||
return R.fail("获取首页文章合并列表失败:" + throwable.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
|
|||
return R.fail("获取用户失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<SysUser>> postSysUserListByUserIds(Long[] userIds, String source) {
|
||||
|
||||
return R.fail("批量获取用户失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> addUserIdentify(Long deptId, Long userId, String roleKey, String source) {
|
||||
return R.fail("组织下新增用户身份失败:" + throwable.getMessage());
|
||||
|
|
|
|||
|
|
@ -80,6 +80,10 @@ public class CacheConstants {
|
|||
* 通过组织Id获取专区详情JSON对象
|
||||
*/
|
||||
public final static String ZONE_JSON_OF_DEPT_ID_KEY = "zoneJSONOfDeptId:";
|
||||
/**
|
||||
* 积分发放部门
|
||||
*/
|
||||
public final static String ZONE_POINTS_DEPT_ID_KEY = "zonePointsDeptId";
|
||||
/**
|
||||
* 内容管理同步缓存前缀
|
||||
*/
|
||||
|
|
@ -245,6 +249,18 @@ public class CacheConstants {
|
|||
return ZONE_PROJECT_SORT_BY_SCORE + "*:" + zoneId + ":*";
|
||||
}
|
||||
|
||||
/**
|
||||
* 专区统计数据缓存前缀
|
||||
*/
|
||||
private final static String ZONE_STATISTICS_KEY = "zone:statistics:";
|
||||
|
||||
/**
|
||||
* 获取专区统计数据缓存key
|
||||
*/
|
||||
public static String getZoneStatisticsKey(Long zoneId) {
|
||||
return ZONE_STATISTICS_KEY + zoneId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件打包是否完成(0:代表未完成;1:代表已完成;-1:代表打包失败,需要重新打包)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -171,4 +171,12 @@ public class UserConstants {
|
|||
* 文章管理-审核文章权限
|
||||
*/
|
||||
public static final String CMS_PERMS_DOCS_AUDIT = "cms:doc:audit";
|
||||
/**
|
||||
* 专区管理-审核项目权限
|
||||
*/
|
||||
public static final String ZONE_PERMS_PROJECT_AUDIT = "zone:project:audit";
|
||||
/**
|
||||
* 专区管理-审核资源权限
|
||||
*/
|
||||
public static final String ZONE_PERMS_RESOURCE_AUDIT = "zone:resource:audit";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ package com.microservices.common.core.enums;
|
|||
public enum DocAndZoneOperation
|
||||
{
|
||||
OPERATION_CREATE("创建", "create"), OPERATION_UPDATE("更新", "update"),
|
||||
OPERATION_DELETE("删除", "delete");
|
||||
OPERATION_DELETE("删除", "delete"), OPERATION_NON_REPO_UPDATE("非仓库更新", "nonRepoUpdate");
|
||||
|
||||
private final String operationName;
|
||||
private final String operationCode;
|
||||
|
|
|
|||
|
|
@ -115,8 +115,7 @@ public class AuthLogic {
|
|||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
public boolean hasPermi(String permission)
|
||||
{
|
||||
public boolean hasPermi(String permission) {
|
||||
return hasPermi(tokenService.getMenuPermissions(), permission);
|
||||
}
|
||||
|
||||
|
|
@ -126,10 +125,8 @@ public class AuthLogic {
|
|||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
public void checkPermi(String permission)
|
||||
{
|
||||
if (!hasPermi(tokenService.getMenuPermissions(), permission))
|
||||
{
|
||||
public void checkPermi(String permission) {
|
||||
if (!hasPermi(tokenService.getMenuPermissions(), permission)) {
|
||||
throw new NotPermissionException(permission);
|
||||
}
|
||||
}
|
||||
|
|
@ -153,13 +150,10 @@ public class AuthLogic {
|
|||
*
|
||||
* @param permissions 权限列表
|
||||
*/
|
||||
public void checkPermiAnd(String... permissions)
|
||||
{
|
||||
public void checkPermiAnd(String... permissions) {
|
||||
Set<String> permissionList = tokenService.getMenuPermissions();
|
||||
for (String permission : permissions)
|
||||
{
|
||||
if (!hasPermi(permissionList, permission))
|
||||
{
|
||||
for (String permission : permissions) {
|
||||
if (!hasPermi(permissionList, permission)) {
|
||||
throw new NotPermissionException(permission);
|
||||
}
|
||||
}
|
||||
|
|
@ -170,13 +164,10 @@ public class AuthLogic {
|
|||
*
|
||||
* @param permissions 权限码数组
|
||||
*/
|
||||
public void checkPermiOr(String... permissions)
|
||||
{
|
||||
public void checkPermiOr(String... permissions) {
|
||||
Set<String> permissionList = tokenService.getMenuPermissions();
|
||||
for (String permission : permissions)
|
||||
{
|
||||
if (hasPermi(permissionList, permission))
|
||||
{
|
||||
for (String permission : permissions) {
|
||||
if (hasPermi(permissionList, permission)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -191,8 +182,7 @@ public class AuthLogic {
|
|||
* @param role 角色标识
|
||||
* @return 用户是否具备某角色
|
||||
*/
|
||||
public boolean hasRole(String role)
|
||||
{
|
||||
public boolean hasRole(String role) {
|
||||
return hasRole(tokenService.getRolePermissions(), role);
|
||||
}
|
||||
|
||||
|
|
@ -225,13 +215,10 @@ public class AuthLogic {
|
|||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public void checkRoleAnd(String... roles)
|
||||
{
|
||||
public void checkRoleAnd(String... roles) {
|
||||
Set<String> roleList = tokenService.getRolePermissions();
|
||||
for (String role : roles)
|
||||
{
|
||||
if (!hasRole(roleList, role))
|
||||
{
|
||||
for (String role : roles) {
|
||||
if (!hasRole(roleList, role)) {
|
||||
throw new NotRoleException(role);
|
||||
}
|
||||
}
|
||||
|
|
@ -242,18 +229,14 @@ public class AuthLogic {
|
|||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public void checkRoleOr(String... roles)
|
||||
{
|
||||
public void checkRoleOr(String... roles) {
|
||||
Set<String> roleList = tokenService.getRolePermissions();
|
||||
for (String role : roles)
|
||||
{
|
||||
if (hasRole(roleList, role))
|
||||
{
|
||||
for (String role : roles) {
|
||||
if (hasRole(roleList, role)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (roles.length > 0)
|
||||
{
|
||||
if (roles.length > 0) {
|
||||
throw new NotRoleException(roles);
|
||||
}
|
||||
}
|
||||
|
|
@ -323,6 +306,9 @@ public class AuthLogic {
|
|||
public boolean hasUserIdentity(Long deptId, String roleKey) {
|
||||
LoginUser loginUser = getLoginUser();
|
||||
List<SysUserDeptRole> sysUserDeptRoleList = tokenService.getAllUserIdentity(loginUser.getUsername());
|
||||
if (sysUserDeptRoleList == null) {
|
||||
return false;
|
||||
}
|
||||
return sysUserDeptRoleList.stream()
|
||||
.anyMatch(x -> {
|
||||
if (x.getDeptId() != null && x.getSysRole() != null && x.getDeptId().equals(deptId)) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.microservices.common.core.utils.uuid.IdUtils;
|
|||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.common.security.interceptor.HeaderInterceptor;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.system.api.RemoteDeptService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
import com.microservices.system.api.domain.SysRole;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
|
|
@ -38,6 +39,8 @@ public class TokenService {
|
|||
private RedisService redisService;
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
@Autowired
|
||||
private RemoteDeptService remoteDeptService;
|
||||
|
||||
protected static final long MILLIS_SECOND = 1000;
|
||||
|
||||
|
|
@ -329,4 +332,16 @@ public class TokenService {
|
|||
}
|
||||
return loginUser.getSysUser();
|
||||
}
|
||||
|
||||
public Boolean hasDeptPerms(Long deptId, String perms) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Boolean hasPerms = FeignUtils.getReturnData(
|
||||
remoteDeptService.checkUserInDeptOrParentDeptHasPerms(deptId, loginUser.getUserId(), perms, SecurityConstants.INNER)
|
||||
);
|
||||
|
||||
if (hasPerms == null) {
|
||||
hasPerms = false;
|
||||
}
|
||||
return hasPerms;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ import io.swagger.annotations.*;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -107,23 +108,13 @@ public class CmsDocController extends BaseController {
|
|||
@ApiImplicitParam(name = "pageNum", value = "当前记录起始索引", paramType = "query", dataType = "Integer"),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页显示记录数", paramType = "query", dataType = "Integer"),
|
||||
})
|
||||
public TableDataInfo docListByZone(
|
||||
public GenericsTableDataInfo<CmsDocAllDto> docListByZone(
|
||||
@ApiParam(name = "zoneId", value = "专区Id") @PathVariable("zoneId") Long zoneId
|
||||
, CmsDocSearchVo cmsDocSearchVo) {
|
||||
Long deptId = cmsDocService.getDeptIdByZoneId(zoneId);
|
||||
cmsDocSearchVo.setIsOpen(false);
|
||||
cmsDocSearchVo.setIsOpen(true);
|
||||
startPage();
|
||||
List<CmsDocAllDto> list = cmsDocService.selectCmsDocListByDept(deptId, cmsDocSearchVo);
|
||||
list.forEach(x -> {
|
||||
String docDetailUrl = cmsDocService.getDocDetailUrl(x.getDeptId(), x.getId());
|
||||
x.setDocDetailUrl(docDetailUrl);
|
||||
|
||||
Boolean editable = cmsDocService.isCmsDocEditable(x);
|
||||
x.setEditable(editable);
|
||||
|
||||
});
|
||||
int count = cmsDocService.selectCmsDocCountByDept(deptId, cmsDocSearchVo);
|
||||
return getDataTable(list, count);
|
||||
return cmsDocService.selectAllDocList(deptId, cmsDocSearchVo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -219,7 +210,7 @@ public class CmsDocController extends BaseController {
|
|||
@ApiOperation("更新文章")
|
||||
public AjaxResult edit(@ApiParam(name = "id", value = "文章Id") @PathVariable Long id,
|
||||
@ApiParam(name = "cmsDoc", value = "文章实体对象") @RequestBody CmsDocDto cmsDocDto) {
|
||||
return toAjax(cmsDocService.updateCmsDoc(id, cmsDocDto));
|
||||
return success(cmsDocService.updateCmsDoc(id, cmsDocDto));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -316,6 +307,24 @@ public class CmsDocController extends BaseController {
|
|||
return R.ok(cmsDocJSONObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部接口:首页文章合并列表(接收置顶文章 docId 有序列表,返回合并去重后的结果)
|
||||
* 供 Zone 服务 Feign 调用,用于 /open/getTopDoc 改造
|
||||
*/
|
||||
@InnerAuth
|
||||
@PostMapping("/homePageDocMergeList/{zoneId}")
|
||||
@ApiOperation(value = "首页文章合并列表", hidden = true)
|
||||
public R<List<JSONObject>> selectHomePageDocMergeList(
|
||||
@PathVariable("zoneId") Long zoneId,
|
||||
@RequestBody List<Long> topDocIds) {
|
||||
List<CmsDocBaseDto> list = cmsDocService.selectHomePageDocMergeList(zoneId, topDocIds);
|
||||
List<JSONObject> result = new ArrayList<>();
|
||||
for (CmsDocBaseDto dto : list) {
|
||||
result.add(JSONObject.from(dto));
|
||||
}
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过组织Id获取专区下文章阅读数量
|
||||
*
|
||||
|
|
|
|||
|
|
@ -121,6 +121,19 @@ public class OpenController extends BaseController {
|
|||
return getAllGenericsDataTableToPage(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询文章列表(不区分栏目)
|
||||
*/
|
||||
@GetMapping("/zone/{zoneId}/allDocList")
|
||||
@ApiOperation("查询文章列表(不区分栏目)")
|
||||
public GenericsTableDataInfo<CmsDocAllDto> allDocList(@ApiParam(name = "zoneId", value = "专区Id") @PathVariable("zoneId") Long zoneId,
|
||||
CmsDocSearchVo cmsDocSearchVo) {
|
||||
Long deptId = cmsDocService.getDeptIdByZoneId(zoneId);
|
||||
cmsDocSearchVo.setIsOpen(true);
|
||||
startPage();
|
||||
return cmsDocService.selectAllDocList(deptId, cmsDocSearchVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询首页文章列表
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -83,4 +83,10 @@ public class CmsDocSearchVo {
|
|||
*/
|
||||
@ApiModelProperty("关键词")
|
||||
private String keywords;
|
||||
|
||||
/**
|
||||
* 排除文章Id
|
||||
*/
|
||||
@ApiModelProperty(value = "排除文章Id", hidden = true)
|
||||
private Long excludeId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ public interface CmsDocMapper {
|
|||
*/
|
||||
public CmsDoc selectCmsDocById(Long id);
|
||||
|
||||
/**
|
||||
* 批量查询文章信息
|
||||
*
|
||||
* @param ids 文章ID列表
|
||||
* @return 文章信息列表
|
||||
*/
|
||||
List<CmsDoc> selectCmsDocByIds(@Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 查询文章信息列表
|
||||
*
|
||||
|
|
@ -83,6 +91,11 @@ public interface CmsDocMapper {
|
|||
|
||||
CmsDoc selectCmsDocByFilePathAndDeptId(@Param("filePath") String filePath, @Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 按文章名+deptId查询(忽略dirName),用于Webhook防重判断
|
||||
*/
|
||||
CmsDoc selectCmsDocByNameAndDeptIdIgnoreDirName(@Param("name") String name, @Param("deptId") Long deptId);
|
||||
|
||||
List<CmsDoc> selectHotCmsDocList(CmsDoc cmsDocInput);
|
||||
|
||||
List<CmsDoc> selectCmsDocDirByDeptIdAndInName(@Param("deptId") Long deptId, @Param("cmsDirNameList") List<String> cmsDirNameList);
|
||||
|
|
|
|||
|
|
@ -101,4 +101,36 @@ public interface ICmsAsyncService {
|
|||
void pushDocDataSearchEngine(CmsDoc cmsDoc);
|
||||
|
||||
void clearTmpDoc(CmsProject cmsProject,List<CmsDoc> tmpDocList);
|
||||
|
||||
/**
|
||||
* 异步增加文章发布积分
|
||||
*
|
||||
* @param deptId 组织ID
|
||||
* @param createBy 创建人用户名
|
||||
* @param docId 文章ID
|
||||
* @param subjectDesc 文章标题
|
||||
*/
|
||||
void addPublishDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc);
|
||||
|
||||
/**
|
||||
* 异步增加文章浏览积分(每满100次+2,上限50)
|
||||
*
|
||||
* @param deptId 组织ID
|
||||
* @param createBy 创建人用户名
|
||||
* @param docId 文章ID
|
||||
* @param docName 文章名称
|
||||
* @param totalVisits 累计阅读次数
|
||||
* @param pointsTriggerCount 当前第几次增加积分
|
||||
*/
|
||||
void addVisitsDocPointsAsync(Long deptId, String createBy, Long docId, String docName, Long totalVisits);
|
||||
|
||||
/**
|
||||
* 异步增加文章被设为精选的积分
|
||||
*
|
||||
* @param deptId 组织ID
|
||||
* @param createBy 创建人用户名
|
||||
* @param docId 文章ID
|
||||
* @param subjectDesc 文章标题
|
||||
*/
|
||||
void addFeaturedDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.microservices.cms.doc.domain.*;
|
|||
import com.microservices.cms.doc.domain.gitlink.EntryDto;
|
||||
import com.microservices.cms.doc.domain.gitlink.FileEntryDto;
|
||||
import com.microservices.cms.project.domain.CmsProject;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
|
@ -56,9 +57,9 @@ public interface ICmsDocService {
|
|||
*
|
||||
* @param id
|
||||
* @param cmsDocDto 文章信息
|
||||
* @return 结果
|
||||
* @return 结果 文章id
|
||||
*/
|
||||
public boolean updateCmsDoc(Long id, CmsDocDto cmsDocDto);
|
||||
public Long updateCmsDoc(Long id, CmsDocDto cmsDocDto);
|
||||
|
||||
/**
|
||||
* 批量删除文章信息
|
||||
|
|
@ -144,6 +145,15 @@ public interface ICmsDocService {
|
|||
*/
|
||||
List<CmsDocBaseDto> selectHomePageDocList(Long deptId);
|
||||
|
||||
/**
|
||||
* 查询首页文章合并列表(积分置顶文章 + 首页推荐文章,自动去重,置顶在前)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param topDocIds 置顶文章 docId 有序列表(前端按此顺序排列)
|
||||
* @return 合并后的首页文章列表(isTop=true 标识置顶文章)
|
||||
*/
|
||||
List<CmsDocBaseDto> selectHomePageDocMergeList(Long zoneId, List<Long> topDocIds);
|
||||
|
||||
/**
|
||||
* 初始化栏目
|
||||
*
|
||||
|
|
@ -198,6 +208,8 @@ public interface ICmsDocService {
|
|||
*/
|
||||
List<CmsDocAllDto> selectCmsDocListByDept(Long deptId, CmsDocSearchVo cmsDocSearchVo);
|
||||
|
||||
GenericsTableDataInfo<CmsDocAllDto> selectAllDocList(Long deptId, CmsDocSearchVo cmsDocSearchVo);
|
||||
|
||||
/**
|
||||
* 查询专区下文章数量
|
||||
*
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
|||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.system.api.RemoteDeptService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
import com.microservices.system.api.RemoteZoneService;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
|
|
@ -97,6 +98,8 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
@Autowired
|
||||
private RemoteZoneService remoteZoneService;
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
@Autowired
|
||||
private RequestConfig config;
|
||||
|
||||
/**
|
||||
|
|
@ -253,7 +256,16 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
CmsDoc cmsDoc = cmsDocMapper.selectCmsDocByNameAndDeptId(CmsUtils.getFileNameNoSuffix(entry.getName()), cmsProject.getDeptId(), dirName);
|
||||
if (cmsDoc == null) {
|
||||
syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
|
||||
// 防重:按文章名+deptId查一次,排除正在移动栏目的已有记录
|
||||
String docName = CmsUtils.getFileNameNoSuffix(entry.getName());
|
||||
CmsDoc existingDoc = cmsDocMapper.selectCmsDocByNameAndDeptIdIgnoreDirName(docName, cmsProject.getDeptId());
|
||||
if (existingDoc != null) {
|
||||
existingDoc.setDirName(dirName);
|
||||
existingDoc.setFilePath(dirName + "/" + existingDoc.getFileName());
|
||||
cmsDocMapper.updateCmsDoc(existingDoc);
|
||||
} else {
|
||||
syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
@ -726,8 +738,8 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
|
||||
if (isChangeName || isChangeDir) {
|
||||
oldCmsDoc = renameAndChangeDirCmsDoc(oldCmsDoc, cmsProject, newName, newDirName, branchName);
|
||||
//todo 此处是否需要更新数据库待讨论
|
||||
//updateCmsCommonDatabase(oldCmsDoc);
|
||||
// 立即更新数据库中的dirName/filePath,避免GitLink Webhook回调时查不到记录导致重复INSERT
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
}
|
||||
|
||||
boolean isChangeContent = false;
|
||||
|
|
@ -1075,4 +1087,127 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为积分部门
|
||||
*
|
||||
* @param deptId 部门ID
|
||||
* @return 是否为积分部门
|
||||
*/
|
||||
private boolean isPointsDept(Long deptId) {
|
||||
Long cachedPointsDeptId = redisService.getCacheObject(CacheConstants.ZONE_POINTS_DEPT_ID_KEY);
|
||||
return cachedPointsDeptId != null && cachedPointsDeptId > 0 && cachedPointsDeptId.equals(deptId);
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void addPublishDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc) {
|
||||
try {
|
||||
if (deptId == null || createBy == null) {
|
||||
logger.warn("文章审核通过增加积分失败,deptId或createBy为空,docId={}", docId);
|
||||
return;
|
||||
}
|
||||
// 检查是否为积分部门
|
||||
if (!isPointsDept(deptId)) {
|
||||
logger.info("文章审核通过增加积分跳过,非积分部门,deptId={},docId={}", deptId, docId);
|
||||
return;
|
||||
}
|
||||
// 获取用户ID
|
||||
com.microservices.system.api.domain.SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(createBy, SecurityConstants.INNER));
|
||||
if (sysUser == null || sysUser.getUserId() == null) {
|
||||
logger.warn("文章审核通过增加积分失败,未找到用户信息,createBy={},docId={}", createBy, docId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 直接写入 Redis 积分队列,由 Zone 模块定时任务消费
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", CmsConstants.PUBLISH_DOC);
|
||||
task.put("userId", sysUser.getUserId());
|
||||
task.put("deptId", deptId);
|
||||
task.put("sourceId", docId);
|
||||
task.put("subjectDesc", subjectDesc);
|
||||
task.put("operatorId", sysUser.getUserId());
|
||||
redisService.leftPush(CmsConstants.ZONE_POINTS_ASYNC_QUEUE_KEY, task.toJSONString());
|
||||
logger.info("文章审核通过增加积分任务已写入队列,docId={},userId={},deptId={}", docId, sysUser.getUserId(), deptId);
|
||||
} catch (Exception e) {
|
||||
// 捕获异常,确保不影响主事务
|
||||
logger.error("文章审核通过增加积分异常,docId={}", docId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void addVisitsDocPointsAsync(Long deptId, String createBy, Long docId, String docName, Long totalVisits) {
|
||||
try {
|
||||
if (deptId == null || createBy == null) {
|
||||
logger.warn("文章浏览增加积分失败,参数不合法,deptId={},createBy={}", deptId, createBy);
|
||||
return;
|
||||
}
|
||||
// 检查是否为积分部门
|
||||
if (!isPointsDept(deptId)) {
|
||||
logger.info("文章浏览增加积分跳过,非积分部门,deptId={},docId={}", deptId, docId);
|
||||
return;
|
||||
}
|
||||
// 获取用户ID
|
||||
com.microservices.system.api.domain.SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(createBy, SecurityConstants.INNER));
|
||||
if (sysUser == null || sysUser.getUserId() == null) {
|
||||
logger.warn("文章浏览增加积分失败,未找到用户信息,createBy={},docId={}", createBy, docId);
|
||||
return;
|
||||
}
|
||||
// 直接写入 Redis 积分队列,由 Zone 模块定时任务消费
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", CmsConstants.VISITS_DOC);
|
||||
task.put("userId", sysUser.getUserId());
|
||||
task.put("deptId", deptId);
|
||||
task.put("sourceId", docId);
|
||||
// JSONObject sourceData = new JSONObject();
|
||||
// sourceData.put("totalVisits", totalVisits);
|
||||
// sourceData.put("currentIncrement", pointsTriggerCount);
|
||||
task.put("sourceData", totalVisits);
|
||||
task.put("subjectDesc", docName);
|
||||
task.put("operatorId", SecurityUtils.getUserId());
|
||||
redisService.leftPush(CmsConstants.ZONE_POINTS_ASYNC_QUEUE_KEY, task.toJSONString());
|
||||
logger.info("文章浏览增加积分任务已写入队列,docId={},userId={},deptId={},totalVisits={}", docId, sysUser.getUserId(), deptId, totalVisits);
|
||||
} catch (Exception e) {
|
||||
// 捕获异常,确保不影响主事务
|
||||
logger.error("文章浏览增加积分异常,docId={}", docId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void addFeaturedDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc) {
|
||||
try {
|
||||
if (deptId == null || createBy == null) {
|
||||
logger.warn("积分-文章精选:参数不合法,deptId={},createBy={}", deptId, createBy);
|
||||
return;
|
||||
}
|
||||
// 检查是否为积分部门
|
||||
if (!isPointsDept(deptId)) {
|
||||
logger.info("积分-文章精选:非积分部门,deptId={},docId={}", deptId, docId);
|
||||
return;
|
||||
}
|
||||
// 获取用户ID
|
||||
com.microservices.system.api.domain.SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(createBy, SecurityConstants.INNER));
|
||||
if (sysUser == null || sysUser.getUserId() == null) {
|
||||
logger.warn("积分-文章精选:未找到用户信息,createBy={},docId={}", createBy, docId);
|
||||
return;
|
||||
}
|
||||
// 直接写入 Redis 积分队列,由 Zone 模块定时任务消费
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", CmsConstants.FEATURED_DOC);
|
||||
task.put("userId", sysUser.getUserId());
|
||||
task.put("deptId", deptId);
|
||||
task.put("sourceId", docId);
|
||||
task.put("subjectDesc", "《" + subjectDesc + "》管理员标记");
|
||||
task.put("operatorId", SecurityUtils.getUserId());
|
||||
redisService.leftPush(CmsConstants.ZONE_POINTS_ASYNC_QUEUE_KEY, task.toJSONString());
|
||||
logger.info("文章被设为精选增加积分任务已写入队列,docId={},userId={},deptId={}", docId, sysUser.getUserId(), deptId);
|
||||
} catch (Exception e) {
|
||||
// 捕获异常,确保不影响主事务
|
||||
logger.error("文章被设为精选增加积分异常,docId={}", docId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,12 @@ import com.microservices.common.core.utils.DateUtils;
|
|||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.common.core.utils.html.EscapeUtil;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.common.httpClient.constant.GitLinkConstants;
|
||||
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
||||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.common.security.auth.AuthUtil;
|
||||
import com.microservices.common.security.service.TokenService;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.system.api.RemoteDeptService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
|
|
@ -48,7 +50,11 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -80,6 +86,8 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
@Autowired
|
||||
private RemoteDeptService remoteDeptService;
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
@Autowired
|
||||
@Lazy
|
||||
private ICmsDocCommentService cmsDocCommentService;
|
||||
@Value("${cms.detailPath:/newdetail}")
|
||||
|
|
@ -89,7 +97,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
* 查询文章信息
|
||||
*
|
||||
* @param id 文章信息主键
|
||||
* @param isOpen
|
||||
* @param isOpen 是否公开访问
|
||||
* @return 文章信息
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -104,7 +112,14 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||
|
||||
String branchName = DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus()) ? CmsConstants.BRANCH_MASTER : cmsDoc.getAuditTmpBranchName();
|
||||
// 确定查询文件的分支:已发布文章或非仓库改动使用 master,其他使用临时分支
|
||||
String branchName;
|
||||
if (DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus())
|
||||
|| (cmsDoc.getAuditType() != null && cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode()))) {
|
||||
branchName = CmsConstants.BRANCH_MASTER;
|
||||
} else {
|
||||
branchName = cmsDoc.getAuditTmpBranchName();
|
||||
}
|
||||
FileEntryDto fileEntryDto = getFileEntryDto(cmsProject, cmsDoc.getFilePath(), branchName);
|
||||
EntryDto entryDto = fileEntryDto.getEntries();
|
||||
|
||||
|
|
@ -115,7 +130,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
if (cmsDoc.getPublishTime() != null && cmsDoc.getPublishTime().after(cmsDoc.getCreateTime())) {
|
||||
cmsDocDto.setIsFirstPublish(false);
|
||||
}
|
||||
if (isOpen) {
|
||||
if (isOpen && DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
updateVisits(cmsDocDto.getId());
|
||||
}
|
||||
return cmsDocDto;
|
||||
|
|
@ -171,6 +186,21 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
return cmsDocList.stream().map(CmsDoc::copyToCmsDocAllDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericsTableDataInfo<CmsDocAllDto> selectAllDocList(Long deptId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
List<CmsDocAllDto> list = selectCmsDocListByDept(deptId, cmsDocSearchVo);
|
||||
list.forEach(x -> {
|
||||
String docDetailUrl = getDocDetailUrl(x.getDeptId(), x.getId());
|
||||
x.setDocDetailUrl(docDetailUrl);
|
||||
|
||||
Boolean editable = isCmsDocEditable(x);
|
||||
x.setEditable(editable);
|
||||
|
||||
});
|
||||
int count = selectCmsDocCountByDept(deptId, cmsDocSearchVo);
|
||||
return new GenericsTableDataInfo<>(list, Long.valueOf(count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int selectCmsDocCountByDept(Long deptId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
cmsDocSearchVo.setDeptId(deptId);
|
||||
|
|
@ -233,14 +263,14 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
@Override
|
||||
public List<CmsDocDetailDto> selectCmsDocDetailList(Long dirId) {
|
||||
List<CmsDocDetailDto> cmsDocDetailDtoList = new ArrayList<>();
|
||||
CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirById(dirId);
|
||||
CmsDoc cmsDir = selectCmsDir(dirId);
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDir.getDeptId());
|
||||
CmsDocSearchVo cmsDocSearchVo = new CmsDocSearchVo();
|
||||
cmsDocSearchVo.setDirName(cmsDir.getName());
|
||||
cmsDocSearchVo.setDeptId(cmsDir.getDeptId());
|
||||
cmsDocSearchVo.setIsDir(false);
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearchVo);
|
||||
List<CompletableFuture<CmsDocDetailDto>> futures = new ArrayList();
|
||||
List<CompletableFuture<CmsDocDetailDto>> futures = new ArrayList<>();
|
||||
for (CmsDoc cmsDoc : cmsDocList) {
|
||||
CompletableFuture<CmsDocDetailDto> future = CompletableFuture.supplyAsync(() -> {
|
||||
CmsDocDetailDto cmsDocDetailDto = cmsDoc.copyToCmsDocDetailDto();
|
||||
|
|
@ -360,12 +390,16 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
checkCmsLockStatus(dirDoc.getDeptId());
|
||||
CmsDoc cmsDoc = cmsDocInputDto.toCmsDoc(dirDoc);
|
||||
|
||||
if (isNoAuditRequired(dirDoc.getDeptId()) || hasDeptAdminPerms(dirDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT)) {
|
||||
if (isNoAuditRequired(dirDoc.getDeptId()) || tokenService.hasDeptPerms(dirDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT)) {
|
||||
//文章自动置为审核通过状态值
|
||||
cmsDoc.setAuditStatus(DocAuditStatus.AUDIT_PASS.getAuditCode());
|
||||
boolean success = insertCommonCmsDoc(cmsDoc,
|
||||
"创建文章:" + StringUtils.truncateStringAndConcatenatingSpecifiedString(cmsDoc.getName(), 100, "..."),
|
||||
cmsDocInputDto.getContent());
|
||||
if (success) {
|
||||
// 自动审核通过时也需要增加积分
|
||||
cmsAsyncService.addPublishDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(), cmsDoc.getId(), cmsDoc.getName());
|
||||
}
|
||||
return success ? cmsDoc.getId().intValue() : null;
|
||||
} else {
|
||||
//创建临时分支,创建文件,创建PR
|
||||
|
|
@ -403,7 +437,9 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
public String getCmsDocFileContent(CmsProject cmsProject, CmsDoc cmsDoc) {
|
||||
String branchName = CmsConstants.BRANCH_MASTER;
|
||||
if (!DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
branchName = cmsDoc.getAuditTmpBranchName();
|
||||
if (StringUtils.isNotEmpty(cmsDoc.getAuditTmpBranchName())) {
|
||||
branchName = cmsDoc.getAuditTmpBranchName();
|
||||
}
|
||||
}
|
||||
//当删除文章为文件夹时,判断该文件夹下是否存在文章,若存在需先删除所有文章
|
||||
JSONObject getSubEntriesResult = gitLinkRequestHelper.doGet(
|
||||
|
|
@ -433,6 +469,24 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
cmsDoc.setRemark(cmsDocAuditVo.getRemark());
|
||||
|
||||
if (cmsDocAuditVo.getPass() == 1) {
|
||||
// 处理非仓库改动的审核通过
|
||||
if (cmsDoc.getAuditType() != null
|
||||
&& cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
Long oldCmsDocId = Long.parseLong(cmsDoc.getAuditType().split("-")[1]);
|
||||
CmsDoc oldCmsDoc = cmsDocMapper.selectCmsDocById(oldCmsDocId);
|
||||
|
||||
// 用新文章的非仓库字段更新旧文章
|
||||
oldCmsDoc.setHeadImg(cmsDoc.getHeadImg());
|
||||
oldCmsDoc.setSummary(cmsDoc.getSummary());
|
||||
oldCmsDoc.setKeywords(cmsDoc.getKeywords());
|
||||
oldCmsDoc.setRemark(cmsDoc.getRemark());
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
|
||||
// 删除待审核记录
|
||||
cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
//同意合并请求
|
||||
JSONObject result = mergePullRequestByGitLink(cmsProject, cmsDoc);
|
||||
if (result.containsKey(GitLinkConstants.STATUS_KEY)) {
|
||||
|
|
@ -454,6 +508,12 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
}
|
||||
}
|
||||
if (cmsDocAuditVo.getPass() == 0) {
|
||||
// 处理非仓库改动的审核拒绝
|
||||
if (cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
handleCmsDocWithNoPassByReedit(cmsDocAuditVo, cmsDoc, cmsProject);
|
||||
return true;
|
||||
}
|
||||
|
||||
//拒绝GitLink合并请求
|
||||
String gitLinkPullRequestNumber = cmsDoc.getAuditPrNumber().split("-")[0];
|
||||
JSONObject result = gitLinkRequestHelper.doPost(
|
||||
|
|
@ -504,8 +564,10 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
if (cmsDocAuditVo.getReedit().equals(0)) {
|
||||
//删除待审核文章
|
||||
cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
//删除分支
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
// 删除分支(如果有)
|
||||
if (StringUtils.isNotEmpty(cmsDoc.getAuditTmpBranchName())) {
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -556,6 +618,8 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
|
||||
// 推送文章地址到搜索引擎
|
||||
cmsAsyncService.pushDocDataSearchEngine(cmsDoc);
|
||||
// 文章审核通过后,给作者增加积分(异步执行,不影响主事务)
|
||||
cmsAsyncService.addPublishDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(), cmsDoc.getId(), cmsDoc.getName());
|
||||
}
|
||||
|
||||
private JSONObject mergePullRequestByGitLink(CmsProject cmsProject, CmsDoc cmsDoc) {
|
||||
|
|
@ -711,11 +775,47 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean updateCmsDoc(Long id, CmsDocDto cmsDocDto) {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long updateCmsDoc(Long id, CmsDocDto cmsDocDto) {
|
||||
CmsDoc oldCmsDoc = cmsDocMapper.selectCmsDocById(id);
|
||||
checkCmsLockStatus(oldCmsDoc.getDeptId());
|
||||
if (!hasRepoRelatedChanged(oldCmsDoc, cmsDocDto)) {
|
||||
return cmsDocMapper.updateCmsDoc(oldCmsDoc) > 0;
|
||||
// 更新非仓库字段到原文章对象
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getHeadImg())) {
|
||||
oldCmsDoc.setHeadImg(cmsDocDto.getHeadImg());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getSummary())) {
|
||||
oldCmsDoc.setSummary(cmsDocDto.getSummary());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getKeywords())) {
|
||||
oldCmsDoc.setKeywords(cmsDocDto.getKeywords());
|
||||
}
|
||||
|
||||
// 管理员或免审核:直接更新原记录
|
||||
if (tokenService.hasDeptPerms(oldCmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT)
|
||||
|| isNoAuditRequired(oldCmsDoc.getDeptId())) {
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
}
|
||||
|
||||
// 需要审核:创建新的待审核记录(与仓库改动逻辑一致)
|
||||
if (oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
||||
CmsDoc newDocWithAudit = insertDocWithAudit(oldCmsDoc,
|
||||
DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode() + "-" + oldCmsDoc.getId(),
|
||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
return newDocWithAudit.getId();
|
||||
}
|
||||
oldCmsDoc.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
if (oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_CREATE.getOperationCode())
|
||||
|| oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_UPDATE.getOperationCode())) {
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(oldCmsDoc.getDeptId());
|
||||
// 重新开启PR
|
||||
String gitLinkPullRequestNumber = oldCmsDoc.getAuditPrNumber().split("-")[0];
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.REOPEN_PULL_REQUEST(cmsProject, gitLinkPullRequestNumber), null);
|
||||
}
|
||||
// 待审核/未通过文章重新编辑
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
}
|
||||
// 当文章名称发生更改时,判断文章名是否在当前栏目下已存在
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getName()) && !cmsDocDto.getName().equals(oldCmsDoc.getName())) {
|
||||
|
|
@ -737,7 +837,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
}
|
||||
}
|
||||
//用户为专区管理员或专区无审核机制时,直接更新文章及仓库主分支
|
||||
if (hasDeptAdminPerms(oldCmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT) || isNoAuditRequired(oldCmsDoc.getDeptId())) {
|
||||
if (tokenService.hasDeptPerms(oldCmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT) || isNoAuditRequired(oldCmsDoc.getDeptId())) {
|
||||
//专区管理员重新编辑并提交审核未通过文章 或 重新编辑并提交待审核文章时专区不需审核机制
|
||||
if (!oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
||||
//文章审核类型:update-原文章id 取出原文章id直接更新,删除待审核更新类型文章
|
||||
|
|
@ -752,7 +852,8 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
if (oldCmsDoc.getAuditType() != null && oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_CREATE.getOperationCode())) {
|
||||
deleteTmpBranchIfBranchExist(oldCmsDoc);
|
||||
cmsDocMapper.deleteCmsDocById(id);
|
||||
return directlyInsertAuditedCmsDocWhenZoneHasNoAuditRequired(cmsDocDto, oldCmsDoc);
|
||||
directlyInsertAuditedCmsDocWhenZoneHasNoAuditRequired(cmsDocDto, oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
}
|
||||
}
|
||||
String branchName = CmsConstants.BRANCH_MASTER;
|
||||
|
|
@ -760,13 +861,49 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
oldCmsDoc.setAuditStatus(DocAuditStatus.AUDIT_PASS.getAuditCode());
|
||||
oldCmsDoc.setAuditTmpBranchName(null);
|
||||
oldCmsDoc.setKeywords(cmsDocDto.getKeywords());
|
||||
return updateCmsCommonDatabase(oldCmsDoc, CmsConstants.BRANCH_MASTER) > 0;
|
||||
updateCmsCommonDatabase(oldCmsDoc, CmsConstants.BRANCH_MASTER);
|
||||
return oldCmsDoc.getId();
|
||||
} else {
|
||||
|
||||
CmsDoc newDocWithAudit = new CmsDoc();
|
||||
//待审核、未通过文章重新编辑并提交
|
||||
if (DocAuditStatus.AUDIT_FAIL.getAuditCode().equals(oldCmsDoc.getAuditStatus())
|
||||
|| DocAuditStatus.TO_BE_AUDIT.getAuditCode().equals(oldCmsDoc.getAuditStatus())) {
|
||||
|
||||
// 非仓库改动待审核记录:检查是否有仓库改动
|
||||
if (oldCmsDoc.getAuditType() != null
|
||||
&& oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
|
||||
if (!hasRepoRelatedChanged(oldCmsDoc, cmsDocDto)) {
|
||||
// 纯非仓库改动:继续在当前记录上更新
|
||||
oldCmsDoc.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getHeadImg())) {
|
||||
oldCmsDoc.setHeadImg(cmsDocDto.getHeadImg());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getSummary())) {
|
||||
oldCmsDoc.setSummary(cmsDocDto.getSummary());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getKeywords())) {
|
||||
oldCmsDoc.setKeywords(cmsDocDto.getKeywords());
|
||||
}
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
} else {
|
||||
// 有仓库改动:转为仓库改动类型,删除当前记录,重新创建
|
||||
Long oldCmsDocId = Long.parseLong(oldCmsDoc.getAuditType().split("-")[1]);
|
||||
CmsDoc originCmsDoc = cmsDocMapper.selectCmsDocById(oldCmsDocId);
|
||||
cmsDocMapper.deleteCmsDocById(oldCmsDoc.getId());
|
||||
|
||||
// 按照仓库改动逻辑重新创建
|
||||
newDocWithAudit = insertDocWithAudit(originCmsDoc,
|
||||
DocAndZoneOperation.OPERATION_UPDATE.getOperationCode() + "-" + oldCmsDocId,
|
||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
cmsAsyncService.asyncUpdateBranchAndFileAndCreatePR(newDocWithAudit, cmsDocDto);
|
||||
return newDocWithAudit.getId();
|
||||
}
|
||||
}
|
||||
|
||||
// 仓库改动待审核记录:继续在当前记录上更新
|
||||
oldCmsDoc.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
newDocWithAudit = oldCmsDoc;
|
||||
} else {
|
||||
|
|
@ -779,7 +916,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
}
|
||||
}
|
||||
cmsAsyncService.asyncUpdateBranchAndFileAndCreatePR(newDocWithAudit, cmsDocDto);
|
||||
return true;
|
||||
return newDocWithAudit.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -870,6 +1007,12 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
oldCmsDoc.setAuditType(auditType);
|
||||
oldCmsDoc.setAuditStatus(auditStatus);
|
||||
oldCmsDoc.setCreateBy(SecurityUtils.getUsername());
|
||||
|
||||
// 非 repo 改动:显式设置 auditTmpBranchName 为 null(没有对应的分支)
|
||||
if (auditType != null && auditType.contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
oldCmsDoc.setAuditTmpBranchName(null);
|
||||
}
|
||||
|
||||
cmsDocMapper.insertCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc;
|
||||
}
|
||||
|
|
@ -1024,7 +1167,13 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
visits = visits + cmsDoc.getVisits();
|
||||
}
|
||||
cmsDoc.setVisits(visits);
|
||||
return cmsDocMapper.updateCmsDoc(cmsDoc) > 0;
|
||||
int rows = cmsDocMapper.updateCmsDoc(cmsDoc);
|
||||
if (rows > 0) {
|
||||
cmsAsyncService.addVisitsDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(),
|
||||
cmsDoc.getId(), cmsDoc.getName(), cmsDoc.getVisits());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1148,6 +1297,9 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
//首页推荐时,需将顺序设置为1
|
||||
setCmsSort(1, cmsDoc, false, null);
|
||||
cmsDoc.setIsHomepage(CmsConstants.TRUE);
|
||||
// 文章被设为精选,异步增加作者积分
|
||||
cmsAsyncService.addFeaturedDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(),
|
||||
cmsDoc.getId(), cmsDoc.getName());
|
||||
}
|
||||
return cmsDocMapper.updateCmsDoc(cmsDoc);
|
||||
}
|
||||
|
|
@ -1171,6 +1323,41 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
return cmsDocBaseDtoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CmsDocBaseDto> selectHomePageDocMergeList(Long zoneId, List<Long> topDocIds) {
|
||||
Long deptId = getDeptIdByZoneId(zoneId);
|
||||
Set<Long> addedDocIds = new HashSet<>();
|
||||
|
||||
// 1. 获取首页推荐文章列表
|
||||
List<CmsDocBaseDto> homePageDocs = selectHomePageDocList(deptId);
|
||||
List<CmsDocBaseDto> result = new ArrayList<>();
|
||||
|
||||
// 2. 批量查询置顶文章完整数据,按传入顺序放入结果头部
|
||||
if (topDocIds != null && !topDocIds.isEmpty()) {
|
||||
List<CmsDoc> topCmsDocs = cmsDocMapper.selectCmsDocByIds(topDocIds);
|
||||
Map<Long, CmsDoc> topDocMap = new HashMap<>();
|
||||
for (CmsDoc doc : topCmsDocs) {
|
||||
topDocMap.put(doc.getId(), doc);
|
||||
}
|
||||
for (Long docId : topDocIds) {
|
||||
CmsDoc doc = topDocMap.get(docId);
|
||||
if (doc != null) {
|
||||
result.add(doc.copyToCmsDocBaseDto());
|
||||
addedDocIds.add(docId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 追加首页推荐文章(跳过已在置顶列表中的)
|
||||
for (CmsDocBaseDto doc : homePageDocs) {
|
||||
if (!addedDocIds.contains(doc.getId())) {
|
||||
result.add(doc);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CmsDir initCmsDir(Long deptId, CmsDir cmsDirInput) {
|
||||
|
|
@ -1317,16 +1504,15 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
cmsAsyncService.updateCmsPublishDataByGitLink(cmsProject, cmsDoc, branchName);
|
||||
}
|
||||
|
||||
private Boolean hasDeptAdminPerms(Long deptId, String perms) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Boolean hasPerms = FeignUtils.getReturnData(
|
||||
remoteDeptService.checkUserInDeptOrParentDeptHasPerms(deptId, loginUser.getUserId(), perms, SecurityConstants.INNER)
|
||||
);
|
||||
|
||||
if (hasPerms == null) {
|
||||
hasPerms = false;
|
||||
private int deleteCmsDir(CmsProject cmsProject, CmsDoc cmsDir) {
|
||||
if (!isNoAuditRequired(cmsDir.getDeptId()) || tokenService.hasDeptPerms(cmsDir.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT)) {
|
||||
boolean deleteResult = cmsAsyncService.deleteCmsDocForGitLink(cmsDir, cmsProject, CmsConstants.BRANCH_MASTER);
|
||||
if (deleteResult) {
|
||||
return cmsDocMapper.deleteCmsDocById(cmsDir.getId());
|
||||
}
|
||||
throw new ServiceException("栏目删除失败");
|
||||
}
|
||||
return hasPerms;
|
||||
throw new ServiceException("无权限删除栏目");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1338,9 +1524,16 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
checkCmsLockStatus(cmsDoc.getDeptId());
|
||||
//2、获取专区项目
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||
if (cmsDoc.getIsDir()) {
|
||||
return deleteCmsDir(cmsProject, cmsDoc);
|
||||
}
|
||||
|
||||
//删除待审核、审核未通过文章——删除临时分支,拒绝合并请求
|
||||
if (DocAuditStatus.TO_BE_AUDIT.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
// 非仓库改动类型直接删除
|
||||
if (cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
return cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
}
|
||||
|
||||
//拒绝GitLink合并请求
|
||||
String gitLinkPullRequestNumber = cmsDoc.getAuditPrNumber().split("-")[0];
|
||||
|
|
@ -1353,7 +1546,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
return cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
}
|
||||
// 判读当前用户是否拥有文章直接删除权限
|
||||
if (hasDeptAdminPerms(cmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT) //当前用户为专区管理员
|
||||
if (tokenService.hasDeptPerms(cmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT) //当前用户为专区管理员
|
||||
|| isNoAuditRequired(cmsDoc.getDeptId()) //当前专区文章发布无需审核机制
|
||||
) {
|
||||
String branchName = CmsConstants.BRANCH_MASTER;
|
||||
|
|
|
|||
|
|
@ -25,4 +25,24 @@ public class CmsConstants {
|
|||
* 是
|
||||
*/
|
||||
public final static String TRUE = "1";
|
||||
|
||||
/**
|
||||
* 专区积分异步队列 Redis Key(与 Zone 模块保持一致)
|
||||
*/
|
||||
public final static String ZONE_POINTS_ASYNC_QUEUE_KEY = "zone:points:async:queue";
|
||||
|
||||
/**
|
||||
* 发布文章积分类型
|
||||
*/
|
||||
public final static String PUBLISH_DOC = "publishDoc";
|
||||
|
||||
/**
|
||||
* 浏览文章积分类型
|
||||
*/
|
||||
public final static String VISITS_DOC = "visitsDoc";
|
||||
|
||||
/**
|
||||
* 精选文章积分类型
|
||||
*/
|
||||
public final static String FEATURED_DOC = "featuredDoc";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
public static GitLinkRequestUrl ADD_USER_TO_ORGANIZATION_TEAM(String orgIdentifier, Long teamId) {
|
||||
return getAdminGitLinkRequestUrl(String.format("/api/organizations/%s/teams/%d/team_users.json", orgIdentifier, teamId));
|
||||
}
|
||||
|
||||
public static String TEAMS_BY_ORGANIZATION_URL(Long orgId) {
|
||||
return String.format("/api/organizations/%s/teams.json", orgId);
|
||||
}
|
||||
|
|
@ -87,6 +88,12 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl REOPEN_PULL_REQUEST(CmsProject cmsProject, String giteaPrNumber) {
|
||||
return getGitLinkRequestUrl(
|
||||
String.format("/api/v1/%s/%s/pulls/%s/reopen", cmsProject.getUsername(), cmsProject.getIdentifier(), giteaPrNumber)
|
||||
);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl GET_PULL_REQUEST_DETAILS(CmsProject cmsProject, String giteaPrNumber) {
|
||||
return getGitLinkRequestUrl(
|
||||
String.format("/api/%s/%s/pulls/%s.json", cmsProject.getUsername(), cmsProject.getIdentifier(), giteaPrNumber)
|
||||
|
|
@ -112,7 +119,7 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
}
|
||||
|
||||
public static GitLinkRequestUrl ADD_USER_FROM_PROJECT(CmsProject cmsProject) {
|
||||
return getGitLinkRequestUrl(
|
||||
return getAdminGitLinkRequestUrl(
|
||||
String.format("/api/%s/%s/collaborators.json", cmsProject.getUsername(), cmsProject.getIdentifier())
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@
|
|||
cd.editor_type,
|
||||
cd.keywords,
|
||||
cd.is_dir,
|
||||
cd.audit_status,
|
||||
cd.audit_type,
|
||||
cd.audit_tmp_branch_name,
|
||||
cd.audit_pr_number,
|
||||
cd.remark
|
||||
from cms_doc cd
|
||||
</sql>
|
||||
|
|
@ -139,6 +143,10 @@
|
|||
cd.editor_type,
|
||||
cd.keywords,
|
||||
cd.is_dir,
|
||||
cd.audit_status,
|
||||
cd.audit_type,
|
||||
cd.audit_tmp_branch_name,
|
||||
cd.audit_pr_number,
|
||||
-- 计算全文搜索相关度评分
|
||||
MATCH(cd.name, cd.summary) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE) AS search_score,
|
||||
cd.remark
|
||||
|
|
@ -180,6 +188,10 @@
|
|||
cd.editor_type,
|
||||
cd.keywords,
|
||||
cd.is_dir,
|
||||
cd.audit_status,
|
||||
cd.audit_type,
|
||||
cd.audit_tmp_branch_name,
|
||||
cd.audit_pr_number,
|
||||
cd.remark
|
||||
from cms_doc cd
|
||||
left join cms_doc dir on cd.dir_name = dir.name and cd.dept_id = dir.dept_id and dir.is_dir=1
|
||||
|
|
@ -205,10 +217,20 @@
|
|||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="selectCmsDocByIds" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where id in
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
and audit_status = '1'
|
||||
</select>
|
||||
|
||||
<select id="selectCmsDocByNameAndDeptId" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
<where>
|
||||
and name = #{name}
|
||||
and audit_status != 0
|
||||
and dept_id = #{deptId}
|
||||
<choose>
|
||||
<when test="dirName != null">
|
||||
|
|
@ -220,6 +242,10 @@
|
|||
</choose>
|
||||
</where>
|
||||
</select>
|
||||
<select id="selectCmsDocByNameAndDeptIdIgnoreDirName" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where name = #{name} and dept_id = #{deptId} and is_dir = 0
|
||||
</select>
|
||||
<select id="selectCmsDocDirByNameAndDeptId" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where name = #{name} and dept_id = #{deptId} and is_dir = 1
|
||||
|
|
@ -260,6 +286,7 @@
|
|||
<if test="auditStatus != null and auditStatus != '-1' ">and audit_status = #{auditStatus}</if>
|
||||
<if test="auditStatus == null ">and audit_status = '1'</if>
|
||||
<if test="createBy != null and createBy != '' ">and create_by = #{createBy}</if>
|
||||
<if test="excludeId != null ">and id != #{excludeId}</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.microservices.file.controller;
|
||||
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.file.service.ISysFileInfoService;
|
||||
import com.microservices.system.api.domain.SysFileInfo;
|
||||
|
|
@ -120,19 +121,20 @@ public class OpenController {
|
|||
@ApiImplicitParam(name = "hierarchy", value = "层级结构(eg: pms项目管理中{enterpriseIdentifier}/products,{enterpriseIdentifier}/projects,{enterpriseIdentifier}/docs/{projectId})", paramType = "query", dataType = "String")
|
||||
})
|
||||
public AjaxResult uploadFile(@RequestPart("file") MultipartFile file, String type, String hierarchy) {
|
||||
SysFileInfo sysFileInfo = sysFileInfoService.upload(file, type, hierarchy);
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("url", sysFileInfo.getDownloadUrl());
|
||||
if (sysFileInfo.getFileIdentifier() != null) {
|
||||
ajax.put("fileIdentifier", sysFileInfo.getFileIdentifier());
|
||||
}
|
||||
ajax.put("fileName", sysFileInfo.getFilePath());
|
||||
if (sysFileInfo.getFileId() != null) {
|
||||
ajax.put("fileId", sysFileInfo.getFileId());
|
||||
}
|
||||
ajax.put("fileOriginName", sysFileInfo.getFileOriginName());
|
||||
ajax.put("fileSuffix", sysFileInfo.getFileSuffix());
|
||||
ajax.put("fileSize", sysFileInfo.getFileSizeInfo());
|
||||
return ajax;
|
||||
throw new ServiceException("该接口已弃用!");
|
||||
// SysFileInfo sysFileInfo = sysFileInfoService.upload(file, type, hierarchy);
|
||||
// AjaxResult ajax = AjaxResult.success();
|
||||
// ajax.put("url", sysFileInfo.getDownloadUrl());
|
||||
// if (sysFileInfo.getFileIdentifier() != null) {
|
||||
// ajax.put("fileIdentifier", sysFileInfo.getFileIdentifier());
|
||||
// }
|
||||
// ajax.put("fileName", sysFileInfo.getFilePath());
|
||||
// if (sysFileInfo.getFileId() != null) {
|
||||
// ajax.put("fileId", sysFileInfo.getFileId());
|
||||
// }
|
||||
// ajax.put("fileOriginName", sysFileInfo.getFileOriginName());
|
||||
// ajax.put("fileSuffix", sysFileInfo.getFileSuffix());
|
||||
// ajax.put("fileSize", sysFileInfo.getFileSizeInfo());
|
||||
// return ajax;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,11 @@ public class SysFileInfoServiceImpl implements ISysFileInfoService {
|
|||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
/** 积分异步任务 Redis 队列 Key */
|
||||
private static final String ZONE_POINTS_ASYNC_QUEUE_KEY = "zone:points:async:queue";
|
||||
/** 资源下载积分任务 sourceType */
|
||||
private static final String DOWNLOAD_RESOURCE_SOURCE_TYPE = "downloadResource";
|
||||
|
||||
@Override
|
||||
public SysFileInfo selectSysFileInfoByFileObjectName(String fileObjectName) {
|
||||
return sysFileInfoMapper.selectSysFileInfoByFileObjectName(fileObjectName);
|
||||
|
|
@ -616,6 +621,15 @@ public class SysFileInfoServiceImpl implements ISysFileInfoService {
|
|||
sysFileInfo.setDownloadCount(downloadCount);
|
||||
updateSysFileInfo(sysFileInfo);
|
||||
|
||||
// 触发资源下载积分任务(直接写入 Redis 异步队列)
|
||||
try {
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", DOWNLOAD_RESOURCE_SOURCE_TYPE);
|
||||
task.put("sourceId", sysFileInfo.getFileId());
|
||||
redisService.leftPush(ZONE_POINTS_ASYNC_QUEUE_KEY, JSONObject.toJSONString(task));
|
||||
} catch (Exception e) {
|
||||
logger.warn("触发资源下载积分任务失败 fileId={} error={}", sysFileInfo.getFileId(), e.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("文件下载异常:%s", e.getMessage());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import io.swagger.annotations.ApiModel;
|
|||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -71,12 +72,18 @@ public class PmsProjectTestcaseDataVo extends BaseEntityVo {
|
|||
@ApiModelProperty(value = "关联产品需求")
|
||||
private PmsProductRequirement productReqSpecs;
|
||||
|
||||
@ApiModelProperty(value = "测试追踪")
|
||||
private String testTracking;
|
||||
|
||||
/**
|
||||
* 用例索引
|
||||
*/
|
||||
@ApiModelProperty(value = "用例索引")
|
||||
private Long index;
|
||||
|
||||
@ApiModelProperty(value = "测试用例标识")
|
||||
private String identifier;
|
||||
|
||||
|
||||
public PmsProjectTestcaseDetailVo toPmsProjectTestcaseDetailVo() {
|
||||
PmsProjectTestcaseDetailVo target = new PmsProjectTestcaseDetailVo();
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
<result property="testMethod" column="test_method"/>
|
||||
<result property="terminationConditions" column="termination_conditions"/>
|
||||
<result property="identifier" column="identifier"/>
|
||||
<result property="testTracking" column="test_track"/>
|
||||
<result property="testTracking" column="test_tracking"/>
|
||||
<result property="productReqSpecsId" column="product_req_specs_id"/>
|
||||
<result property="isImport" column="is_import"/>
|
||||
</resultMap>
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
<sql id="selectPmsProjectTestcaseVo">
|
||||
select id,
|
||||
title,
|
||||
test_tracking,
|
||||
assignee_gitlink_id,
|
||||
pms_project_id,
|
||||
type_id,
|
||||
|
|
@ -186,7 +187,7 @@
|
|||
<if test="testMethod != null">test_method = #{testMethod},</if>
|
||||
<if test="terminationConditions != null">termination_conditions = #{terminationConditions},</if>
|
||||
<if test="identifier != null">identifier = #{identifier},</if>
|
||||
<if test="testTracking != null">#{testTracking},</if>
|
||||
<if test="testTracking != null">test_tracking = #{testTracking},</if>
|
||||
<if test="productReqSpecsId != null">#{productReqSpecsId},</if>
|
||||
<if test="isImport != null">#{isImport},</if>
|
||||
</trim>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.microservices.system.controller;
|
||||
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
|
|
@ -203,6 +204,26 @@ public class SysUserController extends BaseController {
|
|||
return R.ok(sysUser);
|
||||
}
|
||||
|
||||
@InnerAuth
|
||||
@GetMapping("/getSysUserListByUserIds")
|
||||
R<List<SysUser>> getSysUserListByUserIds(@RequestParam("userIds") Long[] userIds) {
|
||||
List<SysUser> sysUserList = userService.selectUserListFromUserIds(userIds);
|
||||
return R.ok(sysUserList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过用户ID数组批量获取用户信息(POST方法,解决URL长度限制)
|
||||
*
|
||||
* @param userIds 用户ID数组
|
||||
* @return 用户列表
|
||||
*/
|
||||
@InnerAuth
|
||||
@PostMapping("/getSysUserListByUserIds")
|
||||
R<List<SysUser>> postSysUserListByUserIds(@RequestBody Long[] userIds) {
|
||||
List<SysUser> sysUserList = userService.selectUserListFromUserIds(userIds);
|
||||
return R.ok(sysUserList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过GitLinkToken获取本系统Token
|
||||
*
|
||||
|
|
|
|||
|
|
@ -131,4 +131,6 @@ public interface SysUserMapper
|
|||
public SysUser checkEmailUnique(String email);
|
||||
|
||||
SysUser selectUserByGitLinkUserId(Long gitLinkUserId);
|
||||
|
||||
List<SysUser> selectUserListFromUserIds(Long[] ids);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,4 +222,6 @@ public interface ISysUserService
|
|||
String getUserNameByGitLinkToken(String gitLinkToken);
|
||||
|
||||
SysUser gitlinkUserToUpdateSysUser(SysUser sysUser, ForgeUser forgeUser);
|
||||
|
||||
List<SysUser> selectUserListFromUserIds(Long[] userIds);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,8 +169,11 @@ public class SysUserDeptRoleServiceImpl implements ISysUserDeptRoleService {
|
|||
if (sysUser == null) {
|
||||
return;
|
||||
}
|
||||
String redisKey = CacheConstants.getUserIdentifyListKey(sysUser.getUserName());
|
||||
// 删除缓存中该用户身份列表信息
|
||||
redisService.deleteObject(CacheConstants.getUserIdentifyListKey(sysUser.getUserName()));
|
||||
redisService.deleteObject(CacheConstants.getUserIdentifyListKey(redisKey));
|
||||
List<SysUserDeptRole> userIdentifyList = selectSysUserDeptRoleListByUserName(sysUser.getUserName());
|
||||
redisService.setCacheObject(redisKey, userIdentifyList);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.validation.Validator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -684,4 +681,9 @@ public class SysUserServiceImpl implements ISysUserService {
|
|||
return sysUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysUser> selectUserListFromUserIds(Long[] userIds) {
|
||||
return userMapper.selectUserListFromUserIds(userIds);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,19 +121,24 @@ public class SyncGitLinkUserInfoJob {
|
|||
for (ForgeUserAction forgeUserAction : forgeUserActionList) {
|
||||
String userActionDataBank = forgeUserAction.getDataBank();
|
||||
if (StringUtils.isNotEmpty(userActionDataBank)) {
|
||||
JSONObject jsonObject = JSON.parseObject(userActionDataBank);
|
||||
if (jsonObject != null) {
|
||||
Long userId = jsonObject.getLong("id");
|
||||
if (userId != null) {
|
||||
SysUser sysUser = sysUserMapper.selectUserByGitLinkUserId(forgeUserAction.getUserId());
|
||||
if (sysUser != null && UserConstants.DEL_FLAG_FALSE.equals(sysUser.getDelFlag())) {
|
||||
log.info("检测到用户{}在Forge端已注销,将该用户在微服务平台的所有身份标记为已注销同时逻辑删除该用户", sysUser.getUserName());
|
||||
// 更新用户所有身份为已注销
|
||||
sysUserDeptRoleService.deleteSysUserDeptRoleByDeleteUser(sysUser.getUserId());
|
||||
// 逻辑删除该用户
|
||||
sysUserService.deleteUserById(sysUser.getUserId());
|
||||
try {
|
||||
JSONObject jsonObject = JSON.parseObject(userActionDataBank);
|
||||
if (jsonObject != null) {
|
||||
Long userId = jsonObject.getLong("id");
|
||||
if (userId != null) {
|
||||
SysUser sysUser = sysUserMapper.selectUserByGitLinkUserId(forgeUserAction.getUserId());
|
||||
if (sysUser != null && UserConstants.DEL_FLAG_FALSE.equals(sysUser.getDelFlag())) {
|
||||
log.info("检测到用户{}在Forge端已注销,将该用户在微服务平台的所有身份标记为已注销同时逻辑删除该用户", sysUser.getUserName());
|
||||
// 更新用户所有身份为已注销
|
||||
sysUserDeptRoleService.deleteSysUserDeptRoleByDeleteUser(sysUser.getUserId());
|
||||
// 逻辑删除该用户
|
||||
sysUserService.deleteUserById(sysUser.getUserId());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析Forge用户操作JSON失败,forgeUserActionId: {}, userId: {}, dataBank: {}, 错误信息: {}",
|
||||
forgeUserAction.getId(), forgeUserAction.getUserId(), userActionDataBank, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,8 +200,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
where u.gitlink_user_id = #{gitLinkUserId}
|
||||
limit 1
|
||||
</select>
|
||||
<select id="selectUserListFromUserIds" resultMap="SysUserResult">
|
||||
<include refid="selectOnlyUserVo"/>
|
||||
where user_id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
|
||||
<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
|
||||
insert into sys_user(
|
||||
<if test="userId != null and userId != 0">user_id,</if>
|
||||
<if test="gitlinkUserId != null and gitlinkUserId != 0">gitlink_user_id,</if>
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@
|
|||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Microservices Common Redis -->
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Microservices Common Async -->
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@ import com.microservices.common.security.annotation.RequiresPermissions;
|
|||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.zone.detail.domain.vo.ZoneFrontRoleVo;
|
||||
import com.microservices.zone.detail.service.IZoneDetailService;
|
||||
import com.microservices.zone.project.domain.ZoneProjectType;
|
||||
import com.microservices.zone.project.domain.vo.*;
|
||||
import com.microservices.zone.project.service.IZoneProjectService;
|
||||
import com.microservices.zone.member.service.IZonePointsAccountService;
|
||||
import com.microservices.zone.project.service.IZoneProjectTypeService;
|
||||
import com.microservices.zone.resource.domain.ZoneResource;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import com.microservices.zone.resource.domain.vo.ZoneResourceDataVo;
|
||||
import com.microservices.zone.resource.domain.vo.ZoneResourceInputVo;
|
||||
import com.microservices.zone.resource.domain.vo.ZoneResourceSearchVo;
|
||||
|
|
@ -28,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -50,6 +52,9 @@ public class FrontController extends BaseController {
|
|||
@Autowired
|
||||
private IZoneProjectTypeService zoneProjectTypeService;
|
||||
|
||||
@Autowired
|
||||
private IZonePointsAccountService zonePointsAccountService;
|
||||
|
||||
/**
|
||||
* 查询我的资源列表
|
||||
*/
|
||||
|
|
@ -182,6 +187,11 @@ public class FrontController extends BaseController {
|
|||
"3、当权限为None时,不展示前台操作按钮\n" +
|
||||
"4、检测到用户登录后才能调用该接口,否则不展示前台操作按钮")
|
||||
public GenericsAjaxResult<ZoneFrontRoleVo> checkCurrentRole(@PathVariable Long zoneId) {
|
||||
return genericsSuccess(zoneDetailService.checkCurrentRoleInZone(zoneId));
|
||||
ZoneFrontRoleVo zoneFrontRoleVo = zoneDetailService.checkCurrentRoleInZone(zoneId);
|
||||
// 专区普通会员,触发每日首次访问积分+1
|
||||
if (ZoneConstants.FRONT_ROLE_MEMBER.equals(zoneFrontRoleVo.getRole())) {
|
||||
zonePointsAccountService.addDailyVisitPointsAsync(zoneId);
|
||||
}
|
||||
return genericsSuccess(zoneFrontRoleVo);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.microservices.zone.common.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
|
|
@ -19,7 +20,12 @@ import com.microservices.zone.detail.service.IZoneDetailService;
|
|||
import com.microservices.zone.member.domain.vo.ZoneMemberDataVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberOpenSearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberOverviewVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberSearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberTypeCountVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTopDocVo;
|
||||
import com.microservices.zone.member.service.IZoneMemberService;
|
||||
import com.microservices.zone.member.service.IZoneMemberTypeService;
|
||||
import com.microservices.zone.member.service.IZonePointsAccountService;
|
||||
import com.microservices.zone.partners.domain.vo.ZonePartnersOverviewVo;
|
||||
import com.microservices.zone.partners.service.IZonePartnersService;
|
||||
import com.microservices.zone.project.domain.ZoneProjectType;
|
||||
|
|
@ -57,6 +63,7 @@ import org.springframework.validation.annotation.Validated;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -72,6 +79,8 @@ public class OpenController extends BaseController {
|
|||
@Autowired
|
||||
private IZoneMemberService zoneMemberService;
|
||||
@Autowired
|
||||
private IZoneMemberTypeService zoneMemberTypeService;
|
||||
@Autowired
|
||||
private IZonePartnersService zonePartnersService;
|
||||
@Autowired
|
||||
private IZoneProjectService zoneProjectService;
|
||||
|
|
@ -80,6 +89,8 @@ public class OpenController extends BaseController {
|
|||
@Autowired
|
||||
private IZoneDetailService zoneDetailService;
|
||||
@Autowired
|
||||
private IZonePointsAccountService zonePointsAccountService;
|
||||
@Autowired
|
||||
private IZoneResourceService zoneResourceService;
|
||||
@Autowired
|
||||
private IZoneDataSetService zoneDataSetService;
|
||||
|
|
@ -214,6 +225,27 @@ public class OpenController extends BaseController {
|
|||
return genericsSuccess(zoneDetailService.getZoneStatistics(zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询专区置顶文章列表(含首页推荐文章,去重,置顶在前)
|
||||
*/
|
||||
@GetMapping("/getTopDoc/{zoneId}")
|
||||
@ApiOperation(value = "查询专区置顶文章列表(含首页推荐,去重)")
|
||||
public GenericsAjaxResult<List<ZonePointsTopDocVo>> getTopDoc(@PathVariable("zoneId") Long zoneId) {
|
||||
return genericsSuccess(zonePointsAccountService.selectHomePageDocMergeList(zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询专区置顶项目列表
|
||||
*/
|
||||
@GetMapping("/getTopProject/{zoneId}")
|
||||
@ApiOperation(value = "查询专区置顶项目列表")
|
||||
public GenericsAjaxResult<List<ZoneProjectDataVo>> getTopProject(@PathVariable("zoneId") Long zoneId) {
|
||||
if (!zoneDetailService.isPointsZone(zoneId)) {
|
||||
return genericsSuccess(Collections.emptyList());
|
||||
}
|
||||
return genericsSuccess(zoneProjectService.selectTopProjectList(zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询特色专区项目分类列表
|
||||
*/
|
||||
|
|
@ -248,6 +280,41 @@ public class OpenController extends BaseController {
|
|||
return getGenericsDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特色专区会员分类列表(含各分类下已审核会员数量)
|
||||
*/
|
||||
@GetMapping("/{zoneId}/memberType/list")
|
||||
@ApiOperation("获取特色专区会员分类列表(含已审核会员数量)")
|
||||
public GenericsTableDataInfo<ZoneMemberTypeCountVo> memberTypeList(
|
||||
@ApiParam(name = "zoneId", value = "专区Id", required = true) @PathVariable("zoneId") Long zoneId,
|
||||
@ApiParam(name = "name", value = "会员分类名称") String name) {
|
||||
List<ZoneMemberTypeCountVo> list = zoneMemberTypeService.selectZoneMemberTypeListWithCount(zoneId, name);
|
||||
return getGenericsDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特色专区会员列表(仅已审核会员,支持名称模糊搜索及分类/等级过滤)
|
||||
*/
|
||||
@GetMapping("/{zoneId}/member/list")
|
||||
@ApiOperation("获取特色专区会员列表")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "pageNum", value = "当前页码", paramType = "query", dataType = "Integer"),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页显示记录数(未传默认100)", paramType = "query", dataType = "Integer")
|
||||
})
|
||||
public GenericsTableDataInfo<ZoneMemberDataVo> memberList(
|
||||
@ApiParam(name = "zoneId", value = "专区Id", required = true) @PathVariable("zoneId") Long zoneId,
|
||||
ZoneMemberSearchVo zoneMemberSearchVo,
|
||||
@RequestParam(value = "pageNum", required = false) Integer pageNum,
|
||||
@RequestParam(value = "pageSize", required = false) Integer pageSize) {
|
||||
zoneMemberSearchVo.setZoneId(zoneId);
|
||||
if (pageNum == null || pageNum < 1) {
|
||||
pageNum = 1;
|
||||
}
|
||||
int effectivePageSize = (pageSize == null || pageSize < 1) ? 100 : pageSize;
|
||||
PageHelper.startPage(pageNum, effectivePageSize);
|
||||
return zoneMemberService.selectOpenZoneMemberList(zoneMemberSearchVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前用户是否有该专区的权限
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -56,4 +56,14 @@ public interface IZoneAsyncService {
|
|||
void clearZoneProjectSortByScoreCache(ZoneProject zoneProject);
|
||||
|
||||
List<JSONObject> getGitlinkProjectsDetail(List<String> gitLinkProjectIdList);
|
||||
|
||||
/**
|
||||
* 异步发放项目审核通过积分
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param createBy 项目创建人用户名
|
||||
* @param projectId 项目ID
|
||||
* @param projectName 项目名称
|
||||
*/
|
||||
void addPublishProjectPointsAsync(Long zoneId, String createBy, Long projectId, String projectName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.microservices.zone.common.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.constant.CacheConstants;
|
||||
|
|
@ -10,6 +11,7 @@ import com.microservices.common.core.utils.StringUtils;
|
|||
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
||||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.system.api.RemoteCmsService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
import com.microservices.zone.common.service.IZoneAsyncService;
|
||||
import com.microservices.zone.detail.domain.ZoneDetail;
|
||||
|
|
@ -60,6 +62,7 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
|
@ -77,6 +80,8 @@ public class ZoneAsyncServiceImpl implements IZoneAsyncService {
|
|||
@Autowired
|
||||
private RemoteCmsService remoteCmsService;
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
@Autowired
|
||||
@Lazy
|
||||
private IZoneProjectTypeService zoneProjectTypeService;
|
||||
@Autowired
|
||||
|
|
@ -139,6 +144,21 @@ public class ZoneAsyncServiceImpl implements IZoneAsyncService {
|
|||
|
||||
@Value("${zone.needCalcScoreZoneIds:}")
|
||||
private String needCalcScoreZoneIds;
|
||||
|
||||
@Value("${zone.pointsDeptId:0}")
|
||||
private Long pointsDeptId;
|
||||
|
||||
/**
|
||||
* 项目启动时,初始化积分部门ID到缓存
|
||||
*/
|
||||
@PostConstruct
|
||||
public void initPointsDeptId() {
|
||||
if (pointsDeptId != null && pointsDeptId > 0) {
|
||||
redisService.setCacheObject(CacheConstants.ZONE_POINTS_DEPT_ID_KEY, pointsDeptId);
|
||||
logger.info("积分部门ID初始化到缓存完成,pointsDeptId={}", pointsDeptId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建线程池
|
||||
* 初始化专区耗时长在初始化文章,经实验在文章初始化完成前其他步骤均已执行完成,故设核心线程数为2
|
||||
|
|
@ -150,11 +170,11 @@ public class ZoneAsyncServiceImpl implements IZoneAsyncService {
|
|||
* Nthreads =Ncpu*Ucpu*(1+W/C)
|
||||
*/
|
||||
static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
|
||||
2
|
||||
5
|
||||
, 10
|
||||
, 10
|
||||
, TimeUnit.SECONDS
|
||||
, new ArrayBlockingQueue<>(100)
|
||||
, new ArrayBlockingQueue<>(10000)
|
||||
, Executors.defaultThreadFactory()
|
||||
, (r, executor) -> {
|
||||
throw new ServiceException("【%s】目前创建的人太多了,请稍后再试", DateUtils.getNowDate());
|
||||
|
|
@ -465,11 +485,6 @@ public class ZoneAsyncServiceImpl implements IZoneAsyncService {
|
|||
List<ZoneProject> zoneProjectList = zoneProjectMapper.selectZoneProjectList(zoneProjectSearchVo);
|
||||
for (ZoneProject zoneProject : zoneProjectList) {
|
||||
setProjectGitlinkInfoCache(zoneProject);
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("初始化gitlink项目统计的定时任务延时被中断");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -521,23 +536,26 @@ public class ZoneAsyncServiceImpl implements IZoneAsyncService {
|
|||
|
||||
@Override
|
||||
public List<JSONObject> getGitlinkProjectsDetail(List<String> gitLinkProjectIdList) {
|
||||
int queryCount = gitLinkProjectIdList.size() / 50 + 1;
|
||||
int total = gitLinkProjectIdList.size();
|
||||
if (total == 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 向上取整分片:修复原 size/50+1 在整除时多出一个空分片(会发出一次 ids 为空的请求)
|
||||
int queryCount = (total + 49) / 50;
|
||||
CountDownLatch countDownLatch = new CountDownLatch(queryCount);
|
||||
List<JSONObject> gitLinkProjectList = new ArrayList<>();
|
||||
// 使用线程安全的 ConcurrentLinkedQueue 收集结果:修复原 ArrayList 在多线程并发 addAll 下丢数据/越界的隐患
|
||||
ConcurrentLinkedQueue<JSONObject> gitLinkProjectQueue = new ConcurrentLinkedQueue<>();
|
||||
for (int i = 0; i < queryCount; i++) {
|
||||
int finalI = i;
|
||||
threadPoolExecutor.execute(() -> {
|
||||
try {
|
||||
int pageMaxCount = (finalI + 1) * 50;
|
||||
if (pageMaxCount >= gitLinkProjectIdList.size()) {
|
||||
pageMaxCount = gitLinkProjectIdList.size();
|
||||
}
|
||||
int pageMaxCount = Math.min((finalI + 1) * 50, total);
|
||||
List<String> tmpIdList = gitLinkProjectIdList.subList(finalI * 50, pageMaxCount);
|
||||
JSONObject result = gitLinkRequestHelper.doGet(
|
||||
ZoneGitLinkRequestUrl.PROJECTS("?ids=" + String.join(ZoneConstants.ARRAY_SPLIT_SYMBOLS, tmpIdList))
|
||||
);
|
||||
|
||||
gitLinkProjectList.addAll(result.getList(ZoneConstants.GITLINK_RESPONSE_PROJECTS_KEY, JSONObject.class));
|
||||
gitLinkProjectQueue.addAll(result.getList(ZoneConstants.GITLINK_RESPONSE_PROJECTS_KEY, JSONObject.class));
|
||||
} catch (Exception e) {
|
||||
logger.error("异步批量获取项目详细信息失败:{}", e.getMessage());
|
||||
} finally {
|
||||
|
|
@ -551,7 +569,7 @@ public class ZoneAsyncServiceImpl implements IZoneAsyncService {
|
|||
logger.error("根据gitlinkProjectId调用Gitlink接口批量获取项目详细信息失败:{}", e.getMessage());
|
||||
throw new ServiceException("获取平台项目详细信息失败");
|
||||
}
|
||||
return gitLinkProjectList;
|
||||
return new ArrayList<>(gitLinkProjectQueue);
|
||||
}
|
||||
|
||||
private Double calcProjectScore(ZoneProject zoneProject, String startDate, String endDate) {
|
||||
|
|
@ -569,4 +587,35 @@ public class ZoneAsyncServiceImpl implements IZoneAsyncService {
|
|||
return theWeekScore;
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void addPublishProjectPointsAsync(Long zoneId, String createBy, Long projectId, String projectName) {
|
||||
try {
|
||||
if (zoneId == null || createBy == null) {
|
||||
logger.warn("项目审核通过增加积分失败,zoneId或createBy为空,projectId={}", projectId);
|
||||
return;
|
||||
}
|
||||
// 获取用户ID
|
||||
com.microservices.system.api.domain.SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(createBy, SecurityConstants.INNER));
|
||||
if (sysUser == null || sysUser.getUserId() == null) {
|
||||
logger.warn("项目审核通过增加积分失败,未找到用户信息,createBy={},projectId={}", createBy, projectId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 写入 Redis 积分队列
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", ZoneConstants.PublishProject.SOURCE_TYPE);
|
||||
task.put("userId", sysUser.getUserId());
|
||||
task.put("zoneId", zoneId);
|
||||
task.put("sourceId", projectId);
|
||||
task.put("subjectDesc", projectName);
|
||||
task.put("operatorId", sysUser.getUserId());
|
||||
redisService.leftPush(ZoneConstants.ZONE_POINTS_ASYNC_QUEUE_KEY, JSON.toJSONString(task));
|
||||
logger.info("项目审核通过增加积分任务已提交 userId={} projectId={} projectName={}", sysUser.getUserId(), projectId, projectName);
|
||||
} catch (Exception e) {
|
||||
logger.error("项目审核通过增加积分任务提交失败 projectId={} error={}", projectId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,6 +186,12 @@ public class ZoneDetailDataVo extends BaseEntity {
|
|||
@ApiModelProperty(value = "会员板块是否展示(0:不展示,1:展示)")
|
||||
private Integer sectionMemberShow;
|
||||
|
||||
/**
|
||||
* 积分板块是否展示(0:不展示,1:展示)
|
||||
*/
|
||||
@ApiModelProperty(value = "积分板块是否展示(0:不展示,1:展示)")
|
||||
private Integer sectionPointsShow;
|
||||
|
||||
/**
|
||||
* 帮助中心板块是否展示(0:不展示,1:展示)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ public interface IZoneDetailService {
|
|||
|
||||
ZoneFrontRoleVo checkCurrentRoleInZone(Long zoneId);
|
||||
|
||||
ZoneFrontRoleVo checkUserRoleInZone(Long zoneId, Long userId);
|
||||
/**
|
||||
* 通过组织id锁定/解锁专区资讯
|
||||
*
|
||||
|
|
@ -235,4 +236,20 @@ public interface IZoneDetailService {
|
|||
ZoneDetail selectZoneDetailByIdNotVerifiedDataScope(Long zoneId);
|
||||
|
||||
ZoneStatisticsVo getZoneStatistics(Long zoneId);
|
||||
|
||||
/**
|
||||
* 计算专区统计数据(内部方法,用于定时任务调用)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 统计数据
|
||||
*/
|
||||
ZoneStatisticsVo calculateZoneStatistics(Long zoneId);
|
||||
|
||||
/**
|
||||
* 判断专区是否为积分专区
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return true=是积分专区,false=不是积分专区
|
||||
*/
|
||||
boolean isPointsZone(Long zoneId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.microservices.system.api.RemoteDeptService;
|
|||
import com.microservices.system.api.RemoteUserService;
|
||||
import com.microservices.system.api.domain.SysDept;
|
||||
import com.microservices.system.api.domain.SysDictData;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
import com.microservices.system.api.domain.SysUserDeptRole;
|
||||
import com.microservices.system.api.model.LoginUser;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
|
|
@ -32,10 +33,14 @@ import com.microservices.zone.detail.domain.vo.*;
|
|||
import com.microservices.zone.detail.mapper.ZoneDetailMapper;
|
||||
import com.microservices.zone.detail.service.IZoneDetailService;
|
||||
import com.microservices.zone.member.domain.ZoneMember;
|
||||
import com.microservices.zone.member.domain.ZoneMemberLevel;
|
||||
import com.microservices.zone.member.domain.ZoneMemberType;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberInputVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberSearchVo;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberLevelMapper;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberMapper;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberTypeMapper;
|
||||
import com.microservices.zone.member.service.IZoneMemberService;
|
||||
import com.microservices.zone.partners.mapper.ZonePartnersMapper;
|
||||
import com.microservices.zone.partners.mapper.ZonePartnersTypeMapper;
|
||||
import com.microservices.zone.project.domain.ZoneProject;
|
||||
|
|
@ -51,6 +56,7 @@ import com.microservices.zone.resource.mapper.ZoneResourceTypeMapper;
|
|||
import com.microservices.zone.specialProject.domain.ZoneSpecialProject;
|
||||
import com.microservices.zone.specialProject.service.IZoneSpecialProjectService;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
|
@ -62,6 +68,7 @@ import java.time.LocalDate;
|
|||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -71,6 +78,7 @@ import java.util.stream.Collectors;
|
|||
* @date 2023-05-09
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ZoneDetailServiceImpl implements IZoneDetailService {
|
||||
@Autowired
|
||||
private ZoneDetailMapper zoneDetailMapper;
|
||||
|
|
@ -107,6 +115,10 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
@Autowired
|
||||
@Lazy
|
||||
private IZoneSpecialProjectService zoneSpecialProjectService;
|
||||
@Autowired
|
||||
@Lazy
|
||||
private IZoneMemberService zoneMemberService;
|
||||
|
||||
@Value("${zone.zoneAdminUrl}")
|
||||
private String zoneAdminUrl;
|
||||
@Value("${zone.zoneConfigurationPath:/zone/configuration}")
|
||||
|
|
@ -119,6 +131,16 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
private String docManagePath;
|
||||
@Value("${zone.projectManagePath:/zone/project/list}")
|
||||
private String projectManagePath;
|
||||
@Value("${zone.resourceManageUrl}")
|
||||
private String resourceManageUrl;
|
||||
@Value("${zone.docManageUrl}")
|
||||
private String docManageUrl;
|
||||
@Value("${zone.autoMemberZoneIds:}")
|
||||
private String autoMemberZoneIds;
|
||||
@Value("${zone.autoMemberTypeName:}")
|
||||
private String autoMemberTypeName;
|
||||
@Value("${zone.autoMemberLevelName:}")
|
||||
private String autoMemberLevelName;
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
|
|
@ -205,13 +227,13 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
Date[] lastWeek = getLastWeek();
|
||||
//专区文章数统计
|
||||
ZoneDetailDataVo articlesGroupByKey = zoneDetailMapper
|
||||
.countArticlesGroupByKey(lastWeek[0], lastWeek[1], zoneDetail.getKey());
|
||||
.countArticlesGroupByKey(lastWeek[0],lastWeek[1],zoneDetail.getKey()) ;
|
||||
if (articlesGroupByKey != null) {
|
||||
zoneDetailDataVo.setWeekArticles(articlesGroupByKey.getWeekArticles());
|
||||
}
|
||||
//专区浏览数据统计
|
||||
ZoneDetailDataVo puVsGroupByKey = zoneDetailMapper
|
||||
.countPUVsGroupByKey(lastWeek[0], lastWeek[1], zoneDetail.getKey());
|
||||
.countPUVsGroupByKey(lastWeek[0],lastWeek[1],zoneDetail.getKey()) ;
|
||||
if (puVsGroupByKey != null) {
|
||||
zoneDetailDataVo.setWeekPV(puVsGroupByKey.getWeekPV());
|
||||
zoneDetailDataVo.setWeekUV(puVsGroupByKey.getWeekUV());
|
||||
|
|
@ -611,9 +633,16 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
if (zoneDetail == null) {
|
||||
throw new ServiceException(HttpStatus.NOT_FOUND, "该特色专区不存在或无权限访问(专区标识[" + zoneKey + "])");
|
||||
}
|
||||
// zoneTemplateCheck(template,zoneDetailDataVo);
|
||||
return getZoneDetailDataVoAndCmsProject(zoneDetail);
|
||||
|
||||
ZoneDetailDataVo zoneDetailDataVo = getZoneDetailDataVoAndCmsProject(zoneDetail);
|
||||
// 判断当前zone的deptId是否为redis中对应的ZONE_POINTS_DEPT_ID_KEY
|
||||
Long cachedPointsDeptId = redisService.getCacheObject(CacheConstants.ZONE_POINTS_DEPT_ID_KEY);
|
||||
if (zoneDetail.getDeptId() != null && cachedPointsDeptId != null
|
||||
&& zoneDetail.getDeptId().equals(cachedPointsDeptId)) {
|
||||
zoneDetailDataVo.setSectionPointsShow(1);
|
||||
} else {
|
||||
zoneDetailDataVo.setSectionPointsShow(0);
|
||||
}
|
||||
return zoneDetailDataVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -643,11 +672,62 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
return JSON.toJSONString(zoneDetail);
|
||||
}
|
||||
|
||||
private ZoneMemberInputVo newZoneMemberInputVo(Long zoneId, SysUser sysUser) {
|
||||
if (sysUser.getGitlinkUserId() == null) {
|
||||
return null;
|
||||
}
|
||||
ZoneMemberInputVo zoneMemberInputVo = new ZoneMemberInputVo();
|
||||
zoneMemberInputVo.setGitLinkUserId(sysUser.getGitlinkUserId());
|
||||
zoneMemberInputVo.setName(sysUser.getNickName());
|
||||
zoneMemberInputVo.setImageUrl(sysUser.getAvatar());
|
||||
ZoneMemberType zoneMemberTypeSearch = new ZoneMemberType();
|
||||
zoneMemberTypeSearch.setZoneId(zoneId);
|
||||
List<ZoneMemberType> zoneMemberTypes = zoneMemberTypeMapper.selectZoneMemberTypeList(zoneMemberTypeSearch);
|
||||
if (zoneMemberTypes == null || zoneMemberTypes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Long zoneMemberTypeId = zoneMemberTypes.get(0).getId();
|
||||
if (StringUtils.isNotEmpty(autoMemberTypeName)) {
|
||||
zoneMemberTypeId = zoneMemberTypes.stream().filter(x -> autoMemberTypeName.equals(x.getName())).map(ZoneMemberType::getId).findFirst().orElse(zoneMemberTypeId);
|
||||
}
|
||||
zoneMemberInputVo.setMemberTypeId(zoneMemberTypeId);
|
||||
ZoneMemberLevel zoneMemberLevelSearch = new ZoneMemberLevel();
|
||||
zoneMemberLevelSearch.setZoneId(zoneId);
|
||||
List<ZoneMemberLevel> zoneMemberLevels = zoneMemberLevelMapper.selectZoneMemberLevelList(zoneMemberLevelSearch);
|
||||
if (zoneMemberLevels == null || zoneMemberLevels.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Long zoneMemberLevelId = zoneMemberLevels.get(0).getId();
|
||||
if (StringUtils.isNotEmpty(autoMemberLevelName)) {
|
||||
zoneMemberLevelId = zoneMemberLevels.stream().filter(x -> autoMemberLevelName.equals(x.getName())).map(ZoneMemberLevel::getId).findFirst().orElse(zoneMemberLevelId);
|
||||
}
|
||||
zoneMemberInputVo.setMemberLevelId(zoneMemberLevelId);
|
||||
zoneMemberInputVo.setIsSendInvitation(false);
|
||||
zoneMemberInputVo.setZoneId(zoneId);
|
||||
return zoneMemberInputVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZoneFrontRoleVo checkCurrentRoleInZone(Long zoneId) {
|
||||
ZoneFrontRoleVo zoneFrontRoleVo = new ZoneFrontRoleVo();
|
||||
ZoneDetail zoneDetail = selectZoneDetailById(zoneId);
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
// 当前专区为指定专区时,用户将自动成为专区会员
|
||||
if (StringUtils.isNotEmpty(autoMemberZoneIds)) {
|
||||
String[] idArr = autoMemberZoneIds.split(",");
|
||||
for (String s : idArr) {
|
||||
if (s.equals(String.valueOf(zoneId))) {
|
||||
ZoneMember zoneMember = zoneMemberMapper.selectZoneMemberByZoneIdAndUserId(zoneId, loginUser.getUserId());
|
||||
if (zoneMember == null) {
|
||||
ZoneMemberInputVo zoneMemberInputVo = newZoneMemberInputVo(zoneId, loginUser.getSysUser());
|
||||
if (zoneMemberInputVo == null) {
|
||||
break;
|
||||
}
|
||||
zoneMemberService.insertZoneMember(zoneMemberInputVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SysDept sysDept = FeignUtils.getReturnData(remoteDeptService.getDeptByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER));
|
||||
List<SysUserDeptRole> userIdentifyList = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserDeptRoleListByUserName(loginUser.getUsername(), SecurityConstants.INNER)
|
||||
|
|
@ -700,6 +780,70 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
return zoneFrontRoleVo;
|
||||
}
|
||||
|
||||
public ZoneFrontRoleVo checkUserRoleInZone(Long zoneId, Long userId) {
|
||||
ZoneFrontRoleVo zoneFrontRoleVo = new ZoneFrontRoleVo();
|
||||
ZoneDetail zoneDetail = selectZoneDetailById(zoneId);
|
||||
|
||||
SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserId(userId, SecurityConstants.INNER)
|
||||
);
|
||||
if (sysUser == null) {
|
||||
zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_NONE);
|
||||
return zoneFrontRoleVo;
|
||||
}
|
||||
|
||||
SysDept sysDept = FeignUtils.getReturnData(remoteDeptService.getDeptByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER));
|
||||
List<SysUserDeptRole> userIdentifyList = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserDeptRoleListByUserName(sysUser.getUserName(), SecurityConstants.INNER)
|
||||
);
|
||||
if (sysDept == null || userIdentifyList == null) {
|
||||
zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_NONE);
|
||||
return zoneFrontRoleVo;
|
||||
} else {
|
||||
List<String> deptIdList = Arrays.asList(sysDept.getAncestors().split(","));
|
||||
SysUserDeptRole parentDeptUserIdentify = userIdentifyList
|
||||
.stream()
|
||||
.filter(x -> deptIdList.contains(String.valueOf(x.getDeptId())))
|
||||
.filter(x -> !x.getSysRole().getRoleKey().equals(SystemRole.ZONE_MEMBER.getRoleKey()))
|
||||
.findFirst().orElse(null);
|
||||
SysUserDeptRole currentUserIdentify = userIdentifyList.stream().filter(x -> x.getDeptId().equals(zoneDetail.getDeptId())).findFirst().orElse(null);
|
||||
String resourceManageUrl = adminUrl + resourceManagePath + "?changeCurrentUserIdentity=";
|
||||
String docManageUrl = adminUrl + docManagePath + "?changeCurrentUserIdentity=";
|
||||
String projectManageUrl = adminUrl + projectManagePath + "?changeCurrentUserIdentity=";
|
||||
if (currentUserIdentify != null) {
|
||||
if (currentUserIdentify.getSysRole().getRoleKey().equals(SystemRole.ZONE_MEMBER.getRoleKey())) {
|
||||
if (parentDeptUserIdentify != null) {
|
||||
zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_MANAGER);
|
||||
zoneFrontRoleVo.setResourceManageUrl(resourceManageUrl + parentDeptUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setDocManageUrl(docManageUrl + parentDeptUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setProjectManageUrl(projectManageUrl + parentDeptUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setDeptId(parentDeptUserIdentify.getDeptId());
|
||||
} else {
|
||||
zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_MEMBER);
|
||||
zoneFrontRoleVo.setDeptId(currentUserIdentify.getDeptId());
|
||||
}
|
||||
} else {
|
||||
zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_MANAGER);
|
||||
zoneFrontRoleVo.setResourceManageUrl(resourceManageUrl + currentUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setDocManageUrl(docManageUrl + currentUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setProjectManageUrl(projectManageUrl + currentUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setDeptId(currentUserIdentify.getDeptId());
|
||||
}
|
||||
return zoneFrontRoleVo;
|
||||
} else if (parentDeptUserIdentify != null) {
|
||||
zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_MANAGER);
|
||||
zoneFrontRoleVo.setResourceManageUrl(resourceManageUrl + parentDeptUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setDocManageUrl(docManageUrl + parentDeptUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setProjectManageUrl(projectManageUrl + parentDeptUserIdentify.getDeptId());
|
||||
zoneFrontRoleVo.setDeptId(parentDeptUserIdentify.getDeptId());
|
||||
return zoneFrontRoleVo;
|
||||
}
|
||||
}
|
||||
|
||||
zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_NONE);
|
||||
return zoneFrontRoleVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lockCmsByDeptId(Long deptId, Integer lockStatus) {
|
||||
ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByDeptId(deptId);
|
||||
|
|
@ -776,7 +920,7 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ZoneStatisticsVo getZoneStatistics(Long zoneId) {
|
||||
public ZoneStatisticsVo calculateZoneStatistics(Long zoneId) {
|
||||
ZoneStatisticsVo zoneStatisticsVo = new ZoneStatisticsVo();
|
||||
|
||||
ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailById(zoneId);
|
||||
|
|
@ -841,6 +985,45 @@ public class ZoneDetailServiceImpl implements IZoneDetailService {
|
|||
return zoneStatisticsVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZoneStatisticsVo getZoneStatistics(Long zoneId) {
|
||||
String cacheKey = CacheConstants.getZoneStatisticsKey(zoneId);
|
||||
|
||||
try {
|
||||
// 1. 尝试从Redis缓存获取
|
||||
ZoneStatisticsVo cachedStatistics = redisService.getCacheObject(cacheKey);
|
||||
if (cachedStatistics != null) {
|
||||
log.debug("专区[{}]统计数据来自缓存", zoneId);
|
||||
return cachedStatistics;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("专区[{}]统计数据缓存读取失败,执行降级逻辑", zoneId, e);
|
||||
}
|
||||
|
||||
// 2. 缓存异常或未命中,执行实时计算
|
||||
log.info("专区[{}]统计数据缓存未命中,执行实时计算", zoneId);
|
||||
ZoneStatisticsVo statistics = calculateZoneStatistics(zoneId);
|
||||
|
||||
// 3. 尝试缓存计算结果(失败不影响主流程)
|
||||
try {
|
||||
redisService.setCacheObject(cacheKey, statistics, 7200L, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
log.warn("专区[{}]统计数据缓存写入失败", zoneId, e);
|
||||
}
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPointsZone(Long zoneId) {
|
||||
ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailById(zoneId);
|
||||
if (zoneDetail == null || zoneDetail.getDeptId() == null) {
|
||||
return false;
|
||||
}
|
||||
Long cachedPointsDeptId = redisService.getCacheObject(CacheConstants.ZONE_POINTS_DEPT_ID_KEY);
|
||||
return cachedPointsDeptId != null && zoneDetail.getDeptId().equals(cachedPointsDeptId);
|
||||
}
|
||||
|
||||
public Date[] getLastWeek() {
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate startOfWeek = today.with(java.time.DayOfWeek.MONDAY).minusDays(7);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,16 @@ public class ZoneMemberController extends BaseController {
|
|||
return AjaxResult.success("审核状态获取成功",auditStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前登录用户会员审核状态
|
||||
*/
|
||||
@GetMapping("/zone/{zoneId}/memberInfo")
|
||||
@ApiOperation("查询当前登录用户会员信息")
|
||||
public AjaxResult getMemberInfo(@PathVariable("zoneId") Long zoneId) {
|
||||
ZoneMember memberInfo = zoneMemberService.selectZoneMemberInfo(zoneId);
|
||||
return AjaxResult.success("审核状态获取成功",memberInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询GitLink用户列表
|
||||
*/
|
||||
|
|
@ -108,6 +118,16 @@ public class ZoneMemberController extends BaseController {
|
|||
return genericsSuccess(zoneMemberService.selectZoneMemberById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据专区ID修改当前登录用户会员信息
|
||||
*/
|
||||
@PutMapping(value = "/customEdit/zone/{zoneId}")
|
||||
@ApiOperation("根据专区ID修改当前登录用户会员信息")
|
||||
@Log(title = "特色专区会员", businessType = BusinessType.UPDATE)
|
||||
public AjaxResult customEdit(@PathVariable("zoneId") Long zoneId, @RequestBody ZoneMemberUpdateVo zoneMemberUpdateVo) {
|
||||
return toAjax(zoneMemberService.updateZoneMemberByMember(zoneId, zoneMemberUpdateVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并获取组织下的会员列表
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
package com.microservices.zone.member.controller;
|
||||
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.common.log.annotation.Log;
|
||||
import com.microservices.common.log.enums.BusinessType;
|
||||
import com.microservices.common.security.annotation.RequiresPermissions;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.domain.vo.*;
|
||||
import com.microservices.zone.member.service.IZonePointsAccountService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 专区积分账户Controller
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/points/account")
|
||||
@Api(tags = "专区积分账户接口")
|
||||
public class ZonePointsAccountController extends BaseController {
|
||||
@Autowired
|
||||
private IZonePointsAccountService zonePointsAccountService;
|
||||
|
||||
/**
|
||||
* 查询专区积分账户列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:list")
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("查询专区积分账户列表")
|
||||
public GenericsTableDataInfo<ZonePointsAccount> list(ZonePointsAccountSearchVo searchVo) {
|
||||
startPage();
|
||||
List<ZonePointsAccount> list = zonePointsAccountService.selectZonePointsAccountList(searchVo.toZonePointsAccount());
|
||||
return getGenericsDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取专区积分账户详细信息
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:query")
|
||||
@GetMapping(value = "/{id}")
|
||||
@ApiOperation(value = "获取专区积分账户详细信息")
|
||||
public GenericsAjaxResult<ZonePointsAccount> getInfo(@PathVariable("id") Long id) {
|
||||
return genericsSuccess(zonePointsAccountService.selectZonePointsAccountById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增专区积分账户
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:add")
|
||||
@Log(title = "专区积分账户", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
@ApiOperation(value = "新增专区积分账户")
|
||||
public AjaxResult add(@RequestBody ZonePointsAccountInputVo inputVo) {
|
||||
return toAjax(zonePointsAccountService.insertZonePointsAccount(inputVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改专区积分账户
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:edit")
|
||||
@Log(title = "专区积分账户", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
@ApiOperation(value = "修改专区积分账户")
|
||||
public AjaxResult edit(@RequestBody ZonePointsAccountUpdateVo updateVo) {
|
||||
return toAjax(zonePointsAccountService.updateZonePointsAccount(updateVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除专区积分账户
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:remove")
|
||||
@Log(title = "专区积分账户", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
@ApiOperation(value = "删除专区积分账户")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(zonePointsAccountService.deleteZonePointsAccountByIds(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询积分账户
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:query")
|
||||
@GetMapping("/user/{userId}/zone/{zoneId}")
|
||||
@ApiOperation(value = "根据用户ID和专区ID查询积分账户")
|
||||
public GenericsAjaxResult<ZonePointsAccount> getByUserIdAndZoneId(@PathVariable("userId") Long userId,
|
||||
@PathVariable("zoneId") Long zoneId) {
|
||||
return genericsSuccess(zonePointsAccountService.selectZonePointsAccountByUserIdAndZoneId(userId, zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据会员ID查询积分账户列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:query")
|
||||
@GetMapping("/member/{memberId}")
|
||||
@ApiOperation(value = "根据会员ID查询积分账户列表")
|
||||
public GenericsAjaxResult<List<ZonePointsAccount>> getByMemberId(@PathVariable("memberId") Long memberId) {
|
||||
return genericsSuccess(zonePointsAccountService.selectZonePointsAccountByMemberId(memberId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的积分账户总览信息
|
||||
*/
|
||||
@GetMapping("/overview/{zoneId}")
|
||||
@ApiOperation(value = "获取当前登录用户的积分账户总览信息")
|
||||
public GenericsAjaxResult<ZonePointsOverviewVo> getCurrentUserPointsOverview(@PathVariable("zoneId") Long zoneId) {
|
||||
return genericsSuccess(zonePointsAccountService.getCurrentUserPointsOverview(zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 电子证书积分扣减(前台用户操作,业务层已做会员身份+积分专区+幂等+积分校验)
|
||||
*/
|
||||
@PostMapping("/certificate/redeem")
|
||||
@ApiOperation(value = "电子证书积分扣减")
|
||||
public AjaxResult redeemCertificate(@RequestBody ZonePointsTransactionInputVo inputVo) {
|
||||
zonePointsAccountService.deductPointsForCertificate(inputVo);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章置顶积分扣减(前台用户操作,业务层已做会员身份+积分专区+积分校验)
|
||||
* 用户使用当前登录用户
|
||||
*/
|
||||
@PostMapping("/article/top")
|
||||
@ApiOperation(value = "文章置顶积分扣减")
|
||||
public AjaxResult topArticle(@RequestBody ZonePointsArticleTopInputVo inputVo) {
|
||||
zonePointsAccountService.deductPointsForArticleTop(inputVo.getZoneId(), inputVo.getId(), inputVo.getName());
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的置顶文章信息
|
||||
*/
|
||||
@GetMapping("/article/top/{zoneId}")
|
||||
@ApiOperation(value = "获取当前登录用户的置顶文章信息")
|
||||
public GenericsAjaxResult<ZonePointsTopDocVo> getCurrentUserPointsTopDoc(@PathVariable("zoneId") Long zoneId) {
|
||||
return genericsSuccess(zonePointsAccountService.getCurrentUserPointsTopDoc(zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的置顶项目信息
|
||||
*/
|
||||
@GetMapping("/project/top/{zoneId}")
|
||||
@ApiOperation(value = "获取当前登录用户的置顶项目信息")
|
||||
public GenericsAjaxResult<ZonePointsTopProjectVo> getZonePointsTopProject(@PathVariable("zoneId") Long zoneId) {
|
||||
return genericsSuccess(zonePointsAccountService.getZonePointsTopProject(zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目置顶积分扣减(前台用户操作,业务层已做会员身份+积分专区+积分校验)
|
||||
* 用户使用当前登录用户
|
||||
*/
|
||||
@PostMapping("/project/top")
|
||||
@ApiOperation(value = "项目置顶积分扣减")
|
||||
public AjaxResult topProject(@RequestBody ZonePointsProjectTopInputVo inputVo) {
|
||||
zonePointsAccountService.deductPointsForProjectTop(inputVo.getZoneId(), inputVo.getId(), inputVo.getName());
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 线下活动积分冻结(前台用户操作,业务层已做会员身份+积分专区+幂等+积分校验)
|
||||
*/
|
||||
@PostMapping("/offlineActivity/freeze")
|
||||
@ApiOperation(value = "线下活动积分冻结")
|
||||
public AjaxResult freezePointsForOfflineActivity(@RequestBody ZonePointsApplyInputVo inputVo) {
|
||||
zonePointsAccountService.freezePointsForOfflineActivity(inputVo);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 专家答疑积分冻结(前台用户操作,业务层已做会员身份+积分专区+幂等+积分校验)
|
||||
*/
|
||||
@PostMapping("/expert/qa/freeze")
|
||||
@ApiOperation(value = "专家答疑积分冻结")
|
||||
public AjaxResult freezePointsForExpertQa(@RequestBody ZonePointsApplyInputVo inputVo) {
|
||||
zonePointsAccountService.freezePointsForExpertQa(inputVo);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回积分申请(管理员操作)
|
||||
* 查询对应申请记录(pending状态),更新状态为fail,
|
||||
* 同时更新pointsEvent的subject括号内容为"已退回"、replyContent为驳回原因,
|
||||
* 并触发积分解冻操作
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:reject")
|
||||
@Log(title = "驳回积分申请", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/apply/reject")
|
||||
@ApiOperation(value = "驳回积分申请")
|
||||
public AjaxResult rejectPointsApply(@RequestBody ZonePointsApplyInputVo inputVo) {
|
||||
zonePointsAccountService.rejectPointsApply(inputVo);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过积分申请(管理员操作)
|
||||
* 查询对应申请记录(pending状态),更新状态为success,
|
||||
* 同时更新pointsEvent的subject去除原括号内容,
|
||||
* 并从冻结积分中正式扣减积分(含总积分扣减)
|
||||
*/
|
||||
@RequiresPermissions("zone:points:account:approve")
|
||||
@Log(title = "通过积分申请", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/apply/approve")
|
||||
@ApiOperation(value = "通过积分申请")
|
||||
public AjaxResult approvePointsApply(@RequestBody ZonePointsApplyInputVo inputVo) {
|
||||
zonePointsAccountService.approvePointsApply(inputVo);
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.microservices.zone.member.controller;
|
||||
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.common.log.annotation.Log;
|
||||
import com.microservices.common.log.enums.BusinessType;
|
||||
import com.microservices.common.security.annotation.RequiresPermissions;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyDetailVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyInputVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplySearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyUpdateVo;
|
||||
import com.microservices.zone.member.service.IZonePointsApplyService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 积分申请表Controller
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/points/apply")
|
||||
@Api(tags = "积分申请表接口")
|
||||
public class ZonePointsApplyController extends BaseController {
|
||||
@Autowired
|
||||
private IZonePointsApplyService zonePointsApplyService;
|
||||
|
||||
/**
|
||||
* 查询积分申请列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:apply:list")
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("查询积分申请列表")
|
||||
public GenericsTableDataInfo<ZonePointsApplyDetailVo> list(ZonePointsApplySearchVo searchVo) {
|
||||
startPage();
|
||||
return zonePointsApplyService.selectZonePointsApplyList(searchVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的积分申请列表
|
||||
*/
|
||||
@GetMapping("/my/list")
|
||||
@ApiOperation("查询我的积分申请列表")
|
||||
public GenericsTableDataInfo<ZonePointsApplyDetailVo> myList(ZonePointsApplySearchVo searchVo) {
|
||||
startPage();
|
||||
searchVo.setUserId(SecurityUtils.getUserId());
|
||||
return zonePointsApplyService.selectZonePointsApplyList(searchVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积分申请详细信息
|
||||
*/
|
||||
@RequiresPermissions("zone:points:apply:query")
|
||||
@GetMapping(value = "/{id}")
|
||||
@ApiOperation(value = "获取积分申请详细信息")
|
||||
public GenericsAjaxResult<ZonePointsApply> getInfo(@PathVariable("id") Long id) {
|
||||
return genericsSuccess(zonePointsApplyService.selectZonePointsApplyById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增积分申请
|
||||
*/
|
||||
@RequiresPermissions("zone:points:apply:add")
|
||||
@Log(title = "积分申请", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
@ApiOperation(value = "新增积分申请")
|
||||
public AjaxResult add(@RequestBody ZonePointsApplyInputVo inputVo) {
|
||||
return toAjax(zonePointsApplyService.insertZonePointsApply(inputVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改积分申请
|
||||
*/
|
||||
@RequiresPermissions("zone:points:apply:edit")
|
||||
@Log(title = "积分申请", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
@ApiOperation(value = "修改积分申请")
|
||||
public AjaxResult edit(@RequestBody ZonePointsApplyUpdateVo updateVo) {
|
||||
return toAjax(zonePointsApplyService.updateZonePointsApply(updateVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除积分申请
|
||||
*/
|
||||
@RequiresPermissions("zone:points:apply:remove")
|
||||
@Log(title = "积分申请", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
@ApiOperation(value = "删除积分申请")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(zonePointsApplyService.deleteZonePointsApplyByIds(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询积分申请列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:apply:query")
|
||||
@GetMapping("/user/{userId}/zone/{zoneId}")
|
||||
@ApiOperation(value = "根据用户ID和专区ID查询积分申请列表")
|
||||
public GenericsAjaxResult<List<ZonePointsApply>> getByUserIdAndZoneId(@PathVariable("userId") Long userId,
|
||||
@PathVariable("zoneId") Long zoneId) {
|
||||
return genericsSuccess(zonePointsApplyService.selectZonePointsApplyByUserIdAndZoneId(userId, zoneId));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package com.microservices.zone.member.controller;
|
||||
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.common.log.annotation.Log;
|
||||
import com.microservices.common.log.enums.BusinessType;
|
||||
import com.microservices.common.security.annotation.RequiresPermissions;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionInputVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionSearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionUpdateVo;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.zone.member.service.IZonePointsTransactionService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 专区积分流水Controller
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/points/transaction")
|
||||
@Api(tags = "专区积分流水接口")
|
||||
public class ZonePointsTransactionController extends BaseController {
|
||||
@Autowired
|
||||
private IZonePointsTransactionService zonePointsTransactionService;
|
||||
|
||||
/**
|
||||
* 查询专区积分流水列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:transaction:list")
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("查询专区积分流水列表")
|
||||
public GenericsTableDataInfo<ZonePointsTransaction> list(ZonePointsTransactionSearchVo searchVo) {
|
||||
startPage();
|
||||
List<ZonePointsTransaction> list = zonePointsTransactionService.selectZonePointsTransactionList(searchVo.toZonePointsTransaction());
|
||||
return getGenericsDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取专区积分流水详细信息
|
||||
*/
|
||||
@RequiresPermissions("zone:points:transaction:query")
|
||||
@GetMapping(value = "/{id}")
|
||||
@ApiOperation(value = "获取专区积分流水详细信息")
|
||||
public GenericsAjaxResult<ZonePointsTransaction> getInfo(@PathVariable("id") Long id) {
|
||||
return genericsSuccess(zonePointsTransactionService.selectZonePointsTransactionById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据事件ID查询流水列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:transaction:query")
|
||||
@GetMapping("/event/{eventId}")
|
||||
@ApiOperation(value = "根据事件ID查询流水列表")
|
||||
public GenericsAjaxResult<List<ZonePointsTransaction>> getByEventId(@PathVariable("eventId") String eventId) {
|
||||
return genericsSuccess(zonePointsTransactionService.selectZonePointsTransactionByEventId(eventId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据账户ID查询流水列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:transaction:query")
|
||||
@GetMapping("/account/{accountId}")
|
||||
@ApiOperation(value = "根据账户ID查询流水列表")
|
||||
public GenericsAjaxResult<List<ZonePointsTransaction>> getByAccountId(@PathVariable("accountId") Long accountId) {
|
||||
return genericsSuccess(zonePointsTransactionService.selectZonePointsTransactionByAccountId(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询流水列表
|
||||
*/
|
||||
@RequiresPermissions("zone:points:transaction:query")
|
||||
@GetMapping("/user/{userId}/zone/{zoneId}")
|
||||
@ApiOperation(value = "根据用户ID和专区ID查询流水列表")
|
||||
public GenericsAjaxResult<List<ZonePointsTransaction>> getByUserIdAndZoneId(@PathVariable("userId") Long userId,
|
||||
@PathVariable("zoneId") Long zoneId) {
|
||||
return genericsSuccess(zonePointsTransactionService.selectZonePointsTransactionByUserIdAndZoneId(userId, zoneId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据专区ID获取当前用户积分明细(分页)
|
||||
*/
|
||||
@GetMapping("/my/{zoneId}")
|
||||
@ApiOperation(value = "根据专区ID获取当前用户积分明细(分页)")
|
||||
public GenericsTableDataInfo<ZonePointsTransaction> getMyPointsDetailsByZone(@PathVariable("zoneId") Long zoneId,
|
||||
ZonePointsTransactionSearchVo searchVo) {
|
||||
startPage();
|
||||
List<ZonePointsTransaction> list = zonePointsTransactionService.selectMyPointsTransactionDetailsByZone(zoneId, SecurityUtils.getUserId(), searchVo.getTransactionType());
|
||||
return getGenericsDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询当前登录用户流水列表(合并后所有业务字段已包含在流水中)
|
||||
*/
|
||||
@GetMapping("/currentUser/{zoneId}")
|
||||
@ApiOperation(value = "分页查询当前登录用户流水列表")
|
||||
public GenericsTableDataInfo<ZonePointsTransaction> getCurrentUserTransactionList(@PathVariable("zoneId") Long zoneId) {
|
||||
startPage();
|
||||
List<ZonePointsTransaction> list = zonePointsTransactionService.selectCurrentUserTransactionWithEvent(SecurityUtils.getUserId(), zoneId);
|
||||
return getGenericsDataTable(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,10 +5,14 @@ import com.microservices.common.core.annotation.Excel;
|
|||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import com.microservices.system.api.domain.SysDept;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberDataVo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 特色专区会员对象 zone_member
|
||||
|
|
@ -92,6 +96,18 @@ public class ZoneMember extends BaseEntity {
|
|||
private SysUser sysUser;
|
||||
private SysDept sysDept;
|
||||
private ZoneMemberLevel zoneMemberLevel;
|
||||
private ZonePointsAccount zonePointsAccount;
|
||||
|
||||
/**
|
||||
* 积分流水(合并后由 zone_points_transaction 表承载事件信息)
|
||||
*/
|
||||
private ZonePointsTransaction pointsEvent;
|
||||
|
||||
/**
|
||||
* 积分申请列表
|
||||
*/
|
||||
private List<ZonePointsApply> applyList;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date auditTime;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,4 +21,6 @@ public class ZoneMemberWithScore extends ZoneMember implements Serializable {
|
|||
private Double searchScore;
|
||||
|
||||
private String memberTypeName;
|
||||
|
||||
private String memberLevelName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package com.microservices.zone.member.domain.points;
|
||||
|
||||
import com.microservices.common.core.annotation.Excel;
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 专区积分账户对象 zone_points_account
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class ZonePointsAccount extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 积分账户主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Excel(name = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 专区ID(积分按专区隔离)
|
||||
*/
|
||||
@Excel(name = "专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
/**
|
||||
* 累计积分
|
||||
*/
|
||||
@Excel(name = "累计积分")
|
||||
private Integer totalPoints;
|
||||
|
||||
/**
|
||||
* 累计获取积分
|
||||
*/
|
||||
@Excel(name = "累计获取积分")
|
||||
private Integer totalEarnedPoints;
|
||||
|
||||
/**
|
||||
* 累计消费积分
|
||||
*/
|
||||
@Excel(name = "累计消费积分")
|
||||
private Integer totalConsumedPoints;
|
||||
|
||||
/**
|
||||
* 可用积分
|
||||
*/
|
||||
@Excel(name = "可用积分")
|
||||
private Integer availablePoints;
|
||||
|
||||
/**
|
||||
* 冻结积分
|
||||
*/
|
||||
@Excel(name = "冻结积分")
|
||||
private Integer frozenPoints;
|
||||
|
||||
/**
|
||||
* 所属组织ID
|
||||
*/
|
||||
@Excel(name = "所属组织ID")
|
||||
private Long deptId;
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
package com.microservices.zone.member.domain.points;
|
||||
|
||||
import com.microservices.common.core.annotation.Excel;
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 积分申请表 zone_points_apply
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class ZonePointsApply extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Excel(name = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 专区ID
|
||||
*/
|
||||
@Excel(name = "专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
/**
|
||||
* 组织ID
|
||||
*/
|
||||
@Excel(name = "组织ID")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 申请类型(如:download下载/redeem兑换等)
|
||||
*/
|
||||
@Excel(name = "申请类型")
|
||||
private String applyType;
|
||||
|
||||
/**
|
||||
* 事件ID(关联积分流水事件)
|
||||
*/
|
||||
@Excel(name = "事件ID")
|
||||
private String eventId;
|
||||
|
||||
/**
|
||||
* 回复/响应内容
|
||||
*/
|
||||
@Excel(name = "回复/响应内容")
|
||||
private String reply;
|
||||
|
||||
/**
|
||||
* 状态:pending待处理/success成功/fail失败/rejected已拒绝
|
||||
*/
|
||||
@Excel(name = "状态")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 申请积分数量
|
||||
*/
|
||||
@Excel(name = "申请积分数量")
|
||||
private Integer points;
|
||||
|
||||
/**
|
||||
* 回复人ID
|
||||
*/
|
||||
@Excel(name = "回复人ID")
|
||||
private Long replyId;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@Excel(name = "手机号")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 真实姓名
|
||||
*/
|
||||
@Excel(name = "真实姓名")
|
||||
private String realName;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@Excel(name = "描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 组织
|
||||
*/
|
||||
@Excel(name = "组织")
|
||||
private String organization;
|
||||
|
||||
/**
|
||||
* 微信号
|
||||
*/
|
||||
@Excel(name = "微信号")
|
||||
private String wechat;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Excel(name = "邮箱")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 专区成员名称
|
||||
*/
|
||||
private String memberName;
|
||||
|
||||
/**
|
||||
* 系统用户信息
|
||||
*/
|
||||
private SysUser sysUser;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.microservices.zone.member.domain.points;
|
||||
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 专区积分文档对象 zone_points_doc
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class ZonePointsDoc extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 专区ID
|
||||
*/
|
||||
private Long zoneId;
|
||||
|
||||
/**
|
||||
* 文章ID
|
||||
*/
|
||||
private Long docId;
|
||||
|
||||
/**
|
||||
* 初始访问次数
|
||||
*/
|
||||
private Integer pointsStartVisits;
|
||||
|
||||
/**
|
||||
* 已触发积分次数
|
||||
*/
|
||||
private Integer pointsTriggerCount;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
private Date expiryTime;
|
||||
|
||||
/**
|
||||
* 是否积分置顶(0代表不置顶 1代表置顶)
|
||||
*/
|
||||
private Boolean isPointsTop;
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.microservices.zone.member.domain.points;
|
||||
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 积分异步任务失败记录对象 zone_points_fail_log
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class ZonePointsFailLog extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 任务完整JSON数据
|
||||
*/
|
||||
private String taskData;
|
||||
|
||||
/**
|
||||
* 失败时间
|
||||
*/
|
||||
private Date failTime;
|
||||
|
||||
/**
|
||||
* 最后失败原因
|
||||
*/
|
||||
private String lastError;
|
||||
|
||||
/**
|
||||
* 处理状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 处理时间
|
||||
*/
|
||||
private Date processTime;
|
||||
|
||||
/**
|
||||
* 人工处理备注
|
||||
*/
|
||||
private String processRemark;
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.microservices.zone.member.domain.points;
|
||||
|
||||
import com.microservices.common.core.annotation.Excel;
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 专区积分流水对象 zone_points_transaction(合并事件+流水)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class ZonePointsTransaction extends BaseEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流水主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 事件ID(关联同一事件的所有操作)
|
||||
*/
|
||||
@Excel(name = "事件ID")
|
||||
private String eventId;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
@Excel(name = "事件类型")
|
||||
private String eventType;
|
||||
|
||||
/**
|
||||
* 积分账户ID
|
||||
*/
|
||||
@Excel(name = "积分账户ID")
|
||||
private Long accountId;
|
||||
|
||||
/**
|
||||
* 类型:add增/reduce减/freezed冻结/unfreezed解冻
|
||||
*/
|
||||
@Excel(name = "类型")
|
||||
private String transactionType;
|
||||
|
||||
/**
|
||||
* 积分数量(正数)
|
||||
*/
|
||||
@Excel(name = "积分数量")
|
||||
private Integer points;
|
||||
|
||||
/**
|
||||
* 变动后可用积分
|
||||
*/
|
||||
@Excel(name = "变动后可用积分")
|
||||
private Integer availableAfter;
|
||||
|
||||
/**
|
||||
* 变动后冻结积分
|
||||
*/
|
||||
@Excel(name = "变动后冻结积分")
|
||||
private Integer frozenAfter;
|
||||
|
||||
/**
|
||||
* 操作人ID
|
||||
*/
|
||||
@Excel(name = "操作人ID")
|
||||
private Long operatorId;
|
||||
|
||||
/**
|
||||
* 变动原因
|
||||
*/
|
||||
@Excel(name = "变动原因")
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 回复内容
|
||||
*/
|
||||
@Excel(name = "回复内容")
|
||||
private String replyContent;
|
||||
|
||||
/**
|
||||
* 来源ID
|
||||
*/
|
||||
@Excel(name = "来源ID")
|
||||
private Long sourceId;
|
||||
|
||||
/**
|
||||
* 来源数据
|
||||
*/
|
||||
@Excel(name = "来源数据")
|
||||
private String sourceData;
|
||||
|
||||
/**
|
||||
* 主题
|
||||
*/
|
||||
@Excel(name = "主题")
|
||||
private String subject;
|
||||
|
||||
/**
|
||||
* 主题描述
|
||||
*/
|
||||
@Excel(name = "主题描述")
|
||||
private String subjectDesc;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 专区会员分类(含已审核会员数量)对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("专区会员分类(含已审核会员数量)对象")
|
||||
public class ZoneMemberTypeCountVo {
|
||||
@ApiModelProperty(value = "专区会员分类Id")
|
||||
private Long id;
|
||||
@ApiModelProperty(value = "专区会员分类名称")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "专区会员分类简介")
|
||||
private String introduction;
|
||||
@ApiModelProperty(value = "排序")
|
||||
private Integer sort;
|
||||
@ApiModelProperty(value = "已审核会员数量")
|
||||
private Long memberCount;
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 积分账户输入对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分账户输入对象")
|
||||
public class ZonePointsAccountInputVo {
|
||||
@ApiModelProperty(value = "用户ID", required = true)
|
||||
@NotNull
|
||||
private Long userId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID", required = true)
|
||||
@NotNull
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty(value = "累计积分")
|
||||
private Integer totalPoints;
|
||||
|
||||
@ApiModelProperty(value = "累计获取积分")
|
||||
private Integer totalEarnedPoints;
|
||||
|
||||
@ApiModelProperty(value = "累计消费积分")
|
||||
private Integer totalConsumedPoints;
|
||||
|
||||
@ApiModelProperty(value = "可用积分")
|
||||
private Integer availablePoints;
|
||||
|
||||
@ApiModelProperty(value = "冻结积分")
|
||||
private Integer frozenPoints;
|
||||
|
||||
public ZonePointsAccount toZonePointsAccount() {
|
||||
ZonePointsAccount zonePointsAccount = new ZonePointsAccount();
|
||||
zonePointsAccount.setUserId(userId);
|
||||
zonePointsAccount.setZoneId(zoneId);
|
||||
zonePointsAccount.setTotalPoints(totalPoints != null ? totalPoints : 0);
|
||||
zonePointsAccount.setTotalEarnedPoints(totalEarnedPoints != null ? totalEarnedPoints : 0);
|
||||
zonePointsAccount.setTotalConsumedPoints(totalConsumedPoints != null ? totalConsumedPoints : 0);
|
||||
zonePointsAccount.setAvailablePoints(availablePoints != null ? availablePoints : 0);
|
||||
zonePointsAccount.setFrozenPoints(frozenPoints != null ? frozenPoints : 0);
|
||||
return zonePointsAccount;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 积分账户搜索对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分账户搜索对象")
|
||||
public class ZonePointsAccountSearchVo {
|
||||
@ApiModelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
public ZonePointsAccount toZonePointsAccount() {
|
||||
ZonePointsAccount zonePointsAccount = new ZonePointsAccount();
|
||||
zonePointsAccount.setUserId(userId);
|
||||
zonePointsAccount.setZoneId(zoneId);
|
||||
return zonePointsAccount;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 积分账户更新对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分账户更新对象")
|
||||
public class ZonePointsAccountUpdateVo {
|
||||
|
||||
@ApiModelProperty(value = "积分账户ID", required = true)
|
||||
@NotNull
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "累计积分")
|
||||
private int totalPoints;
|
||||
|
||||
@ApiModelProperty(value = "累计获取积分")
|
||||
private int totalEarnedPoints;
|
||||
|
||||
@ApiModelProperty(value = "累计消费积分")
|
||||
private int totalConsumedPoints;
|
||||
|
||||
@ApiModelProperty(value = "可用积分")
|
||||
private int availablePoints;
|
||||
|
||||
@ApiModelProperty(value = "冻结积分")
|
||||
private int frozenPoints;
|
||||
|
||||
public ZonePointsAccount toZonePointsAccount() {
|
||||
ZonePointsAccount zonePointsAccount = new ZonePointsAccount();
|
||||
zonePointsAccount.setId(id);
|
||||
zonePointsAccount.setTotalPoints(totalPoints);
|
||||
zonePointsAccount.setTotalEarnedPoints(totalEarnedPoints);
|
||||
zonePointsAccount.setTotalConsumedPoints(totalConsumedPoints);
|
||||
zonePointsAccount.setAvailablePoints(availablePoints);
|
||||
zonePointsAccount.setFrozenPoints(frozenPoints);
|
||||
return zonePointsAccount;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 积分申请详情VO(含系统用户信息)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class ZonePointsApplyDetailVo extends ZonePointsApply {
|
||||
@ApiModelProperty("GitLink账号")
|
||||
private String userName;
|
||||
@ApiModelProperty("GitLink个人主页地址")
|
||||
private String gitLinkUserUrl;
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 积分申请输入对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分申请输入对象")
|
||||
public class ZonePointsApplyInputVo {
|
||||
@ApiModelProperty(value = "申请记录ID(驳回操作时必填)")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "用户ID", required = true)
|
||||
@NotNull
|
||||
private Long userId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID", required = true)
|
||||
@NotNull
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty(value = "组织ID", required = true)
|
||||
@NotNull
|
||||
private Long deptId;
|
||||
|
||||
@ApiModelProperty(value = "申请类型(如:download下载/redeem兑换等)", required = true)
|
||||
@NotNull
|
||||
private String applyType;
|
||||
|
||||
@ApiModelProperty(value = "事件ID(关联积分流水事件)")
|
||||
private String eventId;
|
||||
|
||||
@ApiModelProperty(value = "申请积分数量")
|
||||
private Integer points;
|
||||
|
||||
@ApiModelProperty(value = "手机号")
|
||||
private String phone;
|
||||
|
||||
@ApiModelProperty(value = "真实姓名")
|
||||
private String realName;
|
||||
|
||||
@ApiModelProperty(value = "描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "回复/驳回内容")
|
||||
private String reply;
|
||||
|
||||
@ApiModelProperty(value = "组织")
|
||||
private String organization;
|
||||
|
||||
@ApiModelProperty(value = "微信号")
|
||||
private String wechat;
|
||||
|
||||
@ApiModelProperty(value = "邮箱")
|
||||
private String email;
|
||||
|
||||
public ZonePointsApply toZonePointsApply() {
|
||||
ZonePointsApply zonePointsApply = new ZonePointsApply();
|
||||
zonePointsApply.setUserId(userId);
|
||||
zonePointsApply.setZoneId(zoneId);
|
||||
zonePointsApply.setDeptId(deptId);
|
||||
zonePointsApply.setApplyType(applyType);
|
||||
zonePointsApply.setEventId(eventId);
|
||||
zonePointsApply.setPoints(points);
|
||||
zonePointsApply.setStatus("pending");
|
||||
zonePointsApply.setPhone(phone);
|
||||
zonePointsApply.setRealName(realName);
|
||||
zonePointsApply.setDescription(description);
|
||||
zonePointsApply.setOrganization(organization);
|
||||
zonePointsApply.setWechat(wechat);
|
||||
zonePointsApply.setEmail(email);
|
||||
return zonePointsApply;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 积分申请搜索对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分申请搜索对象")
|
||||
public class ZonePointsApplySearchVo extends BaseEntity {
|
||||
@ApiModelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty(value = "申请类型")
|
||||
private String applyType;
|
||||
|
||||
@ApiModelProperty(value = "事件ID")
|
||||
private String eventId;
|
||||
|
||||
@ApiModelProperty(value = "状态")
|
||||
private String status;
|
||||
|
||||
@ApiModelProperty(value = "手机号")
|
||||
private String phone;
|
||||
|
||||
@ApiModelProperty(value = "真实姓名")
|
||||
private String realName;
|
||||
|
||||
@ApiModelProperty(value = "邮箱")
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty(value = "成员名称")
|
||||
private String memberName;
|
||||
|
||||
@ApiModelProperty(value = "系统用户名")
|
||||
private String userName;
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 积分申请修改对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分申请修改对象")
|
||||
public class ZonePointsApplyUpdateVo {
|
||||
@ApiModelProperty(value = "主键ID", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "回复/响应内容")
|
||||
private String reply;
|
||||
|
||||
@ApiModelProperty(value = "状态:pending待处理/success成功/fail失败/rejected已拒绝")
|
||||
private String status;
|
||||
|
||||
@ApiModelProperty(value = "事件ID(关联积分流水事件)")
|
||||
private String eventId;
|
||||
|
||||
@ApiModelProperty(value = "回复人ID")
|
||||
private Long replyId;
|
||||
|
||||
public ZonePointsApply toZonePointsApply() {
|
||||
ZonePointsApply zonePointsApply = new ZonePointsApply();
|
||||
zonePointsApply.setId(id);
|
||||
zonePointsApply.setReply(reply);
|
||||
zonePointsApply.setStatus(status);
|
||||
zonePointsApply.setEventId(eventId);
|
||||
zonePointsApply.setReplyId(replyId);
|
||||
return zonePointsApply;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文章置顶积分扣减输入对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("文章置顶积分扣减请求")
|
||||
public class ZonePointsArticleTopInputVo {
|
||||
|
||||
@ApiModelProperty(value = "组织ID", required = true)
|
||||
private Long deptId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID", required = true)
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty(value = "文章ID", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "文章名称", required = true)
|
||||
private String name;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 专区积分账户总览对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("专区积分账户总览对象")
|
||||
public class ZonePointsOverviewVo {
|
||||
@ApiModelProperty(value = "积分账户ID")
|
||||
private Long accountId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty(value = "累计获取积分")
|
||||
private Integer totalEarnedPoints;
|
||||
|
||||
@ApiModelProperty(value = "累计消费积分")
|
||||
private Integer totalConsumedPoints;
|
||||
|
||||
@ApiModelProperty(value = "当前可用积分")
|
||||
private Integer availablePoints;
|
||||
|
||||
@ApiModelProperty(value = "冻结积分")
|
||||
private Integer frozenPoints;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 项目置顶积分扣减输入对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("项目置顶积分扣减请求")
|
||||
public class ZonePointsProjectTopInputVo {
|
||||
|
||||
@ApiModelProperty(value = "组织ID", required = true)
|
||||
private Long deptId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID", required = true)
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty(value = "项目ID", required = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "项目名称", required = true)
|
||||
private String name;
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 置顶文章信息返回对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("置顶文章信息")
|
||||
public class ZonePointsTopDocVo {
|
||||
|
||||
@ApiModelProperty("专区积分文档记录ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty("文章ID")
|
||||
private Long docId;
|
||||
|
||||
@ApiModelProperty("文章名称")
|
||||
private String docName;
|
||||
|
||||
@ApiModelProperty("文章概要")
|
||||
private String summary;
|
||||
|
||||
@ApiModelProperty("是否积分置顶")
|
||||
private Boolean isPointsTop;
|
||||
|
||||
@ApiModelProperty("置顶过期时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date expiryTime;
|
||||
|
||||
@ApiModelProperty("文章头图")
|
||||
private String headImg;
|
||||
|
||||
@ApiModelProperty("发布时间")
|
||||
private String publishTime;
|
||||
|
||||
@ApiModelProperty("发布人")
|
||||
private String publishUser;
|
||||
|
||||
@ApiModelProperty("浏览量")
|
||||
private Long visits;
|
||||
|
||||
@ApiModelProperty("文章详情访问地址")
|
||||
private String docDetailUrl;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 置顶项目信息返回对象
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("置顶项目信息")
|
||||
public class ZonePointsTopProjectVo {
|
||||
|
||||
@ApiModelProperty("项目聚合主键")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty("项目名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("gitlink项目完整路径")
|
||||
private String fullName;
|
||||
|
||||
@ApiModelProperty("gitlink项目ID")
|
||||
private Long gitlinkProjectId;
|
||||
|
||||
@ApiModelProperty("是否积分置顶(0代表不是 1代表是)")
|
||||
private String isPointsTop;
|
||||
|
||||
@ApiModelProperty("置顶过期时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date expiryTime;
|
||||
|
||||
@ApiModelProperty("项目访问URL")
|
||||
private String projectURL;
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 积分流水输入对象(合并事件+流水,同时兼容原 ZonePointsEventInputVo 的 API 入参)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分流水输入对象")
|
||||
public class ZonePointsTransactionInputVo {
|
||||
@ApiModelProperty(value = "事件ID")
|
||||
private String eventId;
|
||||
|
||||
@ApiModelProperty(value = "专区ID(API 入参,不存入流水表)")
|
||||
private Long zoneId;
|
||||
|
||||
@ApiModelProperty(value = "用户ID(API 入参,不存入流水表)")
|
||||
private Long userId;
|
||||
|
||||
@ApiModelProperty(value = "事件类型")
|
||||
private String eventType;
|
||||
|
||||
@ApiModelProperty(value = "积分账户ID", required = true)
|
||||
@NotNull
|
||||
private Long accountId;
|
||||
|
||||
@ApiModelProperty(value = "类型:add增/reduce减/freezed冻结/unfreezed解冻", required = true)
|
||||
@NotNull
|
||||
private String transactionType;
|
||||
|
||||
@ApiModelProperty(value = "积分数量(正数)", required = true)
|
||||
@NotNull
|
||||
private Integer points;
|
||||
|
||||
@ApiModelProperty(value = "变动后可用积分")
|
||||
private Integer availableAfter;
|
||||
|
||||
@ApiModelProperty(value = "变动后冻结积分")
|
||||
private Integer frozenAfter;
|
||||
|
||||
@ApiModelProperty(value = "操作人ID")
|
||||
private Long operatorId;
|
||||
|
||||
@ApiModelProperty(value = "变动原因")
|
||||
private String reason;
|
||||
|
||||
@ApiModelProperty(value = "回复内容")
|
||||
private String replyContent;
|
||||
|
||||
@ApiModelProperty(value = "来源ID")
|
||||
private Long sourceId;
|
||||
|
||||
@ApiModelProperty(value = "来源数据")
|
||||
private String sourceData;
|
||||
|
||||
@ApiModelProperty(value = "主题")
|
||||
private String subject;
|
||||
|
||||
@ApiModelProperty(value = "主题描述")
|
||||
private String subjectDesc;
|
||||
|
||||
public ZonePointsTransaction toZonePointsTransaction() {
|
||||
ZonePointsTransaction zonePointsTransaction = new ZonePointsTransaction();
|
||||
zonePointsTransaction.setEventId(eventId);
|
||||
zonePointsTransaction.setEventType(eventType);
|
||||
zonePointsTransaction.setAccountId(accountId);
|
||||
zonePointsTransaction.setTransactionType(transactionType);
|
||||
zonePointsTransaction.setPoints(points);
|
||||
zonePointsTransaction.setAvailableAfter(availableAfter);
|
||||
zonePointsTransaction.setFrozenAfter(frozenAfter);
|
||||
zonePointsTransaction.setOperatorId(operatorId);
|
||||
zonePointsTransaction.setReason(reason);
|
||||
zonePointsTransaction.setReplyContent(replyContent);
|
||||
zonePointsTransaction.setSourceId(sourceId);
|
||||
zonePointsTransaction.setSourceData(sourceData);
|
||||
zonePointsTransaction.setSubject(subject);
|
||||
zonePointsTransaction.setSubjectDesc(subjectDesc);
|
||||
return zonePointsTransaction;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 积分流水搜索对象(合并事件+流水)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分流水搜索对象")
|
||||
public class ZonePointsTransactionSearchVo {
|
||||
@ApiModelProperty(value = "事件ID")
|
||||
private String eventId;
|
||||
|
||||
@ApiModelProperty(value = "事件类型")
|
||||
private String eventType;
|
||||
|
||||
@ApiModelProperty(value = "积分账户ID")
|
||||
private Long accountId;
|
||||
|
||||
@ApiModelProperty(value = "类型:add增/reduce减/freezed冻结/unfreezed解冻")
|
||||
private String transactionType;
|
||||
|
||||
@ApiModelProperty(value = "来源ID")
|
||||
private Long sourceId;
|
||||
|
||||
public ZonePointsTransaction toZonePointsTransaction() {
|
||||
ZonePointsTransaction zonePointsTransaction = new ZonePointsTransaction();
|
||||
zonePointsTransaction.setEventId(eventId);
|
||||
zonePointsTransaction.setEventType(eventType);
|
||||
zonePointsTransaction.setAccountId(accountId);
|
||||
zonePointsTransaction.setTransactionType(transactionType);
|
||||
zonePointsTransaction.setSourceId(sourceId);
|
||||
return zonePointsTransaction;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 积分流水更新对象(合并事件+流水)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("积分流水更新对象")
|
||||
public class ZonePointsTransactionUpdateVo {
|
||||
|
||||
@ApiModelProperty(value = "流水ID", required = true)
|
||||
@NotNull
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "类型:add增/reduce减/freezed冻结/unfreezed解冻")
|
||||
private String transactionType;
|
||||
|
||||
@ApiModelProperty(value = "积分数量(正数)")
|
||||
private int points;
|
||||
|
||||
@ApiModelProperty(value = "变动后可用积分")
|
||||
private int availableAfter;
|
||||
|
||||
@ApiModelProperty(value = "变动后冻结积分")
|
||||
private int frozenAfter;
|
||||
|
||||
@ApiModelProperty(value = "事件类型")
|
||||
private String eventType;
|
||||
|
||||
@ApiModelProperty(value = "变动原因")
|
||||
private String reason;
|
||||
|
||||
@ApiModelProperty(value = "回复内容")
|
||||
private String replyContent;
|
||||
|
||||
@ApiModelProperty(value = "主题")
|
||||
private String subject;
|
||||
|
||||
@ApiModelProperty(value = "主题描述")
|
||||
private String subjectDesc;
|
||||
|
||||
public ZonePointsTransaction toZonePointsTransaction() {
|
||||
ZonePointsTransaction zonePointsTransaction = new ZonePointsTransaction();
|
||||
zonePointsTransaction.setId(id);
|
||||
zonePointsTransaction.setTransactionType(transactionType);
|
||||
zonePointsTransaction.setPoints(points);
|
||||
zonePointsTransaction.setAvailableAfter(availableAfter);
|
||||
zonePointsTransaction.setFrozenAfter(frozenAfter);
|
||||
zonePointsTransaction.setEventType(eventType);
|
||||
zonePointsTransaction.setReason(reason);
|
||||
zonePointsTransaction.setReplyContent(replyContent);
|
||||
zonePointsTransaction.setSubject(subject);
|
||||
zonePointsTransaction.setSubjectDesc(subjectDesc);
|
||||
return zonePointsTransaction;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.microservices.zone.member.domain.vo;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 专区积分流水带事件信息对象(合并后不再需要单独事件关联,保留此类用于前端兼容)
|
||||
*
|
||||
* @author otto
|
||||
* @deprecated 合并后可直接使用 ZonePointsTransaction,此类仅用于 API 兼容过渡
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("积分流水带事件信息对象")
|
||||
@Deprecated
|
||||
public class ZonePointsTransactionWithEventVo extends ZonePointsTransaction {
|
||||
// 合并后所有业务字段已在 ZonePointsTransaction 中,此类仅保留兼容
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.microservices.zone.member.mapper;
|
|||
|
||||
import com.microservices.zone.member.domain.ZoneMember;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberSearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberTypeCountVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
|
|
@ -72,6 +73,25 @@ public interface ZoneMemberMapper {
|
|||
*/
|
||||
ZoneMember selectZoneMemberByZoneIdAndUserId(@Param("zoneId") Long zoneId, @Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户Id和专区/组织查询专区会员(审核状态不为审核未通过)
|
||||
*
|
||||
* @param zoneId 专区ID(与deptId二选一)
|
||||
* @param userId 用户ID
|
||||
* @param deptId 组织ID(与zoneId二选一)
|
||||
* @return
|
||||
*/
|
||||
ZoneMember selectZoneMember(@Param("zoneId") Long zoneId, @Param("userId") Long userId, @Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 查询专区会员信息(含等级和积分账户)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param userId 用户ID
|
||||
* @return 专区会员信息
|
||||
*/
|
||||
ZoneMember selectZoneMemberInfoByZoneIdAndUserId(@Param("zoneId") Long zoneId, @Param("userId") Long userId);
|
||||
|
||||
Integer selectZoneMemberListCount(ZoneMemberSearchVo zoneMemberSearchVo);
|
||||
|
||||
int updateZoneMemberHomePageShow(@Param("id") Long id, @Param("isHomepage") String isHomepage);
|
||||
|
|
@ -102,6 +122,14 @@ public interface ZoneMemberMapper {
|
|||
*/
|
||||
Integer selectCountByZoneId(ZoneMember zoneMember);
|
||||
|
||||
/**
|
||||
* 按会员分类统计专区下已审核会员数量
|
||||
*
|
||||
* @param zoneId 专区Id
|
||||
* @return 每个分类(id)对应的已审核会员数量
|
||||
*/
|
||||
List<ZoneMemberTypeCountVo> selectAuditedMemberCountByType(@Param("zoneId") Long zoneId);
|
||||
|
||||
/**
|
||||
* 获取指定序号的会员
|
||||
*
|
||||
|
|
@ -171,4 +199,28 @@ public interface ZoneMemberMapper {
|
|||
@Param("pageSize") int pageSize);
|
||||
|
||||
Long globalSearchCount(@Param("keyword") String keyword, @Param("zoneId") Long zoneId);
|
||||
|
||||
/**
|
||||
* 全局搜索 - 扩展模糊搜索(含会员分类和等级)
|
||||
*
|
||||
* @param keyword 搜索关键词
|
||||
* @param zoneId 专区ID
|
||||
* @param offset 偏移量
|
||||
* @param pageSize 每页数量
|
||||
* @return 搜索结果列表(含评分)
|
||||
*/
|
||||
List<com.microservices.zone.member.domain.ZoneMemberWithScore> globalSearchWithScoreExtended(
|
||||
@Param("keyword") String keyword,
|
||||
@Param("zoneId") Long zoneId,
|
||||
@Param("offset") int offset,
|
||||
@Param("pageSize") int pageSize);
|
||||
|
||||
/**
|
||||
* 全局搜索 - 扩展模糊搜索计数(含会员分类和等级)
|
||||
*
|
||||
* @param keyword 搜索关键词
|
||||
* @param zoneId 专区ID
|
||||
* @return 匹配总数
|
||||
*/
|
||||
Long globalSearchCountExtended(@Param("keyword") String keyword, @Param("zoneId") Long zoneId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
package com.microservices.zone.member.mapper;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专区积分账户Mapper接口
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Mapper
|
||||
public interface ZonePointsAccountMapper {
|
||||
/**
|
||||
* 查询专区积分账户
|
||||
*
|
||||
* @param id 专区积分账户主键
|
||||
* @return 专区积分账户
|
||||
*/
|
||||
public ZonePointsAccount selectZonePointsAccountById(Long id);
|
||||
|
||||
/**
|
||||
* 查询专区积分账户列表
|
||||
*
|
||||
* @param zonePointsAccount 专区积分账户
|
||||
* @return 专区积分账户集合
|
||||
*/
|
||||
public List<ZonePointsAccount> selectZonePointsAccountList(ZonePointsAccount zonePointsAccount);
|
||||
|
||||
/**
|
||||
* 新增专区积分账户
|
||||
*
|
||||
* @param zonePointsAccount 专区积分账户
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertZonePointsAccount(ZonePointsAccount zonePointsAccount);
|
||||
|
||||
/**
|
||||
* 修改专区积分账户
|
||||
*
|
||||
* @param zonePointsAccount 专区积分账户
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateZonePointsAccount(ZonePointsAccount zonePointsAccount);
|
||||
|
||||
/**
|
||||
* 删除专区积分账户
|
||||
*
|
||||
* @param id 专区积分账户主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsAccountById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除专区积分账户
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsAccountByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询积分账户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分账户
|
||||
*/
|
||||
ZonePointsAccount selectZonePointsAccountByUserIdAndZoneId(@Param("userId") Long userId, @Param("zoneId") Long zoneId);
|
||||
|
||||
/**
|
||||
* 根据会员ID查询积分账户列表
|
||||
*
|
||||
* @param memberId 专区会员ID
|
||||
* @return 专区积分账户列表
|
||||
*/
|
||||
List<ZonePointsAccount> selectZonePointsAccountByMemberId(@Param("memberId") Long memberId);
|
||||
|
||||
/**
|
||||
* 锁定行获取账户信息(用于并发安全更新)
|
||||
*
|
||||
* @param id 账户ID
|
||||
* @return 专区积分账户
|
||||
*/
|
||||
ZonePointsAccount selectZonePointsAccountByIdForUpdate(Long id);
|
||||
|
||||
/**
|
||||
* 原子增加积分(并发安全)
|
||||
*
|
||||
* @param id 账户ID
|
||||
* @param addPoints 增加的积分
|
||||
* @return 影响行数
|
||||
*/
|
||||
int addPointsAtomic(@Param("id") Long id, @Param("addPoints") int addPoints);
|
||||
|
||||
/**
|
||||
* 原子扣除积分(并发安全)
|
||||
*
|
||||
* @param id 账户ID
|
||||
* @param deductPoints 扣除的积分
|
||||
* @return 影响行数
|
||||
*/
|
||||
int deductPointsAtomic(@Param("id") Long id, @Param("deductPoints") int deductPoints);
|
||||
|
||||
int freezePointsAtomic(@Param("id") Long id, @Param("freezePoints") int freezePoints);
|
||||
|
||||
/**
|
||||
* 原子解冻积分(并发安全)
|
||||
*
|
||||
* @param id 账户ID
|
||||
* @param unfreezePoints 解冻的积分
|
||||
* @return 影响行数
|
||||
*/
|
||||
int unfreezePointsAtomic(@Param("id") Long id, @Param("unfreezePoints") int unfreezePoints);
|
||||
|
||||
/**
|
||||
* 原子扣减冻结积分(并发安全),用于申请通过时从冻结积分中正式扣除
|
||||
*
|
||||
* @param id 账户ID
|
||||
* @param deductPoints 扣减的积分
|
||||
* @return 影响行数
|
||||
*/
|
||||
int deductFrozenPointsAtomic(@Param("id") Long id, @Param("deductPoints") int deductPoints);
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.microservices.zone.member.mapper;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplySearchVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 积分申请表Mapper接口
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Mapper
|
||||
public interface ZonePointsApplyMapper {
|
||||
/**
|
||||
* 查询积分申请
|
||||
*
|
||||
* @param id 积分申请主键
|
||||
* @return 积分申请
|
||||
*/
|
||||
public ZonePointsApply selectZonePointsApplyById(Long id);
|
||||
|
||||
/**
|
||||
* 查询积分申请列表
|
||||
*
|
||||
* @param zonePointsApply 积分申请
|
||||
* @return 积分申请集合
|
||||
*/
|
||||
public List<ZonePointsApply> selectZonePointsApplyList(ZonePointsApplySearchVo searchVo);
|
||||
|
||||
/**
|
||||
* 新增积分申请
|
||||
*
|
||||
* @param zonePointsApply 积分申请
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertZonePointsApply(ZonePointsApply zonePointsApply);
|
||||
|
||||
/**
|
||||
* 修改积分申请
|
||||
*
|
||||
* @param zonePointsApply 积分申请
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateZonePointsApply(ZonePointsApply zonePointsApply);
|
||||
|
||||
/**
|
||||
* 删除积分申请
|
||||
*
|
||||
* @param id 积分申请主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsApplyById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除积分申请
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsApplyByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询积分申请列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 积分申请列表
|
||||
*/
|
||||
List<ZonePointsApply> selectZonePointsApplyByUserIdAndZoneId(@Param("userId") Long userId, @Param("zoneId") Long zoneId);
|
||||
|
||||
/**
|
||||
* 统计用户某类型待处理的申请数量(幂等校验)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @param applyType 申请类型
|
||||
* @return 待处理申请数量
|
||||
*/
|
||||
int countPendingByUserZoneAndType(@Param("userId") Long userId, @Param("zoneId") Long zoneId, @Param("applyType") String applyType);
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package com.microservices.zone.member.mapper;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsDoc;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTopDocVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专区积分文档Mapper接口
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Mapper
|
||||
public interface ZonePointsDocMapper {
|
||||
|
||||
/**
|
||||
* 查询专区积分文档
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 专区积分文档
|
||||
*/
|
||||
ZonePointsDoc selectZonePointsDocById(Long id);
|
||||
|
||||
/**
|
||||
* 查询专区积分文档
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param docId 文章ID
|
||||
* @return 专区积分文档
|
||||
*/
|
||||
ZonePointsDoc selectZonePointsDocByZoneIdAndDocId(@Param("zoneId") Long zoneId, @Param("docId") Long docId);
|
||||
|
||||
/**
|
||||
* 新增专区积分文档
|
||||
*
|
||||
* @param zonePointsDoc 专区积分文档
|
||||
* @return 结果
|
||||
*/
|
||||
int insertZonePointsDoc(ZonePointsDoc zonePointsDoc);
|
||||
|
||||
/**
|
||||
* 修改专区积分文档
|
||||
*
|
||||
* @param zonePointsDoc 专区积分文档
|
||||
* @return 结果
|
||||
*/
|
||||
int updateZonePointsDoc(ZonePointsDoc zonePointsDoc);
|
||||
|
||||
/**
|
||||
* 增加触发次数(原子操作)
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @param addCount 增加的触发次数
|
||||
* @return 影响行数
|
||||
*/
|
||||
int incrementTriggerCount(@Param("id") Long id, @Param("addCount") int addCount);
|
||||
|
||||
/**
|
||||
* 检查用户在指定专区下是否已有置顶文章
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param userId 用户ID
|
||||
* @return 置顶文章记录数
|
||||
*/
|
||||
int hasPointsTopByZoneIdAndUserId(@Param("zoneId") Long zoneId, @Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 查询用户在指定专区下的置顶文章
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param userId 用户ID
|
||||
* @return 置顶文章记录
|
||||
*/
|
||||
ZonePointsDoc selectPointsTopByZoneIdAndUserId(@Param("zoneId") Long zoneId, @Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 查询专区下置顶文章列表(左联 cms_doc,过期时间晚于当前时间,用于前台展示)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 置顶文章列表(含文章名称和概要)
|
||||
*/
|
||||
List<ZonePointsTopDocVo> selectTopDocList(@Param("zoneId") Long zoneId);
|
||||
|
||||
/**
|
||||
* 批量取消已过期的积分置顶(is_points_top=1 且 expiry_time 早于当前时间)
|
||||
*
|
||||
* @return 影响行数
|
||||
*/
|
||||
int updateExpiredPointsTop();
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.microservices.zone.member.mapper;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsFailLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 积分异步任务失败记录Mapper接口
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Mapper
|
||||
public interface ZonePointsFailLogMapper {
|
||||
|
||||
/**
|
||||
* 新增积分异步任务失败记录
|
||||
*
|
||||
* @param zonePointsFailLog 失败记录
|
||||
* @return 结果
|
||||
*/
|
||||
int insertZonePointsFailLog(ZonePointsFailLog zonePointsFailLog);
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package com.microservices.zone.member.mapper;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专区积分流水Mapper接口(合并事件+流水)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Mapper
|
||||
public interface ZonePointsTransactionMapper {
|
||||
/**
|
||||
* 查询专区积分流水
|
||||
*
|
||||
* @param id 专区积分流水主键
|
||||
* @return 专区积分流水
|
||||
*/
|
||||
public ZonePointsTransaction selectZonePointsTransactionById(Long id);
|
||||
|
||||
/**
|
||||
* 查询专区积分流水列表
|
||||
*
|
||||
* @param zonePointsTransaction 专区积分流水
|
||||
* @return 专区积分流水集合
|
||||
*/
|
||||
public List<ZonePointsTransaction> selectZonePointsTransactionList(ZonePointsTransaction zonePointsTransaction);
|
||||
|
||||
/**
|
||||
* 新增专区积分流水
|
||||
*
|
||||
* @param zonePointsTransaction 专区积分流水
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertZonePointsTransaction(ZonePointsTransaction zonePointsTransaction);
|
||||
|
||||
/**
|
||||
* 修改专区积分流水
|
||||
*
|
||||
* @param zonePointsTransaction 专区积分流水
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateZonePointsTransaction(ZonePointsTransaction zonePointsTransaction);
|
||||
|
||||
/**
|
||||
* 删除专区积分流水
|
||||
*
|
||||
* @param id 专区积分流水主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsTransactionById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除专区积分流水
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsTransactionByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 根据事件ID查询流水列表
|
||||
*
|
||||
* @param eventId 事件ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectZonePointsTransactionByEventId(@Param("eventId") String eventId);
|
||||
|
||||
/**
|
||||
* 根据账户ID查询流水列表
|
||||
*
|
||||
* @param accountId 积分账户ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectZonePointsTransactionByAccountId(@Param("accountId") Long accountId);
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询流水列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectZonePointsTransactionByUserIdAndZoneId(@Param("userId") Long userId, @Param("zoneId") Long zoneId);
|
||||
|
||||
/**
|
||||
* 根据专区ID获取当前用户积分明细(分页)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param userId 用户ID
|
||||
* @param transactionType 交易类型(可选)
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectMyPointsTransactionDetailsByZone(@Param("zoneId") Long zoneId, @Param("userId") Long userId, @Param("transactionType") String transactionType);
|
||||
|
||||
/**
|
||||
* 查询当前用户流水列表(合并后直接从流水表查询,包含所有业务字段)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectCurrentUserTransactionWithEvent(@Param("userId") Long userId, @Param("zoneId") Long zoneId);
|
||||
|
||||
/**
|
||||
* 统计指定事件类型、来源ID、账户ID的流水记录数(用于幂等校验)
|
||||
*/
|
||||
int countByEventTypeAndSourceAndUser(@Param("eventType") String eventType,
|
||||
@Param("sourceId") Long sourceId,
|
||||
@Param("accountId") Long accountId);
|
||||
|
||||
/**
|
||||
* 统计指定事件类型、专区ID、用户ID的流水记录数(用于幂等校验,JOIN account 获取 zoneId)
|
||||
*/
|
||||
int countByEventTypeAndZoneAndUser(@Param("eventType") String eventType,
|
||||
@Param("zoneId") Long zoneId,
|
||||
@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 根据专区ID、用户ID和事件类型查询积分流水(限制一条,JOIN account 获取 zoneId/userId)
|
||||
*/
|
||||
ZonePointsTransaction selectPointsTransactionOne(@Param("zoneId") Long zoneId,
|
||||
@Param("userId") Long userId,
|
||||
@Param("eventType") String eventType);
|
||||
|
||||
/**
|
||||
* 统计指定账户、事件类型在给定时间范围内的流水记录数(用于幂等校验,日期约束在 SQL 层避免脏数据干扰)
|
||||
*/
|
||||
int countByAccountIdAndEventTypeAndDateRange(@Param("accountId") Long accountId,
|
||||
@Param("eventType") String eventType,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
}
|
||||
|
|
@ -31,6 +31,14 @@ public interface IZoneMemberService {
|
|||
*/
|
||||
public GenericsTableDataInfo<ZoneMemberDetailVo> selectZoneMemberList(ZoneMemberSearchVo zoneMemberSearchVo, boolean isOpen);
|
||||
|
||||
/**
|
||||
* 查询特色专区已审核会员列表(公开接口,不分页由调用方通过 PageHelper 控制)
|
||||
*
|
||||
* @param zoneMemberSearchVo 特色专区会员查询对象(zoneId、name、memberTypeId、memberLevelId)
|
||||
* @return 特色专区会员集合
|
||||
*/
|
||||
public GenericsTableDataInfo<ZoneMemberDataVo> selectOpenZoneMemberList(ZoneMemberSearchVo zoneMemberSearchVo);
|
||||
|
||||
/**
|
||||
* 新增特色专区会员
|
||||
*
|
||||
|
|
@ -97,6 +105,15 @@ public interface IZoneMemberService {
|
|||
*/
|
||||
int updateZoneMemberHomePageShow(Long id);
|
||||
|
||||
/**
|
||||
* 根据专区ID修改当前登录用户会员信息
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param zoneMemberUpdateVo 会员更新信息
|
||||
* @return 结果
|
||||
*/
|
||||
int updateZoneMemberByMember(Long zoneId, ZoneMemberUpdateVo zoneMemberUpdateVo);
|
||||
|
||||
/**
|
||||
* 获取特色专区项目会员总览列表
|
||||
*
|
||||
|
|
@ -136,6 +153,8 @@ public interface IZoneMemberService {
|
|||
*/
|
||||
String selectZoneMemberAuditStatus(Long zoneId);
|
||||
|
||||
ZoneMember selectZoneMemberInfo(Long zoneId);
|
||||
|
||||
Integer selectZoneMemberAuditCount(ZoneMemberSearchVo zoneMemberSearchVo);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.microservices.zone.member.service;
|
||||
|
||||
import com.microservices.zone.member.domain.ZoneMemberType;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberTypeCountVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberTypeUpdateVo;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -28,6 +29,15 @@ public interface IZoneMemberTypeService {
|
|||
*/
|
||||
public List<ZoneMemberType> selectZoneMemberTypeList(ZoneMemberType zoneMemberType);
|
||||
|
||||
/**
|
||||
* 查询特色专区会员分类列表(含各分类下已审核会员数量)
|
||||
*
|
||||
* @param zoneId 专区Id
|
||||
* @param name 会员分类名称(模糊搜索,可为空)
|
||||
* @return 会员分类集合(含已审核会员数量)
|
||||
*/
|
||||
public List<ZoneMemberTypeCountVo> selectZoneMemberTypeListWithCount(Long zoneId, String name);
|
||||
|
||||
/**
|
||||
* 新增特色专区会员分类
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,240 @@
|
|||
package com.microservices.zone.member.service;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.domain.vo.*;
|
||||
import com.microservices.zone.resource.domain.ZoneResource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专区积分账户Service接口
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
public interface IZonePointsAccountService {
|
||||
/**
|
||||
* 查询专区积分账户
|
||||
*
|
||||
* @param id 专区积分账户主键
|
||||
* @return 专区积分账户
|
||||
*/
|
||||
public ZonePointsAccount selectZonePointsAccountById(Long id);
|
||||
|
||||
/**
|
||||
* 查询专区积分账户列表
|
||||
*
|
||||
* @param zonePointsAccount 专区积分账户
|
||||
* @return 专区积分账户集合
|
||||
*/
|
||||
public List<ZonePointsAccount> selectZonePointsAccountList(ZonePointsAccount zonePointsAccount);
|
||||
|
||||
/**
|
||||
* 新增专区积分账户
|
||||
*
|
||||
* @param inputVo 专区积分账户
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertZonePointsAccount(ZonePointsAccountInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 修改专区积分账户
|
||||
*
|
||||
* @param updateVo 专区积分账户
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateZonePointsAccount(ZonePointsAccountUpdateVo updateVo);
|
||||
|
||||
/**
|
||||
* 批量删除专区积分账户
|
||||
*
|
||||
* @param ids 需要删除的专区积分账户主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsAccountByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除专区积分账户信息
|
||||
*
|
||||
* @param id 专区积分账户主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsAccountById(Long id);
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询积分账户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分账户
|
||||
*/
|
||||
ZonePointsAccount selectZonePointsAccountByUserIdAndZoneId(Long userId, Long zoneId);
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的积分账户总览信息
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 积分账户总览(包含累计获取积分、累计消费积分)
|
||||
*/
|
||||
ZonePointsOverviewVo getCurrentUserPointsOverview(Long zoneId);
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的置顶文章信息
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 置顶文章信息(无置顶文章时返回null)
|
||||
*/
|
||||
ZonePointsTopDocVo getCurrentUserPointsTopDoc(Long zoneId);
|
||||
|
||||
/**
|
||||
* 查询专区下置顶文章列表(过期时间晚于当前时间,用于前台展示)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 置顶文章列表
|
||||
*/
|
||||
List<ZonePointsTopDocVo> selectTopDocList(Long zoneId);
|
||||
|
||||
/**
|
||||
* 查询首页文章合并列表(积分置顶文章 + 首页推荐文章,去重,置顶在前)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 合并后的首页文章列表
|
||||
*/
|
||||
List<ZonePointsTopDocVo> selectHomePageDocMergeList(Long zoneId);
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的置顶项目信息
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 置顶项目信息(无置顶项目时返回null)
|
||||
*/
|
||||
ZonePointsTopProjectVo getZonePointsTopProject(Long zoneId);
|
||||
|
||||
/**
|
||||
* 根据会员ID查询积分账户列表
|
||||
*
|
||||
* @param memberId 专区会员ID
|
||||
* @return 专区积分账户列表
|
||||
*/
|
||||
List<ZonePointsAccount> selectZonePointsAccountByMemberId(Long memberId);
|
||||
|
||||
/**
|
||||
* 异步创建会员积分账户并记录流水(不阻塞主业务)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @param operatorId 操作人ID(当前登录用户ID,无则默认0)
|
||||
* @param deptId deptID
|
||||
*/
|
||||
void createPointsAccountAsync(Long userId, Long zoneId, Long operatorId, Long deptId);
|
||||
|
||||
/**
|
||||
* 增加每日首次访问积分(异步方式)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 是否新增成功(false表示今日已领取)
|
||||
*/
|
||||
void addDailyVisitPointsAsync(Long zoneId);
|
||||
|
||||
/**
|
||||
* 从 Redis 队列中消费积分异步任务(在主线程执行,事务正常生效)
|
||||
*
|
||||
* @return 处理的任务数量
|
||||
*/
|
||||
int processPointsAsyncQueue();
|
||||
|
||||
/**
|
||||
* 增加资源发布积分(异步方式,写入 Redis 队列)
|
||||
*
|
||||
* @param zoneResource 专区资源
|
||||
*/
|
||||
void addPublishResourcePointsAsync(ZoneResource zoneResource);
|
||||
|
||||
/**
|
||||
* 增加项目关联积分(异步方式,写入 Redis 队列)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @param sourceId 来源ID(项目ID)
|
||||
* @param projectName 项目名称
|
||||
* @param operatorId 操作人ID
|
||||
*/
|
||||
void addRelevanceProjectPointsAsync(Long userId, Long zoneId, Long sourceId, String projectName, Long operatorId);
|
||||
|
||||
/**
|
||||
* 电子证书积分扣减
|
||||
*
|
||||
* @param inputVo 积分事件输入对象
|
||||
* @return true=扣减成功,false=扣减失败(积分不足)
|
||||
*/
|
||||
boolean deductPointsForCertificate(ZonePointsTransactionInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 文章置顶积分扣减
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param id 文章ID
|
||||
* @param name 文章名称
|
||||
* @return true=扣减成功,false=扣减失败(积分不足)
|
||||
*/
|
||||
boolean deductPointsForArticleTop(Long zoneId, Long id, String name);
|
||||
|
||||
/**
|
||||
* 项目置顶积分扣减
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param id 项目ID
|
||||
* @param name 项目名称
|
||||
* @return true=扣减成功,false=扣减失败(积分不足)
|
||||
*/
|
||||
boolean deductPointsForProjectTop(Long zoneId, Long id, String name);
|
||||
|
||||
/**
|
||||
* 线下活动积分冻结(前台用户操作,业务层已做会员身份+积分专区+幂等+积分校验)
|
||||
*
|
||||
* @param inputVo 积分申请输入对象
|
||||
*/
|
||||
void freezePointsForOfflineActivity(ZonePointsApplyInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 专家答疑积分冻结(前台用户操作,业务层已做会员身份+积分专区+幂等+积分校验)
|
||||
*
|
||||
* @param inputVo 积分申请输入对象
|
||||
*/
|
||||
void freezePointsForExpertQa(ZonePointsApplyInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 驳回积分申请(管理员操作)
|
||||
* 查询对应申请记录(pending状态),更新状态为fail,
|
||||
* 同时更新pointsEvent的subject括号内容为"已退回"、replyContent为驳回原因,
|
||||
* 并触发积分解冻操作
|
||||
*
|
||||
* @param inputVo 积分申请输入对象(id、reply必填)
|
||||
*/
|
||||
void rejectPointsApply(ZonePointsApplyInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 通过积分申请(管理员操作)
|
||||
* 查询对应申请记录(pending状态),更新状态为success,
|
||||
* 同时更新pointsEvent的subject去除原括号内容,
|
||||
* 并从冻结积分中正式扣减积分(含总积分扣减)
|
||||
*
|
||||
* @param inputVo 积分申请输入对象(id、reply必填)
|
||||
*/
|
||||
void approvePointsApply(ZonePointsApplyInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 增加资源下载积分(异步方式,写入 Redis 队列)
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @param sourceData 来源描述(如下载者信息)
|
||||
*/
|
||||
void addDownloadResourcePointsAsync(Long fileId, String sourceData);
|
||||
|
||||
/**
|
||||
* 将失败任务落库保存
|
||||
*
|
||||
* @param taskData 任务JSON数据
|
||||
* @param lastError 失败原因
|
||||
*/
|
||||
void saveFailLog(String taskData, String lastError);
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package com.microservices.zone.member.service;
|
||||
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyDetailVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyInputVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplySearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyUpdateVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 积分申请表Service接口
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
public interface IZonePointsApplyService {
|
||||
/**
|
||||
* 查询积分申请
|
||||
*
|
||||
* @param id 积分申请主键
|
||||
* @return 积分申请
|
||||
*/
|
||||
public ZonePointsApply selectZonePointsApplyById(Long id);
|
||||
|
||||
/**
|
||||
* 查询积分申请列表
|
||||
*
|
||||
* @param zonePointsApply 积分申请
|
||||
* @return 积分申请集合
|
||||
*/
|
||||
public GenericsTableDataInfo<ZonePointsApplyDetailVo> selectZonePointsApplyList(ZonePointsApplySearchVo searchVo);
|
||||
|
||||
/**
|
||||
* 新增积分申请
|
||||
*
|
||||
* @param inputVo 积分申请
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertZonePointsApply(ZonePointsApplyInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 修改积分申请
|
||||
*
|
||||
* @param updateVo 积分申请
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateZonePointsApply(ZonePointsApplyUpdateVo updateVo);
|
||||
|
||||
/**
|
||||
* 批量删除积分申请
|
||||
*
|
||||
* @param ids 需要删除的积分申请主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsApplyByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除积分申请信息
|
||||
*
|
||||
* @param id 积分申请主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsApplyById(Long id);
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询积分申请列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 积分申请列表
|
||||
*/
|
||||
List<ZonePointsApply> selectZonePointsApplyByUserIdAndZoneId(Long userId, Long zoneId);
|
||||
|
||||
/**
|
||||
* 检查用户是否有某类型的待处理申请(幂等校验)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @param applyType 申请类型
|
||||
* @return true=已有待处理申请
|
||||
*/
|
||||
boolean hasPendingApply(Long userId, Long zoneId, String applyType);
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package com.microservices.zone.member.service;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionInputVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionUpdateVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专区积分流水Service接口(合并事件+流水)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
public interface IZonePointsTransactionService {
|
||||
/**
|
||||
* 查询专区积分流水
|
||||
*
|
||||
* @param id 专区积分流水主键
|
||||
* @return 专区积分流水
|
||||
*/
|
||||
public ZonePointsTransaction selectZonePointsTransactionById(Long id);
|
||||
|
||||
/**
|
||||
* 查询专区积分流水列表
|
||||
*
|
||||
* @param zonePointsTransaction 专区积分流水
|
||||
* @return 专区积分流水集合
|
||||
*/
|
||||
public List<ZonePointsTransaction> selectZonePointsTransactionList(ZonePointsTransaction zonePointsTransaction);
|
||||
|
||||
/**
|
||||
* 新增专区积分流水
|
||||
*
|
||||
* @param inputVo 专区积分流水
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertZonePointsTransaction(ZonePointsTransactionInputVo inputVo);
|
||||
|
||||
/**
|
||||
* 修改专区积分流水
|
||||
*
|
||||
* @param updateVo 专区积分流水
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateZonePointsTransaction(ZonePointsTransactionUpdateVo updateVo);
|
||||
|
||||
/**
|
||||
* 删除专区积分流水信息
|
||||
*
|
||||
* @param id 专区积分流水主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteZonePointsTransactionById(Long id);
|
||||
|
||||
/**
|
||||
* 根据事件ID查询流水列表
|
||||
*
|
||||
* @param eventId 事件ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectZonePointsTransactionByEventId(String eventId);
|
||||
|
||||
/**
|
||||
* 根据账户ID查询流水列表
|
||||
*
|
||||
* @param accountId 积分账户ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectZonePointsTransactionByAccountId(Long accountId);
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询流水列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectZonePointsTransactionByUserIdAndZoneId(Long userId, Long zoneId);
|
||||
|
||||
/**
|
||||
* 根据专区ID获取当前用户积分明细(分页)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param userId 用户ID
|
||||
* @param transactionType 交易类型(可选)
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectMyPointsTransactionDetailsByZone(Long zoneId, Long userId, String transactionType);
|
||||
|
||||
/**
|
||||
* 查询当前用户流水列表(合并后直接从流水表查询,所有业务字段已包含)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
List<ZonePointsTransaction> selectCurrentUserTransactionWithEvent(Long userId, Long zoneId);
|
||||
}
|
||||
|
|
@ -26,11 +26,15 @@ import com.microservices.zone.detail.domain.ZoneDetail;
|
|||
import com.microservices.zone.detail.service.IZoneDetailService;
|
||||
import com.microservices.zone.member.domain.ZoneMember;
|
||||
import com.microservices.zone.member.domain.ZoneMemberType;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import com.microservices.zone.member.domain.vo.*;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsApplyMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.IZoneMemberLevelService;
|
||||
import com.microservices.zone.member.service.IZoneMemberService;
|
||||
import com.microservices.zone.member.service.IZoneMemberTypeService;
|
||||
import com.microservices.zone.member.service.IZonePointsAccountService;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import com.microservices.zone.utils.ZoneGitLinkRequestUrl;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -43,6 +47,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 特色专区会员Service业务层处理
|
||||
|
|
@ -68,8 +73,16 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
@Autowired
|
||||
private IZoneDetailService zoneDetailService;
|
||||
@Autowired
|
||||
private IZonePointsAccountService zonePointsAccountService;
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsApplyMapper zonePointsApplyMapper;
|
||||
|
||||
@Value("${zone.invitationLinkExpirationTime}")
|
||||
private Long invitationLinkExpirationTime;
|
||||
@Value("${zone.invitationPagePath}")
|
||||
|
|
@ -116,6 +129,26 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
return PageUtils.toPage(zoneMemberList, this::toZoneMemberDetailVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询特色专区已审核会员列表(公开接口)
|
||||
* 不做数据范围过滤,分页由调用方通过 PageHelper 设置。
|
||||
*
|
||||
* @param zoneMemberSearchVo 特色专区会员查询对象
|
||||
* @return 特色专区会员集合
|
||||
*/
|
||||
@Override
|
||||
public GenericsTableDataInfo<ZoneMemberDataVo> selectOpenZoneMemberList(ZoneMemberSearchVo zoneMemberSearchVo) {
|
||||
zoneMemberSearchVo.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
|
||||
zoneMemberSearchVo.setIsOpen(true);
|
||||
List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo);
|
||||
return PageUtils.toPage(zoneMemberList, this::toOpenZoneMemberDataVo);
|
||||
}
|
||||
|
||||
private ZoneMemberDataVo toOpenZoneMemberDataVo(ZoneMember zoneMember) {
|
||||
String login = zoneMember.getSysUser() != null ? zoneMember.getSysUser().getUserName() : null;
|
||||
return zoneMember.toZoneMemberDataVo(login);
|
||||
}
|
||||
|
||||
private ZoneMemberDetailVo toZoneMemberDetailVo(ZoneMember zoneMember) {
|
||||
ZoneMemberDetailVo zoneMemberDetailVo = new ZoneMemberDetailVo();
|
||||
BeanUtils.copyProperties(zoneMember, zoneMemberDetailVo);
|
||||
|
|
@ -235,7 +268,11 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
maxSort++;
|
||||
}
|
||||
zoneMember.setSort(maxSort);
|
||||
return zoneMemberMapper.insertZoneMember(zoneMember);
|
||||
int result = zoneMemberMapper.insertZoneMember(zoneMember);
|
||||
if (ZoneConstants.MEMBER_AUDIT_PASS.equals(zoneMember.getIsAudit())) { // 新增会员审核通过创建积分账户
|
||||
zonePointsAccountService.createPointsAccountAsync(sysUser.getUserId(), zoneDetail.getId(), SecurityUtils.getUserId(), zoneMember.getDeptId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Integer setSortByOrder(ZoneMember zoneMember, Integer order) {
|
||||
|
|
@ -379,7 +416,7 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
GitLinkRequestUrl.USERS(gitLinkUserSearchVo.genQueryString())
|
||||
);
|
||||
List<JSONObject> list = result.getList("users", JSONObject.class);
|
||||
if(list==null){
|
||||
if (list == null) {
|
||||
throw new ServiceException("Gitlink用户列表获取失败");
|
||||
}
|
||||
|
||||
|
|
@ -442,7 +479,14 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
}
|
||||
redisService.deleteObject(getZoneMemberInvitationTokenKey(invitationToken));
|
||||
zoneMember.setUpdateTime(DateUtils.getNowDate());
|
||||
return zoneMemberMapper.updateZoneMember(zoneMember) > 0;
|
||||
|
||||
int result = zoneMemberMapper.updateZoneMember(zoneMember);
|
||||
|
||||
if (ZoneConstants.MEMBER_AUDIT_PASS.equals(zoneMember.getIsAudit())) { // 会员审核通过创建积分账户
|
||||
zonePointsAccountService.createPointsAccountAsync(sysUser.getUserId(), zoneMember.getZoneId(), SecurityUtils.getUserId(), zoneMember.getDeptId());
|
||||
}
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -546,7 +590,11 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
|
||||
zoneMember.setRemark(remark);
|
||||
zoneMember.setAuditTime(DateUtils.getNowDate());
|
||||
return zoneMemberMapper.updateZoneMember(zoneMember) > 0;
|
||||
boolean result = zoneMemberMapper.updateZoneMember(zoneMember) > 0;
|
||||
if (ZoneConstants.MEMBER_AUDIT_PASS.equals(zoneMember.getIsAudit())) { // 新增会员审核通过创建积分账户
|
||||
zonePointsAccountService.createPointsAccountAsync(zoneMember.getUserId(), zoneMember.getZoneId(), SecurityUtils.getUserId(), zoneMember.getDeptId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
throw new ServiceException("错误的审核状态(审核状态[" + zoneMember.getIsAudit() + "])");
|
||||
|
|
@ -626,12 +674,14 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
|
||||
private List<ZoneMemberDataVo> getZoneMemberDataVoListByZoneMember(List<ZoneMember> zoneMemberList) {
|
||||
List<ZoneMemberDataVo> zoneMemberDataVoList = new ArrayList<>();
|
||||
Long[] userIds = zoneMemberList.stream().map(ZoneMember::getUserId).toArray(Long[]::new);
|
||||
List<SysUser> sysUserList = FeignUtils.getReturnData(
|
||||
remoteUserService.postSysUserListByUserIds(userIds, SecurityConstants.INNER)
|
||||
);
|
||||
for (ZoneMember zoneMember : zoneMemberList) {
|
||||
SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserId(zoneMember.getUserId(), SecurityConstants.INNER)
|
||||
);
|
||||
if (sysUser != null) {
|
||||
ZoneMemberDataVo zoneMemberDataVo = zoneMember.toZoneMemberDataVo(sysUser.getUserName());
|
||||
if (sysUserList != null && !sysUserList.isEmpty()) {
|
||||
String username = sysUserList.stream().filter(x -> x.getUserId().equals(zoneMember.getUserId())).map(SysUser::getUserName).findFirst().orElse(null);
|
||||
ZoneMemberDataVo zoneMemberDataVo = zoneMember.toZoneMemberDataVo(username);
|
||||
zoneMemberDataVoList.add(zoneMemberDataVo);
|
||||
}
|
||||
}
|
||||
|
|
@ -667,7 +717,11 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
zoneMember.setDeptId(zoneDetail.getDeptId());
|
||||
zoneMember.setCreateTime(DateUtils.getNowDate());
|
||||
zoneMember.setIsHomepage(ZoneConstants.TRUE);
|
||||
return zoneMemberMapper.insertZoneMember(zoneMember);
|
||||
int result = zoneMemberMapper.insertZoneMember(zoneMember);
|
||||
if (ZoneConstants.MEMBER_AUDIT_PASS.equals(zoneMember.getIsAudit())) { // 新增会员审核通过创建积分账户
|
||||
zonePointsAccountService.createPointsAccountAsync(sysUser.getUserId(), zoneDetail.getId(), SecurityUtils.getUserId(), zoneMember.getDeptId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -688,6 +742,48 @@ public class ZoneMemberServiceImpl implements IZoneMemberService {
|
|||
return auditStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZoneMember selectZoneMemberInfo(Long zoneId) {
|
||||
Long currentUserId = SecurityUtils.getUserId();
|
||||
ZoneMember zoneMember = zoneMemberMapper.selectZoneMemberInfoByZoneIdAndUserId(zoneId, currentUserId);
|
||||
if (zoneMember != null) {
|
||||
// 查询证书兑换积分流水(取一条)
|
||||
ZonePointsTransaction pointsEvent = zonePointsTransactionMapper.selectPointsTransactionOne(
|
||||
zoneId, currentUserId, "certificateRedeem");
|
||||
zoneMember.setPointsEvent(pointsEvent);
|
||||
// 查询待处理的积分申请列表
|
||||
ZonePointsApplySearchVo applySearchVo = new ZonePointsApplySearchVo();
|
||||
applySearchVo.setZoneId(zoneId);
|
||||
applySearchVo.setUserId(currentUserId);
|
||||
applySearchVo.setStatus("pending");
|
||||
zoneMember.setApplyList(zonePointsApplyMapper.selectZonePointsApplyList(applySearchVo));
|
||||
}
|
||||
return zoneMember;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateZoneMemberByMember(Long zoneId, ZoneMemberUpdateVo zoneMemberUpdateVo) {
|
||||
Long currentUserId = SecurityUtils.getUserId();
|
||||
ZoneMember oldZoneMember = zoneMemberMapper.selectZoneMember(zoneId, currentUserId, null);
|
||||
if (oldZoneMember == null) {
|
||||
throw new ServiceException("该用户在专区中不存在会员信息");
|
||||
}
|
||||
if (zoneMemberUpdateVo.getMemberTypeId() != null) {
|
||||
zoneMemberTypeService.selectZoneMemberTypeByIdAndZoneId(zoneMemberUpdateVo.getMemberTypeId(), zoneId);
|
||||
}
|
||||
if (zoneMemberUpdateVo.getMemberLevelId() != null) {
|
||||
zoneMemberLevelService.selectZoneMemberLevelByIdAndZoneId(zoneMemberUpdateVo.getMemberLevelId(), zoneId);
|
||||
}
|
||||
ZoneMember zoneMember = zoneMemberUpdateVo.toZoneMember(oldZoneMember.getId());
|
||||
if (zoneMemberUpdateVo.getOrder() != null) {
|
||||
Integer setSort = setSortByOrder(oldZoneMember, zoneMemberUpdateVo.getOrder());
|
||||
zoneMember.setSort(setSort);
|
||||
}
|
||||
zoneMember.setUpdateTime(DateUtils.getNowDate());
|
||||
zoneMember.setUpdateBy(SecurityUtils.getUsername());
|
||||
return zoneMemberMapper.updateZoneMember(zoneMember);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer selectZoneMemberAuditCount(ZoneMemberSearchVo zoneMemberSearchVo) {
|
||||
return zoneMemberMapper.selectAuditZoneMemberCount(zoneMemberSearchVo);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.microservices.zone.detail.service.IZoneDetailService;
|
|||
import com.microservices.zone.member.domain.ZoneMember;
|
||||
import com.microservices.zone.member.domain.ZoneMemberType;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberSearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberTypeCountVo;
|
||||
import com.microservices.zone.member.domain.vo.ZoneMemberTypeUpdateVo;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberMapper;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberTypeMapper;
|
||||
|
|
@ -20,7 +21,9 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -67,6 +70,37 @@ public class ZoneMemberTypeServiceImpl implements IZoneMemberTypeService {
|
|||
return zoneMemberTypeMapper.selectZoneMemberTypeList(zoneMemberType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询特色专区会员分类列表(含各分类下已审核会员数量)
|
||||
*
|
||||
* @param zoneId 专区Id
|
||||
* @param name 会员分类名称(模糊搜索,可为空)
|
||||
* @return 会员分类集合(含已审核会员数量)
|
||||
*/
|
||||
@Override
|
||||
public List<ZoneMemberTypeCountVo> selectZoneMemberTypeListWithCount(Long zoneId, String name) {
|
||||
ZoneMemberType query = new ZoneMemberType();
|
||||
query.setZoneId(zoneId);
|
||||
query.setName(name);
|
||||
List<ZoneMemberType> zoneMemberTypeList = zoneMemberTypeMapper.selectZoneMemberTypeList(query);
|
||||
if (zoneMemberTypeList == null || zoneMemberTypeList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Map<Long, Long> countMap = zoneMemberMapper.selectAuditedMemberCountByType(zoneId).stream()
|
||||
.collect(Collectors.toMap(ZoneMemberTypeCountVo::getId, ZoneMemberTypeCountVo::getMemberCount));
|
||||
List<ZoneMemberTypeCountVo> result = new ArrayList<>(zoneMemberTypeList.size());
|
||||
for (ZoneMemberType zoneMemberType : zoneMemberTypeList) {
|
||||
ZoneMemberTypeCountVo vo = new ZoneMemberTypeCountVo();
|
||||
vo.setId(zoneMemberType.getId());
|
||||
vo.setName(zoneMemberType.getName());
|
||||
vo.setIntroduction(zoneMemberType.getIntroduction());
|
||||
vo.setSort(zoneMemberType.getSort());
|
||||
vo.setMemberCount(countMap.getOrDefault(zoneMemberType.getId(), 0L));
|
||||
result.add(vo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增特色专区会员类别
|
||||
*
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,164 @@
|
|||
package com.microservices.zone.member.service.impl;
|
||||
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.core.utils.PageUtils;
|
||||
import com.microservices.common.core.utils.html.EscapeUtil;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.common.datascope.annotation.DataScope;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.zone.detail.service.IZoneDetailService;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsApply;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyDetailVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyInputVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplySearchVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsApplyUpdateVo;
|
||||
import com.microservices.zone.member.mapper.ZonePointsApplyMapper;
|
||||
import com.microservices.zone.member.service.IZonePointsApplyService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 积分申请表Service业务层处理
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Service
|
||||
public class ZonePointsApplyServiceImpl implements IZonePointsApplyService {
|
||||
@Autowired
|
||||
private ZonePointsApplyMapper zonePointsApplyMapper;
|
||||
|
||||
@Autowired
|
||||
private IZoneDetailService zoneDetailService;
|
||||
|
||||
@Value("${http.gitLinkUrl}")
|
||||
private String gitLinkUrl;
|
||||
|
||||
/**
|
||||
* 查询积分申请
|
||||
*
|
||||
* @param id 积分申请主键
|
||||
* @return 积分申请
|
||||
*/
|
||||
@Override
|
||||
public ZonePointsApply selectZonePointsApplyById(Long id) {
|
||||
ZonePointsApply zonePointsApply = zonePointsApplyMapper.selectZonePointsApplyById(id);
|
||||
if (zonePointsApply == null) {
|
||||
throw new ServiceException("该积分申请不存在或无权限访问(积分申请id[" + id + "])");
|
||||
}
|
||||
zoneDetailService.checkZoneDataScope(zonePointsApply.getZoneId());
|
||||
return zonePointsApply;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询积分申请列表
|
||||
*
|
||||
* @param zonePointsApply 积分申请
|
||||
* @return 积分申请
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "zpa")
|
||||
public GenericsTableDataInfo<ZonePointsApplyDetailVo> selectZonePointsApplyList(ZonePointsApplySearchVo searchVo) {
|
||||
List<ZonePointsApply> list = zonePointsApplyMapper.selectZonePointsApplyList(searchVo);
|
||||
return PageUtils.toPage(list, this::toZonePointsApplyDetailVo);
|
||||
}
|
||||
|
||||
private ZonePointsApplyDetailVo toZonePointsApplyDetailVo(ZonePointsApply zonePointsApply) {
|
||||
ZonePointsApplyDetailVo vo = new ZonePointsApplyDetailVo();
|
||||
BeanUtils.copyProperties(zonePointsApply, vo);
|
||||
if (zonePointsApply.getSysUser() != null) {
|
||||
String username = zonePointsApply.getSysUser().getUserName();
|
||||
vo.setUserName(username);
|
||||
vo.setGitLinkUserUrl(
|
||||
EscapeUtil.removeExtraSlashOfUrl(
|
||||
gitLinkUrl + "/" + username
|
||||
));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增积分申请
|
||||
*
|
||||
* @param inputVo 积分申请
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertZonePointsApply(ZonePointsApplyInputVo inputVo) {
|
||||
ZonePointsApply zonePointsApply = inputVo.toZonePointsApply();
|
||||
zonePointsApply.setCreateTime(DateUtils.getNowDate());
|
||||
zonePointsApply.setCreateBy(SecurityUtils.getUsername());
|
||||
return zonePointsApplyMapper.insertZonePointsApply(zonePointsApply);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改积分申请
|
||||
*
|
||||
* @param updateVo 积分申请
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateZonePointsApply(ZonePointsApplyUpdateVo updateVo) {
|
||||
ZonePointsApply oldApply = selectZonePointsApplyById(updateVo.getId());
|
||||
ZonePointsApply zonePointsApply = updateVo.toZonePointsApply();
|
||||
zonePointsApply.setUpdateTime(DateUtils.getNowDate());
|
||||
zonePointsApply.setUpdateBy(SecurityUtils.getUsername());
|
||||
return zonePointsApplyMapper.updateZonePointsApply(zonePointsApply);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除积分申请
|
||||
*
|
||||
* @param ids 需要删除的积分申请主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteZonePointsApplyByIds(Long[] ids) {
|
||||
int success = 0;
|
||||
for (Long id : ids) {
|
||||
success += deleteZonePointsApplyById(id);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除积分申请信息
|
||||
*
|
||||
* @param id 积分申请主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteZonePointsApplyById(Long id) {
|
||||
selectZonePointsApplyById(id);
|
||||
return zonePointsApplyMapper.deleteZonePointsApplyById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询积分申请列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 积分申请列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZonePointsApply> selectZonePointsApplyByUserIdAndZoneId(Long userId, Long zoneId) {
|
||||
return zonePointsApplyMapper.selectZonePointsApplyByUserIdAndZoneId(userId, zoneId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否有某类型的待处理申请(幂等校验)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @param applyType 申请类型
|
||||
* @return true=已有待处理申请
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPendingApply(Long userId, Long zoneId, String applyType) {
|
||||
return zonePointsApplyMapper.countPendingByUserZoneAndType(userId, zoneId, applyType) > 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
package com.microservices.zone.member.service.impl;
|
||||
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.datascope.annotation.DataScope;
|
||||
import com.microservices.zone.detail.service.IZoneDetailService;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsTransaction;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionInputVo;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionUpdateVo;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.IZonePointsTransactionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专区积分流水Service业务层处理(合并事件+流水)
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Service
|
||||
public class ZonePointsTransactionServiceImpl implements IZonePointsTransactionService {
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
@Autowired
|
||||
private IZoneDetailService zoneDetailService;
|
||||
|
||||
/**
|
||||
* 查询专区积分流水
|
||||
*
|
||||
* @param id 专区积分流水主键
|
||||
* @return 专区积分流水
|
||||
*/
|
||||
@Override
|
||||
public ZonePointsTransaction selectZonePointsTransactionById(Long id) {
|
||||
ZonePointsTransaction zonePointsTransaction = zonePointsTransactionMapper.selectZonePointsTransactionById(id);
|
||||
if (zonePointsTransaction == null) {
|
||||
throw new ServiceException("该积分流水不存在或无权限访问(积分流水id[" + id + "])");
|
||||
}
|
||||
return zonePointsTransaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询专区积分流水列表
|
||||
*
|
||||
* @param zonePointsTransaction 专区积分流水
|
||||
* @return 专区积分流水
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "zpt")
|
||||
public List<ZonePointsTransaction> selectZonePointsTransactionList(ZonePointsTransaction zonePointsTransaction) {
|
||||
return zonePointsTransactionMapper.selectZonePointsTransactionList(zonePointsTransaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增专区积分流水
|
||||
*
|
||||
* @param inputVo 专区积分流水
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertZonePointsTransaction(ZonePointsTransactionInputVo inputVo) {
|
||||
ZonePointsTransaction zonePointsTransaction = inputVo.toZonePointsTransaction();
|
||||
zonePointsTransaction.setCreateTime(DateUtils.getNowDate());
|
||||
return zonePointsTransactionMapper.insertZonePointsTransaction(zonePointsTransaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改专区积分流水
|
||||
*
|
||||
* @param updateVo 专区积分流水
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateZonePointsTransaction(ZonePointsTransactionUpdateVo updateVo) {
|
||||
selectZonePointsTransactionById(updateVo.getId());
|
||||
ZonePointsTransaction zonePointsTransaction = updateVo.toZonePointsTransaction();
|
||||
return zonePointsTransactionMapper.updateZonePointsTransaction(zonePointsTransaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除专区积分流水信息
|
||||
*
|
||||
* @param id 专区积分流水主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteZonePointsTransactionById(Long id) {
|
||||
selectZonePointsTransactionById(id);
|
||||
return zonePointsTransactionMapper.deleteZonePointsTransactionById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据事件ID查询流水列表
|
||||
*
|
||||
* @param eventId 事件ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZonePointsTransaction> selectZonePointsTransactionByEventId(String eventId) {
|
||||
return zonePointsTransactionMapper.selectZonePointsTransactionByEventId(eventId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据账户ID查询流水列表
|
||||
*
|
||||
* @param accountId 积分账户ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZonePointsTransaction> selectZonePointsTransactionByAccountId(Long accountId) {
|
||||
return zonePointsTransactionMapper.selectZonePointsTransactionByAccountId(accountId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和专区ID查询流水列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZonePointsTransaction> selectZonePointsTransactionByUserIdAndZoneId(Long userId, Long zoneId) {
|
||||
return zonePointsTransactionMapper.selectZonePointsTransactionByUserIdAndZoneId(userId, zoneId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据专区ID获取当前用户积分明细(分页)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param userId 用户ID
|
||||
* @param transactionType 交易类型(可选)
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "zpt")
|
||||
public List<ZonePointsTransaction> selectMyPointsTransactionDetailsByZone(Long zoneId, Long userId, String transactionType) {
|
||||
return zonePointsTransactionMapper.selectMyPointsTransactionDetailsByZone(zoneId, userId, transactionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户流水列表(合并后直接从流水表查询,所有业务字段已包含)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param zoneId 专区ID
|
||||
* @return 专区积分流水列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZonePointsTransaction> selectCurrentUserTransactionWithEvent(Long userId, Long zoneId) {
|
||||
return zonePointsTransactionMapper.selectCurrentUserTransactionWithEvent(userId, zoneId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.microservices.zone.member.service.points;
|
||||
|
||||
/**
|
||||
* 积分异步任务处理器接口 —— 策略模式
|
||||
* <p>
|
||||
* 每种积分来源类型对应一个实现类,负责该类型任务的完整处理逻辑。
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
public interface IPointsTaskHandler {
|
||||
|
||||
/**
|
||||
* 返回该处理器负责的任务来源类型
|
||||
*
|
||||
* @return sourceType 常量值
|
||||
*/
|
||||
String getSourceType();
|
||||
|
||||
/**
|
||||
* 执行积分任务处理
|
||||
*
|
||||
* @param ctx 任务上下文
|
||||
*/
|
||||
void handle(PointsTaskContext ctx);
|
||||
}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
package com.microservices.zone.member.service.points;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.utils.uuid.IdUtils;
|
||||
import com.microservices.zone.detail.service.IZoneDetailService;
|
||||
import com.microservices.zone.member.domain.ZoneMember;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.domain.vo.ZonePointsTransactionInputVo;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.service.IZonePointsTransactionService;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 积分账户共享操作组件 —— 提供 getOrCreateAccount、recordPointsTransaction、createPointsAccountTask
|
||||
* 供各策略处理器及原有 Service 复用,避免重复代码。
|
||||
* <p>
|
||||
* 合并后只写 zone_points_transaction 单表,不再写 zone_points_event。
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class PointsAccountOperations {
|
||||
private static final Logger logger = LoggerFactory.getLogger(PointsAccountOperations.class);
|
||||
|
||||
/** 无操作人标识(如系统自动创建账户时没有具体操作人) */
|
||||
private static final Long NO_OPERATOR = 0L;
|
||||
|
||||
@Autowired
|
||||
private ZoneMemberMapper zoneMemberMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private IZoneDetailService zoneDetailService;
|
||||
|
||||
@Autowired
|
||||
private IZonePointsTransactionService zonePointsTransactionService;
|
||||
|
||||
/**
|
||||
* 获取或创建积分账户(仅对已审核通过的专区会员有效)
|
||||
*/
|
||||
public ZonePointsAccount getOrCreateAccount(Long userId, Long zoneId) {
|
||||
ZoneMember member = zoneMemberMapper.selectZoneMember(zoneId, userId, null);
|
||||
if (member == null || !ZoneConstants.MEMBER_AUDIT_PASS.equals(member.getIsAudit())) {
|
||||
logger.warn("积分-账户操作:当前用户不是专区会员 userId={} zoneId={}", userId, zoneId);
|
||||
return null;
|
||||
}
|
||||
ZonePointsAccount account = zonePointsAccountMapper.selectZonePointsAccountByUserIdAndZoneId(userId, zoneId);
|
||||
if (account != null) {
|
||||
return account;
|
||||
}
|
||||
return doCreatePointsAccount(userId, zoneId, NO_OPERATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建积分账户并记录初始流水(新会员审核通过时调用)
|
||||
* <p>
|
||||
* 具备幂等保护:若账户已存在则直接返回已有账户,避免重复创建和重复发放积分。
|
||||
*/
|
||||
public ZonePointsAccount createPointsAccountTask(Long userId, Long zoneId, Long operatorId) {
|
||||
// 幂等保护:检查是否已存在相同用户和专区的积分账户
|
||||
ZonePointsAccount existAccount = zonePointsAccountMapper.selectZonePointsAccountByUserIdAndZoneId(userId, zoneId);
|
||||
if (existAccount != null) {
|
||||
logger.info("积分-创建账号:积分账户已存在,跳过创建 userId={} zoneId={} accountId={}", userId, zoneId, existAccount.getId());
|
||||
return existAccount;
|
||||
}
|
||||
return doCreatePointsAccount(userId, zoneId, operatorId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建积分账户并记录初始流水(无幂等检查,调用方需确保账户不存在)
|
||||
*/
|
||||
private ZonePointsAccount doCreatePointsAccount(Long userId, Long zoneId, Long operatorId) {
|
||||
ZonePointsAccount zonePointsAccount = new ZonePointsAccount();
|
||||
zonePointsAccount.setUserId(userId);
|
||||
zonePointsAccount.setZoneId(zoneId);
|
||||
zonePointsAccount.setTotalPoints(ZoneConstants.MemberAudit.POINTS);
|
||||
zonePointsAccount.setTotalEarnedPoints(ZoneConstants.MemberAudit.POINTS);
|
||||
zonePointsAccount.setTotalConsumedPoints(0);
|
||||
zonePointsAccount.setAvailablePoints(ZoneConstants.MemberAudit.POINTS);
|
||||
zonePointsAccount.setFrozenPoints(0);
|
||||
zonePointsAccount.setDeptId(zoneDetailService.selectZoneDetailById(zoneId).getDeptId());
|
||||
zonePointsAccount.setCreateTime(DateUtils.getNowDate());
|
||||
zonePointsAccount.setCreateBy("system");
|
||||
zonePointsAccountMapper.insertZonePointsAccount(zonePointsAccount);
|
||||
|
||||
Long finalOperatorId = operatorId != null ? operatorId : NO_OPERATOR;
|
||||
recordPointsTransaction(zonePointsAccount.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.MemberAudit.POINTS,
|
||||
ZoneConstants.MemberAudit.POINTS, 0,
|
||||
String.format(ZoneConstants.MemberAudit.REASON_TEMPLATE, ZoneConstants.MemberAudit.POINTS),
|
||||
finalOperatorId, null, ZoneConstants.MemberAudit.SOURCE_TYPE, null,
|
||||
ZoneConstants.MemberAudit.SUBJECT, ZoneConstants.MemberAudit.SUBJECT_DESC, null);
|
||||
|
||||
return zonePointsAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录积分变动(写入 zone_points_transaction 单表,合并了原 event + transaction 两张表),内部自动生成 eventId
|
||||
*/
|
||||
public void recordPointsTransaction(Long accountId,
|
||||
String transactionType, int points,
|
||||
int availableAfter, int frozenAfter,
|
||||
String reason, Long operatorId, Long sourceId,
|
||||
String sourceType, String sourceData,
|
||||
String subject, String subjectDesc,
|
||||
String replyContent) {
|
||||
recordPointsTransaction(accountId, transactionType, points,
|
||||
availableAfter, frozenAfter, reason, operatorId, sourceId,
|
||||
sourceType, sourceData, subject, subjectDesc, replyContent, IdUtils.simpleUUID());
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录积分变动(写入 zone_points_transaction 单表),使用指定的 eventId
|
||||
* <p>
|
||||
* 适用于需要在外部持有 eventId 的场景(如冻结操作需要将 eventId 存入申请记录)
|
||||
*/
|
||||
public void recordPointsTransaction(Long accountId,
|
||||
String transactionType, int points,
|
||||
int availableAfter, int frozenAfter,
|
||||
String reason, Long operatorId, Long sourceId,
|
||||
String sourceType, String sourceData,
|
||||
String subject, String subjectDesc,
|
||||
String replyContent,
|
||||
String eventId) {
|
||||
ZonePointsTransactionInputVo inputVo = new ZonePointsTransactionInputVo();
|
||||
inputVo.setEventId(eventId);
|
||||
inputVo.setEventType(sourceType);
|
||||
inputVo.setAccountId(accountId);
|
||||
inputVo.setTransactionType(transactionType);
|
||||
inputVo.setPoints(points);
|
||||
inputVo.setAvailableAfter(availableAfter);
|
||||
inputVo.setFrozenAfter(frozenAfter);
|
||||
inputVo.setOperatorId(operatorId);
|
||||
inputVo.setReason(reason);
|
||||
inputVo.setReplyContent(replyContent);
|
||||
inputVo.setSourceId(sourceId);
|
||||
inputVo.setSourceData(sourceData);
|
||||
inputVo.setSubject(subject);
|
||||
inputVo.setSubjectDesc(subjectDesc);
|
||||
zonePointsTransactionService.insertZonePointsTransaction(inputVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅记录积分流水(不设置事件业务字段,适用于已有事件的补充流水,如驳回/通过申请时只需补充流水)
|
||||
*
|
||||
* @param eventId 关联的已有事件ID
|
||||
*/
|
||||
public void recordPointsTransactionOnly(Long accountId,
|
||||
String transactionType, int points,
|
||||
int availableAfter, int frozenAfter,
|
||||
Long operatorId,
|
||||
String eventId) {
|
||||
ZonePointsTransactionInputVo inputVo = new ZonePointsTransactionInputVo();
|
||||
inputVo.setEventId(eventId);
|
||||
inputVo.setAccountId(accountId);
|
||||
inputVo.setTransactionType(transactionType);
|
||||
inputVo.setPoints(points);
|
||||
inputVo.setAvailableAfter(availableAfter);
|
||||
inputVo.setFrozenAfter(frozenAfter);
|
||||
inputVo.setOperatorId(operatorId);
|
||||
zonePointsTransactionService.insertZonePointsTransaction(inputVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 补齐上下文中的 zoneId(供来自 CMS 模块的任务使用,CMS 侧任务不携带 zoneId)
|
||||
* <p>
|
||||
* 原为各 Handler 中的重复代码,抽取至此公共组件统一维护。
|
||||
*/
|
||||
public void resolveZoneId(PointsTaskContext ctx) {
|
||||
if (ctx.getZoneId() != null) {
|
||||
return;
|
||||
}
|
||||
if (ctx.getDeptId() == null) {
|
||||
logger.warn("积分-{}:zoneId 和 deptId 均为空,无法确定专区 userId={} sourceId={}",
|
||||
ctx.getSourceType(), ctx.getUserId(), ctx.getSourceId());
|
||||
return;
|
||||
}
|
||||
String zoneJson = zoneDetailService.getZoneJSONByDeptId(ctx.getDeptId());
|
||||
if (StringUtils.isEmpty(zoneJson)) {
|
||||
logger.warn("积分-{}:通过 deptId={} 未找到关联专区", ctx.getSourceType(), ctx.getDeptId());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JSONObject zoneObj = JSON.parseObject(zoneJson);
|
||||
Long zoneId = zoneObj.getLong("id");
|
||||
if (zoneId == null) {
|
||||
logger.warn("积分-{}:解析专区 JSON 未获取到 id deptId={}", ctx.getSourceType(), ctx.getDeptId());
|
||||
return;
|
||||
}
|
||||
ctx.setZoneId(zoneId);
|
||||
} catch (Exception e) {
|
||||
logger.error("积分-{}:解析专区 JSON 失败 deptId={} zoneJson={}",
|
||||
ctx.getSourceType(), ctx.getDeptId(), zoneJson, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.microservices.zone.member.service.points;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 积分异步任务处理上下文,封装队列中任务的通用字段
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class PointsTaskContext {
|
||||
|
||||
/** 任务来源类型,对应 ZoneConstants 中的 SOURCE_TYPE */
|
||||
private String sourceType;
|
||||
|
||||
/** 用户ID */
|
||||
private Long userId;
|
||||
|
||||
/** 专区ID */
|
||||
private Long zoneId;
|
||||
|
||||
/** 所属组织ID */
|
||||
private Long deptId;
|
||||
|
||||
/** 来源ID(如文章ID、资源ID) */
|
||||
private Long sourceId;
|
||||
|
||||
/** 来源数据(JSON 字符串) */
|
||||
private String sourceData;
|
||||
|
||||
/** 主题描述 */
|
||||
private String subjectDesc;
|
||||
|
||||
/** 操作人ID */
|
||||
private Long operatorId;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 会员入会审核通过 — 创建积分账户
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class CreateAccountPointsHandler implements IPointsTaskHandler {
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.MemberAudit.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
pointsAccountOperations.createPointsAccountTask(ctx.getUserId(), ctx.getZoneId(), ctx.getOperatorId());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
|
||||
import java.util.Date;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 每日首次访问专区 — 积分奖励
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class DailyVisitPointsHandler implements IPointsTaskHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DailyVisitPointsHandler.class);
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.DailyVisit.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
String redisKey = ZoneConstants.ZONE_DAILY_FIRST_VISIT_KEY + ctx.getZoneId() + ":" + ctx.getUserId();
|
||||
String counterKey = redisKey + ":counter";
|
||||
|
||||
// 幂等检查:counter 必须存在(由 addDailyVisitPointsAsync 的 setIfAbsent 设置)
|
||||
Object counter = redisTemplate.opsForValue().get(counterKey);
|
||||
if (counter == null) {
|
||||
logger.info("积分-每日登录:防重key不存在,跳过处理 userId={} zoneId={}", ctx.getUserId(), ctx.getZoneId());
|
||||
return;
|
||||
}
|
||||
// counter > 1 表示本任务已成功处理过(参见下方 increment),防止重试时重复发放积分
|
||||
if (Long.parseLong(counter.toString()) > 1) {
|
||||
logger.info("积分-每日登录:任务已处理,跳过重试 userId={} zoneId={}", ctx.getUserId(), ctx.getZoneId());
|
||||
return;
|
||||
}
|
||||
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询今日是否已触发过登录积分(SQL 层限定日期范围,避免 order by create_time desc 被未来脏数据干扰)
|
||||
Date now = new Date();
|
||||
Date startOfDay = DateUtils.getZeroDate(now);
|
||||
Date endOfDay = DateUtils.addDays(startOfDay, 1);
|
||||
if (zonePointsTransactionMapper.countByAccountIdAndEventTypeAndDateRange(
|
||||
account.getId(), ZoneConstants.DailyVisit.SOURCE_TYPE, startOfDay, endOfDay) > 0) {
|
||||
logger.info("积分-每日登录:今日已发放过积分,跳过 userId={} zoneId={}", ctx.getUserId(), ctx.getZoneId());
|
||||
return;
|
||||
}
|
||||
|
||||
// 锁定行并读取最新值
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
int availableAfter = locked.getAvailablePoints() + ZoneConstants.DailyVisit.POINTS;
|
||||
int frozenAfter = locked.getFrozenPoints();
|
||||
|
||||
// 原子增加积分
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.DailyVisit.POINTS);
|
||||
|
||||
// 记录积分流水
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.DailyVisit.POINTS,
|
||||
availableAfter, frozenAfter,
|
||||
String.format(ZoneConstants.DailyVisit.REASON_TEMPLATE, ZoneConstants.DailyVisit.POINTS),
|
||||
0L, null, ZoneConstants.DailyVisit.SOURCE_TYPE, null,
|
||||
ZoneConstants.DailyVisit.SUBJECT, ZoneConstants.DailyVisit.SUBJECT_DESC, null);
|
||||
|
||||
// 递增 counter 实现幂等标记,防止任务重试时重复发放积分。
|
||||
// 放在所有 DB 操作之后:若此前任一步骤抛异常,事务回滚,counter 保持 "1",
|
||||
// 重试时仍可正常发放积分;只有全部成功后才将 counter 变为 "2",后续重试会被上方 >1 检查拦截。
|
||||
// increment 保留 key 原有的 TTL,次日零点自动过期,不影响新一天的积分领取。
|
||||
try {
|
||||
redisTemplate.opsForValue().increment(counterKey);
|
||||
logger.info("积分-每日登录:积分发放成功 userId={} zoneId={} accountId={} points={}",
|
||||
ctx.getUserId(), ctx.getZoneId(), account.getId(), ZoneConstants.DailyVisit.POINTS);
|
||||
} catch (Exception e) {
|
||||
// Redis increment 失败不影响主流程(积分已发放),仅记录日志。
|
||||
// 极端情况下若任务被重试且 counter 未递增,可能会重复发放积分,
|
||||
// 但概率极低且 DB 流水可审计追溯。
|
||||
logger.warn("积分-每日登录:counter递增失败,不影响积分发放。若任务重试可能重复发放 userId={} zoneId={}",
|
||||
ctx.getUserId(), ctx.getZoneId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.system.api.RemoteCmsService;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsDoc;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsDocMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 文章浏览阅读量奖励 — 每满 100 次阅读触发积分
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class DocVisitsPointsHandler implements IPointsTaskHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DocVisitsPointsHandler.class);
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsDocMapper zonePointsDocMapper;
|
||||
|
||||
@Autowired
|
||||
private RemoteCmsService remoteCmsService;
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.DocVisits.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
// CMS 侧写入任务时不携带 zoneId,需通过 deptId 解析补齐
|
||||
pointsAccountOperations.resolveZoneId(ctx);
|
||||
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int totalVisits = 0;
|
||||
if (StringUtils.isNotEmpty(ctx.getSourceData())) {
|
||||
totalVisits = Integer.parseInt(ctx.getSourceData());
|
||||
}
|
||||
|
||||
ZonePointsDoc pointsDoc = zonePointsDocMapper.selectZonePointsDocByZoneIdAndDocId(ctx.getZoneId(), ctx.getSourceId());
|
||||
if (pointsDoc == null) {
|
||||
// 首次触发:创建记录
|
||||
ZonePointsDoc newDoc = new ZonePointsDoc();
|
||||
newDoc.setZoneId(ctx.getZoneId());
|
||||
newDoc.setDocId(ctx.getSourceId());
|
||||
newDoc.setPointsStartVisits(totalVisits - 1);
|
||||
newDoc.setPointsTriggerCount(0);
|
||||
newDoc.setUserId(ctx.getUserId());
|
||||
newDoc.setCreateTime(DateUtils.getNowDate());
|
||||
zonePointsDocMapper.insertZonePointsDoc(newDoc);
|
||||
} else {
|
||||
if (pointsDoc.getPointsTriggerCount() >= ZoneConstants.DocVisits.MAX_TRIGGER_COUNT) {
|
||||
logger.info("积分-文章浏览:已达触发上限 zoneId={} docId={} triggerCount={}",
|
||||
ctx.getZoneId(), ctx.getSourceId(), pointsDoc.getPointsTriggerCount());
|
||||
return;
|
||||
}
|
||||
|
||||
int startVisits = pointsDoc.getPointsStartVisits() != null ? pointsDoc.getPointsStartVisits() : 0;
|
||||
boolean needUpdateStartVisits = false;
|
||||
if (pointsDoc.getPointsStartVisits() == null) {
|
||||
try {
|
||||
JSONObject cmsDoc = remoteCmsService.selectCmsDocJSONObjectById(ctx.getSourceId(), SecurityConstants.INNER).getData();
|
||||
if (cmsDoc != null && cmsDoc.getLong("visits") != null) {
|
||||
startVisits = cmsDoc.getLong("visits").intValue();
|
||||
needUpdateStartVisits = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("积分-文章浏览:远程查询cms_doc失败,跳过此次积分 userId={} docId={} error={}",
|
||||
ctx.getUserId(), ctx.getSourceId(), e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果通过远程查询获取到了cms_doc的visits,则同步更新到数据库
|
||||
if (needUpdateStartVisits) {
|
||||
pointsDoc.setPointsStartVisits(startVisits);
|
||||
zonePointsDocMapper.updateZonePointsDoc(pointsDoc);
|
||||
}
|
||||
|
||||
int currentVisits = totalVisits - startVisits;
|
||||
int totalExpected = currentVisits / ZoneConstants.DocVisits.TRIGGER_VISITS;
|
||||
|
||||
if (totalExpected > pointsDoc.getPointsTriggerCount()) {
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
int availableAfter = locked.getAvailablePoints() + ZoneConstants.DocVisits.POINTS_PER_TRIGGER;
|
||||
int frozenAfter = locked.getFrozenPoints();
|
||||
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.DocVisits.POINTS_PER_TRIGGER);
|
||||
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.DocVisits.POINTS_PER_TRIGGER,
|
||||
availableAfter, frozenAfter,
|
||||
String.format(ZoneConstants.DocVisits.REASON_TEMPLATE, ZoneConstants.DocVisits.POINTS_PER_TRIGGER, pointsDoc.getPointsTriggerCount() * 2 + 2),
|
||||
0L, ctx.getSourceId(), ZoneConstants.DocVisits.SOURCE_TYPE, null,
|
||||
ZoneConstants.DocVisits.SUBJECT,
|
||||
String.format(ZoneConstants.DocVisits.SUBJECT_DESC_TEMPLATE, ctx.getSubjectDesc(), totalVisits), null);
|
||||
|
||||
zonePointsDocMapper.incrementTriggerCount(pointsDoc.getId(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.common.core.constant.CacheConstants;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
import com.microservices.zone.detail.service.IZoneDetailService;
|
||||
import com.microservices.zone.member.domain.ZoneMember;
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.detail.domain.vo.ZoneFrontRoleVo;
|
||||
import com.microservices.zone.member.mapper.ZoneMemberMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.resource.domain.ZoneResource;
|
||||
import com.microservices.zone.resource.mapper.ZoneResourceMapper;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 资源下载 — 作者获得积分奖励
|
||||
* <p>
|
||||
* 触发条件(全部满足才发放):
|
||||
* <ol>
|
||||
* <li>文件关联的资源存在且审核通过</li>
|
||||
* <li>该资源累计获得积分未达上限(应用层检查 + DB 层原子约束双重保护)</li>
|
||||
* <li>所属专区为积分专区</li>
|
||||
* <li>资源作者是专区审核通过的普通会员(Member),管理员不发放积分</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class DownloadResourcePointsHandler implements IPointsTaskHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DownloadResourcePointsHandler.class);
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZoneResourceMapper zoneResourceMapper;
|
||||
|
||||
@Autowired
|
||||
private ZoneMemberMapper zoneMemberMapper;
|
||||
|
||||
@Autowired
|
||||
private IZoneDetailService zoneDetailService;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.DownloadResource.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
List<ZoneResource> resourceList = zoneResourceMapper.selectZoneResourceListByFileId(ctx.getSourceId());
|
||||
if (resourceList == null || resourceList.isEmpty()) {
|
||||
logger.info("积分-资源下载:未找到关联资源或资源未通过审核 sourceId={}", ctx.getSourceId());
|
||||
return;
|
||||
}
|
||||
|
||||
for (ZoneResource resource : resourceList) {
|
||||
// 积分专区检查
|
||||
Long deptId = resource.getDeptId();
|
||||
Long cachedPointsDeptId = redisService.getCacheObject(CacheConstants.ZONE_POINTS_DEPT_ID_KEY);
|
||||
if (!Objects.equals(deptId, cachedPointsDeptId)) {
|
||||
logger.info("积分-资源下载:非积分专区 deptId={}", deptId);
|
||||
continue;
|
||||
}
|
||||
|
||||
String createBy = resource.getCreateBy();
|
||||
if (createBy == null) {
|
||||
logger.warn("积分-资源下载:资源作者为空 resourceId={}", resource.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 应用层积分上限检查(快速失败——DB 层有原子约束做双重保护)
|
||||
int currentEarnedPoints = resource.getEarnedPoints() != null ? resource.getEarnedPoints() : 0;
|
||||
if (currentEarnedPoints >= ZoneConstants.DownloadResource.POINTS_LIMIT) {
|
||||
logger.info("积分-资源下载:已达积分上限 resourceId={} earnedPoints={}",
|
||||
resource.getId(), currentEarnedPoints);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 通过 createBy 获取 userId(带 Redis 缓存,减少 Feign 调用)
|
||||
Long authorUserId = getUserIdByUserName(createBy);
|
||||
if (authorUserId == null) {
|
||||
logger.warn("积分-资源下载:未找到资源作者用户 createBy={}", createBy);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 角色检查:必须是普通会员(Member),管理员(Manager)不发放积分
|
||||
ZoneFrontRoleVo roleVo = zoneDetailService.checkUserRoleInZone(resource.getZoneId(), authorUserId);
|
||||
if (roleVo == null || !ZoneConstants.FRONT_ROLE_MEMBER.equals(roleVo.getRole())) {
|
||||
logger.info("积分-资源下载:作者不是普通会员,不发放积分 userId={} zoneId={} role={}",
|
||||
authorUserId, resource.getZoneId(),
|
||||
roleVo != null ? roleVo.getRole() : null);
|
||||
continue;
|
||||
}
|
||||
|
||||
addPointsForAuthor(resource.getZoneId(), authorUserId, resource.getId(), ctx.getSourceId(),
|
||||
resource.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为资源作者增加积分(核心发放逻辑——在 {@link #handle} 的事务内执行)
|
||||
*/
|
||||
private void addPointsForAuthor(Long zoneId, Long authorUserId, Long resourceId, Long sourceId,
|
||||
String resourceName) {
|
||||
// 获取或创建积分账户(含会员资质校验)
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(authorUserId, zoneId);
|
||||
if (account == null) {
|
||||
logger.warn("积分-资源下载:积分账户不存在或创建失败 authorUserId={} zoneId={}", authorUserId, zoneId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 锁定账户行(FOR UPDATE,防并发)
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
if (locked == null) {
|
||||
logger.warn("积分-资源下载:锁定积分账户失败 accountId={}", account.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// 账户积分 +1(原子操作)
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.DownloadResource.POINTS);
|
||||
|
||||
// 资源 earnedPoints +1(原子操作)
|
||||
zoneResourceMapper.addEarnedPointsAtomic(resourceId, ZoneConstants.DownloadResource.POINTS);
|
||||
|
||||
// 重新读取资源获取最新 earnedPoints(即积分触发次数)
|
||||
ZoneResource updatedResource = zoneResourceMapper.selectZoneResourceById(resourceId);
|
||||
int totalEarnedPoints = updatedResource != null && updatedResource.getEarnedPoints() != null
|
||||
? updatedResource.getEarnedPoints() : ZoneConstants.DownloadResource.POINTS;
|
||||
|
||||
// 记录流水
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.DownloadResource.POINTS,
|
||||
locked.getAvailablePoints() + ZoneConstants.DownloadResource.POINTS,
|
||||
locked.getFrozenPoints(),
|
||||
String.format(ZoneConstants.DownloadResource.REASON_TEMPLATE,
|
||||
ZoneConstants.DownloadResource.POINTS, totalEarnedPoints),
|
||||
authorUserId, sourceId, ZoneConstants.DownloadResource.SOURCE_TYPE, null,
|
||||
ZoneConstants.DownloadResource.SUBJECT,
|
||||
String.format(ZoneConstants.DownloadResource.SUBJECT_DESC_TEMPLATE,
|
||||
resourceName, String.valueOf(totalEarnedPoints)), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名获取用户ID(通过远程调用)
|
||||
*/
|
||||
private Long getUserIdByUserName(String userName) {
|
||||
try {
|
||||
SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(userName, SecurityConstants.INNER));
|
||||
if (sysUser != null) {
|
||||
return sysUser.getUserId();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("积分-资源下载:获取用户ID失败 userName={} error={}", userName, e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 文章被设为精选 — 积分奖励
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class FeaturedDocPointsHandler implements IPointsTaskHandler {
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FeaturedDocPointsHandler.class);
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.FeaturedDoc.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
// CMS 侧写入任务时不携带 zoneId,需通过 deptId 解析补齐
|
||||
pointsAccountOperations.resolveZoneId(ctx);
|
||||
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 幂等检查:同一文章被精选同一用户只发放一次
|
||||
if (zonePointsTransactionMapper.countByEventTypeAndSourceAndUser(ZoneConstants.FeaturedDoc.SOURCE_TYPE, ctx.getSourceId(), account.getId()) > 0) {
|
||||
logger.info("积分-文章精选:积分已发放,跳过 sourceId={} userId={}", ctx.getSourceId(), ctx.getUserId());
|
||||
return;
|
||||
}
|
||||
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
int availableAfter = locked.getAvailablePoints() + ZoneConstants.FeaturedDoc.POINTS;
|
||||
int frozenAfter = locked.getFrozenPoints();
|
||||
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.FeaturedDoc.POINTS);
|
||||
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.FeaturedDoc.POINTS,
|
||||
availableAfter, frozenAfter,
|
||||
ZoneConstants.FeaturedDoc.REASON, 0L, ctx.getSourceId(),
|
||||
ZoneConstants.FeaturedDoc.SOURCE_TYPE, null,
|
||||
ZoneConstants.FeaturedDoc.SUBJECT, ctx.getSubjectDesc(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 发布文章审核通过 — 积分奖励
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class PublishDocPointsHandler implements IPointsTaskHandler {
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PublishDocPointsHandler.class);
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.PublishDoc.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
// CMS 侧写入任务时不携带 zoneId,需通过 deptId 解析补齐
|
||||
pointsAccountOperations.resolveZoneId(ctx);
|
||||
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 幂等检查:同一来源同一用户只发放一次
|
||||
if (zonePointsTransactionMapper.countByEventTypeAndSourceAndUser(ZoneConstants.PublishDoc.SOURCE_TYPE, ctx.getSourceId(), account.getId()) > 0) {
|
||||
logger.info("积分-文章发布:积分已发放,跳过 sourceId={} userId={}", ctx.getSourceId(), ctx.getUserId());
|
||||
return;
|
||||
}
|
||||
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
int availableAfter = locked.getAvailablePoints() + ZoneConstants.PublishDoc.POINTS;
|
||||
int frozenAfter = locked.getFrozenPoints();
|
||||
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.PublishDoc.POINTS);
|
||||
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.PublishDoc.POINTS,
|
||||
availableAfter, frozenAfter,
|
||||
ZoneConstants.PublishDoc.REASON, ctx.getOperatorId(), ctx.getSourceId(),
|
||||
ZoneConstants.PublishDoc.SOURCE_TYPE, null,
|
||||
ZoneConstants.PublishDoc.SUBJECT,
|
||||
String.format(ZoneConstants.PublishDoc.SUBJECT_DESC_TEMPLATE, ctx.getSubjectDesc()),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 发布项目审核通过 — 积分奖励
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class PublishProjectPointsHandler implements IPointsTaskHandler {
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PublishProjectPointsHandler.class);
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.PublishProject.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
pointsAccountOperations.resolveZoneId(ctx);
|
||||
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 幂等检查:同一来源同一用户只发放一次
|
||||
if (zonePointsTransactionMapper.countByEventTypeAndSourceAndUser(ZoneConstants.PublishProject.SOURCE_TYPE, ctx.getSourceId(), account.getId()) > 0) {
|
||||
logger.info("积分-项目发布:积分已发放,跳过 sourceId={} userId={}", ctx.getSourceId(), ctx.getUserId());
|
||||
return;
|
||||
}
|
||||
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
int availableAfter = locked.getAvailablePoints() + ZoneConstants.PublishProject.POINTS;
|
||||
int frozenAfter = locked.getFrozenPoints();
|
||||
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.PublishProject.POINTS);
|
||||
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.PublishProject.POINTS,
|
||||
availableAfter, frozenAfter,
|
||||
ZoneConstants.PublishProject.REASON, ctx.getOperatorId(), ctx.getSourceId(),
|
||||
ZoneConstants.PublishProject.SOURCE_TYPE, null,
|
||||
ZoneConstants.PublishProject.SUBJECT,
|
||||
String.format(ZoneConstants.PublishProject.SUBJECT_DESC_TEMPLATE, ctx.getSubjectDesc()),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 发布资源审核通过 — 积分奖励
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class PublishResourcePointsHandler implements IPointsTaskHandler {
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PublishResourcePointsHandler.class);
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.PublishResource.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
|
||||
if (account == null) {
|
||||
logger.warn("积分-资源发布:未能获取积分账户,跳过积分发放 userId={} zoneId={} sourceId={}",
|
||||
ctx.getUserId(), ctx.getZoneId(), ctx.getSourceId());
|
||||
return;
|
||||
}
|
||||
|
||||
// 幂等检查:同一资源发布同一用户只发放一次
|
||||
if (zonePointsTransactionMapper.countByEventTypeAndSourceAndUser(ZoneConstants.PublishResource.SOURCE_TYPE, ctx.getSourceId(), account.getId()) > 0) {
|
||||
logger.info("积分-资源发布:积分已发放,跳过 sourceId={} userId={}", ctx.getSourceId(), ctx.getUserId());
|
||||
return;
|
||||
}
|
||||
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
int availableAfter = locked.getAvailablePoints() + ZoneConstants.PublishResource.POINTS;
|
||||
int frozenAfter = locked.getFrozenPoints();
|
||||
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.PublishResource.POINTS);
|
||||
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.PublishResource.POINTS,
|
||||
availableAfter, frozenAfter,
|
||||
ZoneConstants.PublishResource.REASON, ctx.getOperatorId(), ctx.getSourceId(),
|
||||
ZoneConstants.PublishResource.SOURCE_TYPE, null,
|
||||
ZoneConstants.PublishResource.SUBJECT,
|
||||
String.format(ZoneConstants.PublishResource.SUBJECT_DESC_TEMPLATE, ctx.getSubjectDesc()),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package com.microservices.zone.member.service.points.handler;
|
||||
|
||||
import com.microservices.zone.member.domain.points.ZonePointsAccount;
|
||||
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
|
||||
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
|
||||
import com.microservices.zone.member.service.points.IPointsTaskHandler;
|
||||
import com.microservices.zone.member.service.points.PointsAccountOperations;
|
||||
import com.microservices.zone.member.service.points.PointsTaskContext;
|
||||
import com.microservices.zone.utils.ZoneConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 关联项目 — 积分奖励
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Component
|
||||
public class RelevanceProjectPointsHandler implements IPointsTaskHandler {
|
||||
|
||||
@Autowired
|
||||
private PointsAccountOperations pointsAccountOperations;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsAccountMapper zonePointsAccountMapper;
|
||||
|
||||
@Autowired
|
||||
private ZonePointsTransactionMapper zonePointsTransactionMapper;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RelevanceProjectPointsHandler.class);
|
||||
|
||||
@Override
|
||||
public String getSourceType() {
|
||||
return ZoneConstants.RelevanceProject.SOURCE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handle(PointsTaskContext ctx) {
|
||||
ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 幂等检查:同一项目关联同一用户只发放一次
|
||||
if (zonePointsTransactionMapper.countByEventTypeAndSourceAndUser(ZoneConstants.RelevanceProject.SOURCE_TYPE, ctx.getSourceId(), account.getId()) > 0) {
|
||||
logger.info("积分-关联项目:积分已发放,跳过 sourceId={} userId={}", ctx.getSourceId(), ctx.getUserId());
|
||||
return;
|
||||
}
|
||||
|
||||
ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
|
||||
int availableAfter = locked.getAvailablePoints() + ZoneConstants.RelevanceProject.POINTS;
|
||||
int frozenAfter = locked.getFrozenPoints();
|
||||
|
||||
zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.RelevanceProject.POINTS);
|
||||
|
||||
pointsAccountOperations.recordPointsTransaction(account.getId(),
|
||||
ZoneConstants.TransactionType.ADD,
|
||||
ZoneConstants.RelevanceProject.POINTS,
|
||||
availableAfter, frozenAfter,
|
||||
ZoneConstants.RelevanceProject.REASON, ctx.getOperatorId(), ctx.getSourceId(),
|
||||
ZoneConstants.RelevanceProject.SOURCE_TYPE, null,
|
||||
ZoneConstants.RelevanceProject.SUBJECT,
|
||||
String.format(ZoneConstants.RelevanceProject.SUBJECT_DESC_TEMPLATE, ctx.getSubjectDesc()),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
|
@ -94,6 +94,12 @@ public class ZoneProject extends BaseEntity {
|
|||
@ApiModelProperty(value = "审核人")
|
||||
private String auditBy;
|
||||
|
||||
@ApiModelProperty(value = "是否积分置顶(0代表不是 1代表是)")
|
||||
private String isPointsTop;
|
||||
|
||||
@ApiModelProperty(value = "置顶过期时间")
|
||||
private Date expiryTime;
|
||||
|
||||
public ZoneProjectDataVo toZoneProjectDataVo() {
|
||||
ZoneProjectDataVo zoneProjectDataVo = new ZoneProjectDataVo();
|
||||
BeanUtils.copyProperties(this, zoneProjectDataVo);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ public class ZoneProjectDataVo implements Comparable<ZoneProjectDataVo> {
|
|||
private Date auditTime;
|
||||
@ApiModelProperty(value = "审核人")
|
||||
private String auditBy;
|
||||
@ApiModelProperty(value = "是否积分置顶(0代表不是 1代表是)")
|
||||
private String isPointsTop;
|
||||
@ApiModelProperty(value = "置顶过期时间")
|
||||
private Date expiryTime;
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ public class ZoneProjectOpenSearchVo extends BaseEntity {
|
|||
private String isHomepage;
|
||||
@ApiModelProperty(value = "是否公开",hidden = true)
|
||||
private Boolean isOpen;
|
||||
@ApiModelProperty(value = "排除项目Id", hidden = true)
|
||||
private Long excludeId;
|
||||
|
||||
public ZoneProjectSearchVo toZoneProjectSearchVo(Long zoneId) {
|
||||
ZoneProjectSearchVo zoneProjectSearchVo = new ZoneProjectSearchVo();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,6 @@ public class ZoneProjectSearchVo extends ZoneProjectOpenSearchVo {
|
|||
private Long zoneId;
|
||||
@ApiModelProperty(value = "审核状态(0:待审核,1:审核通过 2:审核不通过)")
|
||||
private String auditStatus;
|
||||
@ApiModelProperty(value = "是否为我的项目", hidden = true)
|
||||
private Boolean isMyProject;
|
||||
@ApiModelProperty(value = "排除未通过审核项目", hidden = true)
|
||||
private Boolean excludesFailure;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,4 +190,28 @@ public interface ZoneProjectMapper {
|
|||
List<String> selectZoneProjectGitlinkIdList(@Param("zoneId") Long zoneId, @Param("projectTypeId") Long projectTypeId);
|
||||
|
||||
List<ZoneProject> selectZoneProjectListFromGitlinkProjectIdList(@Param("zoneId") Long zoneId, @Param("gitlinkProjectIdList") List<Long> gitlinkProjectIdList);
|
||||
|
||||
/**
|
||||
* 查询当前用户在指定专区下的置顶项目
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param createBy 创建者用户名
|
||||
* @return 置顶项目记录
|
||||
*/
|
||||
ZoneProject selectPointsTopByZoneIdAndCreateBy(@Param("zoneId") Long zoneId, @Param("createBy") String createBy);
|
||||
|
||||
/**
|
||||
* 查询专区下置顶项目列表(过期时间晚于当前时间,用于前台展示)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @return 置顶项目列表
|
||||
*/
|
||||
List<ZoneProject> selectTopProjectList(Long zoneId);
|
||||
|
||||
/**
|
||||
* 批量取消已过期的积分置顶(is_points_top=1 且 expiry_time 早于当前时间)
|
||||
*
|
||||
* @return 影响行数
|
||||
*/
|
||||
int updateExpiredPointsTop();
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue