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']
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
|
@ -1,4 +1,7 @@
|
||||
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";
|
||||
|
||||
export interface LoginRequest extends Record<string, string> {
|
||||
@ -25,4 +28,17 @@ export default class BussApi {
|
||||
})
|
||||
.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) {
|
||||
const pages = getCurrentPages() as any[];
|
||||
const user = useUser();
|
||||
user.logout();
|
||||
setTimeout(() => {
|
||||
uni.showToast({ title: "登录已过期,请重新登录", icon: "none" });
|
||||
uni.showToast({
|
||||
title: !!user.token ? "登录已过期,请重新登录" : "请先登录",
|
||||
icon: "none",
|
||||
});
|
||||
user.logout();
|
||||
}, 300);
|
||||
if (
|
||||
!pages[pages.length - 1].$page ||
|
||||
|
@ -20,6 +20,13 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lesson",
|
||||
"path": "pages/lesson/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "课程进度"
|
||||
}
|
||||
}
|
||||
],
|
||||
"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>
|
||||
<page-wrapper>
|
||||
<div class="content">
|
||||
<img class="logo" src="/static/logo.png" />
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<p class="title text-4xl text-neutral-300 font-bold">
|
||||
XSH PPMS
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<wd-collapse v-model="expandedCourse">
|
||||
<wd-collapse-item v-for="(lessons, lessonName) in groupLessons" :title="`${lessonName}`" :name="`${lessonName}`"
|
||||
:key="lessonName">
|
||||
<div class="w-full">
|
||||
<!-- <wd-card type="rectangle" v-for="(course, i) in lessons" :title="course.course_name">
|
||||
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>
|
||||
</page-wrapper>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
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>
|
||||
<style></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>
|
||||
import BussApi from '@/api/BussApi';
|
||||
import { useUser } from '@/stores/useUser';
|
||||
import { useTabbar } from '@/stores/useTabbar';
|
||||
import { useRouter } from 'uni-mini-router';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useToast } from 'wot-design-uni';
|
||||
@ -8,6 +9,7 @@ import { useToast } from 'wot-design-uni';
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
const user = useUser()
|
||||
const tab = useTabbar()
|
||||
|
||||
const model = reactive<{
|
||||
email: string
|
||||
@ -41,6 +43,7 @@ const handleSubmit = () => {
|
||||
user.userinfo = res
|
||||
toast.success({ msg: '登录成功' })
|
||||
setTimeout(() => {
|
||||
tab.activeTab = 'home'
|
||||
router.pushTab('/pages/index/index')
|
||||
}, 1000)
|
||||
}).catch(err => {
|
||||
|
@ -4,8 +4,10 @@ import pageWrapper from '@/components/page-wrapper.vue';
|
||||
import { useUser } from '@/stores/useUser';
|
||||
import { useRouter } from 'uni-mini-router';
|
||||
import { onMounted } from 'vue';
|
||||
import { useToast } from 'wot-design-uni';
|
||||
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
const user = useUser()
|
||||
|
||||
const logout = () => {
|
||||
@ -14,7 +16,11 @@ const logout = () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
toast.loading({
|
||||
msg: '加载中...'
|
||||
})
|
||||
BussApi.profile(user.token!).then(res => {
|
||||
toast.close()
|
||||
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