更新: API文档和数据库文档,优化课程和用户相关功能
This commit is contained in:
parent
5babb8f930
commit
53e5b5cd85
298
API文档.md
298
API文档.md
@ -56,11 +56,12 @@
|
|||||||
### 课程任务相关字段
|
### 课程任务相关字段
|
||||||
|
|
||||||
1. **进度状态 (progressStatus)**
|
1. **进度状态 (progressStatus)**
|
||||||
- 0: 脚本上传
|
- 0: 未开始
|
||||||
- 1: 脚本确认
|
- 1: 脚本制作
|
||||||
- 2: 视频拍摄
|
- 2: 脚本审核
|
||||||
- 3: 后期制作
|
- 3: 脚本确认
|
||||||
- 4: 任务完成
|
- 4: 视频拍摄与制作
|
||||||
|
- 5: 视频确认
|
||||||
|
|
||||||
## 用户接口
|
## 用户接口
|
||||||
|
|
||||||
@ -274,12 +275,12 @@
|
|||||||
### 1. 获取课程任务列表
|
### 1. 获取课程任务列表
|
||||||
|
|
||||||
- **接口**:`GET /api/lesson-tasks`
|
- **接口**:`GET /api/lesson-tasks`
|
||||||
- **描述**:分页获取课程任务列表
|
- **描述**:分页获取课程任务列表,可按用户筛选
|
||||||
- **认证**:需要
|
- **认证**:需要
|
||||||
- **查询参数**:
|
- **查询参数**:
|
||||||
- `page`: 页码(从 1 开始)
|
- `page`: 页码(从 1 开始)
|
||||||
- `size`: 每页数量(默认 10)
|
- `size`: 每页数量(默认 10)
|
||||||
- `userId`: 用户 ID(可选)
|
- `userId`: 用户ID(可选)
|
||||||
- **成功响应**:
|
- **成功响应**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -288,27 +289,35 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"content": [
|
"content": [
|
||||||
{
|
{
|
||||||
"id": 6,
|
"id": 1,
|
||||||
"courseName": "Test Course",
|
"courseName": "数学",
|
||||||
"microLessonName": "Test Lesson",
|
"microLessonName": "数学1-1",
|
||||||
"userId": 12,
|
"userId": 1,
|
||||||
"progressStatus": 1,
|
"progressStatus": 4,
|
||||||
"scriptUploadTime": 1734578081,
|
"scriptCreateTime": 1734940587,
|
||||||
"scriptConfirmTime": 1734578081,
|
"scriptReviewTime": null,
|
||||||
"videoCaptureTime": 1734578081,
|
"scriptConfirmTime": 1734940825,
|
||||||
"videoConfirmTime": 1734578081,
|
"videoCreateTime": 1734940832,
|
||||||
"finishTime": 1734578081,
|
"videoConfirmTime": 1734940837,
|
||||||
"advise": "Test advice",
|
"finishTime": 1734940837,
|
||||||
"createdAt": 1734578081,
|
"advise": "",
|
||||||
"updatedAt": 1734578081
|
"createdAt": 1734674726,
|
||||||
|
"updatedAt": 1734940837
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"totalElements": 4,
|
"pageable": {
|
||||||
|
"pageNumber": 0,
|
||||||
|
"pageSize": 10,
|
||||||
|
"sort": {
|
||||||
|
"empty": true,
|
||||||
|
"unsorted": true,
|
||||||
|
"sorted": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"totalElements": 7,
|
||||||
"totalPages": 1,
|
"totalPages": 1,
|
||||||
"size": 10,
|
|
||||||
"number": 0,
|
|
||||||
"first": true,
|
|
||||||
"last": true,
|
"last": true,
|
||||||
|
"first": true,
|
||||||
"empty": false
|
"empty": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,29 +326,30 @@
|
|||||||
### 2. 获取单个课程任务
|
### 2. 获取单个课程任务
|
||||||
|
|
||||||
- **接口**:`GET /api/lesson-tasks/{id}`
|
- **接口**:`GET /api/lesson-tasks/{id}`
|
||||||
- **描述**:获取指定 ID 的课程任务
|
- **描述**:根据ID获取课程任务详情
|
||||||
- **认证**:需要
|
- **认证**:需要
|
||||||
- **路径参数**:
|
- **路径参数**:
|
||||||
- `id`: 课程任务 ID
|
- `id`: 课程任务ID
|
||||||
- **成功响应**:
|
- **成功响应**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": 10000,
|
"code": 10000,
|
||||||
"message": "成功",
|
"message": "成功",
|
||||||
"data": {
|
"data": {
|
||||||
"id": 6,
|
"id": 1,
|
||||||
"courseName": "Test Course",
|
"courseName": "数学",
|
||||||
"microLessonName": "Test Lesson",
|
"microLessonName": "数学1-1",
|
||||||
"userId": 12,
|
"userId": 1,
|
||||||
"progressStatus": 1,
|
"progressStatus": 4,
|
||||||
"scriptUploadTime": 1734578081,
|
"scriptCreateTime": 1734940587,
|
||||||
"scriptConfirmTime": 1734578081,
|
"scriptReviewTime": null,
|
||||||
"videoCaptureTime": 1734578081,
|
"scriptConfirmTime": 1734940825,
|
||||||
"videoConfirmTime": 1734578081,
|
"videoCreateTime": 1734940832,
|
||||||
"finishTime": 1734578081,
|
"videoConfirmTime": 1734940837,
|
||||||
"advise": "Test advice",
|
"finishTime": 1734940837,
|
||||||
"createdAt": 1734578081,
|
"advise": "",
|
||||||
"updatedAt": 1734578081
|
"createdAt": 1734674726,
|
||||||
|
"updatedAt": 1734940837
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -352,55 +362,10 @@
|
|||||||
- **请求体**:
|
- **请求体**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"courseName": "Java基础", // 课程名称,不可为空
|
"courseName": "测试课程",
|
||||||
"microLessonName": "Java变量", // 微课名称,不可为空
|
"microLessonName": "测试微课",
|
||||||
"userId": 1, // 负责人ID,不可为空,关联users表
|
"userId": 1,
|
||||||
"advise": "请注意讲解速度" // 任务建议或备注,可选
|
"advise": "任务说明"
|
||||||
}
|
|
||||||
```
|
|
||||||
- **成功响应**:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 10000,
|
|
||||||
"message": "成功",
|
|
||||||
"data": {
|
|
||||||
"id": 6,
|
|
||||||
"courseName": "Java基础",
|
|
||||||
"microLessonName": "Java变量",
|
|
||||||
"userId": 1,
|
|
||||||
"progressStatus": 1,
|
|
||||||
"scriptUploadTime": ,
|
|
||||||
"scriptConfirmTime": ,
|
|
||||||
"videoCaptureTime": ,
|
|
||||||
"videoConfirmTime": ,
|
|
||||||
"finishTime": ,
|
|
||||||
"advise": "请注意讲解速度",
|
|
||||||
"createdAt": 1734578081,
|
|
||||||
"updatedAt": 1734578081
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 更新课程任务
|
|
||||||
|
|
||||||
- **接口**:`PUT /api/lesson-tasks/{id}`
|
|
||||||
- **描述**:更新指定 ID 的课程任务
|
|
||||||
- **认证**:需要
|
|
||||||
- **路径参数**:
|
|
||||||
- `id`: 课程任务 ID
|
|
||||||
- **请求体**:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"courseName": "Updated Course", // 课程名称
|
|
||||||
"microLessonName": "Updated Lesson", // 微课名称
|
|
||||||
"userId": 12, // 用户ID
|
|
||||||
"progressStatus": 2, // 进度状态
|
|
||||||
"scriptUploadTime": 1734578081, // 脚本上传时间
|
|
||||||
"scriptConfirmTime": 1734578081, // 脚本确认时间
|
|
||||||
"videoCaptureTime": 1734578081, // 视频录制时间
|
|
||||||
"videoConfirmTime": 1734578081, // 视频确认时间
|
|
||||||
"finishTime": 1734578081, // 完成时间
|
|
||||||
"advise": "Updated advice" // 建议
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- **成功响应**:
|
- **成功响应**:
|
||||||
@ -409,46 +374,69 @@
|
|||||||
"code": 10000,
|
"code": 10000,
|
||||||
"message": "成功",
|
"message": "成功",
|
||||||
"data": {
|
"data": {
|
||||||
"id": 6,
|
"id": 11,
|
||||||
"courseName": "Updated Course",
|
"courseName": "测试课程",
|
||||||
"microLessonName": "Updated Lesson",
|
"microLessonName": "测试微课",
|
||||||
"userId": 12,
|
"userId": 1,
|
||||||
"progressStatus": 2,
|
"progressStatus": 0,
|
||||||
"scriptUploadTime": 1734578081,
|
"scriptCreateTime": null,
|
||||||
"scriptConfirmTime": 1734578081,
|
"scriptReviewTime": null,
|
||||||
"videoCaptureTime": 1734578081,
|
"scriptConfirmTime": null,
|
||||||
"videoConfirmTime": 1734578081,
|
"videoCreateTime": null,
|
||||||
"finishTime": 1734578081,
|
"videoConfirmTime": null,
|
||||||
"advise": "Updated advice",
|
"finishTime": null,
|
||||||
"createdAt": 1734578081,
|
"advise": "任务说明",
|
||||||
"updatedAt": 1734578081
|
"createdAt": 1735003870,
|
||||||
|
"updatedAt": 1735003870
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. 删除课程任务
|
### 4. 更新课程任务
|
||||||
|
|
||||||
- **接口**:`DELETE /api/lesson-tasks/{id}`
|
- **接口**:`PUT /api/lesson-tasks/{id}`
|
||||||
- **描述**:删除指定 ID 的课程任务
|
- **描述**:更新课程任务信息
|
||||||
- **认证**:需要
|
- **认证**:需要
|
||||||
- **路径参数**:
|
- **路径参数**:
|
||||||
- `id`: 课程任务 ID
|
- `id`: 课程任务ID
|
||||||
|
- **请求体**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"progressStatus": 1,
|
||||||
|
"advise": "更新的任务说明"
|
||||||
|
}
|
||||||
|
```
|
||||||
- **成功响应**:
|
- **成功响应**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": 10000,
|
"code": 10000,
|
||||||
"message": "成功",
|
"message": "成功",
|
||||||
"data": null
|
"data": {
|
||||||
|
"id": 11,
|
||||||
|
"courseName": "测试课程",
|
||||||
|
"microLessonName": "测试微课",
|
||||||
|
"userId": 1,
|
||||||
|
"progressStatus": 1,
|
||||||
|
"scriptCreateTime": 1735003922,
|
||||||
|
"scriptReviewTime": null,
|
||||||
|
"scriptConfirmTime": null,
|
||||||
|
"videoCreateTime": null,
|
||||||
|
"videoConfirmTime": null,
|
||||||
|
"finishTime": null,
|
||||||
|
"advise": "更新的任务说明",
|
||||||
|
"createdAt": 1735003870,
|
||||||
|
"updatedAt": 1735003922
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. 按部门 ID 查询课程任务
|
### 5. 获取部门课程任务
|
||||||
|
|
||||||
- **接口**:`GET /api/lesson-tasks/department/{departmentId}`
|
- **接口**:`GET /api/lesson-tasks/department/{departmentId}`
|
||||||
- **描述**:获取指定部门下正常状态用户的课程任务列表(分页)
|
- **描述**:获取指定部门的课程任务列表
|
||||||
- **认证**:需要
|
- **认证**:需要
|
||||||
- **路径参数**:
|
- **路径参数**:
|
||||||
- `departmentId`: 部门 ID
|
- `departmentId`: 部门ID
|
||||||
- **查询参数**:
|
- **查询参数**:
|
||||||
- `page`: 页码(从 1 开始)
|
- `page`: 页码(从 1 开始)
|
||||||
- `size`: 每页数量(默认 10)
|
- `size`: 每页数量(默认 10)
|
||||||
@ -461,89 +449,51 @@
|
|||||||
"content": [
|
"content": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"courseName": "物理",
|
"courseName": "数学",
|
||||||
"microLessonName": "微课1-1",
|
"microLessonName": "数学1-1",
|
||||||
"userId": 1,
|
"userId": 1,
|
||||||
"username": "教师账号1", // 新增:用户名字段
|
"username": "教师账号1",
|
||||||
"progressStatus": 4,
|
"progressStatus": 4,
|
||||||
"scriptUploadTime": 1734498510,
|
"scriptCreateTime": 1734940587,
|
||||||
"scriptConfirmTime": 1734498510,
|
"scriptReviewTime": null,
|
||||||
"videoCaptureTime": 1734498510,
|
"scriptConfirmTime": 1734940825,
|
||||||
"videoConfirmTime": 1734498510,
|
"videoCreateTime": 1734940832,
|
||||||
"finishTime": 1734498510,
|
"videoConfirmTime": 1734940837,
|
||||||
"advise": null,
|
"finishTime": 1734940837,
|
||||||
"createdAt": 1734578081,
|
"advise": "",
|
||||||
"updatedAt": 1734580393
|
"createdAt": 1734674726,
|
||||||
|
"updatedAt": 1734940837
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"totalElements": 10,
|
"pageable": {
|
||||||
"totalPages": 1,
|
"pageNumber": 0,
|
||||||
"size": 10,
|
"pageSize": 10
|
||||||
"number": 0,
|
},
|
||||||
"first": true,
|
"totalElements": 11,
|
||||||
"last": true,
|
"totalPages": 2
|
||||||
"empty": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7. 更新课程任务进度
|
### 6. 删除课程任务
|
||||||
|
|
||||||
- **接口**:`PUT /api/lesson-tasks/{id}`
|
- **接口**:`DELETE /api/lesson-tasks/{id}`
|
||||||
- **描述**:更新课程任务的进度状态和建议
|
- **描述**:删除指定的课程任务
|
||||||
- **认证**:需要
|
- **认证**:需要
|
||||||
- **路径参数**:
|
- **路径参数**:
|
||||||
- `id`: 课程任务 ID
|
- `id`: 课程任务ID
|
||||||
- **请求体**:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"progressStatus": 2, // 进度状态(可选)
|
|
||||||
"advise": "{\"method\":\"wechat\",\"uploaded\":true}" // 建议(可选)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- **说明**:
|
|
||||||
- 更新进度状态时会自动更新对应的时间戳:
|
|
||||||
- 状态 1:更新 scriptUploadTime
|
|
||||||
- 状态 2:更新 scriptConfirmTime
|
|
||||||
- 状态 3:更新 videoCaptureTime
|
|
||||||
- 状态 4:更新 videoConfirmTime
|
|
||||||
- 状态 5:更新 finishTime
|
|
||||||
- 只会更新请求体中包含的字段,未提供的字段保持不变
|
|
||||||
- **成功响应**:
|
- **成功响应**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": 10000,
|
"code": 10000,
|
||||||
"message": "成功",
|
"message": "成功",
|
||||||
"data": {
|
"data": null
|
||||||
"id": 10,
|
|
||||||
"courseName": "测试课程",
|
|
||||||
"microLessonName": "测试微课",
|
|
||||||
"userId": 1,
|
|
||||||
"progressStatus": 2,
|
|
||||||
"scriptUploadTime": null,
|
|
||||||
"scriptConfirmTime": 1734663755,
|
|
||||||
"videoCaptureTime": null,
|
|
||||||
"videoConfirmTime": null,
|
|
||||||
"finishTime": null,
|
|
||||||
"advise": "{\"method\":\"wechat\",\"uploaded\":true}",
|
|
||||||
"createdAt": 1734602440,
|
|
||||||
"updatedAt": 1734663755
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
|
|
||||||
1. 所有需要认证的接口必须在请求头中携带有效的 JWT 令牌
|
1. 所有时间戳字段均使用秒级时间戳(10位)
|
||||||
2. 所有时间戳字段均为秒级时间戳
|
2. 课程任务状态变更时会自动记录相应的时间戳
|
||||||
3. 分页接口的页码从 1 开始
|
3. 部门课程任务列表会额外返回用户名信息
|
||||||
4. 用户密码在传输和存储时都会进行加密处理
|
4. 分页参数中的页码从1开始
|
||||||
5. 课程任务的 progressStatus 字段状态码说明:
|
|
||||||
- 0: 脚本上传
|
|
||||||
- 1: 脚本确认
|
|
||||||
- 2: 视频拍摄
|
|
||||||
- 3: 后期制作
|
|
||||||
- 4: 任务完成
|
|
||||||
6. 用户状态说明:
|
|
||||||
- 1: 正常
|
|
||||||
- 0: 禁用
|
|
||||||
|
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -11,6 +11,7 @@ declare module 'vue' {
|
|||||||
TabBar: typeof import('./src/components/TabBar.vue')['default']
|
TabBar: typeof import('./src/components/TabBar.vue')['default']
|
||||||
WdBadge: typeof import('wot-design-uni/components/wd-badge/wd-badge.vue')['default']
|
WdBadge: typeof import('wot-design-uni/components/wd-badge/wd-badge.vue')['default']
|
||||||
WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default']
|
WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default']
|
||||||
|
WdCard: typeof import('wot-design-uni/components/wd-card/wd-card.vue')['default']
|
||||||
WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default']
|
WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default']
|
||||||
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
|
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
|
||||||
WdCheckbox: typeof import('wot-design-uni/components/wd-checkbox/wd-checkbox.vue')['default']
|
WdCheckbox: typeof import('wot-design-uni/components/wd-checkbox/wd-checkbox.vue')['default']
|
||||||
@ -31,6 +32,7 @@ declare module 'vue' {
|
|||||||
WdSteps: typeof import('wot-design-uni/components/wd-steps/wd-steps.vue')['default']
|
WdSteps: typeof import('wot-design-uni/components/wd-steps/wd-steps.vue')['default']
|
||||||
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
|
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
|
||||||
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
|
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
|
||||||
|
WdTextarea: typeof import('wot-design-uni/components/wd-textarea/wd-textarea.vue')['default']
|
||||||
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
|
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@ -1509,55 +1509,46 @@ packages:
|
|||||||
resolution: {integrity: sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==}
|
resolution: {integrity: sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.21.3':
|
'@rollup/rollup-linux-arm-musleabihf@4.21.3':
|
||||||
resolution: {integrity: sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==}
|
resolution: {integrity: sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.21.3':
|
'@rollup/rollup-linux-arm64-gnu@4.21.3':
|
||||||
resolution: {integrity: sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==}
|
resolution: {integrity: sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.21.3':
|
'@rollup/rollup-linux-arm64-musl@4.21.3':
|
||||||
resolution: {integrity: sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==}
|
resolution: {integrity: sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-powerpc64le-gnu@4.21.3':
|
'@rollup/rollup-linux-powerpc64le-gnu@4.21.3':
|
||||||
resolution: {integrity: sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==}
|
resolution: {integrity: sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.21.3':
|
'@rollup/rollup-linux-riscv64-gnu@4.21.3':
|
||||||
resolution: {integrity: sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==}
|
resolution: {integrity: sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.21.3':
|
'@rollup/rollup-linux-s390x-gnu@4.21.3':
|
||||||
resolution: {integrity: sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==}
|
resolution: {integrity: sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.21.3':
|
'@rollup/rollup-linux-x64-gnu@4.21.3':
|
||||||
resolution: {integrity: sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==}
|
resolution: {integrity: sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.21.3':
|
'@rollup/rollup-linux-x64-musl@4.21.3':
|
||||||
resolution: {integrity: sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==}
|
resolution: {integrity: sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-win32-arm64-msvc@4.21.3':
|
'@rollup/rollup-win32-arm64-msvc@4.21.3':
|
||||||
resolution: {integrity: sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==}
|
resolution: {integrity: sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import http from "@/http/HttpClient";
|
import http from "@/http/HttpClient";
|
||||||
import { useUser } from "@/stores/useUser";
|
import { useUser } from "@/stores/useUser";
|
||||||
import type { PagedData } from "@/types/api/common";
|
import type { LessonTask, UpdateLessonTaskRequest } from "@/types/api/lesson";
|
||||||
import type { CreateLessonTaskRequest, LessonTask, UpdateLessonTaskRequest } from "@/types/api/lesson";
|
|
||||||
import type { LoginRequest } from "@/types/api/auth";
|
import type { LoginRequest } from "@/types/api/auth";
|
||||||
import type { CreateUserRequest, User } from "@/types/api/user";
|
import type { User } from "@/types/api/user";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务API类
|
* 业务API类
|
||||||
@ -176,13 +175,14 @@ export default class BussApi {
|
|||||||
/**
|
/**
|
||||||
* 更新课程进度
|
* 更新课程进度
|
||||||
* @param lessonId - 课程ID
|
* @param lessonId - 课程ID
|
||||||
|
* @param progressStatus - 进度状态 (0-未开始, 1-脚本制作, 2-脚本审核, 3-脚本确认, 4-视频制作, 5-视频确认)
|
||||||
* @returns Promise<void>
|
* @returns Promise<void>
|
||||||
*/
|
*/
|
||||||
static updateLessonProgress(lessonId: number): Promise<void> {
|
static updateLessonProgress(lessonId: number, progressStatus: number): Promise<void> {
|
||||||
const user = useUser();
|
const user = useUser();
|
||||||
return http
|
return http
|
||||||
.server()
|
.server()
|
||||||
.post(`lesson/${lessonId}/progress`, null, {
|
.post(`lesson/${lessonId}/progress`, { progressStatus }, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${user.token}`,
|
Authorization: `Bearer ${user.token}`,
|
||||||
},
|
},
|
||||||
|
@ -31,17 +31,17 @@ const nameLabelIconMap = {
|
|||||||
home: {
|
home: {
|
||||||
title: '进度查看',
|
title: '进度查看',
|
||||||
icon: 'dashboard',
|
icon: 'dashboard',
|
||||||
roles: ['teacher', 'admin', 'liaison', 'sysadmin'] as const // 使用 as const 来确保类型正确
|
roles: ['teacher', 'liaison', 'admin', 'sysadmin'] as const // 校方教师、校方项目负责人、公司课程顾问、公司系统管理员
|
||||||
},
|
},
|
||||||
progress: {
|
progress: {
|
||||||
title: '进度管理',
|
title: '进度管理',
|
||||||
icon: 'transfer',
|
icon: 'transfer',
|
||||||
roles: ['teacher', 'admin', 'sysadmin'] as const
|
roles: ['teacher', 'admin', 'sysadmin'] as const // 校方教师、公司课程顾问、公司系统管理员
|
||||||
},
|
},
|
||||||
my: {
|
my: {
|
||||||
title: '我的',
|
title: '我的',
|
||||||
icon: 'user',
|
icon: 'user',
|
||||||
roles: ['teacher', 'admin', 'liaison', 'sysadmin'] as const
|
roles: ['teacher', 'liaison', 'admin', 'sysadmin'] as const // 校方教师、校方项目负责人、公司课程顾问、公司系统管理员
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ import { ref } from "vue";
|
|||||||
export const useConfig = defineStore('config', () => {
|
export const useConfig = defineStore('config', () => {
|
||||||
// const BASE_URL = ref<string>("https://ppmp.fenshenzhike.com/api");
|
// const BASE_URL = ref<string>("https://ppmp.fenshenzhike.com/api");
|
||||||
// const BASE_URL = ref<string>("http://localhost:1218/api");
|
// const BASE_URL = ref<string>("http://localhost:1218/api");
|
||||||
const BASE_URL = ref<string>("http://192.168.0.178:1218/api");
|
const BASE_URL = ref<string>("http://192.168.0.119:1218/api");
|
||||||
// const BASE_URL = ref<string>("http://192.30.5.16:1218/api");
|
// const BASE_URL = ref<string>("http://192.30.5.11:1218/api");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
BASE_URL
|
BASE_URL
|
||||||
|
@ -4,7 +4,7 @@ import pageWrapper from '@/components/page-wrapper.vue';
|
|||||||
import { useUser } from '@/stores/useUser';
|
import { useUser } from '@/stores/useUser';
|
||||||
import type { LessonTask } from '@/types/api/lesson';
|
import type { LessonTask } from '@/types/api/lesson';
|
||||||
import { calcLessonProgress } from '@/utils/lesson';
|
import { calcLessonProgress } from '@/utils/lesson';
|
||||||
import { onPageShow } from '@dcloudio/uni-app';
|
import { onPageShow, onLoad, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||||
import { useRouter } from 'uni-mini-router';
|
import { useRouter } from 'uni-mini-router';
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { useToast } from 'wot-design-uni';
|
import { useToast } from 'wot-design-uni';
|
||||||
@ -73,8 +73,24 @@ const loadLessons = async () => {
|
|||||||
toast.loading({ msg: '加载中...' })
|
toast.loading({ msg: '加载中...' })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userId = teacherFilterValue.value === 0 ? undefined : teacherFilterValue.value
|
let res;
|
||||||
const res = await BussApi.getLessonTasks(1, 512, userId)
|
|
||||||
|
if (user.hasRole('teacher')) {
|
||||||
|
res = await BussApi.getLessonTasks(1, 512, user.userinfo.id)
|
||||||
|
} else if (user.hasRole('admin') || user.hasRole('liaison')) {
|
||||||
|
const userId = teacherFilterValue.value === 0 ? undefined : teacherFilterValue.value
|
||||||
|
if (userId) {
|
||||||
|
res = await BussApi.getLessonTasks(1, 512, userId)
|
||||||
|
} else {
|
||||||
|
res = await BussApi.getLessonTasks(1, 512)
|
||||||
|
}
|
||||||
|
} else if (user.hasRole('sysadmin')) {
|
||||||
|
const userId = teacherFilterValue.value === 0 ? undefined : teacherFilterValue.value
|
||||||
|
res = await BussApi.getLessonTasks(1, 512, userId)
|
||||||
|
} else {
|
||||||
|
toast.error({ msg: '无权限访问' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (res.code !== 10000 || !res.data?.content || !Array.isArray(res.data.content)) {
|
if (res.code !== 10000 || !res.data?.content || !Array.isArray(res.data.content)) {
|
||||||
toast.error({ msg: res.message || '获取数据失败' })
|
toast.error({ msg: res.message || '获取数据失败' })
|
||||||
@ -92,7 +108,6 @@ const loadLessons = async () => {
|
|||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
groupedLessons.value = groupData
|
groupedLessons.value = groupData
|
||||||
// expand courses with lessons in progress
|
|
||||||
expandedCourse.value = Object.keys(groupData).filter(courseName => {
|
expandedCourse.value = Object.keys(groupData).filter(courseName => {
|
||||||
return groupData[courseName].filter((lesson: LessonTask) =>
|
return groupData[courseName].filter((lesson: LessonTask) =>
|
||||||
calcLessonProgress(lesson) !== 0 && calcLessonProgress(lesson) !== 100
|
calcLessonProgress(lesson) !== 0 && calcLessonProgress(lesson) !== 100
|
||||||
@ -109,7 +124,6 @@ const loadLessons = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听教师筛选值的变化
|
|
||||||
watch(teacherFilterValue, () => {
|
watch(teacherFilterValue, () => {
|
||||||
loadLessons()
|
loadLessons()
|
||||||
})
|
})
|
||||||
@ -125,6 +139,26 @@ const getUsernameById = (userId: number) => {
|
|||||||
} else
|
} else
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
try {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
} finally {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPullDownRefresh(() => {
|
||||||
|
refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
loadLessons()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -143,9 +177,12 @@ const getUsernameById = (userId: number) => {
|
|||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<p class="pt-1">
|
<p class="pt-1">
|
||||||
{{ courseName || '无标题课程' }}
|
{{ courseName || '无标题课程' }}
|
||||||
<span v-if="getUsernameById(courses[0]?.userId)" class=" text-xs text-gray-400 ml-2">
|
<wd-badge hidden is-dot :top="-10">
|
||||||
{{ getUsernameById(courses[0]?.userId) }}
|
<span v-if="!user.hasRole('teacher') && getUsernameById(courses[0]?.userId)"
|
||||||
</span>
|
class=" text-xs text-gray-400 ml-2">
|
||||||
|
<!-- {{ getUsernameById(courses[0]?.userId) }} -->
|
||||||
|
</span>
|
||||||
|
</wd-badge>
|
||||||
</p>
|
</p>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<wd-tag v-if="(() => {
|
<wd-tag v-if="(() => {
|
||||||
@ -162,6 +199,13 @@ const getUsernameById = (userId: number) => {
|
|||||||
});
|
});
|
||||||
return allCompleted;
|
return allCompleted;
|
||||||
})()" custom-class="w-fit" type="success">已完成</wd-tag>
|
})()" custom-class="w-fit" type="success">已完成</wd-tag>
|
||||||
|
<wd-tag v-if="(() => {
|
||||||
|
const allNotStarted = courses.every(lesson => {
|
||||||
|
const progress = calcLessonProgress(lesson);
|
||||||
|
return progress === 0;
|
||||||
|
});
|
||||||
|
return allNotStarted;
|
||||||
|
})()" custom-class="w-fit" type="default">未开始</wd-tag>
|
||||||
<wd-tag custom-class="op-60" plain>
|
<wd-tag custom-class="op-60" plain>
|
||||||
共{{ courses.length }}节微课
|
共{{ courses.length }}节微课
|
||||||
</wd-tag>
|
</wd-tag>
|
||||||
@ -206,7 +250,13 @@ const getUsernameById = (userId: number) => {
|
|||||||
<div v-else class="i-tabler-hourglass-empty"></div>
|
<div v-else class="i-tabler-hourglass-empty"></div>
|
||||||
</div>
|
</div>
|
||||||
</wd-badge>
|
</wd-badge>
|
||||||
<span>{{ lesson.microLessonName || '无标题视频' }}</span>
|
<span>{{ lesson.microLessonName || '无标题微课' }}</span>
|
||||||
|
<wd-badge hidden is-dot :top="-10">
|
||||||
|
<span v-if="!user.hasRole('teacher') && getUsernameById(courses[0]?.userId)"
|
||||||
|
class=" text-xs text-gray-400 ml-2">
|
||||||
|
{{ getUsernameById(courses[0]?.userId) }}
|
||||||
|
</span>
|
||||||
|
</wd-badge>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-24 flex items-center gap-3">
|
<div class="w-24 flex items-center gap-3">
|
||||||
<wd-progress :percentage="calcLessonProgress(lesson)"
|
<wd-progress :percentage="calcLessonProgress(lesson)"
|
||||||
|
@ -8,6 +8,7 @@ import { calcLessonProgress, extractLessonStage, getLessonSteps } from '@/utils/
|
|||||||
import { useRoute, useRouter } from 'uni-mini-router';
|
import { useRoute, useRouter } from 'uni-mini-router';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useToast } from 'wot-design-uni';
|
import { useToast } from 'wot-design-uni';
|
||||||
|
import { onPullDownRefresh, onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -32,7 +33,7 @@ const goProgress = (lessonId: number) => {
|
|||||||
tabbar.activeTab = 'progress'
|
tabbar.activeTab = 'progress'
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
const loadLesson = async () => {
|
||||||
if (!route.params?.courseId) {
|
if (!route.params?.courseId) {
|
||||||
toast.error({
|
toast.error({
|
||||||
msg: '参数错误'
|
msg: '参数错误'
|
||||||
@ -48,7 +49,33 @@ onMounted(() => {
|
|||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
toast.error({ msg: err.message })
|
toast.error({ msg: err.message })
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadLesson()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
try {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: `/pages/lesson/index?courseId=${route.params?.courseId}`
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
} finally {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加下拉刷新处理函数
|
||||||
|
onPullDownRefresh(() => {
|
||||||
|
refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 页面加载时执行
|
||||||
|
onLoad(() => {
|
||||||
|
loadLesson()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -5,6 +5,7 @@ import { useTabbar } from '@/stores/useTabbar';
|
|||||||
import { useRouter } from 'uni-mini-router';
|
import { useRouter } from 'uni-mini-router';
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { useToast } from 'wot-design-uni';
|
import { useToast } from 'wot-design-uni';
|
||||||
|
import { onPullDownRefresh, onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
@ -58,6 +59,21 @@ const handleSubmit = () => {
|
|||||||
// console.log(error, 'error')
|
// console.log(error, 'error')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const refresh = async () => {
|
||||||
|
try {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/login/index'
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
} finally {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 添加下拉刷新处理函数
|
||||||
|
onPullDownRefresh(() => {
|
||||||
|
refresh()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -7,20 +7,33 @@ import { Jobs, Roles } from '@/types/api/user';
|
|||||||
import { useRouter } from 'uni-mini-router';
|
import { useRouter } from 'uni-mini-router';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { useToast } from 'wot-design-uni';
|
import { useToast } from 'wot-design-uni';
|
||||||
|
import { onPullDownRefresh, onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const userInfo = ref<User | null>(null)
|
const userInfo = ref<User | null>(null)
|
||||||
|
|
||||||
onMounted(() => {
|
const loadUserInfo = async () => {
|
||||||
toast.loading({
|
try {
|
||||||
msg: '加载中...'
|
toast.loading({
|
||||||
})
|
msg: '加载中...'
|
||||||
BussApi.profile(user.token!).then(res => {
|
})
|
||||||
|
const res = await BussApi.profile(user.token!)
|
||||||
toast.close()
|
toast.close()
|
||||||
user.userinfo = res
|
user.userinfo = res
|
||||||
})
|
userInfo.value = res
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.close()
|
||||||
|
toast.error(error.message || '获取用户信息失败')
|
||||||
|
if (error.response?.data?.code === 10001) {
|
||||||
|
router.replace('/pages/login/index')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadUserInfo()
|
||||||
})
|
})
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
@ -50,34 +63,39 @@ const departmentMap: Record<DepartmentId, string> = {
|
|||||||
|
|
||||||
// 角色映射
|
// 角色映射
|
||||||
const roleMap: Record<number, string> = {
|
const roleMap: Record<number, string> = {
|
||||||
[Roles.TEACHER]: '教师',
|
[Roles.TEACHER]: '校方教师',
|
||||||
[Roles.GENERAL_ADMIN]: '普通管理员',
|
[Roles.GENERAL_ADMIN]: '公司课程顾问',
|
||||||
[Roles.CONTACTOR]: '沟通联络人',
|
[Roles.CONTACTOR]: '校方项目负责人',
|
||||||
[Roles.SYSTEM_ADMIN]: '系统管理员',
|
[Roles.SYSTEM_ADMIN]: '公司系统管理员',
|
||||||
}
|
}
|
||||||
|
|
||||||
// 岗位映射
|
// 岗位映射
|
||||||
const jobMap: Record<number, string> = {
|
const jobMap: Record<number, string> = {
|
||||||
[Jobs.COURSE_TEACHER]: '课程制作教师',
|
[Jobs.COURSE_TEACHER]: '课程制作教师',
|
||||||
[Jobs.PROJECT_MANAGER]: '课程购买方项目负责人',
|
[Jobs.PROJECT_MANAGER]: '课程审核人员',
|
||||||
[Jobs.COURSE_CONTACTOR]: '课程制作方沟通联络人',
|
[Jobs.COURSE_CONTACTOR]: '校方项目负责人',
|
||||||
[Jobs.SYSTEM_MANAGER]: '系统制作方项目负责人',
|
[Jobs.SYSTEM_MANAGER]: '公司系统管理员',
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
const refresh = async () => {
|
||||||
toast.loading({
|
try {
|
||||||
msg: '加载中...'
|
uni.reLaunch({
|
||||||
})
|
url: '/pages/my/index'
|
||||||
BussApi.profile(user.token!).then(res => {
|
})
|
||||||
toast.close()
|
} catch (err) {
|
||||||
userInfo.value = res
|
} finally {
|
||||||
}).catch(error => {
|
uni.stopPullDownRefresh()
|
||||||
toast.close()
|
}
|
||||||
toast.error(error.message || '获取用户信息失败')
|
}
|
||||||
if (error.response?.data?.code === 10001) {
|
|
||||||
router.replace('/pages/login/index')
|
// 添加下拉刷新处理函数
|
||||||
}
|
onPullDownRefresh(() => {
|
||||||
})
|
refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 页面加载时执行
|
||||||
|
onLoad(() => {
|
||||||
|
loadUserInfo()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BussApi from '@/api/BussApi';
|
import BussApi from '@/api/BussApi';
|
||||||
import { useDayjs } from '@/composables/useDayjs';
|
|
||||||
import type { LessonTask, FileUploadDestination } from '@/types/api/lesson';
|
import type { LessonTask, FileUploadDestination } from '@/types/api/lesson';
|
||||||
import { extractLessonStage, getLessonSteps, getScriptFile, parseCombinedFileString } from '@/utils/lesson';
|
import { extractLessonStage, getLessonSteps } from '@/utils/lesson';
|
||||||
|
import { ProgressStatus } from '@/types/api/lesson';
|
||||||
import { computed, nextTick, onMounted, ref } from 'vue';
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||||
import { useMessage, useToast } from 'wot-design-uni';
|
import { useMessage, useToast } from 'wot-design-uni';
|
||||||
import StatusBlock from './StatusBlock.vue';
|
import StatusBlock from './StatusBlock.vue';
|
||||||
@ -12,8 +12,8 @@ import { onPullDownRefresh } from '@dcloudio/uni-app'
|
|||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
const message_reject = useMessage('wd-message-box-slot')
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const dayjs = useDayjs()
|
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
|
|
||||||
type GroupedLessons = { [key: string]: LessonTask[] }
|
type GroupedLessons = { [key: string]: LessonTask[] }
|
||||||
@ -32,7 +32,7 @@ const pickerLessonColumns = computed(() => {
|
|||||||
}) : []
|
}) : []
|
||||||
})
|
})
|
||||||
const pickerLessonValue = ref()
|
const pickerLessonValue = ref()
|
||||||
const adviseText = ref('')
|
const adviseText = ref<string>('')
|
||||||
|
|
||||||
const selectedLesson = computed(() => {
|
const selectedLesson = computed(() => {
|
||||||
if (!pickerLessonValue.value) return null
|
if (!pickerLessonValue.value) return null
|
||||||
@ -59,7 +59,7 @@ const onLessonPick = ({ value }: { value: number }) => {
|
|||||||
|
|
||||||
const script_file_destination = ref<FileUploadDestination>('wechat')
|
const script_file_destination = ref<FileUploadDestination>('wechat')
|
||||||
|
|
||||||
const onStep1 = () => {
|
const onStep0 = () => {
|
||||||
message.confirm({
|
message.confirm({
|
||||||
title: '提交脚本',
|
title: '提交脚本',
|
||||||
msg: '请确认已经通过微信或平台上传了脚本文件,再确认提交'
|
msg: '请确认已经通过微信或平台上传了脚本文件,再确认提交'
|
||||||
@ -74,12 +74,11 @@ const onStep1 = () => {
|
|||||||
msg: '正在提交...'
|
msg: '正在提交...'
|
||||||
})
|
})
|
||||||
const params = {
|
const params = {
|
||||||
// advise: adviseText.value,
|
advise: "",
|
||||||
// scriptUploadTime: dayjs().unix(),
|
|
||||||
courseName: selectedLesson.value.courseName,
|
courseName: selectedLesson.value.courseName,
|
||||||
microLessonName: selectedLesson.value.microLessonName,
|
microLessonName: selectedLesson.value.microLessonName,
|
||||||
userId: selectedLesson.value.userId,
|
userId: selectedLesson.value.userId,
|
||||||
progressStatus: 1
|
progressStatus: ProgressStatus.SCRIPT_CREATING//1
|
||||||
|
|
||||||
}
|
}
|
||||||
BussApi.updateLessonTask(selectedLesson.value.id, params).then(res => {
|
BussApi.updateLessonTask(selectedLesson.value.id, params).then(res => {
|
||||||
@ -95,11 +94,55 @@ const onStep1 = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const onStep1 = (rejected: boolean = false) => {
|
||||||
|
const msg = rejected ? message_reject : message
|
||||||
|
msg
|
||||||
|
.confirm({
|
||||||
|
title: rejected ? '驳回脚本' : '通过脚本',
|
||||||
|
msg: rejected ? '脚本不符合要求,驳回制作方重做' : '请确认脚本合格无误后,再确认审核通过'
|
||||||
|
}).then(() => {
|
||||||
|
if (!selectedLesson.value?.id) {
|
||||||
|
toast.error({
|
||||||
|
msg: '参数错误'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toast.loading({
|
||||||
|
msg: '正在处理...'
|
||||||
|
})
|
||||||
|
BussApi.updateLessonTask(
|
||||||
|
selectedLesson.value.id,
|
||||||
|
rejected ? {
|
||||||
|
advise: adviseText.value.toString(),
|
||||||
|
courseName: selectedLesson.value.courseName,
|
||||||
|
microLessonName: selectedLesson.value.microLessonName,
|
||||||
|
userId: selectedLesson.value.userId,
|
||||||
|
progressStatus: ProgressStatus.NOT_STARTED//0
|
||||||
|
} : {
|
||||||
|
advise: "",
|
||||||
|
courseName: selectedLesson.value.courseName,
|
||||||
|
microLessonName: selectedLesson.value.microLessonName,
|
||||||
|
userId: selectedLesson.value.userId,
|
||||||
|
progressStatus: ProgressStatus.SCRIPT_REVIEW//2
|
||||||
|
}).then(res => {
|
||||||
|
toast.success({
|
||||||
|
msg: rejected ? '驳回成功' : '审核通过'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
updateLessons()
|
||||||
|
}, 1500);
|
||||||
|
}).catch(err => {
|
||||||
|
toast.error({ msg: err.message })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const onStep2 = (rejected: boolean = false) => {
|
const onStep2 = (rejected: boolean = false) => {
|
||||||
console.log("adviseText.value: " + adviseText.value)
|
const msg = rejected ? message_reject : message
|
||||||
message.confirm({
|
msg.confirm({
|
||||||
title: rejected ? '驳回脚本' : '通过脚本',
|
title: rejected ? '驳回视频拍摄制作' : '通过视频拍摄制作',
|
||||||
msg: rejected ? '脚本不符合要求,驳回制作方重做' : '请确认脚本合格无误后,再确认审核通过'
|
msg: rejected ? '视频拍摄制作不符合要求,驳回拍摄制作方重做' : '请确认视频拍摄制作合格无误后,再确认审核通过'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (!selectedLesson.value?.id) {
|
if (!selectedLesson.value?.id) {
|
||||||
toast.error({
|
toast.error({
|
||||||
@ -114,18 +157,16 @@ const onStep2 = (rejected: boolean = false) => {
|
|||||||
selectedLesson.value.id,
|
selectedLesson.value.id,
|
||||||
rejected ? {
|
rejected ? {
|
||||||
advise: adviseText.value.toString(),
|
advise: adviseText.value.toString(),
|
||||||
// scriptUploadTime: 0,
|
|
||||||
courseName: selectedLesson.value.courseName,
|
courseName: selectedLesson.value.courseName,
|
||||||
microLessonName: selectedLesson.value.microLessonName,
|
microLessonName: selectedLesson.value.microLessonName,
|
||||||
userId: selectedLesson.value.userId,
|
userId: selectedLesson.value.userId,
|
||||||
progressStatus: 0
|
progressStatus: ProgressStatus.SCRIPT_CREATING//1
|
||||||
} : {
|
} : {
|
||||||
advise: adviseText.value.toString(),
|
advise: "",
|
||||||
// scriptConfirmTime: dayjs().unix(),
|
|
||||||
courseName: selectedLesson.value.courseName,
|
courseName: selectedLesson.value.courseName,
|
||||||
microLessonName: selectedLesson.value.microLessonName,
|
microLessonName: selectedLesson.value.microLessonName,
|
||||||
userId: selectedLesson.value.userId,
|
userId: selectedLesson.value.userId,
|
||||||
progressStatus: 2
|
progressStatus: ProgressStatus.SCRIPT_CONFIRMED//3
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
toast.success({
|
toast.success({
|
||||||
msg: rejected ? '驳回成功' : '审核通过'
|
msg: rejected ? '驳回成功' : '审核通过'
|
||||||
@ -140,10 +181,10 @@ const onStep2 = (rejected: boolean = false) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onStep3 = (rejected: boolean = false) => {
|
const onStep3 = (rejected: boolean = false) => {
|
||||||
console.log("adviseText.value: " + adviseText.value)
|
const msg = rejected ? message_reject : message
|
||||||
message.confirm({
|
msg.confirm({
|
||||||
title: rejected ? '驳回视频' : '通过视频',
|
title: rejected ? '驳回视频拍摄制作' : '通过视频拍摄制作',
|
||||||
msg: rejected ? '视频不符合要求,驳回制作方重做' : '请确认视频合格无误后,再确认审核通过'
|
msg: rejected ? '视频拍摄制作不符合要求,驳回拍摄制作方重做' : '请确认视频拍摄制作合格无误后,再确认审核通过'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (!selectedLesson.value?.id) {
|
if (!selectedLesson.value?.id) {
|
||||||
toast.error({
|
toast.error({
|
||||||
@ -158,62 +199,16 @@ const onStep3 = (rejected: boolean = false) => {
|
|||||||
selectedLesson.value.id,
|
selectedLesson.value.id,
|
||||||
rejected ? {
|
rejected ? {
|
||||||
advise: adviseText.value.toString(),
|
advise: adviseText.value.toString(),
|
||||||
// videoCaptureTime: 0,
|
|
||||||
courseName: selectedLesson.value.courseName,
|
courseName: selectedLesson.value.courseName,
|
||||||
microLessonName: selectedLesson.value.microLessonName,
|
microLessonName: selectedLesson.value.microLessonName,
|
||||||
userId: selectedLesson.value.userId,
|
userId: selectedLesson.value.userId,
|
||||||
progressStatus: 1
|
progressStatus: ProgressStatus.VIDEO_CONFIRMED
|
||||||
} : {
|
} : {
|
||||||
advise: adviseText.value.toString(),
|
advise: "",
|
||||||
// videoConfirmTime: dayjs().unix(),
|
|
||||||
courseName: selectedLesson.value.courseName,
|
courseName: selectedLesson.value.courseName,
|
||||||
microLessonName: selectedLesson.value.microLessonName,
|
microLessonName: selectedLesson.value.microLessonName,
|
||||||
userId: selectedLesson.value.userId,
|
userId: selectedLesson.value.userId,
|
||||||
progressStatus: 3
|
progressStatus: ProgressStatus.VIDEO_CONFIRMED
|
||||||
}).then(res => {
|
|
||||||
toast.success({
|
|
||||||
msg: rejected ? '驳回成功' : '审核通过'
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
updateLessons()
|
|
||||||
}, 1500);
|
|
||||||
}).catch(err => {
|
|
||||||
toast.error({ msg: err.message })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const onPostProduction = (rejected: boolean = false) => {
|
|
||||||
console.log("adviseText.value: " + adviseText.value)
|
|
||||||
message.confirm({
|
|
||||||
title: rejected ? '驳回后期制作' : '通过后期制作',
|
|
||||||
msg: rejected ? '后期制作不符合要求,驳回制作方重做' : '请确认后期制作合格无误后,再确认审核通过'
|
|
||||||
}).then(() => {
|
|
||||||
if (!selectedLesson.value?.id) {
|
|
||||||
toast.error({
|
|
||||||
msg: '参数错误'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
toast.loading({
|
|
||||||
msg: '正在处理...'
|
|
||||||
})
|
|
||||||
BussApi.updateLessonTask(
|
|
||||||
selectedLesson.value.id,
|
|
||||||
rejected ? {
|
|
||||||
advise: adviseText.value.toString(),
|
|
||||||
// videoCaptureTime: 0,
|
|
||||||
courseName: selectedLesson.value.courseName,
|
|
||||||
microLessonName: selectedLesson.value.microLessonName,
|
|
||||||
userId: selectedLesson.value.userId,
|
|
||||||
progressStatus: 2
|
|
||||||
} : {
|
|
||||||
advise: adviseText.value.toString(),
|
|
||||||
// videoConfirmTime: dayjs().unix(),
|
|
||||||
courseName: selectedLesson.value.courseName,
|
|
||||||
microLessonName: selectedLesson.value.microLessonName,
|
|
||||||
userId: selectedLesson.value.userId,
|
|
||||||
progressStatus: 4
|
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
toast.success({
|
toast.success({
|
||||||
msg: rejected ? '驳回成功' : '审核通过'
|
msg: rejected ? '驳回成功' : '审核通过'
|
||||||
@ -286,16 +281,17 @@ const updateLessons = async () => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
updateLessons()
|
updateLessons()
|
||||||
})
|
})
|
||||||
|
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
try {
|
try {
|
||||||
await updateLessons()
|
uni.reLaunch({
|
||||||
|
url: '/pages/progress/index'
|
||||||
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
} finally {
|
} finally {
|
||||||
// 停止下拉刷新动画
|
|
||||||
uni.stopPullDownRefresh()
|
uni.stopPullDownRefresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加下拉刷新处理函数
|
// 添加下拉刷新处理函数
|
||||||
onPullDownRefresh(() => {
|
onPullDownRefresh(() => {
|
||||||
refresh()
|
refresh()
|
||||||
@ -310,6 +306,10 @@ onPullDownRefresh(() => {
|
|||||||
<wd-picker :columns="pickerLessonColumns" label="微课选择" v-model="pickerLessonValue" @confirm="onLessonPick"
|
<wd-picker :columns="pickerLessonColumns" label="微课选择" v-model="pickerLessonValue" @confirm="onLessonPick"
|
||||||
:columns-height="280" label-width="80px" safe-area-inset-bottom title="微课选择" :disabled="!pickerCourseValue" />
|
:columns-height="280" label-width="80px" safe-area-inset-bottom title="微课选择" :disabled="!pickerCourseValue" />
|
||||||
</div>
|
</div>
|
||||||
|
<wd-message-box selector="wd-message-box-slot">
|
||||||
|
<wd-textarea v-model="adviseText" type="text" clear-trigger="focus" clearable auto-height show-word-limit
|
||||||
|
:focus-when-clear="false" :maxlength="100" placeholder="请输入审核建议..." block />
|
||||||
|
</wd-message-box>
|
||||||
<div class="p-2 pt-4">
|
<div class="p-2 pt-4">
|
||||||
<wd-status-tip v-if="!pickerLessonValue" image="search" tip="请先选择微课" />
|
<wd-status-tip v-if="!pickerLessonValue" image="search" tip="请先选择微课" />
|
||||||
<div v-else class="space-y-6">
|
<div v-else class="space-y-6">
|
||||||
@ -322,6 +322,11 @@ onPullDownRefresh(() => {
|
|||||||
|
|
||||||
<div v-if="selectedLessonStage?.step === 0" class="px-2">
|
<div v-if="selectedLessonStage?.step === 0" class="px-2">
|
||||||
<div v-if="user.hasRole('teacher')">
|
<div v-if="user.hasRole('teacher')">
|
||||||
|
<div v-if="selectedLesson?.advise && selectedLesson.advise.length > 0" class=" m-2 text-sm">
|
||||||
|
<wd-card title="修改建议">
|
||||||
|
{{ selectedLesson?.advise }}
|
||||||
|
</wd-card>
|
||||||
|
</div>
|
||||||
<wd-cell-group>
|
<wd-cell-group>
|
||||||
<wd-cell title="脚本提交途径" :title-width="'100px'" center custom-class="mb-4">
|
<wd-cell title="脚本提交途径" :title-width="'100px'" center custom-class="mb-4">
|
||||||
<wd-radio-group v-model="script_file_destination" shape="button">
|
<wd-radio-group v-model="script_file_destination" shape="button">
|
||||||
@ -331,11 +336,11 @@ onPullDownRefresh(() => {
|
|||||||
</wd-radio-group>
|
</wd-radio-group>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
</wd-cell-group>
|
</wd-cell-group>
|
||||||
<wd-button type="primary" block @click="onStep1" custom-class="w-full">提交脚本</wd-button>
|
<wd-button type="primary" block @click="onStep0" custom-class="w-full">提交脚本</wd-button>
|
||||||
</div>
|
</div>
|
||||||
<StatusBlock v-else title="脚本还未提交" subtitle="请耐心等待审核">
|
<StatusBlock v-else title="脚本还未提交" subtitle="请耐心等待提交">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<div class="i-tabler-progress-bolt text-7xl text-neutral-400"></div>
|
<div class="i-tabler-file-upload text-7xl text-neutral-400"></div>
|
||||||
</template>
|
</template>
|
||||||
</StatusBlock>
|
</StatusBlock>
|
||||||
</div>
|
</div>
|
||||||
@ -343,45 +348,91 @@ onPullDownRefresh(() => {
|
|||||||
<div v-if="selectedLessonStage?.step === 1">
|
<div v-if="selectedLessonStage?.step === 1">
|
||||||
<StatusBlock v-if="user.hasRole('teacher')" title="脚本已提交" subtitle="请耐心等待审核">
|
<StatusBlock v-if="user.hasRole('teacher')" title="脚本已提交" subtitle="请耐心等待审核">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<div class="i-tabler-progress-bolt text-7xl text-neutral-400"></div>
|
<div class="i-tabler-progress-bolt text-7xl text-neutral-400 "></div>
|
||||||
</template>
|
</template>
|
||||||
</StatusBlock>
|
</StatusBlock>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<StatusBlock title="脚本处理已完成" subtitle="请核对并审核">
|
<div v-if="selectedLesson?.advise && selectedLesson.advise.length > 0" class=" m-2 text-sm">
|
||||||
|
<wd-card title="修改建议">
|
||||||
|
{{ selectedLesson?.advise }}
|
||||||
|
</wd-card>
|
||||||
|
</div>
|
||||||
|
<StatusBlock title="脚本制作已完成" subtitle="请核对并审核">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<div class="i-tabler-progress-check text-7xl text-neutral-400"></div>
|
<div class="i-tabler-progress-check text-7xl text-neutral-400"></div>
|
||||||
</template>
|
</template>
|
||||||
</StatusBlock>
|
</StatusBlock>
|
||||||
<div class="mt-4 space-y-4">
|
<div class="mt-4 space-y-4">
|
||||||
<div class="bg-neutral000 rounded-lg px-4 py-3">
|
|
||||||
<wd-input v-model="adviseText" title="审核建议" type="text" show-clear show-word-limit :maxlength="50"
|
|
||||||
placeholder="请输入审核建议..." block />
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-3 px-4">
|
<div class="flex gap-3 px-4">
|
||||||
<wd-button type="primary" block @click="onStep2()">通过</wd-button>
|
<wd-button type="primary" block @click="onStep1()">确认</wd-button>
|
||||||
<wd-button type="error" block @click="onStep2(true)">驳回</wd-button>
|
<wd-button type="error" block @click="onStep1(true)">驳回</wd-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedLessonStage?.step === 2">
|
<div v-if="selectedLessonStage?.step === 2">
|
||||||
<StatusBlock v-if="user.hasRole('teacher')" title="视频拍摄进行中" subtitle="请等待线下视频拍摄">
|
<StatusBlock v-if="!user.hasRole('teacher')" title="脚本确认进行中" subtitle="请等待脚本内容确认">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<div class="i-tabler-capture text-7xl text-neutral-400"></div>
|
<div class="i-tabler-file-text text-7xl text-neutral-400"></div>
|
||||||
</template>
|
</template>
|
||||||
</StatusBlock>
|
</StatusBlock>
|
||||||
<!-- && selectedLesson && selectedLesson?.videoCaptureTime > 0 -->
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<StatusBlock title="视频拍摄已完成" subtitle="请核对后审核">
|
<StatusBlock title="脚本审核已完成" subtitle="请确认脚本内容">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<div class="i-tabler-capture-filled text-7xl text-neutral-400"></div>
|
<div class="i-tabler-file-text text-7xl text-neutral-400"></div>
|
||||||
|
</template>
|
||||||
|
</StatusBlock>
|
||||||
|
</div>
|
||||||
|
<div v-if="user.hasRole('teacher')" class="mt-4 space-y-4">
|
||||||
|
<div class="flex gap-3 px-4">
|
||||||
|
<wd-button type="primary" block @click="onStep2()">确认</wd-button>
|
||||||
|
<wd-button type="error" block @click="onStep2(true)">驳回</wd-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="selectedLessonStage?.step === 3">
|
||||||
|
<StatusBlock v-if="user.hasRole('teacher')" title="视频拍摄制作进行中" subtitle="请等待视频拍摄制作">
|
||||||
|
<template #icon>
|
||||||
|
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
||||||
|
</template>
|
||||||
|
</StatusBlock>
|
||||||
|
<div v-else>
|
||||||
|
<StatusBlock title="视频拍摄制作进行中" subtitle="完成后请确认">
|
||||||
|
<template #icon>
|
||||||
|
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
||||||
</template>
|
</template>
|
||||||
</StatusBlock>
|
</StatusBlock>
|
||||||
<div class="mt-4 space-y-4">
|
<div class="mt-4 space-y-4">
|
||||||
<div class="bg-neutral000 rounded-lg px-4 py-3">
|
<div class="bg-neutral000 rounded-lg px-4 py-3">
|
||||||
<wd-input v-model="adviseText" title="审核建议" type="text" show-clear show-word-limit :maxlength="50"
|
<wd-textarea v-model="adviseText" title="审核建议" type="text" clear-trigger="focus" clearable auto-height
|
||||||
placeholder="请输入审核建议..." block />
|
show-word-limit :focus-when-clear="false" :maxlength="100" placeholder="请输入审核建议..." block />
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3 px-4 center">
|
||||||
|
<wd-button type="primary" block @click="onStep3()">通过</wd-button>
|
||||||
|
<!-- <wd-button type="error" block @click="onStep3(true)">驳回</wd-button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="selectedLessonStage?.step === 4">
|
||||||
|
<StatusBlock v-if="user.hasRole('teacher')" title="视频拍摄制作进行中" subtitle="请等待视频拍摄制作">
|
||||||
|
<template #icon>
|
||||||
|
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
||||||
|
</template>
|
||||||
|
</StatusBlock>
|
||||||
|
<div v-else>
|
||||||
|
<StatusBlock title="视频拍摄制作进行中" subtitle="完成后请确认">
|
||||||
|
<template #icon>
|
||||||
|
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
||||||
|
</template>
|
||||||
|
</StatusBlock>
|
||||||
|
<div class="mt-4 space-y-4">
|
||||||
|
<div class="bg-neutral000 rounded-lg px-4 py-3">
|
||||||
|
<wd-textarea v-model="adviseText" title="审核建议" type="text" clear-trigger="focus" clearable auto-height
|
||||||
|
show-word-limit :focus-when-clear="false" :maxlength="100" placeholder="请输入审核建议..." block />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-3 px-4">
|
<div class="flex gap-3 px-4">
|
||||||
<wd-button type="primary" block @click="onStep3()">通过</wd-button>
|
<wd-button type="primary" block @click="onStep3()">通过</wd-button>
|
||||||
@ -390,32 +441,8 @@ onPullDownRefresh(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedLessonStage?.step === 3">
|
|
||||||
<StatusBlock v-if="user.hasRole('teacher')" title="后期制作进行中" subtitle="请等待视频后期制作">
|
<div v-else-if="selectedLessonStage?.step === 5">
|
||||||
<template #icon>
|
|
||||||
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
|
||||||
</template>
|
|
||||||
</StatusBlock>
|
|
||||||
<!-- && selectedLesson && selectedLesson?.videoPostProductionTime > 0 -->
|
|
||||||
<div v-else>
|
|
||||||
<StatusBlock title="后期制作已完成" subtitle="请核对后审核">
|
|
||||||
<template #icon>
|
|
||||||
<div class="i-tabler-video text-7xl text-neutral-400"></div>
|
|
||||||
</template>
|
|
||||||
</StatusBlock>
|
|
||||||
<div class="mt-4 space-y-4">
|
|
||||||
<div class="bg-neutral000 rounded-lg px-4 py-3">
|
|
||||||
<wd-input v-model="adviseText" title="审核建议" type="text" show-clear show-word-limit :maxlength="50"
|
|
||||||
placeholder="请输入审核建议..." block />
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-3 px-4">
|
|
||||||
<wd-button type="primary" block @click="onPostProduction()">通过</wd-button>
|
|
||||||
<wd-button type="error" block @click="onPostProduction(true)">驳回</wd-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="selectedLessonStage?.step === 4">
|
|
||||||
<wd-status-tip image="comment" tip="该微课已完成" />
|
<wd-status-tip image="comment" tip="该微课已完成" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,9 +34,9 @@ export const useUser = defineStore("user", () => {
|
|||||||
|
|
||||||
const jobMap = {
|
const jobMap = {
|
||||||
teacher: 1, // 课程制作教师
|
teacher: 1, // 课程制作教师
|
||||||
projectManager: 2, // 课程购买方项目负责人
|
projectManager: 2, // 课程审核人员
|
||||||
liaison: 3, // 课程制作方沟通联络人
|
liaison: 3, // 校方项目负责人
|
||||||
sysManager: 4 // 系统制作方项目负责人
|
sysManager: 4 // 公司系统管理员
|
||||||
};
|
};
|
||||||
|
|
||||||
return userinfo.value.jobs === jobMap[job];
|
return userinfo.value.jobs === jobMap[job];
|
||||||
|
@ -12,13 +12,15 @@ export interface LessonTask {
|
|||||||
userId: number;
|
userId: number;
|
||||||
/** 进度状态 */
|
/** 进度状态 */
|
||||||
progressStatus: number;
|
progressStatus: number;
|
||||||
/** 脚本上传时间(时间戳) */
|
/** 脚本开始制作时间(时间戳) */
|
||||||
scriptUploadTime?: number;
|
scriptCreateTime?: number;
|
||||||
/** 脚本确认时间(时间戳) */
|
/** 脚本提交审核时间(时间戳) */
|
||||||
|
scriptReviewTime?: number;
|
||||||
|
/** 脚本审核通过时间(时间戳) */
|
||||||
scriptConfirmTime?: number;
|
scriptConfirmTime?: number;
|
||||||
/** 视频拍摄时间(时间戳) */
|
/** 开始视频制作时间(时间戳) */
|
||||||
videoCaptureTime?: number;
|
videoCreateTime?: number;
|
||||||
/** 视频确认时间(时间戳) */
|
/** 视频审核通过时间(时间戳) */
|
||||||
videoConfirmTime?: number;
|
videoConfirmTime?: number;
|
||||||
/** 任务完成时间(时间戳) */
|
/** 任务完成时间(时间戳) */
|
||||||
finishTime?: number;
|
finishTime?: number;
|
||||||
@ -41,13 +43,22 @@ export interface LessonTaskPagination {
|
|||||||
empty: boolean;
|
empty: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT_STARTED = 0, // 脚本制作
|
||||||
|
SCRIPT_CREATING = 1, // 脚本审核
|
||||||
|
SCRIPT_REVIEW = 2, // 脚本审核
|
||||||
|
SCRIPT_CONFIRMED = 3, // 视频拍摄与制作
|
||||||
|
VIDEO_CREATING = 4, // 视频确认
|
||||||
|
VIDEO_CONFIRMED = 5 // 任务完成
|
||||||
|
*/
|
||||||
// 进度状态枚举
|
// 进度状态枚举
|
||||||
export enum ProgressStatus {
|
export enum ProgressStatus {
|
||||||
SCRIPT_UPLOAD = 0, // 脚本上传
|
NOT_STARTED = 0, // 脚本制作
|
||||||
SCRIPT_CONFIRM = 1, // 脚本确认
|
SCRIPT_CREATING = 1, // 脚本审核
|
||||||
VIDEO_CAPTURE = 2, // 视频拍摄
|
SCRIPT_REVIEW = 2, // 脚本审核
|
||||||
POST_PRODUCTION = 3, // 后期制作
|
SCRIPT_CONFIRMED = 3, // 视频拍摄与制作
|
||||||
FINISHED = 4, // 任务完成
|
VIDEO_CREATING = 4, // 视频确认
|
||||||
|
VIDEO_CONFIRMED = 5 // 任务完成
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FileUploadDestination = "qq" | "wechat" | "platform";
|
export type FileUploadDestination = "qq" | "wechat" | "platform";
|
||||||
@ -78,15 +89,17 @@ export interface UpdateLessonTaskRequest {
|
|||||||
userId?: number;
|
userId?: number;
|
||||||
/** 进度状态 */
|
/** 进度状态 */
|
||||||
progressStatus?: number;
|
progressStatus?: number;
|
||||||
/** 脚本上传时间 */
|
/** 脚本开始制作时间 */
|
||||||
scriptUploadTime?: number;
|
scriptCreateTime?: number;
|
||||||
/** 脚本确认时间 */
|
/** 脚本提交审核时间 */
|
||||||
|
scriptReviewTime?: number;
|
||||||
|
/** 脚本审核通过时间 */
|
||||||
scriptConfirmTime?: number;
|
scriptConfirmTime?: number;
|
||||||
/** 视频拍摄时间 */
|
/** 开始视频制作时间 */
|
||||||
videoCaptureTime?: number;
|
videoCreateTime?: number;
|
||||||
/** 视频确认时间 */
|
/** 视频审核通过时间 */
|
||||||
videoConfirmTime?: number;
|
videoConfirmTime?: number;
|
||||||
/** 完成时间 */
|
/** 任务完成时间 */
|
||||||
finishTime?: number;
|
finishTime?: number;
|
||||||
/** 建议信息 */
|
/** 建议信息 */
|
||||||
advise?: string;
|
advise?: string;
|
||||||
|
@ -20,18 +20,18 @@ export interface Authority {
|
|||||||
|
|
||||||
// 角色枚举
|
// 角色枚举
|
||||||
export enum Roles {
|
export enum Roles {
|
||||||
TEACHER = 1, // 教师
|
TEACHER = 1, // 校方教师
|
||||||
GENERAL_ADMIN = 2, // 普通管理员
|
GENERAL_ADMIN = 2, // 公司课程顾问
|
||||||
CONTACTOR = 3, // 沟通联络人
|
CONTACTOR = 3, // 校方项目负责人
|
||||||
SYSTEM_ADMIN = 4 // 系统管理员
|
SYSTEM_ADMIN = 4 // 公司系统管理员
|
||||||
}
|
}
|
||||||
|
|
||||||
// 岗位枚举
|
// 岗位枚举
|
||||||
export enum Jobs {
|
export enum Jobs {
|
||||||
COURSE_TEACHER = 1, // 课程制作教师
|
COURSE_TEACHER = 1, // 课程制作教师
|
||||||
PROJECT_MANAGER = 2, // 课程购买方项目负责人
|
PROJECT_MANAGER = 2, // 课程审核人员
|
||||||
COURSE_CONTACTOR = 3, // 课程制作方沟通联络人
|
COURSE_CONTACTOR = 3, // 校方项目负责人
|
||||||
SYSTEM_MANAGER = 4 // 系统制作方项目负责人
|
SYSTEM_MANAGER = 4 // 公司系统管理员
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户状态枚举
|
// 用户状态枚举
|
||||||
|
@ -2,14 +2,16 @@ import { useDayjs } from "@/composables/useDayjs";
|
|||||||
import type { FileUploadDestination,LessonTask } from "@/types/api/lesson";
|
import type { FileUploadDestination,LessonTask } from "@/types/api/lesson";
|
||||||
|
|
||||||
export const extractLessonStage = (lesson: LessonTask) => {
|
export const extractLessonStage = (lesson: LessonTask) => {
|
||||||
|
const currentStep = lesson?.progressStatus || 0;
|
||||||
const stages = {
|
const stages = {
|
||||||
script_upload: !!lesson?.scriptUploadTime,
|
script_creating: currentStep >= 1, // 脚本制作
|
||||||
script_confirm: !!lesson?.scriptConfirmTime,
|
script_review: currentStep >= 2, // 脚本审核
|
||||||
video_capture: !!lesson?.videoCaptureTime,
|
script_confirmed: currentStep >= 3, // 脚本确认
|
||||||
post_production: !!lesson?.videoConfirmTime,
|
video_creating: currentStep >= 4, // 视频制作
|
||||||
|
video_confirmed: currentStep >= 5, // 视频确认
|
||||||
step: 0,
|
step: 0,
|
||||||
};
|
};
|
||||||
stages.step = Object.values(stages).filter((v) => v).length;
|
stages.step = currentStep;
|
||||||
return stages;
|
return stages;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -17,18 +19,19 @@ export const calcLessonProgress = (lesson: LessonTask) => {
|
|||||||
if (!lesson) return 0;
|
if (!lesson) return 0;
|
||||||
|
|
||||||
// 根据 progressStatus 计算进度
|
// 根据 progressStatus 计算进度
|
||||||
// 0-脚本上传, 1-脚本确认, 2-视频拍摄, 3-后期制作, 4-任务完成
|
// 0-未开始, 1-脚本制作, 2-脚本审核, 3-脚本确认, 4-视频拍摄与制作, 5-视频确认
|
||||||
switch (lesson.progressStatus) {
|
switch (lesson.progressStatus) {
|
||||||
case 4: // 任务完成
|
case 5: // 视频确认
|
||||||
return 100;
|
return 100;
|
||||||
case 3: // 后期制作
|
case 4: // 视频拍摄与制作
|
||||||
return 75;
|
return 80;
|
||||||
case 2: // 视频拍摄
|
case 3: // 脚本确认
|
||||||
return 50;
|
return 60;
|
||||||
case 1: // 脚本确认
|
case 2: // 脚本审核
|
||||||
return 25;
|
return 40;
|
||||||
case 0: // 脚本上传
|
case 1: // 脚本制作
|
||||||
return 0;
|
return 20;
|
||||||
|
case 0: // 未开始
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -40,79 +43,51 @@ export const getLessonSteps = (lesson: LessonTask, simplify: boolean = false) =>
|
|||||||
const progress = extractLessonStage(lesson);
|
const progress = extractLessonStage(lesson);
|
||||||
|
|
||||||
const formatTime = (timestamp?: number | null) => {
|
const formatTime = (timestamp?: number | null) => {
|
||||||
if (!timestamp) return '-';
|
if (!timestamp || isNaN(timestamp) || timestamp <= 0) return '-';
|
||||||
return dayjs(timestamp * 1000).format(dateFormat);
|
const date = dayjs(timestamp * 1000);
|
||||||
|
return date.isValid() ? date.format(dateFormat) : '-';
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: progress.script_upload ? "脚本提交" : undefined,
|
title: progress.script_creating ? "脚本制作" : undefined,
|
||||||
description: progress.script_upload
|
description: progress.script_creating
|
||||||
? simplify
|
? simplify
|
||||||
? "已完成"
|
? "已完成"
|
||||||
: `已于 ${formatTime(lesson.scriptUploadTime)} 完成上传`
|
: `已于 ${formatTime(lesson.scriptCreateTime)} 完成脚本制作`
|
||||||
: "脚本文件提交",
|
: "开始制作脚本",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: progress.script_confirm ? "脚本确认" : undefined,
|
title: progress.script_review ? "脚本审核" : undefined,
|
||||||
description: progress.script_confirm
|
description: progress.script_review
|
||||||
? simplify
|
? simplify
|
||||||
? "已完成"
|
? "已完成"
|
||||||
: `已于 ${formatTime(lesson.scriptConfirmTime)} 完成确认`
|
: `已于 ${formatTime(lesson.scriptReviewTime)} 完成脚本审核`
|
||||||
: "脚本文件确认",
|
: "提交脚本审核",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: progress.video_capture ? "视频拍摄" : undefined,
|
title: progress.script_confirmed ? "脚本确认" : undefined,
|
||||||
description: progress.video_capture
|
description: progress.script_confirmed
|
||||||
? simplify
|
? simplify
|
||||||
? "已完成"
|
? "已完成"
|
||||||
: `已于 ${formatTime(lesson.videoCaptureTime)} 完成上传`
|
: `已于 ${formatTime(lesson.scriptConfirmTime)} 完成脚本确认`
|
||||||
: "视频拍摄提交",
|
: "确认脚本内容",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: progress.post_production ? "后期制作" : undefined,
|
title: progress.video_creating ? "视频拍摄制作" : undefined,
|
||||||
description: progress.post_production
|
description: progress.video_creating
|
||||||
? simplify
|
? simplify
|
||||||
? "已完成"
|
? "已完成"
|
||||||
: `已于 ${formatTime(lesson.videoConfirmTime)} 完成上传`
|
: `已于 ${formatTime(lesson.videoCreateTime)} 完成拍摄制作`
|
||||||
: "视频后期制作",
|
: "视频拍摄制作",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: progress.video_confirmed ? "视频确认" : undefined,
|
||||||
|
description: progress.video_confirmed
|
||||||
|
? simplify
|
||||||
|
? "已完成"
|
||||||
|
: `已于 ${formatTime(lesson.videoConfirmTime)} 完成视频确认`
|
||||||
|
: "确认视频内容",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getScriptFile = (lesson: LessonTask) => {
|
|
||||||
const scriptFile = lesson.script_file ? lesson.script_file.split("|") : [];
|
|
||||||
return {
|
|
||||||
way: scriptFile[0] || null,
|
|
||||||
reupload: scriptFile[1] || null,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const parseCombinedFileString = (
|
|
||||||
lesson: LessonTask,
|
|
||||||
// key: keyof Pick<LessonTask, "script_file" | "capture_file" | "material_file">
|
|
||||||
key: keyof Pick<LessonTask, "advise">
|
|
||||||
): {
|
|
||||||
method: FileUploadDestination | undefined;
|
|
||||||
uploaded: boolean;
|
|
||||||
} => {
|
|
||||||
const value = lesson[key];
|
|
||||||
if (!value) {
|
|
||||||
return {
|
|
||||||
method: undefined,
|
|
||||||
uploaded: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(value);
|
|
||||||
return {
|
|
||||||
method: (parsed.method as FileUploadDestination) || undefined,
|
|
||||||
uploaded: !!parsed.uploaded,
|
|
||||||
};
|
|
||||||
} catch {
|
|
||||||
return {
|
|
||||||
method: undefined,
|
|
||||||
uploaded: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
143
数据库.md
143
数据库.md
@ -15,7 +15,8 @@ CREATE TABLE departments (
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 字段说明
|
### 字段说明
|
||||||
- `id`: 部门ID,自增主键
|
|
||||||
|
- `id`: 部门 ID,自增主键
|
||||||
- `name`: 部门名称,不可为空
|
- `name`: 部门名称,不可为空
|
||||||
- `description`: 部门描述,可为空
|
- `description`: 部门描述,可为空
|
||||||
- `created_at`: 创建时间,毫秒级时间戳
|
- `created_at`: 创建时间,毫秒级时间戳
|
||||||
@ -32,8 +33,8 @@ CREATE TABLE users (
|
|||||||
email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
|
email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
|
||||||
password VARCHAR(100) NOT NULL COMMENT '密码',
|
password VARCHAR(100) NOT NULL COMMENT '密码',
|
||||||
department_id BIGINT NOT NULL COMMENT '所属部门',
|
department_id BIGINT NOT NULL COMMENT '所属部门',
|
||||||
roles INT NOT NULL COMMENT '角色: 1-教师, 2-普通管理员, 3-沟通联络人, 4-系统管理员',
|
roles INT NOT NULL COMMENT '角色: 1-校方教师, 2-公司课程顾问, 3-校方项目负责人, 4-公司系统管理员',
|
||||||
jobs INT NOT NULL COMMENT '岗位: 1-课程制作教师, 2-课程购买方项目负责人, 3-课程制作方沟通联络人, 4-系统制作方项目负责人',
|
jobs INT NOT NULL COMMENT '岗位: 1-课程制作教师, 2-课程审核人员, 3-校方项目负责人, 4-公司系统管理员',
|
||||||
avatar VARCHAR(255) DEFAULT NULL COMMENT '头像',
|
avatar VARCHAR(255) DEFAULT NULL COMMENT '头像',
|
||||||
creator_id BIGINT NOT NULL DEFAULT 1 COMMENT '创建用户的管理员ID',
|
creator_id BIGINT NOT NULL DEFAULT 1 COMMENT '创建用户的管理员ID',
|
||||||
status INT NOT NULL DEFAULT 1 COMMENT '用户状态: 1-正常, 0-禁用',
|
status INT NOT NULL DEFAULT 1 COMMENT '用户状态: 1-正常, 0-禁用',
|
||||||
@ -45,11 +46,12 @@ CREATE TABLE users (
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 字段说明
|
### 字段说明
|
||||||
- `id`: 用户ID,自增主键
|
|
||||||
|
- `id`: 用户 ID,自增主键
|
||||||
- `username`: 用户名,不可为空
|
- `username`: 用户名,不可为空
|
||||||
- `email`: 邮箱地址,不可为空,唯一索引
|
- `email`: 邮箱地址,不可为空,唯一索引
|
||||||
- `password`: 密码(加密存储),不可为空
|
- `password`: 密码(加密存储),不可为空
|
||||||
- `department_id`: 所属部门ID,外键关联departments表
|
- `department_id`: 所属部门 ID,外键关联 departments 表
|
||||||
- `roles`: 用户角色,整数枚举:
|
- `roles`: 用户角色,整数枚举:
|
||||||
- 1: 教师
|
- 1: 教师
|
||||||
- 2: 普通管理员
|
- 2: 普通管理员
|
||||||
@ -60,8 +62,8 @@ CREATE TABLE users (
|
|||||||
- 2: 课程购买方项目负责人
|
- 2: 课程购买方项目负责人
|
||||||
- 3: 课程制作方沟通联络人
|
- 3: 课程制作方沟通联络人
|
||||||
- 4: 系统制作方项目负责人
|
- 4: 系统制作方项目负责人
|
||||||
- `avatar`: 用户头像URL,可为空
|
- `avatar`: 用户头像 URL,可为空
|
||||||
- `creator_id`: 创建该用户的管理员ID
|
- `creator_id`: 创建该用户的管理员 ID
|
||||||
- `status`: 用户状态:
|
- `status`: 用户状态:
|
||||||
- 1: 正常
|
- 1: 正常
|
||||||
- 0: 禁用
|
- 0: 禁用
|
||||||
@ -69,6 +71,7 @@ CREATE TABLE users (
|
|||||||
- `updated_at`: 更新时间,毫秒级时间戳
|
- `updated_at`: 更新时间,毫秒级时间戳
|
||||||
|
|
||||||
### 索引
|
### 索引
|
||||||
|
|
||||||
- 主键索引:`id`
|
- 主键索引:`id`
|
||||||
- 外键索引:`idx_users_department_id (department_id)`
|
- 外键索引:`idx_users_department_id (department_id)`
|
||||||
- 唯一索引:`email`
|
- 唯一索引:`email`
|
||||||
@ -78,68 +81,114 @@ CREATE TABLE users (
|
|||||||
存储课程制作任务的信息和进度。
|
存储课程制作任务的信息和进度。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE lesson_tasks (
|
CREATE TABLE lesson_tasks
|
||||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
(
|
||||||
course_name VARCHAR(100) NOT NULL COMMENT '课程名称',
|
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID,系统自动生成的唯一标识',
|
||||||
micro_lesson_name VARCHAR(100) NOT NULL COMMENT '微课名称',
|
course_name VARCHAR(100) NOT NULL COMMENT '所属课程名称,标识任务所属的主课程',
|
||||||
user_id BIGINT NOT NULL COMMENT '负责人ID',
|
micro_lesson_name VARCHAR(100) NOT NULL COMMENT '具体微课名称,标识任务所属的具体微课单元',
|
||||||
progress_status INT NOT NULL DEFAULT 0 COMMENT '当前任务进度状态: 0-脚本上传, 1-脚本确认, 2-视频拍摄, 3-后期制作, 4-任务完成',
|
user_id BIGINT NOT NULL COMMENT '任务负责人ID,关联users表的主键id',
|
||||||
script_upload_time BIGINT DEFAULT NULL COMMENT '脚本上传时间(时间戳)',
|
progress_status INT NOT NULL DEFAULT 0 COMMENT '任务进度状态:
|
||||||
script_confirm_time BIGINT DEFAULT NULL COMMENT '脚本确认时间(时间戳)',
|
0-未开始:任务创建后的初始状态
|
||||||
video_capture_time BIGINT DEFAULT NULL COMMENT '视频拍摄时间(时间戳)',
|
1-脚本制作:正在编写课程脚本
|
||||||
video_confirm_time BIGINT DEFAULT NULL COMMENT '视频确认时间(时间戳)',
|
2-脚本审核:脚本提交审核阶段
|
||||||
finish_time BIGINT DEFAULT NULL COMMENT '任务完成时间(时间戳)',
|
3-脚本确认:脚本审核通过确认
|
||||||
advise TEXT DEFAULT NULL COMMENT '任务建议或备注',
|
4-视频拍摄与制作:进行视频录制和后期制作
|
||||||
created_at BIGINT NOT NULL COMMENT '创建时间(时间戳)',
|
5-视频确认:最终视频审核确认',
|
||||||
updated_at BIGINT NOT NULL COMMENT '更新时间(时间戳)',
|
script_create_time BIGINT DEFAULT NULL COMMENT '脚本开始制作的时间戳,状态1时记录',
|
||||||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
|
script_review_time BIGINT DEFAULT NULL COMMENT '脚本提交审核的时间戳,状态2时记录',
|
||||||
INDEX idx_lesson_tasks_user_id (user_id),
|
script_confirm_time BIGINT DEFAULT NULL COMMENT '脚本审核通过的时间戳,状态3时记录',
|
||||||
INDEX idx_lesson_tasks_progress_status (progress_status)
|
video_create_time BIGINT DEFAULT NULL COMMENT '开始视频制作的时间戳,状态4时记录',
|
||||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='课程任务表';
|
video_confirm_time BIGINT DEFAULT NULL COMMENT '视频审核通过的时间戳,状态5时记录',
|
||||||
|
finish_time BIGINT DEFAULT NULL COMMENT '整个任务完成的时间戳,最终确认后记录',
|
||||||
|
advise TEXT DEFAULT NULL COMMENT '任务相关的建议、修改意见或其他重要备注信息',
|
||||||
|
created_at BIGINT NOT NULL COMMENT '记录创建的时间戳,系统自动生成',
|
||||||
|
updated_at BIGINT NOT NULL COMMENT '记录最后更新的时间戳,系统自动更新',
|
||||||
|
|
||||||
|
-- 外键约束:确保user_id关联到users表的有效用户
|
||||||
|
CONSTRAINT fk_lesson_tasks_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
|
||||||
|
-- 索引设计:
|
||||||
|
-- 1. 用户ID索引:用于快速查找特定用户的所有任务
|
||||||
|
INDEX idx_user_id (user_id),
|
||||||
|
-- 2. 进度状态索引:用于按状态筛选和统计任务
|
||||||
|
INDEX idx_progress_status (progress_status),
|
||||||
|
-- 3. 课程名称索引:用于按课程分组和查询
|
||||||
|
INDEX idx_course_name (course_name),
|
||||||
|
-- 4. 复合索引:用于同时按用户和状态查询
|
||||||
|
INDEX idx_user_progress (user_id, progress_status)
|
||||||
|
) ENGINE=InnoDB
|
||||||
|
DEFAULT CHARSET=utf8mb4
|
||||||
|
COMMENT='课程任务管理表:记录微课制作的完整流程,包括脚本编写、审核、视频制作等各个环节的进度和时间节点';
|
||||||
```
|
```
|
||||||
|
|
||||||
### 字段说明
|
### 字段说明
|
||||||
- `id`: 任务ID,自增主键
|
|
||||||
|
- `id`: 任务 ID,自增主键
|
||||||
- `course_name`: 课程名称,不可为空
|
- `course_name`: 课程名称,不可为空
|
||||||
- `micro_lesson_name`: 微课名称,不可为空
|
- `micro_lesson_name`: 微课名称,不可为空
|
||||||
- `user_id`: 负责人ID,外键关联users表
|
- `user_id`: 负责人 ID,外键关联 users 表
|
||||||
- `progress_status`: 任务进度状态:
|
- `progress_status`: 任务进度状态:
|
||||||
- 0: 脚本上传
|
- 0: 未开始
|
||||||
- 1: 脚本确认
|
- 1: 脚本制作
|
||||||
- 2: 视频拍摄
|
- 2: 脚本审核
|
||||||
- 3: 后期制作
|
- 3: 脚本确认
|
||||||
- 4: 任务完成
|
- 4: 视频拍摄与制作
|
||||||
- `script_upload_time`: 脚本上传时间,毫秒级时间戳
|
- 5: 视频确认
|
||||||
- `script_confirm_time`: 脚本确认时间,毫秒级时间戳
|
- `script_create_time`: 脚本开始制作的时间戳,状态 1 时记录
|
||||||
- `video_capture_time`: 视频拍摄时间,毫秒级时间戳
|
- `script_review_time`: 脚本提交审核的时间戳,状态 2 时记录
|
||||||
- `video_confirm_time`: 视频确认时间,毫秒级时间戳
|
- `script_confirm_time`: 脚本审核通过的时间戳,状态 3 时记录
|
||||||
- `finish_time`: 任务完成时间,毫秒级时间戳
|
- `video_create_time`: 开始视频制作的时间戳,状态 4 时记录
|
||||||
- `advise`: 任务相关的建议或备注,文本字段
|
- `video_confirm_time`: 视频审核通过的时间戳,状态 5 时记录
|
||||||
- `created_at`: 创建时间,毫秒级时间戳
|
- `finish_time`: 整个任务完成的时间戳,最终确认后记录
|
||||||
- `updated_at`: 更新时间,毫秒级时间戳
|
- `advise`: 任务相关的建议、修改意见或其他重要备注信息
|
||||||
|
- `created_at`: 记录创建的时间戳,系统自动生成
|
||||||
|
- `updated_at`: 记录最后更新的时间戳,系统自动更新
|
||||||
|
|
||||||
### 索引
|
### 索引
|
||||||
|
|
||||||
- 主键索引:`id`
|
- 主键索引:`id`
|
||||||
- 外键索引:`idx_lesson_tasks_user_id (user_id)`
|
- 外键索引:`idx_user_id (user_id)`
|
||||||
- 普通索引:`idx_lesson_tasks_progress_status (progress_status)`
|
- 普通索引:`idx_progress_status (progress_status)`
|
||||||
|
- 普通索引:`idx_course_name (course_name)`
|
||||||
|
- 复合索引:`idx_user_progress (user_id, progress_status)`
|
||||||
|
|
||||||
## 数据库关系
|
## 数据库关系
|
||||||
|
|
||||||
1. `users.department_id` -> `departments.id`
|
1. `users.department_id` -> `departments.id`
|
||||||
|
|
||||||
- 一个部门可以有多个用户
|
- 一个部门可以有多个用户
|
||||||
- 一个用户只能属于一个部门
|
- 一个用户只能属于一个部门
|
||||||
- 使用RESTRICT约束,防止删除仍有用户的部门
|
- 使用 RESTRICT 约束,防止删除仍有用户的部门
|
||||||
|
|
||||||
2. `lesson_tasks.user_id` -> `users.id`
|
2. `lesson_tasks.user_id` -> `users.id`
|
||||||
|
|
||||||
- 一个用户可以负责多个课程任务
|
- 一个用户可以负责多个课程任务
|
||||||
- 一个课程任务只能有一个负责人
|
- 一个课程任务只能有一个负责人
|
||||||
- 使用CASCADE约束,删除用户时自动删除其负责的课程任务
|
- 使用 CASCADE 约束,删除用户时自动删除其负责的课程任务
|
||||||
|
|
||||||
|
3. `lesson_tasks` 和 `users` 表关系:
|
||||||
|
|
||||||
|
- 一对多关系:一个用户(users)可以负责多个课程任务(lesson_tasks)
|
||||||
|
- 通过 `user_id` 外键关联,确保任务负责人的有效性
|
||||||
|
- 使用 CASCADE 级联删除:当用户被删除时,相关任务也会被自动删除
|
||||||
|
- 使用 CASCADE 级联更新:当用户 ID 更新时,相关任务的 user_id 也会自动更新
|
||||||
|
|
||||||
|
4. 索引说明:
|
||||||
|
|
||||||
|
- `idx_user_id`: 优化按负责人查询任务的性能
|
||||||
|
- `idx_progress_status`: 优化按任务状态筛选和统计的性能
|
||||||
|
- `idx_course_name`: 优化按课程名称查询和分组的性能
|
||||||
|
- `idx_user_progress`: 优化同时按用户和任务状态查询的性能,适用于查看特定用户的特定状态任务
|
||||||
|
|
||||||
|
5. 时间节点追踪:
|
||||||
|
- 系统通过各个时间戳字段(script_create_time, script_review_time 等)完整记录任务的每个阶段
|
||||||
|
- 可以通过这些时间戳计算各阶段的耗时,用于任务进度分析和效率优化
|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
|
|
||||||
1. 所有时间戳字段使用BIGINT类型,存储毫秒级时间戳
|
1. 所有时间戳字段使用 BIGINT 类型,存储毫秒级时间戳
|
||||||
2. 字符编码统一使用utf8mb4,支持完整的Unicode字符集
|
2. 字符编码统一使用 utf8mb4,支持完整的 Unicode 字符集
|
||||||
3. 所有表都使用InnoDB引擎,支持事务和外键
|
3. 所有表都使用 InnoDB 引擎,支持事务和外键
|
||||||
4. 关键字段都建立了适当的索引以提高查询性能
|
4. 关键字段都建立了适当的索引以提高查询性能
|
||||||
5. 用户密码在存储前需要进行加密处理
|
5. 用户密码在存储前需要进行加密处理
|
||||||
6. 删除用户时会自动删除其关联的课程任务,但不会影响部门数据
|
6. 删除用户时会自动删除其关联的课程任务,但不会影响部门数据
|
||||||
|
66
数据库测试数据.md
66
数据库测试数据.md
@ -1,66 +0,0 @@
|
|||||||
```sql
|
|
||||||
-- 插入角色:教师,岗位:课程制作教师
|
|
||||||
INSERT INTO users (username, email, password, department_id, roles, jobs, avatar, creator_id, status, created_at,
|
|
||||||
updated_at)
|
|
||||||
VALUES ('教师账号1', 'user1@qq.com', '$2a$10$6RzWwYoBa/ZFWc6U9LmshemE801Yc/aUw.KxgT6JAihcYRfDgaoZq', 2, 1, 1, NULL, 1,
|
|
||||||
1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 插入角色:普通管理员,岗位:课程购买方项目负责人
|
|
||||||
INSERT INTO users (username, email, password, department_id, roles, jobs, avatar, creator_id, status, created_at,
|
|
||||||
updated_at)
|
|
||||||
VALUES ('普通管理员账号2', 'user2@qq.com', '$2a$10$6RzWwYoBa/ZFWc6U9LmshemE801Yc/aUw.KxgT6JAihcYRfDgaoZq', 2, 2, 2,
|
|
||||||
NULL, 1, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 插入角色:沟通联络人,岗位:课程制作方沟通联络人
|
|
||||||
INSERT INTO users (username, email, password, department_id, roles, jobs, avatar, creator_id, status, created_at,
|
|
||||||
updated_at)
|
|
||||||
VALUES ('沟通联络人账号3', 'user3@qq.com', '$2a$10$6RzWwYoBa/ZFWc6U9LmshemE801Yc/aUw.KxgT6JAihcYRfDgaoZq', 1, 3, 3,
|
|
||||||
NULL, 1, 1, UNIX_TIMESTAMP(),
|
|
||||||
UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 插入角色:系统管理员
|
|
||||||
INSERT INTO users (username, email, password, department_id, roles, jobs, avatar, creator_id, status, created_at,
|
|
||||||
updated_at)
|
|
||||||
VALUES ('系统管理员', 'admin@qq.com', '$2a$10$6RzWwYoBa/ZFWc6U9LmshemE801Yc/aUw.KxgT6JAihcYRfDgaoZq', 1, 4, 4, NULL, 1,
|
|
||||||
1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:数学,微课名:微课1-1
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('数学', '微课1-1', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:数学,微课名:微课1-2
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('数学', '微课1-2', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:数学,微课名:微课1-3
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('数学', '微课1-3', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:物理,微课名:微课2-1
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('物理', '微课2-1', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:物理,微课名:微课2-2
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('物理', '微课2-2', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:物理,微课名:微课2-3
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('物理', '微课2-3', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:英语,微课名:微课3-1
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('英语', '微课3-1', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:英语,微课名:微课3-2
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('英语', '微课3-2', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
-- 课程名:英语,微课名:微课3-3
|
|
||||||
INSERT INTO lesson_tasks (course_name, micro_lesson_name, user_id, progress_status, created_at, updated_at)
|
|
||||||
VALUES ('英语', '微课3-3', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
||||||
|
|
||||||
INSERT INTO departments (name, description, created_at, updated_at)
|
|
||||||
VALUES ('重庆眨生花科技有限公司', '重庆眨生花科技有限公司', NOW(), NOW()),
|
|
||||||
('重庆电子科技职业大学', '重庆电子科技职业大学', NOW(), NOW());
|
|
||||||
```
|
|
Loading…
Reference in New Issue
Block a user