Merge remote-tracking branch 'origin/master'
5310
reading-platform-frontend/package-lock.json
generated
@ -42,7 +42,7 @@
|
||||
"orval": "^8.5.3",
|
||||
"sass-embedded": "^1.97.3",
|
||||
"typescript": "~5.4.0",
|
||||
"unocss": "^66.6.6",
|
||||
"unocss": "^0.58.5",
|
||||
"unplugin-auto-import": "^0.17.5",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"unplugin-vue-router": "^0.19.2",
|
||||
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
@ -1,121 +0,0 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- complementary [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- generic [ref=e6]:
|
||||
- img "Logo" [ref=e7]
|
||||
- generic [ref=e8]:
|
||||
- generic [ref=e9]: 少儿智慧阅读
|
||||
- generic [ref=e10]: 服务管理后台
|
||||
- menu [ref=e12]:
|
||||
- menuitem "数据看板" [ref=e13] [cursor=pointer]:
|
||||
- img [ref=e14]
|
||||
- generic [ref=e20]: 数据看板
|
||||
- menuitem "课程包管理" [ref=e21] [cursor=pointer]:
|
||||
- img [ref=e22]
|
||||
- generic [ref=e25]: 课程包管理
|
||||
- menuitem "database 套餐管理" [ref=e26] [cursor=pointer]:
|
||||
- img "database" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e31]: 套餐管理
|
||||
- menuitem "format-painter 主题字典" [ref=e32] [cursor=pointer]:
|
||||
- img "format-painter" [ref=e33]:
|
||||
- img [ref=e34]
|
||||
- generic [ref=e37]: 主题字典
|
||||
- menuitem "租户管理" [ref=e38] [cursor=pointer]:
|
||||
- img [ref=e39]
|
||||
- generic [ref=e44]: 租户管理
|
||||
- menuitem "资源库" [ref=e45] [cursor=pointer]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e49]: 资源库
|
||||
- menuitem "系统设置" [ref=e50] [cursor=pointer]:
|
||||
- img [ref=e51]
|
||||
- generic [ref=e55]: 系统设置
|
||||
- generic [ref=e56]:
|
||||
- generic [ref=e57]:
|
||||
- img "menu-fold" [ref=e59] [cursor=pointer]:
|
||||
- img [ref=e60]
|
||||
- generic [ref=e63]:
|
||||
- generic [ref=e65]:
|
||||
- img "bell" [ref=e66] [cursor=pointer]:
|
||||
- img [ref=e67]
|
||||
- superscript [ref=e69]:
|
||||
- paragraph [ref=e71]: "5"
|
||||
- generic [ref=e73] [cursor=pointer]:
|
||||
- img "user" [ref=e76]:
|
||||
- img [ref=e77]
|
||||
- generic [ref=e79]: 系统管理员
|
||||
- img "down" [ref=e81]:
|
||||
- img [ref=e82]
|
||||
- main [ref=e84]:
|
||||
- generic [ref=e85]:
|
||||
- generic [ref=e87]:
|
||||
- generic [ref=e88]:
|
||||
- button "返回" [ref=e90] [cursor=pointer]:
|
||||
- img "arrow-left" [ref=e91]:
|
||||
- img [ref=e92]
|
||||
- generic "编辑课程包" [ref=e94]
|
||||
- generic [ref=e98]:
|
||||
- button "保存草稿" [ref=e100] [cursor=pointer]:
|
||||
- generic [ref=e101]: 保存草稿
|
||||
- button "保 存" [ref=e103] [cursor=pointer]:
|
||||
- generic [ref=e104]: 保 存
|
||||
- generic [ref=e108]:
|
||||
- generic [ref=e109]:
|
||||
- button "check 基本信息" [ref=e111] [cursor=pointer]:
|
||||
- img "check" [ref=e114]:
|
||||
- img [ref=e115]
|
||||
- generic [ref=e118]: 基本信息
|
||||
- button "check 课程介绍" [ref=e120] [cursor=pointer]:
|
||||
- img "check" [ref=e123]:
|
||||
- img [ref=e124]
|
||||
- generic [ref=e127]: 课程介绍
|
||||
- button "check 排课参考" [ref=e129] [cursor=pointer]:
|
||||
- img "check" [ref=e132]:
|
||||
- img [ref=e133]
|
||||
- generic [ref=e136]: 排课参考
|
||||
- button "check 导入课" [ref=e138] [cursor=pointer]:
|
||||
- img "check" [ref=e141]:
|
||||
- img [ref=e142]
|
||||
- generic [ref=e145]: 导入课
|
||||
- button "check 集体课" [ref=e147] [cursor=pointer]:
|
||||
- img "check" [ref=e150]:
|
||||
- img [ref=e151]
|
||||
- generic [ref=e154]: 集体课
|
||||
- button "check 领域课" [ref=e156] [cursor=pointer]:
|
||||
- img "check" [ref=e159]:
|
||||
- img [ref=e160]
|
||||
- generic [ref=e163]: 领域课
|
||||
- button "7 环创建设" [ref=e165]:
|
||||
- generic [ref=e166]: "7"
|
||||
- generic [ref=e168]: 环创建设
|
||||
- generic [ref=e169]:
|
||||
- generic [ref=e170]: 完成度
|
||||
- progressbar [ref=e171]:
|
||||
- img "check-circle" [ref=e176]:
|
||||
- img [ref=e177]
|
||||
- generic [ref=e179]:
|
||||
- text: "* : * : * : : * : 26 / 200 : : : 60 / 1500 64 / 1500 71 / 1500 61 / 1500 33 / 1500 35 / 1500 33 / 1500 36 / 1500 : : : 0 / 500 : : : * : 94 / 1500 * : 64 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500 : : : 0 / 500 : : : * : 0 / 1500 * : 0 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500 : : : 0 / 500 : : : * : 64 / 1500 * : 0 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500 : : : 0 / 500 : : : * : 68 / 1500 * : 0 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500"
|
||||
- generic [ref=e180]:
|
||||
- generic [ref=e181]:
|
||||
- generic [ref=e182]: 环创建设
|
||||
- generic [ref=e183]: 已填写
|
||||
- alert [ref=e185]:
|
||||
- img "info-circle" [ref=e186]:
|
||||
- img [ref=e187]
|
||||
- generic [ref=e190]:
|
||||
- generic [ref=e191]: 填写提示
|
||||
- generic [ref=e192]: 环创建设内容可包括:主题环境布置、区域活动环境、阅读角创设、材料投放建议等,帮助教师更好地创设支持幼儿学习的环境。
|
||||
- generic [ref=e194]:
|
||||
- textbox "请输入环创建设内容,例如: - 主题墙布置建议 - 阅读区环境创设 - 材料展示区设置 - 互动区域规划 - 相关装饰物品建议等" [ref=e195]:
|
||||
- /placeholder: "请输入环创建设内容,例如:\r\n- 主题墙布置建议\r\n- 阅读区环境创设\r\n- 材料展示区设置\r\n- 互动区域规划\r\n- 相关装饰物品建议等"
|
||||
- text: 1. 夸夸卡展示区:展示幼儿制作的夸夸卡 2. "我的特别之处"展示墙:张贴幼儿分享的特别之处作品 3. 兔子探秘墙:张贴兔子图片和观察记录 4. 音乐角环创:张贴儿歌歌词图谱、兔子头饰 5. 健康小卫士展示区:张贴保护耳朵方法海报
|
||||
- text: 116 / 3000
|
||||
- generic [ref=e196]:
|
||||
- button "上一步" [ref=e197] [cursor=pointer]:
|
||||
- generic [ref=e198]: 上一步
|
||||
- button "保 存" [active] [ref=e199] [cursor=pointer]:
|
||||
- generic [ref=e200]: 保 存
|
||||
```
|
||||
|
Before Width: | Height: | Size: 87 KiB |
@ -26,7 +26,6 @@ declare module 'vue' {
|
||||
AForm: typeof import('ant-design-vue/es')['Form']
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
AImage: typeof import('ant-design-vue/es')['Image']
|
||||
AImagePreviewGroup: typeof import('ant-design-vue/es')['ImagePreviewGroup']
|
||||
AInput: typeof import('ant-design-vue/es')['Input']
|
||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||
@ -35,9 +34,6 @@ declare module 'vue' {
|
||||
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
|
||||
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
|
||||
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
|
||||
AList: typeof import('ant-design-vue/es')['List']
|
||||
AListItem: typeof import('ant-design-vue/es')['ListItem']
|
||||
AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
|
||||
AMenu: typeof import('ant-design-vue/es')['Menu']
|
||||
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
|
||||
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||
@ -52,7 +48,6 @@ declare module 'vue' {
|
||||
ARate: typeof import('ant-design-vue/es')['Rate']
|
||||
ARow: typeof import('ant-design-vue/es')['Row']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup']
|
||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
|
||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||
@ -60,8 +55,6 @@ declare module 'vue' {
|
||||
AStatistic: typeof import('ant-design-vue/es')['Statistic']
|
||||
AStep: typeof import('ant-design-vue/es')['Step']
|
||||
ASteps: typeof import('ant-design-vue/es')['Steps']
|
||||
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
|
||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||
ATable: typeof import('ant-design-vue/es')['Table']
|
||||
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
||||
ATabs: typeof import('ant-design-vue/es')['Tabs']
|
||||
@ -69,8 +62,6 @@ declare module 'vue' {
|
||||
ATextarea: typeof import('ant-design-vue/es')['Textarea']
|
||||
ATimeRangePicker: typeof import('ant-design-vue/es')['TimeRangePicker']
|
||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
|
||||
AUpload: typeof import('ant-design-vue/es')['Upload']
|
||||
FilePreviewModal: typeof import('./components/FilePreviewModal.vue')['default']
|
||||
FileUploader: typeof import('./components/course/FileUploader.vue')['default']
|
||||
LessonConfigPanel: typeof import('./components/course/LessonConfigPanel.vue')['default']
|
||||
|
||||
@ -1,6 +1,20 @@
|
||||
{
|
||||
"status": "failed",
|
||||
"failedTests": [
|
||||
"c69a9057cbaf3e338784-66eea60b1dfabe5e5fd7"
|
||||
"bc6fce14a8e0cd420e54-2397ca16ed541560cb91",
|
||||
"bc6fce14a8e0cd420e54-52368475d8ba13ee1a3f",
|
||||
"bc6fce14a8e0cd420e54-fbecd85bef134508dcac",
|
||||
"bc6fce14a8e0cd420e54-2e284d330d630a4904c4",
|
||||
"bc6fce14a8e0cd420e54-f732cd5c981a1387a2d0",
|
||||
"bc6fce14a8e0cd420e54-565449e6def898950455",
|
||||
"bc6fce14a8e0cd420e54-202cf860344bf8e55e3b",
|
||||
"bc6fce14a8e0cd420e54-c522b8ebd663dd7252ed",
|
||||
"bc6fce14a8e0cd420e54-b63a3be9bf25f1ac0883",
|
||||
"bc6fce14a8e0cd420e54-a2ff7763cecba2b90746",
|
||||
"bc6fce14a8e0cd420e54-4a406d8834fbcaeba74d",
|
||||
"bc6fce14a8e0cd420e54-588b18110e12525029d4",
|
||||
"bc6fce14a8e0cd420e54-85d504e0ef234d6620c5",
|
||||
"bc6fce14a8e0cd420e54-c45f2878d18c601e386a",
|
||||
"bc6fce14a8e0cd420e54-108280346c48a6e65fbd"
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 159 KiB |
@ -29,7 +29,7 @@
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: admin
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
@ -39,9 +39,7 @@
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [ref=e69] [cursor=pointer]:
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- button "一键测试(超管账号)" [ref=e76] [cursor=pointer]:
|
||||
- generic [ref=e77]: 一键测试(超管账号)
|
||||
- generic [ref=e78]: © 2026 少儿智慧阅读服务平台
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
@ -0,0 +1,45 @@
|
||||
# Page snapshot
|
||||
|
||||
```yaml
|
||||
- generic [ref=e3]:
|
||||
- generic [ref=e4]:
|
||||
- generic [ref=e5]:
|
||||
- img "Logo" [ref=e6]
|
||||
- generic [ref=e7]:
|
||||
- heading "少儿智慧阅读" [level=1] [ref=e8]
|
||||
- paragraph [ref=e9]: 读启智慧,阅见未来
|
||||
- generic [ref=e10]:
|
||||
- generic [ref=e11] [cursor=pointer]:
|
||||
- img "setting" [ref=e12]:
|
||||
- img [ref=e13]
|
||||
- generic [ref=e15]: 超管
|
||||
- generic [ref=e16] [cursor=pointer]:
|
||||
- img "solution" [ref=e17]:
|
||||
- img [ref=e18]
|
||||
- generic [ref=e20]: 学校
|
||||
- generic [ref=e21] [cursor=pointer]:
|
||||
- img "read" [ref=e22]:
|
||||
- img [ref=e23]
|
||||
- generic [ref=e25]: 教师
|
||||
- generic [ref=e26] [cursor=pointer]:
|
||||
- img "home" [ref=e27]:
|
||||
- img [ref=e28]
|
||||
- generic [ref=e30]: 家长
|
||||
- generic [ref=e31]:
|
||||
- generic [ref=e37]:
|
||||
- img "user" [ref=e39]:
|
||||
- img [ref=e40]
|
||||
- textbox "请输入账号" [ref=e42]: teacher1
|
||||
- button "close-circle" [ref=e44] [cursor=pointer]:
|
||||
- img "close-circle" [ref=e45]:
|
||||
- img [ref=e46]
|
||||
- generic [ref=e53]:
|
||||
- img "lock" [ref=e55]:
|
||||
- img [ref=e56]
|
||||
- textbox "请输入密码" [ref=e58]: "123456"
|
||||
- img "eye-invisible" [ref=e60] [cursor=pointer]:
|
||||
- img [ref=e61]
|
||||
- button "登 录" [active] [ref=e69] [cursor=pointer]:
|
||||
- generic [ref=e70]: 登 录
|
||||
- generic [ref=e71]: © 2026 少儿智慧阅读服务平台
|
||||
```
|
||||
|
After Width: | Height: | Size: 152 KiB |
85
reading-platform-frontend/tests/e2e/teacher/00-login.spec.ts
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 登录
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { TEACHER_CONFIG } from './fixtures';
|
||||
|
||||
test.describe('教师端登录功能', () => {
|
||||
test('验证登录页面加载', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// 验证页面标题
|
||||
await expect(page).toHaveTitle(/幼儿阅读教学服务平台/);
|
||||
|
||||
// 验证角色选择按钮存在
|
||||
await expect(page.locator('.role-btn')).toBeVisible();
|
||||
|
||||
// 验证教师角色按钮存在
|
||||
const teacherBtn = page.locator('.role-btn').filter({ hasText: '教师' });
|
||||
await expect(teacherBtn).toBeVisible();
|
||||
});
|
||||
|
||||
test('使用正确账号密码登录', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// 点击教师角色按钮
|
||||
await page.locator('.role-btn').filter({ hasText: '教师' }).first().click();
|
||||
|
||||
// 输入账号密码
|
||||
await page.getByPlaceholder('请输入账号').fill(TEACHER_CONFIG.account);
|
||||
await page.getByPlaceholder('请输入密码').fill(TEACHER_CONFIG.password);
|
||||
|
||||
// 点击登录按钮
|
||||
await page.locator('.login-btn').click();
|
||||
|
||||
// 等待登录按钮消失
|
||||
await page.locator('.login-btn').waitFor({ state: 'hidden', timeout: 10000 });
|
||||
|
||||
// 等待页面跳转
|
||||
await page.waitForURL(/teacher/, { timeout: 10000 });
|
||||
|
||||
// 验证跳转到教师端首页
|
||||
await expect(page).toHaveURL(/.*teacher.*/);
|
||||
});
|
||||
|
||||
test('使用错误密码登录', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// 点击教师角色按钮
|
||||
await page.locator('.role-btn').filter({ hasText: '教师' }).first().click();
|
||||
|
||||
// 输入账号和错误密码
|
||||
await page.getByPlaceholder('请输入账号').fill(TEACHER_CONFIG.account);
|
||||
await page.getByPlaceholder('请输入密码').fill('wrongpassword');
|
||||
|
||||
// 点击登录按钮
|
||||
await page.locator('.login-btn').click();
|
||||
|
||||
// 等待错误提示
|
||||
await page.waitForSelector('.ant-message-error, [class*="error"]', { timeout: 5000 }).catch(() => {});
|
||||
|
||||
// 验证仍在登录页
|
||||
await expect(page).toHaveURL(/.*login.*/);
|
||||
});
|
||||
|
||||
test('登录表单验证', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// 点击教师角色按钮
|
||||
await page.locator('.role-btn').filter({ hasText: '教师' }).first().click();
|
||||
|
||||
// 不输入账号密码直接点击登录
|
||||
await page.locator('.login-btn').click();
|
||||
|
||||
// 等待验证提示
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 验证是否显示验证错误提示
|
||||
const hasError = await page.locator('.ant-message-error, .ant-form-item-explain-error').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `表单验证提示:${hasError ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
});
|
||||
100
reading-platform-frontend/tests/e2e/teacher/01-dashboard.spec.ts
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 仪表盘
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher } from './helpers';
|
||||
import { TEACHER_CONFIG } from './fixtures';
|
||||
|
||||
test.describe('教师端仪表盘功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证仪表盘页面加载', async ({ page }) => {
|
||||
// 验证页面标题
|
||||
await expect(page).toHaveTitle(/幼儿阅读教学服务平台/);
|
||||
|
||||
// 验证教师端仪表盘标题
|
||||
await expect(page.getByRole('heading', { name: /仪表盘|我的教学|教学概览/ })).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('验证统计数据卡片显示', async ({ page }) => {
|
||||
// 检查统计数据卡片(班级数、学生数、课程数等)
|
||||
const statsCards = page.locator('.ant-statistic, [class*="statistic"], [class*="stats"]');
|
||||
const statsCount = await statsCards.count();
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `统计数据卡片数量:${statsCount}`,
|
||||
});
|
||||
|
||||
expect(statsCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('验证今日课程显示', async ({ page }) => {
|
||||
// 检查是否有今日课程列表
|
||||
const todayLessons = page.locator('[class*="lesson"], [class*="course"], [class*="schedule"]');
|
||||
const lessonCount = await todayLessons.count();
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `今日课程数量:${lessonCount}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证推荐课程显示', async ({ page }) => {
|
||||
// 检查是否有推荐课程
|
||||
const recommendedCourses = page.locator('[class*="course-card"], [class*="recommend"]');
|
||||
const courseCount = await recommendedCourses.count();
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `推荐课程数量:${courseCount}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证侧边栏导航菜单', async ({ page }) => {
|
||||
// 检查侧边栏菜单项
|
||||
const menuItems = page.locator('.ant-menu-item, [class*="menu-item"], .ant-menu-submenu');
|
||||
const menuCount = await menuItems.count();
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `菜单项数量:${menuCount}`,
|
||||
});
|
||||
|
||||
// 验证核心菜单项存在
|
||||
const expectedMenus = ['首页', '我的课表', '课程列表', '授课记录', '班级管理', '学生管理', '任务管理', '成长记录'];
|
||||
for (const menu of expectedMenus) {
|
||||
const menuExists = await page.getByText(menu).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: menuExists ? 'success' : 'warning',
|
||||
description: `${menu}菜单:${menuExists ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证用户信息区域显示', async ({ page }) => {
|
||||
// 检查右上角用户信息显示
|
||||
const userInfo = page.locator('[class*="user"], [class*="profile"]');
|
||||
const userExists = await userInfo.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `用户信息区域:${userExists ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('截图保存仪表盘状态', async ({ page }) => {
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-dashboard.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '仪表盘截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
106
reading-platform-frontend/tests/e2e/teacher/02-schedule.spec.ts
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 我的课表/排课管理
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable, waitForSuccess } from './helpers';
|
||||
|
||||
test.describe('教师端课表管理功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证课表页面加载', async ({ page }) => {
|
||||
// 导航到课表页面
|
||||
await clickSubMenu(page, '教学管理', '我的课表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/课表 | 排课 | 我的课表/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `课表标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证课表数据加载', async ({ page }) => {
|
||||
// 导航到课表页面
|
||||
await clickSubMenu(page, '教学管理', '我的课表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有课表数据或空状态
|
||||
const hasSchedule = await page.locator('[class*="schedule"], [class*="timetable"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无排课 | 空/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `课表数据:${hasSchedule ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证创建排课功能', async ({ page }) => {
|
||||
// 导航到课表页面
|
||||
await clickSubMenu(page, '教学管理', '我的课表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找创建按钮
|
||||
const createBtn = page.getByRole('button', { name: /创建 | 新建 | 添加/ });
|
||||
const hasCreateBtn = await createBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建按钮:${hasCreateBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
|
||||
if (hasCreateBtn) {
|
||||
// 点击创建按钮
|
||||
await createBtn.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 验证弹窗是否打开
|
||||
const hasModal = await page.locator('.ant-modal, [class*="modal"], [class*="dialog"]').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建弹窗:${hasModal ? '打开' : '未打开'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证课表视图切换', async ({ page }) => {
|
||||
// 导航到课表页面
|
||||
await clickSubMenu(page, '教学管理', '我的课表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找视图切换按钮(周/月)
|
||||
const viewSwitcher = page.locator('[class*="switch"], [class*="view"], .ant-radio-group');
|
||||
const hasViewSwitcher = await viewSwitcher.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `视图切换:${hasViewSwitcher ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('截图保存课表状态', async ({ page }) => {
|
||||
// 导航到课表页面
|
||||
await clickSubMenu(page, '教学管理', '我的课表');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-schedule.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '课表页面截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
112
reading-platform-frontend/tests/e2e/teacher/03-classes.spec.ts
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 班级管理
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable } from './helpers';
|
||||
|
||||
test.describe('教师端班级管理功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证班级列表页面加载', async ({ page }) => {
|
||||
// 导航到班级管理页面
|
||||
await clickSubMenu(page, '班级管理', '班级列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/班级 | 我的班级/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `班级标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证班级数据加载', async ({ page }) => {
|
||||
// 导航到班级管理页面
|
||||
await clickSubMenu(page, '班级管理', '班级列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有班级数据
|
||||
const hasClassList = await page.locator('[class*="class"], [class*="card"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无班级/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `班级数据:${hasClassList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证班级学生列表', async ({ page }) => {
|
||||
// 导航到班级管理页面
|
||||
await clickSubMenu(page, '班级管理', '班级列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找第一个班级并点击进入
|
||||
const firstClass = page.locator('[class*="class-card"], [class*="class-item"], table tbody tr').first();
|
||||
const hasClass = await firstClass.count() > 0;
|
||||
|
||||
if (hasClass) {
|
||||
// 尝试点击进入班级详情
|
||||
await firstClass.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证是否进入班级详情页
|
||||
const hasStudentList = await page.locator('[class*="student"], table').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `学生列表:${hasStudentList ? '存在' : '不存在'}`,
|
||||
});
|
||||
} else {
|
||||
test.info().annotations.push({
|
||||
type: 'warning',
|
||||
description: '没有找到班级数据',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证班级教师列表', async ({ page }) => {
|
||||
// 导航到班级管理页面
|
||||
await clickSubMenu(page, '班级管理', '班级列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找第一个班级并查看教师
|
||||
const firstClass = page.locator('[class*="class-card"], [class*="class-item"], table tbody tr').first();
|
||||
const hasClass = await firstClass.count() > 0;
|
||||
|
||||
if (hasClass) {
|
||||
// 查找查看教师按钮
|
||||
const viewTeachersBtn = page.getByRole('button', { name: /教师 | 老师/ }).first();
|
||||
const hasBtn = await viewTeachersBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `查看教师按钮:${hasBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('截图保存班级列表状态', async ({ page }) => {
|
||||
// 导航到班级管理页面
|
||||
await clickSubMenu(page, '班级管理', '班级列表');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-classes.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '班级列表截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
104
reading-platform-frontend/tests/e2e/teacher/04-courses.spec.ts
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 课程列表
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable } from './helpers';
|
||||
|
||||
test.describe('教师端课程列表功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证课程列表页面加载', async ({ page }) => {
|
||||
// 导航到课程列表页面
|
||||
await clickSubMenu(page, '教学管理', '课程列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/课程 | 教学课程/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `课程标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证课程数据加载', async ({ page }) => {
|
||||
// 导航到课程列表页面
|
||||
await clickSubMenu(page, '教学管理', '课程列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有课程数据
|
||||
const hasCourseList = await page.locator('[class*="course"], [class*="card"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无课程/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `课程数据:${hasCourseList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证课程详情查看', async ({ page }) => {
|
||||
// 导航到课程列表页面
|
||||
await clickSubMenu(page, '教学管理', '课程列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找第一个课程并点击查看
|
||||
const firstCourse = page.locator('[class*="course-card"], [class*="course-item"], table tbody tr').first();
|
||||
const hasCourse = await firstCourse.count() > 0;
|
||||
|
||||
if (hasCourse) {
|
||||
// 尝试点击查看课程详情
|
||||
await firstCourse.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证是否进入课程详情页
|
||||
const hasDetailPage = await page.locator('[class*="course-detail"], [class*="detail"]').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `课程详情页:${hasDetailPage ? '存在' : '不存在'}`,
|
||||
});
|
||||
} else {
|
||||
test.info().annotations.push({
|
||||
type: 'warning',
|
||||
description: '没有找到课程数据',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证课程筛选功能', async ({ page }) => {
|
||||
// 导航到课程列表页面
|
||||
await clickSubMenu(page, '教学管理', '课程列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找筛选器
|
||||
const hasFilter = await page.locator('[class*="filter"], [class*="search"], .ant-input, .ant-select').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `筛选功能:${hasFilter ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('截图保存课程列表状态', async ({ page }) => {
|
||||
// 导航到课程列表页面
|
||||
await clickSubMenu(page, '教学管理', '课程列表');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-courses.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '课程列表截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
129
reading-platform-frontend/tests/e2e/teacher/05-lessons.spec.ts
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 授课记录
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable, waitForSuccess } from './helpers';
|
||||
|
||||
test.describe('教师端授课记录功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证授课记录列表页面加载', async ({ page }) => {
|
||||
// 导航到授课记录页面
|
||||
await clickSubMenu(page, '教学管理', '授课记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/授课 | 教学记录/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `授课记录标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证授课记录数据加载', async ({ page }) => {
|
||||
// 导航到授课记录页面
|
||||
await clickSubMenu(page, '教学管理', '授课记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有授课记录数据
|
||||
const hasLessonList = await page.locator('[class*="lesson"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无授课/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `授课记录数据:${hasLessonList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证创建授课记录功能', async ({ page }) => {
|
||||
// 导航到授课记录页面
|
||||
await clickSubMenu(page, '教学管理', '授课记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找创建按钮
|
||||
const createBtn = page.getByRole('button', { name: /创建 | 新建 | 添加 | 备课/ });
|
||||
const hasCreateBtn = await createBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建按钮:${hasCreateBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
|
||||
if (hasCreateBtn) {
|
||||
// 点击创建按钮
|
||||
await createBtn.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 验证弹窗是否打开
|
||||
const hasModal = await page.locator('.ant-modal, [class*="modal"]').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建弹窗:${hasModal ? '打开' : '未打开'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证授课记录操作按钮', async ({ page }) => {
|
||||
// 导航到授课记录页面
|
||||
await clickSubMenu(page, '教学管理', '授课记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 查找操作按钮(开始、结束、取消等)
|
||||
const actionBtns = page.locator('button:has-text("开始"), button:has-text("结束"), button:has-text("取消")');
|
||||
const hasActionBtns = await actionBtns.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `操作按钮:${hasActionBtns ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证学生评价记录功能', async ({ page }) => {
|
||||
// 导航到授课记录页面
|
||||
await clickSubMenu(page, '教学管理', '授课记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找第一个授课记录并点击查看学生评价
|
||||
const firstLesson = page.locator('table tbody tr').first();
|
||||
const hasLesson = await firstLesson.count() > 0;
|
||||
|
||||
if (hasLesson) {
|
||||
// 查找学生评价按钮
|
||||
const studentRecordBtn = page.getByRole('button', { name: /学生 | 评价 | 记录/ }).first();
|
||||
const hasBtn = await studentRecordBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `学生评价按钮:${hasBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('截图保存授课记录状态', async ({ page }) => {
|
||||
// 导航到授课记录页面
|
||||
await clickSubMenu(page, '教学管理', '授课记录');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-lessons.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '授课记录截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
143
reading-platform-frontend/tests/e2e/teacher/06-tasks.spec.ts
Normal file
@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 任务管理
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable, waitForSuccess } from './helpers';
|
||||
|
||||
test.describe('教师端任务管理功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证任务列表页面加载', async ({ page }) => {
|
||||
// 导航到任务管理页面
|
||||
await clickSubMenu(page, '任务管理', '任务列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/任务 | 阅读任务/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `任务管理标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证任务数据加载', async ({ page }) => {
|
||||
// 导航到任务管理页面
|
||||
await clickSubMenu(page, '任务管理', '任务列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有任务数据
|
||||
const hasTaskList = await page.locator('[class*="task"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无任务/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `任务数据:${hasTaskList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证创建任务功能', async ({ page }) => {
|
||||
// 导航到任务管理页面
|
||||
await clickSubMenu(page, '任务管理', '任务列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找创建按钮
|
||||
const createBtn = page.getByRole('button', { name: /创建 | 新建 | 添加/ });
|
||||
const hasCreateBtn = await createBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建按钮:${hasCreateBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
|
||||
if (hasCreateBtn) {
|
||||
// 点击创建按钮
|
||||
await createBtn.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 验证弹窗是否打开
|
||||
const hasModal = await page.locator('.ant-modal, [class*="modal"]').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建弹窗:${hasModal ? '打开' : '未打开'}`,
|
||||
});
|
||||
|
||||
if (hasModal) {
|
||||
// 验证表单字段
|
||||
const hasTitleInput = await page.locator('[class*="title"] input, input[placeholder*="标题"]').count() > 0;
|
||||
const hasTypeSelect = await page.locator('[class*="type"] .ant-select, [class*="taskType"]').count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `标题输入框:${hasTitleInput ? '存在' : '不存在'}`,
|
||||
});
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `任务类型选择:${hasTypeSelect ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('验证任务筛选功能', async ({ page }) => {
|
||||
// 导航到任务管理页面
|
||||
await clickSubMenu(page, '任务管理', '任务列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找筛选器
|
||||
const hasFilter = await page.locator('[class*="filter"], [class*="search"], .ant-input, .ant-select').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `筛选功能:${hasFilter ? '存在' : '不存在'}`,
|
||||
});
|
||||
|
||||
// 查找状态筛选
|
||||
const hasStatusFilter = await page.getByText(/状态 | 全部 | 进行中 | 已完成/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `状态筛选:${hasStatusFilter ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证任务操作按钮', async ({ page }) => {
|
||||
// 导航到任务管理页面
|
||||
await clickSubMenu(page, '任务管理', '任务列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 查找操作按钮(编辑、删除等)
|
||||
const actionBtns = page.locator('button:has-text("编辑"), button:has-text("删除"), button:has-text("详情")');
|
||||
const hasActionBtns = await actionBtns.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `操作按钮:${hasActionBtns ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('截图保存任务管理状态', async ({ page }) => {
|
||||
// 导航到任务管理页面
|
||||
await clickSubMenu(page, '任务管理', '任务列表');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-tasks.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '任务管理截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 任务模板
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable } from './helpers';
|
||||
|
||||
test.describe('教师端任务模板功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证任务模板列表页面加载', async ({ page }) => {
|
||||
// 导航到任务模板页面
|
||||
await clickSubMenu(page, '任务管理', '任务模板');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/模板 | 任务模板/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `任务模板标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证任务模板数据加载', async ({ page }) => {
|
||||
// 导航到任务模板页面
|
||||
await clickSubMenu(page, '任务管理', '任务模板');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有模板数据
|
||||
const hasTemplateList = await page.locator('[class*="template"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无模板/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `任务模板数据:${hasTemplateList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证创建任务模板功能', async ({ page }) => {
|
||||
// 导航到任务模板页面
|
||||
await clickSubMenu(page, '任务管理', '任务模板');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找创建按钮
|
||||
const createBtn = page.getByRole('button', { name: /创建 | 新建 | 添加/ });
|
||||
const hasCreateBtn = await createBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建按钮:${hasCreateBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
|
||||
if (hasCreateBtn) {
|
||||
// 点击创建按钮
|
||||
await createBtn.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 验证弹窗是否打开
|
||||
const hasModal = await page.locator('.ant-modal, [class*="modal"]').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建弹窗:${hasModal ? '打开' : '未打开'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证从模板创建任务功能', async ({ page }) => {
|
||||
// 导航到任务模板页面
|
||||
await clickSubMenu(page, '任务管理', '任务模板');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 查找第一个模板
|
||||
const firstTemplate = page.locator('table tbody tr, [class*="template-card"]').first();
|
||||
const hasTemplate = await firstTemplate.count() > 0;
|
||||
|
||||
if (hasTemplate) {
|
||||
// 查找使用模板按钮
|
||||
const useBtn = page.getByRole('button', { name: /使用 | 应用 | 创建任务/ }).first();
|
||||
const hasUseBtn = await useBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `使用模板按钮:${hasUseBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('截图保存任务模板状态', async ({ page }) => {
|
||||
// 导航到任务模板页面
|
||||
await clickSubMenu(page, '任务管理', '任务模板');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-task-templates.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '任务模板截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
114
reading-platform-frontend/tests/e2e/teacher/08-feedbacks.spec.ts
Normal file
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 课程反馈
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable } from './helpers';
|
||||
|
||||
test.describe('教师端课程反馈功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证课程反馈列表页面加载', async ({ page }) => {
|
||||
// 导航到课程反馈页面
|
||||
await clickSubMenu(page, '教学管理', '课程反馈');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/反馈 | 课程反馈 | 教学反馈/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `课程反馈标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证课程反馈数据加载', async ({ page }) => {
|
||||
// 导航到课程反馈页面
|
||||
await clickSubMenu(page, '教学管理', '课程反馈');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有反馈数据
|
||||
const hasFeedbackList = await page.locator('[class*="feedback"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无反馈/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `课程反馈数据:${hasFeedbackList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证反馈统计数据显示', async ({ page }) => {
|
||||
// 导航到课程反馈页面
|
||||
await clickSubMenu(page, '教学管理', '课程反馈');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找统计数据卡片
|
||||
const statsCards = page.locator('[class*="statistic"], [class*="stats"], [class*="chart"]');
|
||||
const hasStats = await statsCards.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `反馈统计:${hasStats ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证反馈评分显示', async ({ page }) => {
|
||||
// 导航到课程反馈页面
|
||||
await clickSubMenu(page, '教学管理', '课程反馈');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 查找第一个反馈记录
|
||||
const firstFeedback = page.locator('table tbody tr, [class*="feedback-item"]').first();
|
||||
const hasFeedback = await firstFeedback.count() > 0;
|
||||
|
||||
if (hasFeedback) {
|
||||
// 查找评分显示
|
||||
const hasRating = await page.locator('[class*="rating"], [class*="score"], .ant-rate').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `评分显示:${hasRating ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证反馈详情查看', async ({ page }) => {
|
||||
// 导航到课程反馈页面
|
||||
await clickSubMenu(page, '教学管理', '课程反馈');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找操作按钮
|
||||
const viewBtn = page.getByRole('button', { name: /查看 | 详情/ }).first();
|
||||
const hasViewBtn = await viewBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `查看详情按钮:${hasViewBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('截图保存课程反馈状态', async ({ page }) => {
|
||||
// 导航到课程反馈页面
|
||||
await clickSubMenu(page, '教学管理', '课程反馈');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-feedbacks.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '课程反馈截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
128
reading-platform-frontend/tests/e2e/teacher/09-students.spec.ts
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 学生管理
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable } from './helpers';
|
||||
|
||||
test.describe('教师端学生管理功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证学生列表页面加载', async ({ page }) => {
|
||||
// 导航到学生管理页面
|
||||
await clickSubMenu(page, '学生管理', '学生列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/学生 | 幼儿管理 | 我的学生/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `学生管理标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证学生数据加载', async ({ page }) => {
|
||||
// 导航到学生管理页面
|
||||
await clickSubMenu(page, '学生管理', '学生列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有学生数据
|
||||
const hasStudentList = await page.locator('[class*="student"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无学生/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `学生数据:${hasStudentList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证学生筛选功能', async ({ page }) => {
|
||||
// 导航到学生管理页面
|
||||
await clickSubMenu(page, '学生管理', '学生列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找筛选器
|
||||
const hasFilter = await page.locator('[class*="filter"], [class*="search"], .ant-input, .ant-select').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `筛选功能:${hasFilter ? '存在' : '不存在'}`,
|
||||
});
|
||||
|
||||
// 查找班级筛选
|
||||
const hasClassFilter = await page.getByText(/班级 | 全部班级/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `班级筛选:${hasClassFilter ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证学生详情查看', async ({ page }) => {
|
||||
// 导航到学生管理页面
|
||||
await clickSubMenu(page, '学生管理', '学生列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 查找第一个学生记录
|
||||
const firstStudent = page.locator('table tbody tr').first();
|
||||
const hasStudent = await firstStudent.count() > 0;
|
||||
|
||||
if (hasStudent) {
|
||||
// 查找查看按钮
|
||||
const viewBtn = page.getByRole('button', { name: /查看 | 详情/ }).first();
|
||||
const hasViewBtn = await viewBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `查看详情按钮:${hasViewBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证学生信息完整性', async ({ page }) => {
|
||||
// 导航到学生管理页面
|
||||
await clickSubMenu(page, '学生管理', '学生列表');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查表格列头
|
||||
const headers = page.locator('thead th');
|
||||
const headerCount = await headers.count();
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `表格列数:${headerCount}`,
|
||||
});
|
||||
|
||||
// 检查是否有姓名列
|
||||
const hasNameColumn = await page.getByText(/姓名 | 学生姓名/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `姓名显示:${hasNameColumn ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('截图保存学生管理状态', async ({ page }) => {
|
||||
// 导航到学生管理页面
|
||||
await clickSubMenu(page, '学生管理', '学生列表');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-students.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '学生管理截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
136
reading-platform-frontend/tests/e2e/teacher/10-growth.spec.ts
Normal file
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 成长记录
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForTable, waitForSuccess } from './helpers';
|
||||
|
||||
test.describe('教师端成长记录功能', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证成长记录列表页面加载', async ({ page }) => {
|
||||
// 导航到成长记录页面
|
||||
await clickSubMenu(page, '成长记录', '成长记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 验证页面标题
|
||||
const hasTitle = await page.getByText(/成长 | 成长记录 | 幼儿成长/).count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: hasTitle ? 'success' : 'warning',
|
||||
description: `成长记录标题:${hasTitle ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证成长记录数据加载', async ({ page }) => {
|
||||
// 导航到成长记录页面
|
||||
await clickSubMenu(page, '成长记录', '成长记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否有成长记录数据
|
||||
const hasRecordList = await page.locator('[class*="growth"], [class*="record"], table').count() > 0;
|
||||
const hasEmpty = await page.getByText(/暂无数据 | 暂无记录/).count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `成长记录数据:${hasRecordList ? '存在' : hasEmpty ? '空状态' : '未知'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证创建成长记录功能', async ({ page }) => {
|
||||
// 导航到成长记录页面
|
||||
await clickSubMenu(page, '成长记录', '成长记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找创建按钮
|
||||
const createBtn = page.getByRole('button', { name: /创建 | 新建 | 添加/ });
|
||||
const hasCreateBtn = await createBtn.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建按钮:${hasCreateBtn ? '存在' : '不存在'}`,
|
||||
});
|
||||
|
||||
if (hasCreateBtn) {
|
||||
// 点击创建按钮
|
||||
await createBtn.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 验证弹窗是否打开
|
||||
const hasModal = await page.locator('.ant-modal, [class*="modal"]').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `创建弹窗:${hasModal ? '打开' : '未打开'}`,
|
||||
});
|
||||
|
||||
if (hasModal) {
|
||||
// 验证表单字段
|
||||
const hasStudentSelect = await page.locator('[class*="student"] .ant-select, [placeholder*="学生"]').count() > 0;
|
||||
const hasTypeSelect = await page.locator('[class*="type"] .ant-select, [placeholder*="类型"]').count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `学生选择:${hasStudentSelect ? '存在' : '不存在'}`,
|
||||
});
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `类型选择:${hasTypeSelect ? '存在' : '不存在'}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('验证成长记录筛选功能', async ({ page }) => {
|
||||
// 导航到成长记录页面
|
||||
await clickSubMenu(page, '成长记录', '成长记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找筛选器
|
||||
const hasFilter = await page.locator('[class*="filter"], [class*="search"], .ant-input, .ant-select').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `筛选功能:${hasFilter ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证成长记录操作按钮', async ({ page }) => {
|
||||
// 导航到成长记录页面
|
||||
await clickSubMenu(page, '成长记录', '成长记录');
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 查找操作按钮(编辑、删除等)
|
||||
const actionBtns = page.locator('button:has-text("编辑"), button:has-text("删除"), button:has-text("详情")');
|
||||
const hasActionBtns = await actionBtns.count() > 0;
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `操作按钮:${hasActionBtns ? '存在' : '不存在'}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('截图保存成长记录状态', async ({ page }) => {
|
||||
// 导航到成长记录页面
|
||||
await clickSubMenu(page, '成长记录', '成长记录');
|
||||
|
||||
// 等待页面完全加载
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// 截图
|
||||
await page.screenshot({ path: 'test-results/teacher-growth-records.png' });
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '成长记录截图已保存',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,408 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 所有功能接口全面测试
|
||||
* 覆盖所有后端 API 接口并验证前端适配
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu, waitForPageLoad } from './helpers';
|
||||
|
||||
test.describe('教师端 - 所有功能接口全面测试', () => {
|
||||
let authContext: { authToken: string };
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
await page.waitForTimeout(2000);
|
||||
});
|
||||
|
||||
// ==================== 仪表盘测试 ====================
|
||||
test.describe('1. 仪表盘功能测试', () => {
|
||||
test('验证仪表盘页面加载和 API 调用', async ({ page }) => {
|
||||
await page.goto('/teacher/dashboard');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 验证页面元素
|
||||
const dashboardContent = page.locator('.ant-layout-content');
|
||||
await expect(dashboardContent).toBeVisible();
|
||||
|
||||
// 等待并验证 API 响应
|
||||
const responsePromise = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/dashboard') || res.url().includes('/teacher/stats'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await responsePromise;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `仪表盘 API: status=${response.status()}, data=${JSON.stringify(data).substring(0, 100)}`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '仪表盘页面加载成功',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 我的课表测试 ====================
|
||||
test.describe('2. 我的课表功能测试', () => {
|
||||
test('验证课表页面加载和列表 API', async ({ page }) => {
|
||||
await page.goto('/teacher/schedule');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 验证课表视图
|
||||
const scheduleView = page.locator('[class*="schedule"], [class*="timetable"]');
|
||||
await expect(scheduleView).toBeVisible({ timeout: 10000 }).catch(() => {
|
||||
test.info().annotations.push({ type: 'warning', description: '课表视图未找到,可能使用其他布局' });
|
||||
});
|
||||
|
||||
// 等待并验证排课 API
|
||||
const scheduleResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/schedules'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await scheduleResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `排课列表 API: status=${response.status()}`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '课表页面加载成功',
|
||||
});
|
||||
});
|
||||
|
||||
test('验证课程表 API(timetable)', async ({ page }) => {
|
||||
await page.goto('/teacher/schedule');
|
||||
|
||||
// 等待 timetable API 调用
|
||||
const timetableResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/schedules/timetable'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await timetableResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `课程表 API: status=${response.status()}, records=${Array.isArray(data?.data) ? data.data.length : 'N/A'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 课程列表测试 ====================
|
||||
test.describe('3. 课程列表功能测试', () => {
|
||||
test('验证课程列表页面和 API', async ({ page }) => {
|
||||
await page.goto('/teacher/courses');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 等待课程 API
|
||||
const coursesResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/courses') && !res.url().includes('/courses/'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await coursesResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `课程列表 API: status=${response.status()}, total=${data?.data?.total ?? 'N/A'}`,
|
||||
});
|
||||
}
|
||||
|
||||
// 验证课程卡片显示
|
||||
const courseCards = page.locator('[class*="course-card"], [class*="course"] .ant-card');
|
||||
const count = await courseCards.count();
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: `课程列表页面加载成功,显示 ${count} 个课程`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证班级 API 调用', async ({ page }) => {
|
||||
await page.goto('/teacher/courses');
|
||||
|
||||
const classesResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/classes'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await classesResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `班级列表 API: status=${response.status()}, count=${Array.isArray(data?.data) ? data.data.length : 'N/A'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 授课记录测试 ====================
|
||||
test.describe('4. 授课记录功能测试', () => {
|
||||
test('验证授课记录页面和列表 API', async ({ page }) => {
|
||||
await page.goto('/teacher/lessons');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 等待授课记录 API
|
||||
const lessonsResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/lessons') && !res.url().includes('/lessons/'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await lessonsResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `授课记录 API: status=${response.status()}, total=${data?.data?.total ?? 'N/A'}`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '授课记录页面加载成功',
|
||||
});
|
||||
});
|
||||
|
||||
test('验证今日授课 API', async ({ page }) => {
|
||||
await page.goto('/teacher/lessons');
|
||||
|
||||
const todayResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/lessons/today'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await todayResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `今日授课 API: status=${response.status()}, count=${Array.isArray(data?.data) ? data.data.length : 'N/A'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 班级管理测试 ====================
|
||||
test.describe('5. 班级管理功能测试', () => {
|
||||
test('验证班级列表页面和 API', async ({ page }) => {
|
||||
await page.goto('/teacher/classes');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 验证班级表格
|
||||
const table = page.locator('table, .ant-table');
|
||||
await expect(table).toBeVisible({ timeout: 10000 });
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '班级列表页面加载成功',
|
||||
});
|
||||
});
|
||||
|
||||
test('验证班级学生 API', async ({ page }) => {
|
||||
await page.goto('/teacher/classes');
|
||||
|
||||
// 等待学生 API(如果有)
|
||||
const studentsResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/classes/') && res.url().includes('/students'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await studentsResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `班级学生 API: status=${response.status()}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 学生管理测试 ====================
|
||||
test.describe('6. 学生管理功能测试', () => {
|
||||
test('验证学生列表页面和 API', async ({ page }) => {
|
||||
await page.goto('/teacher/students');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 等待学生 API
|
||||
const studentsResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/students'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await studentsResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `学生列表 API: status=${response.status()}, total=${data?.data?.total ?? 'N/A'}`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '学生列表页面加载成功',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 任务管理测试 ====================
|
||||
test.describe('7. 任务管理功能测试', () => {
|
||||
test('验证任务列表页面和 API', async ({ page }) => {
|
||||
await page.goto('/teacher/tasks');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 等待任务 API
|
||||
const tasksResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/tasks') && !res.url().includes('/tasks/'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await tasksResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `任务列表 API: status=${response.status()}, total=${data?.data?.total ?? 'N/A'}`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '任务列表页面加载成功',
|
||||
});
|
||||
});
|
||||
|
||||
test('验证任务模板 API', async ({ page }) => {
|
||||
await page.goto('/teacher/tasks');
|
||||
|
||||
// 等待任务模板 API(如果有)
|
||||
const templatesResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/task-templates') || res.url().includes('/task/template'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await templatesResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `任务模板 API: status=${response.status()}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 成长记录测试 ====================
|
||||
test.describe('8. 成长记录功能测试', () => {
|
||||
test('验证成长记录页面和 API', async ({ page }) => {
|
||||
await page.goto('/teacher/growth-records');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 等待成长记录 API
|
||||
const growthResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/growth') || res.url().includes('/teacher/records'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await growthResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `成长记录 API: status=${response.status()}`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '成长记录页面加载成功',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 教学反馈测试 ====================
|
||||
test.describe('9. 教学反馈功能测试', () => {
|
||||
test('验证反馈页面和 API', async ({ page }) => {
|
||||
await page.goto('/teacher/feedback');
|
||||
await waitForPageLoad(page);
|
||||
|
||||
// 等待反馈 API
|
||||
const feedbackResponse = page.waitForResponse(
|
||||
async (res) => res.url().includes('/teacher/feedback') || res.url().includes('/feedback'),
|
||||
{ timeout: 10000 }
|
||||
).catch(() => null);
|
||||
|
||||
const response = await feedbackResponse;
|
||||
if (response) {
|
||||
expect(response.status()).toBe(200);
|
||||
const data = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'API 验证',
|
||||
description: `反馈 API: status=${response.status()}`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '反馈页面加载成功',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 综合流程测试 ====================
|
||||
test.describe('10. 综合流程测试', () => {
|
||||
test('完整教学流程:课表 → 课程 → 授课 → 反馈', async ({ page }) => {
|
||||
const steps = [
|
||||
{ name: '仪表盘', path: '/teacher/dashboard' },
|
||||
{ name: '我的课表', path: '/teacher/schedule' },
|
||||
{ name: '课程列表', path: '/teacher/courses' },
|
||||
{ name: '授课记录', path: '/teacher/lessons' },
|
||||
{ name: '班级管理', path: '/teacher/classes' },
|
||||
{ name: '学生列表', path: '/teacher/students' },
|
||||
{ name: '任务管理', path: '/teacher/tasks' },
|
||||
{ name: '成长记录', path: '/teacher/growth-records' },
|
||||
{ name: '教学反馈', path: '/teacher/feedback' },
|
||||
];
|
||||
|
||||
for (const step of steps) {
|
||||
await page.goto(step.path);
|
||||
await waitForPageLoad(page);
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: `访问${step.name}(${step.path}) - OK`,
|
||||
});
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '完整教学流程测试通过!所有页面均可正常访问。',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 综合流程测试
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher, clickSubMenu } from './helpers';
|
||||
|
||||
test.describe('教师端综合流程测试', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('完整教学流程测试', async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'feature',
|
||||
description: '测试完整教学流程:课表 → 课程 → 授课 → 反馈',
|
||||
});
|
||||
|
||||
// 1. 访问仪表盘
|
||||
await page.goto('/teacher/dashboard');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 1: 仪表盘页面加载成功',
|
||||
});
|
||||
|
||||
// 2. 访问我的课表
|
||||
await clickSubMenu(page, '教学管理', '我的课表');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 2: 我的课表页面加载成功',
|
||||
});
|
||||
|
||||
// 3. 访问课程列表
|
||||
await clickSubMenu(page, '教学管理', '课程列表');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 3: 课程列表页面加载成功',
|
||||
});
|
||||
|
||||
// 4. 访问授课记录
|
||||
await clickSubMenu(page, '教学管理', '授课记录');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 4: 授课记录页面加载成功',
|
||||
});
|
||||
|
||||
// 5. 访问班级管理
|
||||
await clickSubMenu(page, '班级管理', '班级列表');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 5: 班级管理页面加载成功',
|
||||
});
|
||||
|
||||
// 6. 访问学生管理
|
||||
await clickSubMenu(page, '学生管理', '学生列表');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 6: 学生管理页面加载成功',
|
||||
});
|
||||
|
||||
// 7. 访问任务管理
|
||||
await clickSubMenu(page, '任务管理', '任务列表');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 7: 任务管理页面加载成功',
|
||||
});
|
||||
|
||||
// 8. 访问成长记录
|
||||
await clickSubMenu(page, '成长记录', '成长记录');
|
||||
await page.waitForTimeout(2000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '步骤 8: 成长记录页面加载成功',
|
||||
});
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '完整教学流程测试完成!',
|
||||
});
|
||||
});
|
||||
|
||||
test('验证所有菜单导航', async ({ page }) => {
|
||||
const menus = [
|
||||
{ parent: '首页', child: null, path: '/teacher/dashboard' },
|
||||
{ parent: '教学管理', child: '我的课表', path: '/teacher/schedule' },
|
||||
{ parent: '教学管理', child: '课程列表', path: '/teacher/courses' },
|
||||
{ parent: '教学管理', child: '授课记录', path: '/teacher/lessons' },
|
||||
{ parent: '班级管理', child: '班级列表', path: '/teacher/classes' },
|
||||
{ parent: '学生管理', child: '学生列表', path: '/teacher/students' },
|
||||
{ parent: '任务管理', child: '任务列表', path: '/teacher/tasks' },
|
||||
{ parent: '成长记录', child: '成长记录', path: '/teacher/growth-records' },
|
||||
];
|
||||
|
||||
for (const menu of menus) {
|
||||
if (menu.path) {
|
||||
await page.goto(menu.path);
|
||||
await page.waitForTimeout(1000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: `导航成功:${menu.parent} - ${menu.child || '首页'} (${menu.path})`,
|
||||
});
|
||||
} else if (menu.parent && menu.child) {
|
||||
await clickSubMenu(page, menu.parent, menu.child);
|
||||
await page.waitForTimeout(1000);
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: `导航成功:${menu.parent} - ${menu.child}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
test.info().annotations.push({
|
||||
type: 'success',
|
||||
description: '所有菜单导航验证完成!',
|
||||
});
|
||||
});
|
||||
|
||||
test('验证页面响应式布局', async ({ page }) => {
|
||||
// 测试不同屏幕尺寸
|
||||
const sizes = [
|
||||
{ width: 1920, height: 1080 },
|
||||
{ width: 1366, height: 768 },
|
||||
{ width: 1024, height: 768 },
|
||||
];
|
||||
|
||||
for (const size of sizes) {
|
||||
await page.setViewportSize({ width: size.width, height: size.height });
|
||||
await page.goto('/teacher/dashboard');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// 检查页面是否正常显示
|
||||
const hasContent = await page.locator('.ant-layout-content').count() > 0;
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `分辨率 ${size.width}x${size.height}: ${hasContent ? '正常' : '异常'}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
146
reading-platform-frontend/tests/e2e/teacher/99-api-test.spec.ts
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - API 接口测试
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { loginAsTeacher } from './helpers';
|
||||
|
||||
test.describe('教师端 API 接口测试', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await loginAsTeacher(page);
|
||||
});
|
||||
|
||||
test('验证仪表盘 API 调用', async ({ page }) => {
|
||||
// 设置监听 API 请求
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse(/.*\/teacher\/dashboard.*/, { timeout: 10000 }),
|
||||
page.goto('/teacher/dashboard'),
|
||||
]);
|
||||
|
||||
// 验证响应状态
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
// 验证响应数据格式
|
||||
const jsonData = await response.json();
|
||||
expect(jsonData).toBeDefined();
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `仪表盘 API 响应:${JSON.stringify(jsonData).substring(0, 200)}`,
|
||||
});
|
||||
});
|
||||
|
||||
test('验证课程列表 API 调用', async ({ page }) => {
|
||||
await page.goto('/teacher/courses');
|
||||
|
||||
try {
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse(/.*\/teacher\/courses.*/, { timeout: 10000 }),
|
||||
]);
|
||||
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
const jsonData = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `课程列表 API 响应:${JSON.stringify(jsonData).substring(0, 200)}`,
|
||||
});
|
||||
} catch (e) {
|
||||
test.info().annotations.push({
|
||||
type: 'warning',
|
||||
description: '课程列表 API 请求未捕获到',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证班级列表 API 调用', async ({ page }) => {
|
||||
await page.goto('/teacher/classes');
|
||||
|
||||
try {
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse(/.*\/teacher\/classes.*/, { timeout: 10000 }),
|
||||
]);
|
||||
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
const jsonData = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `班级列表 API 响应:${JSON.stringify(jsonData).substring(0, 200)}`,
|
||||
});
|
||||
} catch (e) {
|
||||
test.info().annotations.push({
|
||||
type: 'warning',
|
||||
description: '班级列表 API 请求未捕获到',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证授课记录列表 API 调用', async ({ page }) => {
|
||||
await page.goto('/teacher/lessons');
|
||||
|
||||
try {
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse(/.*\/teacher\/lessons.*/, { timeout: 10000 }),
|
||||
]);
|
||||
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
const jsonData = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `授课记录 API 响应:${JSON.stringify(jsonData).substring(0, 200)}`,
|
||||
});
|
||||
} catch (e) {
|
||||
test.info().annotations.push({
|
||||
type: 'warning',
|
||||
description: '授课记录 API 请求未捕获到',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证任务列表 API 调用', async ({ page }) => {
|
||||
await page.goto('/teacher/tasks');
|
||||
|
||||
try {
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse(/.*\/teacher\/tasks.*/, { timeout: 10000 }),
|
||||
]);
|
||||
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
const jsonData = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `任务列表 API 响应:${JSON.stringify(jsonData).substring(0, 200)}`,
|
||||
});
|
||||
} catch (e) {
|
||||
test.info().annotations.push({
|
||||
type: 'warning',
|
||||
description: '任务列表 API 请求未捕获到',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('验证课表 API 调用', async ({ page }) => {
|
||||
await page.goto('/teacher/schedule');
|
||||
|
||||
try {
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse(/.*\/teacher\/schedules.*/, { timeout: 10000 }),
|
||||
]);
|
||||
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
const jsonData = await response.json();
|
||||
test.info().annotations.push({
|
||||
type: 'info',
|
||||
description: `课表 API 响应:${JSON.stringify(jsonData).substring(0, 200)}`,
|
||||
});
|
||||
} catch (e) {
|
||||
test.info().annotations.push({
|
||||
type: 'warning',
|
||||
description: '课表 API 请求未捕获到',
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
70
reading-platform-frontend/tests/e2e/teacher/fixtures.ts
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 测试数据和常量
|
||||
*/
|
||||
|
||||
export const TEACHER_CONFIG = {
|
||||
account: 'teacher1',
|
||||
password: '123456',
|
||||
dashboardPath: '/teacher/dashboard',
|
||||
};
|
||||
|
||||
export const TEST_DATA = {
|
||||
schedule: {
|
||||
classId: 1,
|
||||
courseId: 1,
|
||||
scheduledTime: '09:00',
|
||||
repeatType: 'WEEKLY',
|
||||
},
|
||||
lesson: {
|
||||
title: `测试授课_${Date.now()}`,
|
||||
status: 'pending',
|
||||
},
|
||||
studentRecord: {
|
||||
focus: 4,
|
||||
participation: 5,
|
||||
interest: 4,
|
||||
understanding: 3,
|
||||
notes: '测试评价记录',
|
||||
},
|
||||
feedback: {
|
||||
designQuality: 4,
|
||||
participation: 5,
|
||||
goalAchievement: 4,
|
||||
pros: '课程设计很好',
|
||||
suggestions: '可以增加更多互动环节',
|
||||
},
|
||||
task: {
|
||||
title: `测试任务_${Date.now()}`,
|
||||
description: '测试任务描述',
|
||||
taskType: 'READING' as const,
|
||||
targetType: 'CLASS' as const,
|
||||
startDate: '2026-03-16',
|
||||
endDate: '2026-03-30',
|
||||
},
|
||||
taskTemplate: {
|
||||
name: `测试模板_${Date.now()}`,
|
||||
description: '测试任务模板描述',
|
||||
taskType: 'READING' as const,
|
||||
defaultDuration: 7,
|
||||
},
|
||||
growth: {
|
||||
type: 'reading',
|
||||
description: '测试成长记录',
|
||||
score: 5,
|
||||
},
|
||||
};
|
||||
|
||||
// 班级年级映射
|
||||
export const GRADE_MAP: Record<string, string> = {
|
||||
nursery: '托班',
|
||||
small: '小班',
|
||||
middle: '中班',
|
||||
big: '大班',
|
||||
};
|
||||
|
||||
// 教师角色映射
|
||||
export const TEACHER_ROLE_MAP: Record<string, string> = {
|
||||
MAIN: '主班',
|
||||
ASSIST: '配班',
|
||||
CARE: '保育',
|
||||
};
|
||||
189
reading-platform-frontend/tests/e2e/teacher/helpers.ts
Normal file
@ -0,0 +1,189 @@
|
||||
/**
|
||||
* 教师端 E2E 测试 - 通用工具函数
|
||||
*/
|
||||
|
||||
import { Page, expect } from '@playwright/test';
|
||||
import { TEACHER_CONFIG } from './fixtures';
|
||||
|
||||
/**
|
||||
* 使用教师端账号登录
|
||||
*/
|
||||
export async function loginAsTeacher(page: Page) {
|
||||
await page.goto('/login');
|
||||
|
||||
// 点击教师角色按钮
|
||||
await page.locator('.role-btn').filter({ hasText: '教师' }).first().click();
|
||||
|
||||
// 输入账号密码
|
||||
await page.getByPlaceholder('请输入账号').fill(TEACHER_CONFIG.account);
|
||||
await page.getByPlaceholder('请输入密码').fill(TEACHER_CONFIG.password);
|
||||
|
||||
// 点击登录按钮
|
||||
await page.locator('.login-btn').click();
|
||||
|
||||
// 等待登录按钮消失(表示登录请求完成)
|
||||
await page.locator('.login-btn').waitFor({ state: 'hidden', timeout: 10000 });
|
||||
|
||||
// 等待页面加载
|
||||
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
|
||||
|
||||
// 等待 URL 包含 teacher(使用正则表达式)
|
||||
await page.waitForURL(/teacher/, { timeout: 5000 }).catch(() => {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击二级菜单项
|
||||
* @param page 页面对象
|
||||
* @param parentMenu 一级菜单文本
|
||||
* @param childMenu 二级菜单文本
|
||||
*/
|
||||
export async function clickSubMenu(page: Page, parentMenu: string, childMenu: string) {
|
||||
// 等待页面加载
|
||||
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 检查侧边栏是否折叠,如果折叠则展开
|
||||
const isCollapsed = await page.locator('.ant-layout-sider-collapsed').count() > 0;
|
||||
if (isCollapsed) {
|
||||
const collapseButton = page.locator('.trigger').first();
|
||||
await collapseButton.click();
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
// 点击一级菜单展开
|
||||
const parentMenuItem = page.locator('.ant-menu-submenu-title:has-text("' + parentMenu + '")').first();
|
||||
await parentMenuItem.click();
|
||||
|
||||
// 等待二级菜单 DOM 出现
|
||||
await page.waitForSelector('.ant-menu-submenu-open', { timeout: 5000 }).catch(() => {});
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// 使用 evaluate 在浏览器上下文中点击,绕过可见性检查
|
||||
await page.evaluate((menuText) => {
|
||||
const items = Array.from(document.querySelectorAll('.ant-menu-item'));
|
||||
const target = items.find(item => item.textContent?.includes(menuText));
|
||||
if (target) {
|
||||
(target as HTMLElement).click();
|
||||
}
|
||||
}, childMenu);
|
||||
|
||||
await page.waitForTimeout(1500);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
export async function logout(page: Page) {
|
||||
// 尝试多种方式找到退出登录按钮
|
||||
|
||||
// 方式 1:查找退出登录按钮
|
||||
const logoutBtn1 = page.getByText(/退出登录 | 退出|logout/i).first();
|
||||
if (await logoutBtn1.count() > 0) {
|
||||
try {
|
||||
await logoutBtn1.click({ timeout: 3000 });
|
||||
await page.waitForURL(/.*\/login.*/, { timeout: 10000 }).catch(() => {});
|
||||
return;
|
||||
} catch (e) {
|
||||
// 如果点击失败,继续尝试其他方式
|
||||
}
|
||||
}
|
||||
|
||||
// 方式 2:查找用户头像/菜单按钮并点击
|
||||
const userMenuBtn = page.locator('.ant-dropdown-trigger, .user-menu, [class*="user"]').first();
|
||||
if (await userMenuBtn.count() > 0) {
|
||||
try {
|
||||
await userMenuBtn.click({ timeout: 3000 });
|
||||
await page.waitForTimeout(500);
|
||||
const logoutInMenu = page.getByText(/退出登录 | 退出|logout/i).first();
|
||||
if (await logoutInMenu.count() > 0) {
|
||||
await logoutInMenu.click({ timeout: 3000 });
|
||||
await page.waitForURL(/.*\/login.*/, { timeout: 10000 }).catch(() => {});
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// 如果点击失败,继续尝试其他方式
|
||||
}
|
||||
}
|
||||
|
||||
// 方式 3:尝试清空 localStorage 和 sessionStorage 并跳转到登录页
|
||||
await page.evaluate(() => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
});
|
||||
await page.goto('/login');
|
||||
await page.waitForURL(/.*\/login.*/, { timeout: 10000 });
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待表格加载完成
|
||||
*/
|
||||
export async function waitForTable(page: Page, timeout = 10000) {
|
||||
await page.waitForSelector('table, .ant-table', { timeout });
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待弹窗显示
|
||||
*/
|
||||
export async function waitForModal(page: Page, title?: string, timeout = 5000) {
|
||||
if (title) {
|
||||
await page.getByText(title).waitFor({ timeout });
|
||||
} else {
|
||||
await page.waitForSelector('.ant-modal', { timeout });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待成功提示
|
||||
*/
|
||||
export async function waitForSuccess(page: Page, message?: string, timeout = 5000) {
|
||||
if (message) {
|
||||
await page.getByText(message).waitFor({ timeout });
|
||||
} else {
|
||||
await page.waitForSelector('.ant-message-success', { timeout });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待错误提示
|
||||
*/
|
||||
export async function waitForError(page: Page, message?: string, timeout = 5000) {
|
||||
if (message) {
|
||||
await page.getByText(message).waitFor({ timeout });
|
||||
} else {
|
||||
await page.waitForSelector('.ant-message-error', { timeout });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在表格中查找并点击操作按钮
|
||||
*/
|
||||
export async function clickRowAction(page: Page, rowName: string, action: string) {
|
||||
const row = page.getByRole('row').filter({ hasText: rowName });
|
||||
await row.getByRole('button', { name: action }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
export async function closeModal(page: Page) {
|
||||
await page.keyboard.press('Escape');
|
||||
// 或者点击关闭按钮
|
||||
const closeBtn = page.locator('.ant-modal-close');
|
||||
if (await closeBtn.count() > 0) {
|
||||
await closeBtn.click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待页面加载完成
|
||||
*/
|
||||
export async function waitForPageLoad(page: Page, timeout = 10000) {
|
||||
await page.waitForLoadState('networkidle', { timeout });
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待 API 请求完成
|
||||
*/
|
||||
export async function waitForAPI(page: Page, urlPattern: string | RegExp, timeout = 10000) {
|
||||
await page.waitForResponse(urlPattern, { timeout }).catch(() => {});
|
||||
}
|
||||
@ -59,9 +59,12 @@ public class AdminCourseController {
|
||||
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(required = false, defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false) String category) {
|
||||
log.info("查询课程列表,pageNum={}, pageSize={}, keyword={}, category={}", pageNum, pageSize, keyword, category);
|
||||
Page<Course> page = courseService.getSystemCoursePage(pageNum, pageSize, keyword, category, null, false);
|
||||
@RequestParam(required = false) String category,
|
||||
@RequestParam(required = false) String status,
|
||||
@RequestParam(required = false, defaultValue = "false") Boolean reviewOnly) {
|
||||
log.info("查询课程列表,pageNum={}, pageSize={}, keyword={}, category={}, status={}, reviewOnly={}",
|
||||
pageNum, pageSize, keyword, category, status, reviewOnly);
|
||||
Page<Course> page = courseService.getSystemCoursePage(pageNum, pageSize, keyword, category, status, reviewOnly);
|
||||
PageResult<Course> result = PageResult.of(page);
|
||||
log.info("课程列表查询结果,total={}, list={}", result.getTotal(), result.getList().size());
|
||||
return Result.success(result);
|
||||
|
||||
@ -18,18 +18,42 @@ public class LessonFeedbackResponse {
|
||||
@Schema(description = "ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "课时 ID")
|
||||
@Schema(description = "课程 ID")
|
||||
private Long lessonId;
|
||||
|
||||
@Schema(description = "教师 ID")
|
||||
private Long teacherId;
|
||||
|
||||
@Schema(description = "内容")
|
||||
@Schema(description = "教师姓名")
|
||||
private String teacherName;
|
||||
|
||||
@Schema(description = "反馈内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "评分")
|
||||
private Integer rating;
|
||||
|
||||
@Schema(description = "教学设计评分 (1-5)")
|
||||
private Integer designQuality;
|
||||
|
||||
@Schema(description = "学生参与度评分 (1-5)")
|
||||
private Integer participation;
|
||||
|
||||
@Schema(description = "目标达成度评分 (1-5)")
|
||||
private Integer goalAchievement;
|
||||
|
||||
@Schema(description = "各步骤反馈 (JSON 数组)")
|
||||
private String stepFeedbacks;
|
||||
|
||||
@Schema(description = "优点")
|
||||
private String pros;
|
||||
|
||||
@Schema(description = "建议")
|
||||
private String suggestions;
|
||||
|
||||
@Schema(description = "已完成的活动")
|
||||
private String activitiesDone;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
|
||||
@ -28,11 +28,41 @@ public class SchedulePlanResponse {
|
||||
@Schema(description = "班级 ID")
|
||||
private Long classId;
|
||||
|
||||
@Schema(description = "开始日期")
|
||||
private LocalDate startDate;
|
||||
@Schema(description = "班级名称")
|
||||
private String className;
|
||||
|
||||
@Schema(description = "结束日期")
|
||||
private LocalDate endDate;
|
||||
@Schema(description = "课程 ID")
|
||||
private Long courseId;
|
||||
|
||||
@Schema(description = "课程名称")
|
||||
private String courseName;
|
||||
|
||||
@Schema(description = "教师 ID")
|
||||
private Long teacherId;
|
||||
|
||||
@Schema(description = "教师姓名")
|
||||
private String teacherName;
|
||||
|
||||
@Schema(description = "排课日期")
|
||||
private LocalDate scheduledDate;
|
||||
|
||||
@Schema(description = "时间段 (如:09:00-10:00)")
|
||||
private String scheduledTime;
|
||||
|
||||
@Schema(description = "星期几 (1-7)")
|
||||
private Integer weekDay;
|
||||
|
||||
@Schema(description = "重复方式 (NONE/WEEKLY)")
|
||||
private String repeatType;
|
||||
|
||||
@Schema(description = "重复截止日期")
|
||||
private LocalDate repeatEndDate;
|
||||
|
||||
@Schema(description = "来源 (SCHOOL/TEACHER)")
|
||||
private String source;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String note;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@ -24,6 +24,9 @@ public class StudentRecordResponse {
|
||||
@Schema(description = "学生 ID")
|
||||
private Long studentId;
|
||||
|
||||
@Schema(description = "学生姓名")
|
||||
private String studentName;
|
||||
|
||||
@Schema(description = "出勤状态")
|
||||
private String attendance;
|
||||
|
||||
@ -33,6 +36,21 @@ public class StudentRecordResponse {
|
||||
@Schema(description = "备注")
|
||||
private String notes;
|
||||
|
||||
@Schema(description = "专注度评分 (1-5)")
|
||||
private Integer focus;
|
||||
|
||||
@Schema(description = "参与度评分 (1-5)")
|
||||
private Integer participation;
|
||||
|
||||
@Schema(description = "兴趣度评分 (1-5)")
|
||||
private Integer interest;
|
||||
|
||||
@Schema(description = "理解度评分 (1-5)")
|
||||
private Integer understanding;
|
||||
|
||||
@Schema(description = "领域达成 (JSON 数组)")
|
||||
private String domainAchievements;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
|
||||
@ -30,6 +30,24 @@ public class TaskTemplateResponse {
|
||||
@Schema(description = "模板类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "任务类型")
|
||||
private String taskType;
|
||||
|
||||
@Schema(description = "关联课程 ID")
|
||||
private Long relatedCourseId;
|
||||
|
||||
@Schema(description = "默认持续时间 (天)")
|
||||
private Integer defaultDuration;
|
||||
|
||||
@Schema(description = "是否默认模板")
|
||||
private Integer isDefault;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "创建人 ID")
|
||||
private Long createdBy;
|
||||
|
||||
@Schema(description = "模板内容")
|
||||
private String content;
|
||||
|
||||
|
||||