fix: 成长记录 images 序列化统一 + 租户套餐移除确认流程
- 成长记录: images 统一为 string[],修复 OpenAPI/Java DTO/前端类型 - 租户更新: TenantUpdateRequest 新增 forceRemove,ErrorCode 新增 REMOVE_PACKAGE_HAS_SCHEDULES - 异常处理: BusinessException 支持附加 data,GlobalExceptionHandler 返回 data 供前端确认弹窗 Made-with: Cursor
This commit is contained in:
parent
da415703cf
commit
029881f09f
@ -26910,8 +26910,9 @@
|
||||
"description": "内容"
|
||||
},
|
||||
"images": {
|
||||
"type": "string",
|
||||
"description": "图片(JSON 数组)"
|
||||
"type": "array",
|
||||
"items": { "type": "string", "description": "图片 URL" },
|
||||
"description": "图片 URL 列表"
|
||||
},
|
||||
"recordDate": {
|
||||
"type": "string",
|
||||
@ -30152,8 +30153,9 @@
|
||||
"description": "内容"
|
||||
},
|
||||
"images": {
|
||||
"type": "string",
|
||||
"description": "图片(JSON 数组)"
|
||||
"type": "array",
|
||||
"items": { "type": "string", "description": "图片 URL" },
|
||||
"description": "图片 URL 列表"
|
||||
},
|
||||
"recordDate": {
|
||||
"type": "string",
|
||||
|
||||
@ -31,6 +31,8 @@ async function fetchAndFix() {
|
||||
if (spec.components?.schemas) {
|
||||
delete spec.components.schemas['ResultObject[]'];
|
||||
}
|
||||
// 修复成长记录 images 字段:统一为 array of string(避免 SpringDoc 误生成为 string)
|
||||
fixGrowthRecordImagesSchema(spec.components?.schemas);
|
||||
|
||||
writeFileSync(OUTPUT, JSON.stringify(spec, null, 2));
|
||||
console.log('OpenAPI spec written to:', OUTPUT);
|
||||
@ -61,6 +63,22 @@ function fixSchema(schema) {
|
||||
if (schema.items) fixSchema(schema.items);
|
||||
}
|
||||
|
||||
/** 将 GrowthRecordCreateRequest/GrowthRecordUpdateRequest 的 images 统一为 array of string */
|
||||
function fixGrowthRecordImagesSchema(schemas) {
|
||||
if (!schemas) return;
|
||||
const arrayOfString = {
|
||||
type: 'array',
|
||||
items: { type: 'string', description: '图片 URL' },
|
||||
description: '图片 URL 列表',
|
||||
};
|
||||
for (const name of ['GrowthRecordCreateRequest', 'GrowthRecordUpdateRequest']) {
|
||||
const s = schemas[name];
|
||||
if (s?.properties?.images?.type === 'string') {
|
||||
schemas[name].properties.images = arrayOfString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function inlineResultObjectArrayRef(paths) {
|
||||
const inlineSchema = {
|
||||
type: 'object',
|
||||
|
||||
@ -18,8 +18,8 @@ export interface GrowthRecordCreateRequest {
|
||||
title: string;
|
||||
/** 内容 */
|
||||
content?: string;
|
||||
/** 图片(JSON 数组) */
|
||||
images?: string;
|
||||
/** 图片 URL 列表 */
|
||||
images?: string[];
|
||||
/** 记录日期 */
|
||||
recordDate?: string;
|
||||
/** 标签 */
|
||||
|
||||
@ -16,8 +16,8 @@ export interface GrowthRecordUpdateRequest {
|
||||
title?: string;
|
||||
/** 内容 */
|
||||
content?: string;
|
||||
/** 图片(JSON 数组) */
|
||||
images?: string;
|
||||
/** 图片 URL 列表 */
|
||||
images?: string[];
|
||||
/** 记录日期 */
|
||||
recordDate?: string;
|
||||
/** 标签 */
|
||||
|
||||
@ -37,6 +37,7 @@ public enum ErrorCode {
|
||||
|
||||
// Package Errors (3100+)
|
||||
PACKAGE_NOT_FOUND(3101, "Package not found"),
|
||||
REMOVE_PACKAGE_HAS_SCHEDULES(3102, "该套餐下有排课计划"),
|
||||
|
||||
// User Errors (4000+)
|
||||
USER_NOT_FOUND(4001, "User not found"),
|
||||
|
||||
@ -11,29 +11,41 @@ public class BusinessException extends RuntimeException {
|
||||
|
||||
private final Integer code;
|
||||
private final String message;
|
||||
private final Object data;
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
this.code = 500;
|
||||
this.message = message;
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
public BusinessException(Integer code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode) {
|
||||
super(errorCode.getMessage());
|
||||
this.code = errorCode.getCode();
|
||||
this.message = errorCode.getMessage();
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode, String message) {
|
||||
super(message);
|
||||
this.code = errorCode.getCode();
|
||||
this.message = message;
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode, String message, Object data) {
|
||||
super(message);
|
||||
this.code = errorCode.getCode();
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static BusinessException of(String message) {
|
||||
|
||||
@ -33,9 +33,9 @@ public class GlobalExceptionHandler {
|
||||
private String activeProfile;
|
||||
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public Result<Void> handleBusinessException(BusinessException e, HttpServletRequest request) {
|
||||
public Result<Object> handleBusinessException(BusinessException e, HttpServletRequest request) {
|
||||
log.warn("业务异常 at {}: {}", request.getRequestURI(), e.getMessage());
|
||||
return Result.error(e.getCode(), e.getMessage());
|
||||
return Result.error(e.getCode(), e.getMessage(), e.getData());
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
|
||||
@ -84,6 +84,17 @@ public class Result<T> implements Serializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应(带错误码、消息和附加数据)
|
||||
*/
|
||||
public static <T> Result<T> error(Integer code, String message, T data) {
|
||||
Result<T> result = new Result<>();
|
||||
result.setCode(code);
|
||||
result.setMessage(message);
|
||||
result.setData(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应(默认 500)
|
||||
*/
|
||||
|
||||
@ -29,13 +29,13 @@ public class GrowthRecordCreateRequest {
|
||||
@Schema(description = "内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "图片 URL 列表")
|
||||
@Schema(description = "图片 URL 列表", type = "array", implementation = String.class)
|
||||
private List<String> images;
|
||||
|
||||
@Schema(description = "记录日期")
|
||||
private LocalDate recordDate;
|
||||
|
||||
@Schema(description = "标签")
|
||||
@Schema(description = "标签", type = "array", implementation = String.class)
|
||||
private List<String> tags;
|
||||
|
||||
}
|
||||
|
||||
@ -19,13 +19,13 @@ public class GrowthRecordUpdateRequest {
|
||||
@Schema(description = "内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "图片 URL 列表")
|
||||
@Schema(description = "图片 URL 列表", type = "array", implementation = String.class)
|
||||
private List<String> images;
|
||||
|
||||
@Schema(description = "记录日期")
|
||||
private LocalDate recordDate;
|
||||
|
||||
@Schema(description = "标签")
|
||||
@Schema(description = "标签", type = "array", implementation = String.class)
|
||||
private List<String> tags;
|
||||
|
||||
}
|
||||
|
||||
@ -36,6 +36,9 @@ public class TenantUpdateRequest {
|
||||
@Schema(description = "课程套餐ID(用于三层架构)")
|
||||
private List<Long> collectionIds;
|
||||
|
||||
@Schema(description = "是否强制移除套餐(即便套餐下有排课计划)")
|
||||
private Boolean forceRemove;
|
||||
|
||||
@Schema(description = "教师配额")
|
||||
private Integer teacherQuota;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user