diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysTenantPackageController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysTenantPackageController.java
new file mode 100644
index 0000000..817ad82
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysTenantPackageController.java
@@ -0,0 +1,150 @@
+package com.ruoyi.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import com.ruoyi.common.core.constant.TenantConstants;
+import com.ruoyi.common.core.core.domain.R;
+import com.ruoyi.common.excel.utils.ExcelUtil;
+import com.ruoyi.common.web.annotation.RepeatSubmit;
+import com.ruoyi.common.log.annotation.Log;
+import com.ruoyi.common.log.enums.BusinessType;
+import com.ruoyi.common.orm.core.page.TableDataInfo;
+import com.ruoyi.common.web.core.BaseController;
+import com.ruoyi.system.domain.bo.SysTenantPackageBo;
+import com.ruoyi.system.domain.vo.SysTenantPackageVo;
+import com.ruoyi.system.service.ISysTenantPackageService;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 租户套餐管理
+ *
+ * @author Michelle.Chung
+ * author 数据小王子
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/tenant/package")
+public class SysTenantPackageController extends BaseController
+{
+    @Resource
+    private  ISysTenantPackageService tenantPackageService;
+
+    /**
+     * 查询租户套餐列表
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysTenantPackageVo> list(SysTenantPackageBo sysTenantPackageBo) {
+        return tenantPackageService.selectPage(sysTenantPackageBo);
+    }
+
+    /**
+     * 查询租户套餐下拉选列表
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:list")
+    @GetMapping("/selectList")
+    public R<List<SysTenantPackageVo>> selectList() {
+        return R.ok(tenantPackageService.selectList());
+    }
+
+    /**
+     * 导出租户套餐列表
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:export")
+    @Log(title = "租户套餐", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(SysTenantPackageBo sysTenantPackageBo, HttpServletResponse response) {
+        List<SysTenantPackageVo> list = tenantPackageService.queryList(sysTenantPackageBo);
+        ExcelUtil.exportExcel(list, "租户套餐", SysTenantPackageVo.class, response);
+    }
+
+    /**
+     * 获取租户套餐详细信息
+     *
+     * @param packageId 主键
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:query")
+    @GetMapping("/{packageId}")
+    public R<SysTenantPackageVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable Long packageId) {
+        return R.ok(tenantPackageService.selectById(packageId));
+    }
+
+    /**
+     * 新增租户套餐
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:add")
+    @Log(title = "租户套餐", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated @RequestBody SysTenantPackageBo sysTenantPackageBo) {
+        boolean inserted = tenantPackageService.insert(sysTenantPackageBo);
+        if (!inserted) {
+            return R.fail("新增租户套餐记录失败!");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 修改租户套餐
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:edit")
+    @Log(title = "租户套餐", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated @RequestBody SysTenantPackageBo sysTenantPackageBo) {
+        Boolean updated = tenantPackageService.update(sysTenantPackageBo);
+        if (!updated) {
+            R.fail("修改租户套餐记录失败!");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 状态修改
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:edit")
+    @Log(title = "租户套餐", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysTenantPackageBo sysTenantPackageBo) {
+        Boolean updated = tenantPackageService.updatePackageStatus(sysTenantPackageBo);
+        if (!updated) {
+            R.fail("修改租户套餐记录状态失败!");
+        }
+        return R.ok();
+    }
+
+    /**
+     * 删除租户套餐
+     *
+     * @param packageIds 主键串
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:remove")
+    @Log(title = "租户套餐", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{packageIds}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable Long[] packageIds) {
+        boolean deleted = tenantPackageService.deleteByIds(packageIds, true);
+        if (!deleted) {
+            R.fail("删除租户套餐记录失败!");
+        }
+        return R.ok();
+    }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTenantPackage.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTenantPackage.java
new file mode 100644
index 0000000..2feec0d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTenantPackage.java
@@ -0,0 +1,75 @@
+package com.ruoyi.system.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.Table;
+import lombok.Data;
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 租户套餐对象 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ * @author 数据小王子
+ */
+@Data
+@Table("sys_tenant_package")
+public class SysTenantPackage implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 租户套餐id
+     */
+    @Id
+    private Long packageId;
+    /**
+     * 套餐名称
+     */
+    private String packageName;
+    /**
+     * 关联菜单id
+     */
+    private String menuIds;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)
+     */
+    private Boolean menuCheckStrictly;
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+    /**
+     * 删除标志(0代表存在 1代表删除)
+     */
+    private Integer delFlag;
+
+    /**
+     * 创建者
+     */
+    private Long createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 更新者
+     */
+    private Long updateBy;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysTenantPackageBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysTenantPackageBo.java
new file mode 100644
index 0000000..c6e0096
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysTenantPackageBo.java
@@ -0,0 +1,51 @@
+package com.ruoyi.system.domain.bo;
+
+import com.ruoyi.system.domain.SysTenantPackage;
+import io.github.linpeilie.annotations.AutoMapper;
+import io.github.linpeilie.annotations.AutoMapping;
+import lombok.Data;
+import jakarta.validation.constraints.*;
+import java.io.Serializable;
+
+/**
+ * 租户套餐业务对象 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@AutoMapper(target = SysTenantPackage.class, reverseConvertGenerate = false)
+public class SysTenantPackageBo implements Serializable {
+
+    /**
+     * 租户套餐id
+     */
+    private Long packageId;
+
+    /**
+     * 套餐名称
+     */
+    @NotBlank(message = "套餐名称不能为空")
+    private String packageName;
+
+    /**
+     * 关联菜单id
+     */
+    @AutoMapping(target = "menuIds", expression = "java(com.ruoyi.common.core.utils.StringUtils.join(source.getMenuIds(), \",\"))")
+    private Long[] menuIds;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 菜单树选择项是否关联显示
+     */
+    private Boolean menuCheckStrictly;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysTenantPackageVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysTenantPackageVo.java
new file mode 100644
index 0000000..a24615b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysTenantPackageVo.java
@@ -0,0 +1,64 @@
+package com.ruoyi.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.ruoyi.common.excel.annotation.ExcelDictFormat;
+import com.ruoyi.common.excel.convert.ExcelDictConvert;
+import com.ruoyi.system.domain.SysTenantPackage;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 租户套餐视图对象 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysTenantPackage.class)
+public class SysTenantPackageVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 租户套餐id
+     */
+    @ExcelProperty(value = "租户套餐id")
+    private Long packageId;
+
+    /**
+     * 套餐名称
+     */
+    @ExcelProperty(value = "套餐名称")
+    private String packageName;
+
+    /**
+     * 关联菜单id
+     */
+    @ExcelProperty(value = "关联菜单id")
+    private String menuIds;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+    /**
+     * 菜单树选择项是否关联显示
+     */
+    @ExcelProperty(value = "菜单树选择项是否关联显示")
+    private Boolean menuCheckStrictly;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
+    private String status;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTenantPackageMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTenantPackageMapper.java
new file mode 100644
index 0000000..beea414
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTenantPackageMapper.java
@@ -0,0 +1,15 @@
+package com.ruoyi.system.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import com.ruoyi.system.domain.SysTenantPackage;
+
+/**
+ * 租户套餐Mapper接口
+ *
+ * @author 数据小王子
+ */
+@Mapper
+public interface SysTenantPackageMapper extends BaseMapper<SysTenantPackage> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTenantPackageService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTenantPackageService.java
new file mode 100644
index 0000000..312edbf
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTenantPackageService.java
@@ -0,0 +1,62 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.common.orm.core.service.IBaseService;
+import com.ruoyi.system.domain.SysTenantPackage;
+import com.ruoyi.system.domain.vo.SysTenantPackageVo;
+import com.ruoyi.system.domain.bo.SysTenantPackageBo;
+import com.ruoyi.common.orm.core.page.TableDataInfo;
+import com.ruoyi.common.orm.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 租户套餐Service接口
+ *
+ * @author 数据小王子
+ */
+public interface ISysTenantPackageService extends IBaseService<SysTenantPackage> {
+
+    /**
+     * 查询租户套餐
+     */
+    SysTenantPackageVo selectById(Long packageId);
+
+    /**
+     * 分页查询租户套餐
+     *
+     * @param sysTenantPackageBo 租户套餐Bo
+     * @return 租户套餐集合
+     */
+    TableDataInfo<SysTenantPackageVo> selectPage(SysTenantPackageBo sysTenantPackageBo);
+
+    /**
+     * 查询租户套餐下拉选列表
+     */
+    List<SysTenantPackageVo> selectList();
+
+    /**
+     * 查询租户套餐列表
+     */
+    List<SysTenantPackageVo> queryList(SysTenantPackageBo bo);
+
+    /**
+     * 新增租户套餐
+     */
+    Boolean insert(SysTenantPackageBo sysTenantPackageBo);
+
+    /**
+     * 修改租户套餐
+     */
+    Boolean update(SysTenantPackageBo sysTenantPackageBo);
+
+    /**
+     * 修改套餐状态
+     */
+    Boolean updatePackageStatus(SysTenantPackageBo sysTenantPackageBo);
+
+    /**
+     * 校验并批量删除租户套餐信息
+     */
+    Boolean deleteByIds(Long[] packageIds, Boolean isValid);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantPackageServiceImpl.java
new file mode 100644
index 0000000..951d930
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantPackageServiceImpl.java
@@ -0,0 +1,190 @@
+package com.ruoyi.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.mybatisflex.core.paginate.Page;
+import com.mybatisflex.core.query.QueryWrapper;
+import com.mybatisflex.core.util.UpdateEntity;
+import com.ruoyi.common.orm.core.service.impl.BaseServiceImpl;
+import com.ruoyi.common.security.utils.LoginHelper;
+import jakarta.annotation.Resource;
+import lombok.RequiredArgsConstructor;
+import com.ruoyi.common.core.constant.TenantConstants;
+import com.ruoyi.common.core.exception.ServiceException;
+import com.ruoyi.common.core.utils.MapstructUtils;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.orm.core.page.PageQuery;
+import com.ruoyi.common.orm.core.page.TableDataInfo;
+import com.ruoyi.system.domain.SysTenantPackage;
+import com.ruoyi.system.domain.bo.SysTenantPackageBo;
+import com.ruoyi.system.domain.vo.SysTenantPackageVo;
+import com.ruoyi.system.mapper.SysTenantMapper;
+import com.ruoyi.system.mapper.SysTenantPackageMapper;
+import com.ruoyi.system.service.ISysTenantPackageService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import static com.ruoyi.system.domain.table.SysTenantPackageTableDef.SYS_TENANT_PACKAGE;
+import static com.ruoyi.system.domain.table.SysTenantTableDef.SYS_TENANT;
+
+/**
+ * 租户套餐Service业务层处理
+ *
+ * @author 数据小王子
+ */
+@RequiredArgsConstructor
+@Service
+public class SysTenantPackageServiceImpl extends BaseServiceImpl<SysTenantPackageMapper, SysTenantPackage> implements ISysTenantPackageService {
+
+    @Resource
+    private  SysTenantPackageMapper tenantPackageMapper;
+    @Resource
+    private  SysTenantMapper tenantMapper;
+
+    @Override
+    public QueryWrapper query() {
+        return super.query().from(SYS_TENANT_PACKAGE);
+    }
+
+    private QueryWrapper buildQueryWrapper(SysTenantPackageBo bo) {
+        return  super.buildBaseQueryWrapper()
+            .and(SYS_TENANT_PACKAGE.PACKAGE_NAME.like(bo.getPackageName()))
+            .and(SYS_TENANT_PACKAGE.STATUS.eq(bo.getStatus()))
+            .orderBy(SYS_TENANT_PACKAGE.PACKAGE_ID.desc());
+    }
+
+    /**
+     * 查询租户套餐
+     */
+    @Override
+    public SysTenantPackageVo selectById(Long packageId){
+        return this.getOneAs(query().where(SYS_TENANT_PACKAGE.PACKAGE_ID.eq(packageId)), SysTenantPackageVo.class);
+    }
+
+    /**
+     * 分页查询租户套餐
+     *
+     * @param sysTenantPackageBo 租户套餐Bo
+     * @return 租户套餐集合
+     */
+    @Override
+    public TableDataInfo<SysTenantPackageVo> selectPage(SysTenantPackageBo sysTenantPackageBo)
+    {
+        QueryWrapper queryWrapper = buildQueryWrapper(sysTenantPackageBo);
+        Page<SysTenantPackageVo> page = this.pageAs(PageQuery.build(), queryWrapper, SysTenantPackageVo.class);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 查询租户套餐下拉选列表
+     */
+    @Override
+    public List<SysTenantPackageVo> selectList() {
+        SysTenantPackageBo tenantPackageBo = new SysTenantPackageBo();
+        tenantPackageBo.setStatus(TenantConstants.NORMAL);
+        QueryWrapper queryWrapper = buildQueryWrapper(tenantPackageBo);
+        return this.listAs(queryWrapper, SysTenantPackageVo.class);
+    }
+
+    /**
+     * 查询租户套餐列表
+     */
+    @Override
+    public List<SysTenantPackageVo> queryList(SysTenantPackageBo sysTenantPackageBo) {
+        QueryWrapper queryWrapper = buildQueryWrapper(sysTenantPackageBo);
+        return this.listAs(queryWrapper, SysTenantPackageVo.class);
+    }
+
+    /**
+     * 新增租户套餐
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insert(SysTenantPackageBo sysTenantPackageBo) {
+        SysTenantPackage sysTenantPackage = MapstructUtils.convert(sysTenantPackageBo, SysTenantPackage.class);
+        if(ObjectUtil.isNull(sysTenantPackage)){
+            return true;
+        }
+        // 保存菜单id
+        List<Long> menuIds = Arrays.asList(sysTenantPackageBo.getMenuIds());
+        if (CollUtil.isNotEmpty(menuIds)) {
+            sysTenantPackage.setMenuIds(StringUtils.join(menuIds, ", "));
+        } else {
+            sysTenantPackage.setMenuIds("");
+        }
+
+        Long loginUserId = LoginHelper.getUserId();
+        Date createTime = new Date();
+        sysTenantPackage.setCreateBy(loginUserId);
+        sysTenantPackage.setCreateTime(createTime);
+        sysTenantPackage.setUpdateBy(loginUserId);
+        sysTenantPackage.setUpdateTime(createTime);
+
+        return this.save(sysTenantPackage);
+    }
+
+    /**
+     * 修改租户套餐
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(SysTenantPackageBo sysTenantPackageBo) {
+        SysTenantPackage sysTenantPackage = MapstructUtils.convert(sysTenantPackageBo, SysTenantPackage.class);
+        if(ObjectUtil.isNull(sysTenantPackage)){
+            return true;
+        }
+        // 保存菜单id
+        List<Long> menuIds = Arrays.asList(sysTenantPackageBo.getMenuIds());
+        if (CollUtil.isNotEmpty(menuIds)) {
+            sysTenantPackage.setMenuIds(StringUtils.join(menuIds, ", "));
+        } else {
+            sysTenantPackage.setMenuIds("");
+        }
+
+        Long loginUserId = LoginHelper.getUserId();
+        Date createTime = new Date();
+        sysTenantPackage.setUpdateBy(loginUserId);
+        sysTenantPackage.setUpdateTime(createTime);
+
+        return this.updateById(sysTenantPackage);
+    }
+
+    /**
+     * 修改套餐状态
+     *
+     * @param sysTenantPackageBo 套餐信息
+     * @return 结果
+     */
+    @Override
+    public Boolean updatePackageStatus(SysTenantPackageBo sysTenantPackageBo) {
+        SysTenantPackage sysTenantPackage = UpdateEntity.of(SysTenantPackage.class, sysTenantPackageBo.getPackageId());
+
+        Long loginUserId = LoginHelper.getUserId();
+        Date createTime = new Date();
+        sysTenantPackage.setUpdateBy(loginUserId);
+        sysTenantPackage.setUpdateTime(createTime);
+
+        sysTenantPackage.setStatus(sysTenantPackageBo.getStatus());
+        return tenantPackageMapper.update(sysTenantPackage) > 0;
+    }
+
+    /**
+     * 批量删除租户套餐
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteByIds(Long[] packageIds, Boolean isValid) {
+        if(isValid){
+            boolean exists = tenantMapper.selectCountByQuery(query().where(SYS_TENANT.PACKAGE_ID.in(List.of(packageIds)))) >0;
+            if (exists) {
+                throw new ServiceException("租户套餐已被使用");
+            }
+        }
+        return this.removeByIds(Arrays.asList(packageIds));
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantServiceImpl.java
new file mode 100644
index 0000000..a2f992a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTenantServiceImpl.java
@@ -0,0 +1,455 @@
+package com.ruoyi.system.service.impl;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.mybatisflex.core.paginate.Page;
+import com.mybatisflex.core.query.QueryWrapper;
+import com.mybatisflex.core.util.UpdateEntity;
+import com.ruoyi.common.orm.core.service.impl.BaseServiceImpl;
+import com.ruoyi.common.security.utils.LoginHelper;
+import com.ruoyi.system.domain.vo.SysTenantPackageVo;
+import com.ruoyi.system.service.ISysRoleService;
+import com.ruoyi.system.service.ISysTenantPackageService;
+import jakarta.annotation.Resource;
+import lombok.RequiredArgsConstructor;
+import com.ruoyi.common.core.constant.CacheNames;
+import com.ruoyi.common.core.constant.Constants;
+import com.ruoyi.common.core.constant.TenantConstants;
+import com.ruoyi.common.core.exception.ServiceException;
+import com.ruoyi.common.core.utils.MapstructUtils;
+import com.ruoyi.common.core.utils.SpringUtils;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.orm.core.page.PageQuery;
+import com.ruoyi.common.orm.core.page.TableDataInfo;
+import com.ruoyi.common.tenant.helper.TenantHelper;
+import com.ruoyi.system.domain.*;
+import com.ruoyi.system.domain.bo.SysTenantBo;
+import com.ruoyi.system.domain.vo.SysTenantVo;
+import com.ruoyi.system.mapper.*;
+import com.ruoyi.system.service.ISysTenantService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import static com.ruoyi.system.domain.table.SysConfigTableDef.SYS_CONFIG;
+import static com.ruoyi.system.domain.table.SysDictDataTableDef.SYS_DICT_DATA;
+import static com.ruoyi.system.domain.table.SysDictTypeTableDef.SYS_DICT_TYPE;
+import static com.ruoyi.system.domain.table.SysOssConfigTableDef.SYS_OSS_CONFIG;
+import static com.ruoyi.system.domain.table.SysRoleMenuTableDef.SYS_ROLE_MENU;
+import static com.ruoyi.system.domain.table.SysRoleTableDef.SYS_ROLE;
+import static com.ruoyi.system.domain.table.SysTenantTableDef.SYS_TENANT;
+import static com.ruoyi.system.domain.table.SysUserTableDef.SYS_USER;
+
+/**
+ * 租户Service业务层处理
+ *
+ * @author Michelle.Chung
+ * author 数据小王子
+ */
+@RequiredArgsConstructor
+@Service
+public class SysTenantServiceImpl extends BaseServiceImpl<SysTenantMapper, SysTenant> implements ISysTenantService {
+
+    @Resource
+    private SysTenantMapper tenantMapper;
+    @Resource
+    private SysTenantPackageMapper tenantPackageMapper;
+    @Resource
+    private ISysTenantPackageService tenantPackageService;
+    @Resource
+    private SysUserMapper userMapper;
+    @Resource
+    private SysDeptMapper deptMapper;
+    @Resource
+    private SysRoleMapper roleMapper;
+    @Resource
+    private ISysRoleService roleService;
+    @Resource
+    private SysRoleMenuMapper roleMenuMapper;
+    @Resource
+    private SysRoleDeptMapper roleDeptMapper;
+    @Resource
+    private SysUserRoleMapper userRoleMapper;
+    @Resource
+    private SysDictTypeMapper dictTypeMapper;
+    @Resource
+    private SysDictDataMapper dictDataMapper;
+    @Resource
+    private SysConfigMapper configMapper;
+    @Resource
+    private SysOssConfigMapper ossConfigMapper;
+
+    public QueryWrapper query() {
+        return super.query().from(SYS_TENANT);
+    }
+
+    private QueryWrapper buildQueryWrapper(SysTenantBo sysTenantBo) {
+        return super.buildBaseQueryWrapper()
+            .and(SYS_TENANT.CONTACT_USER_NAME.like(sysTenantBo.getContactUserName()))
+            .and(SYS_TENANT.CONTACT_PHONE.eq(sysTenantBo.getContactPhone()))
+            .and(SYS_TENANT.COMPANY_NAME.like(sysTenantBo.getCompanyName()))
+            .and(SYS_TENANT.LICENSE_NUMBER.eq(sysTenantBo.getLicenseNumber()))
+            .and(SYS_TENANT.ADDRESS.eq(sysTenantBo.getAddress()))
+            .and(SYS_TENANT.INTRO.eq(sysTenantBo.getIntro()))
+            .and(SYS_TENANT.DOMAIN.like(sysTenantBo.getDomain()))
+            .and(SYS_TENANT.PACKAGE_ID.eq(sysTenantBo.getPackageId()))
+            .and(SYS_TENANT.EXPIRE_TIME.eq(sysTenantBo.getExpireTime()))
+            .and(SYS_TENANT.ACCOUNT_COUNT.eq(sysTenantBo.getAccountCount()))
+            .and(SYS_TENANT.STATUS.eq(sysTenantBo.getStatus()))
+            .orderBy(SYS_TENANT.TENANT_ID.desc());
+    }
+
+    /**
+     * 分页查询租户列表
+     *
+     * @param sysTenantBo 租户Bo
+     * @return 租户列表集合
+     */
+    public TableDataInfo<SysTenantVo> selectPage(SysTenantBo sysTenantBo) {
+        return TenantHelper.ignore(() -> {
+            QueryWrapper queryWrapper = buildQueryWrapper(sysTenantBo);
+            Page<SysTenantVo> page = this.pageAs(PageQuery.build(), queryWrapper, SysTenantVo.class);
+            return TableDataInfo.build(page);
+        });
+    }
+
+    /**
+     * 查询租户列表
+     */
+    @Override
+    public List<SysTenantVo> selectList(SysTenantBo sysTenantBo) {
+        return TenantHelper.ignore(() -> {
+            QueryWrapper queryWrapper = buildQueryWrapper(sysTenantBo);
+            return this.listAs(queryWrapper, SysTenantVo.class);
+        });
+    }
+
+    /**
+     * 基于租户ID查询租户
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId")
+    @Override
+    public SysTenantVo selectById(Long tenantId) {
+        return TenantHelper.ignore(() -> this.getOneAs(query().where(SYS_TENANT.TENANT_ID.eq(tenantId)), SysTenantVo.class));
+    }
+
+    /**
+     * 新增租户
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean insert(SysTenantBo sysTenantBo) {
+        return TenantHelper.ignore(() -> {
+            SysTenant sysTenant = MapstructUtils.convert(sysTenantBo, SysTenant.class);
+            if (ObjectUtil.isNull(sysTenant)) {
+                throw new ServiceException("新增租户参数为空");
+            }
+            Long loginUserId = LoginHelper.getUserId();
+            Date createTime = new Date();
+            sysTenant.setCreateBy(loginUserId);
+            sysTenant.setCreateTime(createTime);
+            sysTenant.setUpdateBy(loginUserId);
+            sysTenant.setUpdateTime(createTime);
+            boolean inserted = this.save(sysTenant);
+            if (!inserted) {
+                throw new ServiceException("新增租户失败");
+            }
+            Long tenantId = sysTenant.getTenantId();
+
+
+            // 根据套餐创建角色
+            Long roleId = createTenantRole(tenantId, sysTenantBo.getPackageId());
+
+            // 创建部门: 公司名是部门名称
+            SysDept dept = new SysDept();
+            dept.setTenantId(tenantId);
+            dept.setDeptName(sysTenantBo.getCompanyName());
+            dept.setParentId(Constants.TOP_PARENT_ID);
+            dept.setAncestors(Constants.TOP_PARENT_ID.toString());
+            dept.setDelFlag(0);//0 代表存在
+            int insertedDeptRows = deptMapper.insert(dept, true);
+            if (insertedDeptRows != 1) {
+                throw new ServiceException("新增租户的部门记录失败");
+            }
+            Long deptId = dept.getDeptId();
+
+            // 角色和部门关联表
+            SysRoleDept roleDept = new SysRoleDept();
+            roleDept.setRoleId(roleId);
+            roleDept.setDeptId(deptId);
+            int insertedRoleDept = roleDeptMapper.insertWithPk(roleDept);
+            if (insertedRoleDept != 1) {
+                throw new ServiceException("新增租户的角色部门记录失败");
+            }
+
+            // 新增系统用户
+            SysUser user = new SysUser();
+            user.setTenantId(tenantId);
+            user.setUserName(sysTenantBo.getUsername());
+            user.setNickName(sysTenantBo.getUsername());
+            user.setPassword(BCrypt.hashpw(sysTenantBo.getPassword()));
+            user.setDeptId(deptId);
+            user.setDelFlag(0);
+            user.setStatus("0");
+            user.setUserType("sys_user");//sys_user是系统用户
+            int insertedUser = userMapper.insert(user, true);
+            if (insertedUser != 1) {
+                throw new ServiceException("新增租户的用户记录失败");
+            }
+
+            // 用户和角色关联表
+            SysUserRole userRole = new SysUserRole();
+            userRole.setUserId(user.getUserId());
+            userRole.setRoleId(roleId);
+            int insertedUserRole = userRoleMapper.insertWithPk(userRole);
+            if (insertedUserRole != 1) {
+                throw new ServiceException("新增租户的用户角色记录失败");
+            }
+
+            // 增加字典记录
+            Long defaultTenantId = TenantConstants.DEFAULT_TENANT_ID;
+            List<SysDictType> dictTypeList = dictTypeMapper.selectListByQuery(QueryWrapper.create().from(SYS_DICT_TYPE)
+                .where(SYS_DICT_TYPE.TENANT_ID.eq(defaultTenantId)));
+            List<SysDictData> dictDataList = dictDataMapper.selectListByQuery(
+                QueryWrapper.create().from(SYS_DICT_DATA)
+                    .where(SYS_DICT_DATA.TENANT_ID.eq(defaultTenantId)));
+            for (SysDictType dictType : dictTypeList) {
+                dictType.setDictId(null);
+                dictType.setTenantId(tenantId);
+            }
+            for (SysDictData dictData : dictDataList) {
+                dictData.setDictCode(null);
+                dictData.setTenantId(tenantId);
+            }
+            dictTypeMapper.insertBatch(dictTypeList);
+            dictDataMapper.insertBatch(dictDataList);
+
+            // 增加参数配置记录
+            List<SysConfig> sysConfigList = configMapper.selectListByQuery(
+                QueryWrapper.create().from(SYS_CONFIG).where(SYS_CONFIG.TENANT_ID.eq(defaultTenantId)));
+            for (SysConfig config : sysConfigList) {
+                config.setConfigId(null);
+                config.setTenantId(tenantId);
+            }
+            configMapper.insertBatch(sysConfigList);
+
+            //增加SysOssConfig记录
+            List<SysOssConfig> sysOssConfigList = ossConfigMapper.selectListByQuery(
+                QueryWrapper.create().from(SYS_OSS_CONFIG).where(SYS_OSS_CONFIG.TENANT_ID.eq(defaultTenantId)));
+            for (SysOssConfig ossConfig : sysOssConfigList) {
+                ossConfig.setOssConfigId(null);
+                ossConfig.setTenantId(tenantId);
+            }
+            ossConfigMapper.insertBatch(sysOssConfigList);
+
+            return true;
+        });
+
+    }
+
+    /**
+     * 根据租户菜单创建租户角色
+     *
+     * @param tenantId  租户编号
+     * @param packageId 租户套餐id
+     * @return 角色id
+     */
+    private Long createTenantRole(Long tenantId, Long packageId) {
+        // 获取租户套餐
+        SysTenantPackageVo tenantPackageVo = tenantPackageService.selectById(packageId);
+        if (ObjectUtil.isNull(tenantPackageVo)) {
+            throw new ServiceException("套餐不存在");
+        }
+        // 获取套餐菜单id
+        List<Long> menuIds = StringUtils.splitTo(tenantPackageVo.getMenuIds(), Convert::toLong);
+
+        // 创建角色
+        SysRole role = new SysRole();
+        role.setTenantId(tenantId);
+        role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME);
+        role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY);
+        role.setRoleSort(1);
+        role.setStatus(TenantConstants.NORMAL);
+        role.setDelFlag(0);
+        role.setDataScope("1");//默认1:全部数据权限
+        int insertedRows = roleMapper.insert(role, true);
+        if (insertedRows != 1) {
+            throw new ServiceException("添加租户管理员角色记录失败!");
+        }
+        Long roleId = role.getRoleId();
+        role.setMenuIds(menuIds.toArray(new Long[menuIds.size()]));
+        //新增角色菜单记录
+        boolean insertedRoleMenu = roleService.insertRoleMenu(role);
+        if (!insertedRoleMenu) {
+            throw new ServiceException("添加租户管理员的角色菜单记录失败!");
+        }
+
+        return roleId;
+    }
+
+    /**
+     * 修改租户
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#sysTenantBo.tenantId")
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean update(SysTenantBo sysTenantBo) {
+        return TenantHelper.ignore(() -> {
+            SysTenant tenant = MapstructUtils.convert(sysTenantBo, SysTenant.class);
+            if (ObjectUtil.isNull(tenant)) {
+                throw new ServiceException("租户的参数为空!");
+            }
+
+            //如果更换了套餐,则需要同步套餐sys_role_menu表
+            SysTenantVo oldTenantVo = selectById(tenant.getTenantId());
+            if (!oldTenantVo.getPackageId().equals(tenant.getPackageId())) {
+                boolean synced = syncTenantPackage(tenant.getTenantId(), tenant.getPackageId());
+                if (!synced) {
+                    throw new ServiceException("同步套餐失败!");
+                }
+            }
+
+            Long loginUserId = LoginHelper.getUserId();
+            Date createTime = new Date();
+            tenant.setUpdateBy(loginUserId);
+            tenant.setUpdateTime(createTime);
+
+            return tenantMapper.update(tenant) > 0;
+        });
+    }
+
+    /**
+     * 修改租户状态
+     *
+     * @param sysTenantBo 租户信息
+     * @return 结果
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#sysTenantBo.tenantId")
+    @Override
+    public boolean updateTenantStatus(SysTenantBo sysTenantBo) {
+        return TenantHelper.ignore(() -> {
+            SysTenant sysTenant = UpdateEntity.of(SysTenant.class, sysTenantBo.getTenantId());
+
+            Long loginUserId = LoginHelper.getUserId();
+            Date createTime = new Date();
+            sysTenant.setUpdateBy(loginUserId);
+            sysTenant.setUpdateTime(createTime);
+
+            sysTenant.setStatus(sysTenantBo.getStatus());
+
+            return tenantMapper.update(sysTenant) > 0;
+        });
+    }
+
+    /**
+     * 校验租户是否允许操作
+     *
+     * @param tenantId 租户ID
+     */
+    @Override
+    public void checkTenantAllowed(Long tenantId) {
+        if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
+            throw new ServiceException("不允许操作超级管理员租户");
+        }
+    }
+
+    /**
+     * 批量删除租户
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true)
+    @Override
+    public boolean deleteByIds(Collection<Long> tenantIds, Boolean isValid) {
+        if (isValid) {
+            // 做一些业务上的校验,判断是否需要校验
+            if (tenantIds.contains(TenantConstants.SUPER_ADMIN_ID)) {
+                throw new ServiceException("超级管理员租户不能删除");
+            }
+        }
+        return TenantHelper.ignore(() -> this.removeByIds(tenantIds));//逻辑删除
+    }
+
+    /**
+     * 校验企业名称是否唯一
+     */
+    @Override
+    public boolean checkCompanyNameUnique(SysTenantBo sysTenantBo) {
+        return TenantHelper.ignore(() -> tenantMapper.selectCountByQuery(
+            query().where(SYS_TENANT.COMPANY_NAME.eq(sysTenantBo.getCompanyName())))) == 0;
+    }
+
+    /**
+     * 校验账号余额
+     */
+    @Override
+    public boolean checkAccountBalance(Long tenantId) {
+        SysTenantVo tenant = SpringUtils.getAopProxy(this).selectById(tenantId);
+        // 如果余额为-1则代表不限制
+        if (tenant.getAccountCount() == -1) {
+            return true;
+        }
+        Long userNumber = TenantHelper.ignore(() -> userMapper.selectCountByQuery(QueryWrapper.create().from(SYS_USER).where(SYS_USER.TENANT_ID.eq(tenantId))));
+        // 如果余额大于0则代表还有可用名额
+        return tenant.getAccountCount() - userNumber > 0;
+    }
+
+    /**
+     * 校验有效期
+     */
+    @Override
+    public boolean checkExpireTime(Long tenantId) {
+        SysTenantVo tenant = SpringUtils.getAopProxy(this).selectById(tenantId);
+        // 如果未设置过期时间代表不限制
+        if (ObjectUtil.isNull(tenant.getExpireTime())) {
+            return true;
+        }
+        // 如果当前时间在过期时间之前则通过
+        return new Date().before(tenant.getExpireTime());
+    }
+
+    /**
+     * 同步租户套餐
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean syncTenantPackage(Long tenantId, Long packageId) {
+        return TenantHelper.ignore(() -> {
+                SysTenantPackage tenantPackage = tenantPackageMapper.selectOneById(packageId);
+                List<SysRole> roles = TenantHelper.ignore(() -> roleMapper.selectListByQuery(
+                    QueryWrapper.create().from(SYS_ROLE).where(SYS_ROLE.TENANT_ID.eq(tenantId))));
+                List<Long> roleIds = new ArrayList<>(roles.size() - 1);
+                List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
+                roles.forEach(role -> {
+                    if (TenantConstants.TENANT_ADMIN_ROLE_KEY.equals(role.getRoleKey())) {
+                        int deletedRoleMenu = roleMenuMapper.deleteByQuery(QueryWrapper.create().from(SYS_ROLE_MENU).where(SYS_ROLE_MENU.ROLE_ID.eq(role.getRoleId())));
+                        if (deletedRoleMenu == 0) {
+                            throw new ServiceException("删除租户的角色菜单记录失败!");
+                        }
+
+                        role.setMenuIds(menuIds.toArray(new Long[menuIds.size()]));
+                        boolean insertedRoleMenu = roleService.insertRoleMenu(role);
+                        if (!insertedRoleMenu) {
+                            throw new ServiceException("添加租户管理员的角色菜单记录失败!");
+                        }
+                    } else {
+                        roleIds.add(role.getRoleId());
+                    }
+                });
+                if (!roleIds.isEmpty()) {
+                    int deletedRows = roleMenuMapper.deleteByQuery(
+                        QueryWrapper.create().from(SYS_ROLE_MENU).where(SYS_ROLE_MENU.ROLE_ID.in(roleIds)).and(SYS_ROLE_MENU.MENU_ID.notIn(menuIds)));
+                    if (deletedRows == 0) {
+                        throw new ServiceException("删除租户的无用角色菜单记录失败!");
+                    }
+                }
+                return true;
+            }
+        );
+    }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml
new file mode 100644
index 0000000..23b46df
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysTenantPackageMapper">
+
+</mapper>