parent
eeed36b787
commit
331e7dc95f
@ -0,0 +1,38 @@ |
|||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import {curriculum} from "@/api"; |
||||||
|
|
||||||
|
const KEY = 'unique_ident' |
||||||
|
|
||||||
|
|
||||||
|
/** 设置学习记录缓存 */ |
||||||
|
function set(data: HourCacheParam) { |
||||||
|
Taro.removeStorageSync(KEY) |
||||||
|
Taro.setStorage({ |
||||||
|
key: KEY, |
||||||
|
data |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 上传学习记录 |
||||||
|
* @param duration 视频播放的学习时长 |
||||||
|
* @param start_date 记录当前的时间戳 |
||||||
|
* @param upload 是否上传 |
||||||
|
*/ |
||||||
|
function put(duration?: number, start_date?: number, upload = true) { |
||||||
|
const data: HourCacheParam | undefined = Taro.getStorageSync(KEY) |
||||||
|
if (data) { |
||||||
|
data.duration = duration || data.duration |
||||||
|
data.start_date = start_date || data.start_date |
||||||
|
Taro.setStorageSync(KEY, data) |
||||||
|
if (upload) { |
||||||
|
curriculum.hourCache(data.courseId, data) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export default { |
||||||
|
set, |
||||||
|
put |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
export default definePageConfig({ |
||||||
|
navigationBarTitleText: '课程学习记录' |
||||||
|
}) |
@ -0,0 +1,55 @@ |
|||||||
|
page { |
||||||
|
padding: 30px; |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
|
||||||
|
.cur { |
||||||
|
background: #fff; |
||||||
|
overflow: hidden; |
||||||
|
border-radius: 16px; |
||||||
|
font-weight: bold; |
||||||
|
|
||||||
|
View { |
||||||
|
color: #323635; |
||||||
|
padding: 24px; |
||||||
|
} |
||||||
|
|
||||||
|
Image { |
||||||
|
width: 100%; |
||||||
|
height: 288rpx; |
||||||
|
display: block; |
||||||
|
background: #ddd; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.record { |
||||||
|
background: #fff; |
||||||
|
overflow: hidden; |
||||||
|
border-radius: 16px; |
||||||
|
font-weight: bold; |
||||||
|
padding: 0 24px; |
||||||
|
margin-top: 30px; |
||||||
|
font-weight: 400; |
||||||
|
} |
||||||
|
|
||||||
|
.recordItem { |
||||||
|
padding: 24px 0 38rpx; |
||||||
|
border-bottom: 1px solid #F5F8F7; |
||||||
|
|
||||||
|
Progress { |
||||||
|
margin-top: 16px; |
||||||
|
color: #45D4A8; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.hourRecord { |
||||||
|
padding: 30px; |
||||||
|
max-height: 70vh; |
||||||
|
overflow: auto; |
||||||
|
|
||||||
|
& > View { |
||||||
|
padding-bottom: env(safe-area-inset-bottom); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,76 @@ |
|||||||
|
import {Image, PageContainer, Progress, View} from "@tarojs/components"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import styles from './curHistory.module.scss' |
||||||
|
import {useState} from "react"; |
||||||
|
import {userApi} from "@/api"; |
||||||
|
import {formatDateTime, formatMinute} from "@/utils/time"; |
||||||
|
|
||||||
|
const CurHistory = () => { |
||||||
|
const [show, setShow] = useState(false) |
||||||
|
const {course_id, name} = Taro.getCurrentInstance().preloadData as { course_id: number, name: string } |
||||||
|
const [data, setData] = useState<userRecord[]>([]) |
||||||
|
|
||||||
|
Taro.useLoad(() => { |
||||||
|
Taro.setNavigationBarTitle({title: name}) |
||||||
|
userApi.courseRecord(course_id).then(res => { |
||||||
|
setData(Object.values(res)) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
function setHour() { |
||||||
|
setShow(true) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<View> |
||||||
|
<View className={styles.cur}> |
||||||
|
<Image src={''} mode='aspectFit'/> |
||||||
|
<View>{name}</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
|
||||||
|
<View className={styles.record}> |
||||||
|
|
||||||
|
{ |
||||||
|
data.map(d => <View onClick={() => setHour()} className={styles.recordItem}> |
||||||
|
<View>{formatDateTime(new Date(d.start_at), "MM-dd HH:ss")} - {formatDateTime(new Date(d.end_at), "MM-dd HH:ss")}</View> |
||||||
|
<View>观看:{formatMinute(d.duration)}</View> |
||||||
|
<Progress |
||||||
|
percent={d.duration} |
||||||
|
showInfo |
||||||
|
borderRadius={10} |
||||||
|
active |
||||||
|
strokeWidth={10} |
||||||
|
color={'#45D4A8'} |
||||||
|
/> |
||||||
|
</View>) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
</View> |
||||||
|
|
||||||
|
<PageContainer |
||||||
|
show={show} |
||||||
|
round |
||||||
|
onAfterLeave={() => setShow(false)}> |
||||||
|
{show && <View className={styles.hourRecord}> |
||||||
|
<View> |
||||||
|
<View onClick={() => setHour()} className={styles.recordItem}> |
||||||
|
<View>2023-6-19</View> |
||||||
|
<Progress |
||||||
|
percent={10} |
||||||
|
showInfo |
||||||
|
borderRadius={10} |
||||||
|
active |
||||||
|
strokeWidth={10} |
||||||
|
color={'#45D4A8'} |
||||||
|
/> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View>} |
||||||
|
</PageContainer> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default CurHistory |
@ -0,0 +1,35 @@ |
|||||||
|
import {FC, useState} from "react"; |
||||||
|
import {View} from "@tarojs/components"; |
||||||
|
import {publicApi} from "@/api/public"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import Tabs, {OnChangOpt, TabList} from "@/components/tabs/tabs"; |
||||||
|
|
||||||
|
interface Props { |
||||||
|
changeTabs: (id: number) => void |
||||||
|
} |
||||||
|
|
||||||
|
const CategoryTabs: FC<Props> = ({changeTabs}) => { |
||||||
|
const [tabs, setTabs] = useState<TabList[]>([]) |
||||||
|
|
||||||
|
async function getData() { |
||||||
|
const res = await publicApi.category() |
||||||
|
const data = Object.values(res.categories).reduce((pre, cur) => { |
||||||
|
pre.push(...cur) |
||||||
|
return pre |
||||||
|
}, []).map<TabList>(d => ({title: d.name, value: d.id})) |
||||||
|
setTabs(data) |
||||||
|
changeTabs(data[0].value as number) |
||||||
|
} |
||||||
|
|
||||||
|
function onChange(data: OnChangOpt) { |
||||||
|
changeTabs(data.tab?.value as number) |
||||||
|
} |
||||||
|
|
||||||
|
Taro.useLoad(getData) |
||||||
|
return ( |
||||||
|
<View className='bg-white'> |
||||||
|
<Tabs tabList={tabs} onChange={onChange}/> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
export default CategoryTabs |
@ -0,0 +1,3 @@ |
|||||||
|
export default definePageConfig({ |
||||||
|
navigationBarTitleText: '历史记录' |
||||||
|
}) |
@ -0,0 +1,50 @@ |
|||||||
|
.category { |
||||||
|
padding: 30px; |
||||||
|
border-bottom: 1px solid #F5F8F7; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
background: #fff; |
||||||
|
} |
||||||
|
|
||||||
|
.thumb { |
||||||
|
background: #ddd; |
||||||
|
width: 300rpx; |
||||||
|
height: 188rpx; |
||||||
|
border-radius: 8px; |
||||||
|
position: relative; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
Image { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
View { |
||||||
|
width: 100%; |
||||||
|
text-align: center; |
||||||
|
height: 48rpx; |
||||||
|
background: rgba(#000, .5); |
||||||
|
color: #fff; |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
bottom: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.text { |
||||||
|
height: 188px; |
||||||
|
flex: 1; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
margin-left: 20px; |
||||||
|
justify-content: space-between; |
||||||
|
font-weight: bold; |
||||||
|
word-break: break-all; |
||||||
|
|
||||||
|
& > View:last-child { |
||||||
|
font-weight: 100; |
||||||
|
color: #909795; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,45 @@ |
|||||||
|
import {Image, View} from "@tarojs/components"; |
||||||
|
import CategoryTabs from "@/pages/business/history/components/CategoryTabs"; |
||||||
|
// import {useState} from "react";
|
||||||
|
import styles from './history.module.scss' |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import {userApi} from "@/api"; |
||||||
|
import {useState} from "react"; |
||||||
|
import {formatMinute} from "@/utils/time"; |
||||||
|
|
||||||
|
const History = () => { |
||||||
|
const [data, setData] = useState<userRecord[]>([]) |
||||||
|
|
||||||
|
async function getData(id: number) { |
||||||
|
const res = await userApi.record(id) |
||||||
|
setData(Object.values(res)) |
||||||
|
} |
||||||
|
|
||||||
|
function jump(course_id: number, name: string) { |
||||||
|
Taro.preload({course_id, name}) |
||||||
|
Taro.navigateTo({url: `/pages/business/curHistory/curHistory`}) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<View> |
||||||
|
<CategoryTabs changeTabs={getData}/> |
||||||
|
|
||||||
|
<View className='mt-3'> |
||||||
|
{data.map(d => <View className={styles.category} onClick={() => jump(d.course_id, d.course.title)}> |
||||||
|
<View className={styles.thumb}> |
||||||
|
<Image src={d.course.thumb} /> |
||||||
|
<View>共{d.total_hour_count}节/已学{d.finished_count}节</View> |
||||||
|
</View> |
||||||
|
<View className={styles.text}> |
||||||
|
<View>{d.course.title}</View> |
||||||
|
<View>{formatMinute(d.duration)}</View> |
||||||
|
</View> |
||||||
|
</View>)} |
||||||
|
|
||||||
|
<View className='text-center text-muted mt-3'>- 暂无更多数据 -</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default History |
@ -0,0 +1,4 @@ |
|||||||
|
.content{ |
||||||
|
padding-bottom: env(safe-area-inset-bottom); |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
@ -1,41 +0,0 @@ |
|||||||
import {View} from "@tarojs/components"; |
|
||||||
import {FC, useEffect, useState} from "react"; |
|
||||||
import {CurLearningRecord, ManageApi} from "@/api/manage"; |
|
||||||
import PopPut from "@/components/popPut/popPut"; |
|
||||||
|
|
||||||
interface Props { |
|
||||||
id: number |
|
||||||
} |
|
||||||
|
|
||||||
const StudentRecord: FC<Props> = ({id}) => { |
|
||||||
const [data, setData] = useState<CurLearningRecord | null>(null) |
|
||||||
|
|
||||||
async function getDate() { |
|
||||||
try { |
|
||||||
const res = await ManageApi.userRecord(id) |
|
||||||
setData(res) |
|
||||||
} catch (e) { |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function record(id: number): string { |
|
||||||
return `${data?.user_course_records?.[id]?.finished_count || 0}/${data?.course.class_hour || 0}` |
|
||||||
} |
|
||||||
|
|
||||||
useEffect(() => { |
|
||||||
getDate() |
|
||||||
}, [id]) |
|
||||||
|
|
||||||
return ( |
|
||||||
<View> |
|
||||||
{data?.data?.map(d => <PopPut |
|
||||||
leftImage={d.avatar} |
|
||||||
title={d.name} |
|
||||||
content={record(d.id)} |
|
||||||
chevron |
|
||||||
/>)} |
|
||||||
</View> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default StudentRecord |
|
@ -1,12 +1,19 @@ |
|||||||
.operation { |
.operation { |
||||||
display: flex; |
|
||||||
width: 100%; |
width: 100%; |
||||||
justify-content: space-around; |
|
||||||
background: #F5F8F7; |
background: #F5F8F7; |
||||||
position: fixed; |
position: fixed; |
||||||
bottom: 0; |
bottom: 0; |
||||||
padding-bottom: env(safe-area-inset-bottom); |
padding: 30px 0; |
||||||
padding-top: 30px; |
|
||||||
color: #45D4A8; |
color: #45D4A8; |
||||||
left: 0; |
left: 0; |
||||||
|
|
||||||
|
.safeAreaInsetBottom { |
||||||
|
justify-content: space-around; |
||||||
|
padding-bottom: env(safe-area-inset-bottom); |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.depForm { |
||||||
|
padding: 20px 20px env(safe-area-inset-bottom); |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue