From 54e4643f0b9fb2fd0990b0eb19abcc9bfb933ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B3=95=E6=8B=8951246?= <719602854@qq.com> Date: Sat, 7 Jun 2025 01:21:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E9=97=A8=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E5=BC=BA=E5=88=B6=E8=B8=A2=E4=B8=8B=E7=BA=BF=20?= =?UTF-8?q?=E5=A4=A7=E5=B1=8F=E8=BF=87=E6=BB=A4null=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=EF=BC=8C=E8=A7=A3=E5=86=B3=E5=AF=BC=E8=87=B4=E7=9A=84=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=20=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E5=A2=9E=E5=8A=A0=E5=AE=8C=E6=AF=95=20=E5=B8=A6?= =?UTF-8?q?=E5=87=BA=E6=9D=A5=E5=AE=A2=E6=88=B7=E6=95=B0=E6=8D=AE=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=B8=A6=E5=87=BA=E6=89=80=E5=B1=9E=E9=83=A8=E9=97=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/common/pojo/PageParam.java | 3 ++ .../mybatis/core/dataobject/BaseDO.java | 7 ++++ .../core/handler/DefaultDBFieldHandler.java | 12 +++++++ .../core/util/SecurityFrameworkUtils.java | 8 +++++ .../web/core/util/WebFrameworkUtils.java | 23 +++++++++++++ .../oauth2/OAuth2TokenServiceImpl.java | 32 ++++++++++++++++++- .../service/user/AdminUserServiceImpl.java | 24 ++++++++++++++ yudao-module-visit/pom.xml | 4 +++ .../customerinfo/CustomerInfoController.java | 5 +++ .../controller/admin/info/InfoController.java | 4 +++ .../admin/product/ProductController.java | 5 +++ .../customerinfo/CustomerInfoMapper.java | 21 +++++++++++- .../visit/dal/mysql/info/InfoMapper.java | 7 ++++ .../dal/mysql/product/ProductMapper.java | 17 +++++++++- .../customerinfo/CustomerInfoServiceImpl.java | 4 ++- .../visit/service/home/HomeServiceImpl.java | 17 ++++++++-- .../service/product/ProductServiceImpl.java | 8 ++++- .../src/views/Home/Index.vue | 4 ++- .../src/views/Home/components/PieChart.vue | 4 +-- .../src/views/system/user/UserForm.vue | 14 +++++++- .../src/views/visit/info/InfoForm.vue | 4 ++- 21 files changed, 215 insertions(+), 12 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java index 97819f9..12d4010 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java @@ -33,4 +33,7 @@ public class PageParam implements Serializable { @Max(value = 100, message = "每页条数最大值为 100") private Integer pageSize = PAGE_SIZE; + //控制数据权限 + private Long companyId; + } diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java index fc5f0a3..96b7a2c 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java @@ -52,5 +52,12 @@ public abstract class BaseDO implements Serializable, TransPojo { */ @TableLogic private Boolean deleted; + /** + * 所在部门,目前使用 部门编号 + * + * + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long companyId; } diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java index 16d3af3..7e2a1d2 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java @@ -42,6 +42,12 @@ public class DefaultDBFieldHandler implements MetaObjectHandler { if (Objects.nonNull(userName) && Objects.isNull(baseDO.getUpdater())) { baseDO.setUpdater(userName); } + + //自动插入登录人所属分公司id + Long userDeptId = WebFrameworkUtils.getLoginUserDeptId(); + if (Objects.nonNull(userDeptId)) { + baseDO.setCompanyId(userDeptId); + } } } @@ -59,5 +65,11 @@ public class DefaultDBFieldHandler implements MetaObjectHandler { if (Objects.nonNull(userId) && Objects.isNull(modifier)) { setFieldValByName("updater", userId.toString(), metaObject); } + + //自动插入登录人所属分公司id + Long userDeptId = WebFrameworkUtils.getLoginUserDeptId(); + if (Objects.nonNull(userDeptId)) { + setFieldValByName("companyId", userDeptId, metaObject); + } } } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java index 90b8250..dd5eba1 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java @@ -134,6 +134,14 @@ public class SecurityFrameworkUtils { .orElse("未知"); WebFrameworkUtils.setLoginUserName(request, nickname); + Long deptId = Optional.ofNullable(loginUser.getInfo()) + .map(info -> info.get("deptId")) + .map(Object::toString) + .map(Long::valueOf) + .orElse(null); + + WebFrameworkUtils.setLoginUserDept(request, deptId); + WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType()); } diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java index 71aaa70..68252b8 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java @@ -22,6 +22,7 @@ public class WebFrameworkUtils { private static final String REQUEST_ATTRIBUTE_LOGIN_USER_ID = "login_user_id"; private static final String REQUEST_ATTRIBUTE_LOGIN_USER_NAME = "login_user_name"; + private static final String REQUEST_ATTRIBUTE_LOGIN_USER_DEPT = "login_user_dept"; private static final String REQUEST_ATTRIBUTE_LOGIN_USER_TYPE = "login_user_type"; private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result"; @@ -79,6 +80,15 @@ public class WebFrameworkUtils { public static void setLoginUserName(ServletRequest request, String nickname) { request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_NAME, nickname); } + /** + * 登录用户的所属分公司 + * + * @param request 登录用户 + * @param deptid 用户 + */ + public static void setLoginUserDept(ServletRequest request, Long deptid) { + request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_DEPT, deptid); + } /** * 设置用户类型 @@ -111,6 +121,15 @@ public class WebFrameworkUtils { .map(Object::toString) .orElse(""); } + public static Long getLoginUserDeptId(HttpServletRequest request) { + if (request == null) { + return null; + } + return Optional.ofNullable(request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_DEPT)) + .map(Object::toString) + .map(Long::valueOf) + .orElse(null); + } /** * 获得当前用户的类型 @@ -151,6 +170,10 @@ public class WebFrameworkUtils { HttpServletRequest request = getRequest(); return getLoginUserName(request); } + public static Long getLoginUserDeptId() { + HttpServletRequest request = getRequest(); + return getLoginUserDeptId(request); + } public static Integer getTerminal() { HttpServletRequest request = getRequest(); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java index 04bc744..db127a5 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java @@ -14,10 +14,12 @@ import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper; import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper; import cn.iocoder.yudao.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO; @@ -57,6 +59,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { @Lazy // 懒加载,避免循环依赖 private AdminUserService adminUserService; + @Resource + private DeptMapper deptMapper; + @Override @Transactional(rollbackFor = Exception.class) public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List scopes) { @@ -199,8 +204,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { private Map buildUserInfo(Long userId, Integer userType) { if (userType.equals(UserTypeEnum.ADMIN.getValue())) { AdminUserDO user = adminUserService.getUser(userId); + Long branchDeptId = findBranchDeptId(user.getDeptId(), 100L);//找到分公司Id,这里的100L是总公司的ID,未来某一天如果有变,就改这里 return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname()) - .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build(); + .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(branchDeptId)).build(); } else if (userType.equals(UserTypeEnum.MEMBER.getValue())) { // 注意:目前 Member 暂时不读取,可以按需实现 return Collections.emptyMap(); @@ -208,6 +214,30 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { return null; } + + //找出自己所在分公司 + public Long findBranchDeptId(Long currentDeptId, Long rootDeptId) { + Long lastDeptId = null; + + while (currentDeptId != null && currentDeptId != 0) { + DeptDO dept = deptMapper.selectById(currentDeptId); + if (dept == null) break; + + Long parentId = dept.getParentId(); + + // 如果当前部门的 parent 是 rootDeptId,说明当前就是直属分公司 + if (parentId != null && parentId.equals(rootDeptId)) { + return currentDeptId; + } + + lastDeptId = currentDeptId; + currentDeptId = parentId; + } + + return null; // 没找到直属分公司 + } + + private static String generateAccessToken() { return IdUtil.fastSimpleUUID(); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 2bf35eb..cc37350 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.ServiceException; @@ -12,9 +13,12 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthRegisterReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportExcelVO; @@ -23,11 +27,14 @@ import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqV import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper; import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; import cn.iocoder.yudao.module.system.service.dept.DeptService; import cn.iocoder.yudao.module.system.service.dept.PostService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.tenant.TenantService; import com.google.common.annotations.VisibleForTesting; @@ -86,6 +93,9 @@ public class AdminUserServiceImpl implements AdminUserService { @Resource private ConfigApi configApi; + @Resource + private OAuth2TokenService oauth2TokenService; + @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}", @@ -159,6 +169,20 @@ public class AdminUserServiceImpl implements AdminUserService { userMapper.updateById(updateObj); // 2.2 更新岗位 updateUserPost(updateReqVO, updateObj); + // 新增:先判断修改的这个用户是不是自己 + if (ObjectUtil.notEqual(updateReqVO.getId(), SecurityFrameworkUtils.getLoginUserId())) { + //进入这里说明不是自己,那就根据逻辑是否强制下线 + // 新增:如果更新了部门编号,则先查看该用户的id,根据id删除该用户token,强制下线重新登录 + if (Objects.nonNull(updateReqVO.getDeptId())&& !oldUser.getDeptId().equals(updateObj.getDeptId()) ) { + OAuth2AccessTokenPageReqVO reqVO = new OAuth2AccessTokenPageReqVO(); + reqVO.setUserId(oldUser.getId()); + PageResult accessTokenPage = oauth2TokenService.getAccessTokenPage(reqVO); + for (OAuth2AccessTokenDO accessToken : accessTokenPage.getList()) { + oauth2TokenService.removeAccessToken(accessToken.getAccessToken()); + } + } + } + //修改的是自己前端会刷新token,所以不能再t下线了,要保持登陆状态 // 3. 记录操作日志上下文 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class)); diff --git a/yudao-module-visit/pom.xml b/yudao-module-visit/pom.xml index 615dd2f..259c90b 100644 --- a/yudao-module-visit/pom.xml +++ b/yudao-module-visit/pom.xml @@ -57,6 +57,10 @@ 2.4.2-jdk8-SNAPSHOT compile + + cn.iocoder.boot + yudao-spring-boot-starter-protection + diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/CustomerInfoController.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/CustomerInfoController.java index d9b292e..ce92a1e 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/CustomerInfoController.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/CustomerInfoController.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.visit.controller.admin.customerinfo; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; import cn.iocoder.yudao.module.visit.controller.admin.product.vo.ProductImportExcelVO; import cn.iocoder.yudao.module.visit.controller.admin.product.vo.ProductImportRespVO; import cn.iocoder.yudao.module.visit.controller.admin.product.vo.ProductSimpleReqVO; @@ -51,6 +52,7 @@ public class CustomerInfoController { @PostMapping("/create") @Operation(summary = "创建客户信息") @PreAuthorize("@ss.hasPermission('visit:customer-info:create')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult createCustomerInfo(@Valid @RequestBody CustomerInfoSaveReqVO createReqVO) { return success(customerInfoService.createCustomerInfo(createReqVO)); } @@ -58,6 +60,7 @@ public class CustomerInfoController { @PutMapping("/update") @Operation(summary = "更新客户信息") @PreAuthorize("@ss.hasPermission('visit:customer-info:update')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult updateCustomerInfo(@Valid @RequestBody CustomerInfoSaveReqVO updateReqVO) { customerInfoService.updateCustomerInfo(updateReqVO); return success(true); @@ -67,6 +70,7 @@ public class CustomerInfoController { @Operation(summary = "删除客户信息") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('visit:customer-info:delete')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult deleteCustomerInfo(@RequestParam("id") Long id) { customerInfoService.deleteCustomerInfo(id); return success(true); @@ -154,6 +158,7 @@ public class CustomerInfoController { @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") }) @PreAuthorize("@ss.hasPermission('visit:customer-info:import')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { List list = ExcelUtils.read(file, CustomerImportExcelVO.class); diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/InfoController.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/InfoController.java index b924304..4621533 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/InfoController.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/InfoController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.visit.controller.admin.info; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; import com.fhs.common.utils.StringUtil; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -42,6 +43,7 @@ public class InfoController { @PostMapping("/create") @Operation(summary = "创建客户拜访记录") @PreAuthorize("@ss.hasPermission('visit:info:create')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult createInfo(@Valid @RequestBody InfoSaveReqVO createReqVO) { return success(infoService.createInfo(createReqVO)); } @@ -49,6 +51,7 @@ public class InfoController { @PutMapping("/update") @Operation(summary = "更新客户拜访记录") @PreAuthorize("@ss.hasPermission('visit:info:update')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult updateInfo(@Valid @RequestBody InfoSaveReqVO updateReqVO) { infoService.updateInfo(updateReqVO); return success(true); @@ -58,6 +61,7 @@ public class InfoController { @Operation(summary = "删除客户拜访记录") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('visit:info:delete')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult deleteInfo(@RequestParam("id") Long id) { infoService.deleteInfo(id); return success(true); diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/product/ProductController.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/product/ProductController.java index b802481..2abf47d 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/product/ProductController.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/product/ProductController.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.visit.controller.admin.product; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; import cn.iocoder.yudao.module.system.enums.common.SexEnum; import io.swagger.v3.oas.annotations.Parameters; import org.springframework.web.bind.annotation.*; @@ -46,6 +47,7 @@ public class ProductController { @PostMapping("/create") @Operation(summary = "创建产品") @PreAuthorize("@ss.hasPermission('visit:product:create')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) { return success(productService.createProduct(createReqVO)); } @@ -53,6 +55,7 @@ public class ProductController { @PutMapping("/update") @Operation(summary = "更新产品") @PreAuthorize("@ss.hasPermission('visit:product:update')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult updateProduct(@Valid @RequestBody ProductSaveReqVO updateReqVO) { productService.updateProduct(updateReqVO); return success(true); @@ -62,6 +65,7 @@ public class ProductController { @Operation(summary = "删除产品") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('visit:product:delete')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult deleteProduct(@RequestParam("id") Long id) { productService.deleteProduct(id); return success(true); @@ -129,6 +133,7 @@ public class ProductController { @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") }) @PreAuthorize("@ss.hasPermission('visit:product:import')") + @Idempotent(timeout = 10, message = "重复请求,请稍后重试") public CommonResult importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { List list = ExcelUtils.read(file, ProductImportExcelVO.class); diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/customerinfo/CustomerInfoMapper.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/customerinfo/CustomerInfoMapper.java index 44ecbf8..a676559 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/customerinfo/CustomerInfoMapper.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/customerinfo/CustomerInfoMapper.java @@ -5,6 +5,7 @@ import java.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.visit.dal.dataobject.customerinfo.CustomerInfoDO; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.module.visit.controller.admin.customerinfo.vo.*; @@ -18,38 +19,56 @@ import cn.iocoder.yudao.module.visit.controller.admin.customerinfo.vo.*; public interface CustomerInfoMapper extends BaseMapperX { default PageResult selectPage(CustomerInfoPageReqVO reqVO) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(CustomerInfoDO::getCustomerName, reqVO.getCustomerName()) .eqIfPresent(CustomerInfoDO::getContact, reqVO.getContact()) .likeIfPresent(CustomerInfoDO::getCompanyName, reqVO.getCompanyName()) .eqIfPresent(CustomerInfoDO::getCustomerType, reqVO.getCustomerType()) .eqIfPresent(CustomerInfoDO::getCityCode, reqVO.getCityCode()) + .eqIfPresent(CustomerInfoDO::getCompanyId,companyId) .betweenIfPresent(CustomerInfoDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(CustomerInfoDO::getId)); } default PageResult selectHomePage(CustomerInfoPageReqVO reqVO) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(CustomerInfoDO::getCustomerName, reqVO.getCustomerName()) .eqIfPresent(CustomerInfoDO::getContact, reqVO.getContact()) .eqIfPresent(CustomerInfoDO::getCompanyName, reqVO.getCompanyName()) .eqIfPresent(CustomerInfoDO::getCustomerType, reqVO.getCustomerType()) .eqIfPresent(CustomerInfoDO::getCityCode, reqVO.getCityCode()) + .eqIfPresent(CustomerInfoDO::getCompanyId,companyId) .betweenIfPresent(CustomerInfoDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(CustomerInfoDO::getId)); } //根据公司名称查询客户信息(验证是否唯一使用) default CustomerInfoDO selectByCompanyName(String companyName){ - return selectOne(CustomerInfoDO::getCompanyName, companyName); + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); + return selectOne(new LambdaQueryWrapperX() + .eq(CustomerInfoDO::getCompanyName, companyName) + .eqIfPresent(CustomerInfoDO::getCompanyId, companyId) + ); } // 根据公司名称或手机号查询(根据任一条件带出符合条件的列表) default List selectListByCompanyName(String companyName) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); return selectList(new LambdaQueryWrapperX() + .eqIfPresent(CustomerInfoDO::getCompanyId, companyId) .likeIfPresent(CustomerInfoDO::getCompanyName, companyName)); } default List selectListByContact(String contact) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); return selectList(new LambdaQueryWrapperX() + .eqIfPresent(CustomerInfoDO::getCompanyId, companyId) .likeIfPresent(CustomerInfoDO::getContact, contact)); } + + default List selectList(Long companyId){ + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(CustomerInfoDO::getCompanyId, companyId)); + } + } \ No newline at end of file diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/info/InfoMapper.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/info/InfoMapper.java index f72051f..3b6b73b 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/info/InfoMapper.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/info/InfoMapper.java @@ -5,6 +5,7 @@ import java.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.visit.dal.dataobject.info.InfoDO; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.module.visit.controller.admin.info.vo.*; @@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.visit.controller.admin.info.vo.*; public interface InfoMapper extends BaseMapperX { default PageResult selectPage(InfoPageReqVO reqVO) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(InfoDO::getCustomerName, reqVO.getCustomerName()) .eqIfPresent(InfoDO::getContact, reqVO.getContact()) @@ -27,10 +29,12 @@ public interface InfoMapper extends BaseMapperX { .eqIfPresent(InfoDO::getVisitProductIds, reqVO.getVisitProductIds()) .eqIfPresent(InfoDO::getVisitMethod, reqVO.getVisitMethod()) .eqIfPresent(InfoDO::getVisitType, reqVO.getVisitType()) + .eqIfPresent(InfoDO::getCompanyId,companyId) .betweenIfPresent(InfoDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(InfoDO::getId)); } default PageResult selectHomePage(InfoPageReqVO reqVO) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(InfoDO::getCustomerName, reqVO.getCustomerName()) .eqIfPresent(InfoDO::getContact, reqVO.getContact()) @@ -40,12 +44,15 @@ public interface InfoMapper extends BaseMapperX { .eqIfPresent(InfoDO::getVisitProductIds, reqVO.getVisitProductIds()) .eqIfPresent(InfoDO::getVisitMethod, reqVO.getVisitMethod()) .eqIfPresent(InfoDO::getVisitType, reqVO.getVisitType()) + .eqIfPresent(InfoDO::getCompanyId,companyId) .betweenIfPresent(InfoDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(InfoDO::getId)); } default List selectByCompanyName(String companyName) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); return selectList(new LambdaQueryWrapperX() + .eqIfPresent(InfoDO::getCompanyId,companyId) .eq(InfoDO::getCompanyName, companyName)); } } \ No newline at end of file diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/product/ProductMapper.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/product/ProductMapper.java index 6573103..9a803ba 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/product/ProductMapper.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/product/ProductMapper.java @@ -5,7 +5,9 @@ import java.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.visit.dal.dataobject.product.ProductDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.module.visit.controller.admin.product.vo.*; @@ -18,7 +20,14 @@ import cn.iocoder.yudao.module.visit.controller.admin.product.vo.*; public interface ProductMapper extends BaseMapperX { default ProductDO selectByProductParam(String productName, String specification, String packageName) { - return selectOne(ProductDO::getProductName, productName, ProductDO::getSpecification, specification, ProductDO::getPackageName, packageName); + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); + return selectOne(new LambdaQueryWrapperX() + .eqIfPresent(ProductDO::getProductName, productName) + .eqIfPresent(ProductDO::getSpecification, specification) + .eqIfPresent(ProductDO::getPackageName, packageName) + .eqIfPresent(ProductDO::getCompanyId, companyId) + + ); } default PageResult selectPage(ProductPageReqVO reqVO) { @@ -27,8 +36,14 @@ public interface ProductMapper extends BaseMapperX { .eqIfPresent(ProductDO::getPackageName, reqVO.getPackageName()) .eqIfPresent(ProductDO::getSpecification, reqVO.getSpecification()) .eqIfPresent(ProductDO::getStatus, reqVO.getStatus()) + .eqIfPresent(ProductDO::getCompanyId, reqVO.getCompanyId()) .betweenIfPresent(ProductDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(ProductDO::getId)); } + default List selectByIds(List list, Long companyId){ + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(ProductDO::getCompanyId, companyId) + .inIfPresent(ProductDO::getId, list)); + } } \ No newline at end of file diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/customerinfo/CustomerInfoServiceImpl.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/customerinfo/CustomerInfoServiceImpl.java index f3056cb..6ab4eac 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/customerinfo/CustomerInfoServiceImpl.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/customerinfo/CustomerInfoServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.visit.service.customerinfo; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.infra.service.file.FileService; import cn.iocoder.yudao.module.visit.controller.admin.product.vo.ProductPageReqVO; import cn.iocoder.yudao.module.visit.dal.dataobject.product.ProductDO; @@ -132,7 +133,8 @@ public class CustomerInfoServiceImpl implements CustomerInfoService { @Override public List getAllCustomerInfo() { - return customerInfoMapper.selectList(); + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); + return customerInfoMapper.selectList(companyId); } @Override diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/home/HomeServiceImpl.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/home/HomeServiceImpl.java index b3a31b0..83a0ea5 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/home/HomeServiceImpl.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/home/HomeServiceImpl.java @@ -78,8 +78,18 @@ public class HomeServiceImpl implements HomeService { PageResult infoDOPageResult = infoMapper.selectHomePage(infoPageReqVO);//精准查询 //客户拜访总次数 homeFirstRespVO.setVisitCount(String.valueOf(infoDOPageResult.getTotal())); - homeFirstRespVO.setSykfcs(String.valueOf(infoDOPageResult.getList().stream().filter(infoDO -> infoDO.getVisitType() == 0).count())); - homeFirstRespVO.setYlkfcs(String.valueOf(infoDOPageResult.getList().stream().filter(infoDO -> infoDO.getVisitType() == 1).count())); + List list = Optional.ofNullable(infoDOPageResult.getList()) + .orElse(Collections.emptyList()); + + homeFirstRespVO.setSykfcs(String.valueOf( + list.stream() + .filter(infoDO -> Integer.valueOf(0).equals(infoDO.getVisitType())) + .count())); + + homeFirstRespVO.setYlkfcs(String.valueOf( + list.stream() + .filter(infoDO -> Integer.valueOf(1).equals(infoDO.getVisitType())) + .count())); return homeFirstRespVO; } @@ -215,6 +225,7 @@ public class HomeServiceImpl implements HomeService { // 2.分组计数:Map Map typeCountMap = records.stream() + .filter(info -> info.getVisitMethod() != null) // ✅ null 保护 .collect(Collectors.groupingBy(InfoDO::getVisitMethod, Collectors.counting())); // 3. 加载字典并转换为 Map @@ -252,6 +263,7 @@ public class HomeServiceImpl implements HomeService { // 2.分组计数:Map Map typeCountMap = records.stream() + .filter(record -> record.getDepartment() != null) .collect(Collectors.groupingBy(InfoDO::getDepartment, Collectors.counting())); // 3. 加载字典并转换为 Map @@ -289,6 +301,7 @@ public class HomeServiceImpl implements HomeService { // 2.分组计数:Map Map typeCountMap = records.stream() + .filter(info -> info.getVisitType() != null) // ✅ null 保护 .collect(Collectors.groupingBy(InfoDO::getVisitType, Collectors.counting())); // 3. 加载字典并转换为 Map diff --git a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/product/ProductServiceImpl.java b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/product/ProductServiceImpl.java index e973d91..fec5d20 100644 --- a/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/product/ProductServiceImpl.java +++ b/yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/product/ProductServiceImpl.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.validation.ConstraintViolationException; @@ -77,6 +78,8 @@ public class ProductServiceImpl implements ProductService { @Override public PageResult getProductPage(ProductPageReqVO pageReqVO) { + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); + pageReqVO.setCompanyId(companyId); return productMapper.selectPage(pageReqVO); } @@ -121,7 +124,8 @@ public class ProductServiceImpl implements ProductService { String[] ids = productIds.split(","); //3.判断数组长度 if (ids.length > 0) { - List productDOS = productMapper.selectByIds(Arrays.asList(ids)); + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); + List productDOS = productMapper.selectByIds(Arrays.asList(ids), companyId); return BeanUtils.toBean(productDOS, ProductSimpleReqVO.class); } return new ArrayList<>(); @@ -133,6 +137,8 @@ public class ProductServiceImpl implements ProductService { productPageReqVO.setProductName(productName); productPageReqVO.setSpecification(specification); productPageReqVO.setPackageName(packageName); + Long companyId = SecurityFrameworkUtils.getLoginUserDeptId(); + productPageReqVO.setCompanyId(companyId); PageResult productDOPageResult = productMapper.selectPage(productPageReqVO); if (productDOPageResult.getTotal() > 0) { throw exception(PRODUCT_PRODUCT_EXISTS); diff --git a/yudao-ui/yudao-ui-admin-vue3/src/views/Home/Index.vue b/yudao-ui/yudao-ui-admin-vue3/src/views/Home/Index.vue index 15dd0fc..3b097e5 100644 --- a/yudao-ui/yudao-ui-admin-vue3/src/views/Home/Index.vue +++ b/yudao-ui/yudao-ui-admin-vue3/src/views/Home/Index.vue @@ -9,6 +9,7 @@ = ref([]) const homeInfoKhbmzbqk: Ref = ref([]) const homeInfoKhbflxzbqk: Ref = ref([]) const homeInfoBfcplxzbqk: Ref = ref([]) -const homeInfoBfztjVal = ref('拜访日统计') +const homeInfoBfztjVal = ref('拜访周统计') const homeInfoBfrtjVal = ref('拜访日统计') // 获取图表数据 const getEcharts = async () => { error.value = '' + if (loading.value) return; // ✅ 防止重复调用 loading.value = true const params: any = { diff --git a/yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/PieChart.vue b/yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/PieChart.vue index 5580025..1d8dabe 100644 --- a/yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/PieChart.vue +++ b/yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/PieChart.vue @@ -1,6 +1,6 @@