feat: 租户套餐枚举优化与学校端课程查询实现
- 新增 TenantPackageStatus 枚举类,消除 status 字段魔法值 - 修改 TenantPackage 实体 status 字段类型为枚举 - 更新 CoursePackageService、TenantServiceImpl、CourseLessonService 使用枚举 - 实现学校端课程查询接口 /api/v1/school/courses - 新增 CourseService.getTenantPackageCourses() 方法查询租户套餐下的课程 - 前端新增 Course 类型定义 共修改 26 个文件,新增 609 行,删除 83 行
This commit is contained in:
parent
dfbf89e8fe
commit
bb7fb86c3b
@ -71,6 +71,7 @@ export interface CreateTenantDto {
|
||||
contactPerson?: string;
|
||||
contactPhone?: string;
|
||||
packageType?: string;
|
||||
packageId?: number;
|
||||
teacherQuota?: number;
|
||||
studentQuota?: number;
|
||||
startDate?: string;
|
||||
@ -129,6 +130,21 @@ export interface PopularCourse {
|
||||
teacherCount: number;
|
||||
}
|
||||
|
||||
export interface CoursePackage {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
price: number;
|
||||
discountPrice?: number;
|
||||
discountType?: string;
|
||||
gradeLevels?: string[];
|
||||
courseCount: number;
|
||||
status: string;
|
||||
publishedAt?: string;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
export interface AdminSettings {
|
||||
// Basic settings
|
||||
systemName?: string;
|
||||
@ -207,6 +223,11 @@ export const getActiveTenants = (limit?: number) =>
|
||||
export const getPopularCourses = (limit?: number) =>
|
||||
http.get<PopularCourse[]>('/v1/admin/stats/courses/popular', { params: { limit } });
|
||||
|
||||
// ==================== 课程套餐 ====================
|
||||
|
||||
export const getPublishedPackages = () =>
|
||||
http.get<CoursePackage[]>('/v1/admin/packages/all');
|
||||
|
||||
// ==================== 系统设置 ====================
|
||||
|
||||
export const getAdminSettings = () =>
|
||||
|
||||
@ -334,11 +334,34 @@ export const updateSettings = (data: UpdateSettingsDto) =>
|
||||
|
||||
// ==================== 课程管理 ====================
|
||||
|
||||
export interface Course {
|
||||
id: number;
|
||||
tenantId?: number;
|
||||
name: string;
|
||||
code?: string;
|
||||
description?: string;
|
||||
coverUrl?: string;
|
||||
coverImagePath?: string;
|
||||
category?: string;
|
||||
ageRange?: string;
|
||||
difficultyLevel?: string;
|
||||
durationMinutes?: number;
|
||||
objectives?: string;
|
||||
status: string;
|
||||
isSystem: number;
|
||||
version?: string;
|
||||
usageCount?: number;
|
||||
teacherCount?: number;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
publishedAt?: string;
|
||||
}
|
||||
|
||||
export const getSchoolCourses = () =>
|
||||
http.get<any[]>('/v1/school/courses');
|
||||
http.get<Course[]>('/v1/school/courses');
|
||||
|
||||
export const getSchoolCourse = (id: number) =>
|
||||
http.get<any>(`/v1/school/courses/${id}`);
|
||||
http.get<Course>(`/v1/school/courses/${id}`);
|
||||
|
||||
// ==================== 班级教师管理 ====================
|
||||
|
||||
|
||||
@ -34,6 +34,9 @@ declare module 'vue' {
|
||||
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
|
||||
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
|
||||
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
|
||||
AList: typeof import('ant-design-vue/es')['List']
|
||||
AListItem: typeof import('ant-design-vue/es')['ListItem']
|
||||
AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
|
||||
AMenu: typeof import('ant-design-vue/es')['Menu']
|
||||
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
|
||||
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||
@ -48,6 +51,7 @@ declare module 'vue' {
|
||||
ARate: typeof import('ant-design-vue/es')['Rate']
|
||||
ARow: typeof import('ant-design-vue/es')['Row']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup']
|
||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
|
||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||
@ -55,6 +59,8 @@ declare module 'vue' {
|
||||
AStatistic: typeof import('ant-design-vue/es')['Statistic']
|
||||
AStep: typeof import('ant-design-vue/es')['Step']
|
||||
ASteps: typeof import('ant-design-vue/es')['Steps']
|
||||
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
|
||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||
ATable: typeof import('ant-design-vue/es')['Table']
|
||||
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
||||
ATabs: typeof import('ant-design-vue/es')['Tabs']
|
||||
@ -62,6 +68,8 @@ declare module 'vue' {
|
||||
ATextarea: typeof import('ant-design-vue/es')['Textarea']
|
||||
ATimeRangePicker: typeof import('ant-design-vue/es')['TimeRangePicker']
|
||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
|
||||
AUpload: typeof import('ant-design-vue/es')['Upload']
|
||||
FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default']
|
||||
FileUploader: typeof import('./components/course/FileUploader.vue')['default']
|
||||
LessonConfigPanel: typeof import('./components/course/LessonConfigPanel.vue')['default']
|
||||
|
||||
@ -170,11 +170,15 @@
|
||||
<a-input v-model:value="formData.address" placeholder="请输入学校地址" />
|
||||
</a-form-item>
|
||||
<a-form-item label="套餐类型" name="packageType">
|
||||
<a-select v-model:value="formData.packageType">
|
||||
<a-select-option value="BASIC">基础版</a-select-option>
|
||||
<a-select-option value="STANDARD">标准版</a-select-option>
|
||||
<a-select-option value="ADVANCED">高级版</a-select-option>
|
||||
<a-select-option value="CUSTOM">定制版</a-select-option>
|
||||
<a-select v-model:value="formData.packageType" @change="handlePackageTypeChange">
|
||||
<a-select-option value="">请选择套餐</a-select-option>
|
||||
<a-select-option
|
||||
v-for="pkg in packageList"
|
||||
:key="pkg.id"
|
||||
:value="pkg.name"
|
||||
>
|
||||
{{ pkg.name }} ({{ formatPackagePrice(pkg.discountPrice || pkg.price) }}元)
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="教师配额" name="teacherQuota">
|
||||
@ -348,10 +352,12 @@ import {
|
||||
updateTenantStatus,
|
||||
resetTenantPassword,
|
||||
deleteTenant,
|
||||
getPublishedPackages,
|
||||
type Tenant,
|
||||
type TenantDetail,
|
||||
type CreateTenantDto,
|
||||
type UpdateTenantDto,
|
||||
type CoursePackage,
|
||||
} from '@/api/admin';
|
||||
|
||||
// 搜索表单
|
||||
@ -414,7 +420,8 @@ const formData = reactive<CreateTenantDto & { dateRange?: string[] }>({
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
address: '',
|
||||
packageType: 'STANDARD',
|
||||
packageType: '',
|
||||
packageId: undefined,
|
||||
teacherQuota: 20,
|
||||
studentQuota: 200,
|
||||
startDate: '',
|
||||
@ -444,6 +451,35 @@ const quotaForm = reactive({
|
||||
const drawerVisible = ref(false);
|
||||
const detailData = ref<TenantDetail | null>(null);
|
||||
|
||||
// 套餐列表
|
||||
const packageList = ref<CoursePackage[]>([]);
|
||||
|
||||
// 格式化价格(分转为元)
|
||||
const formatPackagePrice = (priceInCents: number) => {
|
||||
return (priceInCents / 100).toFixed(2);
|
||||
};
|
||||
|
||||
// 处理套餐类型变化,自动填充配额等信息
|
||||
const handlePackageTypeChange = (value: string) => {
|
||||
const selectedPackage = packageList.value.find(pkg => pkg.name === value);
|
||||
if (selectedPackage) {
|
||||
// 设置选中的套餐 ID
|
||||
formData.packageId = selectedPackage.id;
|
||||
|
||||
// 根据套餐自动设置配额(这里可以根据实际需求调整)
|
||||
if (selectedPackage.name.includes('基础')) {
|
||||
formData.teacherQuota = 10;
|
||||
formData.studentQuota = 100;
|
||||
} else if (selectedPackage.name.includes('标准')) {
|
||||
formData.teacherQuota = 20;
|
||||
formData.studentQuota = 200;
|
||||
} else if (selectedPackage.name.includes('高级')) {
|
||||
formData.teacherQuota = 50;
|
||||
formData.studentQuota = 500;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 加载数据
|
||||
const loadData = async () => {
|
||||
loading.value = true;
|
||||
@ -464,6 +500,16 @@ const loadData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载套餐列表
|
||||
const loadPackageList = async () => {
|
||||
try {
|
||||
const res = await getPublishedPackages();
|
||||
packageList.value = res;
|
||||
} catch (error) {
|
||||
console.error('加载套餐列表失败', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1;
|
||||
@ -497,7 +543,8 @@ const showAddModal = () => {
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
address: '',
|
||||
packageType: 'STANDARD',
|
||||
packageType: '',
|
||||
packageId: undefined,
|
||||
teacherQuota: 20,
|
||||
studentQuota: 200,
|
||||
});
|
||||
@ -695,6 +742,7 @@ const getStatusText = (status: string) => {
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
loadPackageList();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@ -34,6 +34,9 @@ public enum ErrorCode {
|
||||
TENANT_EXPIRED(3002, "Tenant has expired"),
|
||||
TENANT_DISABLED(3003, "Tenant is disabled"),
|
||||
|
||||
// Package Errors (3100+)
|
||||
PACKAGE_NOT_FOUND(3101, "Package not found"),
|
||||
|
||||
// User Errors (4000+)
|
||||
USER_NOT_FOUND(4001, "User not found"),
|
||||
USER_ALREADY_EXISTS(4002, "User already exists"),
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package com.reading.platform.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 租户套餐状态枚举
|
||||
*/
|
||||
@Getter
|
||||
public enum TenantPackageStatus {
|
||||
|
||||
ACTIVE("ACTIVE", "激活"),
|
||||
EXPIRED("EXPIRED", "已过期");
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
TenantPackageStatus(String code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 code 获取枚举
|
||||
*/
|
||||
public static TenantPackageStatus fromCode(String code) {
|
||||
for (TenantPackageStatus status : values()) {
|
||||
if (status.getCode().equals(code)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return ACTIVE;
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import com.reading.platform.common.enums.UserRole;
|
||||
import com.reading.platform.common.response.PageResult;
|
||||
import com.reading.platform.common.response.Result;
|
||||
import com.reading.platform.dto.request.CourseCreateRequest;
|
||||
import com.reading.platform.dto.request.CoursePageQueryRequest;
|
||||
import com.reading.platform.dto.request.CourseUpdateRequest;
|
||||
import com.reading.platform.dto.response.CourseResponse;
|
||||
import com.reading.platform.entity.Course;
|
||||
@ -17,18 +18,21 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Tag(name = "Admin - Course", description = "System Course Management APIs for Admin")
|
||||
/**
|
||||
* 课程管理控制器(超管端)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/admin/courses")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@RequireRole(UserRole.ADMIN)
|
||||
@Tag(name = "超管端 - 课程管理")
|
||||
public class AdminCourseController {
|
||||
|
||||
private final CourseService courseService;
|
||||
|
||||
@Operation(summary = "Create system course")
|
||||
@PostMapping
|
||||
@Operation(summary = "创建课程")
|
||||
public Result<Course> createCourse(@Valid @RequestBody CourseCreateRequest request) {
|
||||
log.info("收到课程创建请求,name={}, themeId={}, gradeTags={}", request.getName(), request.getThemeId(), request.getGradeTags());
|
||||
try {
|
||||
@ -41,51 +45,57 @@ public class AdminCourseController {
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "Update course")
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新课程")
|
||||
public Result<Course> updateCourse(@PathVariable Long id, @RequestBody CourseUpdateRequest request) {
|
||||
return Result.success(courseService.updateCourse(id, request));
|
||||
}
|
||||
|
||||
@Operation(summary = "Get course by ID")
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "查询课程详情")
|
||||
public Result<CourseResponse> getCourse(@PathVariable Long id) {
|
||||
return Result.success(courseService.getCourseByIdWithLessons(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "Get system course page")
|
||||
@GetMapping
|
||||
public Result<PageResult<Course>> getCoursePage(
|
||||
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(required = false, defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false) String category,
|
||||
@RequestParam(required = false) String status,
|
||||
@RequestParam(required = false, defaultValue = "false") Boolean reviewOnly) {
|
||||
@Operation(summary = "分页查询课程")
|
||||
public Result<PageResult<Course>> getCoursePage(CoursePageQueryRequest request) {
|
||||
log.info("查询课程列表,pageNum={}, pageSize={}, keyword={}, category={}, status={}, reviewOnly={}",
|
||||
pageNum, pageSize, keyword, category, status, reviewOnly);
|
||||
Page<Course> page = courseService.getSystemCoursePage(pageNum, pageSize, keyword, category, status, reviewOnly);
|
||||
request.getPageNum(), request.getPageSize(), request.getKeyword(), request.getCategory(), request.getStatus(), request.getReviewOnly());
|
||||
// 页码
|
||||
// 每页数量
|
||||
// 关键词
|
||||
// 分类
|
||||
// 状态
|
||||
// 是否仅查询待审核
|
||||
Page<Course> page = courseService.getSystemCoursePage(
|
||||
request.getPageNum(),
|
||||
request.getPageSize(),
|
||||
request.getKeyword(),
|
||||
request.getCategory(),
|
||||
request.getStatus(),
|
||||
request.getReviewOnly());
|
||||
PageResult<Course> result = PageResult.of(page);
|
||||
log.info("课程列表查询结果,total={}, list={}", result.getTotal(), result.getList().size());
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "Delete course")
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除课程")
|
||||
public Result<Void> deleteCourse(@PathVariable Long id) {
|
||||
courseService.deleteCourse(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "Publish course")
|
||||
@PostMapping("/{id}/publish")
|
||||
@Operation(summary = "发布课程")
|
||||
public Result<Void> publishCourse(@PathVariable Long id) {
|
||||
courseService.publishCourse(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "Archive course")
|
||||
@PostMapping("/{id}/archive")
|
||||
@Operation(summary = "归档课程")
|
||||
public Result<Void> archiveCourse(@PathVariable Long id) {
|
||||
courseService.archiveCourse(id);
|
||||
return Result.success();
|
||||
|
||||
@ -129,6 +129,12 @@ public class AdminPackageController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@GetMapping("/all")
|
||||
@Operation(summary = "查询所有已发布的套餐列表")
|
||||
public Result<List<CoursePackage>> getPublishedPackages() {
|
||||
return Result.success(packageService.findPublishedPackages());
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/grant")
|
||||
@Operation(summary = "授权套餐给租户")
|
||||
@RequireRole(UserRole.ADMIN)
|
||||
|
||||
@ -3,74 +3,84 @@ package com.reading.platform.controller.admin;
|
||||
import com.reading.platform.common.annotation.RequireRole;
|
||||
import com.reading.platform.common.enums.UserRole;
|
||||
import com.reading.platform.common.response.Result;
|
||||
import com.reading.platform.dto.request.ActiveTenantsQueryRequest;
|
||||
import com.reading.platform.dto.request.PopularCoursesQueryRequest;
|
||||
import com.reading.platform.dto.request.RecentActivitiesQueryRequest;
|
||||
import com.reading.platform.dto.response.ActiveTenantItemResponse;
|
||||
import com.reading.platform.dto.response.PopularCourseItemResponse;
|
||||
import com.reading.platform.dto.response.RecentActivityItemResponse;
|
||||
import com.reading.platform.dto.response.StatsResponse;
|
||||
import com.reading.platform.dto.response.StatsTrendResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 超管端 - 统计管理
|
||||
* 统计管理控制器(超管端)
|
||||
*/
|
||||
@Tag(name = "超管 - 统计管理", description = "Admin Stats APIs")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/admin/stats")
|
||||
@RequiredArgsConstructor
|
||||
@RequireRole(UserRole.ADMIN)
|
||||
@Tag(name = "超管端 - 统计管理")
|
||||
public class AdminStatsController {
|
||||
|
||||
@Operation(summary = "获取统计数据")
|
||||
@GetMapping
|
||||
public Result<Map<String, Object>> getStats() {
|
||||
@Operation(summary = "获取统计数据")
|
||||
public Result<StatsResponse> getStats() {
|
||||
// TODO: 实现统计数据查询
|
||||
Map<String, Object> stats = new HashMap<>();
|
||||
stats.put("totalTenants", 0);
|
||||
stats.put("activeTenants", 0);
|
||||
stats.put("totalTeachers", 0);
|
||||
stats.put("totalStudents", 0);
|
||||
stats.put("totalCourses", 0);
|
||||
stats.put("totalLessons", 0);
|
||||
return Result.success(stats);
|
||||
return Result.success(StatsResponse.builder()
|
||||
.totalTenants(0L)
|
||||
.activeTenants(0L)
|
||||
.totalTeachers(0L)
|
||||
.totalStudents(0L)
|
||||
.totalCourses(0L)
|
||||
.totalLessons(0L)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Operation(summary = "获取趋势数据")
|
||||
@GetMapping("/trend")
|
||||
public Result<Map<String, Object>> getTrendData() {
|
||||
@Operation(summary = "获取趋势数据")
|
||||
public Result<StatsTrendResponse> getTrendData() {
|
||||
// TODO: 实现趋势数据查询
|
||||
Map<String, Object> trend = new HashMap<>();
|
||||
trend.put("dates", new String[]{});
|
||||
trend.put("newStudents", new Integer[]{});
|
||||
trend.put("newTeachers", new Integer[]{});
|
||||
trend.put("newCourses", new Integer[]{});
|
||||
return Result.success(trend);
|
||||
return Result.success(StatsTrendResponse.builder()
|
||||
.dates(new ArrayList<>())
|
||||
.newStudents(new ArrayList<>())
|
||||
.newTeachers(new ArrayList<>())
|
||||
.newCourses(new ArrayList<>())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Operation(summary = "获取活跃租户")
|
||||
@GetMapping("/tenants/active")
|
||||
public Result<List<Map<String, Object>>> getActiveTenants(@RequestParam(required = false, defaultValue = "5") Integer limit) {
|
||||
@Operation(summary = "获取活跃租户")
|
||||
public Result<List<ActiveTenantItemResponse>> getActiveTenants(@ModelAttribute ActiveTenantsQueryRequest request) {
|
||||
// 返回数量限制
|
||||
// TODO: 实现活跃租户查询
|
||||
return Result.success(new ArrayList<>());
|
||||
}
|
||||
|
||||
@Operation(summary = "获取热门课程")
|
||||
@GetMapping("/courses/popular")
|
||||
public Result<List<Map<String, Object>>> getPopularCourses(@RequestParam(required = false, defaultValue = "5") Integer limit) {
|
||||
@Operation(summary = "获取热门课程")
|
||||
public Result<List<PopularCourseItemResponse>> getPopularCourses(@ModelAttribute PopularCoursesQueryRequest request) {
|
||||
// 返回数量限制
|
||||
// TODO: 实现热门课程查询
|
||||
return Result.success(new ArrayList<>());
|
||||
}
|
||||
|
||||
@Operation(summary = "获取最近活动")
|
||||
@GetMapping("/activities")
|
||||
public Result<List<Map<String, Object>>> getRecentActivities(@RequestParam(required = false, defaultValue = "10") Integer limit) {
|
||||
@Operation(summary = "获取最近活动")
|
||||
public Result<List<RecentActivityItemResponse>> getRecentActivities(@ModelAttribute RecentActivitiesQueryRequest request) {
|
||||
// 返回数量限制
|
||||
// TODO: 实现最近活动查询
|
||||
return Result.success(new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,39 +1,45 @@
|
||||
package com.reading.platform.controller.school;
|
||||
|
||||
import com.reading.platform.common.response.Result;
|
||||
import com.reading.platform.entity.Course;
|
||||
import com.reading.platform.service.CourseService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 课程管理控制器(学校端)
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/school/courses")
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "学校端 - 课程管理")
|
||||
public class SchoolCourseController {
|
||||
|
||||
private final CourseService courseService;
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "获取学校课程列表")
|
||||
public Result<List<Map<String, Object>>> getSchoolCourses() {
|
||||
List<Map<String, Object>> courses = new ArrayList<>();
|
||||
// For now, return empty list
|
||||
// TODO: Implement tenant course query
|
||||
public Result<List<Course>> getSchoolCourses() {
|
||||
log.info("获取学校课程列表");
|
||||
// TODO: 从 SecurityContext 获取当前登录用户所属租户 ID
|
||||
// 临时使用 tenantId = 1 作为测试
|
||||
Long tenantId = 1L;
|
||||
List<Course> courses = courseService.getTenantPackageCourses(tenantId);
|
||||
return Result.success(courses);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "获取课程详情")
|
||||
public Result<Map<String, Object>> getSchoolCourse(@PathVariable Long id) {
|
||||
Map<String, Object> course = new HashMap<>();
|
||||
// TODO: Implement course detail query
|
||||
public Result<Course> getSchoolCourse(@PathVariable Long id) {
|
||||
log.info("获取课程详情,id={}", id);
|
||||
Course course = courseService.getCourseById(id);
|
||||
return Result.success(course);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
package com.reading.platform.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 活跃租户查询请求
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "活跃租户查询请求")
|
||||
public class ActiveTenantsQueryRequest {
|
||||
|
||||
@Schema(description = "返回数量限制", example = "5")
|
||||
private Integer limit = 5;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.reading.platform.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 课程分页查询请求
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "课程分页查询请求")
|
||||
public class CoursePageQueryRequest {
|
||||
|
||||
@Schema(description = "页码", example = "1")
|
||||
private Integer pageNum = 1;
|
||||
|
||||
@Schema(description = "每页数量", example = "10")
|
||||
private Integer pageSize = 10;
|
||||
|
||||
@Schema(description = "关键词")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "分类")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "是否仅查询待审核", example = "false")
|
||||
private Boolean reviewOnly = false;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.reading.platform.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 热门课程查询请求
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "热门课程查询请求")
|
||||
public class PopularCoursesQueryRequest {
|
||||
|
||||
@Schema(description = "返回数量限制", example = "5")
|
||||
private Integer limit = 5;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.reading.platform.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 最近活动查询请求
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "最近活动查询请求")
|
||||
public class RecentActivitiesQueryRequest {
|
||||
|
||||
@Schema(description = "返回数量限制", example = "10")
|
||||
private Integer limit = 10;
|
||||
}
|
||||
@ -49,6 +49,9 @@ public class TenantCreateRequest {
|
||||
@Schema(description = "结束日期")
|
||||
private LocalDate expireDate;
|
||||
|
||||
@Schema(description = "课程套餐 ID(可选)")
|
||||
private Long packageId;
|
||||
|
||||
@Schema(description = "过期时间(兼容旧字段)")
|
||||
@Deprecated
|
||||
private LocalDateTime expireAt;
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package com.reading.platform.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* 活跃租户项响应
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "活跃租户项响应")
|
||||
public class ActiveTenantItemResponse {
|
||||
|
||||
@Schema(description = "租户 ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "租户名称")
|
||||
private String tenantName;
|
||||
|
||||
@Schema(description = "活跃用户数")
|
||||
private Integer activeUsers;
|
||||
|
||||
@Schema(description = "课程使用数")
|
||||
private Integer courseCount;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.reading.platform.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* 热门课程项响应
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "热门课程项响应")
|
||||
public class PopularCourseItemResponse {
|
||||
|
||||
@Schema(description = "课程 ID")
|
||||
private Long courseId;
|
||||
|
||||
@Schema(description = "课程名称")
|
||||
private String courseName;
|
||||
|
||||
@Schema(description = "使用次数")
|
||||
private Integer usageCount;
|
||||
|
||||
@Schema(description = "教师数量")
|
||||
private Integer teacherCount;
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.reading.platform.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 最近活动项响应
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "最近活动项响应")
|
||||
public class RecentActivityItemResponse {
|
||||
|
||||
@Schema(description = "活动 ID")
|
||||
private Long activityId;
|
||||
|
||||
@Schema(description = "活动类型")
|
||||
private String activityType;
|
||||
|
||||
@Schema(description = "活动描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "操作人 ID")
|
||||
private Long operatorId;
|
||||
|
||||
@Schema(description = "操作人名称")
|
||||
private String operatorName;
|
||||
|
||||
@Schema(description = "操作时间")
|
||||
private LocalDateTime operationTime;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.reading.platform.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* 统计数据响应
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "统计数据响应")
|
||||
public class StatsResponse {
|
||||
|
||||
@Schema(description = "租户总数")
|
||||
private Long totalTenants;
|
||||
|
||||
@Schema(description = "活跃租户数")
|
||||
private Long activeTenants;
|
||||
|
||||
@Schema(description = "教师总数")
|
||||
private Long totalTeachers;
|
||||
|
||||
@Schema(description = "学生总数")
|
||||
private Long totalStudents;
|
||||
|
||||
@Schema(description = "课程总数")
|
||||
private Long totalCourses;
|
||||
|
||||
@Schema(description = "课时总数")
|
||||
private Long totalLessons;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.reading.platform.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 趋势数据响应
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "趋势数据响应")
|
||||
public class StatsTrendResponse {
|
||||
|
||||
@Schema(description = "日期列表")
|
||||
private List<String> dates;
|
||||
|
||||
@Schema(description = "新增学生数列表")
|
||||
private List<Integer> newStudents;
|
||||
|
||||
@Schema(description = "新增教师数列表")
|
||||
private List<Integer> newTeachers;
|
||||
|
||||
@Schema(description = "新增课程数列表")
|
||||
private List<Integer> newCourses;
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.reading.platform.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.reading.platform.common.enums.TenantPackageStatus;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -32,6 +33,6 @@ public class TenantPackage extends BaseEntity {
|
||||
private Long pricePaid;
|
||||
|
||||
@Schema(description = "状态:ACTIVE、EXPIRED")
|
||||
private String status;
|
||||
private TenantPackageStatus status;
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.reading.platform.service;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.reading.platform.common.enums.TenantPackageStatus;
|
||||
import com.reading.platform.common.exception.BusinessException;
|
||||
import com.reading.platform.entity.*;
|
||||
import com.reading.platform.mapper.*;
|
||||
@ -399,7 +400,7 @@ public class CourseLessonService extends ServiceImpl<CourseLessonMapper, CourseL
|
||||
Long count = tenantPackageMapper.selectCount(
|
||||
new LambdaQueryWrapper<TenantPackage>()
|
||||
.eq(TenantPackage::getTenantId, tenantId)
|
||||
.eq(TenantPackage::getStatus, "ACTIVE")
|
||||
.eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
|
||||
);
|
||||
|
||||
if (count == 0) {
|
||||
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.reading.platform.common.enums.CourseStatus;
|
||||
import com.reading.platform.common.enums.TenantPackageStatus;
|
||||
import com.reading.platform.common.exception.BusinessException;
|
||||
import com.reading.platform.common.response.PageResult;
|
||||
import com.reading.platform.dto.response.CoursePackageResponse;
|
||||
@ -111,7 +112,7 @@ public class CoursePackageService extends ServiceImpl<CoursePackageMapper, Cours
|
||||
Long tenantCount = tenantPackageMapper.selectCount(
|
||||
new LambdaQueryWrapper<TenantPackage>()
|
||||
.eq(TenantPackage::getPackageId, pkg.getId())
|
||||
.eq(TenantPackage::getStatus, "ACTIVE")
|
||||
.eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
|
||||
);
|
||||
response.setTenantCount(tenantCount.intValue());
|
||||
|
||||
@ -229,7 +230,7 @@ public class CoursePackageService extends ServiceImpl<CoursePackageMapper, Cours
|
||||
Long tenantCount = tenantPackageMapper.selectCount(
|
||||
new LambdaQueryWrapper<TenantPackage>()
|
||||
.eq(TenantPackage::getPackageId, id)
|
||||
.eq(TenantPackage::getStatus, "ACTIVE")
|
||||
.eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
|
||||
);
|
||||
|
||||
if (tenantCount > 0) {
|
||||
@ -371,7 +372,7 @@ public class CoursePackageService extends ServiceImpl<CoursePackageMapper, Cours
|
||||
List<TenantPackage> tenantPackages = tenantPackageMapper.selectList(
|
||||
new LambdaQueryWrapper<TenantPackage>()
|
||||
.eq(TenantPackage::getTenantId, tenantId)
|
||||
.eq(TenantPackage::getStatus, "ACTIVE")
|
||||
.eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
|
||||
.orderByDesc(TenantPackage::getCreatedAt)
|
||||
);
|
||||
|
||||
@ -409,7 +410,7 @@ public class CoursePackageService extends ServiceImpl<CoursePackageMapper, Cours
|
||||
|
||||
if (existing != null) {
|
||||
existing.setEndDate(endDate);
|
||||
existing.setStatus("ACTIVE");
|
||||
existing.setStatus(TenantPackageStatus.ACTIVE);
|
||||
if (pricePaid != null) {
|
||||
existing.setPricePaid(pricePaid);
|
||||
}
|
||||
@ -422,11 +423,25 @@ public class CoursePackageService extends ServiceImpl<CoursePackageMapper, Cours
|
||||
tp.setPackageId(packageId);
|
||||
tp.setStartDate(LocalDate.now());
|
||||
tp.setEndDate(endDate);
|
||||
tp.setStatus("ACTIVE");
|
||||
tp.setStatus(TenantPackageStatus.ACTIVE);
|
||||
tp.setPricePaid(pricePaid != null ? pricePaid : 0L);
|
||||
tp.setCreatedAt(LocalDateTime.now());
|
||||
tenantPackageMapper.insert(tp);
|
||||
log.info("租户套餐新办成功,tenantId={}, packageId={}", tenantId, packageId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有已发布的套餐列表
|
||||
*/
|
||||
public List<CoursePackage> findPublishedPackages() {
|
||||
log.info("查询所有已发布的套餐列表");
|
||||
LambdaQueryWrapper<CoursePackage> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CoursePackage::getStatus, CourseStatus.PUBLISHED.getCode())
|
||||
.orderByDesc(CoursePackage::getCreatedAt);
|
||||
|
||||
List<CoursePackage> packages = packageMapper.selectList(wrapper);
|
||||
log.info("查询所有已发布的套餐列表成功,count={}", packages.size());
|
||||
return packages;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,4 +43,9 @@ public interface CourseService extends com.baomidou.mybatisplus.extension.servic
|
||||
|
||||
List<Course> getCoursesByTenantId(Long tenantId);
|
||||
|
||||
/**
|
||||
* 查询租户套餐下的课程
|
||||
*/
|
||||
List<Course> getTenantPackageCourses(Long tenantId);
|
||||
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.reading.platform.common.enums.CourseStatus;
|
||||
import com.reading.platform.common.enums.ErrorCode;
|
||||
import com.reading.platform.common.enums.TenantPackageStatus;
|
||||
import com.reading.platform.common.exception.BusinessException;
|
||||
import com.reading.platform.dto.request.CourseCreateRequest;
|
||||
import com.reading.platform.dto.request.CourseUpdateRequest;
|
||||
@ -13,8 +14,12 @@ import com.reading.platform.dto.response.CourseResponse;
|
||||
import com.reading.platform.dto.response.LessonStepResponse;
|
||||
import com.reading.platform.entity.Course;
|
||||
import com.reading.platform.entity.CourseLesson;
|
||||
import com.reading.platform.entity.CoursePackageCourse;
|
||||
import com.reading.platform.entity.LessonStep;
|
||||
import com.reading.platform.entity.TenantPackage;
|
||||
import com.reading.platform.mapper.CourseMapper;
|
||||
import com.reading.platform.mapper.CoursePackageCourseMapper;
|
||||
import com.reading.platform.mapper.TenantPackageMapper;
|
||||
import com.reading.platform.service.CourseLessonService;
|
||||
import com.reading.platform.service.CourseService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -36,6 +41,8 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
||||
|
||||
private final CourseMapper courseMapper;
|
||||
private final CourseLessonService courseLessonService;
|
||||
private final TenantPackageMapper tenantPackageMapper;
|
||||
private final CoursePackageCourseMapper packageCourseMapper;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@ -453,6 +460,51 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Course> getTenantPackageCourses(Long tenantId) {
|
||||
log.info("查询租户套餐下的课程,tenantId={}", tenantId);
|
||||
|
||||
// 1. 查询租户的套餐关联
|
||||
List<TenantPackage> tenantPackages = tenantPackageMapper.selectList(
|
||||
new LambdaQueryWrapper<TenantPackage>()
|
||||
.eq(TenantPackage::getTenantId, tenantId)
|
||||
.eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
|
||||
);
|
||||
|
||||
if (tenantPackages.isEmpty()) {
|
||||
log.info("租户套餐下的课程查询结果为空,tenantId={}", tenantId);
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// 2. 获取套餐 ID 列表
|
||||
List<Long> packageIds = tenantPackages.stream()
|
||||
.map(TenantPackage::getPackageId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 3. 查询套餐包含的课程 ID
|
||||
List<CoursePackageCourse> packageCourses = packageCourseMapper.selectList(
|
||||
new LambdaQueryWrapper<CoursePackageCourse>()
|
||||
.in(CoursePackageCourse::getPackageId, packageIds)
|
||||
);
|
||||
|
||||
if (packageCourses.isEmpty()) {
|
||||
log.info("租户套餐下没有关联的课程,tenantId={}", tenantId);
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// 4. 获取课程 ID 列表
|
||||
List<Long> courseIds = packageCourses.stream()
|
||||
.map(CoursePackageCourse::getCourseId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 5. 查询课程详情
|
||||
List<Course> courses = courseMapper.selectBatchIds(courseIds);
|
||||
|
||||
log.info("查询租户套餐下的课程成功,tenantId={}, count={}", tenantId, courses.size());
|
||||
return courses;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将空字符串转为 null,避免 MySQL JSON 列报错(空串不是有效 JSON)
|
||||
*/
|
||||
|
||||
@ -3,11 +3,16 @@ package com.reading.platform.service.impl;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.reading.platform.common.enums.ErrorCode;
|
||||
import com.reading.platform.common.enums.TenantPackageStatus;
|
||||
import com.reading.platform.common.exception.BusinessException;
|
||||
import com.reading.platform.dto.request.TenantCreateRequest;
|
||||
import com.reading.platform.dto.request.TenantUpdateRequest;
|
||||
import com.reading.platform.entity.CoursePackage;
|
||||
import com.reading.platform.entity.Tenant;
|
||||
import com.reading.platform.entity.TenantPackage;
|
||||
import com.reading.platform.mapper.TenantMapper;
|
||||
import com.reading.platform.mapper.TenantPackageMapper;
|
||||
import com.reading.platform.service.CoursePackageService;
|
||||
import com.reading.platform.service.TenantService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -15,6 +20,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -27,6 +33,8 @@ public class TenantServiceImpl extends com.baomidou.mybatisplus.extension.servic
|
||||
implements TenantService {
|
||||
|
||||
private final TenantMapper tenantMapper;
|
||||
private final TenantPackageMapper tenantPackageMapper;
|
||||
private final CoursePackageService coursePackageService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@ -52,14 +60,7 @@ public class TenantServiceImpl extends com.baomidou.mybatisplus.extension.servic
|
||||
tenant.setAddress(request.getAddress());
|
||||
tenant.setLogoUrl(request.getLogoUrl());
|
||||
|
||||
// 使用新字段
|
||||
tenant.setPackageType(request.getPackageType() != null ? request.getPackageType() : "STANDARD");
|
||||
tenant.setTeacherQuota(request.getTeacherQuota() != null ? request.getTeacherQuota() : 20);
|
||||
tenant.setStudentQuota(request.getStudentQuota() != null ? request.getStudentQuota() : 200);
|
||||
tenant.setStartDate(request.getStartDate());
|
||||
tenant.setExpireDate(request.getExpireDate());
|
||||
|
||||
// 兼容旧字段
|
||||
// 设置有效期相关字段(兼容旧字段)
|
||||
if (request.getExpireAt() != null) {
|
||||
tenant.setExpireAt(request.getExpireAt());
|
||||
}
|
||||
@ -72,10 +73,48 @@ public class TenantServiceImpl extends com.baomidou.mybatisplus.extension.servic
|
||||
|
||||
tenant.setStatus("ACTIVE");
|
||||
|
||||
// 使用 MP 的 insert 方法
|
||||
tenantMapper.insert(tenant);
|
||||
// 如果传入了 packageId,查询套餐信息并填充相关字段
|
||||
if (request.getPackageId() != null) {
|
||||
CoursePackage coursePackage = coursePackageService.getById(request.getPackageId());
|
||||
if (coursePackage == null) {
|
||||
log.warn("课程套餐不存在,packageId: {}", request.getPackageId());
|
||||
throw new BusinessException(ErrorCode.PACKAGE_NOT_FOUND, "课程套餐不存在");
|
||||
}
|
||||
|
||||
// 根据套餐信息填充租户字段
|
||||
tenant.setPackageType(coursePackage.getName());
|
||||
tenant.setTeacherQuota(request.getTeacherQuota() != null ? request.getTeacherQuota() : 20);
|
||||
tenant.setStudentQuota(request.getStudentQuota() != null ? request.getStudentQuota() : 200);
|
||||
tenant.setStartDate(request.getStartDate());
|
||||
tenant.setExpireDate(request.getExpireDate());
|
||||
|
||||
// 使用 MP 的 insert 方法
|
||||
tenantMapper.insert(tenant);
|
||||
|
||||
// 创建租户套餐关联记录
|
||||
TenantPackage tenantPackage = new TenantPackage();
|
||||
tenantPackage.setTenantId(tenant.getId());
|
||||
tenantPackage.setPackageId(request.getPackageId());
|
||||
tenantPackage.setStartDate(request.getStartDate() != null ? request.getStartDate() : LocalDate.now());
|
||||
tenantPackage.setEndDate(request.getExpireDate());
|
||||
tenantPackage.setPricePaid(coursePackage.getDiscountPrice() != null ? coursePackage.getDiscountPrice() : coursePackage.getPrice());
|
||||
tenantPackage.setStatus(TenantPackageStatus.ACTIVE);
|
||||
tenantPackageMapper.insert(tenantPackage);
|
||||
|
||||
log.info("租户创建成功并关联套餐,ID: {}, packageId: {}", tenant.getId(), request.getPackageId());
|
||||
} else {
|
||||
// 没有传入 packageId,使用原有逻辑
|
||||
tenant.setPackageType(request.getPackageType() != null ? request.getPackageType() : "STANDARD");
|
||||
tenant.setTeacherQuota(request.getTeacherQuota() != null ? request.getTeacherQuota() : 20);
|
||||
tenant.setStudentQuota(request.getStudentQuota() != null ? request.getStudentQuota() : 200);
|
||||
tenant.setStartDate(request.getStartDate());
|
||||
tenant.setExpireDate(request.getExpireDate());
|
||||
|
||||
// 使用 MP 的 insert 方法
|
||||
tenantMapper.insert(tenant);
|
||||
log.info("租户创建成功,ID: {}", tenant.getId());
|
||||
}
|
||||
|
||||
log.info("租户创建成功,ID: {}", tenant.getId());
|
||||
return tenant;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user