commit d863fa0550def9f053e6fa8c4954e17e4901933e Author: figmar Date: Sun Aug 9 08:06:26 2026 +0800 Publish apes-Authon via gitea-publish skill diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8000d9e --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Build output +target/ +*.class + +# IDE +.idea/ +*.iml +.vscode/ +.settings/ +.project +.classpath + +# OS +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log +nohup.out + +# Maven +*.jar +*.war +!.mvn/wrapper/maven-wrapper.jar diff --git a/README.md b/README.md new file mode 100644 index 0000000..bda42fa --- /dev/null +++ b/README.md @@ -0,0 +1,203 @@ +# apes-Authon — 账权独立服务 + +> 从 saas-service(账权平台)提取的纯净认证/授权/用户/角色/权限/多租户体系 +> 目标:作为独立微服务运行,为所有业务系统提供统一的账权能力 + +## 项目背景 + +本项目源自 `saas-service`(账权平台)单体应用,经过耦合度分析确认账权模块与业务模块零直接 Service 调用,具备独立服务化条件。本仓库是提取后的纯净账权代码,不包含任何业务逻辑(溯源、称重、水肥、巡检、维修、农大同步等)。 + +### 提取依据 + +- AuthContext 被 52 个文件 / 111 处引用,但业务 Service → 账权 Service 直接调用为 **0 个** +- 账权模块仅通过 ThreadLocal(AuthContext)与业务模块间接耦合 +- 新增业务模块(如巡检、维修)均不直接调用账权 Service,验证了独立服务化的可行性 + +## 技术栈 + +| 组件 | 版本 | 用途 | +|------|------|------| +| Spring Boot | 2.2.1.RELEASE | Web 框架 | +| Java | 11 | 运行时 | +| MyBatis Plus | 3.5.7 | ORM | +| dynamic-datasource | 3.6.1 | 多租户数据源切换 | +| Redisson | 3.35.0 | Redis 客户端 / 分布式锁 | +| Hutool | 5.8.16 | 通用工具 | +| apes-commons | 0.0.7-SNAPSHOT | 认证核心(AuthContext / @Login / Res / DbEntity) | + +## 代码结构 + +``` +src/main/java/cn/apes/ +├── AuthonApplication.java # 主启动类 +└── cloud/ + ├── controller/ # 11 个 Controller + │ ├── UserController.java # 用户认证(登录/注册/改密/多企业切换) + │ ├── PermissionController.java # 权限管理(菜单/权限码/角色/成员角色) + │ ├── AccessTokenController.java # 外部 API Token 管理 + │ ├── CustomerController.java # 客户/企业管理 + │ ├── CustomerPackageController.java # 客户套餐管理 + │ ├── AppController.java # 应用管理 + │ ├── SysOrganizationController.java # 组织架构 + │ ├── SysPackagePlanController.java # 套餐方案 + │ ├── SysQuotaController.java # 配额模板 + │ ├── SysOperationLogController.java # 操作日志 + │ └── UserPreferenceController.java # 用户偏好 + ├── domain/ + │ ├── entity/ # 23 个实体类 + │ ├── dto/ # 12 个 DTO(含公共 PageDTO) + │ ├── vo/ # 3 个 VO + │ └── huoban/ # 11 个伙伴云 API 模型(SSO 依赖) + ├── service/ # 6 个 Service 接口 + │ └── impl/ # 16 个 Service 实现 + ├── mapper/ # 23 个 Mapper + ├── config/ # 5 个配置类 + │ ├── AccessTokenFilterConfig.java # Token 过滤器注册 + │ ├── DataSourceHeaderAspect.java # 多租户数据源 AOP 切面 + │ ├── TenantSource.java # @TenantSource 注解 + │ ├── HbTokenContext.java # 伙伴云 Token ThreadLocal + │ └── SiteConfig.java # 站点配置 + ├── filter/ + │ └── AccessTokenFilter.java # 外部 API 鉴权过滤器 + └── util/ + ├── OperationLogUtil.java # 操作日志工具 + └── RsaUtil.java # RSA 加解密工具 +``` + +## 模块说明 + +### 1. 用户认证 + +- **密码登录**:`UserController.loginPwd()` → `UserInfoServiceImpl` → Redis 会话 +- **多企业切换**:`UserController.selectCustomer()` → 切换 Redis 中的企业上下文 +- **企业认证**:`UserController.certifyEnterprise()` → 提交企业资质 +- **注册/改密**:`UserController.register()` / `UserController.updatePwd()` + +### 2. RBAC 权限模型 + +``` +AppInfo(应用) + └── SysMenu(菜单)── SysPermission(权限码) + └── SysRole(角色)── SysRolePermission(角色-权限关联) + └── SysMemberRole(成员-角色关联) +``` + +- 菜单树:`PermissionController.menuTree()` +- 权限码:`PermissionController.permissionCodes()` +- 角色管理:`PermissionController` 的 role CRUD +- 成员角色:`PermissionController` 的 member-role 分配 + +### 3. 多租户管理 + +- **数据源切换**:`@TenantSource` 注解 + `DataSourceHeaderAspect` AOP,从 `X-Tenant-ID` 请求头读取数据源标识 +- **租户隔离**:业务数据通过 `AuthContext.getLoginInfo().getCustomer().getId()` 获取 customerId 过滤 + +### 4. 外部 API 鉴权 + +- `AccessTokenFilter`(order=1)拦截所有请求 +- 校验 `X-Access-Token` / `Bearer` Token +- 校验通过后将用户/企业信息写入 Redis,使 `@Login` AOP 正常工作 + +### 5. SSO 单点登录 + +- 伙伴云 SSO V1:`SsoServiceImpl` → HMAC-SHA256 签名 → 伙伴云 `/sso/get_token` +- 伙伴云 SSO V2:`Sso2ServiceImpl` → 同上,不同 baseUrl + +### 6. 套餐与配额 + +``` +SysPackagePlan(套餐方案)── SysPackagePlanPermission(套餐-权限) + └── SysPackagePlanQuota(套餐-配额) +CustomerPackage(客户套餐)── CustomerPackageQuota(客户配额) + └── CustomerPackageExtendApply(延期申请) +SysQuota(配额模板) +``` + +## 外部依赖 + +### apes-commons JAR + +本服务依赖 `cn.apes:apes-commons:0.0.7-SNAPSHOT`,提供以下核心类: + +| 类 | 说明 | +|----|------| +| `AuthContext` | ThreadLocal 认证上下文,存储 UserSession | +| `UserSession` | 会话对象(LoginUser + LoginCustomer) | +| `LoginUser` | 登录用户信息 | +| `LoginCustomer` | 登录客户/企业信息 | +| `@Login` | 方法级注解,AOP 自动注入登录信息 | +| `Res` | 统一 API 响应包装 | +| `DbEntity` | 基础实体(id / createTime / updateTime / isDel) | + +**安装方式**:将 `apes-commons-0.0.7-SNAPSHOT.jar` 安装到本地 Maven 仓库: + +```bash +mvn install:install-file \ + -Dfile=apes-commons-0.0.7-SNAPSHOT.jar \ + -DgroupId=cn.apes \ + -DartifactId=apes-commons \ + -Dversion=0.0.7-SNAPSHOT \ + -Dpackaging=jar +``` + +## 启动方式 + +```bash +# 1. 安装 apes-commons JAR +mvn install:install-file -Dfile=apes-commons-0.0.7-SNAPSHOT.jar ... + +# 2. 编译打包 +mvn clean package -DskipTests + +# 3. 运行 +java -jar target/apes-authon.jar +``` + +服务默认端口 `8090`,context-path `/authon`。 + +## 待完成事项 + +### Phase 1: 验证编译(当前) +- [ ] 安装 apes-commons JAR 后验证编译通过 +- [ ] 补充缺失的 MyBatis XML(如有) +- [ ] 编写基础单元测试 + +### Phase 2: 包名重构 +- [ ] `cn.apes.cloud` → `cn.apes.authon` 全局包名重构 +- [ ] 调整 MapperScan 路径 +- [ ] 更新所有 import + +### Phase 3: SDK 化 +- [ ] 将 `AuthContext` 改造为可远程调用的 SDK +- [ ] 提供 `authon-sdk` 模块供业务系统引用 +- [ ] Token 校验改为 HTTP API 调用 + +### Phase 4: 网关集成 +- [ ] 接入 API 网关(Spring Cloud Gateway / Nginx) +- [ ] 请求头注入认证信息(替代 ThreadLocal) +- [ ] 多租户数据源改为网关路由模式 + +## 从原项目提取的文件清单 + +共提取 **114 个 Java 文件**: + +| 类型 | 数量 | +|------|------| +| Controller | 11 | +| Entity | 23 | +| DTO | 12 | +| VO | 3 | +| Service 接口 | 6 | +| Service 实现 | 16 | +| Mapper | 23 | +| Config | 5 | +| Filter | 1 | +| Util | 2 | +| Huoban DTO | 11 | +| 主启动类 | 1 | + +## 关联仓库 + +- 源仓库:[apes-Authdata](https://gitea.apescale.com/figmar/apes-Authdata) — 完整单体应用(含业务代码) +- 方案文档:`docs/账权模块独立服务化方案.html`(在 apes-Authdata 仓库中) +- 源码对比:`docs/源码版本对比分析-20260809.md`(在 apes-Authdata 仓库中) diff --git a/docs/账权模块提取说明.md b/docs/账权模块提取说明.md new file mode 100644 index 0000000..26ec8a8 --- /dev/null +++ b/docs/账权模块提取说明.md @@ -0,0 +1,144 @@ +# 账权模块提取说明 + +> 提取日期:2026-08-09 +> 源仓库:apes-Authdata (saas-service) +> 目标仓库:apes-Authon + +## 一、提取原则 + +1. **纯账权逻辑**:只提取认证、授权、用户、角色、菜单、权限、多租户、套餐、配额、SSO、操作日志相关的代码 +2. **零业务代码**:不包含溯源(Trace*)、称重(Weight*)、水肥(Fei*)、巡检(Inspection*)、维修(Repair*)、农大同步(Nongda*)、LLM Agent 等任何业务逻辑 +3. **保留包名**:暂保留 `cn.apes.cloud` 包名以最小化改动,后续 Phase 2 再统一重构为 `cn.apes.authon` +4. **保留依赖**:`apes-commons` 外部 JAR 作为核心依赖保留,提供 AuthContext / @Login / Res / DbEntity 等基础设施 + +## 二、提取文件清单 + +### Controller(11 个) + +| 文件 | 核心功能 | +|------|---------| +| UserController | 密码登录、注册、改密、用户CRUD、企业认证、多企业切换 | +| PermissionController | 菜单树、权限码、角色CRUD、角色权限分配、成员角色管理 | +| AccessTokenController | 外部 API Token 的创建/查询/撤销/启用/重新生成 | +| CustomerController | 客户/企业CRUD、员工管理、应用关联、SSO配置 | +| CustomerPackageController | 客户套餐管理、配额管理、延期申请 | +| AppController | 应用CRUD、应用详情(含菜单+权限+关联客户) | +| SysOrganizationController | 组织架构CRUD、组织树 | +| SysPackagePlanController | 套餐方案CRUD、套餐权限分配 | +| SysQuotaController | 配额模板CRUD | +| SysOperationLogController | 操作日志查询 | +| UserPreferenceController | 用户偏好(UI尺寸)查询/更新 | + +### Entity(23 个) + +UserInfo, SysRole, SysMenu, SysPermission, SysRolePermission, SysMemberRole, SysAccessToken, CustomerInfo, CustomerUser, CustomerApp, CustomerPackage, CustomerPackageQuota, CustomerPackageExtendApply, CustomerQuotaChangeLog, SsoConfig, SysOrganization, SysPackagePlan, SysPackagePlanPermission, SysPackagePlanQuota, SysQuota, UserPreference, SysOperationLog, AppInfo + +### Service 接口(6 个) + +CustomerPackageService, SysAccessTokenService, SysOperationLogService, SysPackagePlanQuotaService, SysPackagePlanService, SysQuotaService + +### Service 实现(16 个) + +PermissionServiceImpl, UserInfoServiceImpl, SysAccessTokenServiceImpl, SsoServiceImpl, Sso2ServiceImpl, CustomerUserServiceImpl, CustomerInfoServiceImpl, CustomerAppServiceImpl, SysOrganizationServiceImpl, SysPackagePlanServiceImpl, CustomerPackageServiceImpl, SysQuotaServiceImpl, SysPackagePlanQuotaServiceImpl, UserPreferenceServiceImpl, SysOperationLogServiceImpl, AppInfoServiceImpl + +### Mapper(23 个) + +对应每个 Entity 各一个 Mapper。 + +### Config(5 个) + +| 文件 | 说明 | +|------|------| +| AccessTokenFilterConfig | 注册 AccessTokenFilter(order=1,拦截 /*) | +| DataSourceHeaderAspect | @TenantSource AOP 切面,多租户数据源切换 | +| TenantSource | @TenantSource 注解定义 | +| HbTokenContext | 伙伴云 Token 的 ThreadLocal 上下文 | +| SiteConfig | 站点配置(支付域名、Cookie域名) | + +### Filter(1 个) + +AccessTokenFilter — 外部 API 鉴权(X-Access-Token / Bearer) + +### Util(2 个) + +| 文件 | 说明 | +|------|------| +| OperationLogUtil | 操作日志工具(@PostConstruct 抓 bean + AuthContext 获取操作人) | +| RsaUtil | RSA 加解密(密码加密/解密) | + +### DTO/VO(15 个) + +LoginDTO, RegisterDTO, PwdDTO, UserSearchDTO, RoleSearchDTO, SysRoleDTO, CustomerSearchDTO, EnterpriseCertifyDTO, SelectCustomerDTO, PageDTO, RelationDTO, AppSearchDTO, CustomerPackageVO, CustomerPackageExtendApplyVO, CustomerAppVO + +### Huoban DTO(11 个) + +UpsertOne, DataCreate, DataUpdate, DataFilter, DataFilterCondition, DataUpsert, BulkDel, TableSub, TableColumn, TableInfo, CategoryConfig — 伙伴云 API 请求/响应模型,被 CustomerInfoServiceImpl 用于同步客户数据到伙伴云 + +## 三、未提取的文件(排除原因) + +| 文件 | 排除原因 | +|------|---------| +| CustomerUiConfigServiceImpl | 依赖 `cn.apes.cloud.domain.weight.CustomerUiConfig`(weight 业务包) | +| CommonController | 混合业务(文件上传等),非纯账权 | +| WeightController | 称重业务 | +| TrackingConfigController | 追踪配置业务 | +| 所有 Trace*/Weight*/Fei*/Llm*/Nongda* 文件 | 业务模块 | +| RedissonConfiguration | 通用配置,需按实际部署环境重新配置 | +| MybatisPlusConfig | 通用配置,需按实际部署环境重新配置 | +| OssConfiguration | OSS 配置,账权服务不需要 | +| WebSocketConfig | WebSocket 配置,账权服务不需要 | +| RestTemplateConfiguration | HTTP 客户端配置,按需添加 | +| SchedulingConfig | 定时任务配置,按需添加 | +| JacksonAutoConfiguration | Jackson 配置,Spring Boot 自动配置 | + +## 四、外部依赖分析 + +### apes-commons 0.0.7-SNAPSHOT + +提供以下核心类(全部为接口级别依赖,无源码): + +``` +cn.apes.commons.Res → 统一 API 响应包装 +cn.apes.commons.auth.AuthContext → ThreadLocal 认证上下文 +cn.apes.commons.auth.Login → @Login 注解(方法级,AOP 自动注入) +cn.apes.commons.auth.LoginUser → 登录用户信息 +cn.apes.commons.auth.LoginCustomer → 登录客户/企业信息 +cn.apes.commons.auth.UserSession → 会话对象(user + customer) +cn.apes.commons.domain.DbEntity → 基础实体(id/createTime/updateTime/isDel) +``` + +### 第三方依赖 + +| 依赖 | 用途 | +|------|------| +| spring-boot-starter-web | REST API | +| spring-boot-starter-aop | @TenantSource 切面 / @Login AOP | +| spring-boot-starter-data-redis | Redis 会话管理 | +| mybatis-plus-boot-starter | ORM | +| dynamic-datasource-spring-boot-starter | 多租户数据源 | +| mysql-connector-java | MySQL 驱动 | +| lombok | 简化代码 | +| hutool-all | 通用工具(HMAC 签名、HTTP 调用等) | +| redisson | Redis 客户端 | +| fastjson | JSON 序列化 | + +## 五、耦合度验证 + +提取过程中验证了以下耦合点: + +1. **业务 Service → 账权 Service 直接调用:0 个** ✅ +2. **业务 Controller → 账权 Controller 直接调用:0 个** ✅ +3. **账权 Service → 业务 Mapper 直接调用:0 个** ✅ +4. **唯一的业务包交叉引用**:`CustomerInfoServiceImpl` → `cn.apes.cloud.domain.huoban.UpsertOne` + - 解决方案:将 huoban DTO 包一起提取(11 个纯 DTO 文件,无业务逻辑) +5. **外部 JAR 依赖**:`apes-commons` 提供 AuthContext 等核心类 + - 解决方案:保留为 Maven 依赖,后续 Phase 3 改造为 SDK + +## 六、后续路线图 + +| 阶段 | 目标 | 状态 | +|------|------|------| +| Phase 1 | 验证编译通过 | 待执行 | +| Phase 2 | 包名重构 cn.apes.cloud → cn.apes.authon | 待启动 | +| Phase 3 | SDK 化(AuthContext → 远程调用) | 待设计 | +| Phase 4 | 网关集成(ThreadLocal → HTTP Header) | 待设计 | diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b8e8438 --- /dev/null +++ b/pom.xml @@ -0,0 +1,162 @@ + + + 4.0.0 + + cn.apes + apes-authon + 0.1.0-SNAPSHOT + apes-Authon + 账权独立服务 — 从 saas-service 提取的纯净认证/授权/用户/角色/权限/多租户体系 + + + 11 + UTF-8 + UTF-8 + UTF-8 + 2.2.1.RELEASE + 1.18.36 + 8.0.15 + 3.5.7 + 3.35.0 + 5.8.16 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus-boot-starter.version} + + + + com.baomidou + dynamic-datasource-spring-boot-starter + 3.6.1 + + + + + mysql + mysql-connector-java + ${mysql-connector-java.version} + + + + + org.projectlombok + lombok + ${lombok.version} + + + + + cn.hutool + hutool-all + ${hutool.version} + + + + + org.redisson + redisson + ${redisson.version} + + + + + com.alibaba + fastjson + 1.2.83 + + + + + cn.apes + apes-commons + 0.0.7-SNAPSHOT + + + cn.hutool + hutool-all + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + apes-authon + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + 11 + UTF-8 + + + org.projectlombok + lombok + ${lombok.version} + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + cn.apes.AuthonApplication + + + + + repackage + + + + + + + + diff --git a/src/main/java/cn/apes/AuthonApplication.java b/src/main/java/cn/apes/AuthonApplication.java new file mode 100644 index 0000000..21fada8 --- /dev/null +++ b/src/main/java/cn/apes/AuthonApplication.java @@ -0,0 +1,30 @@ +package cn.apes; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * 账权独立服务 — 从 saas-service 提取的纯净认证/授权/用户/角色/权限/多租户体系 + * + * 本服务包含: + * - 用户认证(密码登录 / Redis 会话 / Token 管理) + * - RBAC 权限模型(菜单 / 权限码 / 角色 / 成员角色) + * - 多租户管理(客户/企业 / 组织架构 / 数据源切换) + * - 套餐与配额管理 + * - SSO 单点登录(伙伴云) + * - 操作日志 + * - 用户偏好 + */ +@SpringBootApplication +@EnableAsync +@EnableScheduling +@MapperScan("cn.apes.cloud.mapper") +public class AuthonApplication { + + public static void main(String[] args) { + SpringApplication.run(AuthonApplication.class, args); + } +} diff --git a/src/main/java/cn/apes/cloud/config/AccessTokenFilterConfig.java b/src/main/java/cn/apes/cloud/config/AccessTokenFilterConfig.java new file mode 100644 index 0000000..207286f --- /dev/null +++ b/src/main/java/cn/apes/cloud/config/AccessTokenFilterConfig.java @@ -0,0 +1,31 @@ +package cn.apes.cloud.config; + +import cn.apes.cloud.filter.AccessTokenFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.servlet.DispatcherType; + +/** + * AccessToken 过滤器注册 + * 注册为最高优先级,确保在 Spring 其他拦截之前执行 + */ +@Configuration +public class AccessTokenFilterConfig { + + @Autowired + private AccessTokenFilter accessTokenFilter; + + @Bean + public FilterRegistrationBean accessTokenFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(accessTokenFilter); + registration.addUrlPatterns("/*"); + registration.setOrder(1); // 最高优先级 + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setName("accessTokenFilter"); + return registration; + } +} diff --git a/src/main/java/cn/apes/cloud/config/DataSourceHeaderAspect.java b/src/main/java/cn/apes/cloud/config/DataSourceHeaderAspect.java new file mode 100644 index 0000000..0883545 --- /dev/null +++ b/src/main/java/cn/apes/cloud/config/DataSourceHeaderAspect.java @@ -0,0 +1,64 @@ +package cn.apes.cloud.config; + + +import cn.apes.commons.Res; +import cn.apes.commons.auth.AuthContext; +import cn.apes.commons.auth.Login; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RBucket; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.List; + +@Slf4j +@Aspect +@Component +@Order(1) +public class DataSourceHeaderAspect { + + + List heads = CollUtil.newArrayList("user", "zx","plant"); + + @Around("@within(tenantSource)") + public Object clazz(ProceedingJoinPoint pjp, TenantSource tenantSource) throws Throwable { + return exc(pjp, tenantSource); + } + + @Around("@annotation(tenantSource)") + public Object menthod(ProceedingJoinPoint pjp, TenantSource tenantSource) throws Throwable { + return exc(pjp, tenantSource); + } + + Object exc(ProceedingJoinPoint pjp, TenantSource tenantSource) throws Throwable { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + // 保留 AccessToken 过滤器已设置的认证上下文 + if (request.getAttribute("accessTokenVerified") == null) { + AuthContext.clean(); + } + String head = request.getHeader("X-Tenant-ID"); + if (StrUtil.isEmpty(head)) { + head="user"; + } + if(!heads.contains(head)) { + throw new RuntimeException("数据源ID有误"); + } + DynamicDataSourceContextHolder.push(head); + + return pjp.proceed(); + + } +} diff --git a/src/main/java/cn/apes/cloud/config/HbTokenContext.java b/src/main/java/cn/apes/cloud/config/HbTokenContext.java new file mode 100644 index 0000000..23b357f --- /dev/null +++ b/src/main/java/cn/apes/cloud/config/HbTokenContext.java @@ -0,0 +1,32 @@ +package cn.apes.cloud.config; + + +public class HbTokenContext { + + private static final ThreadLocal LOGIN_THREAD_LOCAL = new ThreadLocal<>(); + + /** + * 设置伙伴云token + * + * @param loginInfo 登录信息 + */ + public static void setHbToken(String loginInfo) { + LOGIN_THREAD_LOCAL.set(loginInfo); + } + + /** + * 获取登录token + * + * @return + */ + public static String getHbToken() { + return LOGIN_THREAD_LOCAL.get(); + } + + /** + * 清空登录用户信息 + */ + public static void clean() { + LOGIN_THREAD_LOCAL.remove(); + } +} diff --git a/src/main/java/cn/apes/cloud/config/SiteConfig.java b/src/main/java/cn/apes/cloud/config/SiteConfig.java new file mode 100644 index 0000000..bb35215 --- /dev/null +++ b/src/main/java/cn/apes/cloud/config/SiteConfig.java @@ -0,0 +1,18 @@ +package cn.apes.cloud.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "sit.config") +public class SiteConfig { + + @Value("${sit.config.payment.domain}") + private String paymentDomain; + + @Value("${sit.config.payment.cookieDomain}") + private String cookieDomain; +} diff --git a/src/main/java/cn/apes/cloud/config/TenantSource.java b/src/main/java/cn/apes/cloud/config/TenantSource.java new file mode 100644 index 0000000..4769814 --- /dev/null +++ b/src/main/java/cn/apes/cloud/config/TenantSource.java @@ -0,0 +1,10 @@ +package cn.apes.cloud.config; + +import java.lang.annotation.*; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TenantSource { + String value() default "user"; +} diff --git a/src/main/java/cn/apes/cloud/controller/AccessTokenController.java b/src/main/java/cn/apes/cloud/controller/AccessTokenController.java new file mode 100644 index 0000000..b23554c --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/AccessTokenController.java @@ -0,0 +1,170 @@ +package cn.apes.cloud.controller; + +import cn.apes.cloud.domain.entity.SysAccessToken; +import cn.apes.cloud.service.SysAccessTokenService; +import cn.apes.cloud.util.OperationLogUtil; +import cn.apes.commons.auth.AuthContext; +import cn.apes.commons.auth.Login; +import cn.apes.commons.auth.LoginCustomer; +import cn.apes.commons.auth.UserSession; +import cn.apes.commons.Res; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * AccessToken 管理接口 + */ +@Login +@RestController +@RequestMapping("/sysAccessToken") +public class AccessTokenController { + + @Autowired + private SysAccessTokenService accessTokenService; + + /** + * 创建 AccessToken + */ + @PostMapping("/create") + public Res create(@RequestBody Map params) { + UserSession authUserInfo = AuthContext.getLoginInfo(); + LoginCustomer customer = authUserInfo.getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + + SysAccessToken record = new SysAccessToken(); + record.setCustomerId(customer.getId()); + record.setName((String) params.get("name")); + record.setScope(params.get("scope") != null ? (String) params.get("scope") : "*"); + record.setWhitelistIps(params.get("whitelistIps") != null ? (String) params.get("whitelistIps") : ""); + record.setStatus(1); + + if (params.get("expireTime") != null) { + try { + record.setExpireTime(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse((String) params.get("expireTime"))); + } catch (Exception e) { + return Res.fail("过期时间格式错误,应为 yyyy-MM-dd HH:mm:ss"); + } + } + + String token = accessTokenService.generateToken(); + record.setToken(token); + record.setCreateBy(authUserInfo.getUser() != null ? authUserInfo.getUser().getId() : null); + accessTokenService.save(record); + + OperationLogUtil.log("AccessToken管理", "创建", "创建AccessToken[" + record.getName() + "]"); + + // 返回完整 Token(只在创建时展示一次) + java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Map result = new HashMap<>(); + result.put("id", record.getId()); + result.put("name", record.getName()); + result.put("token", token); + result.put("customerId", record.getCustomerId()); + result.put("scope", record.getScope()); + result.put("expireTime", record.getExpireTime() != null ? sdf.format(record.getExpireTime()) : null); + result.put("message", "Token 仅在创建时显示一次,请妥善保存"); + return Res.success(result); + } + + private Long parseId(Map params) { + Object val = params.get("id"); + if (val == null) return null; + return Long.parseLong(val.toString()); + } + + /** + * 分页查询列表 + */ + @PostMapping("/page") + public Res page(@RequestBody Map params) { + UserSession authUserInfo = AuthContext.getLoginInfo(); + LoginCustomer customer = authUserInfo.getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + + int pageIndex = params.get("pageIndex") != null ? Integer.parseInt(params.get("pageIndex").toString()) : 1; + int pageSize = params.get("pageSize") != null ? Integer.parseInt(params.get("pageSize").toString()) : 10; + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysAccessToken::getCustomerId, customer.getId()); + wrapper.orderByDesc(SysAccessToken::getCreateTime); + + Page page = accessTokenService.page(new Page<>(pageIndex, pageSize), wrapper); + + // 脱敏:不返回完整 token + for (SysAccessToken item : page.getRecords()) { + if (item.getToken() != null && item.getToken().length() > 8) { + item.setToken(item.getToken().substring(0, 6) + "****" + item.getToken().substring(item.getToken().length() - 2)); + } + } + + return Res.success(page); + } + + /** + * 撤销 Token + */ + @PostMapping("/revoke") + public Res revoke(@RequestBody Map params) { + Long id = parseId(params); + if (id == null) return Res.fail("缺少 id 参数"); + SysAccessToken record = accessTokenService.getById(id); + String name = record != null ? record.getName() : "id=" + id; + accessTokenService.revoke(id); + OperationLogUtil.log("AccessToken管理", "停用", "停用AccessToken[" + name + "]"); + return Res.success("已撤销"); + } + + /** + * 启用 Token + */ + @PostMapping("/enable") + public Res enable(@RequestBody Map params) { + Long id = parseId(params); + if (id == null) return Res.fail("缺少 id 参数"); + SysAccessToken record = accessTokenService.getById(id); + String name = record != null ? record.getName() : "id=" + id; + accessTokenService.enable(id); + OperationLogUtil.log("AccessToken管理", "启用", "启用AccessToken[" + name + "]"); + return Res.success("已启用"); + } + + /** + * 重新生成 Token + */ + @PostMapping("/regenerate") + public Res regenerate(@RequestBody Map params) { + Long id = parseId(params); + if (id == null) return Res.fail("缺少 id 参数"); + SysAccessToken record = accessTokenService.getById(id); + String name = record != null ? record.getName() : "id=" + id; + String newToken = accessTokenService.regenerate(id); + OperationLogUtil.log("AccessToken管理", "重新生成", "重新生成AccessToken[" + name + "]"); + Map result = new HashMap<>(); + result.put("token", newToken); + result.put("message", "新 Token 已生成,旧 Token 立即失效"); + return Res.success(result); + } + + /** + * 删除 Token + */ + @PostMapping("/delete") + public Res delete(@RequestBody Map params) { + Long id = parseId(params); + if (id == null) return Res.fail("缺少 id 参数"); + SysAccessToken record = accessTokenService.getById(id); + String name = record != null ? record.getName() : "id=" + id; + accessTokenService.removeById(id); + OperationLogUtil.log("AccessToken管理", "删除", "删除AccessToken[" + name + "]"); + return Res.success("已删除"); + } +} diff --git a/src/main/java/cn/apes/cloud/controller/AppController.java b/src/main/java/cn/apes/cloud/controller/AppController.java new file mode 100644 index 0000000..8cdf7ed --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/AppController.java @@ -0,0 +1,110 @@ +package cn.apes.cloud.controller; + +import cn.apes.commons.Res; +import cn.apes.commons.auth.Login; +import cn.apes.cloud.config.TenantSource; +import cn.apes.cloud.domain.dto.AppSearchDTO; +import cn.apes.cloud.domain.entity.AppInfo; +import cn.apes.cloud.domain.entity.SysMenu; +import cn.apes.cloud.domain.entity.SysPermission; +import cn.apes.cloud.domain.entity.CustomerInfo; +import cn.apes.cloud.domain.entity.CustomerApp; +import cn.apes.cloud.service.impl.AppInfoServiceImpl; +import cn.apes.cloud.service.impl.CustomerAppServiceImpl; +import cn.apes.cloud.service.impl.CustomerInfoServiceImpl; +import cn.apes.cloud.mapper.SysMenuMapper; +import cn.apes.cloud.mapper.SysPermissionMapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Login +@RestController +@TenantSource +@RequestMapping("/app") +public class AppController { + @Autowired + AppInfoServiceImpl appInfoService; + + @Autowired + CustomerAppServiceImpl customerAppService; + + @Autowired + CustomerInfoServiceImpl customerInfoService; + + @Autowired + SysMenuMapper sysMenuMapper; + + @Autowired + SysPermissionMapper sysPermissionMapper; + + /** + * 分页查询应用列表 + */ + @PostMapping("/pageApp") + public Res pageApp(@RequestBody AppSearchDTO searchDTO) { + return appInfoService.pageApp(searchDTO); + } + + /** + * 新增/编辑应用 + */ + @PostMapping("/saveApp") + public Res saveApp(@RequestBody AppInfo appInfo) { + return appInfoService.saveApp(appInfo); + } + + /** + * 删除应用 + */ + @PostMapping("/deleteApp") + public Res deleteApp(@RequestBody AppInfo appInfo) { + return appInfoService.deleteApp(appInfo); + } + + /** + * 获取应用详情(基本信息 + 菜单 + 权限 + 关联客户) + */ + @PostMapping("/getAppDetail") + public Res getAppDetail(@RequestBody AppInfo param) { + String appKey = param.getAppKey(); + AppInfo appInfo = appInfoService.getById(appKey); + if (appInfo == null) { + return Res.fail("应用不存在"); + } + + // 隐藏敏感字段 + appInfo.setRemark(null); + + // 查询关联的菜单列表 + List menuList = sysMenuMapper.selectList( + new LambdaQueryWrapper().eq(SysMenu::getAppName, appKey) + ); + + // 查询关联的权限列表 + List permissionList = sysPermissionMapper.selectList( + new LambdaQueryWrapper().eq(SysPermission::getAppName, appKey) + ); + + // 查询关联的客户列表 + List customerIds = customerAppService.getCustomerIdsByAppKey(appKey); + List customerList = new ArrayList<>(); + if (!customerIds.isEmpty()) { + customerList = customerInfoService.listByIds(customerIds); + } + + Map result = new HashMap<>(); + result.put("appInfo", appInfo); + result.put("menuList", menuList); + result.put("permissionList", permissionList); + result.put("customerList", customerList); + + return Res.success(result); + } +} diff --git a/src/main/java/cn/apes/cloud/controller/CustomerController.java b/src/main/java/cn/apes/cloud/controller/CustomerController.java new file mode 100644 index 0000000..418f829 --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/CustomerController.java @@ -0,0 +1,196 @@ +package cn.apes.cloud.controller; + +import cn.apes.commons.Res; +import cn.apes.commons.auth.AuthContext; +import cn.apes.commons.auth.Login; +import cn.apes.commons.auth.LoginCustomer; +import cn.apes.cloud.config.TenantSource; +import cn.apes.cloud.domain.dto.CustomerSearchDTO; +import cn.apes.cloud.domain.entity.CustomerInfo; +import cn.apes.cloud.domain.entity.SsoConfig; +import cn.apes.cloud.service.impl.CustomerAppServiceImpl; +import cn.apes.cloud.service.impl.CustomerInfoServiceImpl; +import cn.apes.cloud.service.impl.CustomerUserServiceImpl; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@Login +@RestController +@TenantSource +@RequestMapping("/customer") +public class CustomerController { + + @Autowired + CustomerInfoServiceImpl customerInfoService; + + @Autowired + CustomerUserServiceImpl customerUserService; + + @Autowired + CustomerAppServiceImpl customerAppService; + + @PostMapping("/pageCustomer") + public Res pageCustomer(@RequestBody CustomerSearchDTO searchDTO) { + return customerInfoService.pageCustomer(searchDTO); + } + + @GetMapping("/getCustomerDetail") + public Res getCustomerDetail(@RequestParam("id") Long id) { + return customerInfoService.getCustomerDetail(id); + } + + @GetMapping("/addUser") + public Res addUser(Long customerId, Long userId) { + return customerUserService.addUser(customerId, userId); + } + + @GetMapping("/delUser") + public Res delUser(Long customerId, Long userId) { + return customerUserService.delUser(customerId, userId); + } + + /** + * 分页查询员工列表(customerId 从登录上下文获取) + */ + @PostMapping("/employee/page") + public Res pageEmployee(@RequestBody JSONObject data) { + int pageIndex = data.getIntValue("pageIndex"); + int pageSize = data.getIntValue("pageSize"); + Long orgId = data.getLong("orgId"); + if (pageIndex <= 0) pageIndex = 1; + if (pageSize <= 0) pageSize = 10; + return customerUserService.pageEmployee(pageIndex, pageSize, orgId); + } + + /** + * 获取员工详情(编辑用) + */ + @GetMapping("/employee/detail") + public Res getEmployeeDetail(@RequestParam("userId") Long userId) { + return customerUserService.getEmployeeDetail(userId); + } + + /** + * 更新员工信息 + */ + @PostMapping("/employee/update") + public Res updateEmployee(@RequestBody JSONObject data) { + Long userId = data.getLong("userId"); + Long orgId = data.getLong("orgId"); + String name = data.getString("name"); + String title = data.getString("title"); + String position = data.getString("position"); + String appIds = data.getString("appIds"); + return customerUserService.updateEmployee(userId, orgId, name, title, position, appIds); + } + + /** + * 新增/编辑客户 + */ + @PostMapping("/saveCustomer") + public Res saveCustomer(@RequestBody CustomerInfo customerInfo) { + return customerInfoService.saveCustomer(customerInfo); + } + + /** + * 删除客户 + */ + @PostMapping("/deleteCustomer") + public Res deleteCustomer(@RequestBody CustomerInfo customerInfo) { + return customerInfoService.deleteCustomer(customerInfo); + } + + /** + * 查询当前登录客户已关联的应用列表(从登录上下文获取 customerId) + */ + @GetMapping("/getMyApps") + public Res getMyApps() { + LoginCustomer customer = AuthContext.getLoginInfo().getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + return Res.success(customerAppService.getMyAppsWithSource(customer.getId())); + } + + /** + * 查询指定客户已关联的应用列表(管理端用) + */ + @GetMapping("/getCustomerApps") + public Res getCustomerApps(@RequestParam("customerId") Long customerId) { + return Res.success(customerAppService.getApps(customerId)); + } + + /** + * 关联应用给客户 + */ + @PostMapping("/addCustomerApp") + public Res addCustomerApp(@RequestBody JSONObject data) { + Long customerId = data.getLong("customerId"); + String appKey = data.getString("appKey"); + return customerAppService.addApp(customerId, appKey); + } + + /** + * 解绑客户的应用 + */ + @PostMapping("/removeCustomerApp") + public Res removeCustomerApp(@RequestBody JSONObject data) { + Long customerId = data.getLong("customerId"); + String appKey = data.getString("appKey"); + return customerAppService.removeApp(customerId, appKey); + } + + /** + * 查询所有应用(用于选择器) + */ + @GetMapping("/getAllApps") + public Res getAllApps() { + return Res.success(customerAppService.getAllApps()); + } + + /** + * 获取客户SSO配置(公司级别 user_id=0) + */ + @GetMapping("/getSSOConfig") + public Res getSSOConfig(@RequestParam("customerId") Long customerId) { + return customerInfoService.getSSOConfig(customerId); + } + + /** + * 保存客户SSO配置(公司级别 user_id=0) + */ + @PostMapping("/saveSSOConfig") + public Res saveSSOConfig(@RequestBody SsoConfig ssoConfig) { + return customerInfoService.saveSSOConfig(ssoConfig); + } + + /** + * 更新客户状态 + */ + @PostMapping("/updateCustomerStatus") + public Res updateCustomerStatus(@RequestBody CustomerInfo customerInfo) { + return customerInfoService.updateCustomerStatus(customerInfo.getId(), customerInfo.getCustomerStatus()); + } + + /** + * 审核企业认证(通过/拒绝) + */ + @PostMapping("/auditCertification") + public Res auditCertification(@RequestBody JSONObject data) { + Long customerId = data.getLong("customerId"); + Integer auditStatus = data.getInteger("customerStatus"); // 1=通过, 5=拒绝 + String auditRemark = data.getString("auditRemark"); // 拒绝原因 + return customerInfoService.auditCertification(customerId, auditStatus, auditRemark); + } + + + /** + * 同步全部租户信息到伙伴云(使用 upsetOne 接口) + */ + @PostMapping("/syncTenantsToHuoban") + public Res syncTenantsToHuoban() { + return customerInfoService.syncAllTenantsToHuoban(); + } + +} diff --git a/src/main/java/cn/apes/cloud/controller/CustomerPackageController.java b/src/main/java/cn/apes/cloud/controller/CustomerPackageController.java new file mode 100644 index 0000000..4da2053 --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/CustomerPackageController.java @@ -0,0 +1,143 @@ +package cn.apes.cloud.controller; + +import cn.apes.commons.Res; +import cn.apes.commons.auth.AuthContext; +import cn.apes.commons.auth.Login; +import cn.apes.commons.auth.LoginCustomer; +import cn.apes.cloud.domain.entity.CustomerPackage; +import cn.apes.cloud.service.CustomerPackageService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@Login +@RestController +@RequestMapping("/customerPackage") +public class CustomerPackageController { + + @Autowired + private CustomerPackageService customerPackageService; + + /** + * 获取客户的套餐列表 + */ + @GetMapping("/list") + public Object list(@RequestParam Long customerId) { + return customerPackageService.getCustomerPackages(customerId); + } + + /** + * 新增客户套餐 + */ + @PostMapping("/add") + public Object add(@RequestBody CustomerPackage customerPackage) { + return customerPackageService.addCustomerPackage(customerPackage); + } + + /** + * 编辑客户套餐 + */ + @PostMapping("/edit") + public Object edit(@RequestBody java.util.Map data) { + return customerPackageService.editCustomerPackage(data); + } + + /** + * 删除客户套餐 + */ + @PostMapping("/delete") + public Object delete(@RequestBody CustomerPackage customerPackage) { + return customerPackageService.deleteCustomerPackage(customerPackage.getId()); + } + + /** + * 保存客户套餐配额 + */ + @PostMapping("/saveQuotas") + public Object saveQuotas(@RequestBody java.util.Map data) { + Long packageId = data.get("packageId") != null ? Long.parseLong(data.get("packageId").toString()) : null; + @SuppressWarnings("unchecked") + java.util.Map quotaValues = (java.util.Map) data.get("quotaValues"); + return customerPackageService.saveCustomerPackageQuotas(packageId, quotaValues); + } + + /** + * 获取客户套餐配额 + */ + @GetMapping("/getQuotas") + public Object getQuotas(@RequestParam Long packageId) { + return customerPackageService.getCustomerPackageQuotas(packageId); + } + + /** + * 获取当前登录客户的套餐列表(从登录上下文获取 customerId) + */ + @GetMapping("/myPackages") + public Res myPackages() { + LoginCustomer customer = AuthContext.getLoginInfo().getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + return customerPackageService.getMyPackages(customer.getId()); + } + + /** + * 管理端:查询所有客户的套餐概况 + */ + @PostMapping("/overview") + public Object overview(@RequestBody java.util.Map params) { + return customerPackageService.getCustomerPackageOverview(params); + } + + + /** + * 提交套餐延期申请 + */ + @PostMapping("/submitExtendApply") + public Object submitExtendApply(@RequestBody java.util.Map params) { + params.put("userId", AuthContext.getLoginInfo().getCustomer().getId()); + return customerPackageService.submitExtendApply(params); + } + + + /** + * 管理端:查询套餐延期申请记录列表 + */ + @PostMapping("/extendApplyList") + public Object extendApplyList(@RequestBody java.util.Map params) { + return customerPackageService.getExtendApplyList(params); + } + + + /** + * 审核延期申请(同意/拒绝) + */ + @PostMapping("/reviewExtendApply") + public Object reviewExtendApply(@RequestBody java.util.Map params) { + return customerPackageService.reviewExtendApply(params); + } + + /** + * 增加客户套餐额度 + */ + @PostMapping("/increaseQuota") + public Object increaseQuota(@RequestBody java.util.Map params) { + return customerPackageService.increaseQuota(params); + } + + /** + * 减少客户套餐额度 + */ + @PostMapping("/decreaseQuota") + public Object decreaseQuota(@RequestBody java.util.Map params) { + return customerPackageService.decreaseQuota(params); + } + + /** + * 获取配额变更日志列表 + */ + @GetMapping("/quotaChangeLogs") + public Object getQuotaChangeLogs(@RequestParam java.util.Map params) { + return customerPackageService.getQuotaChangeLogs(params); + } + +} diff --git a/src/main/java/cn/apes/cloud/controller/PermissionController.java b/src/main/java/cn/apes/cloud/controller/PermissionController.java new file mode 100644 index 0000000..d2ab9a8 --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/PermissionController.java @@ -0,0 +1,226 @@ +package cn.apes.cloud.controller; + +import cn.apes.commons.Res; +import cn.apes.commons.auth.AuthContext; +import cn.apes.commons.auth.UserSession; +import cn.apes.cloud.config.TenantSource; +import cn.apes.cloud.domain.dto.RoleSearchDTO; +import cn.apes.cloud.domain.entity.SysMenu; +import cn.apes.cloud.domain.entity.SysPermission; +import cn.apes.cloud.domain.entity.SysRole; +import cn.apes.cloud.service.impl.PermissionServiceImpl; +import cn.apes.commons.auth.Login; +import cn.apes.commons.auth.LoginCustomer; +import cn.hutool.http.server.HttpServerResponse; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Login +@RestController +@TenantSource +@RequestMapping("/permission") +public class PermissionController { + + @Autowired + PermissionServiceImpl permissionService; + + @GetMapping("/currentMenus") + public Res getCurrentMenus() { + UserSession authUserInfo = AuthContext.getLoginInfo(); + return permissionService.getMemberMenus(authUserInfo.getUser().getId()); + } + + /** + * 获取指定应用的全部菜单树(按用户权限过滤) + */ + @GetMapping("/getAppMenus") + public Res getAppMenus(@RequestParam("appName") String appName) { + UserSession authUserInfo = AuthContext.getLoginInfo(); + return permissionService.getAppMenus(authUserInfo.getUser().getId(), appName); + } + + /** + * 获取当前用户在当前企业的所有权限code,按应用名分组 + * 返回格式: {"BASE_APP": ["code1", "code2"], "guobang": ["code1"]} + */ + @GetMapping("/getMyPermissionCodes") + public Res getMyPermissionCodes() { + UserSession authUserInfo = AuthContext.getLoginInfo(); + return permissionService.getMyPermissionCodesByApp(authUserInfo.getUser().getId()); + } + + /** + * 获取指定应用的菜单树(按客户套餐权限过滤) + */ + @GetMapping("/getPackageAppMenus") + public Res getPackageAppMenus(@RequestParam("appName") String appName) { + UserSession authUserInfo = AuthContext.getLoginInfo(); + LoginCustomer customer = authUserInfo.getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + Long userId = authUserInfo.getUser() != null ? authUserInfo.getUser().getId() : null; + if (userId == null) { + return Res.fail("未找到当前登录用户信息"); + } + return permissionService.getPackageAppMenus(userId, customer.getId(), appName); + } + +// @GetMapping("/getOldMemberMenus") +// public Res getOldMemberMenus(@RequestHeader("version") String version){ +// AuthUserInfo authUserInfo = AuthContext.getLoginInfo(); +// AppInfo appInfo = AuthContext.getAppInfo(); +// return permissionService.getOldMemberMenus(authUserInfo.getMemberNo(),appInfo.getAppName(),version); +// } + +// @GetMapping("/getRolePermission") +// public Res getRolePermission(){ +// UserSession authUserInfo = AuthContext.getLoginInfo(); +// return permissionService.getRolePermission(authUserInfo.getUser().getId()); +// } + + @PostMapping("/saveMenu") + public Res saveMenu(@RequestBody SysMenu menu) { + return permissionService.saveMenu(menu); + } + + @GetMapping("/getAllMenu") + public Res getAllMenu(@RequestParam("appName") String appName) { + return permissionService.getAllMenu(appName); + } + + @PostMapping("/savePermission") + public Res savePermission(@RequestBody SysPermission menu) { + return permissionService.savePermission(menu); + } + + @GetMapping("/getAllPermission") + public Res getAllPermission(String appName) { + return permissionService.getAllPermission(appName); + } + + /** + * 获取指定套餐下指定应用的权限树(仅包含该套餐拥有的权限) + */ + @GetMapping("/getPlanPermissionTree") + public Res getPlanPermissionTree(@RequestParam("planId") Long planId, @RequestParam("appName") String appName) { + return permissionService.getPlanPermissionTree(planId, appName); + } + + @PostMapping("/deletePermission") + public Res deletePermission(@RequestBody JSONObject data) { + Long permissionId = data.getLong("permissionId"); + return permissionService.deletePermission(permissionId); + } + + @PostMapping("/deleteMenu") + public Res deleteMenu(@RequestBody JSONObject data) { + Long menuId = data.getLong("menuId"); + return permissionService.deleteMenu(menuId); + } + + @PostMapping("/getAllRole") + public Res getAllRole(@RequestBody RoleSearchDTO searchDTO) { + return permissionService.getAllRole(searchDTO); + } + + @PostMapping("/getAllRoleByAppName") + public Res getAllRoleByAppName(@RequestBody RoleSearchDTO searchDTO) { + return permissionService.getAllRoleByAppName(searchDTO); + } + + @PostMapping("/saveRole") + public Res saveRole(@RequestBody SysRole role) { + return permissionService.saveRole(role); + } + + @PostMapping("/deleteRole") + public Res deleteRole(@RequestBody JSONObject data) { + Long roleId = data.getLong("roleId"); + return permissionService.deleteRole(roleId); + } + + @PostMapping("/setRolePermission") + public Res setRolePermission(@RequestBody JSONObject data) { + return permissionService.setRolePermission(data); + } + + @GetMapping("/getRolePermission") + public Res getRolePermission(Long roleId) { + return permissionService.getRolePermission(roleId); + } + + @PostMapping("/setMemberRole") + public Res setMemberRole(@RequestBody JSONObject data) { + return permissionService.setMemberRole(data); + } + + /** + * Get available roles for current customer (based on plan's apps) + */ + @GetMapping("/getMemberAvailableRoles") + public Res getMemberAvailableRoles() { + LoginCustomer customer = AuthContext.getLoginInfo().getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + return permissionService.getAvailableRolesForCustomer(customer.getId()); + } + + /** + * Get member's assigned roles (scoped by current customer) + */ + @GetMapping("/getMemberAssignedRoles") + public Res getMemberAssignedRoles(@RequestParam("userId") Long userId) { + LoginCustomer customer = AuthContext.getLoginInfo().getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + return permissionService.getMemberRolesByCustomer(customer.getId(), userId); + } + + /** + * Set member roles (scoped by current customer) + */ + @PostMapping("/setMemberRolesByCustomer") + public Res setMemberRolesByCustomer(@RequestBody JSONObject data) { + LoginCustomer customer = AuthContext.getLoginInfo().getCustomer(); + if (customer == null || customer.getId() == null) { + return Res.fail("未找到当前登录客户信息"); + } + data.put("customerId", customer.getId()); + return permissionService.setMemberRoleByCustomer(data); + } + + @GetMapping("/getHuoBanUrl") + public Res getPageUrl(Long menuId) { + return permissionService.getPageUrl(menuId); + } + + /** + * 获取伙伴云 SSO Token 信息(不需要菜单,不返回 pageUrl/menu) + */ + @GetMapping("/getHuobanToken") + public Res getHuobanToken() { + return permissionService.getHuobanToken(); + } + + @GetMapping("/getMenu") + public Res getMenu(Long menuId) { + return permissionService.getMenu(menuId); + } + + @GetMapping("/getPaymentMenu") + public Res getMenu(Long menuId, HttpServletResponse response, HttpServletRequest request) { + return permissionService.getPaymentUrl(menuId, response, request); + } + + @GetMapping("/changePaymentGroup") + public Res changePaymentGroup(Integer group, HttpServletRequest request){ + return permissionService.changePaymentGroup(group, request); + } +} diff --git a/src/main/java/cn/apes/cloud/controller/SysOperationLogController.java b/src/main/java/cn/apes/cloud/controller/SysOperationLogController.java new file mode 100644 index 0000000..e57f7d9 --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/SysOperationLogController.java @@ -0,0 +1,51 @@ +package cn.apes.cloud.controller; + +import cn.apes.commons.Res; +import cn.apes.commons.auth.Login; +import cn.apes.cloud.config.TenantSource; +import cn.apes.cloud.service.impl.SysOperationLogServiceImpl; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 操作日志控制器 + */ +@Login +@RestController +@TenantSource +@RequestMapping("/operationLog") +public class SysOperationLogController { + + @Autowired + private SysOperationLogServiceImpl operationLogService; + + /** + * 分页查询操作日志 + */ + @PostMapping("/page") + public Res pageLogs(@RequestBody Map params) { + int pageIndex = params.get("pageIndex") != null ? ((Number) params.get("pageIndex")).intValue() : 1; + int pageSize = params.get("pageSize") != null ? ((Number) params.get("pageSize")).intValue() : 10; + Long customerId = params.get("customerId") != null ? ((Number) params.get("customerId")).longValue() : null; + Long userId = params.get("userId") != null ? ((Number) params.get("userId")).longValue() : null; + String startDate = params.get("startDate") != null ? params.get("startDate").toString() : null; + String endDate = params.get("endDate") != null ? params.get("endDate").toString() : null; + IPage> result = operationLogService.pageLogs( + pageIndex, pageSize, customerId, userId, startDate, endDate); + Map pageData = new java.util.HashMap<>(); + pageData.put("records", result.getRecords()); + pageData.put("total", result.getTotal()); + return Res.success(pageData); + } + + /** + * 获取企业列表(用于下拉筛选) + */ + @GetMapping("/listCustomers") + public Res listCustomers() { + return Res.success(operationLogService.listCustomers()); + } +} diff --git a/src/main/java/cn/apes/cloud/controller/SysOrganizationController.java b/src/main/java/cn/apes/cloud/controller/SysOrganizationController.java new file mode 100644 index 0000000..faadc68 --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/SysOrganizationController.java @@ -0,0 +1,78 @@ +package cn.apes.cloud.controller; + +import cn.apes.commons.Res; +import cn.apes.commons.auth.Login; +import cn.apes.cloud.config.TenantSource; +import cn.apes.cloud.domain.entity.SysOrganization; +import cn.apes.cloud.service.impl.SysOrganizationServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 组织管理控制器 + */ +@Login +@RestController +@TenantSource +@RequestMapping("/organization") +public class SysOrganizationController { + + @Autowired + private SysOrganizationServiceImpl organizationService; + + /** + * 分页查询组织列表 + */ + @PostMapping("/page") + public Res pageOrganizations(@RequestParam(required = false) String orgName) { + return organizationService.pageOrganizations(orgName); + } + + /** + * 查询组织树 + */ + @GetMapping("/tree") + public Res getOrganizationTree() { + return organizationService.getOrganizationTree(); + } + + /** + * 查询组织详情 + */ + @GetMapping("/detail") + public Res detail(@RequestParam Long id) { + return organizationService.getDetail(id); + } + + /** + * 新增组织 + */ + @PostMapping("/add") + public Res addOrganization(@RequestBody SysOrganization org) { + return organizationService.addOrganization(org); + } + + /** + * 更新组织 + */ + @PostMapping("/update") + public Res updateOrganization(@RequestBody SysOrganization org) { + return organizationService.updateOrganization(org); + } + + /** + * 删除组织 + */ + @PostMapping("/delete") + public Res deleteOrganization(@RequestParam Long id) { + return organizationService.deleteOrganization(id); + } + + /** + * 查询所有启用的组织列表 + */ + @GetMapping("/listAll") + public Res listAllOrganizations() { + return organizationService.listAllOrganizations(); + } +} diff --git a/src/main/java/cn/apes/cloud/controller/SysPackagePlanController.java b/src/main/java/cn/apes/cloud/controller/SysPackagePlanController.java new file mode 100644 index 0000000..9415ff3 --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/SysPackagePlanController.java @@ -0,0 +1,164 @@ +package cn.apes.cloud.controller; + +import cn.apes.cloud.domain.entity.SysPackagePlan; +import cn.apes.cloud.service.impl.SysPackagePlanServiceImpl; +import cn.apes.commons.Res; +import cn.apes.commons.auth.Login; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@Login +@RestController +@RequestMapping("/packagePlan") +public class SysPackagePlanController { + + @Autowired + private SysPackagePlanServiceImpl sysPackagePlanService; + + @Autowired + private cn.apes.cloud.service.SysPackagePlanQuotaService sysPackagePlanQuotaService; + + @PostMapping("/page") + public Res pagePackagePlan(@RequestBody JSONObject data) { + int pageIndex = data.getIntValue("pageIndex"); + int pageSize = data.getIntValue("pageSize"); + if (pageIndex <= 0) pageIndex = 1; + if (pageSize <= 0) pageSize = 10; + String planName = data.getString("planName"); + return Res.success(sysPackagePlanService.pagePackagePlan(pageIndex, pageSize, planName)); + } + + @PostMapping("/add") + public Res addPackagePlan(@RequestBody SysPackagePlan plan) { + return sysPackagePlanService.addPackagePlan(plan); + } + + @PostMapping("/update") + public Res updatePackagePlan(@RequestBody SysPackagePlan plan) { + return sysPackagePlanService.updatePackagePlan(plan); + } + + @PostMapping("/delete") + public Res deletePackagePlan(@RequestBody JSONObject data) { + Long id = data.getLong("id"); + return sysPackagePlanService.deletePackagePlan(id); + } + + @PostMapping("/toggleStatus") + public Res toggleStatus(@RequestBody JSONObject data) { + Long id = data.getLong("id"); + Integer status = data.getInteger("status"); + return sysPackagePlanService.toggleStatus(id, status); + } + + @GetMapping("/detail") + public Res getDetail(@RequestParam Long id) { + SysPackagePlan plan = sysPackagePlanService.getById(id); + if (plan == null) return Res.fail("套餐不存在"); + return Res.success(plan); + } + + /** + * 获取套餐已分配的权限 + */ + @GetMapping("/getPermissions") + public Res getPermissions(@RequestParam Long planId) { + return Res.success(sysPackagePlanService.getPlanPermissions(planId)); + } + + /** + * 保存套餐权限关联 + */ + @PostMapping("/savePermissions") + public Res savePermissions(@RequestBody JSONObject data) { + Long planId = data.getLong("planId"); + Map> appPermissions = new java.util.HashMap<>(); + JSONObject appPermsObj = data.getJSONObject("appPermissions"); + if (appPermsObj != null) { + for (String appKey : appPermsObj.keySet()) { + List permIds = new java.util.ArrayList<>(); + Object val = appPermsObj.get(appKey); + if (val instanceof List) { + for (Object item : (List) val) { + if (item instanceof Number) { + permIds.add(((Number) item).longValue()); + } else if (item != null) { + try { + permIds.add(Long.parseLong(item.toString())); + } catch (NumberFormatException e) { + // skip + } + } + } + } + appPermissions.put(appKey, permIds); + } + } + return sysPackagePlanService.savePlanPermissions(planId, appPermissions); + } + + /** + * 获取套餐配额配置(已绑定的) + */ + @GetMapping("/getQuotas") + public Res getPlanQuotas(@RequestParam Long planId) { + return sysPackagePlanQuotaService.getPlanQuotas(planId); + } + + /** + * 获取所有配额模板 + 标记当前套餐是否已配置 + */ + @GetMapping("/getAllQuotas") + public Res getAllQuotas(@RequestParam Long planId) { + return sysPackagePlanQuotaService.getAllQuotas(planId); + } + + /** + * 获取套餐关联的应用列表 + */ + @GetMapping("/getPlanApps") + public Res getPlanApps(@RequestParam Long planId) { + return sysPackagePlanService.getPlanApps(planId); + } + + /** + * 保存套餐配额配置 + */ + @RequestMapping(value = "/saveQuotas", method = {org.springframework.web.bind.annotation.RequestMethod.GET, org.springframework.web.bind.annotation.RequestMethod.POST}) + public Res savePlanQuotas(@RequestBody(required = false) JSONObject data) { + // 兼容 GET 请求(可能被重定向转换) + if (data == null || data.isEmpty()) { + // 尝试从 request parameters 获取 + javax.servlet.http.HttpServletRequest request = ((org.springframework.web.context.request.ServletRequestAttributes) org.springframework.web.context.request.RequestContextHolder.getRequestAttributes()).getRequest(); + Long planId = request.getParameter("planId") != null ? Long.parseLong(request.getParameter("planId")) : null; + String quotaValuesStr = request.getParameter("quotaValues"); + Map quotaValues = new java.util.HashMap<>(); + if (quotaValuesStr != null) { + try { + JSONObject qv = JSONObject.parseObject(quotaValuesStr); + for (String key : qv.keySet()) { + Object val = qv.get(key); + quotaValues.put(Long.parseLong(key), val != null ? val.toString() : null); + } + } catch (Exception e) { + return Res.fail("quotaValues格式错误"); + } + } + return sysPackagePlanQuotaService.savePlanQuotas(planId, quotaValues); + } + Long planId = data.getLong("planId"); + JSONObject quotaValuesObj = data.getJSONObject("quotaValues"); + Map quotaValues = new java.util.HashMap<>(); + if (quotaValuesObj != null) { + for (String key : quotaValuesObj.keySet()) { + Object val = quotaValuesObj.get(key); + quotaValues.put(Long.parseLong(key), val != null ? val.toString() : null); + } + } + return sysPackagePlanQuotaService.savePlanQuotas(planId, quotaValues); + } +} diff --git a/src/main/java/cn/apes/cloud/controller/SysQuotaController.java b/src/main/java/cn/apes/cloud/controller/SysQuotaController.java new file mode 100644 index 0000000..fdacdde --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/SysQuotaController.java @@ -0,0 +1,51 @@ +package cn.apes.cloud.controller; + +import cn.apes.cloud.domain.entity.SysQuota; +import cn.apes.cloud.service.impl.SysQuotaServiceImpl; +import cn.apes.commons.Res; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/quota") +public class SysQuotaController { + + @Autowired + private SysQuotaServiceImpl sysQuotaService; + + @PostMapping("/page") + public Res pageQuota(@RequestBody JSONObject data) { + int pageIndex = data.getIntValue("pageIndex"); + int pageSize = data.getIntValue("pageSize"); + if (pageIndex <= 0) pageIndex = 1; + if (pageSize <= 0) pageSize = 10; + String appKey = data.getString("appKey"); + String quotaName = data.getString("quotaName"); + String quotaCode = data.getString("quotaCode"); + return Res.success(sysQuotaService.pageQuota(pageIndex, pageSize, appKey, quotaName, quotaCode)); + } + + @PostMapping("/add") + public Res addQuota(@RequestBody SysQuota quota) { + return sysQuotaService.addQuota(quota); + } + + @PostMapping("/update") + public Res updateQuota(@RequestBody SysQuota quota) { + return sysQuotaService.updateQuota(quota); + } + + @PostMapping("/delete") + public Res deleteQuota(@RequestBody JSONObject data) { + Long id = data.getLong("id"); + return sysQuotaService.deleteQuota(id); + } + + @GetMapping("/detail") + public Res getDetail(@RequestParam Long id) { + SysQuota quota = sysQuotaService.getById(id); + if (quota == null) return Res.fail("配额不存在"); + return Res.success(quota); + } +} diff --git a/src/main/java/cn/apes/cloud/controller/UserController.java b/src/main/java/cn/apes/cloud/controller/UserController.java new file mode 100644 index 0000000..2a4384f --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/UserController.java @@ -0,0 +1,207 @@ +package cn.apes.cloud.controller; + +import cn.apes.commons.Res; +import cn.apes.commons.auth.AuthContext; +import cn.apes.commons.auth.Login; +import cn.apes.cloud.config.TenantSource; +import cn.apes.cloud.domain.dto.LoginDTO; +import cn.apes.cloud.domain.dto.PwdDTO; +import cn.apes.cloud.domain.dto.RegisterDTO; +import cn.apes.cloud.domain.dto.SelectCustomerDTO; +import cn.apes.cloud.domain.dto.UserSearchDTO; +import cn.apes.cloud.domain.dto.EnterpriseCertifyDTO; +import cn.apes.cloud.domain.entity.CustomerInfo; +import cn.apes.cloud.domain.entity.UserInfo; +import cn.apes.cloud.service.impl.UserInfoServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@TenantSource +@RequestMapping("/user") +public class UserController { + + @Autowired + UserInfoServiceImpl userInfoService; + + @Login + @PostMapping("/saveUserInfo") + public Res saveUserInfo(@RequestBody UserInfo userInfo) { + return userInfoService.saveUserInfo(userInfo); + } + + @Login +// @CrossOrigin("*") + @PostMapping("/pageUser") + public Res pageUser(@RequestBody UserSearchDTO searchDTO) { + return userInfoService.pageUser(searchDTO); + } + + @PostMapping("/loginPwd") + public Res loginPwd(@RequestBody LoginDTO loginDTO) { + log.info("开始登录了"); + return userInfoService.loginPwd(loginDTO); + } + + /** + * 用户注册 + */ + @PostMapping("/register") + public Res register(@RequestBody RegisterDTO dto) { + return userInfoService.register(dto); + } + + @Login + @PostMapping("/resetPwd") + public Res resetPwd(@RequestBody UserInfo userInfo) { + return userInfoService.resetPwd(userInfo); + } + + @Login + @GetMapping("/getCurrentUser") + public Res getCurrentUser() { + try { + Object loginInfo = AuthContext.getLoginInfo(); + if (loginInfo == null) { + return Res.fail("未登录"); + } + return Res.success(loginInfo); + } catch (Exception e) { + return Res.fail("获取用户信息失败"); + } + } + + @Login + @PostMapping("/editPwd") + public Res editPwd(@RequestBody PwdDTO pwdDTO) { + return userInfoService.editPwd(pwdDTO); + } + + @Login + @GetMapping("/getUserByPhone") + public Res getUserByPhone(String phone) { + return userInfoService.getUser(phone); + } + + @Login + @GetMapping("/getCustomerUser") + public Res getCustomerUser(Long customerId) { + return userInfoService.getCustomerUser(customerId); + } + + /** + * 多客户时用户选择企业 + */ + @PostMapping("/selectCustomer") + public Res selectCustomer(@RequestBody SelectCustomerDTO dto) { + return userInfoService.selectCustomer(dto.getToken(), dto.getCustomerId()); + } + + /** + * 获取当前用户关联的企业列表(用于切换企业场景) + */ + @Login + @GetMapping("/getMyCustomers") + public Res getMyCustomers() { + return userInfoService.getMyCustomers(); + } + + /** + * 编辑当前用户的个人资料(昵称、头像) + */ + @Login + @PostMapping("/editProfile") + public Res editProfile(@RequestBody UserInfo userInfo) { + return userInfoService.editProfile(userInfo); + } + + /** + * 编辑当前企业信息(仅更新当前登录用户的所属企业) + */ + @Login + @PostMapping("/customer/editCurrent") + public Res editCurrentCustomer(@RequestBody CustomerInfo customerInfo) { + return userInfoService.editCurrentCustomer(customerInfo); + } + + /** + * 获取当前企业信息(从数据库直接读取,不走Redis缓存) + */ + @Login + @GetMapping("/customer/getCurrent") + public Res getCurrentCustomer() { + return userInfoService.getCurrentCustomerFromDb(); + } + + /** + * 企业认证:用户提交认证表单,创建客户记录并关联当前用户 + * 使用登录返回的 token(无需额外登录态校验) + */ + @PostMapping("/certifyEnterprise") + public Res certifyEnterprise(@RequestBody EnterpriseCertifyDTO dto) { + if (dto == null || cn.hutool.core.util.StrUtil.isBlank(dto.getToken())) { + return Res.fail("token不能为空"); + } + CustomerInfo customerInfo = new CustomerInfo(); + customerInfo.setCustomerName(dto.getCustomerName()); + customerInfo.setLogo(dto.getLogo()); + customerInfo.setShortName(dto.getShortName()); + customerInfo.setCustomerType(dto.getCustomerType()); + customerInfo.setCustomerIdNumber(dto.getCustomerIdNumber()); + customerInfo.setLegalName(dto.getLegalName()); + customerInfo.setLegalIdFront(dto.getLegalIdFront()); + customerInfo.setLegalIdBack(dto.getLegalIdBack()); + customerInfo.setAdminName(dto.getAdminName()); + customerInfo.setAdminPhone(dto.getAdminPhone()); + customerInfo.setAdminIdNumber(dto.getAdminIdNumber()); + customerInfo.setResponsibleIdFront(dto.getResponsibleIdFront()); + customerInfo.setResponsibleIdBack(dto.getResponsibleIdBack()); + customerInfo.setIndustry(dto.getIndustry()); + customerInfo.setIndustrySub(dto.getIndustrySub()); + customerInfo.setSalesChannel(dto.getSalesChannel()); + customerInfo.setIndustryType(dto.getIndustryType()); + customerInfo.setProvince(dto.getProvince()); + customerInfo.setCity(dto.getCity()); + customerInfo.setBusinessLicense(dto.getBusinessLicense()); + return userInfoService.certifyEnterprise(dto.getToken(), customerInfo); + } + + /** + * 获取当前用户的企业信息(用于重新编辑) + */ + @GetMapping("/getPendingCustomer") + public Res getPendingCustomer(@RequestParam("token") String token) { + return userInfoService.getPendingCustomer(token); + } + + /** + * 重新提交企业认证 + */ + @PostMapping("/recertifyEnterprise") + public Res recertifyEnterprise(@RequestBody EnterpriseCertifyDTO dto) { + CustomerInfo customerInfo = new CustomerInfo(); + customerInfo.setCustomerName(dto.getCustomerName()); + customerInfo.setShortName(dto.getShortName()); + customerInfo.setCustomerIdNumber(dto.getCustomerIdNumber()); + customerInfo.setAdminName(dto.getAdminName()); + customerInfo.setAdminPhone(dto.getAdminPhone()); + customerInfo.setAdminIdNumber(dto.getAdminIdNumber()); + customerInfo.setLegalName(dto.getLegalName()); + customerInfo.setLegalIdFront(dto.getLegalIdFront()); + customerInfo.setLegalIdBack(dto.getLegalIdBack()); + customerInfo.setResponsibleIdFront(dto.getResponsibleIdFront()); + customerInfo.setResponsibleIdBack(dto.getResponsibleIdBack()); + customerInfo.setLogo(dto.getLogo()); + customerInfo.setIndustry(dto.getIndustry()); + customerInfo.setIndustrySub(dto.getIndustrySub()); + customerInfo.setSalesChannel(dto.getSalesChannel()); + customerInfo.setIndustryType(dto.getIndustryType()); + customerInfo.setProvince(dto.getProvince()); + customerInfo.setCity(dto.getCity()); + customerInfo.setBusinessLicense(dto.getBusinessLicense()); + return userInfoService.recertifyEnterprise(dto.getToken(), customerInfo); + } + +} diff --git a/src/main/java/cn/apes/cloud/controller/UserPreferenceController.java b/src/main/java/cn/apes/cloud/controller/UserPreferenceController.java new file mode 100644 index 0000000..7f452c5 --- /dev/null +++ b/src/main/java/cn/apes/cloud/controller/UserPreferenceController.java @@ -0,0 +1,117 @@ +package cn.apes.cloud.controller; + +import cn.apes.cloud.config.TenantSource; +import cn.apes.cloud.domain.entity.UserPreference; +import cn.apes.cloud.service.impl.UserPreferenceServiceImpl; +import cn.apes.commons.Res; +import cn.apes.commons.auth.Login; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * 用户个性化配置控制器 + * + * @author OpenClaw + * @since 2026-08-06 + */ +@RestController +@TenantSource +@RequestMapping("/userPreference") +public class UserPreferenceController { + + @Resource + private UserPreferenceServiceImpl userPreferenceService; + + /** + * 查询指定用户的个性化配置 + * + * @param userId 用户ID + * @return Res 响应对象 + * - code: 状态码,1表示成功 + * - data: 个性化配置对象(未配置时返回默认值 uiSize=2) + */ + @Login + @PostMapping("/get") + public Res getUserPreference(@RequestParam Long userId) { + return userPreferenceService.getUserPreference(userId); + } + + /** + * 查询当前登录用户的个性化配置 + * + * @return Res 响应对象 + * - code: 状态码,1表示成功 + * - data: 当前用户的个性化配置对象(未配置时返回默认值 uiSize=2) + */ + @Login + @PostMapping("/mine") + public Res getCurrentUserPreference() { + return userPreferenceService.getCurrentUserPreference(); + } + + /** + * 新增用户个性化配置 + * + * @param preference 配置对象 + * - userId: 用户ID(必填) + * - uiSize: UI尺寸 1-最大 2-中等 3-最小(必填) + * @return Res 响应对象 + * - code: 状态码,1表示成功 + * - msg: 操作结果消息 + */ + @Login + @PostMapping("/add") + public Res addUserPreference(@RequestBody UserPreference preference) { + return userPreferenceService.addUserPreference(preference); + } + + /** + * 更新用户个性化配置 + * + * @param preference 配置对象 + * - userId: 用户ID(必填) + * - uiSize: UI尺寸 1-最大 2-中等 3-最小(必填) + * @return Res 响应对象 + * - code: 状态码,1表示成功 + * - msg: 操作结果消息 + */ + @Login + @PostMapping("/update") + public Res updateUserPreference(@RequestBody UserPreference preference) { + return userPreferenceService.updateUserPreference(preference); + } + + /** + * 保存当前登录用户的个性化配置(不存在则新增,已存在则更新) + * + * @param preference 配置对象 + * - uiSize: UI尺寸 1-最大 2-中等 3-最小(必填) + * @return Res 响应对象 + * - code: 状态码,1表示成功 + * - msg: 操作结果消息 + */ + @Login + @PostMapping("/save") + public Res saveCurrentUserPreference(@RequestBody UserPreference preference) { + return userPreferenceService.saveCurrentUserPreference(preference); + } + + /** + * 删除用户个性化配置(逻辑删除) + * + * @param userId 用户ID + * @return Res 响应对象 + * - code: 状态码,1表示成功 + * - msg: 操作结果消息 + */ + @Login + @PostMapping("/delete") + public Res deleteUserPreference(@RequestParam Long userId) { + return userPreferenceService.deleteUserPreference(userId); + } +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/AppSearchDTO.java b/src/main/java/cn/apes/cloud/domain/dto/AppSearchDTO.java new file mode 100644 index 0000000..c5fb715 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/AppSearchDTO.java @@ -0,0 +1,10 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class AppSearchDTO extends PageDTO { + private String appName; + private String appKey; + private Boolean userVisible; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/CustomerSearchDTO.java b/src/main/java/cn/apes/cloud/domain/dto/CustomerSearchDTO.java new file mode 100644 index 0000000..22055a4 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/CustomerSearchDTO.java @@ -0,0 +1,9 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class CustomerSearchDTO extends PageDTO{ + + +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/EnterpriseCertifyDTO.java b/src/main/java/cn/apes/cloud/domain/dto/EnterpriseCertifyDTO.java new file mode 100644 index 0000000..903c23f --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/EnterpriseCertifyDTO.java @@ -0,0 +1,52 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class EnterpriseCertifyDTO { + /** 企业名称 */ + private String customerName; + /** 企业LOGO */ + private String logo; + /** 企业简称 */ + private String shortName; + /** 主体类型 1.个人 2.企业 3.个体户 4.政府 */ + private Integer customerType; + /** 营业执照号/证件号 */ + private String customerIdNumber; + /** 法人姓名 */ + private String legalName; + /** 法人身份证正面 */ + private String legalIdFront; + /** 法人身份证反面 */ + private String legalIdBack; + /** 负责人姓名 */ + private String adminName; + /** 负责人手机 */ + private String adminPhone; + /** 负责人证件号 */ + private String adminIdNumber; + /** 负责人身份证正面 */ + private String responsibleIdFront; + /** 负责人身份证反面 */ + private String responsibleIdBack; + /** 行业(一级) */ + private String industry; + /** 行业(二级细分) */ + private String industrySub; + /** 销售渠道 */ + private String salesChannel; + /** 行业类型 */ + private String industryType; + /** 省份 */ + private String province; + /** 城市 */ + private String city; + /** 营业执照 */ + private String businessLicense; + + /** + * Token from login response + */ + private String token; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/LoginDTO.java b/src/main/java/cn/apes/cloud/domain/dto/LoginDTO.java new file mode 100644 index 0000000..9361ffd --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/LoginDTO.java @@ -0,0 +1,9 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class LoginDTO { + String phone; + String password; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/PageDTO.java b/src/main/java/cn/apes/cloud/domain/dto/PageDTO.java new file mode 100644 index 0000000..6ed3973 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/PageDTO.java @@ -0,0 +1,25 @@ +package cn.apes.cloud.domain.dto; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.Data; + +@Data +public class PageDTO { + Integer pageIndex; + Integer pageSize; + + + Integer page; + Integer perPage; + + public IPage getPage() { + if (page != null && perPage != null) { + return new Page(page, perPage); + } + if (pageIndex != null && pageSize != null) { + return new Page(pageIndex, pageSize); + } + return new Page(1, 10); + } +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/PwdDTO.java b/src/main/java/cn/apes/cloud/domain/dto/PwdDTO.java new file mode 100644 index 0000000..b9471e4 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/PwdDTO.java @@ -0,0 +1,10 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class PwdDTO { + String oldPwd; + String pwd1; + String pwd2; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/RegisterDTO.java b/src/main/java/cn/apes/cloud/domain/dto/RegisterDTO.java new file mode 100644 index 0000000..4609646 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/RegisterDTO.java @@ -0,0 +1,19 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class RegisterDTO { + /** + * 用户昵称 + */ + private String nickname; + /** + * 手机号 + */ + private String phone; + /** + * 密码 + */ + private String password; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/RelationDTO.java b/src/main/java/cn/apes/cloud/domain/dto/RelationDTO.java new file mode 100644 index 0000000..ff19acc --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/RelationDTO.java @@ -0,0 +1,15 @@ +package cn.apes.cloud.domain.dto; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class RelationDTO { + String fieldName; + Long fieldId; + List dataIds =new ArrayList<>(); + List dataList; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/RoleSearchDTO.java b/src/main/java/cn/apes/cloud/domain/dto/RoleSearchDTO.java new file mode 100644 index 0000000..d0f0576 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/RoleSearchDTO.java @@ -0,0 +1,13 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +import java.util.Set; + +@Data +public class RoleSearchDTO extends PageDTO{ + Long userNo; + String appName; + Set appNames; + Long planId; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/SelectCustomerDTO.java b/src/main/java/cn/apes/cloud/domain/dto/SelectCustomerDTO.java new file mode 100644 index 0000000..7ae877d --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/SelectCustomerDTO.java @@ -0,0 +1,9 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class SelectCustomerDTO { + String token; + Long customerId; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/SysRoleDTO.java b/src/main/java/cn/apes/cloud/domain/dto/SysRoleDTO.java new file mode 100644 index 0000000..7a2b0a4 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/SysRoleDTO.java @@ -0,0 +1,21 @@ +package cn.apes.cloud.domain.dto; + +import cn.apes.cloud.domain.entity.SysRole; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * description + * + * @date 2024/7/9 09:44 + */ +@Data +public class SysRoleDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private String appName; + + private List SysRoleList; +} diff --git a/src/main/java/cn/apes/cloud/domain/dto/UserSearchDTO.java b/src/main/java/cn/apes/cloud/domain/dto/UserSearchDTO.java new file mode 100644 index 0000000..625194e --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/dto/UserSearchDTO.java @@ -0,0 +1,9 @@ +package cn.apes.cloud.domain.dto; + +import lombok.Data; + +@Data +public class UserSearchDTO extends PageDTO{ + String nickName; + String phone; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/AppInfo.java b/src/main/java/cn/apes/cloud/domain/entity/AppInfo.java new file mode 100644 index 0000000..910535e --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/AppInfo.java @@ -0,0 +1,25 @@ +package cn.apes.cloud.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import lombok.Data; + +import java.util.Date; + +@Data +public class AppInfo { + @TableId + private String appKey; + private String appIcon; + private String appName; + private String appShortName; + private String appType; + private String remark; + private Boolean userVisible; + private String huobanSpaceId; // 伙伴云工作区ID + private String huobanSpaceGroupId; // 伙伴云工作区用户组ID + private Date createTime; + private Date updateTime; + @TableLogic + private Boolean isDel; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/CustomerApp.java b/src/main/java/cn/apes/cloud/domain/entity/CustomerApp.java new file mode 100644 index 0000000..898b420 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/CustomerApp.java @@ -0,0 +1,14 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class CustomerApp extends DbEntity implements Serializable { + + private Long customerId; + + private String appKey; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/CustomerInfo.java b/src/main/java/cn/apes/cloud/domain/entity/CustomerInfo.java new file mode 100644 index 0000000..1595637 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/CustomerInfo.java @@ -0,0 +1,142 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +public class CustomerInfo extends DbEntity implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 客户类型 1.个人 2.企业 3.个体户 4.政府 + */ + private Integer customerType; + + /** + * 客户名称 + */ + private String customerName; + + /** + * 客户LOGO图片URL + */ + private String logo; + + /** + * 客户名称 + */ + private String shortName; + + /** + * 证件号,确保唯一性并不允许空值。 + */ + private String customerIdNumber; + + /** + * 企业状态:0=待审核,1=使用中,3=已注销,4=暂停服务,5=审核拒绝 + */ + private Integer customerStatus; + + /** + * 审核拒绝原因 + */ + private String auditRemark; + + /** + * 审核时间 + */ + private java.util.Date auditTime; + + /** + * 管理员姓名,不允许空值。 + */ + private String adminName; + + /** + * 管理员手机号,不允许空值。 + */ + private String adminPhone; + + /** + * 管理员证件号,确保唯一性并不允许空值。 + */ + private String adminIdNumber; + + // ========== 资质管理 ========== + + /** + * 营业执照图片URL + */ + private String businessLicense; + + /** + * 法人姓名 + */ + private String legalName; + + /** + * 法人身份证正面图片URL + */ + private String legalIdFront; + + /** + * 法人身份证反面图片URL + */ + private String legalIdBack; + + /** + * 负责人身份证正面图片URL + */ + private String responsibleIdFront; + + /** + * 负责人身份证反面图片URL + */ + private String responsibleIdBack; + + // ========== 行业 / 区域 / 渠道 ========== + + /** + * 行业(一级) + */ + private String industry; + + /** + * 行业(二级细分) + */ + private String industrySub; + + /** + * 销售渠道 + */ + private String salesChannel; + + /** + * 行业类型:供应商/加工商/经销商/零售商 + */ + private String industryType; + + /** + * 省份 + */ + private String province; + + /** + * 城市 + */ + private String city; + + /** + * 关联套餐列表(非数据库字段) + */ + @com.baomidou.mybatisplus.annotation.TableField(exist = false) + private List plans; + +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/CustomerPackage.java b/src/main/java/cn/apes/cloud/domain/entity/CustomerPackage.java new file mode 100644 index 0000000..90fccb6 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/CustomerPackage.java @@ -0,0 +1,53 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +@TableName("customer_package") +public class CustomerPackage extends DbEntity implements Serializable { + + /** + * 客户ID + */ + private Long customerId; + + /** + * 套餐ID + */ + private Long planId; + + /** + * 到期时间 + */ + private Date expireTime; + + /** + * 套餐名称(非数据库字段) + */ + @TableField(exist = false) + private String planName; + + /** + * 套餐级别(非数据库字段) + */ + @TableField(exist = false) + private Integer planLevel; + + /** + * 收费模式(非数据库字段) + */ + @TableField(exist = false) + private String chargeMode; + + /** + * 金额(非数据库字段) + */ + @TableField(exist = false) + private java.math.BigDecimal amount; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/CustomerPackageExtendApply.java b/src/main/java/cn/apes/cloud/domain/entity/CustomerPackageExtendApply.java new file mode 100644 index 0000000..57f3974 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/CustomerPackageExtendApply.java @@ -0,0 +1,43 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("customer_package_extend_apply") +public class CustomerPackageExtendApply extends DbEntity { + + /** 客户ID */ + private Long customerId; + + /** 套餐ID */ + private Long planId; + + /** 申请用户ID */ + private Long userId; + + /** 联系电话 */ + private String contactPhone; + + /** 延期原因 */ + private String reason; + + /** 申请延期天数 */ + private Integer applyDays; + + /** 状态:0-申请中 1-已调整 2-已拒绝 */ + private Integer status; + + /** 操作人ID(同意/拒绝的人) */ + private Long operatorId; + + /** 操作人姓名 */ + private String operatorName; + + /** 操作时间 */ + private java.util.Date operateTime; + + /** 申请时间 */ + private java.util.Date applyTime; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/CustomerPackageQuota.java b/src/main/java/cn/apes/cloud/domain/entity/CustomerPackageQuota.java new file mode 100644 index 0000000..79923c0 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/CustomerPackageQuota.java @@ -0,0 +1,68 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +@Data +@TableName("customer_package_quota") +public class CustomerPackageQuota extends DbEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 客户套餐关联ID + */ + private Long customerPackageId; + + /** + * 配额模板ID + */ + private Long quotaId; + + /** + * 应用标识 + */ + private String appKey; + + /** + * 配额编码 + */ + private String quotaCode; + + /** + * 配额名称 + */ + private String quotaName; + + /** + * 数据类型 + */ + private String dataType; + + /** + * 配额值 + */ + private String quotaValue; + + /** + * 应用名称(非数据库字段) + */ + @TableField(exist = false) + private String appName; + + /** + * 单位(非数据库字段,来自sys_quota) + */ + @TableField(exist = false) + private String unit; + + /** + * 重置周期(非数据库字段,来自sys_quota) + */ + @TableField(exist = false) + private String resetCycle; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/CustomerQuotaChangeLog.java b/src/main/java/cn/apes/cloud/domain/entity/CustomerQuotaChangeLog.java new file mode 100644 index 0000000..b463286 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/CustomerQuotaChangeLog.java @@ -0,0 +1,86 @@ +package cn.apes.cloud.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 客户配额变更日志 + */ +@Data +@TableName("customer_quota_change_log") +public class CustomerQuotaChangeLog implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 客户套餐关联ID + */ + private Long customerPackageId; + + /** + * 配额编码 + */ + private String quotaCode; + + /** + * 配额名称 + */ + private String quotaName; + + /** + * 变更类型:1=增加,2=减少 + */ + private Integer changeType; + + /** + * 变更数量 + */ + private Integer changeAmount; + + /** + * 变更前值 + */ + private String oldValue; + + /** + * 变更后值 + */ + private String newValue; + + /** + * 变更原因 + */ + private String reason; + + /** + * 操作人ID + */ + private Long operatorId; + + /** + * 操作人姓名 + */ + private String operatorName; + + /** + * 操作时间 + */ + private Date operateTime; + + /** + * 客户名称(非数据库字段,用于展示) + */ + @com.baomidou.mybatisplus.annotation.TableField(exist = false) + private String customerName; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/CustomerUser.java b/src/main/java/cn/apes/cloud/domain/entity/CustomerUser.java new file mode 100644 index 0000000..49c2b04 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/CustomerUser.java @@ -0,0 +1,29 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class CustomerUser extends DbEntity implements Serializable { + + private long userId; + + private long customerId; + + /** 所属组织ID */ + private Long orgId; + + /** 姓名 */ + private String name; + + /** 职称 */ + private String title; + + /** 岗位 */ + private String position; + + /** 应用ID集合(逗号分隔) */ + private String appIds; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SsoConfig.java b/src/main/java/cn/apes/cloud/domain/entity/SsoConfig.java new file mode 100644 index 0000000..34e2b45 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SsoConfig.java @@ -0,0 +1,31 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class SsoConfig extends DbEntity implements Serializable { + @JsonSerialize(using = ToStringSerializer.class) + private Long userId; // 用户ID + private Long customerId; + //伙伴云配置 + private String huobanMobile; // 伙伴云绑定手机号 + @JsonSerialize(using = ToStringSerializer.class) + private Long huobanCompanyId; // 伙伴云公司ID + private String huobanName; // 伙伴云用户名 + private Integer huobanStatus; + private Long huobanUserId; // 伙伴云用户ID + private String huobanUserName; // 伙伴云用户名(搜索返回的name) + private String huobanAvatar; // 伙伴云用户头像 + + //交易平台配置 + private String paymentUserName; + private String paymentPassword; + private Integer paymentGroup; + private Integer paymentStatus; + +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysAccessToken.java b/src/main/java/cn/apes/cloud/domain/entity/SysAccessToken.java new file mode 100644 index 0000000..cc17cf0 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysAccessToken.java @@ -0,0 +1,75 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 外部系统调用用的 AccessToken 表 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class SysAccessToken extends DbEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * Token 值(明文存储) + */ + private String token; + + /** + * 名称,用于管理识别 + */ + private String name; + + /** + * 所属客户(企业)ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long customerId; + + /** + * 接口范围:* 表示全部,否则为逗号分隔的 Ant 路径 + */ + private String scope; + + /** + * IP 白名单,多个用逗号分隔,为空表示不限制 + */ + private String whitelistIps; + + /** + * 状态 1=启用 2=停用 + */ + private Integer status; + + /** + * 过期时间,NULL 表示永不过期 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date expireTime; + + /** + * 最后使用时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date lastUsedTime; + + /** + * 最后使用 IP + */ + private String lastUsedIp; + + /** + * 创建人 + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long createBy; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysMemberRole.java b/src/main/java/cn/apes/cloud/domain/entity/SysMemberRole.java new file mode 100644 index 0000000..494721b --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysMemberRole.java @@ -0,0 +1,38 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class SysMemberRole extends DbEntity implements Serializable { + + + private String appName; + /** + * 角色id + */ + private Long roleId; + + /** + * 账号id + */ + private Long userId; + + /** + * 角色附加数据 一般用于子账号保存主账号userno + */ + private String roleData; + + /** + * 角色所属客户(企业),系统角色为0 + */ + private Long customerId; + + +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysMenu.java b/src/main/java/cn/apes/cloud/domain/entity/SysMenu.java new file mode 100644 index 0000000..43f7ef4 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysMenu.java @@ -0,0 +1,103 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author + * @description sys_menu + * @date 2023-06-29 + */ +@Data +public class SysMenu extends DbEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 菜单名称 + */ + + private String menuTitle; + + /** + * 菜单路径 + */ + private String menuPath; + + /** + * 菜单类型 1.vue菜单2.伙伴云菜单 3.交易系统菜单 + */ + private Integer menuType; + + private String configJson; + + @TableField(exist = false) + private JSONObject config; + + private String vuePath; + private String vueName; + + private Long amisId; + /** + * 菜单图片 + */ + private String menuIcon; + + /** + * 父级id 根为0 + */ + private Long parentId; + + /** + * 平台类型 + */ + private String appName; + + /** + * 对应的权限code + */ + private String permissionCode; + + /** + * 备注 + */ + @JsonIgnore + private String remark; + /** + * 低版本 + */ + @JsonIgnore + private String lowVersion; + /** + * 高版本 + */ + @JsonIgnore + private String highVersion; + + private Integer sort; + + private boolean hidden; + + /** + * 是否在看板显示 + */ + private Boolean showOnBoard; + + @TableField(exist = false) + private List child; + + public SysMenu() { + } +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysOperationLog.java b/src/main/java/cn/apes/cloud/domain/entity/SysOperationLog.java new file mode 100644 index 0000000..2de4bce --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysOperationLog.java @@ -0,0 +1,65 @@ +package cn.apes.cloud.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + +/** + * 操作日志表 + */ +@Data +@TableName("sys_operation_log") +public class SysOperationLog { + + @TableId(type = IdType.AUTO) + private Long id; + + /** 用户ID */ + private Long userId; + + /** 用户名 */ + private String userName; + + /** 租户/企业ID */ + private Long customerId; + + /** 企业名称 */ + private String customerName; + + /** 模块名称 */ + private String module; + + /** 操作名称 */ + private String action; + + /** 日志说明 */ + private String description; + + /** IP地址 */ + private String ip; + + /** 浏览器/设备信息 */ + private String userAgent; + + /** 登录地址(预留) */ + private String loginLocation; + + /** 请求方法 */ + private String requestMethod; + + /** 请求URL */ + private String requestUrl; + + /** 请求参数 */ + private String requestParams; + + /** 操作时间 */ + private Date operateTime; + + private String createBy; + + private Date createTime; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysOrganization.java b/src/main/java/cn/apes/cloud/domain/entity/SysOrganization.java new file mode 100644 index 0000000..0267df9 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysOrganization.java @@ -0,0 +1,62 @@ +package cn.apes.cloud.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * 组织表 + */ +@Data +@TableName("sys_organization") +public class SysOrganization { + + @TableId(type = IdType.AUTO) + private Long id; + + /** 租户ID */ + private Long customerId; + + /** 组织名称 */ + private String orgName; + + /** 上级组织ID,根节点为0 */ + private Long parentId; + + /** 组织类型 */ + private String orgType; + + /** 组织说明 */ + private String description; + + /** 排序 */ + private Integer sortOrder; + + /** 状态 1启用/0停用 */ + private Integer status; + + /** 逻辑删除 0正常/1删除 */ + private Integer isDel; + + private String createBy; + + private Date createTime; + + private String updateBy; + + private Date updateTime; + + /** 子节点列表(非数据库字段) */ + @TableField(exist = false) + private List children; + + /** 父级名称(非数据库字段) */ + @TableField(exist = false) + private String parentName; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlan.java b/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlan.java new file mode 100644 index 0000000..6a29967 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlan.java @@ -0,0 +1,50 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class SysPackagePlan extends DbEntity implements Serializable { + + /** + * 套餐名称 + */ + private String planName; + + /** + * 套餐级别: 1/2/3 + */ + private Integer planLevel; + + /** + * 套餐说明 + */ + private String description; + + /** + * 收费模式: monthly/yearly + */ + private String chargeMode; + + /** + * 金额 + */ + private java.math.BigDecimal amount; + + /** + * 状态: 1启用 0停用 + */ + private Integer status; + + /** + * 图标URL + */ + private String iconUrl; + + /** + * 应用ID集合,逗号分隔 + */ + private String appIds; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlanPermission.java b/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlanPermission.java new file mode 100644 index 0000000..ca7cbc2 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlanPermission.java @@ -0,0 +1,41 @@ +package cn.apes.cloud.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +@TableName("sys_package_plan_permission") +public class SysPackagePlanPermission implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 套餐ID + */ + private Long planId; + + /** + * 应用Key + */ + private String appKey; + + /** + * 权限ID + */ + private Long permissionId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlanQuota.java b/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlanQuota.java new file mode 100644 index 0000000..753339c --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysPackagePlanQuota.java @@ -0,0 +1,102 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +@Data +@TableName("sys_package_plan_quota") +public class SysPackagePlanQuota extends DbEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 套餐ID + */ + private Long planId; + + /** + * 配额模板ID + */ + private Long quotaId; + + /** + * 配额值 + */ + private String quotaValue; + + /** + * 配额名称(非数据库字段) + */ + @TableField(exist = false) + private String quotaName; + + /** + * 配额编码(非数据库字段) + */ + @TableField(exist = false) + private String quotaCode; + + /** + * 数据类型(非数据库字段) + */ + @TableField(exist = false) + private String dataType; + + /** + * 应用标识(非数据库字段) + */ + @TableField(exist = false) + private String appKey; + + /** + * 应用名称(非数据库字段) + */ + @TableField(exist = false) + private String appName; + + /** + * 最大配额(非数据库字段) + */ + @TableField(exist = false) + private Long maxQuota; + + /** + * 最大配额值-小数(非数据库字段) + */ + @TableField(exist = false) + private java.math.BigDecimal maxQuotaValue; + + /** + * 枚举值(非数据库字段) + */ + @TableField(exist = false) + private String enumValues; + + /** + * 单位(非数据库字段) + */ + @TableField(exist = false) + private String unit; + + /** + * 重置周期(非数据库字段) + */ + @TableField(exist = false) + private String resetCycle; + + /** + * 默认值(非数据库字段) + */ + @TableField(exist = false) + private String defaultValue; + + /** + * 是否已在当前套餐中配置(非数据库字段) + */ + @TableField(exist = false) + private Boolean configured; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysPermission.java b/src/main/java/cn/apes/cloud/domain/entity/SysPermission.java new file mode 100644 index 0000000..b66deb2 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysPermission.java @@ -0,0 +1,59 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @description sys_permission + * @author zhengkai.blog.csdn.net + * @date 2023-06-29 + */ +@Data +public class SysPermission extends DbEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 权限名称 + */ + private String permissionName; + + /** + * 权限code + */ + private String permissionCode; + + /** + * 备注 + */ + private String remark; + + /** + * 父级id 根为0 + */ + private Long parentId; + + /** + * 平台类型 + */ + private String appName; + + + + @TableField(exist = false) + private List child; + + + public SysPermission() {} +} \ No newline at end of file diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysQuota.java b/src/main/java/cn/apes/cloud/domain/entity/SysQuota.java new file mode 100644 index 0000000..5417405 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysQuota.java @@ -0,0 +1,79 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class SysQuota extends DbEntity implements Serializable { + + /** + * 配额名称 + */ + private String quotaName; + + /** + * 标识编码 + */ + private String quotaCode; + + /** + * 数据类型: integer/decimal/boolean/enum + */ + private String dataType; + + /** + * 最大配额(整数类型) + */ + private Long maxQuota; + + /** + * 最大配额单位(整数类型) + */ + private String maxQuotaUnit; + + /** + * 最大配额值(小数类型) + */ + private java.math.BigDecimal maxQuotaValue; + + /** + * 单位(小数类型) + */ + private String unit; + + /** + * 枚举值,JSON数组格式 + */ + private String enumValues; + + /** + * 默认值 + */ + private String defaultValue; + + /** + * 重置周期: none/daily/weekly/monthly/yearly + */ + private String resetCycle; + + /** + * 是否显示: 1显示 0隐藏 + */ + private Integer isVisible; + + /** + * 说明 + */ + private String description; + + /** + * 关联应用标识 + */ + private String appKey; +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysRole.java b/src/main/java/cn/apes/cloud/domain/entity/SysRole.java new file mode 100644 index 0000000..831943b --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysRole.java @@ -0,0 +1,50 @@ +package cn.apes.cloud.domain.entity; + + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class SysRole extends DbEntity implements Serializable { + + /** + * 角色名 + */ + private String roleName; + + /** + * 角色标识 + */ + private String roleKey; + + /** + * 角色所属用户,系统角色为0 + */ + private Long userNo; + + + + /** + * 所属套餐ID + */ + private Long planId; + + /** + * @deprecated 已废弃,角色不再直接关联应用,改为通过套餐关联 + * 保留该字段是为了兼容存量数据 + */ + @Deprecated + private String appName; + + @TableField(exist = false) + private cn.apes.cloud.domain.entity.SysPackagePlan planInfo; + + +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/SysRolePermission.java b/src/main/java/cn/apes/cloud/domain/entity/SysRolePermission.java new file mode 100644 index 0000000..1b30f1e --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/SysRolePermission.java @@ -0,0 +1,40 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * @description 角色权限表 + * @author zhengkai.blog.csdn.net + * @date 2023-06-29 + */ +@Data +public class SysRolePermission extends DbEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + + + /** + * 角色id + */ + private Long roleId; + + /** + * 权限id + */ + private Long permissionId; + + /** + * 应用Key + */ + private String appKey; + + public SysRolePermission() {} +} diff --git a/src/main/java/cn/apes/cloud/domain/entity/UserInfo.java b/src/main/java/cn/apes/cloud/domain/entity/UserInfo.java new file mode 100644 index 0000000..8806033 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/UserInfo.java @@ -0,0 +1,81 @@ +package cn.apes.cloud.domain.entity; + +import cn.apes.commons.domain.DbEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 用户信息实体类 + * + * @author [你的名字] + * @since [创建时间] + */ +@Data + +public class UserInfo extends DbEntity implements Serializable { + + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户头像链接 + */ + private String portrait; + + /** + * 用户手机号码 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 备用邮箱 + */ + private String backupEmail; + + /** + * 用户密码(加密存储) + */ + private String password; + + /** + * 用户状态(1.正常 2.禁止登录) + */ + private Integer status; + + /** + * 用户备注信息 + */ + private String remark; + + + @TableField(exist = false) + List customerList; + @TableField(exist = false) + List roles; + @TableField(exist = false) + + private Integer paymentStatus; + @TableField(exist = false) + + private Integer huobanStatus; + @TableField(exist = false) + private Date bindTime; + + +} \ No newline at end of file diff --git a/src/main/java/cn/apes/cloud/domain/entity/UserPreference.java b/src/main/java/cn/apes/cloud/domain/entity/UserPreference.java new file mode 100644 index 0000000..81e6ff8 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/entity/UserPreference.java @@ -0,0 +1,53 @@ +package cn.apes.cloud.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; + +/** + * 用户个性化配置实体类 + *

+ * 注意:该表以 user_id 作为主键(无自增 id 列),因此不继承 DbEntity, + * 避免父类 id 字段映射到不存在的列。 + * + * @author OpenClaw + * @since 2026-08-06 + */ +@Data +@TableName("user_preference") +public class UserPreference { + + /** + * 用户ID(主键) + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * UI尺寸 1-最大 2-中等 3-最小 + */ + private Integer uiSize; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + + /** + * 逻辑删除 0-正常 1-删除 + */ + @TableLogic + private Integer isDel; +} diff --git a/src/main/java/cn/apes/cloud/domain/huoban/BulkDel.java b/src/main/java/cn/apes/cloud/domain/huoban/BulkDel.java new file mode 100644 index 0000000..81196d5 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/huoban/BulkDel.java @@ -0,0 +1,12 @@ +package cn.apes.cloud.domain.huoban; + +import lombok.Data; + +import java.util.List; + +@Data +public class BulkDel { + private String tableId; + private List itemIds; + +} diff --git a/src/main/java/cn/apes/cloud/domain/huoban/CategoryConfig.java b/src/main/java/cn/apes/cloud/domain/huoban/CategoryConfig.java new file mode 100644 index 0000000..f09c341 --- /dev/null +++ b/src/main/java/cn/apes/cloud/domain/huoban/CategoryConfig.java @@ -0,0 +1,18 @@ +package cn.apes.cloud.domain.huoban; + +import lombok.Data; + +import java.util.List; + +@Data +public class CategoryConfig { + private List