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 { |
||||
display: flex; |
||||
width: 100%; |
||||
justify-content: space-around; |
||||
background: #F5F8F7; |
||||
position: fixed; |
||||
bottom: 0; |
||||
padding-bottom: env(safe-area-inset-bottom); |
||||
padding-top: 30px; |
||||
padding: 30px 0; |
||||
color: #45D4A8; |
||||
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