新增个人折线图

v2
king 1 year ago
parent 54e581f2ae
commit ce42bfd06f
  1. 2
      src/api/user.ts
  2. 71
      src/components/learningRecord/learningRecord.tsx
  3. 20
      src/components/lineChart/lineChart.tsx
  4. 58
      src/pages/manage/userInfo/userInfo.tsx
  5. 4
      src/pages/my/components/header/service.tsx
  6. 4
      src/pages/my/components/header/time.tsx
  7. 30
      src/pages/my/my.module.scss
  8. 16
      src/pages/my/my.tsx
  9. 36
      src/utils/time.tsx

@ -79,7 +79,7 @@ export const userApi = {
return request<User>(`/api/v1/statistics/${user_id}`, "GET")
},
/**获取指定学员指定时间学习记录 */
statistics(user_id: string, data: StatisticsParam) {
statistics(user_id: string | number, data: StatisticsParam) {
return request<{
data: Record<number, number>
}>(`/api/v1/statistics/statistics/${user_id}?start_time=${data.start_time}&end_time=${data.end_time}`, "GET")

@ -0,0 +1,71 @@
import {Text, View} from "@tarojs/components";
import styles from "@/pages/manage/userInfo/userInfo.module.scss";
import Tabs, {OnChangOpt, TabList} from "@/components/tabs/tabs";
import {everyDay, formatTime, getMonday, getSunday, monthEnd, monthFirst} from "@/utils/time";
import LineChart from "@/components/lineChart/lineChart";
import {FC, useEffect, useState} from "react";
import {StatisticsParam, userApi} from "@/api";
const tabList: TabList<any>[] = [
{
title: '日',
value: {
start_time: new Date().setHours(0, 0, 0, 0),
end_time: new Date().setHours(24, 0, 0, 0)
}
},
{
title: '周', value: {
start_time: getMonday(),
end_time: getSunday()
}
},
{
title: '月', value: {
start_time: monthFirst(),
end_time: monthEnd()
}
},
]
interface Props {
userId: string | number
}
/**
* 线
*/
const LearningRecord: FC<Props> = ({userId}) => {
const [lineData, setLineData] = useState<any[]>([])
async function getStatistics(data: StatisticsParam) {
try {
const res = await userApi.statistics(userId, data)
const everyDayValue = everyDay(data.start_time, Number(data.end_time), res.data)
setLineData(everyDayValue)
} catch (e) {
setLineData([])
}
}
function tabChange({tab}: OnChangOpt<StatisticsParam>) {
getStatistics(tab?.value! as StatisticsParam)
}
useEffect(() => {
userId && getStatistics(tabList[0].value)
}, [userId])
return (<View className={`${styles.box}`} style={{display: 'block'}}>
<Tabs tabList={tabList} onChange={tabChange}/>
<View className='font-weight font-36 mt-5 mb-3'>
<Text style={{margin: '0 10px', color: '#00D6AC'}}>
{formatTime(lineData.reduce((pre, cur) => pre + cur.value, 0) || 0)}
</Text>
</View>
<LineChart data={lineData}/>
</View>)
}
export default LearningRecord

@ -1,7 +1,7 @@
import {ScrollView, View} from "@tarojs/components";
import {ScrollView, Text, View} from "@tarojs/components";
import {FC, useEffect, useState} from "react";
import style from './lineChart.module.scss'
import {formatMinute} from "@/utils/time";
import {formatDateTime, formatTime} from "@/utils/time";
export interface lineData {
time: string
@ -24,21 +24,25 @@ const LineChart: FC<Props> = ({data}) => {
return cur
}
return pre
}, {time: '', value: 0}))
}, {time: formatDateTime(new Date(), 'MM/dd'), value: 0}))
}, [data])
return (
<>
<ScrollView scrollX={!!maxHeight.value}>
<View style={{marginBottom: '30px'}}>{maxHeight.time}{formatMinute(maxHeight.value)}</View>
<View style={{marginBottom: '15px'}}>
<Text>{formatDateTime(new Date(maxHeight.time), 'MM月dd日')}</Text>
{maxHeight.value > 0 ? `日最努力` : `期间没有学习记录`}{formatTime(maxHeight.value)}
</View>
<ScrollView scrollX={!!maxHeight.value} enhanced showScrollbar={false}>
<View className={style.lineChart}>
{!maxHeight.value && <View className={style.empty}></View>}
{
!!maxHeight.value && lineChartList.map(d => <View key={d.time}>
<View className={style.columnBox} style={{width: "100px"}}>
<View className={style.line} style={{height: height - 10 - (d.value / maxHeight.value * height) + "px"}}></View>
{d.value > 0 && <View>{formatMinute(d.value)}</View>}
<View className={style.column} style={{height: d.value / maxHeight.value * height + "px"}}> </View>
<View className={style.line}
style={{height: height - 10 - (d.value / maxHeight.value * height) + "px"}}></View>
{d.value > 0 && <View style={{whiteSpace: "nowrap"}}>{formatTime(d.value, 0)}</View>}
<View className={style.column} style={{height: d.value / maxHeight.value * height + "px"}}/>
<View>{d.time}</View>
</View>
</View>)

@ -1,42 +1,17 @@
import {Text, View} from "@tarojs/components";
import {View} from "@tarojs/components";
import {FC, useEffect, useState} from "react";
import styles from './userInfo.module.scss'
import Taro from "@tarojs/taro";
import Info from "@/pages/manage/userInfo/components/info";
import Tabs, {OnChangOpt, TabList} from "@/components/tabs/tabs";
import MyButton from "@/components/button/MyButton";
import {ManageApi, StatisticsParam, userApi} from "@/api";
import {ManageApi, userApi} from "@/api";
import {Profile} from "@/store";
import {everyDay, formatMinute, getMonday, getSunday, monthEnd, monthFirst} from "@/utils/time";
import LineChart from "@/components/lineChart/lineChart";
import LearningRecord from "@/components/learningRecord/learningRecord";
const tabList: TabList<any>[] = [
{
title: '日',
value: {
start_time: new Date().setHours(0, 0, 0, 0),
end_time: new Date().setHours(24, 0, 0, 0)
}
},
{
title: '周', value: {
start_time: getMonday(),
end_time: getSunday()
}
},
{
title: '月', value: {
start_time: monthFirst(),
end_time: monthEnd()
}
},
]
const UserInfo: FC = () => {
const {userId} = Taro.getCurrentInstance().router?.params as { userId: string }
const [data, setData] = useState<User | null>(null)
const [lineData, setLineData] = useState<any[]>([])
const router = Taro.useRouter()
const {user} = Profile.useContainer()
@ -81,22 +56,9 @@ const UserInfo: FC = () => {
})
}
async function getStatistics(data: StatisticsParam) {
try {
const res = await userApi.statistics(userId, data)
const everyDayValue = everyDay(data.start_time, Number(data.end_time), res.data)
setLineData(everyDayValue)
} catch (e) {
}
}
function tabChange({tab}: OnChangOpt<StatisticsParam>) {
getStatistics(tab?.value! as StatisticsParam)
}
useEffect(() => {
getStatistics(tabList[0].value)
userApi.info(userId).then(res => {
setData(res)
})
@ -114,17 +76,7 @@ const UserInfo: FC = () => {
<View className={styles.page}>
<Info data={data}/>
<View className={`${styles.box} mt-3`} style={{display: 'block'}}>
<Tabs tabList={tabList} onChange={tabChange}/>
<View className='font-weight font-36 mt-5 mb-3'>
<Text style={{margin: '0 10px', color: '#00D6AC'}}>
{formatMinute(lineData.reduce((pre, cur) => pre + cur.value, 0) || 0)}
</Text>
</View>
<LineChart data={lineData}/>
</View>
<LearningRecord userId={userId}/>
<View className='mt-5'>

@ -57,9 +57,9 @@ const Service = () => {
}
return (
<View className={'mt-3 ' + styles.tool}>
<View className={styles.tool}>
<View className='font-weight font-32'></View>
<View className={'mt-4 ' + styles.service}>
<View className={styles.service}>
{
list.map(d => {
return (

@ -57,14 +57,14 @@ const Time: FC = () => {
return (
<View className='flex mt-3 justify-between flex-wrap' style={{padding: '0 10px'}}>
<View className='flex mt-3 mb-1 justify-between flex-wrap'>
{
list.map(d => {
return (
<View className={styles.timeBox} key={d.title} onClick={() => jump(d.type)}>
<View className={styles.timeBoxFlex}>
<View>
<View className='mb-2'>{d.title}</View>
<View className='mb-2 font-28 font-weight'>{d.title}</View>
{token && <View className='text-muted font-26'>{d.time}</View>}
</View>
<Image src={d.src} mode='aspectFit' className={styles.timeImag}/>

@ -1,13 +1,17 @@
page {
background: #F2F8F6 !important;
width: 750rpx;
overflow: hidden;
overflow-x: hidden;
}
.content {
background: linear-gradient(180deg, #45D4A8 0%, rgba(69, 212, 168, 0) 100%) no-repeat;
background-size: 100% 458rpx;
position: relative;
padding: 0 10rpx;
width: 750rpx;
box-sizing: border-box;
overflow: hidden;
&:after {
content: '';
@ -37,7 +41,7 @@ page {
}
.header {
padding: 130px 20px 0;
padding: 130px 10rpx 0;
font-size: 10rpx;
.avatar {
@ -50,9 +54,9 @@ page {
.timeBox {
width: 50%;
line-height: 1.7;
margin-bottom: 20px;
padding: 0 10rpx;
height: 124rpx;
margin-bottom: 15rpx;
padding: 12rpx 10rpx;
box-sizing: border-box;
}
@ -71,10 +75,10 @@ page {
}
.service {
margin-top: 44rpx;
display: grid;
margin-top: 48rpx;
grid-template-columns:1fr 1fr 1fr 1fr;
grid-auto-rows: 100px 100px 100px 100px;
grid-auto-rows: 80px 80px 80px 80px;
grid-gap: 60px;
font-size: 28px;
text-align: center;
@ -87,9 +91,9 @@ page {
.tool {
background: #fff;
border-radius: 20px;
padding: 30rpx 20px;
margin: 20rpx;
border-radius: 20rpx;
padding: 30rpx 20px 46rpx;
margin-top: 30rpx;
}
.box {
@ -99,9 +103,11 @@ page {
padding: 16rpx 0;
box-sizing: border-box;
border-bottom: 2rpx solid #F5F8F7;
&.noBorder {
border: none;
}
.image {
width: 68rpx;
height: 68rpx;
@ -109,6 +115,7 @@ page {
border-radius: 8rpx;
overflow: hidden;
}
.innerBox {
height: 68rpx;
align-items: center;
@ -117,6 +124,7 @@ page {
flex: 1;
display: flex;
justify-content: space-between;
.title {
font-size: 32rpx;
font-weight: 500;
@ -128,10 +136,12 @@ page {
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.icon {
margin-left: 24rpx;
width: 24rpx;
height: 24rpx;
&.hide {
background: none;
}

@ -9,10 +9,11 @@ import {Profile} from "@/store";
import Img from "@/components/image/image";
import GreenNike from "@/static/img/greenNike.png"
import {userApi} from "@/api";
import LearningRecord from "@/components/learningRecord/learningRecord";
const My: FC = () => {
const globalData = Taro.getApp().globalData
const {token, company, setCompany} = Profile.useContainer()
const {token, company, setCompany, user} = Profile.useContainer()
const [companyShow, setCompanyShow] = useState(false)
const [companyList, setCompanyList] = useState<Company[]>([])
Taro.useDidShow(() => {
@ -26,7 +27,12 @@ const My: FC = () => {
<Header companyList={companyList} showCompany={() => companyList.length >= 2 && setCompanyShow(true)}/>
<Time/>
{token && <Service/>}
{
token && user && <View className='px-1'>
<LearningRecord userId={user.id}/>
<Service/>
</View>
}
<PageContainer
@ -37,11 +43,7 @@ const My: FC = () => {
onClickOverlay={() => setCompanyShow(false)}>
<View className="px-3 py-5">
<View className="font-32 pb-3"
style={{
display: 'flex',
justifyContent: 'center',
borderBottom: '2rpx solid #f5f8f7'
}}></View>
style={{display: 'flex', justifyContent: 'center', borderBottom: '2rpx solid #f5f8f7'}}></View>
{
companyList.length >= 1 &&
companyList.map((d, idx) =>

@ -1,11 +1,12 @@
/*
import {lineData} from "@/components/lineChart/lineChart";
import {Text} from "@tarojs/components";
/**
*
* s
* 20:20:20
* 10:10
* */
import {lineData} from "@/components/lineChart/lineChart";
*/
export function formatMinute(s: number | string): string {
const time = Number(s)
if (isNaN(time)) {
@ -19,6 +20,31 @@ export function formatMinute(s: number | string): string {
return `${hours > 0 ? `${hours}:` : ''}${min < 10 ? '0' + min : min}:${formatSecond < 10 ? '0' + formatSecond : formatSecond}`
}
/**
* 60
* 60s - 1h
* 1h
*/
export function formatTime(time: number, padding = 10): JSX.Element {
if (time < 60) {
return (<>
{time}
<Text style={{color: '#000', paddingLeft: `${padding}px`}}></Text>
</>)
} else if (time >= 60 && time < 3600) {
return (<>
{(time / 60).toFixed(2)}
<Text style={{color: '#000', paddingLeft: `${padding}px`}}></Text>
</>)
} else if (time >= 3600) {
return (<>
{(time / 3600).toFixed(2)}
<Text style={{color: '#000', paddingLeft: `${padding}px`}}></Text>
</>)
}
return <></>
}
export function formatDateTime(date, format) {
const o = {
'M+': date.getMonth() + 1, // 月份
@ -112,7 +138,7 @@ export function everyDay(start_time: number, end_time: number, data: Record<numb
return new Array(days === 1 ? 1 : days + 1).fill(0).map((_, index) => {
const day = start_time + index * time
return {
time: formatDateTime(new Date(day), 'MM-dd'),
time: formatDateTime(new Date(day), 'MM/dd'),
value: data?.[String(day)] || 0
}
})
Loading…
Cancel
Save