diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java index 76c3b52..b1245bf 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -8,9 +8,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO; -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.*; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; import cn.iocoder.yudao.module.system.service.tenant.TenantService; import io.swagger.v3.oas.annotations.Operation; @@ -109,7 +108,11 @@ public class TenantController { @PreAuthorize("@ss.hasPermission('system:tenant:query')") public CommonResult> getTenantPage(@Valid TenantPageReqVO pageVO) { PageResult pageResult = tenantService.getTenantPage(pageVO); - return success(BeanUtils.toBean(pageResult, TenantRespVO.class)); + PageResult bean = BeanUtils.toBean(pageResult, TenantRespVO.class); + for (TenantRespVO tenantRespVO : bean.getList()) { + tenantRespVO.setHasChildren(tenantRespVO.getTenantType().equals("代理")); + } + return success(bean); } @GetMapping("/export-excel") @@ -124,4 +127,53 @@ public class TenantController { BeanUtils.toBean(list, TenantRespVO.class)); } + +// 以下是控制代理租户的租户查询 +// ---------------------------------------------------------------------------------- + + @GetMapping("/page_self") + @Operation(summary = "代理获得自己下属租户分页") + @PreAuthorize("@ss.hasPermission('system:tenant:query-self')") + public CommonResult> getSelfTenantPage(@Valid TenantPageReqVO pageVO) { + PageResult pageResult = tenantService.getSelfTenantPage(pageVO); + PageResult bean = BeanUtils.toBean(pageResult, TenantRespVO.class); + for (TenantRespVO tenantRespVO : bean.getList()) { + tenantRespVO.setHasChildren(tenantRespVO.getTenantType().equals("代理")); + } + return success(bean); + } + + @GetMapping("/getSelfTenantLevel") + @Operation(summary = "获取自身代理级别") + @PreAuthorize("@ss.hasPermission('system:tenant:query-self-Level')") + public CommonResult getSelfTenantPage() { + Long tenantId = TenantContextHolder.getTenantId(); + TenantDO tenant = tenantService.getTenant(tenantId); + return success(BeanUtils.toBean(tenant, TenantLevelRespVO.class)); + } + + + @GetMapping("/get-children") + @Operation(summary = "获得代理租户下级") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant:query-children')") + public CommonResult> getChildrenTenant(@RequestParam("id") Long id) { + List tenantList = tenantService.getChildrenTenant(id); + List bean = BeanUtils.toBean(tenantList, TenantRespVO.class); + for (TenantRespVO tenantRespVO : bean) { + tenantRespVO.setHasChildren(tenantRespVO.getTenantType().equals("代理")); + } + return success(bean); + } + + + @PutMapping("/renewal") + @Operation(summary = "租户续费") + @PreAuthorize("@ss.hasPermission('system:tenant:renewal')") + public CommonResult renewalTenant(@Valid @RequestBody TenantRenewalReqVO renewalReqVO) { + tenantService.renewalTenant(renewalReqVO); + return success(true); + } + + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantPackageController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantPackageController.java index f523d51..2958275 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantPackageController.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantPackageController.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.*; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; import cn.iocoder.yudao.module.system.service.tenant.TenantPackageService; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Parameter; @@ -73,7 +74,7 @@ public class TenantPackageController { @GetMapping({"/get-simple-list", "simple-list"}) @Operation(summary = "获取租户套餐精简信息列表", description = "只包含被开启的租户套餐,主要用于前端的下拉选项") public CommonResult> getTenantPackageList() { - List list = tenantPackageService.getTenantPackageListByStatus(CommonStatusEnum.ENABLE.getStatus()); + List list = tenantPackageService.getTenantPackageListByStatus(CommonStatusEnum.ENABLE.getStatus()); return success(BeanUtils.toBean(list, TenantPackageSimpleRespVO.class)); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java index bc3d62a..5a07ce7 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java @@ -17,4 +17,12 @@ public class TenantPackageSimpleRespVO { @NotNull(message = "套餐名不能为空") private String name; + @Schema(description = "套餐类型", example = "1") + private Integer packageType; + + @Schema(description = "套餐价格", example = "30") + private Integer price; + + @Schema(description = "套餐有效期天数", example = "30") + private Integer days; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantLevelRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantLevelRespVO.java new file mode 100755 index 0000000..af12227 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantLevelRespVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +@Schema(description = "管理后台 - 租户 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TenantLevelRespVO { + + @Schema(description = "租户等级",example = "1") + private String tenantLevel; +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java index 73a177c..dbd8875 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java @@ -47,4 +47,10 @@ public class TenantPageReqVO extends PageParam { @Schema private String remark; + + @Schema(description = "父租户Id") + private Long parentId; + + @Schema(description = "租户类型", example = "代理/客户") + private String tenantType; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRenewalReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRenewalReqVO.java new file mode 100644 index 0000000..2e054eb --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRenewalReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +/* + * @author: ziin + * @date: 2025/11/25 20:54 + */ +@Schema(description = "管理后台 - 租户续费 Request VO") +@Data +public class TenantRenewalReqVO { + @Schema(description = "租户编号", example = "1024") + private Long id; + + @Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "租户套餐编号不能为空") + private Long packageId; + + @Schema(description = "备注", example = "备注") + private String remark; +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java index 44b4c0b..def5d13 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java @@ -64,4 +64,15 @@ public class TenantRespVO { @Schema(description = "备注", example = "备注") private String remark; + @Schema(description = "上级租户 Id", example = "1024") + private Long parentId; + + @Schema(description = "租户类型", example = "代理/客户") + private String tenantType; + + @Schema(description = "租户等级",example = "1") + private String tenantLevel; + + @Schema(description = "是否存在下级",example = "true") + private Boolean hasChildren; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java index 9df617a..a1bce11 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java @@ -86,4 +86,8 @@ public class TenantSaveReqVO { @Schema(description = "备注", example = "备注") private String remark; + @Schema(description = "租户类型", example = "代理/客户") + @NotNull(message = "租户类型不能为空") + private String tenantType; + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/TenantAgencyPackageController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/TenantAgencyPackageController.java new file mode 100644 index 0000000..cf99969 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/TenantAgencyPackageController.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo.*; +import cn.iocoder.yudao.module.system.service.tenantagencypackage.TenantAgencyPackageService; + +@Tag(name = "管理后台 - 代理租户套餐") +@RestController +@RequestMapping("/system/tenant-agency-package") +@Validated +public class TenantAgencyPackageController { + + @Resource + private TenantAgencyPackageService tenantAgencyPackageService; + + @PostMapping("/create") + @Operation(summary = "创建代理租户套餐") + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:create')") + public CommonResult createTenantAgencyPackage(@Valid @RequestBody TenantAgencyPackageSaveReqVO createReqVO) { + return success(tenantAgencyPackageService.createTenantAgencyPackage(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新代理租户套餐") + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:update')") + public CommonResult updateTenantAgencyPackage(@Valid @RequestBody TenantAgencyPackageSaveReqVO updateReqVO) { + tenantAgencyPackageService.updateTenantAgencyPackage(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除代理租户套餐") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:delete')") + public CommonResult deleteTenantAgencyPackage(@RequestParam("id") Long id) { + tenantAgencyPackageService.deleteTenantAgencyPackage(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除代理租户套餐") + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:delete')") + public CommonResult deleteTenantAgencyPackageList(@RequestParam("ids") List ids) { + tenantAgencyPackageService.deleteTenantAgencyPackageListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得代理租户套餐") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:query')") + public CommonResult getTenantAgencyPackage(@RequestParam("id") Long id) { + TenantAgencyPackageDO tenantAgencyPackage = tenantAgencyPackageService.getTenantAgencyPackage(id); + return success(BeanUtils.toBean(tenantAgencyPackage, TenantAgencyPackageRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得代理租户套餐分页") + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:query')") + public CommonResult> getTenantAgencyPackagePage(@Valid TenantAgencyPackagePageReqVO pageReqVO) { + PageResult pageResult = tenantAgencyPackageService.getTenantAgencyPackagePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, TenantAgencyPackageRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出代理租户套餐 Excel") + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportTenantAgencyPackageExcel(@Valid TenantAgencyPackagePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = tenantAgencyPackageService.getTenantAgencyPackagePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "代理租户套餐.xls", "数据", TenantAgencyPackageRespVO.class, + BeanUtils.toBean(list, TenantAgencyPackageRespVO.class)); + } + + @GetMapping({"/get-simple-list", "代理套餐精简列表"}) + @Operation(summary = "获取代理租户套餐精简信息列表", description = "只包含被开启的租户套餐,主要用于前端的下拉选项") + @PreAuthorize("@ss.hasPermission('system:tenant-agency-package:simple-list')") + public CommonResult> getTenantPackageList() { + List list = tenantAgencyPackageService.getTenantPackageListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(BeanUtils.toBean(list, AgencyTenantPackageSimpleRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/AgencyTenantPackageSimpleRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/AgencyTenantPackageSimpleRespVO.java new file mode 100644 index 0000000..0148bcc --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/AgencyTenantPackageSimpleRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 租户套餐精简 Response VO") +@Data +public class AgencyTenantPackageSimpleRespVO { + + @Schema(description = "套餐编号", example = "1024") + private Long id; + + @Schema(description = "套餐名", example = "VIP") + private String name; + + @Schema(description = "Ai自动回复权限 0关闭 1 开启", example = "1") + private Integer packageType; + + @Schema(description = "套餐价格", example = "1000") + private Integer price; +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackagePageReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackagePageReqVO.java new file mode 100644 index 0000000..f62954f --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackagePageReqVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 代理租户套餐分页 Request VO") +@Data +public class TenantAgencyPackagePageReqVO extends PageParam { + + @Schema(description = "套餐名", example = "芋艿") + private String name; + + @Schema(description = "租户状态(0正常 1停用)", example = "2") + private Integer status; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "关联的菜单编号") + private Set menuIds; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "套餐天数") + private Integer days; + + @Schema(description = "套餐价格", example = "22890") + private Integer price; + + @Schema(description = "爬主播客户端 0 关闭 1 开启") + private Integer hostslClient; + + @Schema(description = "爬大哥客户端 0 关闭 1 开启") + private Integer brotherClient; + + @Schema(description = "AI 客户端 0 关闭 1 开启") + private Integer aiClient; + + @Schema(description = "Ai自动回复权限 0关闭 1 开启") + private Integer aiReplay; + + @Schema(description = "套餐类型", example = "2") + private Integer packageType; + + @Schema(description = "WebAi权限 0关闭 1开启") + private Integer webAi; + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackageRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackageRespVO.java new file mode 100644 index 0000000..dffd552 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackageRespVO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 代理租户套餐 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TenantAgencyPackageRespVO { + + @Schema(description = "套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20125") + @ExcelProperty("套餐编号") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("套餐名") + private String name; + + @Schema(description = "租户状态(0正常 1停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("租户状态(0正常 1停用)") + private Integer status; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "关联的菜单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("关联的菜单编号") + private Set menuIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "套餐天数", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("套餐天数") + private Integer days; + + @Schema(description = "套餐价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "22890") + @ExcelProperty("套餐价格") + private Integer price; + + @Schema(description = "爬主播客户端 0 关闭 1 开启") + @ExcelProperty("爬主播客户端 0 关闭 1 开启") + private Integer hostslClient; + + @Schema(description = "爬大哥客户端 0 关闭 1 开启") + @ExcelProperty("爬大哥客户端 0 关闭 1 开启") + private Integer brotherClient; + + @Schema(description = "AI 客户端 0 关闭 1 开启") + @ExcelProperty("AI 客户端 0 关闭 1 开启") + private Integer aiClient; + + @Schema(description = "套餐类型", example = "2") + @ExcelProperty("套餐类型") + private Integer packageType; + + @Schema(description = "Ai自动回复权限 0关闭 1 开启") + @ExcelProperty("Ai 自动回复权限 0关闭 1开启") + private Integer aiReplay; + + @Schema(description = "WebAi权限 0关闭 1开启") + @ExcelProperty("WebAi权限 0关闭 1开启") + private Integer webAi; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackageSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackageSaveReqVO.java new file mode 100644 index 0000000..c124bac --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantagencypackage/vo/TenantAgencyPackageSaveReqVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 代理租户套餐新增/修改 Request VO") +@Data +public class TenantAgencyPackageSaveReqVO { + + @Schema(description = "套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20125") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "套餐名不能为空") + private String name; + + @Schema(description = "租户状态(0正常 1停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "租户状态(0正常 1停用)不能为空") + private Integer status; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "关联的菜单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "关联的菜单编号不能为空") + private Set menuIds; + + @Schema(description = "套餐天数", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "套餐天数不能为空") + private Integer days; + + @Schema(description = "套餐价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "22890") + @NotNull(message = "套餐价格不能为空") + private Integer price; + + @Schema(description = "爬主播客户端 0 关闭 1 开启") + private Integer hostslClient; + + @Schema(description = "爬大哥客户端 0 关闭 1 开启") + private Integer brotherClient; + + @Schema(description = "AI 客户端 0 关闭 1 开启") + private Integer aiClient; + + @Schema(description = "套餐类型", example = "2") + private Integer packageType; + + @Schema(description = "Ai自动回复权限 0关闭 1 开启") + private Integer aiReplay; + + @Schema(description = "WebAi权限 0关闭 1开启") + private Integer webAi; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/TenantBalanceController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/TenantBalanceController.java new file mode 100644 index 0000000..856b599 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/TenantBalanceController.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantbalance; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantbalance.TenantBalanceDO; +import cn.iocoder.yudao.module.system.service.tenantbalance.TenantBalanceService; + +@Tag(name = "管理后台 - 租户余额") +@RestController +@RequestMapping("/system/tenant-balance") +@Validated +public class TenantBalanceController { + + @Resource + private TenantBalanceService tenantBalanceService; + + @PostMapping("/create") + @Operation(summary = "创建租户余额") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:create')") + public CommonResult createTenantBalance(@Valid @RequestBody TenantBalanceSaveReqVO createReqVO) { + return success(tenantBalanceService.createTenantBalance(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租户余额") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:update')") + public CommonResult updateTenantBalance(@Valid @RequestBody TenantBalanceSaveReqVO updateReqVO) { + tenantBalanceService.updateTenantBalance(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租户余额") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:tenant-balance:delete')") + public CommonResult deleteTenantBalance(@RequestParam("id") Long id) { + tenantBalanceService.deleteTenantBalance(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除租户余额") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:delete')") + public CommonResult deleteTenantBalanceList(@RequestParam("ids") List ids) { + tenantBalanceService.deleteTenantBalanceListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租户余额") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:query')") + public CommonResult getTenantBalance(@RequestParam("id") Long id) { + TenantBalanceDO tenantBalance = tenantBalanceService.getTenantBalance(id); + return success(BeanUtils.toBean(tenantBalance, TenantBalanceRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租户余额分页") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:query')") + public CommonResult> getTenantBalancePage(@Valid TenantBalancePageReqVO pageReqVO) { + PageResult tenantBalancePage = tenantBalanceService.getTenantBalancePage(pageReqVO); + return success(BeanUtils.toBean(tenantBalancePage, TenantBalanceRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出租户余额 Excel") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportTenantBalanceExcel(@Valid TenantBalancePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = tenantBalanceService.getTenantBalancePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "租户余额.xls", "数据", TenantBalanceRespVO.class, + BeanUtils.toBean(list, TenantBalanceRespVO.class)); + } + + + @PostMapping("/addAmount") + @Operation(summary = "添加租户余额") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:add')") + public CommonResult addTenantBalance(@Valid @RequestBody TenantBalanceAddReqVO addReqVO) { + tenantBalanceService.addTenantBalance(addReqVO); + return success(true); + } + + @PostMapping("/transfer") + @Operation(summary = "租户余额转账") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:transfer')") + public CommonResult transferToTenant(@Valid @RequestBody TenantBalanceTransferReqVO transferReqVO) { + tenantBalanceService.transferToTenant(transferReqVO); + return success(true); + } + + @GetMapping("/get-self-amount") + @Operation(summary = "获得自己的余额") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:self-amount')") + public CommonResult getTenantBalance() { + TenantBalanceDO tenantBalance = tenantBalanceService.getSelfBalance(); + return success(BeanUtils.toBean(tenantBalance, TenantBalanceRespVO.class)); + } + + @GetMapping("/get-self-subordinate-amount-page") + @Operation(summary = "获得自己下级余额的分页") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:self-subordinate')") + public CommonResult> getSelfSubordinate(@Valid TenantBalancePageReqVO pageReqVO) { + PageResult tenantBalancePage = tenantBalanceService.getSelfSubordinateTenantBalancePage(pageReqVO); + return success(BeanUtils.toBean(tenantBalancePage, TenantBalanceRespVO.class)); + } + + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceAddReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceAddReqVO.java new file mode 100644 index 0000000..9b8eb29 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceAddReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/* + * @author: ziin + * @date: 2025/11/19 21:05 + */ +@Schema(description = "管理后台 - 租户余额添加VO") +@Data +public class TenantBalanceAddReqVO { + @Schema(description = "租户 Id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19954") + @NotNull(message = "租户 Id 不能为空") + private Long id; + + @Schema(description = "增加的余额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000000") + @NotNull(message = "增加的余额不能为空") + private Integer amount; + + @Schema(description = "备注", example = "备注") + private String remark; +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceConsumptionReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceConsumptionReqVO.java new file mode 100644 index 0000000..3f053b5 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceConsumptionReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/* + * @author: ziin + * @date: 2025/11/24 15:32 + */ +@Schema(description = "管理后台 - 租户余额消费") +@Data +public class TenantBalanceConsumptionReqVO { + + @Schema( description = "套餐编号") + private Long id; + +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalancePageReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalancePageReqVO.java new file mode 100644 index 0000000..9fa3298 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalancePageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租户余额分页 Request VO") +@Data +public class TenantBalancePageReqVO extends PageParam { + + @Schema(description = "租户编号", example = "1024") + private Long id; + + @Schema(description = "当前积分余额") + private Integer balance; + + @Schema(description = "乐观锁版本号") + private Integer version; + + @Schema(description = "更新时间") + private LocalDateTime updatedAt; + + @Schema(description = "测试账号数") + @ExcelProperty("测试账号数") + private Integer testAccountNum; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceRespVO.java new file mode 100644 index 0000000..94687fe --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 租户余额 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TenantBalanceRespVO { + + @Schema(description = "租户 Id", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("租户 Id") + private Long id; + + @Schema(description = "当前积分余额", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("当前积分余额") + private Integer balance; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updatedAt; + + @Schema(description = "代理名称") + @ExcelProperty("代理名称") + private String tenantName; + + @Schema(description = "测试账号数") + @ExcelProperty("测试账号数") + private Integer testAccountNum; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceSaveReqVO.java new file mode 100644 index 0000000..f3195eb --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceSaveReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租户余额新增/修改 Request VO") +@Data +public class TenantBalanceSaveReqVO { + + @Schema(description = "租户 Id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19954") + private Long id; + + @Schema(description = "当前积分余额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "当前积分余额不能为空") + private Integer balance; + + @Schema(description = "乐观锁版本号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "乐观锁版本号不能为空") + private Integer version; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "更新时间不能为空") + private LocalDateTime updatedAt; + + @Schema(description = "测试账号数") + @ExcelProperty("测试账号数") + private Integer testAccountNum; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceTransferReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceTransferReqVO.java new file mode 100644 index 0000000..5f0e939 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantbalance/vo/TenantBalanceTransferReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/* + * @author: ziin + * @date: 2025/11/19 21:05 + */ +@Schema(description = "管理后台 - 租户余额添加VO") +@Data +public class TenantBalanceTransferReqVO { + @Schema(description = "租户 Id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "租户 Id 不能为空") + private Long targetTenantId; + + + @Schema(description = "转账的金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @NotNull(message = "增加的余额不能为空") + private Integer transferAmount; + + + @Schema(description = "登录密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "登录密码不能为空") + private String password; + + @Schema(description = "备注", example = "转账") + private String remark; +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/TenantPointsController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/TenantPointsController.java new file mode 100644 index 0000000..8aadcef --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/TenantPointsController.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantpoints; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantpoints.TenantPointsDO; +import cn.iocoder.yudao.module.system.service.tenantpoints.TenantPointsService; + +@Tag(name = "管理后台 - 租户积分记录") +@RestController +@RequestMapping("/system/tenant-points") +@Validated +public class TenantPointsController { + + @Resource + private TenantPointsService tenantPointsService; + + @PostMapping("/create") + @Operation(summary = "创建租户积分记录") + @PreAuthorize("@ss.hasPermission('system:tenant-points:create')") + public CommonResult createTenantPoints(@Valid @RequestBody TenantPointsSaveReqVO createReqVO) { + return success(tenantPointsService.createTenantPoints(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租户积分记录") + @PreAuthorize("@ss.hasPermission('system:tenant-points:update')") + public CommonResult updateTenantPoints(@Valid @RequestBody TenantPointsSaveReqVO updateReqVO) { + tenantPointsService.updateTenantPoints(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租户积分记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:tenant-points:delete')") + public CommonResult deleteTenantPoints(@RequestParam("id") Long id) { + tenantPointsService.deleteTenantPoints(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除租户积分记录") + @PreAuthorize("@ss.hasPermission('system:tenant-points:delete')") + public CommonResult deleteTenantPointsList(@RequestParam("ids") List ids) { + tenantPointsService.deleteTenantPointsListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租户积分记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant-points:query')") + public CommonResult getTenantPoints(@RequestParam("id") Long id) { + TenantPointsDO tenantPoints = tenantPointsService.getTenantPoints(id); + return success(BeanUtils.toBean(tenantPoints, TenantPointsRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租户积分记录分页") + @PreAuthorize("@ss.hasPermission('system:tenant-points:query')") + public CommonResult> getTenantPointsPage(@Valid TenantPointsPageReqVO pageReqVO) { + PageResult tenantPointsPage = tenantPointsService.getTenantPointsPage(pageReqVO); + return success(tenantPointsPage); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出租户积分记录 Excel") + @PreAuthorize("@ss.hasPermission('system:tenant-points:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportTenantPointsExcel(@Valid TenantPointsPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + + List list = tenantPointsService.getTenantPointsPage(pageReqVO).getList(); + + // 导出 Excel + ExcelUtils.write(response, "租户积分记录.xls", "数据", TenantPointsPageRespVO.class, + BeanUtils.toBean(list, TenantPointsPageRespVO.class)); + } + + @GetMapping("/transaction-history/page") + @Operation(summary = "获得租户积分记录分页") + @Parameter(name = "tenantId", description = "租户 Id") + @PreAuthorize("@ss.hasPermission('system:tenant-balance:query')") + public CommonResult> getTenantTransactionHistoryPointsPage(PageParam pageReqVO, + @RequestParam("tenantId") Long tenantId) { + return success(tenantPointsService.getTenantTransactionHistoryPointsPage(pageReqVO, tenantId)); + } + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsPageReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsPageReqVO.java new file mode 100644 index 0000000..094b9b5 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsPageReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租户积分记录分页 Request VO") +@Data +public class TenantPointsPageReqVO extends PageParam { + + @Schema(description = "本次变动点数,正加负减") + private Integer points; + + @Schema(description = "变动后余额快照(冗余)") + private Integer balance; + + @Schema(description = "变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN", example = "1") + private String type; + + @Schema(description = "变动描述", example = "随便") + private String description; + + @Schema(description = "订单 Id/业务单号", example = "84") + private String orderId; + + @Schema(description = "业务流水号(转账、订单等唯一标识)") + private String bizNo; + + @Schema(description = "操作人 Id", example = "8171") + private Long operatorId; + + @Schema(description = "目标租户 Id(转账使用)", example = "18731") + private Long targetTenantId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createdAt; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsPageRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsPageRespVO.java new file mode 100644 index 0000000..170fd00 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsPageRespVO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租户积分记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TenantPointsPageRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "16587") + @ExcelProperty("主键") + private Long id; + + @Schema(description = "本次变动点数,正加负减", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("本次变动点数,正加负减") + private Integer points; + + @Schema(description = "变动后余额快照(冗余)") + @ExcelProperty("变动后余额快照(冗余)") + private Integer balance; + + @Schema(description = "变动类型,", example = "转账") + @ExcelProperty("变动类型,") + private String type; + + @Schema(description = "变动描述", example = "转账金额 100") + @ExcelProperty("变动描述") + private String description; + + @Schema(description = "订单 Id/业务单号", example = "84") + @ExcelProperty("订单 Id/业务单号") + private String orderId; + + @Schema(description = "业务流水号(转账、订单等唯一标识)") + @ExcelProperty("业务流水号(转账、订单等唯一标识)") + private String bizNo; + + @Schema(description = "操作人 Id", example = "8171") + @ExcelProperty("操作人 Id") + private Long operatorId; + + @Schema(description = "目标租户 Id(转账使用)", example = "18731") + @ExcelProperty("目标租户 Id(转账使用)") + private Long targetTenantId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createdAt; + + @Schema(description = "租户名称", example = "租户 A") + @ExcelProperty("租户名称") + private String tenantName; + + @Schema(description = "测试账号数", example = "1") + @ExcelProperty("测试账号数") + private Integer testAccountNum; + + @Schema(description = "备注", example = "转账金额:1000") + @ExcelProperty("备注") + private String remark; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsRespVO.java new file mode 100644 index 0000000..79b50a5 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsRespVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 租户积分记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TenantPointsRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "16587") + @ExcelProperty("主键") + private Long id; + + @Schema(description = "本次变动点数,正加负减", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("本次变动点数,正加负减") + private Integer points; + + @Schema(description = "变动后余额快照(冗余)") + @ExcelProperty("变动后余额快照(冗余)") + private Integer balance; + + @Schema(description = "变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN", example = "1") + @ExcelProperty("变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN") + private String type; + + @Schema(description = "变动描述", example = "随便") + @ExcelProperty("变动描述") + private String description; + + @Schema(description = "订单 Id/业务单号", example = "84") + @ExcelProperty("订单 Id/业务单号") + private String orderId; + + @Schema(description = "业务流水号(转账、订单等唯一标识)") + @ExcelProperty("业务流水号(转账、订单等唯一标识)") + private String bizNo; + + @Schema(description = "操作人 Id", example = "8171") + @ExcelProperty("操作人 Id") + private Long operatorId; + + @Schema(description = "目标租户 Id(转账使用)", example = "18731") + @ExcelProperty("目标租户 Id(转账使用)") + private Long targetTenantId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createdAt; + + @Schema(description = "测试账号数", example = "1") + @ExcelProperty("测试账号数") + private Integer testAccountNum; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsSaveReqVO.java new file mode 100644 index 0000000..2afa813 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenantpoints/vo/TenantPointsSaveReqVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租户积分记录新增/修改 Request VO") +@Data +public class TenantPointsSaveReqVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "16587") + private Long id; + + @Schema(description = "本次变动点数,正加负减", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "本次变动点数,正加负减不能为空") + private Integer points; + + @Schema(description = "变动后余额快照(冗余)") + private Integer balance; + + @Schema(description = "变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN", example = "1") + private String type; + + @Schema(description = "变动描述", example = "随便") + private String description; + + @Schema(description = "订单 Id/业务单号", example = "84") + private String orderId; + + @Schema(description = "业务流水号(转账、订单等唯一标识)") + private String bizNo; + + @Schema(description = "操作人 Id", example = "8171") + private Long operatorId; + + @Schema(description = "目标租户 Id(转账使用)", example = "18731") + private Long targetTenantId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "创建时间不能为空") + private LocalDateTime createdAt; + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserClientSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserClientSaveReqVO.java index e0d5e7e..bbb4fdd 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserClientSaveReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserClientSaveReqVO.java @@ -36,4 +36,7 @@ public class UserClientSaveReqVO { @Schema(description = "是否允许使用 AI 回复", example = "0不允许,1允许") private Byte aiReplay; + + @Schema(description = "是否允许登录 Web AI 客户端", example = "0不允许,1允许") + private Byte webAi; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java index 4f4cffd..3745302 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java @@ -83,4 +83,7 @@ public class UserRespVO{ @Schema(description = "是否允许使用 AI 回复", example = "0不允许,1允许") private Byte aiReplay; + + @Schema(description = "是否允许登录 Web AI 客户端", example = "0不允许,1允许") + private Byte webAi; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java index be7689b..091525e 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java @@ -91,4 +91,7 @@ public class UserSaveReqVO { @Schema(description = "是否允许使用 AI 回复", example = "0不允许,1允许") private Byte aiReplay; + + @Schema(description = "是否允许登录 Web AI 客户端", example = "0不允许,1允许") + private Byte webAi; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java index 15085f1..9400f03 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java @@ -87,7 +87,30 @@ public class TenantDO extends BaseDO { /** * 账号数量 */ + private Integer accountCount; + /** + * 上级租户 Id + */ + private Long parentId; + + /** + * 备注 + */ + private String remark; + + + /** + * 租户类型 + */ + private String tenantType; + + /** + * 代理级别 + */ + private Integer tenantLevel; + + private String initialUser; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantagencypackage/TenantAgencyPackageDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantagencypackage/TenantAgencyPackageDO.java new file mode 100644 index 0000000..1a4b31c --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantagencypackage/TenantAgencyPackageDO.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage; + +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 代理租户套餐 DO + * + * @author 总后台 + */ +@TableName(value = "system_tenant_agency_package",autoResultMap = true) +@KeySequence("system_tenant_agency_package_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TenantIgnore +public class TenantAgencyPackageDO extends BaseDO { + + /** + * 套餐编号 + */ + @TableId + private Long id; + /** + * 套餐名 + */ + private String name; + /** + * 租户状态(0正常 1停用) + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 关联的菜单编号 + */ + + @TableField(typeHandler = JacksonTypeHandler.class) + private Set menuIds; + + /** + * 套餐天数 + */ + private Integer days; + /** + * 套餐价格 + */ + private Integer price; + /** + * 爬主播客户端 0 关闭 1 开启 + */ + private Integer hostslClient; + /** + * 爬大哥客户端 0 关闭 1 开启 + */ + private Integer brotherClient; + /** + * AI 客户端 0 关闭 1 开启 + */ + private Integer aiClient; + /** + * 套餐类型 + */ + private Integer packageType; + + /** + * Ai自动回复权限 0关闭 1开启 + */ + private Integer aiReplay; + + /** + * WebAi权限 0关闭 1开启 + */ + private Integer webAi; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantbalance/TenantBalanceDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantbalance/TenantBalanceDO.java new file mode 100644 index 0000000..7c04c4b --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantbalance/TenantBalanceDO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.tenantbalance; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 租户余额 DO + * + * @author 总后台 + */ +@TableName("system_tenant_balance") +@KeySequence("system_tenant_balance_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TenantBalanceDO{ + + private Long id; + /** + * 当前积分余额 + */ + private Integer balance; + /** + * 乐观锁版本号 + */ + private Integer version; + /** + * 更新时间 + */ + private LocalDateTime updatedAt; + + private Integer testAccountNum; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantpoints/TenantPointsDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantpoints/TenantPointsDO.java new file mode 100644 index 0000000..73f5ca3 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenantpoints/TenantPointsDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.tenantpoints; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 租户积分记录 DO + * + * @author 总后台 + */ +@TableName("system_tenant_points") +@KeySequence("system_tenant_points_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TenantPointsDO { + + /** + * 主键 + */ + @TableId(type = IdType.AUTO) + private Long id; + /** + * 本次变动点数,正加负减 + */ + private Integer points; + /** + * 变动后余额快照(冗余) + */ + private Integer balance; + /** + * 变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN + */ + private String type; + /** + * 变动描述 + */ + private String description; + /** + * 订单 Id/业务单号 + */ + private String orderId; + /** + * 业务流水号(转账、订单等唯一标识) + */ + private String bizNo; + /** + * 操作人 Id + */ + private Long operatorId; + /** + * 目标租户 Id(转账使用) + */ + private Long targetTenantId; + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + private Long tenantId; + + private String remark; + + private Integer testAccountNum; +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java index b0a20c7..08cb237 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java @@ -108,4 +108,7 @@ public class AdminUserDO extends TenantBaseDO { @Schema(description = "是否允许使用AI回复", example = "0不允许,1允许") private Byte aiReplay; + + @Schema(description = "是否允许登录Web AI客户端", example = "0不允许,1允许") + private Byte webAi; } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java index 6cf149d..af18b79 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java @@ -28,6 +28,7 @@ public interface TenantMapper extends BaseMapperX { .likeIfPresent(TenantDO::getContactName, reqVO.getContactName()) .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile()) .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) + .eqIfPresent(TenantDO::getTenantType, reqVO.getTenantType()) .betweenIfPresent(TenantDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(TenantDO::getAiExpireTime, reqVO.getAiExpireTime()) .betweenIfPresent(TenantDO::getExpireTime, reqVO.getExpireTime()) @@ -63,4 +64,22 @@ public interface TenantMapper extends BaseMapperX { } + default PageResult selectSelfPage(TenantPageReqVO reqVO){ + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(TenantDO::getParentId, reqVO.getParentId()) + .likeIfPresent(TenantDO::getName, reqVO.getName()) + .likeIfPresent(TenantDO::getContactName, reqVO.getContactName()) + .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile()) + .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(TenantDO::getCreateTime, reqVO.getCreateTime()) + .betweenIfPresent(TenantDO::getAiExpireTime, reqVO.getAiExpireTime()) + .betweenIfPresent(TenantDO::getExpireTime, reqVO.getExpireTime()) + .betweenIfPresent(TenantDO::getBrotherExpireTime, reqVO.getBrotherExpireTime()) + .likeIfPresent(TenantDO::getRemark, reqVO.getRemark()) + .orderByDesc(TenantDO::getId)); + } + + default List selectTenantByParentId(Long id){ + return selectList(TenantDO::getParentId, id); + } } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantagencypackage/TenantAgencyPackageMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantagencypackage/TenantAgencyPackageMapper.java new file mode 100644 index 0000000..6a820b0 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantagencypackage/TenantAgencyPackageMapper.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.dal.mysql.tenantagencypackage; + +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.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo.*; + +/** + * 代理租户套餐 Mapper + * + * @author 总后台 + */ +@Mapper +public interface TenantAgencyPackageMapper extends BaseMapperX { + + default PageResult selectPage(TenantAgencyPackagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(TenantAgencyPackageDO::getName, reqVO.getName()) + .eqIfPresent(TenantAgencyPackageDO::getStatus, reqVO.getStatus()) + .eqIfPresent(TenantAgencyPackageDO::getRemark, reqVO.getRemark()) + .eqIfPresent(TenantAgencyPackageDO::getMenuIds, reqVO.getMenuIds()) + .betweenIfPresent(TenantAgencyPackageDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(TenantAgencyPackageDO::getDays, reqVO.getDays()) + .eqIfPresent(TenantAgencyPackageDO::getPrice, reqVO.getPrice()) + .eqIfPresent(TenantAgencyPackageDO::getHostslClient, reqVO.getHostslClient()) + .eqIfPresent(TenantAgencyPackageDO::getBrotherClient, reqVO.getBrotherClient()) + .eqIfPresent(TenantAgencyPackageDO::getAiClient, reqVO.getAiClient()) + .eqIfPresent(TenantAgencyPackageDO::getPackageType, reqVO.getPackageType()) + .orderByDesc(TenantAgencyPackageDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(TenantAgencyPackageDO::getStatus, status); + } + + TenantAgencyPackageDO selectWithXml(Long packageId); +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantbalance/TenantBalanceMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantbalance/TenantBalanceMapper.java new file mode 100644 index 0000000..173f773 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantbalance/TenantBalanceMapper.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.system.dal.mysql.tenantbalance; + +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.module.system.dal.dataobject.tenantbalance.TenantBalanceDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo.*; +import org.apache.ibatis.annotations.Param; + +/** + * 租户余额 Mapper + * + * @author 总后台 + */ +@Mapper +public interface TenantBalanceMapper extends BaseMapperX { + + default PageResult selectPage(TenantBalancePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(TenantBalanceDO::getBalance, reqVO.getBalance()) + .eqIfPresent(TenantBalanceDO::getVersion, reqVO.getVersion()) + .eqIfPresent(TenantBalanceDO::getUpdatedAt, reqVO.getUpdatedAt()) + .orderByDesc(TenantBalanceDO::getId)); + } + + default Integer updateBalanceWithVersion(Long id, int amount, Integer oldVersion) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + + wrapper.eq(TenantBalanceDO::getId, id); + wrapper.eq(TenantBalanceDO::getVersion, oldVersion); + + // balance = balance + amount + wrapper.setSql("balance = balance + " + amount); + + // version = version + 1 + wrapper.setSql("version = version + 1"); + + return this.update(null, wrapper); + } + + + IPage selectPageWithTenantName(IPage iPage,@Param("req") TenantBalancePageReqVO pageReqVO); + + IPage selectPageWithSelfSubordinateTenant(@Param("iPage") IPage iPage, @Param("pageReqVO") TenantBalancePageReqVO pageReqVO, @Param("tenantId") Long tenantId); + + default Integer updateTestAccountNumWithVersion(Long currentTenantId, Integer newTestAccountNum, Integer oldVersion){ + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + + wrapper.eq(TenantBalanceDO::getId, currentTenantId); + wrapper.eq(TenantBalanceDO::getVersion, oldVersion); + + // testAccount = testAccount + -1 + wrapper.setSql("test_account_num = test_account_num + " + newTestAccountNum); + + // version = version + 1 + wrapper.setSql("version = version + 1"); + + return this.update(null, wrapper); + } +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantpoints/TenantPointsMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantpoints/TenantPointsMapper.java new file mode 100644 index 0000000..75c0ecf --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenantpoints/TenantPointsMapper.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.system.dal.mysql.tenantpoints; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +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.module.system.dal.dataobject.tenantpoints.TenantPointsDO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo.*; +import org.apache.ibatis.annotations.Param; + +/** + * 租户积分记录 Mapper + * + * @author 总后台 + */ +@Mapper +public interface TenantPointsMapper extends BaseMapperX { + + default PageResult selectPage(TenantPointsPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(TenantPointsDO::getPoints, reqVO.getPoints()) + .eqIfPresent(TenantPointsDO::getBalance, reqVO.getBalance()) + .eqIfPresent(TenantPointsDO::getType, reqVO.getType()) + .eqIfPresent(TenantPointsDO::getDescription, reqVO.getDescription()) + .eqIfPresent(TenantPointsDO::getOrderId, reqVO.getOrderId()) + .eqIfPresent(TenantPointsDO::getBizNo, reqVO.getBizNo()) + .eqIfPresent(TenantPointsDO::getOperatorId, reqVO.getOperatorId()) + .eqIfPresent(TenantPointsDO::getTargetTenantId, reqVO.getTargetTenantId()) + .eqIfPresent(TenantPointsDO::getCreatedAt, reqVO.getCreatedAt()) + .orderByDesc(TenantPointsDO::getId)); + } + + default PageResult TenantTransactionHistoryPointsPage(PageParam pageReqVO, Long tenantId){ + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(TenantPointsDO::getTenantId, tenantId) + .orderByDesc(TenantPointsDO::getCreatedAt)); + } + + default PageResult selectPageWithTenantId(TenantPointsPageReqVO reqVO, Long tenantId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(TenantPointsDO::getTenantId, tenantId) + .eqIfPresent(TenantPointsDO::getPoints, reqVO.getPoints()) + .eqIfPresent(TenantPointsDO::getBalance, reqVO.getBalance()) + .eqIfPresent(TenantPointsDO::getType, reqVO.getType()) + .eqIfPresent(TenantPointsDO::getDescription, reqVO.getDescription()) + .eqIfPresent(TenantPointsDO::getOrderId, reqVO.getOrderId()) + .eqIfPresent(TenantPointsDO::getBizNo, reqVO.getBizNo()) + .eqIfPresent(TenantPointsDO::getOperatorId, reqVO.getOperatorId()) + .eqIfPresent(TenantPointsDO::getTargetTenantId, reqVO.getTargetTenantId()) + .eqIfPresent(TenantPointsDO::getCreatedAt, reqVO.getCreatedAt()) + .orderByDesc(TenantPointsDO::getId)); + } + + IPage selectPageWithXML(@Param("iPage") IPage iPage, @Param("pageReqVO") TenantPointsPageReqVO pageReqVO); + + IPage selectPageWithTenantIdXML(@Param("iPage")IPage iPage,@Param("pageReqVO") TenantPointsPageReqVO pageReqVO,@Param("tenantId") Long tenantId); +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java index c303525..d598ead 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java @@ -3,10 +3,12 @@ package cn.iocoder.yudao.module.system.dal.mysql.user; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserRespVO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.Collection; import java.util.List; @@ -18,6 +20,7 @@ public interface AdminUserMapper extends BaseMapperX { return selectOne(AdminUserDO::getUsername, username); } + default AdminUserDO selectByUsernameAndTenantId(String username,Long tenantId) { return selectOne(AdminUserDO::getUsername, username ,AdminUserDO::getTenantId, tenantId); @@ -62,4 +65,10 @@ public interface AdminUserMapper extends BaseMapperX { } List selectTenantUserById(Long tenantId); + + @TenantIgnore + AdminUserDO selectByUsernameAndTenantIdWithAgencyRenewal(@Param("initialUser") String initialUser,@Param("targetTenantId") Long targetTenantId); + + @TenantIgnore + int updateByIdWithRenwal(AdminUserDO targetTenantUser); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index c89a5dc..9786772 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -109,25 +109,47 @@ public interface ErrorCodeConstants { ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!"); ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在"); ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的租户已存在"); + ErrorCode TENANT_LEVEL_CANT_CREATE_AGENCY = new ErrorCode(1_002_015_006, "租户级别不能创建代理租户"); + // ========== 租户套餐 1-002-016-000 ========== ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在"); ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "租户正在使用该套餐,请给租户重新设置套餐后再尝试删除"); ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用"); ErrorCode TENANT_PACKAGE_NAME_DUPLICATE = new ErrorCode(1_002_016_003, "已经存在该名字的租户套餐"); + ErrorCode TENANT_USER_NOT_EXISTS = new ErrorCode(1_002_016_004, "租户初始用户不存在"); + +// ========== 租户套餐 1-002-017-000 ========== + ErrorCode TENANT_POINTS_NOT_EXISTS = new ErrorCode(1_002_017_000, "租户积分不存在"); + +// ========== 租户余额 1-003-017-000 ========== + ErrorCode TENANT_BALANCE_NOT_EXISTS = new ErrorCode(1_003_017_000, "租户余额不存在"); + ErrorCode TENANT_BALANCE_VERSION_ERROR = new ErrorCode(1_003_017_001, "租户余额版本号错误"); + ErrorCode TENANT_BALANCE_BALANCE_ERROR = new ErrorCode(1_003_017_002, "租户余额余额错误"); + ErrorCode TENANT_BALANCE_BALANCE_NOT_ENOUGH = new ErrorCode(1_003_017_003, "租户余额余额不足"); + ErrorCode TENANT_BALANCE_RECHARGE_ERROR = new ErrorCode(1_003_017_004, "租户余额充值错误"); + ErrorCode TENANT_WALLET_NOT_EXISTS = new ErrorCode(1_003_017_005, "租户钱包不存在"); + ErrorCode TENANT_BALANCE_NOT_ENOUGH = new ErrorCode(1_003_017_006, "当前余额余额不足"); + ErrorCode TENANT_BALANCE_TRANSFER_ERROR = new ErrorCode(1_003_017_007, "转账余额不能小于等与 0"); + ErrorCode TENANT_BALANCE_TRANSFER_TARGET_NOT_EXISTS = new ErrorCode(1_003_017_008, "转账目标租户钱包不存在"); + ErrorCode TENANT_BALANCE_TRANSFER_OPERATION_ERROR = new ErrorCode(1_003_017_009, "转账操作失败"); + ErrorCode TENANT_BALANCE_TRANSFER_PASSWORD_ERROR = new ErrorCode(1_003_017_010, "转账密码错误"); + ErrorCode TENANT_BALANCE_TRANSFER_PASSWORD_ERROR_IS_NULL = new ErrorCode(1_003_017_011, "转账密码不能为空"); + ErrorCode TENANT_BALANCE_TRANSFER_ERROR_TARGET_NOT_SUBORDINATE = new ErrorCode(1_003_017_012, "转账目标租户不是当前租户的下级"); + ErrorCode TENANT_BALANCE_CONSUMPTION_OPERATION_ERROR = new ErrorCode(1_003_017_013, "租户余额消费操作失败"); + ErrorCode TENANT_CREATE_FAIL = new ErrorCode(1_003_017_014, "租户创建失败"); + ErrorCode TENANT_BALANCE_TEST_ACCOUNT_NUM_NOT_ENOUGH = new ErrorCode(1_003_017_015, "当前账户测试账户数量不足"); + ErrorCode TENANT_BALANCE_TEST_ACCOUNT_NUM_OPERATION_ERROR = new ErrorCode(1_003_017_016, "租户测试账户数量操作错误"); + ErrorCode TENANT_IS_AGENCY = new ErrorCode(1_003_017_017, "代理租户,不能进行续费操作"); + ErrorCode TENANT_UPDATE_INITIAL_USER_INFO_FAIL = new ErrorCode(1_003_017_018, "更新租户初始用户信息失败"); + ErrorCode TENANT_RENEWAL_FAIL = new ErrorCode(1_003_017_019, "租户续费失败"); + +// ================= 租户套餐 1-003-018-000 ================== + ErrorCode TENANT_AGENCY_PACKAGE_NOT_EXISTS = new ErrorCode(1_003_018_000, "代理租户套餐不存在"); + + - // ========== 社交用户 1-002-018-000 ========== - ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}"); - ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "获得小程序订阅消息模版失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR = new ErrorCode(1_002_018_203, "发送小程序订阅消息失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR = new ErrorCode(1_002_018_204, "上传微信小程序发货信息失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_NOTIFY_CONFIRM_RECEIVE_ERROR = new ErrorCode(1_002_018_205, "上传微信小程序订单收货信息失败"); - ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "社交客户端不存在"); - ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置"); // ========== OAuth2 客户端 1-002-020-000 ========= ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在"); diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/agencyTenantPackage/PackageTypeEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/agencyTenantPackage/PackageTypeEnum.java new file mode 100644 index 0000000..298e97c --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/agencyTenantPackage/PackageTypeEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.enums.agencyTenantPackage; + + +import lombok.Getter; + +/* + * @author: ziin + * @date: 2025/11/25 15:22 + */ +@Getter +public enum PackageTypeEnum { + + AI(0, "AI"), + CRAWL(1, "爬虫"), + BROTHER_CRAWL(2, "兄弟爬虫"), + TEST(99, "测试账户"), + AGENCY(999, "代理"); + + private final Integer value; + private final String name; + + PackageTypeEnum(Integer value, String name) { + this.value = value; + this.name = name; + } +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/balance/BalanceEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/balance/BalanceEnum.java new file mode 100644 index 0000000..a08a69a --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/balance/BalanceEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.enums.balance; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/* + * @author: ziin + * @date: 2025/11/19 21:30 + */ +@Getter +@AllArgsConstructor +@NoArgsConstructor +public enum BalanceEnum { + + + RECHARGE("充值"), + TRANSFER_OUT("转出"), + TRANSFER_IN("转入"), + CONSUMPTION("消费"), + BONUS("奖励"); + + + private String desc; + + + + +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/tenant/TenantEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/tenant/TenantEnum.java new file mode 100644 index 0000000..5432ea0 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/tenant/TenantEnum.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.enums.tenant; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/* + * @author: ziin + * @date: 2025/11/21 18:55 + */ +@Getter +@AllArgsConstructor +@NoArgsConstructor +public enum TenantEnum { + + + AGENCY("代理"), + USER("用户"); + + + private String tenantType; + +} diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageService.java index 1abe4fe..c190ab7 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageService.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; import javax.validation.Valid; import java.util.List; @@ -67,6 +68,6 @@ public interface TenantPackageService { * @param status 状态 * @return 租户套餐 */ - List getTenantPackageListByStatus(Integer status); + List getTenantPackageListByStatus(Integer status); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java index 8fccc64..88d8123 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java @@ -1,15 +1,20 @@ package cn.iocoder.yudao.module.system.service.tenant; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageSimpleRespVO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantPackageMapper; +import cn.iocoder.yudao.module.system.dal.mysql.tenantagencypackage.TenantAgencyPackageMapper; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.google.common.annotations.VisibleForTesting; import org.springframework.context.annotation.Lazy; @@ -38,6 +43,9 @@ public class TenantPackageServiceImpl implements TenantPackageService { @Lazy // 避免循环依赖的报错 private TenantService tenantService; + @Resource + private TenantAgencyPackageMapper tenantAgencyPackageMapper; + @Override public Long createTenantPackage(TenantPackageSaveReqVO createReqVO) { // 校验套餐名是否重复 @@ -113,8 +121,14 @@ public class TenantPackageServiceImpl implements TenantPackageService { } @Override - public List getTenantPackageListByStatus(Integer status) { - return tenantPackageMapper.selectListByStatus(status); + public List getTenantPackageListByStatus(Integer status) { + Long tenantId = TenantContextHolder.getTenantId(); + if (tenantId != 1) { + return tenantAgencyPackageMapper.selectListByStatus(status); + } + List tenantPackageDOS = tenantPackageMapper.selectListByStatus(status); + return BeanUtils.toBean(tenantPackageDOS, TenantAgencyPackageDO.class); + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java index 96af6bc..3749144 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.tenant; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRenewalReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; @@ -135,4 +136,9 @@ public interface TenantService { */ void validTenant(Long id); + PageResult getSelfTenantPage(@Valid TenantPageReqVO pageVO); + + List getChildrenTenant(Long id); + + void renewalTenant( TenantRenewalReqVO updateReqVO); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java index 956b957..69a7877 100755 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.system.service.tenant; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; @@ -11,33 +14,48 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.tenant.config.TenantProperties; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 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.permission.vo.role.RoleSaveReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRenewalReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantbalance.TenantBalanceDO; +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.tenant.TenantMapper; +import cn.iocoder.yudao.module.system.dal.mysql.tenantbalance.TenantBalanceMapper; +import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper; +import cn.iocoder.yudao.module.system.enums.agencyTenantPackage.PackageTypeEnum; import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; +import cn.iocoder.yudao.module.system.enums.tenant.TenantEnum; import cn.iocoder.yudao.module.system.service.permission.MenuService; import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.permission.RoleService; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; +import cn.iocoder.yudao.module.system.service.tenantagencypackage.TenantAgencyPackageService; +import cn.iocoder.yudao.module.system.service.tenantbalance.TenantBalanceService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Objects; import java.util.Set; @@ -74,6 +92,16 @@ public class TenantServiceImpl implements TenantService { private MenuService menuService; @Resource private PermissionService permissionService; + @Resource + private TenantBalanceMapper tenantBalanceMapper; + @Resource + private TenantAgencyPackageService tenantAgencyPackageService; + @Resource + private AdminUserMapper userMapper; + @Resource + private TenantBalanceService balanceService; + @Autowired + private TenantBalanceService tenantBalanceService; @Override public List getTenantIdList() { @@ -95,29 +123,262 @@ public class TenantServiceImpl implements TenantService { } } + @Override + public PageResult getSelfTenantPage(TenantPageReqVO pageVO) { + Long tenantId = TenantContextHolder.getTenantId(); + pageVO.setParentId(tenantId); + return tenantMapper.selectSelfPage(pageVO); + } + + @Override + public List getChildrenTenant(Long id) { + return tenantMapper.selectTenantByParentId(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TenantIgnore + public void renewalTenant(TenantRenewalReqVO updateReqVO) { + // 校验租户是否存在 + TenantDO targetTenant = getTenant(updateReqVO.getId()); + Long currentTenantId = TenantContextHolder.getTenantId(); + if (targetTenant == null) { + throw exception(TENANT_NOT_EXISTS); + } + + // 校验租户是否为代理类型 + if (targetTenant.getTenantType().equals(TenantEnum.AGENCY.getTenantType())) { + throw exception(TENANT_IS_AGENCY); + } + + TenantAgencyPackageDO tenantAgencyPackage = tenantAgencyPackageService.getTenantAgencyPackage(updateReqVO.getPackageId()); + + TenantBalanceDO tenantBalance = tenantBalanceService.getTenantBalance(currentTenantId); + + AdminUserDO targetTenantUser = userService.getUserByTenantIdAndUserName(updateReqVO.getId(), targetTenant.getInitialUser()); + + + if (targetTenantUser == null) { + throw exception(TENANT_USER_NOT_EXISTS); + } + + if (tenantBalance.getBalance()<=tenantAgencyPackage.getPrice()){ + throw exception(TENANT_BALANCE_NOT_ENOUGH); + } + + if (balanceService.consumption(tenantAgencyPackage.getId(), targetTenant.getId(), updateReqVO.getRemark())) { + log.info("代理: {} 续费租户:{} 成功,套餐 Id:{}", currentTenantId,targetTenant.getId(),updateReqVO.getPackageId()); + } + + if (targetTenant.getExpireTime().isBefore(LocalDateTime.now())){ + targetTenant.setExpireTime(LocalDateTime.now().plusDays(tenantAgencyPackage.getDays())); + targetTenant.setStatus(CommonStatusEnum.ENABLE.getStatus()); + targetTenantUser.setCrawl((byte) 1); + }else { + targetTenant.setExpireTime(targetTenant.getExpireTime().plusDays(tenantAgencyPackage.getDays())); + } + + if (tenantAgencyPackage.getAiClient()==1){ + if (targetTenant.getAiExpireTime().isBefore(LocalDateTime.now())){ + targetTenant.setAiExpireTime(LocalDateTime.now().plusDays(tenantAgencyPackage.getDays())); + targetTenantUser.setAiReplay((byte) 1); + targetTenantUser.setAiChat((byte) 1); + }else { + targetTenant.setAiExpireTime(targetTenant.getAiExpireTime().plusDays(tenantAgencyPackage.getDays())); + } + } + + if (tenantAgencyPackage.getBrotherClient() ==1 ){ + if (targetTenant.getBrotherExpireTime().isBefore(LocalDateTime.now())){ + targetTenant.setBrotherExpireTime(LocalDateTime.now().plusDays(tenantAgencyPackage.getDays())); + targetTenantUser.setBigBrother((byte) 1); + }else { + targetTenant.setBrotherExpireTime(targetTenant.getBrotherExpireTime().plusDays(tenantAgencyPackage.getDays())); + } + } + int updateInitialUserCount = userMapper.updateByIdWithRenwal(targetTenantUser); + if (updateInitialUserCount <= 0) { + throw exception(TENANT_UPDATE_INITIAL_USER_INFO_FAIL); + } + + int updateTenantCount = tenantMapper.updateById(targetTenant); + if (updateTenantCount <= 0) { + throw exception(TENANT_RENEWAL_FAIL); + } + + } + @Override @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 @DataPermission(enable = false) // 参见 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1154 说明 public Long createTenant(TenantSaveReqVO createReqVO) { - // 校验租户名称是否重复 + + // 获取当前操作租户的ID(即创建者的租户ID) + Long currentTenantId = TenantContextHolder.getTenantId(); + if (currentTenantId != 1){ + // 校验租户名称是否重复(null表示新增场景,无需排除当前ID) + validTenantNameDuplicate(createReqVO.getName(), null); + + // 校验租户域名是否重复(null表示新增场景,无需排除当前ID) + validTenantWebsiteDuplicate(createReqVO.getWebsite(), null); + + // 校验并获取租户套餐信息(确保套餐存在且未被禁用) + TenantAgencyPackageDO tenantAgencyPackageDO = tenantAgencyPackageService.validTenantPackage(createReqVO.getPackageId()); + + // 查询当前租户的详细信息 + TenantDO currentTenant = tenantMapper.selectById(currentTenantId); + + // 校验租户类型和层级权限:不允许创建代理类型租户,或当前租户级别为2的租户不允许创建 + if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) && currentTenant.getTenantLevel() == 2) { + throw exception(TENANT_LEVEL_CANT_CREATE_AGENCY); + } + + // 将请求参数转换为租户数据对象 + TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class); + + // 获取当前时间并计算租户过期时间 + String now = DateUtil.now(); // 获取当前时间字符串 + DateTime dt = DateUtil.parse(now); // 将时间字符串解析为DateTime对象 + LocalDateTime localDateTime = LocalDateTimeUtil.of(dt); // 转换为LocalDateTime对象 + // 根据套餐天数计算过期时间:当前时间 + 套餐天数 + LocalDateTime offset = LocalDateTimeUtil.offset(localDateTime, tenantAgencyPackageDO.getDays(), ChronoUnit.DAYS); + + // 设置租户的基本过期时间 + tenant.setExpireTime(offset); + // 设置租户的初始用户名(创建者) + tenant.setInitialUser(createReqVO.getUsername()); + + // 根据套餐配置设置特定功能的过期时间 + // 如果套餐包含"大哥客户端"功能,则设置大哥客户端的过期时间 + if (tenantAgencyPackageDO.getBrotherClient() == 1){ + tenant.setBrotherExpireTime(offset); + } + // 如果套餐包含"AI客户端"功能,则设置AI客户端的过期时间 + if (tenantAgencyPackageDO.getAiClient() == 1){ + tenant.setAiExpireTime(offset); + } + if(tenantAgencyPackageDO.getBrotherClient() == 2){} + // 设置新租户的级别为当前租户级别+1(层级关系) + if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType())){ + tenant.setTenantLevel(currentTenant.getTenantLevel() + 1); + } + // 设置新租户的父租户ID为当前租户ID(建立层级关系) + tenant.setParentId(currentTenantId); + + if (tenant.getTenantType().equals(TenantEnum.AGENCY.getTenantType())) { + tenant.setStatus(CommonStatusEnum.DISABLE.getStatus()); + } + + tenantMapper.insert(tenant); + // 扣除开通费用, + if (balanceService.consumption(createReqVO.getPackageId(), tenant.getId(), createReqVO.getRemark())) { + log.info("代理: {} 开通租户:{} 成功,套餐 Id:{}", currentTenantId,tenant.getId(),createReqVO.getPackageId()); + } + // 开通测试套餐扣除测试账号数 + if (tenantAgencyPackageDO.getPackageType().equals(PackageTypeEnum.TEST.getValue())){ + balanceService.reduceTestAccountNum(currentTenantId, createReqVO.getRemark()); + } + if (!tenantAgencyPackageDO.getPackageType().equals(PackageTypeEnum.AGENCY.getValue()) + && !tenantAgencyPackageDO.getPackageType().equals(PackageTypeEnum.TEST.getValue())) { + balanceService.addTestAccountNum(currentTenantId, createReqVO.getRemark()); + } + + // 在新创建的租户上下文中执行管理员初始化操作 + TenantUtils.execute(tenant.getId(), () -> { + // 创建租户的默认角色 + Long roleId = AgencyCreateRole(tenantAgencyPackageDO); + + // 创建租户的管理员用户,并分配角色 + Long userId = createUser(roleId, createReqVO); + AdminUserDO user = userService.getUser(userId); + if (tenantAgencyPackageDO.getHostslClient() == 1){ + user.setCrawl((byte) 1); + } + if (tenantAgencyPackageDO.getBrotherClient() == 1){ + user.setBigBrother((byte) 1); + } + if (tenantAgencyPackageDO.getAiClient() == 1){ + user.setAiChat((byte) 1); + } + if (tenantAgencyPackageDO.getAiReplay() == 1){ + user.setAiReplay((byte) 1); + } + if (tenantAgencyPackageDO.getWebAi() == 1){ + user.setWebAi((byte) 1); + } + userMapper.updateById(user); + // 将创建的用户设置为租户的联系人(管理员) + tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); + }); + + // 如果创建的是代理类型租户,则初始化其钱包 + if (tenant.getTenantType().equals("代理")) { + // 创建租户钱包对象 + TenantBalanceDO tenantBalance = new TenantBalanceDO(); + tenantBalance.setId(tenant.getId()); // 钱包ID与租户ID一致 + tenantBalance.setBalance(0); // 初始余额设为0 + tenantBalance.setVersion(0); // 初始版本号设为0 + tenantBalance.setTestAccountNum(15); + tenantBalanceMapper.insert(tenantBalance); // 插入钱包记录 + } + + // 返回新创建的租户ID + return tenant.getId(); + } + // 校验租户名称是否重复(null表示新增场景,无需排除当前ID) validTenantNameDuplicate(createReqVO.getName(), null); - // 校验租户域名是否重复 + + // 校验租户域名是否重复(null表示新增场景,无需排除当前ID) validTenantWebsiteDuplicate(createReqVO.getWebsite(), null); - // 校验套餐被禁用 + + // 校验并获取租户套餐信息(确保套餐存在且未被禁用) TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId()); - // 创建租户 + // 查询当前租户的详细信息 + TenantDO currentTenant = tenantMapper.selectById(currentTenantId); + + // 校验租户类型和层级权限:不允许创建代理类型租户,或当前租户级别为2的租户不允许创建 + if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) && currentTenant.getTenantLevel() == 2) { + throw exception(TENANT_LEVEL_CANT_CREATE_AGENCY); + } + + // 将请求参数转换为租户数据对象 TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class); + + // 设置新租户的级别为当前租户级别+1(层级关系) + if (createReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType())){ + tenant.setTenantLevel(currentTenant.getTenantLevel() + 1); + } + // 设置新租户的父租户ID为当前租户ID(建立层级关系) + tenant.setParentId(currentTenantId); + + // 将新租户信息插入数据库 tenantMapper.insert(tenant); - // 创建租户的管理员 + + // 在新创建的租户上下文中执行管理员初始化操作 TenantUtils.execute(tenant.getId(), () -> { - // 创建角色 + // 创建租户的默认角色 Long roleId = createRole(tenantPackage); - // 创建用户,并分配角色 + + // 创建租户的管理员用户,并分配角色 Long userId = createUser(roleId, createReqVO); - // 修改租户的管理员 + + // 将创建的用户设置为租户的联系人(管理员) tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); }); + + // 如果创建的是代理类型租户,则初始化其钱包 + if (tenant.getTenantType().equals("代理")) { + // 创建租户钱包对象 + TenantBalanceDO tenantBalance = new TenantBalanceDO(); + tenantBalance.setId(tenant.getId()); // 钱包ID与租户ID一致 + tenantBalance.setBalance(0); // 初始余额设为0 + tenantBalance.setVersion(0); // 初始版本号设为0 + tenantBalance.setTestAccountNum(15); + tenantBalanceMapper.insert(tenantBalance); // 插入钱包记录 + } + + // 返回新创建的租户ID return tenant.getId(); } @@ -140,6 +401,17 @@ public class TenantServiceImpl implements TenantService { return roleId; } + private Long AgencyCreateRole(TenantAgencyPackageDO agencyPackageDO) { + // 创建角色 + RoleSaveReqVO reqVO = new RoleSaveReqVO(); + reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode()) + .setSort(0).setRemark("系统自动生成"); + Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType()); + // 分配权限 + permissionService.assignRoleMenu(roleId, agencyPackageDO.getMenuIds()); + return roleId; + } + @Override @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 public void updateTenant(TenantSaveReqVO updateReqVO) { @@ -150,15 +422,27 @@ public class TenantServiceImpl implements TenantService { // 校验租户域名是否重复 validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId()); // 校验套餐被禁用 - TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); - // 更新租户 - TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class); - tenantMapper.updateById(updateObj); - // 如果套餐发生变化,则修改其角色的权限 - if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { - updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds()); + if (updateReqVO.getTenantType().equals(TenantEnum.AGENCY.getTenantType()) || tenant.getParentId() != 1) { + TenantAgencyPackageDO tenantAgencyPackageDO = tenantAgencyPackageService.validTenantPackage(updateReqVO.getPackageId()); + // 更新租户 + TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class); + tenantMapper.updateById(updateObj); + // 如果套餐发生变化,则修改其角色的权限 + if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { + updateTenantRoleMenu(tenant.getId(), tenantAgencyPackageDO.getMenuIds()); + } + }else { + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); + // 更新租户 + TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class); + tenantMapper.updateById(updateObj); + // 如果套餐发生变化,则修改其角色的权限 + if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { + updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds()); + } } + } private void validTenantNameDuplicate(String name, Long id) { @@ -310,4 +594,4 @@ public class TenantServiceImpl implements TenantService { return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable()); } -} +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantagencypackage/TenantAgencyPackageService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantagencypackage/TenantAgencyPackageService.java new file mode 100644 index 0000000..8eba9f4 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantagencypackage/TenantAgencyPackageService.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.system.service.tenantagencypackage; + +import java.util.*; +import javax.validation.*; +import javax.validation.constraints.NotNull; + +import cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo.*; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; + +/** + * 代理租户套餐 Service 接口 + * + * @author 总后台 + */ +public interface TenantAgencyPackageService { + + /** + * 创建代理租户套餐 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTenantAgencyPackage(@Valid TenantAgencyPackageSaveReqVO createReqVO); + + /** + * 更新代理租户套餐 + * + * @param updateReqVO 更新信息 + */ + void updateTenantAgencyPackage(@Valid TenantAgencyPackageSaveReqVO updateReqVO); + + /** + * 删除代理租户套餐 + * + * @param id 编号 + */ + void deleteTenantAgencyPackage(Long id); + + /** + * 批量删除代理租户套餐 + * + * @param ids 编号 + */ + void deleteTenantAgencyPackageListByIds(List ids); + + /** + * 获得代理租户套餐 + * + * @param id 编号 + * @return 代理租户套餐 + */ + TenantAgencyPackageDO getTenantAgencyPackage(Long id); + + /** + * 获得代理租户套餐分页 + * + * @param pageReqVO 分页查询 + * @return 代理租户套餐分页 + */ + PageResult getTenantAgencyPackagePage(TenantAgencyPackagePageReqVO pageReqVO); + + TenantAgencyPackageDO validTenantPackage(@NotNull(message = "租户套餐编号不能为空") Long packageId); + + List getTenantPackageListByStatus(Integer status); +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantagencypackage/TenantAgencyPackageServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantagencypackage/TenantAgencyPackageServiceImpl.java new file mode 100644 index 0000000..ec2b6cb --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantagencypackage/TenantAgencyPackageServiceImpl.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.system.service.tenantagencypackage; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; + +import java.util.*; +import cn.iocoder.yudao.module.system.controller.admin.tenantagencypackage.vo.*; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.system.dal.mysql.tenantagencypackage.TenantAgencyPackageMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 代理租户套餐 Service 实现类 + * + * @author 总后台 + */ +@Service +@Validated +public class TenantAgencyPackageServiceImpl implements TenantAgencyPackageService { + + @Resource + private TenantAgencyPackageMapper tenantAgencyPackageMapper; + + @Override + public Long createTenantAgencyPackage(TenantAgencyPackageSaveReqVO createReqVO) { + // 插入 + TenantAgencyPackageDO tenantAgencyPackage = BeanUtils.toBean(createReqVO, TenantAgencyPackageDO.class); + tenantAgencyPackageMapper.insert(tenantAgencyPackage); + // 返回 + return tenantAgencyPackage.getId(); + } + + @Override + public void updateTenantAgencyPackage(TenantAgencyPackageSaveReqVO updateReqVO) { + // 校验存在 + validateTenantAgencyPackageExists(updateReqVO.getId()); + // 更新 + TenantAgencyPackageDO updateObj = BeanUtils.toBean(updateReqVO, TenantAgencyPackageDO.class); + tenantAgencyPackageMapper.updateById(updateObj); + } + + @Override + public void deleteTenantAgencyPackage(Long id) { + // 校验存在 + validateTenantAgencyPackageExists(id); + // 删除 + tenantAgencyPackageMapper.deleteById(id); + } + + @Override + public void deleteTenantAgencyPackageListByIds(List ids) { + // 校验存在 + validateTenantAgencyPackageExists(ids); + // 删除 + tenantAgencyPackageMapper.deleteByIds(ids); + } + + private void validateTenantAgencyPackageExists(List ids) { + List list = tenantAgencyPackageMapper.selectByIds(ids); + if (CollUtil.isEmpty(list) || list.size() != ids.size()) { + throw exception(TENANT_AGENCY_PACKAGE_NOT_EXISTS); + } + } + + private void validateTenantAgencyPackageExists(Long id) { + if (tenantAgencyPackageMapper.selectById(id) == null) { + throw exception(TENANT_AGENCY_PACKAGE_NOT_EXISTS); + } + } + + @Override + public TenantAgencyPackageDO getTenantAgencyPackage(Long id) { + return tenantAgencyPackageMapper.selectById(id); + } + + @Override + public PageResult getTenantAgencyPackagePage(TenantAgencyPackagePageReqVO pageReqVO) { + return tenantAgencyPackageMapper.selectPage(pageReqVO); + } + + @Override + public TenantAgencyPackageDO validTenantPackage(Long packageId) { + + TenantAgencyPackageDO tenantAgencyPackageDO = tenantAgencyPackageMapper.selectById(packageId); + + if (tenantAgencyPackageDO == null) { + throw exception(TENANT_PACKAGE_NOT_EXISTS); + } + if (tenantAgencyPackageDO.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { + throw exception(TENANT_PACKAGE_DISABLE, tenantAgencyPackageDO.getName()); + } + return tenantAgencyPackageDO; + } + + @Override + public List getTenantPackageListByStatus(Integer status) { + return tenantAgencyPackageMapper.selectListByStatus(status); + } + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantbalance/TenantBalanceService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantbalance/TenantBalanceService.java new file mode 100644 index 0000000..adb7886 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantbalance/TenantBalanceService.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.system.service.tenantbalance; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantbalance.TenantBalanceDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 租户余额 Service 接口 + * + * @author 总后台 + */ +public interface TenantBalanceService { + + /** + * 创建租户余额 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTenantBalance(@Valid TenantBalanceSaveReqVO createReqVO); + + /** + * 更新租户余额 + * + * @param updateReqVO 更新信息 + */ + void updateTenantBalance(@Valid TenantBalanceSaveReqVO updateReqVO); + + /** + * 删除租户余额 + * + * @param id 编号 + */ + void deleteTenantBalance(Long id); + + /** + * 批量删除租户余额 + * + * @param ids 编号 + */ + void deleteTenantBalanceListByIds(List ids); + + /** + * 获得租户余额 + * + * @param id 编号 + * @return 租户余额 + */ + TenantBalanceDO getTenantBalance(Long id); + + /** + * 获得租户余额分页 + * + * @param pageReqVO 分页查询 + * @return 租户余额分页 + */ + PageResult getTenantBalancePage(TenantBalancePageReqVO pageReqVO); + + void addTenantBalance(@Valid TenantBalanceAddReqVO updateReqVO); + + void transferToTenant(@Valid TenantBalanceTransferReqVO transferReqVO); + + TenantBalanceDO getSelfBalance(); + + PageResult getSelfSubordinateTenantBalancePage(@Valid TenantBalancePageReqVO pageReqVO); + + Boolean consumption(Long PackageId, Long targetTenantId,String remark); + + Boolean reduceTestAccountNum(Long currentTenantId, String remark); + + Boolean addTestAccountNum(Long currentTenantId, String remark); +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantbalance/TenantBalanceServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantbalance/TenantBalanceServiceImpl.java new file mode 100644 index 0000000..4046ea6 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantbalance/TenantBalanceServiceImpl.java @@ -0,0 +1,430 @@ +package cn.iocoder.yudao.module.system.service.tenantbalance; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.module.system.controller.admin.tenantbalance.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantagencypackage.TenantAgencyPackageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantbalance.TenantBalanceDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantpoints.TenantPointsDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; +import cn.iocoder.yudao.module.system.dal.mysql.tenantagencypackage.TenantAgencyPackageMapper; +import cn.iocoder.yudao.module.system.dal.mysql.tenantbalance.TenantBalanceMapper; +import cn.iocoder.yudao.module.system.dal.mysql.tenantpoints.TenantPointsMapper; +import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import cn.iocoder.yudao.module.system.util.BizNoGenerator; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.system.enums.balance.BalanceEnum.*; + +/** + * 租户余额 Service 实现类 + * + * @author 总后台 + */ +@Service +@Validated +public class TenantBalanceServiceImpl implements TenantBalanceService { + + @Resource + private TenantBalanceMapper tenantBalanceMapper; + + @Resource + private TenantPointsMapper tenantPointsMapper; + + @Resource + private AdminUserService userService; + + @Resource + private TenantMapper tenantMapper; + + @Resource + private TenantAgencyPackageMapper tenantAgencyPackageMapper; + + @Override + public Long createTenantBalance(TenantBalanceSaveReqVO createReqVO) { + // 插入 + TenantBalanceDO tenantBalance = BeanUtils.toBean(createReqVO, TenantBalanceDO.class); + tenantBalanceMapper.insert(tenantBalance); + // 返回 + return tenantBalance.getId(); + } + + @Override + public void updateTenantBalance(TenantBalanceSaveReqVO updateReqVO) { + // 校验存在 + validateTenantBalanceExists(updateReqVO.getId()); + // 更新 + TenantBalanceDO updateObj = BeanUtils.toBean(updateReqVO, TenantBalanceDO.class); + tenantBalanceMapper.updateById(updateObj); + } + + @Override + public void deleteTenantBalance(Long id) { + // 校验存在 + validateTenantBalanceExists(id); + // 删除 + tenantBalanceMapper.deleteById(id); + } + + @Override + public void deleteTenantBalanceListByIds(List ids) { + // 校验存在 + validateTenantBalanceExists(ids); + // 删除 + tenantBalanceMapper.deleteByIds(ids); + } + + private void validateTenantBalanceExists(List ids) { + List list = tenantBalanceMapper.selectByIds(ids); + if (CollUtil.isEmpty(list) || list.size() != ids.size()) { + throw exception(TENANT_BALANCE_NOT_EXISTS); + } + } + + private void validateTenantBalanceExists(Long id) { + if (tenantBalanceMapper.selectById(id) == null) { + throw exception(TENANT_BALANCE_NOT_EXISTS); + } + } + + @Override + public TenantBalanceDO getTenantBalance(Long id) { + return tenantBalanceMapper.selectById(id); + } + + @Override + public PageResult getTenantBalancePage(TenantBalancePageReqVO pageReqVO) { + IPage iPage = new Page<>(pageReqVO.getPageNo(),pageReqVO.getPageSize()); + IPage tenantBalanceRespVOIPage = tenantBalanceMapper.selectPageWithTenantName(iPage, pageReqVO); + return new PageResult<>(tenantBalanceRespVOIPage.getRecords(),tenantBalanceRespVOIPage.getTotal()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addTenantBalance(TenantBalanceAddReqVO addReqVO) { + + // 校验存在 + if (tenantBalanceMapper.selectById(addReqVO.getId()) == null) { + // 初始化余额为 0 + TenantBalanceDO tenantBalance = new TenantBalanceDO(); + tenantBalance.setId(addReqVO.getId()); + tenantBalance.setBalance(0); + tenantBalance.setVersion(0); + tenantBalanceMapper.insert(tenantBalance); + } + String recharge = BizNoGenerator.generate("RECHARGE"); + // 获取初始化查询结果 + + TenantBalanceDO tenantBalance = tenantBalanceMapper.selectById(addReqVO.getId()); + Integer newBalance = tenantBalance.getBalance()+addReqVO.getAmount(); + Integer oldVersion = tenantBalance.getVersion(); + + Integer updateCount = tenantBalanceMapper.updateBalanceWithVersion(addReqVO.getId(), addReqVO.getAmount(), oldVersion); + if (updateCount == 0) { + throw exception(TENANT_BALANCE_RECHARGE_ERROR); + } + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser == null) { + throw exception(USER_NOT_EXISTS); + } + + TenantPointsDO tenantPointsDO = new TenantPointsDO(); + tenantPointsDO.setTenantId(addReqVO.getId()); + tenantPointsDO.setPoints(addReqVO.getAmount()); + tenantPointsDO.setBalance(newBalance); + tenantPointsDO.setOperatorId(loginUser.getId()); + tenantPointsDO.setType(RECHARGE.getDesc()); // RECHARGE / BONUS / ... + tenantPointsDO.setDescription("总后台充值,金额:"+addReqVO.getAmount()); + tenantPointsDO.setRemark(addReqVO.getRemark()); + tenantPointsDO.setBizNo(recharge); + tenantPointsMapper.insert(tenantPointsDO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void transferToTenant(TenantBalanceTransferReqVO transferReqVO) { + + /** + * 执行租户余额转账操作 + * 注:这部分代码应该位于某个转账相关的方法中 + */ + // 获取当前登录用户ID,用于操作记录和权限验证 + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + + // 生成转账业务流水号,用于唯一标识这笔转账交易 + String transfer = BizNoGenerator.generate("TRANSFER"); + + // 验证转账密码是否为空 + if (transferReqVO.getPassword().isEmpty()) { + throw exception(TENANT_BALANCE_TRANSFER_PASSWORD_ERROR_IS_NULL); + } + TenantDO targetTenantInfo = tenantMapper.selectById(transferReqVO.getTargetTenantId()); + + + // 获取当前登录用户信息 + AdminUserDO user = userService.getUser(loginUserId); + + // 验证转账密码是否正确 + if (!userService.isPasswordMatch(transferReqVO.getPassword(), user.getPassword())) { + throw exception(TENANT_BALANCE_TRANSFER_PASSWORD_ERROR); + } + + // 获取当前租户ID(转出方) + Long tenantId = TenantContextHolder.getTenantId(); + + if (!Objects.equals(targetTenantInfo.getParentId(), tenantId)) { + throw exception(TENANT_BALANCE_TRANSFER_ERROR_TARGET_NOT_SUBORDINATE); + } + + // 校验当前租户钱包是否存在 + TenantBalanceDO tenantBalanceDO = tenantBalanceMapper.selectById(tenantId); + if (tenantBalanceDO == null) { + throw exception(TENANT_WALLET_NOT_EXISTS); + } + + // 获取目标租户(转入方)的余额信息 + TenantBalanceDO targetTenantBalance = tenantBalanceMapper.selectById(transferReqVO.getTargetTenantId()); + + // 校验目标租户钱包是否存在 + if (targetTenantBalance == null) { + throw exception(TENANT_BALANCE_TRANSFER_TARGET_NOT_EXISTS); + } + + // 校验当前租户余额是否足够支付转账金额 + if (tenantBalanceDO.getBalance() < transferReqVO.getTransferAmount()) { + throw exception(TENANT_BALANCE_NOT_ENOUGH); + } + + // 校验转账金额是否有效(必须大于0) + if (transferReqVO.getTransferAmount() <= 0) { + throw exception(TENANT_BALANCE_TRANSFER_ERROR); + } + + // 计算转账后转出方的新余额 + Integer tenantNewBalance = tenantBalanceDO.getBalance() - transferReqVO.getTransferAmount(); + + // 计算转账后转入方的新余额 + Integer targetTenantNewBalance = targetTenantBalance.getBalance() + transferReqVO.getTransferAmount(); + + // 获取转出方当前的版本号(用于乐观锁控制) + Integer tenantBalanceDOVersion = tenantBalanceDO.getVersion(); + + // 获取转入方当前的版本号(用于乐观锁控制) + Integer targetTenantBalanceVersion = targetTenantBalance.getVersion(); + + // 先更新转入方的余额(使用乐观锁) + Integer updateTargetBalanceCount = tenantBalanceMapper + .updateBalanceWithVersion(transferReqVO.getTargetTenantId(), transferReqVO.getTransferAmount(), targetTenantBalanceVersion); + + // 如果更新转入方失败,抛出异常 + if (updateTargetBalanceCount == 0) { + throw exception(TENANT_BALANCE_TRANSFER_OPERATION_ERROR); + } + + // 再更新转出方的余额(使用乐观锁,金额为负数表示减少) + Integer updateCount = tenantBalanceMapper + .updateBalanceWithVersion(tenantId, -transferReqVO.getTransferAmount(), tenantBalanceDOVersion); + + // 如果更新转出方失败,抛出异常 + if (updateCount == 0) { + throw exception(TENANT_BALANCE_TRANSFER_OPERATION_ERROR); + } + + // 创建转出方的积分变动记录 + TenantPointsDO tenantPointsDO = new TenantPointsDO(); + tenantPointsDO.setTenantId(tenantId); // 设置租户ID + tenantPointsDO.setPoints(-transferReqVO.getTransferAmount()); // 设置变动积分(负数表示减少) + tenantPointsDO.setBalance(tenantNewBalance); // 设置变动后的余额 + tenantPointsDO.setOperatorId(loginUserId); // 设置操作人ID + tenantPointsDO.setType(TRANSFER_OUT.getDesc()); // 设置交易类型为转账 + tenantPointsDO.setDescription("转账给租户" + transferReqVO.getTargetTenantId() + ",金额:" + transferReqVO.getTransferAmount()); // 设置交易描述 + tenantPointsDO.setTargetTenantId(transferReqVO.getTargetTenantId()); // 设置目标租户ID + tenantPointsDO.setBizNo(transfer); // 设置业务流水号 + tenantPointsDO.setRemark(transferReqVO.getRemark()); + int tenantInsert = tenantPointsMapper.insert(tenantPointsDO); // 插入记录 + + // 创建转入方的积分变动记录 + TenantPointsDO targetPointsDO = new TenantPointsDO(); + targetPointsDO.setTenantId(transferReqVO.getTargetTenantId()); // 设置目标租户ID + targetPointsDO.setPoints(transferReqVO.getTransferAmount()); // 设置变动积分(正数表示增加) + targetPointsDO.setBalance(targetTenantNewBalance); // 设置变动后的余额 + targetPointsDO.setOperatorId(loginUserId); // 设置操作人ID + targetPointsDO.setType(TRANSFER_IN.getDesc()); // 设置交易类型为转账 + targetPointsDO.setTargetTenantId(tenantId);// 设置目标租户ID + targetPointsDO.setDescription("转账来自租户" + tenantId + ",金额:" + transferReqVO.getTransferAmount()); // 设置交易描述 + targetPointsDO.setBizNo(transfer); // 设置业务流水号(与转出方使用同一个流水号) + int targetInsert = tenantPointsMapper.insert(targetPointsDO); // 插入记录 + + // 验证交易记录是否都插入成功 + if (tenantInsert == 0 || targetInsert == 0) { + throw exception(TENANT_BALANCE_TRANSFER_OPERATION_ERROR); + } + + } + + @Override + public TenantBalanceDO getSelfBalance() { + Long tenantId = TenantContextHolder.getTenantId(); + TenantBalanceDO tenantBalance = tenantBalanceMapper.selectById(tenantId); + if (tenantBalance == null) { + throw exception(TENANT_WALLET_NOT_EXISTS); + } + return tenantBalance; + } + + @Override + public PageResult getSelfSubordinateTenantBalancePage(TenantBalancePageReqVO pageReqVO) { + Long tenantId = TenantContextHolder.getTenantId(); + IPage iPage = new Page<>(pageReqVO.getPageNo(),pageReqVO.getPageSize()); + IPage tenantBalanceRespVOIPage = tenantBalanceMapper.selectPageWithSelfSubordinateTenant(iPage, pageReqVO,tenantId); + return new PageResult<>(tenantBalanceRespVOIPage.getRecords(),tenantBalanceRespVOIPage.getTotal()); + } + + @Override + public Boolean consumption(Long PackageId, Long targetTenantId,String remark) { + + Long tenantId = TenantContextHolder.getTenantId(); + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + + String consumption = BizNoGenerator.generate("CONSUMPTION"); + String order = BizNoGenerator.generate("ORDER"); + + // 从数据库中查询租户余额 + TenantBalanceDO tenantBalance = tenantBalanceMapper.selectById(tenantId); + if (tenantBalance == null) { + throw exception(TENANT_WALLET_NOT_EXISTS); + } + // 从数据库中查询套餐信息 + TenantAgencyPackageDO tenantAgencyPackageDO = tenantAgencyPackageMapper.selectById(PackageId); + if (tenantAgencyPackageDO == null) { + throw exception(TENANT_AGENCY_PACKAGE_NOT_EXISTS); + } + // 检查租户余额是否足够 + if (tenantBalance.getBalance() < tenantAgencyPackageDO.getPrice()) { + throw exception(TENANT_BALANCE_BALANCE_NOT_ENOUGH); + } + + Integer tenantBalanceDOVersion = tenantBalance.getVersion(); + + Integer oldBalance = tenantBalance.getBalance(); + + Integer newBalance = oldBalance - tenantAgencyPackageDO.getPrice(); + // 更新租户余额 + Integer updateCount = tenantBalanceMapper.updateBalanceWithVersion(tenantId, -tenantAgencyPackageDO.getPrice(), tenantBalanceDOVersion); + + if (updateCount == 0) { + throw exception(TENANT_BALANCE_CONSUMPTION_OPERATION_ERROR); + } + + // 消费积分变动记录 + TenantPointsDO tenantPointsDO = new TenantPointsDO(); + tenantPointsDO.setTenantId(tenantId); // 设置租户ID + tenantPointsDO.setPoints(-tenantAgencyPackageDO.getPrice()); // 设置变动积分(负数表示减少) + tenantPointsDO.setBalance(newBalance); // 设置变动后的余额 + tenantPointsDO.setOperatorId(loginUserId); // 设置操作人ID + tenantPointsDO.setType(CONSUMPTION.getDesc()); // 设置交易类型为转账 + tenantPointsDO.setDescription("给租户" + targetTenantId + "开通套餐" + tenantAgencyPackageDO.getName() + ",金额:" + tenantAgencyPackageDO.getPrice()); // 设置交易描述 + tenantPointsDO.setTargetTenantId(targetTenantId); // 设置目标租户ID + tenantPointsDO.setBizNo(consumption); // 设置业务流水号 + tenantPointsDO.setRemark(remark); + tenantPointsDO.setOrderId(order); + int tenantInsert = tenantPointsMapper.insert(tenantPointsDO); // 插入记录 + if (tenantInsert == 0) { + throw exception(TENANT_BALANCE_CONSUMPTION_OPERATION_ERROR); + } + + return true; + + + + } + + @Override + public Boolean reduceTestAccountNum(Long currentTenantId,String remark) { + TenantBalanceDO tenantBalanceDO = tenantBalanceMapper.selectById(currentTenantId); + if (tenantBalanceDO.getTestAccountNum()<=0) { + throw exception(TENANT_BALANCE_TEST_ACCOUNT_NUM_NOT_ENOUGH); + } + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + Integer oldVersion = tenantBalanceDO.getVersion(); + Integer newTestAccountNum = tenantBalanceDO.getTestAccountNum() - 1; + + Integer i = tenantBalanceMapper.updateTestAccountNumWithVersion(currentTenantId, -1, oldVersion); + if (i == 0) { + throw exception(TENANT_BALANCE_TEST_ACCOUNT_NUM_OPERATION_ERROR); + } + String consumption = BizNoGenerator.generate("CONSUMPTION"); + + // 消费积分变动记录 + TenantPointsDO tenantPointsDO = new TenantPointsDO(); + tenantPointsDO.setTenantId(currentTenantId); // 设置租户ID + tenantPointsDO.setPoints(-1); // 设置变动积分(负数表示减少) + tenantPointsDO.setBalance(tenantPointsDO.getBalance()); + tenantPointsDO.setTestAccountNum(newTestAccountNum); // 设置变动后的余额 + tenantPointsDO.setOperatorId(loginUserId); // 设置操作人ID + tenantPointsDO.setType(CONSUMPTION.getDesc()); // 设置交易类型为转账 + tenantPointsDO.setDescription("开通测试账户"); // 设置交易描述 + tenantPointsDO.setRemark(remark); + tenantPointsDO.setBizNo(consumption); // 设置业务流水号 + int tenantInsert = tenantPointsMapper.insert(tenantPointsDO); // 插入记录 + if (tenantInsert == 0) { + throw exception(TENANT_BALANCE_CONSUMPTION_OPERATION_ERROR); + } + return true; + } + + @Override + public Boolean addTestAccountNum(Long currentTenantId,String remark) { + TenantBalanceDO tenantBalanceDO = tenantBalanceMapper.selectById(currentTenantId); + + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + + Integer oldVersion = tenantBalanceDO.getVersion(); + + Integer newTestAccountNum = tenantBalanceDO.getTestAccountNum() + 5; + + Integer i = tenantBalanceMapper.updateTestAccountNumWithVersion(currentTenantId, 5, oldVersion); + if (i == 0) { + throw exception(TENANT_BALANCE_TEST_ACCOUNT_NUM_OPERATION_ERROR); + } + String bonus = BizNoGenerator.generate("BONUS"); + + // 消费积分变动记录 + TenantPointsDO tenantPointsDO = new TenantPointsDO(); + tenantPointsDO.setTenantId(currentTenantId); // 设置租户ID + tenantPointsDO.setPoints(5); // 设置变动积分(负数表示减少) + tenantPointsDO.setTestAccountNum(newTestAccountNum); // 设置变动后的余额 + tenantPointsDO.setBalance(tenantPointsDO.getBalance()); + tenantPointsDO.setOperatorId(loginUserId); // 设置操作人ID + tenantPointsDO.setType(BONUS.getDesc()); // 设置交易类型为转账 + tenantPointsDO.setDescription("开通测试账户,增加测试账号数量"); // 设置交易描述 + tenantPointsDO.setBizNo(bonus); // 设置业务流水号 + tenantPointsDO.setRemark(remark); + int tenantInsert = tenantPointsMapper.insert(tenantPointsDO); // 插入记录 + if (tenantInsert == 0) { + throw exception(TENANT_BALANCE_CONSUMPTION_OPERATION_ERROR); + } + + return true; + } + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantpoints/TenantPointsService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantpoints/TenantPointsService.java new file mode 100644 index 0000000..a7c548e --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantpoints/TenantPointsService.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.service.tenantpoints; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantpoints.TenantPointsDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 租户积分记录 Service 接口 + * + * @author 总后台 + */ +public interface TenantPointsService { + + /** + * 创建租户积分记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTenantPoints(@Valid TenantPointsSaveReqVO createReqVO); + + /** + * 更新租户积分记录 + * + * @param updateReqVO 更新信息 + */ + void updateTenantPoints(@Valid TenantPointsSaveReqVO updateReqVO); + + /** + * 删除租户积分记录 + * + * @param id 编号 + */ + void deleteTenantPoints(Long id); + + /** + * 批量删除租户积分记录 + * + * @param ids 编号 + */ + void deleteTenantPointsListByIds(List ids); + + /** + * 获得租户积分记录 + * + * @param id 编号 + * @return 租户积分记录 + */ + TenantPointsDO getTenantPoints(Long id); + + /** + * 获得租户积分记录分页 + * + * @param pageReqVO 分页查询 + * @return 租户积分记录分页 + */ + PageResult getTenantPointsPage(TenantPointsPageReqVO pageReqVO); + + PageResult getTenantTransactionHistoryPointsPage(PageParam pageReqVO, Long tenantId); +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantpoints/TenantPointsServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantpoints/TenantPointsServiceImpl.java new file mode 100644 index 0000000..a3623ae --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/tenantpoints/TenantPointsServiceImpl.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.system.service.tenantpoints; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; + +import java.util.*; +import cn.iocoder.yudao.module.system.controller.admin.tenantpoints.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.tenantpoints.TenantPointsDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.system.dal.mysql.tenantpoints.TenantPointsMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 租户积分记录 Service 实现类 + * + * @author 总后台 + */ +@Service +@Validated +public class TenantPointsServiceImpl implements TenantPointsService { + + @Resource + private TenantPointsMapper tenantPointsMapper; + + @Override + public Long createTenantPoints(TenantPointsSaveReqVO createReqVO) { + // 插入 + TenantPointsDO tenantPoints = BeanUtils.toBean(createReqVO, TenantPointsDO.class); + tenantPointsMapper.insert(tenantPoints); + // 返回 + return tenantPoints.getId(); + } + + @Override + public void updateTenantPoints(TenantPointsSaveReqVO updateReqVO) { + // 校验存在 + validateTenantPointsExists(updateReqVO.getId()); + // 更新 + TenantPointsDO updateObj = BeanUtils.toBean(updateReqVO, TenantPointsDO.class); + tenantPointsMapper.updateById(updateObj); + } + + @Override + public void deleteTenantPoints(Long id) { + // 校验存在 + validateTenantPointsExists(id); + // 删除 + tenantPointsMapper.deleteById(id); + } + + @Override + public void deleteTenantPointsListByIds(List ids) { + // 校验存在 + validateTenantPointsExists(ids); + // 删除 + tenantPointsMapper.deleteByIds(ids); + } + + private void validateTenantPointsExists(List ids) { + List list = tenantPointsMapper.selectByIds(ids); + if (CollUtil.isEmpty(list) || list.size() != ids.size()) { + throw exception(TENANT_POINTS_NOT_EXISTS); + } + } + + private void validateTenantPointsExists(Long id) { + if (tenantPointsMapper.selectById(id) == null) { + throw exception(TENANT_POINTS_NOT_EXISTS); + } + } + + @Override + public TenantPointsDO getTenantPoints(Long id) { + return tenantPointsMapper.selectById(id); + } + + @Override + public PageResult getTenantPointsPage(TenantPointsPageReqVO pageReqVO) { + Long tenantId = TenantContextHolder.getTenantId(); + + if (tenantId == 1) { + IPage iPage = new Page<>(pageReqVO.getPageNo(),pageReqVO.getPageSize()); + IPage tenantPointsPageRespVOIPage = tenantPointsMapper.selectPageWithXML(iPage, pageReqVO); + return new PageResult<>(tenantPointsPageRespVOIPage.getRecords(),tenantPointsPageRespVOIPage.getTotal()); + } + + IPage iPage = new Page<>(pageReqVO.getPageNo(),pageReqVO.getPageSize()); + IPage tenantPointsPageRespVOIPage = tenantPointsMapper.selectPageWithTenantIdXML(iPage,pageReqVO,tenantId); + return new PageResult<>(tenantPointsPageRespVOIPage.getRecords(),tenantPointsPageRespVOIPage.getTotal()); + + } + + @Override + public PageResult getTenantTransactionHistoryPointsPage(PageParam pageReqVO, Long tenantId) { + return tenantPointsMapper.TenantTransactionHistoryPointsPage(pageReqVO,tenantId); + } + +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java index 0b45730..9361d31 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -209,4 +209,6 @@ public interface AdminUserService { List getTenantUserById(Long tenantId); void updateUserWithClientRole(@Valid UserClientSaveReqVO reqVO); + + AdminUserDO getUserByTenantIdAndUserName(Long targetTenantId, String initialUser); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index f4cf966..cf17221 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -13,6 +13,7 @@ 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.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthRegisterReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; @@ -552,6 +553,11 @@ public class AdminUserServiceImpl implements AdminUserService { userMapper.updateById(updateObj); } + @Override + public AdminUserDO getUserByTenantIdAndUserName(Long targetTenantId, String initialUser) { + return userMapper.selectByUsernameAndTenantIdWithAgencyRenewal(initialUser,targetTenantId); + } + private AdminUserDO validateUserForCreateOrUpdate(Long id, String username,Long tenantId) { return DataPermissionUtils.executeIgnore(() -> { diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/util/BizNoGenerator.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/util/BizNoGenerator.java new file mode 100644 index 0000000..32dd235 --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/util/BizNoGenerator.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.system.util; + +import cn.hutool.core.util.IdUtil; + +public class BizNoGenerator { + public static String generate(String prefix) { + return prefix + "-" + IdUtil.getSnowflakeNextIdStr(); + } +} diff --git a/yudao-module-system/src/main/resources/mapper/AdminUserMapper.xml b/yudao-module-system/src/main/resources/mapper/AdminUserMapper.xml index 7ed6ff6..6a32c37 100644 --- a/yudao-module-system/src/main/resources/mapper/AdminUserMapper.xml +++ b/yudao-module-system/src/main/resources/mapper/AdminUserMapper.xml @@ -16,4 +16,67 @@ select * from system_users where tenant_id=#{tenantId,jdbcType=BIGINT} + + + + + update system_users set + + username = #{username,jdbcType=VARCHAR}, + + + password = #{password,jdbcType=VARCHAR}, + + + nickname = #{nickname,jdbcType=VARCHAR}, + + + remark = #{remark,jdbcType=VARCHAR}, + + + dept_id = #{deptId,jdbcType=BIGINT}, + + + post_ids = #{postIds,jdbcType=VARCHAR,typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler}, + + + email = #{email,jdbcType=VARCHAR}, + + + mobile = #{mobile,jdbcType=VARCHAR}, + + + sex = #{sex,jdbcType=INTEGER}, + + + avatar = #{avatar,jdbcType=VARCHAR}, + + + status = #{status,jdbcType=INTEGER}, + + + login_ip = #{loginIp,jdbcType=VARCHAR}, + + + login_date = #{loginDate,jdbcType=TIMESTAMP}, + + + crawl = #{crawl,jdbcType=TINYINT}, + + + big_brother = #{bigBrother,jdbcType=TINYINT}, + + + ai_chat = #{aiChat,jdbcType=TINYINT}, + + + ai_replay = #{aiReplay,jdbcType=TINYINT}, + + update_time = NOW() + where id = #{id,jdbcType=BIGINT} + \ No newline at end of file diff --git a/yudao-module-system/src/main/resources/mapper/TenantAgencyPackageMapper.xml b/yudao-module-system/src/main/resources/mapper/TenantAgencyPackageMapper.xml new file mode 100644 index 0000000..ff228aa --- /dev/null +++ b/yudao-module-system/src/main/resources/mapper/TenantAgencyPackageMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/yudao-module-system/src/main/resources/mapper/TenantBalanceMapper.xml b/yudao-module-system/src/main/resources/mapper/TenantBalanceMapper.xml new file mode 100644 index 0000000..7159368 --- /dev/null +++ b/yudao-module-system/src/main/resources/mapper/TenantBalanceMapper.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/yudao-module-system/src/main/resources/mapper/TenantPointsMapper.xml b/yudao-module-system/src/main/resources/mapper/TenantPointsMapper.xml new file mode 100644 index 0000000..8bc8dc7 --- /dev/null +++ b/yudao-module-system/src/main/resources/mapper/TenantPointsMapper.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 8da4943..999695d 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -7,6 +7,9 @@ spring: autoconfigure: exclude: - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 禁用 AI 模块的 Milvus,手动创建 + - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 + - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 + - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 # 数据源配置项 datasource: diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index b7307c1..b1e2b79 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -12,7 +12,7 @@ spring: - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 - org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建 - - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建 + - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模tenant-agency-package/get-simple-list块的 Milvus,手动创建 # 数据源配置项 datasource: druid: # Druid 【监控】相关的全局配置 diff --git a/yudao-server/src/main/resources/application-test.yaml b/yudao-server/src/main/resources/application-test.yaml new file mode 100644 index 0000000..86ce684 --- /dev/null +++ b/yudao-server/src/main/resources/application-test.yaml @@ -0,0 +1,216 @@ +server: + port: 48080 + +--- #################### 数据库相关配置 #################### +spring: + autoconfigure: + # noinspection SpringBootApplicationYaml + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 +# - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置 + - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 + - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 + - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 + - org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建 + - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建 + # 数据源配置项 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 1 # 初始连接数 + min-idle: 1 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true&allowMultiQueries=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 + # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 + # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例 + # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 + # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 + username: ruoyi-vue-pro + password: ki7kbrP3TXADPddS + # username: sa # SQL Server 连接的示例 + # password: Yudao@2024 # SQL Server 连接的示例 + # username: SYSDBA # DM 连接的示例 + # password: SYSDBA001 # DM 连接的示例 + # username: root # OpenGauss 连接的示例 + # password: Yudao@2024 # OpenGauss 连接的示例 +# slave: # 模拟从库,可根据自己需要修改 +# lazy: true # 开启懒加载,保证启动速度 +# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true +# username: root +# password: 123456 +# tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!) +# url: jdbc:TAOS-RS://127.0.0.1:6041/ruoyi_vue_pro +# driver-class-name: com.taosdata.jdbc.rs.RestfulDriver +# username: root +# password: taosdata +# druid: +# validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: dev # 密码,建议生产环境开启 + +--- #################### 定时任务相关配置 #################### + +# Quartz 配置项,对应 QuartzProperties 配置类 +spring: + quartz: + auto-startup: true # 本地开发环境,尽量不要开启 Job + scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName + job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。 + wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true + properties: # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档 + org: + quartz: + # Scheduler 相关配置 + scheduler: + instanceName: schedulerName + instanceId: AUTO # 自动生成 instance ID + # JobStore 相关配置 + jobStore: + # JobStore 实现类。可见博客:https://blog.csdn.net/weixin_42458219/article/details/122247162 + class: org.springframework.scheduling.quartz.LocalDataSourceJobStore + isClustered: true # 是集群模式 + clusterCheckinInterval: 15000 # 集群检查频率,单位:毫秒。默认为 15000,即 15 秒 + misfireThreshold: 60000 # misfire 阀值,单位:毫秒。 + # 线程池相关配置 + threadPool: + threadCount: 25 # 线程池大小。默认为 10 。 + threadPriority: 5 # 线程优先级 + class: org.quartz.simpl.SimpleThreadPool # 线程池类型 + jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置 + initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。 + +--- #################### 消息队列相关 #################### + +spring: + # RabbitMQ 配置项,对应 RabbitProperties 配置类 + rabbitmq: + host: 127.0.0.1 # RabbitMQ 服务的地址 + port: 5672 # RabbitMQ 服务的端口 + username: guest # RabbitMQ 服务的账号 + password: guest # RabbitMQ 服务的密码 + + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + # Spring Boot Admin Server 服务端的相关配置 + context-path: /admin # 配置 Spring + +# 日志文件配置 +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + level: + # 配置自己写的 MyBatis Mapper 打印日志 + cn.iocoder.yudao.module.bpm.dal.mysql: debug + cn.iocoder.yudao.module.infra.dal.mysql: debug + cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper: INFO # 配置 ApiErrorLogMapper 的日志级别为 info,避免和 GlobalExceptionHandler 重复打印 + cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info + cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper: INFO # 配置 FileConfigMapper 的日志级别为 info + cn.iocoder.yudao.module.pay.dal.mysql: debug + cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 PayNotifyTaskMapper 的日志级别为 info + cn.iocoder.yudao.module.system.dal.mysql: debug + cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 配置 SmsChannelMapper 的日志级别为 info + cn.iocoder.yudao.module.tool.dal.mysql: debug + cn.iocoder.yudao.module.member.dal.mysql: debug + cn.iocoder.yudao.module.trade.dal.mysql: debug + cn.iocoder.yudao.module.promotion.dal.mysql: debug + cn.iocoder.yudao.module.statistics.dal.mysql: debug + cn.iocoder.yudao.module.crm.dal.mysql: debug + cn.iocoder.yudao.module.erp.dal.mysql: debug + cn.iocoder.yudao.module.iot.dal.mysql: debug + cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG + cn.iocoder.yudao.module.ai.dal.mysql: debug + cn.iocoder.yudao.module.tkdata.dal.mysql: debug + org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 + +debug: false + + + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + captcha: + enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试; + security: + mock-enable: true + pay: + order-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 + refund-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 + transfer-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 + access-log: # 访问日志的配置项 + enable: false + demo: false # 关闭演示模式 + wxa-code: + env-version: develop # 小程序版本: 正式版为 "release";体验版为 "trial";开发版为 "develop" + wxa-subscribe-message: + miniprogram-state: developer # 跳转小程序类型:开发版为 “developer”;体验版为 “trial”为;正式版为 “formal” + tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc + + +--- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 #################### +pf4j: +# pluginsDir: /tmp/ + pluginsDir: ../plugins \ No newline at end of file diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 2a97a81..c4ca279 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -193,6 +193,9 @@ yudao: - server_country_info - ai_comment - ai_language + - system_tenant_balance + - system_tenant_points + - system_tenant_agency_package ignore-caches: - user_role_ids - permission_menu_ids