feat: 功能优化
This commit is contained in:
@@ -20,12 +20,121 @@ globs: **/*.java, **/*.xml, **/*.yaml, **/*.yml
|
||||
- **VO 层**: 视图对象,用于前后端交互
|
||||
- **DO 层**: 数据对象,对应数据库表
|
||||
|
||||
## 目录结构规范
|
||||
|
||||
### 模块目录结构
|
||||
|
||||
业务模块的标准目录结构如下:
|
||||
|
||||
```
|
||||
yudao-module-{模块名}/
|
||||
└── src/main/java/cn/iocoder/yudao/module/{模块名}/
|
||||
├── controller/ # Controller 层
|
||||
│ └── {Xxx}Controller.java
|
||||
├── service/ # Service 层
|
||||
│ ├── {Xxx}Service.java # Service 接口
|
||||
│ ├── {Xxx}ServiceImpl.java # Service 实现类
|
||||
│ └── {Xxx}Util.java # Service 工具类(可选)
|
||||
├── mapper/ # Mapper 层
|
||||
│ └── {Xxx}Mapper.java
|
||||
├── dataobject/ # DO 对象(可选)
|
||||
│ └── {Xxx}DO.java
|
||||
├── vo/ # VO 对象
|
||||
│ ├── {Xxx}SaveReqVO.java
|
||||
│ ├── {Xxx}PageReqVO.java
|
||||
│ ├── {Xxx}UpdateReqVO.java
|
||||
│ └── {Xxx}RespVO.java
|
||||
├── enums/ # 枚举类(可选)
|
||||
│ └── {Xxx}Enum.java
|
||||
└── mq/ # 消息队列(可选)
|
||||
└── consumer/
|
||||
└── {Xxx}Consumer.java
|
||||
```
|
||||
|
||||
### 目录结构说明
|
||||
|
||||
- **mapper/**: Mapper 接口,继承 `BaseMapperX<T>`
|
||||
- **dataobject/**: DO 对象(可选),继承 `BaseDO` 或 `TenantBaseDO`
|
||||
- 如果模块没有 DO 对象,可以省略 `dataobject/` 包
|
||||
|
||||
### 包命名规范
|
||||
|
||||
#### Controller 包
|
||||
- Controller 类名:`{Xxx}Controller` 或 `App{Xxx}Controller`
|
||||
- 直接放在 `controller/` 包下
|
||||
|
||||
#### Service 包
|
||||
- Service 接口:`{Xxx}Service.java`
|
||||
- Service 实现:`{Xxx}ServiceImpl.java`
|
||||
- Service 工具类:`{Xxx}Util.java` 或 `{Xxx}Helper.java`
|
||||
|
||||
#### Mapper 包
|
||||
- Mapper 接口:`mapper/{Xxx}Mapper.java`
|
||||
- Mapper 接口继承 `BaseMapperX<T>`
|
||||
|
||||
#### DO 包
|
||||
- DO 对象:`dataobject/{Xxx}DO.java`(可选)
|
||||
- DO 类名:`{Xxx}DO.java`
|
||||
- 继承 `BaseDO` 或 `TenantBaseDO`
|
||||
|
||||
#### VO 包
|
||||
- Request VO: `{Xxx}SaveReqVO`、`{Xxx}PageReqVO`、`{Xxx}UpdateReqVO`
|
||||
- Response VO: `{Xxx}RespVO`
|
||||
- App VO: `App{Xxx}ReqVO`、`App{Xxx}RespVO`
|
||||
- 直接放在 `vo/` 包下
|
||||
|
||||
### 目录结构示例
|
||||
|
||||
#### 示例 1:简单模块(tikhup)
|
||||
```
|
||||
tikhup/
|
||||
├── controller/
|
||||
│ └── TikHupController.java
|
||||
├── service/
|
||||
│ ├── TikHupService.java
|
||||
│ ├── TikHupServiceImpl.java
|
||||
│ └── TikFileTransCharacters.java
|
||||
├── mapper/
|
||||
│ ├── TikPromptMapper.java
|
||||
│ └── TikTokenMapper.java
|
||||
└── vo/
|
||||
├── TikPromptVO.java
|
||||
└── TikTokenVO.java
|
||||
```
|
||||
|
||||
#### 示例 2:完整模块(file)
|
||||
```
|
||||
file/
|
||||
├── controller/
|
||||
│ ├── AppTikUserFileController.java
|
||||
│ ├── AppTikFileGroupController.java
|
||||
│ └── AppTikTestController.java
|
||||
├── service/
|
||||
│ ├── TikUserFileService.java
|
||||
│ ├── TikUserFileServiceImpl.java
|
||||
│ ├── TikFileGroupService.java
|
||||
│ └── TikFileGroupServiceImpl.java
|
||||
├── mapper/
|
||||
│ ├── TikUserFileMapper.java
|
||||
│ └── TikFileGroupMapper.java
|
||||
├── vo/
|
||||
│ ├── AppTikUserFilePageReqVO.java
|
||||
│ ├── AppTikUserFileRespVO.java
|
||||
│ └── AppTikFileGroupCreateReqVO.java
|
||||
└── enums/
|
||||
└── TikFileCategoryEnum.java
|
||||
```
|
||||
|
||||
### 目录结构原则
|
||||
|
||||
1. **统一性**:同一模块内保持结构一致
|
||||
2. **简洁性**:使用 `mapper/` 和 `dataobject/` 包,结构清晰
|
||||
3. **可选性**:没有 DO 对象时可以省略 `dataobject/` 包
|
||||
4. **可扩展性**:预留扩展空间,便于后续功能扩展
|
||||
|
||||
## Controller 层规范
|
||||
|
||||
### 包结构
|
||||
- `controller.admin.*`: 管理后台接口
|
||||
- `controller.app.*`: 用户端接口(C 端)
|
||||
- App Controller 和 VO 必须添加 `App` 前缀
|
||||
|
||||
|
||||
### 注解使用
|
||||
- 使用 `@RestController` 而非 `@Controller`
|
||||
@@ -260,7 +369,7 @@ public UserPromptDO getUserPrompt(Long id) {
|
||||
|
||||
### 路径前缀
|
||||
- 管理后台:`/admin-api`
|
||||
- 用户端:`/app-api`
|
||||
- 用户端:`/api`
|
||||
- Controller 路径:`/模块/资源`,如 `/ai/user-prompt`
|
||||
|
||||
### HTTP 方法
|
||||
|
||||
@@ -39,10 +39,9 @@ export const MaterialService = {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('fileCategory', fileCategory)
|
||||
// 大文件上传需要更长的超时时间(30分钟)
|
||||
return http.post(`${BASE_URL}/upload`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
timeout: 30 * 60 * 1000 // 30分钟
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</p>
|
||||
<p class="ant-upload-text">点击或拖拽文件到此处上传</p>
|
||||
<p class="ant-upload-hint">
|
||||
支持多文件上传,单个文件不超过 500MB
|
||||
支持多文件上传,单个文件不超过 100MB
|
||||
<br />
|
||||
支持格式:视频(MP4、MOV、AVI等)、图片(JPG、PNG、GIF等)、音频(MP3、WAV等)
|
||||
</p>
|
||||
@@ -63,7 +63,7 @@
|
||||
<a-button
|
||||
type="primary"
|
||||
:loading="uploading"
|
||||
:disabled="fileList.length === 0 || !fileCategory"
|
||||
:disabled="fileList.length === 0"
|
||||
@click="handleConfirm"
|
||||
>
|
||||
{{ uploading ? '上传中...' : `上传 (${fileList.length})` }}
|
||||
@@ -94,16 +94,16 @@ const emit = defineEmits(['update:visible', 'confirm', 'cancel'])
|
||||
|
||||
// 数据
|
||||
const fileList = ref([])
|
||||
const fileCategory = ref('video') // 文件分类,默认为视频集
|
||||
// 文件分类使用默认值,不再在UI中显示
|
||||
const DEFAULT_FILE_CATEGORY = 'video'
|
||||
|
||||
// 支持的文件类型
|
||||
const acceptTypes = 'video/*,image/*,audio/*,.mp4,.mov,.avi,.mkv,.jpg,.jpeg,.png,.gif,.webp,.mp3,.wav,.aac'
|
||||
|
||||
// 监听 visible 变化,重置文件列表和分类
|
||||
// 监听 visible 变化,重置文件列表
|
||||
watch(() => props.visible, (newVal) => {
|
||||
if (!newVal) {
|
||||
fileList.value = []
|
||||
fileCategory.value = 'video' // 重置为默认分类
|
||||
}
|
||||
})
|
||||
|
||||
@@ -134,9 +134,9 @@ const formatFileSize = (bytes) => {
|
||||
|
||||
// 上传前处理
|
||||
const handleBeforeUpload = (file) => {
|
||||
// 检查文件大小(500MB)
|
||||
if (file.size > 500 * 1024 * 1024) {
|
||||
message.warning(`文件 ${file.name} 超过 500MB,已跳过`)
|
||||
// 检查文件大小(100MB)
|
||||
if (file.size > 100 * 1024 * 1024) {
|
||||
message.warning(`文件 ${file.name} 超过 100MB,已跳过`)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -214,12 +214,8 @@ const handleConfirm = () => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!fileCategory.value) {
|
||||
message.warning('请选择文件分类')
|
||||
return
|
||||
}
|
||||
|
||||
emit('confirm', files, fileCategory.value)
|
||||
// 使用默认分类
|
||||
emit('confirm', files, DEFAULT_FILE_CATEGORY)
|
||||
}
|
||||
|
||||
// 处理 visible 变化
|
||||
@@ -239,16 +235,6 @@ const handleCancel = () => {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.upload-category-select {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.upload-label {
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,6 @@ const uploading = ref(false)
|
||||
|
||||
// 筛选条件
|
||||
const filters = reactive({
|
||||
fileCategory: undefined,
|
||||
fileName: '',
|
||||
createTime: undefined
|
||||
})
|
||||
@@ -204,11 +203,6 @@ const handleConfirmUpload = async (files, fileCategory) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!fileCategory) {
|
||||
message.warning('请选择文件分类')
|
||||
return
|
||||
}
|
||||
|
||||
uploading.value = true
|
||||
let successCount = 0
|
||||
let failCount = 0
|
||||
@@ -289,7 +283,6 @@ const handleFilterChange = () => {
|
||||
}
|
||||
|
||||
const handleResetFilters = () => {
|
||||
filters.fileCategory = undefined
|
||||
filters.fileName = ''
|
||||
filters.createTime = undefined
|
||||
pagination.pageNo = 1
|
||||
|
||||
@@ -12,8 +12,8 @@ spring:
|
||||
servlet:
|
||||
# 文件上传相关配置项
|
||||
multipart:
|
||||
max-file-size: 16MB # 单个文件大小
|
||||
max-request-size: 32MB # 设置总上传的文件大小
|
||||
max-file-size: 100MB # 单个文件大小
|
||||
max-request-size: 200MB # 设置总上传的文件大小(支持多文件上传)
|
||||
|
||||
# Jackson 配置项
|
||||
jackson:
|
||||
@@ -348,4 +348,4 @@ yudao:
|
||||
message-bus:
|
||||
type: redis # 消息总线的类型
|
||||
|
||||
debug: false
|
||||
debug: false
|
||||
|
||||
Reference in New Issue
Block a user