feat: Add "lesson" page and related components
This commit adds a new "lesson" page along with the necessary components and types. The "lesson" page displays the details of a specific lesson and includes a dynamic route parameter for the lesson name. Additionally, the commit includes updates to the `pages.json` file to configure the navigation bar title for the "lesson" page.
This commit is contained in:
parent
8f0c422dd8
commit
53287e4cbd
3
components.d.ts
vendored
3
components.d.ts
vendored
@ -12,8 +12,11 @@ declare module 'vue' {
|
|||||||
WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default']
|
WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default']
|
||||||
WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default']
|
WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default']
|
||||||
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
|
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
|
||||||
|
WdCollapse: typeof import('wot-design-uni/components/wd-collapse/wd-collapse.vue')['default']
|
||||||
|
WdCollapseItem: typeof import('wot-design-uni/components/wd-collapse-item/wd-collapse-item.vue')['default']
|
||||||
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
|
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
|
||||||
WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default']
|
WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default']
|
||||||
|
WdProgress: typeof import('wot-design-uni/components/wd-progress/wd-progress.vue')['default']
|
||||||
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
|
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
|
||||||
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
|
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
|
||||||
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
|
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import http from "@/http/HttpClient";
|
import http from "@/http/HttpClient";
|
||||||
|
import { useUser } from "@/stores/useUser";
|
||||||
|
import type { PagedData } from "@/types/api/common";
|
||||||
|
import type { Lesson } from "@/types/api/lesson";
|
||||||
import type { User } from "@/types/api/user";
|
import type { User } from "@/types/api/user";
|
||||||
|
|
||||||
export interface LoginRequest extends Record<string, string> {
|
export interface LoginRequest extends Record<string, string> {
|
||||||
@ -25,4 +28,17 @@ export default class BussApi {
|
|||||||
})
|
})
|
||||||
.then((res) => res.data);
|
.then((res) => res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static lessons(page: number = 1, limit: number = 20): Promise<PagedData<Lesson>> {
|
||||||
|
const user = useUser();
|
||||||
|
return http
|
||||||
|
.server()
|
||||||
|
.get("/lesson/task", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${user.token}`,
|
||||||
|
},
|
||||||
|
params: { page, limit },
|
||||||
|
})
|
||||||
|
.then((res) => res.data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,12 @@ export default class ApiClient {
|
|||||||
if (response.data.code === 10001) {
|
if (response.data.code === 10001) {
|
||||||
const pages = getCurrentPages() as any[];
|
const pages = getCurrentPages() as any[];
|
||||||
const user = useUser();
|
const user = useUser();
|
||||||
user.logout();
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.showToast({ title: "登录已过期,请重新登录", icon: "none" });
|
uni.showToast({
|
||||||
|
title: !!user.token ? "登录已过期,请重新登录" : "请先登录",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
user.logout();
|
||||||
}, 300);
|
}, 300);
|
||||||
if (
|
if (
|
||||||
!pages[pages.length - 1].$page ||
|
!pages[pages.length - 1].$page ||
|
||||||
|
@ -20,6 +20,13 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "登录"
|
"navigationBarTitleText": "登录"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lesson",
|
||||||
|
"path": "pages/lesson/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "课程进度"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
|
@ -1,43 +1,70 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import BussApi from '@/api/BussApi';
|
||||||
|
import pageWrapper from '@/components/page-wrapper.vue';
|
||||||
|
import type { Lesson } from '@/types/api/lesson';
|
||||||
|
import { useRouter } from 'uni-mini-router';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { useToast } from 'wot-design-uni';
|
||||||
|
|
||||||
|
const toast = useToast()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const expandedCourse = ref(['lesson'])
|
||||||
|
const groupLessons = ref<{ [key: string]: Lesson[] }>({})
|
||||||
|
|
||||||
|
const openLessonDetail = (lessonName: string) => {
|
||||||
|
console.log(router.routes);
|
||||||
|
|
||||||
|
router.push({
|
||||||
|
name: 'lesson',
|
||||||
|
params: {
|
||||||
|
lessonName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
toast.loading({
|
||||||
|
msg: '加载中...'
|
||||||
|
})
|
||||||
|
BussApi.lessons().then(res => {
|
||||||
|
toast.close()
|
||||||
|
const groupData = res.data.reduce((acc: any, cur: any) => {
|
||||||
|
if (!acc[cur.m_lesson_name]) {
|
||||||
|
acc[cur.m_lesson_name] = []
|
||||||
|
}
|
||||||
|
acc[cur.m_lesson_name].push(cur)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
groupLessons.value = groupData
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<page-wrapper>
|
<page-wrapper>
|
||||||
<div class="content">
|
<div>
|
||||||
<img class="logo" src="/static/logo.png" />
|
<wd-collapse v-model="expandedCourse">
|
||||||
<div class="flex flex-col items-center gap-4">
|
<wd-collapse-item v-for="(lessons, lessonName) in groupLessons" :title="`${lessonName}`" :name="`${lessonName}`"
|
||||||
<p class="title text-4xl text-neutral-300 font-bold">
|
:key="lessonName">
|
||||||
XSH PPMS
|
<div class="w-full">
|
||||||
</p>
|
<!-- <wd-card type="rectangle" v-for="(course, i) in lessons" :title="course.course_name">
|
||||||
</div>
|
todo
|
||||||
|
</wd-card> -->
|
||||||
|
<div v-for="(course, i) in lessons" :key="i" @click="openLessonDetail(`${lessonName}`)"
|
||||||
|
class="w-full flex justify-between items-center gap-20" style="justify-content: space-between;">
|
||||||
|
<div class="">
|
||||||
|
{{ course.course_name || '无标题课程' }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<wd-progress :percentage="30" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</wd-collapse-item>
|
||||||
|
</wd-collapse>
|
||||||
</div>
|
</div>
|
||||||
</page-wrapper>
|
</page-wrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<style></style>
|
||||||
import pageWrapper from '@/components/page-wrapper.vue';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 200rpx;
|
|
||||||
width: 200rpx;
|
|
||||||
margin-top: 200rpx;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-bottom: 50rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-area {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 36rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
16
src/pages/lesson/index.vue
Normal file
16
src/pages/lesson/index.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useRoute } from 'uni-mini-router';
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1>lesson detail</h1>
|
||||||
|
<p>{{ decodeURI(route.params?.lessonName) }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BussApi from '@/api/BussApi';
|
import BussApi from '@/api/BussApi';
|
||||||
import { useUser } from '@/stores/useUser';
|
import { useUser } from '@/stores/useUser';
|
||||||
|
import { useTabbar } from '@/stores/useTabbar';
|
||||||
import { useRouter } from 'uni-mini-router';
|
import { useRouter } from 'uni-mini-router';
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { useToast } from 'wot-design-uni';
|
import { useToast } from 'wot-design-uni';
|
||||||
@ -8,6 +9,7 @@ import { useToast } from 'wot-design-uni';
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
|
const tab = useTabbar()
|
||||||
|
|
||||||
const model = reactive<{
|
const model = reactive<{
|
||||||
email: string
|
email: string
|
||||||
@ -41,6 +43,7 @@ const handleSubmit = () => {
|
|||||||
user.userinfo = res
|
user.userinfo = res
|
||||||
toast.success({ msg: '登录成功' })
|
toast.success({ msg: '登录成功' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
tab.activeTab = 'home'
|
||||||
router.pushTab('/pages/index/index')
|
router.pushTab('/pages/index/index')
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
@ -4,8 +4,10 @@ import pageWrapper from '@/components/page-wrapper.vue';
|
|||||||
import { useUser } from '@/stores/useUser';
|
import { useUser } from '@/stores/useUser';
|
||||||
import { useRouter } from 'uni-mini-router';
|
import { useRouter } from 'uni-mini-router';
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
|
import { useToast } from 'wot-design-uni';
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const toast = useToast()
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
@ -14,7 +16,11 @@ const logout = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
toast.loading({
|
||||||
|
msg: '加载中...'
|
||||||
|
})
|
||||||
BussApi.profile(user.token!).then(res => {
|
BussApi.profile(user.token!).then(res => {
|
||||||
|
toast.close()
|
||||||
user.userinfo = res
|
user.userinfo = res
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
26
src/types/api/common.ts
Normal file
26
src/types/api/common.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export interface PagedRequest {
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PagedData<T> {
|
||||||
|
current_page: number;
|
||||||
|
data: T[];
|
||||||
|
first_page_url: string;
|
||||||
|
from: number;
|
||||||
|
last_page: number;
|
||||||
|
last_page_url: string;
|
||||||
|
links: Link[];
|
||||||
|
next_page_url: null;
|
||||||
|
path: string;
|
||||||
|
per_page: number;
|
||||||
|
prev_page_url: null;
|
||||||
|
to: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Link {
|
||||||
|
url: null | string;
|
||||||
|
label: string;
|
||||||
|
active: boolean;
|
||||||
|
}
|
17
src/types/api/lesson.ts
Normal file
17
src/types/api/lesson.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export interface Lesson {
|
||||||
|
id: number;
|
||||||
|
course_name: string;
|
||||||
|
m_lesson_name: string;
|
||||||
|
user_id: number | null;
|
||||||
|
schedule_status: number;
|
||||||
|
script_confirm_time: number;
|
||||||
|
video_confirm_time: number;
|
||||||
|
finish_time: number;
|
||||||
|
script_upload_time: number;
|
||||||
|
video_capture_time: number;
|
||||||
|
script_file: null;
|
||||||
|
material_file: null;
|
||||||
|
capture_file: null;
|
||||||
|
advise: null;
|
||||||
|
created_at: string;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user