Compare commits
137 Commits
Author | SHA1 | Date |
---|---|---|
一杯沧海 | 88f1eb3720 | 10 months ago |
一杯沧海 | 07fed1a1e5 | 1 year ago |
一杯沧海 | e3ced26435 | 1 year ago |
一杯沧海 | 624d7cb183 | 1 year ago |
一杯沧海 | c421e30b71 | 1 year ago |
一杯沧海 | 163af32973 | 1 year ago |
一杯沧海 | 1df2db15b0 | 1 year ago |
一杯沧海 | 9178e7ba47 | 1 year ago |
一杯沧海 | 7666062ea0 | 1 year ago |
一杯沧海 | 3844bbc0ca | 1 year ago |
一杯沧海 | b33c7170ea | 1 year ago |
一杯沧海 | 2a29617017 | 1 year ago |
king | 84fbd98fa9 | 1 year ago |
king | c2b9a4812f | 1 year ago |
king | acd6b352b5 | 1 year ago |
king | a43a0fabc2 | 1 year ago |
king | 9d9506c66e | 1 year ago |
king | ee5741a752 | 1 year ago |
king | 5e6375cd4f | 1 year ago |
king | 9f17e4c886 | 1 year ago |
king | aeb6e1bbc5 | 1 year ago |
king | 3a777d0b57 | 1 year ago |
king | cb88f49e85 | 1 year ago |
king | aa4e006b00 | 1 year ago |
king | 358c3ee95c | 1 year ago |
king | 50bc02a178 | 1 year ago |
king | d52902def3 | 1 year ago |
king | bc0682351e | 1 year ago |
king | 380b7be4fa | 1 year ago |
king | fd06be84d5 | 1 year ago |
king | 22e012e711 | 1 year ago |
king | a004bceaf9 | 1 year ago |
king | a538461a9b | 1 year ago |
king | c1e6f8a5bc | 1 year ago |
56de47bf2c | 1 year ago | |
king | 93064963a7 | 1 year ago |
king | cecc425f17 | 1 year ago |
king | a318591244 | 1 year ago |
king | 278a408137 | 1 year ago |
一杯沧海 | 887b7a4bb6 | 1 year ago |
king | 4cc69d9c2f | 1 year ago |
一杯沧海 | e4acf12d87 | 1 year ago |
king | 86bc1a4cc0 | 1 year ago |
一杯沧海 | 5e00de014c | 1 year ago |
king | ae52d73588 | 1 year ago |
king | 353e1d51e0 | 1 year ago |
king | d47392954a | 1 year ago |
king | e97f59d7f8 | 1 year ago |
一杯沧海 | 29006f34f3 | 1 year ago |
一杯沧海 | c332fdca11 | 1 year ago |
king | c37e360cb6 | 1 year ago |
king | 5137d3297f | 1 year ago |
king | 805b47435f | 1 year ago |
king | 3e4a30cf1f | 1 year ago |
king | 68d99f86b1 | 1 year ago |
king | adc5d17a5d | 1 year ago |
king | fa81566f32 | 1 year ago |
king | 389827ac79 | 1 year ago |
king | 85da032f41 | 1 year ago |
4d2b83b950 | 1 year ago | |
king | ae57654a46 | 1 year ago |
king | 8f104e2a54 | 1 year ago |
king | a70dcc2de1 | 1 year ago |
king | 13c6a2d7b9 | 1 year ago |
king | 9f5e6af772 | 1 year ago |
king | 9fb280b866 | 1 year ago |
king | 485bc0815b | 1 year ago |
king | 70e61e187e | 1 year ago |
a43fc7498c | 1 year ago | |
king | dfe30478ea | 1 year ago |
king | 451828b70c | 1 year ago |
king | 9d8b36f300 | 1 year ago |
king | ce42bfd06f | 1 year ago |
king | 54e581f2ae | 1 year ago |
19e01cf623 | 1 year ago | |
king | 017d05d456 | 1 year ago |
king | c99493e9de | 1 year ago |
king | e437e131cd | 1 year ago |
king | c0038a7e93 | 1 year ago |
一杯沧海 | 5af5eb80da | 1 year ago |
king | 6b052df04c | 1 year ago |
king | 178c227b1a | 1 year ago |
一杯沧海 | e629874abe | 1 year ago |
一杯沧海 | 3c8e8f626c | 1 year ago |
一杯沧海 | eea8f99fe7 | 1 year ago |
king | 4605f01aeb | 1 year ago |
king | 38afb77146 | 1 year ago |
一杯沧海 | 806614f5d6 | 1 year ago |
king | eb218db694 | 1 year ago |
king | f8703c0754 | 1 year ago |
一杯沧海 | 8cbad8268b | 1 year ago |
一杯沧海 | 02c1a92a37 | 1 year ago |
king | be402c557b | 1 year ago |
king | cfd404dda1 | 1 year ago |
一杯沧海 | 3e5190d0bd | 1 year ago |
一杯沧海 | 1cd8fba6a3 | 1 year ago |
king | fe67088214 | 1 year ago |
king | 7075cd45ac | 1 year ago |
一杯沧海 | 3fe6226304 | 1 year ago |
king | f1bef606a9 | 1 year ago |
king | a51502d559 | 1 year ago |
king | 2fdf0d3085 | 1 year ago |
king | 8ae17e1bfc | 1 year ago |
king | d742560fb2 | 1 year ago |
一杯沧海 | aa94eb9a27 | 1 year ago |
一杯沧海 | 1775c39136 | 1 year ago |
king | bcbf3b8e41 | 1 year ago |
king | 20564f42fb | 1 year ago |
一杯沧海 | 1eb468a699 | 1 year ago |
king | 8e465b9d03 | 1 year ago |
king | 76b08de3c1 | 1 year ago |
king | b3fd259076 | 1 year ago |
king | 8cb14727c0 | 1 year ago |
一杯沧海 | 26fbcc475a | 1 year ago |
3794aca0a7 | 1 year ago | |
king | 0e46e2d76b | 1 year ago |
king | 7e03c67400 | 1 year ago |
king | 4fd03d0b8d | 1 year ago |
king | cccb057722 | 1 year ago |
king | c2ee704cf9 | 1 year ago |
一杯沧海 | 2efdeb0bd2 | 1 year ago |
一杯沧海 | 5380bc35a0 | 1 year ago |
king | 7ee05c66d0 | 1 year ago |
一杯沧海 | ea75fdc4c9 | 1 year ago |
king | c961892d9b | 1 year ago |
一杯沧海 | 7844106068 | 1 year ago |
king | 2029037d7a | 1 year ago |
king | 7b0c91dfcd | 1 year ago |
一杯沧海 | c2cea8feef | 1 year ago |
king | 50460bd891 | 1 year ago |
king | a6fed2ec3a | 1 year ago |
king | ad75871248 | 1 year ago |
king | ed2c5aedb0 | 1 year ago |
一杯沧海 | 39aa8c808c | 1 year ago |
king | 736f9387b6 | 1 year ago |
一杯沧海 | 14a6cfac38 | 1 year ago |
一杯沧海 | 6caf55b914 | 1 year ago |
@ -1,5 +1,6 @@ |
|||||||
#TARO_APP_API=https://yjx.dev.yaojiankang.top |
#TARO_APP_API=https://yjx.dev.yaojiankang.top |
||||||
TARO_APP_API=https://mooc.yaojiankang.top |
#TARO_APP_API=https://mooc.yaojiankang.top |
||||||
|
TARO_APP_API=https://xingui.yaojiankang.top |
||||||
#TARO_APP_API=https://shopfix.yaojiankang.top |
#TARO_APP_API=https://shopfix.yaojiankang.top |
||||||
#TARO_APP_API=https://playedu.yaojiankang.top |
#TARO_APP_API=https://playedu.yaojiankang.top |
||||||
TARO_APP_LGOIN=true |
TARO_APP_LGOIN=true |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,42 +1,58 @@ |
|||||||
import {request} from "@/api/request"; |
import {request} from "@/api/request"; |
||||||
|
import {Illness} from "@/api/illness"; |
||||||
|
|
||||||
export type BrandRecord = { |
export type BrandRecord = { |
||||||
logo: string; |
logo: string; |
||||||
name: string; |
name: string; |
||||||
id: number |
id: number |
||||||
introductory_video: string |
introductory_video: string |
||||||
brand_album: string[] |
brand_album: string |
||||||
graphic_introduction: string |
graphic_introduction: string |
||||||
disabled: number |
disabled: number |
||||||
introductory_video_resource:any |
introductory_video_resource: any |
||||||
|
article_count: number |
||||||
|
created_at: string |
||||||
|
page_view: number |
||||||
|
collect: boolean |
||||||
|
last_publish_time: string |
||||||
} |
} |
||||||
export type ArticleRecord = { |
export type ArticleRecord = { |
||||||
|
id: number; |
||||||
title: string |
title: string |
||||||
page_view: number |
page_view: number |
||||||
created_at: string |
created_at: string |
||||||
content: string |
content: string |
||||||
|
brands: BrandRecord[] |
||||||
|
illness: Illness[] |
||||||
|
collect: boolean |
||||||
|
cover: string |
||||||
|
owner_type: 1 | 2 // 疾病
|
||||||
} |
} |
||||||
|
|
||||||
export const brandApi = { |
export const brandApi = { |
||||||
/** 品牌列表 */ |
/** 品牌列表 */ |
||||||
list(page: number , page_size: number) { |
list(page: number, page_size: number) { |
||||||
return request<{ |
return request<{ |
||||||
list: BrandRecord[], |
list: BrandRecord[], |
||||||
total: number |
total: number |
||||||
}>(`/home/v1/brand/list?page=${page}&page_size=${page_size}` , "GET") |
}>(`/home/v1/brand/list?page=${page}&page_size=${page_size}`, "GET") |
||||||
}, |
}, |
||||||
/** 品牌详情 */ |
/** 品牌详情 */ |
||||||
info(id: number) { |
info(id: number) { |
||||||
return request<BrandRecord>(`/home/v1/brand/${id}`, "GET") |
return request<BrandRecord>(`/home/v1/brand/${id}`, "GET") |
||||||
}, |
}, |
||||||
/** 文章列表 */ |
/** 文章列表 */ |
||||||
articleList(owner_id: number,page:number) { |
articleList(owner_id: number, page: number) { |
||||||
return request<{ |
return request<{ |
||||||
list: ArticleRecord[], |
list: Articles[], |
||||||
total: number |
total: number |
||||||
}>(`/home/v1/article/list?owner_id=${owner_id}&page=${page}&page_size=10` , "GET") |
}>(`/home/v1/article/list?owner_id=${owner_id}&page=${page}&page_size=10`, "GET") |
||||||
}, |
}, |
||||||
articleInfo(id: number ) { |
articleInfo(id: number) { |
||||||
return request<ArticleRecord>(`/home/v1/article/${id}` , "GET") |
return request<ArticleRecord>(`/home/v1/article/${id}`, "GET") |
||||||
}, |
}, |
||||||
|
/** 品牌 & 健康详情 */ |
||||||
|
videoInfo(id: number | string) { |
||||||
|
return request<VideList>(`/home/v1/health/${id}`, "GET") |
||||||
|
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,11 @@ |
|||||||
|
import {request} from "@/api/request"; |
||||||
|
|
||||||
|
export const SearchApi = { |
||||||
|
/** 品牌列表 */ |
||||||
|
list(page: number , page_size: number, name: string) { |
||||||
|
return request<{ |
||||||
|
data: any[], |
||||||
|
total: number |
||||||
|
}>(`/home/v1/search/home?page=${page}&page_size=${page_size}&keywords=${name}&sort_type=1&sort=0` , "GET") |
||||||
|
}, |
||||||
|
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,88 @@ |
|||||||
|
import { CSSProperties, FC } from "react" |
||||||
|
import { Text, ITouchEvent } from "@tarojs/components" |
||||||
|
import './icon.css' |
||||||
|
|
||||||
|
export type IconName = |
||||||
|
| 'arrow-clockwise' |
||||||
|
| 'arrow-counterclockwise' |
||||||
|
| 'backspace' |
||||||
|
| 'bar-chart' |
||||||
|
| 'bar-chart-line' |
||||||
|
| 'caret-down' |
||||||
|
| 'caret-up' |
||||||
|
| 'caret-left' |
||||||
|
| 'caret-right' |
||||||
|
| 'check' |
||||||
|
| 'check-all' |
||||||
|
| 'chevron-double-down' |
||||||
|
| 'chevron-double-up' |
||||||
|
| 'chevron-double-left' |
||||||
|
| 'chevron-double-right' |
||||||
|
| 'chevron-down' |
||||||
|
| 'chevron-up' |
||||||
|
| 'chevron-left' |
||||||
|
| 'chevron-right' |
||||||
|
| 'circle' |
||||||
|
| 'exclamation' |
||||||
|
| 'gear' |
||||||
|
| 'gender-female' |
||||||
|
| 'gender-male' |
||||||
|
| 'heart' |
||||||
|
| 'info' |
||||||
|
| 'list' |
||||||
|
| 'lock' |
||||||
|
| 'unlock' |
||||||
|
| 'play-btn' |
||||||
|
| 'play' |
||||||
|
| 'question' |
||||||
|
| 'shield' |
||||||
|
| 'square' |
||||||
|
| 'star' |
||||||
|
| 'three-dots-vertical' |
||||||
|
| 'three-dots' |
||||||
|
| 'trash' |
||||||
|
| 'x' |
||||||
|
|
||||||
|
export type IconShape = |
||||||
|
| 'circle' |
||||||
|
| 'square' |
||||||
|
| 'diamond' |
||||||
|
| 'octagon' |
||||||
|
| 'triangle' |
||||||
|
|
||||||
|
export interface IconProps { |
||||||
|
name: IconName |
||||||
|
shape?: IconShape |
||||||
|
color?: string |
||||||
|
size?: string | number |
||||||
|
fill?: boolean |
||||||
|
className?: string |
||||||
|
style?: CSSProperties |
||||||
|
onClick?: (event: ITouchEvent) => void |
||||||
|
} |
||||||
|
|
||||||
|
const XgIcon: FC<IconProps> = (props) => { |
||||||
|
const name = [ |
||||||
|
props.name, |
||||||
|
props.shape, |
||||||
|
props.fill ? 'fill' : undefined |
||||||
|
].filter(Boolean).join('-') |
||||||
|
|
||||||
|
const color = props.color ?? 'currentColor' |
||||||
|
const size = typeof props.size === 'string' ? props.size : `${props.size ?? 16}px` |
||||||
|
const fontStyle: CSSProperties = { |
||||||
|
...(props.style ?? {}), |
||||||
|
fontSize: size, |
||||||
|
color, |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<Text |
||||||
|
className={`xg-icon xg-icon-${name} ${props.className}`} |
||||||
|
style={fontStyle} |
||||||
|
onClick={props.onClick} |
||||||
|
/> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default XgIcon |
@ -0,0 +1,40 @@ |
|||||||
|
.artcles { |
||||||
|
padding: 30rpx 0; |
||||||
|
border-bottom: 1px solid #F5F8F7; |
||||||
|
} |
||||||
|
|
||||||
|
.outside { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
|
||||||
|
|
||||||
|
.title { |
||||||
|
font-size: 28rpx; |
||||||
|
font-family: PingFang SC-Bold, PingFang SC; |
||||||
|
font-weight: bold; |
||||||
|
color: #323635; |
||||||
|
} |
||||||
|
|
||||||
|
.intro { |
||||||
|
font-size: 24rpx; |
||||||
|
font-family: PingFang SC-Medium, PingFang SC; |
||||||
|
font-weight: 500; |
||||||
|
color: #909795; |
||||||
|
margin-top: 10rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.img { |
||||||
|
overflow: hidden; |
||||||
|
border-radius: 10rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.pageView { |
||||||
|
font-size: 22rpx; |
||||||
|
font-family: PingFang SC-Medium, PingFang SC; |
||||||
|
font-weight: 500; |
||||||
|
color: #909795; |
||||||
|
margin-top: 20rpx; |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,68 @@ |
|||||||
|
import {FC, useEffect, useState} from "react"; |
||||||
|
import {Text, View} from "@tarojs/components"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import styles from './articlesBox.module.scss' |
||||||
|
import Img from "@/components/image/image"; |
||||||
|
import {beforeTime} from "@/utils/time"; |
||||||
|
import articlesEvent from "@/hooks/articlesEvent"; |
||||||
|
|
||||||
|
interface Props { |
||||||
|
data: Articles |
||||||
|
} |
||||||
|
|
||||||
|
const ArticlesBox: FC<Props> = (props) => { |
||||||
|
const [data, setData] = useState(props.data) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setData(props.data) |
||||||
|
}, [props.data]) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
articlesEvent.recordsOn(data.id, ({view}) => { |
||||||
|
setData({ |
||||||
|
...data, |
||||||
|
page_view: view |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, []) |
||||||
|
|
||||||
|
Taro.useUnload(() => { |
||||||
|
articlesEvent.off(data.id) |
||||||
|
}) |
||||||
|
|
||||||
|
Taro.useDidShow(()=>{ |
||||||
|
articlesEvent.recordsOn(data.id, ({view}) => { |
||||||
|
setData({ |
||||||
|
...data, |
||||||
|
page_view: view |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
const toArticlePage = () => { |
||||||
|
Taro.navigateTo({ |
||||||
|
url: `/pages/preview/brand/article/article?id=${data.id}` |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<View className={styles.artcles} onClick={toArticlePage}> |
||||||
|
<View className={styles.outside}> |
||||||
|
<View className='flex-1 mr-2'> |
||||||
|
<View className={`${styles.title} text-ellipsis-1`}>{data.title}</View> |
||||||
|
<View className={`${styles.intro} text-ellipsis-2`}>{data.intro}</View> |
||||||
|
<View className={styles.pageView}> |
||||||
|
<Text>{beforeTime(data.created_at)}</Text>· |
||||||
|
<Text>{data.page_view || 0}阅读</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
<Img src={data.cover || ''} |
||||||
|
errorType={data.owner_type === 1 ? 'brand' : 'health'} |
||||||
|
width={148} |
||||||
|
height={116} |
||||||
|
className={styles.img}/> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
export default ArticlesBox |
@ -0,0 +1,66 @@ |
|||||||
|
.collect { |
||||||
|
width: 130rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
color: #909795; |
||||||
|
padding: 0 10rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.collectImage { |
||||||
|
position: relative; |
||||||
|
margin-right: 10rpx; |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
.zoom { |
||||||
|
|
||||||
|
position: absolute; |
||||||
|
content: ''; |
||||||
|
width: 32rpx; |
||||||
|
height: 32rpx; |
||||||
|
border-radius: 50%; |
||||||
|
border: 1px solid #FF9E5F; |
||||||
|
padding: 0 !important; |
||||||
|
margin: 0 !important; |
||||||
|
animation: Zooms 300ms ease forwards; |
||||||
|
opacity: 1; |
||||||
|
transform-origin: -100%, -100% 0; |
||||||
|
} |
||||||
|
|
||||||
|
.pulse { |
||||||
|
animation: Pulse 300ms; |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes Zooms { |
||||||
|
0% { |
||||||
|
transform: scale(1); |
||||||
|
} |
||||||
|
30% { |
||||||
|
transform: scale(1.5); |
||||||
|
left: -5%; |
||||||
|
top: -5%; |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
100% { |
||||||
|
transform: scale(1.5); |
||||||
|
left: -5%; |
||||||
|
top: -5%; |
||||||
|
opacity: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes Pulse { |
||||||
|
0% { |
||||||
|
transform: scale(.2); |
||||||
|
} |
||||||
|
60% { |
||||||
|
transform: scale(1.2); |
||||||
|
} |
||||||
|
80% { |
||||||
|
transform: scale(.8); |
||||||
|
} |
||||||
|
100% { |
||||||
|
transform: scale(1); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
import {CSSProperties, FC, useCallback, useEffect, useState} from "react"; |
||||||
|
// import star from '@/static/img/star.png'
|
||||||
|
// import starLine from '@/static/img/starLine.png'
|
||||||
|
import {View,Text} from "@tarojs/components"; |
||||||
|
import styles from './collect.module.scss' |
||||||
|
import {Profile} from "@/store" |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import {userApi} from "@/api"; |
||||||
|
import IconFont from "@/components/IconFont"; |
||||||
|
|
||||||
|
interface Props { |
||||||
|
onClick?: () => void |
||||||
|
select?: boolean |
||||||
|
stylesImage?: CSSProperties |
||||||
|
styles?: CSSProperties |
||||||
|
owner_id: number |
||||||
|
owner_type: CreateOwnerType |
||||||
|
textHidden?: boolean |
||||||
|
onUpdate?: (v: boolean) => void |
||||||
|
} |
||||||
|
|
||||||
|
const versions = new Map() |
||||||
|
|
||||||
|
const collect = async (scope: string, params: Create, setSelect: (v: boolean) => void, value: boolean) => { |
||||||
|
const localVersion = (versions.get(scope) || 0) + 1 |
||||||
|
versions.set(scope, localVersion) |
||||||
|
await userApi.create(params) |
||||||
|
if (localVersion === versions.get(scope)) { |
||||||
|
setSelect(value) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** 收藏 */ |
||||||
|
const Collect: FC<Props> = (props) => { |
||||||
|
const {token} = Profile.useContainer() |
||||||
|
const [loading, setLoading] = useState(false) |
||||||
|
const [select, setSelect] = useState(props.select) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setSelect(props.select) |
||||||
|
}, [props]) |
||||||
|
|
||||||
|
const change = useCallback(async () => { |
||||||
|
if (!token) { |
||||||
|
Taro.navigateTo({url: '/pages/login/login'}) |
||||||
|
return |
||||||
|
} |
||||||
|
props.onClick?.() |
||||||
|
setSelect(!select) |
||||||
|
setLoading(true) |
||||||
|
collect(`${props.owner_id}#${props.owner_type}`, { |
||||||
|
owner_id: props.owner_id, |
||||||
|
owner_type: props.owner_type, |
||||||
|
}, (v) => { |
||||||
|
setSelect(v) |
||||||
|
props.onUpdate?.(v) |
||||||
|
}, !select) |
||||||
|
setTimeout(() => { |
||||||
|
setLoading(false) |
||||||
|
}, 300) |
||||||
|
}, [loading, token, select]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<View className={styles.collect} onClick={change} style={props.styles}> |
||||||
|
<View className={styles.collectImage} style={props.stylesImage}> |
||||||
|
{/*<View className={`${loading && select && styles.zoom}`}/>*/} |
||||||
|
<View className={`${loading ? styles.pulse : ''}`}> |
||||||
|
<IconFont name='star' fill={!!(select && token)} color={(select && token) ? '#FF9E5F' : undefined} /> |
||||||
|
</View> |
||||||
|
{/*<Image src={(select && token) ? star : starLine} className={`${loading && styles.pulse}`}/>*/} |
||||||
|
</View> |
||||||
|
{/*{!props.textHidden && (select ? '已收藏' : '收藏')}*/} |
||||||
|
{ |
||||||
|
!props.textHidden && |
||||||
|
<Text style={{fontSize:'30rpx',lineHeight:'30rpx'}}>收藏</Text> |
||||||
|
} |
||||||
|
{/*<Text>{!props.textHidden && '收藏'}</Text>*/} |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default Collect |
@ -0,0 +1,16 @@ |
|||||||
|
.box { |
||||||
|
background: #fff; |
||||||
|
border-radius: 20rpx; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
box-sizing: border-box; |
||||||
|
line-height: 1.75; |
||||||
|
} |
||||||
|
|
||||||
|
.total { |
||||||
|
font-size: 40rpx; |
||||||
|
font-family: PingFang SC-Heavy, PingFang SC; |
||||||
|
font-weight: 800; |
||||||
|
color: #323635; |
||||||
|
margin-top: 48rpx; |
||||||
|
} |
@ -0,0 +1,99 @@ |
|||||||
|
import {Text, View} from "@tarojs/components"; |
||||||
|
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 {CSSProperties, FC, useEffect, useState} from "react"; |
||||||
|
import {StatisticsParam, userApi} from "@/api"; |
||||||
|
import styles from './learningRecord.module.scss' |
||||||
|
import Spin from "@/components/spinner"; |
||||||
|
import {Profile} from "@/store"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import debounce from "@/utils/debounce"; |
||||||
|
|
||||||
|
const tabList: TabList<any>[] = [ |
||||||
|
{ |
||||||
|
title: '月', value: { |
||||||
|
start_time: monthFirst(), |
||||||
|
end_time: monthEnd() |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '周', value: { |
||||||
|
start_time: getMonday(), |
||||||
|
end_time: getSunday() |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '日', |
||||||
|
value: { |
||||||
|
start_time: new Date().setHours(0, 0, 0, 0), |
||||||
|
end_time: new Date().setHours(24, 0, 0, 0) |
||||||
|
} |
||||||
|
}, |
||||||
|
] |
||||||
|
|
||||||
|
interface Props { |
||||||
|
userId?: string | number |
||||||
|
style?: CSSProperties |
||||||
|
className?: string |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 学习记录折线图 |
||||||
|
*/ |
||||||
|
const LearningRecord: FC<Props> = ({userId, style, className}) => { |
||||||
|
const [lineData, setLineData] = useState<any[]>([]) |
||||||
|
const [loading, setLoading] = useState(false) |
||||||
|
const {token} = Profile.useContainer() |
||||||
|
|
||||||
|
async function getStatistics(data: StatisticsParam) { |
||||||
|
try { |
||||||
|
if (!userId) return; |
||||||
|
setLineData([]) |
||||||
|
const res = await userApi.statistics(userId, data) |
||||||
|
const everyDayValue = everyDay(data.start_time, Number(data.end_time), res.data) |
||||||
|
setLineData(everyDayValue) |
||||||
|
} catch (e) { |
||||||
|
setLineData([]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
function tabChange({tab}: OnChangOpt<StatisticsParam>) { |
||||||
|
if (!token) { |
||||||
|
Taro.navigateTo({url: '/pages/login/login'}) |
||||||
|
return |
||||||
|
} |
||||||
|
setLoading(true) |
||||||
|
debounce(() => { |
||||||
|
try { |
||||||
|
getStatistics(tab?.value! as StatisticsParam).then() |
||||||
|
} catch (e) { |
||||||
|
} |
||||||
|
setLoading(false) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
userId && setTimeout(() => { |
||||||
|
getStatistics(tabList[0].value) |
||||||
|
}, 500) |
||||||
|
}, [userId]) |
||||||
|
|
||||||
|
return (<View className={[styles.box, className].filter(Boolean).join(' ')} style={{display: 'block', ...style}}> |
||||||
|
<Tabs tabList={tabList} onChange={tabChange} backMode/> |
||||||
|
<View style={{position: "relative"}}> |
||||||
|
{loading && <Spin enable={loading} block/>} |
||||||
|
<View className={styles.total}> |
||||||
|
总共学习 |
||||||
|
<Text style={{margin: '0 10px', color: '#00D6AC'}}> |
||||||
|
{formatTime(lineData.reduce((pre, cur) => pre + cur.value, 0) || 0)} |
||||||
|
</Text> |
||||||
|
</View> |
||||||
|
<LineChart data={lineData}/> |
||||||
|
</View> |
||||||
|
</View>) |
||||||
|
} |
||||||
|
|
||||||
|
export default LearningRecord |
@ -0,0 +1,38 @@ |
|||||||
|
.fixedBox { |
||||||
|
position: relative; |
||||||
|
width: 100vw; |
||||||
|
height: 100vw; |
||||||
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1), rgba(255, 255, 255, 1)); |
||||||
|
//border: 1px solid #f40; |
||||||
|
|
||||||
|
&-inner { |
||||||
|
position: absolute; |
||||||
|
width: 100vw; |
||||||
|
bottom: 24rpx; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
|
||||||
|
&-icon { |
||||||
|
image { |
||||||
|
width: 32rpx; |
||||||
|
height: 32rpx; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&-box { |
||||||
|
margin-top: 24rpx; |
||||||
|
width: 680rpx; |
||||||
|
left: 35rpx; |
||||||
|
height: 76rpx; |
||||||
|
background-color: #45D4A8; |
||||||
|
color: #fff; |
||||||
|
line-height: 76rpx; |
||||||
|
text-align: center; |
||||||
|
font-size: 32rpx; |
||||||
|
font-weight: 500; |
||||||
|
border-radius: 8rpx 8rpx 8rpx 8rpx; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
import styles from "./index.module.scss"; |
||||||
|
import { Text, View} from "@tarojs/components"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import {CSSProperties, FC} from "react"; |
||||||
|
import IconFont from "@/components/IconFont"; |
||||||
|
|
||||||
|
type Props = { |
||||||
|
className?: string |
||||||
|
style?: CSSProperties |
||||||
|
} |
||||||
|
|
||||||
|
const LoginView3: FC<Props> = ({className,style}) => { |
||||||
|
return ( |
||||||
|
|
||||||
|
<View className={`${styles.fixedBox} ${className}`} style={style}> |
||||||
|
<View className={styles['fixedBox-inner']}> |
||||||
|
<View className={styles['fixedBox-inner-icon']}> |
||||||
|
<IconFont color='#909795' name='chevron-double-down'/> |
||||||
|
</View> |
||||||
|
<View className={styles['fixedBox-inner-box']} |
||||||
|
onClick={() => Taro.navigateTo({url: '/pages/login/login'})}> |
||||||
|
<Text>登录查看更多内容1</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
export default LoginView3 |
@ -0,0 +1,47 @@ |
|||||||
|
.content { |
||||||
|
position: relative; |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
|
||||||
|
image { |
||||||
|
width: 320rpx; |
||||||
|
height: 208rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.title { |
||||||
|
font-size: 28rpx; |
||||||
|
font-weight: bold; |
||||||
|
color: #323635; |
||||||
|
} |
||||||
|
|
||||||
|
.label { |
||||||
|
font-size: 24rpx; |
||||||
|
font-weight: 500; |
||||||
|
color: #909795; |
||||||
|
line-height: 24rpx; |
||||||
|
margin: 20rpx 0 ; |
||||||
|
} |
||||||
|
|
||||||
|
.button { |
||||||
|
padding: 0 60rpx; |
||||||
|
height: 76rpx; |
||||||
|
background: #45D4A8; |
||||||
|
border-radius: 38rpx 38rpx 38rpx 38rpx; |
||||||
|
color: #fff; |
||||||
|
line-height: 76rpx; |
||||||
|
text-align: center; |
||||||
|
font-size: 32rpx; |
||||||
|
font-weight: 500; |
||||||
|
} |
||||||
|
|
||||||
|
.nextLabel { |
||||||
|
font-size: 24rpx; |
||||||
|
font-weight: 500; |
||||||
|
color: #909795; |
||||||
|
line-height: 24rpx; |
||||||
|
margin-top: 15rpx; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
import {CSSProperties, FC, useState} from "react"; |
||||||
|
import {View, Image} from "@tarojs/components"; |
||||||
|
import styles from './index.module.scss' |
||||||
|
import NoLogin from '@/static/img/noLogin.png' |
||||||
|
import {Profile} from "@/store"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import {userApi} from "@/api"; |
||||||
|
|
||||||
|
interface Props { |
||||||
|
tips?: string |
||||||
|
height?: number |
||||||
|
paddingTop?: number |
||||||
|
style?: CSSProperties |
||||||
|
offImage?: boolean |
||||||
|
onSuccess?: VoidFunction |
||||||
|
} |
||||||
|
|
||||||
|
export const LoginView: FC<Props> = (props) => { |
||||||
|
const [isLoading, setLoading] = useState(false) |
||||||
|
const {setUser, setToken, setCompany} = Profile.useContainer() |
||||||
|
const sizeStyle: CSSProperties = { |
||||||
|
height: `${props.height || 1000}rpx`, |
||||||
|
paddingTop: `${props.paddingTop || 0}rpx`, |
||||||
|
...props.style, |
||||||
|
} |
||||||
|
|
||||||
|
function login() { |
||||||
|
if (isLoading) return; |
||||||
|
Taro.showLoading({title: '微信授权中...'}) |
||||||
|
setLoading(true) |
||||||
|
Taro.login({ |
||||||
|
success: async (res) => { |
||||||
|
try { |
||||||
|
const {catch_key, user, token, company} = await userApi.login(res.code) |
||||||
|
Taro.hideLoading() |
||||||
|
if (token) { |
||||||
|
Taro.showToast({title: '授权成功', duration: 1500, icon: 'success', mask: true}) |
||||||
|
setTimeout(() => { |
||||||
|
setUser(user) |
||||||
|
setToken(token) |
||||||
|
setCompany(company) |
||||||
|
setLoading(false) |
||||||
|
if (props.onSuccess) { |
||||||
|
props.onSuccess() |
||||||
|
} else { |
||||||
|
Taro.switchTab({url: '/pages/home/home'}) |
||||||
|
} |
||||||
|
}, 1500) |
||||||
|
} else { |
||||||
|
Taro.setStorageSync('openid', catch_key) |
||||||
|
Taro.reLaunch({url: '/pages/check/check'}) |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
Taro.hideLoading() |
||||||
|
} |
||||||
|
setLoading(false) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<View className={styles.content} style={sizeStyle}> |
||||||
|
{ |
||||||
|
!props.offImage && <> |
||||||
|
<Image src={NoLogin}/> |
||||||
|
<View className={styles.title}>暂未登录</View> |
||||||
|
</> |
||||||
|
} |
||||||
|
<View className={styles.label}>点击按钮完成微信授权</View> |
||||||
|
<View onClick={login} className={styles.button}>立即登录</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
const LoginView2: FC<Props> = (props) => { |
||||||
|
|
||||||
|
const sizeStyle: CSSProperties = { |
||||||
|
height: `${props.height || 1000}rpx`, |
||||||
|
paddingTop: `${props.paddingTop || 0}rpx`, |
||||||
|
...props.style, |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<View className={styles.content} style={sizeStyle}> |
||||||
|
{ |
||||||
|
!props.offImage && <> |
||||||
|
<Image src={NoLogin}/> |
||||||
|
{/*<View className={styles.title}>暂未登录</View>*/} |
||||||
|
</> |
||||||
|
} |
||||||
|
<View onClick={() => { |
||||||
|
Taro.navigateTo({ |
||||||
|
url:'/pages/login/login' |
||||||
|
}) |
||||||
|
}} className={styles.button}>去登录</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default LoginView2 |
@ -0,0 +1,34 @@ |
|||||||
|
.navigation { |
||||||
|
position: sticky; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
z-index: 100; |
||||||
|
overflow: hidden; |
||||||
|
background: #fff; |
||||||
|
} |
||||||
|
|
||||||
|
.leftNode { |
||||||
|
position: absolute; |
||||||
|
display: flex; |
||||||
|
left: 20rpx; |
||||||
|
bottom: 0; |
||||||
|
align-items: center; |
||||||
|
z-index: 1; |
||||||
|
} |
||||||
|
|
||||||
|
.text { |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
margin: auto; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
font-size: 28rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.arrow { |
||||||
|
width: 32px; |
||||||
|
height: 32px; |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
import {Image, View} from "@tarojs/components"; |
||||||
|
import React, {CSSProperties, FC, ReactNode, useMemo} from "react"; |
||||||
|
import styles from './navigationBar.module.scss' |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import leftArrow from '@/static/img/leftArrow.png' |
||||||
|
|
||||||
|
interface Props { |
||||||
|
// 文本
|
||||||
|
text?: string | ReactNode |
||||||
|
children?: ReactNode | ReactNode[] |
||||||
|
// 左边节点
|
||||||
|
leftNode?: string | ReactNode | ReactNode[] |
||||||
|
// 字体颜色
|
||||||
|
color?: string |
||||||
|
// 背景颜色
|
||||||
|
backgroundColor?: string |
||||||
|
// 取消返回按钮
|
||||||
|
cancelBack?: boolean |
||||||
|
// 跟随页面滚动
|
||||||
|
inherit?: boolean |
||||||
|
className?: string |
||||||
|
style?: CSSProperties |
||||||
|
} |
||||||
|
|
||||||
|
const NavigationBar: FC<Props> = (props) => { |
||||||
|
const globalData = Taro.getApp().globalData |
||||||
|
const navigationBarStyle = useMemo((): React.CSSProperties => ({ |
||||||
|
background: props.backgroundColor, |
||||||
|
position: props.inherit ? 'inherit' : "sticky", |
||||||
|
paddingTop: globalData.statusBarHeight + 'px', |
||||||
|
height: globalData.textBarHeight + globalData.statusBarHeight + 'px', |
||||||
|
boxSizing: 'border-box', |
||||||
|
...props.style |
||||||
|
}), [props]) |
||||||
|
|
||||||
|
|
||||||
|
const navigationTextStyle = useMemo((): React.CSSProperties => ({ |
||||||
|
color: props.color, |
||||||
|
height: globalData.textBarHeight + 'px', |
||||||
|
}), [props]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<View className={`${props.className} ${styles.navigation}`} style={navigationBarStyle}> |
||||||
|
<View style={navigationTextStyle} className={styles.leftNode}> |
||||||
|
{ |
||||||
|
!props.cancelBack && <View className="flex flex-column justify-center align-center" style={{ |
||||||
|
width: globalData.textBarHeight + 'px', |
||||||
|
height: globalData.textBarHeight + 'px', |
||||||
|
}} onClick={() => Taro.navigateBack()}> |
||||||
|
<Image src={leftArrow} mode='aspectFill' className={styles.arrow}/> |
||||||
|
</View> |
||||||
|
} |
||||||
|
{props.leftNode} |
||||||
|
</View> |
||||||
|
<View style={navigationTextStyle} className={styles.text}>{props.children || props.text}</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default NavigationBar |
@ -0,0 +1,18 @@ |
|||||||
|
import {CSSProperties, FC} from "react"; |
||||||
|
import {View} from "@tarojs/components"; |
||||||
|
|
||||||
|
interface Props { |
||||||
|
text?: string |
||||||
|
styles?: CSSProperties |
||||||
|
className?: string |
||||||
|
} |
||||||
|
|
||||||
|
const PageScript: FC<Props> = (props) => { |
||||||
|
return <View |
||||||
|
className={'text-center font-24 text-muted py-3 ' + props.className} |
||||||
|
style={props.styles}> |
||||||
|
{props.text || "暂无更多"} |
||||||
|
</View> |
||||||
|
} |
||||||
|
|
||||||
|
export default PageScript |
@ -0,0 +1,27 @@ |
|||||||
|
.container { |
||||||
|
width: 100%; |
||||||
|
padding: 20rpx; |
||||||
|
box-sizing: border-box; |
||||||
|
columns: 2; |
||||||
|
column-gap: 20rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.health { |
||||||
|
break-inside: avoid; |
||||||
|
background: #fff; |
||||||
|
border-radius: 10px; |
||||||
|
overflow: hidden; |
||||||
|
margin-bottom: 20rpx; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.play { |
||||||
|
position: absolute; |
||||||
|
min-height: 70rpx !important; |
||||||
|
z-index: 9999; |
||||||
|
width: 40rpx !important; |
||||||
|
height: 40rpx !important; |
||||||
|
top: 20rpx; |
||||||
|
right: 20rpx; |
||||||
|
background: transparent !important; |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
import {FC, useEffect, useState} from "react"; |
||||||
|
import styles from "@/pages/preview/health/health.module.scss"; |
||||||
|
import {Image, Text, View} from "@tarojs/components"; |
||||||
|
import Img from "@/components/image/image"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import videoEvent from "@/hooks/videoEvent"; |
||||||
|
import playWhite from '@/static/img/palyWhite.png' |
||||||
|
import starWhite from '@/static/img/starWhite.png' |
||||||
|
import {formatMinute} from "@/utils/time"; |
||||||
|
import { getWfsInfo } from '@/utils/wfs' |
||||||
|
|
||||||
|
interface Props { |
||||||
|
data: VideList |
||||||
|
errorType?: ImgErrType |
||||||
|
} |
||||||
|
|
||||||
|
const VideoList: FC<Props> = (props) => { |
||||||
|
const [data, setData] = useState<VideList>(props.data) |
||||||
|
const [cover,setCover] = useState<string>('') |
||||||
|
|
||||||
|
console.log(data,'data现在的数据') |
||||||
|
useEffect(() => { |
||||||
|
|
||||||
|
getWfsInfo(data.resource_id).then(res => { |
||||||
|
setData((data) =>({...data, url_path:res.object.thumb,video_width:res.object.width,video_height:res.object.height})) |
||||||
|
setCover(res.object.thumb) |
||||||
|
}).catch(()=>{ |
||||||
|
console.log('获取失败') |
||||||
|
setData((data) => ({...data,video_width:data.resource.width,video_height:data.resource.height})) |
||||||
|
}) |
||||||
|
}, []) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
videoEvent.videoOn(data.id, ({view}) => { |
||||||
|
setData((data) => ({ |
||||||
|
...data, |
||||||
|
video_view: view |
||||||
|
})) |
||||||
|
}) |
||||||
|
}, []) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Taro.useUnload(() => { |
||||||
|
videoEvent.off(data.id) |
||||||
|
}) |
||||||
|
|
||||||
|
function jump() { |
||||||
|
Taro.preload(data) |
||||||
|
Taro.navigateTo({url: `/pages/preview/videoFull/videoFull?id=${data.id}`}) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
{ data.video_height && data.video_width |
||||||
|
&& |
||||||
|
<View className={styles.health}> |
||||||
|
<View key={data.id} onClick={jump} className="bg-white"> |
||||||
|
|
||||||
|
<Img src={cover || data.url_path} height={data.video_height/data.video_width*348} errorType={props.errorType} /> |
||||||
|
<View className='p-2 relative'> |
||||||
|
<View className='text-ellipsis-1 font-28 text-dark'>{data.title}</View> |
||||||
|
<View className='text-ellipsis-2 mt-2 font-24 text-secondary'>{data.introduction}</View> |
||||||
|
|
||||||
|
<View className={styles.info}> |
||||||
|
<View className='flex'> |
||||||
|
<View className='flex align-center mr-3'> |
||||||
|
<Image src={playWhite}/> |
||||||
|
<Text>{(data.video_view || 0)}</Text> |
||||||
|
</View> |
||||||
|
|
||||||
|
<View className='flex align-center'> |
||||||
|
<Image src={starWhite}/> |
||||||
|
<Text>{(data.collect_quantity || 0)}</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
<View>{formatMinute(data.duration || 0)}</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
} |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default VideoList |
@ -0,0 +1,8 @@ |
|||||||
|
.progressBottom{ |
||||||
|
bottom: calc(env(safe-area-inset-bottom) + 100rpx); |
||||||
|
//bottom:0; |
||||||
|
position: fixed; |
||||||
|
z-index: 1000; |
||||||
|
left:0; |
||||||
|
right:0; |
||||||
|
} |
@ -0,0 +1,247 @@ |
|||||||
|
import React, {FC, useEffect, useRef, useState, useImperativeHandle} from "react"; |
||||||
|
import {Image, Text, Video, View} from "@tarojs/components"; |
||||||
|
import styles from "./index.module.scss" |
||||||
|
import Icon from "@/components/icon"; |
||||||
|
import {AtSlider} from "taro-ui"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
import full from "@/static/img/fullscreen.png" |
||||||
|
import unFull from "@/static/img/exitFullscreen.png" |
||||||
|
|
||||||
|
type Props = { |
||||||
|
src: string |
||||||
|
onRef?: any |
||||||
|
showFull?: boolean |
||||||
|
height?: number |
||||||
|
progress2bottom?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
const VideoPro:FC<Props> = ({src,onRef,showFull,height,progress2bottom}) => { |
||||||
|
const globalData = Taro.getApp().globalData |
||||||
|
|
||||||
|
if(onRef){ |
||||||
|
//用useImperativeHandle暴露一些外部ref能访问的属性
|
||||||
|
useImperativeHandle(onRef, () => { |
||||||
|
return { |
||||||
|
func: pause, |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 视频ui控制需要的响应式数据
|
||||||
|
const videoContext = useRef<any>() |
||||||
|
const [isPlay, setIsPlay] = useState(true) |
||||||
|
const [duration,setDuration] = useState(0) // 视频长度 单位秒
|
||||||
|
const updateState = useRef(false) |
||||||
|
const [sliderValue,setSlidervalue] = useState(0) |
||||||
|
const [process_duration, set_process_duration] = useState('00:00') |
||||||
|
const [total_duration, set_total_duration] = useState('00:00') |
||||||
|
const [showMenu,setShowMenu] = useState(true) |
||||||
|
const [isFull,setIsFull] = useState(false) |
||||||
|
const time = useRef<NodeJS.Timeout>() |
||||||
|
|
||||||
|
const [videoHeight] = useState<number>(height || 600) |
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
console.log('组件加载') |
||||||
|
videoContext.current = Taro.createVideoContext('video') |
||||||
|
updateState.current = true |
||||||
|
}, []); |
||||||
|
|
||||||
|
|
||||||
|
function onTouchStart(){ |
||||||
|
if(!showMenu) { |
||||||
|
setShowMenu(true) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function onTouchEnd(){ |
||||||
|
if(time.current) { |
||||||
|
clearTimeout(time.current) |
||||||
|
time.current = undefined |
||||||
|
} |
||||||
|
time.current = setTimeout(() => { |
||||||
|
setShowMenu(false) |
||||||
|
},5000) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
function bindTimeupdateFun(e) { |
||||||
|
if (updateState.current) { |
||||||
|
let sliderValue = e.detail.currentTime / e.detail.duration * 100; |
||||||
|
setSlidervalue(sliderValue) |
||||||
|
setDuration(e.detail.duration) |
||||||
|
set_total_duration(formatSeconds(e.detail.duration)) |
||||||
|
set_process_duration(formatSeconds(e.detail.currentTime)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function addZero(i){ |
||||||
|
i = typeof i === 'string' ? Number(i) : i; |
||||||
|
return i < 10 ? "0" + i : "" + i; |
||||||
|
} |
||||||
|
|
||||||
|
function formatSeconds(value){ |
||||||
|
if (value == undefined) { |
||||||
|
value = 0; |
||||||
|
} |
||||||
|
let second = parseInt(value); |
||||||
|
let min = 0; |
||||||
|
let secondStr = '' |
||||||
|
let minStr = '' |
||||||
|
let result = '' |
||||||
|
if (second > 60) { |
||||||
|
min = parseInt(String(second / 60)); |
||||||
|
second = parseInt(String(second % 60)); |
||||||
|
if (min > 60) { |
||||||
|
// hour = parseInt(String(min / 60));
|
||||||
|
min = parseInt(String(min % 60)); |
||||||
|
} |
||||||
|
} |
||||||
|
if (min > 0) { |
||||||
|
minStr = addZero(parseInt(String(min))); |
||||||
|
result = minStr + ":"; |
||||||
|
}else{ |
||||||
|
result = "00:"; |
||||||
|
} |
||||||
|
if(second > 0){ |
||||||
|
secondStr = addZero(parseInt(String(second))); |
||||||
|
result = result + secondStr; |
||||||
|
}else{ |
||||||
|
result = result + '00'; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
function bindEnded(){ |
||||||
|
setIsPlay(false) |
||||||
|
if(!showMenu){ |
||||||
|
setShowMenu(true) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function onFullScreenChange(e){ |
||||||
|
console.log(e.detail.fullScreen) |
||||||
|
if(e.detail.fullScreen){ |
||||||
|
setIsFull(true) |
||||||
|
}else{ |
||||||
|
setIsFull(false) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function play(e){ |
||||||
|
e.stopPropagation(); |
||||||
|
videoContext.current.play() |
||||||
|
setIsPlay(true) |
||||||
|
} |
||||||
|
|
||||||
|
function pause(){ |
||||||
|
setIsPlay(false) |
||||||
|
videoContext.current.pause() |
||||||
|
} |
||||||
|
function sliderOnChange(e){ |
||||||
|
if (duration) { |
||||||
|
// 视频跳转到指定位置
|
||||||
|
videoContext.current.seek(e / 100 * duration); |
||||||
|
videoContext.current.play() |
||||||
|
setIsPlay(true) |
||||||
|
updateState.current = true |
||||||
|
setSlidervalue(e) |
||||||
|
} |
||||||
|
} |
||||||
|
function sliderOnChanging(){ |
||||||
|
updateState.current = false |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<View style={{width: '750rpx', height: `${videoHeight}rpx`}}> |
||||||
|
<Video |
||||||
|
style={{width: '750rpx', height: `${videoHeight}rpx`}} |
||||||
|
id='video' |
||||||
|
autoplay |
||||||
|
src={src} |
||||||
|
controls={false} |
||||||
|
showPlayBtn={false} |
||||||
|
showCenterPlayBtn={false} |
||||||
|
showProgress={false} |
||||||
|
showFullscreenBtn={false} |
||||||
|
enableProgressGesture={false} |
||||||
|
onTimeUpdate={bindTimeupdateFun} |
||||||
|
onEnded={bindEnded} |
||||||
|
onFullScreenChange={onFullScreenChange} |
||||||
|
> |
||||||
|
<View onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} style={{ |
||||||
|
width:isFull?`${globalData.screenHeight}px`:'750rpx', |
||||||
|
height:isFull?'750rpx':`${videoHeight}rpx`,display:'flex',flexDirection:'column', |
||||||
|
boxSizing:'border-box',paddingLeft:isFull?`${globalData.statusBarHeight}px`:'0', |
||||||
|
paddingRight:isFull?`${globalData.statusBarHeight}px`:'0'}} |
||||||
|
> |
||||||
|
<View onClick={pause} className="justify-center align-center flex pt-5" style={{flex:'1',boxSizing:'border-box'}}> |
||||||
|
{ !isPlay && showMenu && |
||||||
|
<View className="flex justify-center align-center rounded-50 pl-1" style={{width:'50px',height:'50px',backgroundColor:'rgba(0,0,0,0.5)',boxSizing:'border-box'}}> |
||||||
|
<Icon onClick={play} name="play" color="#fff" size="35px"></Icon> |
||||||
|
</View> |
||||||
|
} |
||||||
|
</View> |
||||||
|
<View className="flex align-center px-3" style={{height:'40px',boxSizing:'border-box'}}> |
||||||
|
{ duration > 0 && showMenu && !progress2bottom && |
||||||
|
<> |
||||||
|
{ |
||||||
|
isPlay ? |
||||||
|
<Icon name="pause" color="#fff" size="23px" onClick={() => {videoContext.current.pause();setIsPlay(false)}} /> : |
||||||
|
<Icon name="play" color="#fff" size="23px" onClick={() => {videoContext.current.play();setIsPlay(true)}} /> |
||||||
|
} |
||||||
|
<Text className="text-white pl-2 font-26">{process_duration}</Text> |
||||||
|
|
||||||
|
|
||||||
|
<View style={{flex:'1'}}> |
||||||
|
<AtSlider onChange={sliderOnChange} onChanging={sliderOnChanging} step={1} value={sliderValue} activeColor='#fff' backgroundColor='#BDBDBD' blockColor='#fff' blockSize={10}></AtSlider> |
||||||
|
</View> |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Text className="text-white font-26 pr-2">{total_duration}</Text> |
||||||
|
{ showFull && |
||||||
|
<> |
||||||
|
{isFull? <Image style={{width:'25px',height:'25px'}} onClick={() => videoContext.current.exitFullScreen() } src={unFull} /> |
||||||
|
: <Image style={{width:'23px',height:'23px'}} src={full} onClick={() => videoContext.current.requestFullScreen({direction:90}) } />} |
||||||
|
</> |
||||||
|
} |
||||||
|
</> |
||||||
|
} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</Video> |
||||||
|
|
||||||
|
<View className={`${styles.progressBottom} flex align-center px-3`} style={{height:'40px',boxSizing:'border-box'}}> |
||||||
|
{ duration > 0 && showMenu && progress2bottom && |
||||||
|
<> |
||||||
|
{ |
||||||
|
isPlay ? |
||||||
|
<Icon name="pause" color="#fff" size="23px" onClick={() => {videoContext.current.pause();setIsPlay(false)}} /> : |
||||||
|
<Icon name="play" color="#fff" size="23px" onClick={() => {videoContext.current.play();setIsPlay(true)}} /> |
||||||
|
} |
||||||
|
<Text className="text-white pl-2 font-26" style={{width:'60rpx'}}>{process_duration}</Text> |
||||||
|
|
||||||
|
|
||||||
|
<View style={{flex:'1'}}> |
||||||
|
<AtSlider onChange={sliderOnChange} onChanging={sliderOnChanging} step={1} value={sliderValue} activeColor='#fff' backgroundColor='#BDBDBD' blockColor='#fff' blockSize={10}></AtSlider> |
||||||
|
</View> |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Text className="text-white font-26 pr-2">{total_duration}</Text> |
||||||
|
{ showFull && |
||||||
|
<> |
||||||
|
{isFull? <Image style={{width:'25px',height:'25px'}} onClick={() => videoContext.current.exitFullScreen() } src={unFull} /> |
||||||
|
: <Image style={{width:'23px',height:'23px'}} src={full} onClick={() => videoContext.current.requestFullScreen({direction:90}) } />} |
||||||
|
</> |
||||||
|
} |
||||||
|
</> |
||||||
|
} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
export default VideoPro |
@ -0,0 +1,73 @@ |
|||||||
|
.wang_product{ |
||||||
|
width:100%; |
||||||
|
} |
||||||
|
|
||||||
|
.wang_product .product_water .water { |
||||||
|
border-radius: 16rpx !important; |
||||||
|
//background-color: #ffffff; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
.wang_product .product_water .water .image { |
||||||
|
border-radius: 16rpx 16rpx 0 0 !important; |
||||||
|
width: 100%; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.wang_product .product_water.col_2_20 .water { |
||||||
|
margin-bottom: 20rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.wang_product .product_water.col_2_20 .water.right { |
||||||
|
margin-left: 10rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.wang_product .product_water.col_2_20 .water.left { |
||||||
|
margin-right: 10rpx; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 二列布局 */ |
||||||
|
.wang_product .product_list[class*='col-2-'] .item image, |
||||||
|
.wang_product .product_list[class*='col-2-'] .item .img-wrap { |
||||||
|
width: 100%; |
||||||
|
height: 400rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.wang_product .product_list[class*='col-2-'] .comment { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.wang_product .product_list[class*='col-2-'] .content { |
||||||
|
height: 200rpx; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.wang_product .product_list.col_2_20:after { |
||||||
|
content: ''; |
||||||
|
width: calc((100% - 20rpx) / 2); |
||||||
|
} |
||||||
|
|
||||||
|
.wang_product .product_list.col_2_20 .item { |
||||||
|
width: calc((100% - 20rpx) / 2); |
||||||
|
margin-bottom: 20rpx; |
||||||
|
} |
||||||
|
|
||||||
|
.wang_waterfall { |
||||||
|
display: flex; |
||||||
|
flex-direction: row; |
||||||
|
align-items: flex-start; |
||||||
|
.wang_column { |
||||||
|
display: flex; |
||||||
|
flex: 1; |
||||||
|
flex-direction: column; |
||||||
|
height: auto; |
||||||
|
width: 50%; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,102 @@ |
|||||||
|
import { FC, useEffect, useState } from 'react' |
||||||
|
import { View } from '@tarojs/components' |
||||||
|
import VideoList from '@/components/videoList/videoList' |
||||||
|
import Taro from '@tarojs/taro' |
||||||
|
import styles from './index.module.scss' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
data: any[] |
||||||
|
} |
||||||
|
const WaterFull: FC<Props> = ({data}) => { |
||||||
|
const [leftList,setLeftList] = useState<any[]>([]) |
||||||
|
const [rightList,setRightList] = useState<any[]>([]) |
||||||
|
const [tempList,setTempList] = useState<any[]>([]) |
||||||
|
const [copyFlowList,setCopyFlowList] = useState<any[]>([]) |
||||||
|
const startLength = copyFlowList.length |
||||||
|
// const query = Taro.createSelectorQuery()
|
||||||
|
|
||||||
|
console.log(rightList.length,leftList.length,"高") |
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setTempList(cloneData(data).splice(startLength)) |
||||||
|
setCopyFlowList(cloneData(data)) |
||||||
|
}, [data]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
let tempArr = cloneData(tempList) |
||||||
|
splitData(tempArr) |
||||||
|
}, [tempList]) |
||||||
|
|
||||||
|
|
||||||
|
async function splitData(arr: any[]){ |
||||||
|
|
||||||
|
if (!arr.length) { |
||||||
|
return |
||||||
|
} |
||||||
|
// let leftHeight = await getRect('#wang-left-column')
|
||||||
|
// let rightHeight = await getRect('#wang-right-column')
|
||||||
|
// console.log("左侧高度",leftHeight,)
|
||||||
|
let item = arr[0] |
||||||
|
Taro.nextTick(() => { |
||||||
|
arr.length % 2 == 0 ? setLeftList((data) => ([...data, item])) : setRightList((data) => ([...data, item])) |
||||||
|
}) |
||||||
|
// if (leftHeight < rightHeight) {
|
||||||
|
// console.log("左侧插入",leftHeight,rightHeight)
|
||||||
|
// setLeftList((data) => ([...data,item]))
|
||||||
|
// } else if (leftHeight > rightHeight) {
|
||||||
|
// console.log("右侧插入",leftHeight,rightHeight)
|
||||||
|
// setRightList((data) => ([...data,item]))
|
||||||
|
// } else {
|
||||||
|
// console.log("左侧插入")
|
||||||
|
// setLeftList((data) => ([...data,item]))
|
||||||
|
// }
|
||||||
|
// 移除临时列表的第一项
|
||||||
|
arr.splice(0, 1) |
||||||
|
// 如果临时数组还有数据,继续循环
|
||||||
|
Taro.nextTick(() => { |
||||||
|
if (arr.length) { |
||||||
|
splitData(arr) // 在当前同步流程结束后,下一个时间片执行
|
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// async function getRect(selector:string): Promise<number> {
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
//
|
||||||
|
// query.select(selector).boundingClientRect()
|
||||||
|
// // 执行查询,获取结果
|
||||||
|
// query.exec((res) => {
|
||||||
|
// if (res && res[0]) {
|
||||||
|
// console.log('Element height:',res, res[0].height)
|
||||||
|
// resolve(res[0].height)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
function cloneData(data:unknown[]) { |
||||||
|
return JSON.parse(JSON.stringify(data)) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<View className={styles.wang_product}> |
||||||
|
<View className={[styles.product_water,styles.col_2_20].join(" ")}> |
||||||
|
<View className={styles.wang_waterfall}> |
||||||
|
<View id="wang-left-column" className={styles.wang_column}> |
||||||
|
<View className={`${styles.water} ${styles.left}`}> |
||||||
|
|
||||||
|
{leftList.map(d => <VideoList key={d.id} data={d} errorType='health'/>)} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
<View id="wang-right-column" className={styles.wang_column}> |
||||||
|
<View className={[styles.water,styles.right].join(" ")}> |
||||||
|
{rightList.map(d => <VideoList key={d.id} data={d} errorType='health'/>)} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
export default WaterFull |
@ -0,0 +1,28 @@ |
|||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
|
||||||
|
const KEY = 'ARTICLES_EVENTS' |
||||||
|
|
||||||
|
interface Data { |
||||||
|
id: number |
||||||
|
view: number |
||||||
|
} |
||||||
|
|
||||||
|
function recordsAdd(data: Data) { |
||||||
|
Taro.eventCenter.trigger(KEY + data.id, data) |
||||||
|
} |
||||||
|
|
||||||
|
function recordsOn(id: number, fn: (data: Data) => void) { |
||||||
|
Taro.eventCenter.on(KEY + id, fn) |
||||||
|
} |
||||||
|
|
||||||
|
function off(id: number) { |
||||||
|
Taro.eventCenter.off(KEY + id) |
||||||
|
} |
||||||
|
|
||||||
|
const ArticlesEvent = { |
||||||
|
recordsAdd, |
||||||
|
recordsOn, |
||||||
|
off |
||||||
|
} |
||||||
|
|
||||||
|
export default ArticlesEvent |
@ -1,25 +0,0 @@ |
|||||||
import Taro from "@tarojs/taro"; |
|
||||||
|
|
||||||
/** |
|
||||||
* 首页全局事件 |
|
||||||
* 当某个课程看完-触发未完成移动已完成 |
|
||||||
*/ |
|
||||||
const KEY = 'REFRESH_INDEX' |
|
||||||
|
|
||||||
interface RefreshIndex { |
|
||||||
id: number |
|
||||||
} |
|
||||||
|
|
||||||
function on(fn: (arg: RefreshIndex) => void) { |
|
||||||
Taro.eventCenter.on(KEY, fn) |
|
||||||
} |
|
||||||
|
|
||||||
function trigger(data: RefreshIndex) { |
|
||||||
Taro.eventCenter.trigger(KEY, data) |
|
||||||
} |
|
||||||
|
|
||||||
export default { |
|
||||||
on, |
|
||||||
trigger |
|
||||||
} |
|
||||||
|
|
@ -0,0 +1,40 @@ |
|||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
|
||||||
|
type Topic = string | symbol |
||||||
|
type Subscriber = (...args: any[]) => void |
||||||
|
|
||||||
|
export default function usePubsub() { |
||||||
|
const events = new Map<Topic, Subscriber[]>() |
||||||
|
const registers = new Map<Topic, Subscriber>() |
||||||
|
|
||||||
|
const pub = (topic: Topic, data: any) => { |
||||||
|
console.log("发布没有") |
||||||
|
Taro.eventCenter.trigger(topic, data) |
||||||
|
}; |
||||||
|
|
||||||
|
const sub = (topic: Topic, callback: Subscriber) => { |
||||||
|
const cbs = events.get(topic) ?? [] |
||||||
|
events.set(topic, cbs.concat(callback)) |
||||||
|
if (!registers.has(topic)) { |
||||||
|
console.log({topic}) |
||||||
|
const listener = (...args: any[]): void => { |
||||||
|
events.get(topic)?.forEach((cb) => cb(...args)) |
||||||
|
} |
||||||
|
registers.set(topic, listener) |
||||||
|
Taro.eventCenter.on(topic, listener) |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
Taro.useUnload(() => { |
||||||
|
registers.forEach((listener, topic) => { |
||||||
|
Taro.eventCenter.off(topic, listener) |
||||||
|
}) |
||||||
|
registers.clear() |
||||||
|
events.clear() |
||||||
|
}) |
||||||
|
|
||||||
|
return { |
||||||
|
pub, |
||||||
|
sub |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
|
||||||
|
const KEY = 'VIDEO_EVENTS' |
||||||
|
|
||||||
|
interface Data { |
||||||
|
id: number |
||||||
|
view: number |
||||||
|
} |
||||||
|
|
||||||
|
function videoAdd(data: Data) { |
||||||
|
Taro.eventCenter.trigger(KEY + data.id, data) |
||||||
|
} |
||||||
|
|
||||||
|
function videoOn(id: number, fn: (data: Data) => void) { |
||||||
|
Taro.eventCenter.on(KEY + id, fn) |
||||||
|
} |
||||||
|
|
||||||
|
function off(id: number) { |
||||||
|
Taro.eventCenter.off(KEY + id) |
||||||
|
} |
||||||
|
|
||||||
|
const VideoEvent = { |
||||||
|
videoAdd, |
||||||
|
videoOn, |
||||||
|
off |
||||||
|
} |
||||||
|
|
||||||
|
export default VideoEvent |
@ -0,0 +1,3 @@ |
|||||||
|
export default definePageConfig({ |
||||||
|
navigationBarTitleText: 'waterFull' |
||||||
|
}) |
@ -0,0 +1,37 @@ |
|||||||
|
import VirtualList from '@tarojs/components/virtual-list' |
||||||
|
import React, { Component } from 'react' |
||||||
|
import { View } from '@tarojs/components' |
||||||
|
function buildData(offset = 0) { |
||||||
|
return Array(500) |
||||||
|
.fill(0) |
||||||
|
.map((_, i) => i + offset) |
||||||
|
} |
||||||
|
|
||||||
|
const Row = React.memo(({ id, index, data }:{id: any,index:any,data:any}) => { |
||||||
|
return ( |
||||||
|
<View id={id} className={index % 2 ? 'ListItemOdd' : 'ListItemEven'}> |
||||||
|
Row {index} : {data[index]} |
||||||
|
</View> |
||||||
|
) |
||||||
|
}) |
||||||
|
|
||||||
|
export default class Index extends Component { |
||||||
|
state = { |
||||||
|
data: buildData(0), |
||||||
|
} |
||||||
|
|
||||||
|
render() { |
||||||
|
const { data } = this.state |
||||||
|
const dataLen = data.length |
||||||
|
return ( |
||||||
|
<VirtualList |
||||||
|
height={800} /* 列表的高度 */ |
||||||
|
width="100%" /* 列表的宽度 */ |
||||||
|
item={Row} /* 列表单项组件,这里只能传入一个组件 */ |
||||||
|
itemData={data} /* 渲染列表的数据 */ |
||||||
|
itemCount={dataLen} /* 渲染列表的长度 */ |
||||||
|
itemSize={100} /* 列表单项的高度 */ |
||||||
|
/> |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -1,3 +1,3 @@ |
|||||||
export default definePageConfig({ |
export default definePageConfig({ |
||||||
navigationBarTitleText: '绑定手机号' |
navigationBarTitleText: '员工验证', |
||||||
}) |
}) |
||||||
|
@ -1,21 +1,20 @@ |
|||||||
import {FC} from "react"; |
import {FC} from "react"; |
||||||
import {Input, View} from "@tarojs/components"; |
import {Image, View} from "@tarojs/components"; |
||||||
import styles from "../home.module.scss"; |
import styles from "../home.module.scss"; |
||||||
import Icon from "@/components/icon"; |
import Taro from "@tarojs/taro"; |
||||||
|
import search from "@/static/img/search.png" |
||||||
|
|
||||||
interface Props { |
|
||||||
onConfirm: (value: string) => void |
|
||||||
} |
|
||||||
|
|
||||||
export const Search: FC<Props> = (props) => { |
export const Search: FC = () => { |
||||||
|
|
||||||
|
function jump() { |
||||||
|
Taro.navigateTo({url: '/pages/preview/search/search/index'}) |
||||||
|
} |
||||||
|
|
||||||
return ( |
return ( |
||||||
<View className={styles.search}> |
<View className={styles.search} onClick={jump}> |
||||||
<Icon name='search' size={18} color='#808080'/> |
<Image src={search} mode='widthFix' style={{width: 16, height: 16, verticalAlign: 'middle',paddingRight:'10rpx'}}/> |
||||||
<Input |
<View>点击搜索</View> |
||||||
placeholder='搜索疾病名称' |
|
||||||
confirmType='search' |
|
||||||
onConfirm={(e) => props.onConfirm((e.target as any).value!)} |
|
||||||
className='flex-1 pl-1'/> |
|
||||||
</View> |
</View> |
||||||
) |
) |
||||||
} |
} |
||||||
|
@ -1,7 +1,9 @@ |
|||||||
export default definePageConfig({ |
export default definePageConfig({ |
||||||
navigationBarTitleText: '康一诺', |
navigationBarTitleText: '康一诺', |
||||||
// navigationStyle: 'custom',
|
navigationStyle: 'custom', |
||||||
navigationBarBackgroundColor: '#92ecc5', |
navigationBarBackgroundColor: '#92ecc5', |
||||||
navigationBarTextStyle: 'white', |
// navigationBarTextStyle: 'white',
|
||||||
onReachBottomDistance: 50 |
onReachBottomDistance: 50, |
||||||
|
enableShareTimeline: true, |
||||||
|
enableShareAppMessage: true |
||||||
}) |
}) |
||||||
|
@ -1,5 +1,5 @@ |
|||||||
export default definePageConfig({ |
export default definePageConfig({ |
||||||
navigationBarTitleText: '医学道', |
navigationStyle: 'custom', |
||||||
navigationBarBackgroundColor: '#92ecc5', |
enableShareTimeline: true, |
||||||
navigationBarTextStyle: 'white', |
enableShareAppMessage: true |
||||||
}) |
}) |
||||||
|
@ -1,32 +1,87 @@ |
|||||||
import {FC, useState} from "react"; |
import {FC, useEffect, useState} from "react"; |
||||||
import {View} from "@tarojs/components"; |
import {View, Text} from "@tarojs/components"; |
||||||
import styles from './index.module.scss' |
import styles from './index.module.scss' |
||||||
import {VideoList} from "@/pages/index/components/videoList"; |
import {VideoList} from "@/pages/index/components/videoList"; |
||||||
import Tabs, {OnChangOpt, TabList} from "@/components/tabs/tabs"; |
import Tabs, {OnChangOpt, TabList} from "@/components/tabs/tabs"; |
||||||
import {CoursesKey} from "@/api/public"; |
import {CoursesKey, publicApi} from "@/api/public"; |
||||||
|
import NavigationBar from "@/components/navigationBar/navigationBar"; |
||||||
|
import Spin from "@/components/spinner"; |
||||||
|
import {isBoolean} from "@tarojs/shared"; |
||||||
|
import ArticlesBox from "@/components/articlesBox/articlesBox"; |
||||||
|
import PageScript from "@/components/pageScript/pageScript"; |
||||||
|
import Taro from "@tarojs/taro"; |
||||||
|
|
||||||
|
const category: TabList[] = [ |
||||||
|
{title: "企选课程", value: 'is_required'}, |
||||||
|
{title: "平台课程", value: 'is_not_required'}, |
||||||
|
] |
||||||
|
|
||||||
const Index: FC = () => { |
const Index: FC = () => { |
||||||
const category: TabList[] = [ |
|
||||||
{title: "必修", value: 'is_required'}, |
|
||||||
{title: "选修", value: 'is_not_required'}, |
|
||||||
{title: "已完成", value: 'is_finished'}, |
|
||||||
{title: "未完成", value: 'is_not_finished'}, |
|
||||||
] |
|
||||||
const [categoryKey, setCategoryKey] = useState<CoursesKey>('is_required') |
const [categoryKey, setCategoryKey] = useState<CoursesKey>('is_required') |
||||||
|
|
||||||
function tabChange(data: OnChangOpt) { |
function tabChange(data: OnChangOpt) { |
||||||
setCategoryKey(data.tab?.value as CoursesKey) |
setCategoryKey(data.tab?.value as CoursesKey) |
||||||
} |
} |
||||||
|
|
||||||
|
Taro.useShareAppMessage((res) => { |
||||||
|
if(res.from === 'button'){ |
||||||
|
|
||||||
|
} |
||||||
|
return { |
||||||
|
title:'信桂', |
||||||
|
path: '/pages/index/index' |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
Taro.useShareTimeline(() => { |
||||||
|
return { |
||||||
|
title: '信桂' |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
return ( |
||||||
|
<View className={styles.content}> |
||||||
|
<NavigationBar |
||||||
|
cancelBack |
||||||
|
leftNode={<Tabs tabList={category} onChange={tabChange} current={categoryKey} scrollable={false} hiddenSliding/>} |
||||||
|
/> |
||||||
|
<VideoList |
||||||
|
categoryKey={categoryKey} |
||||||
|
setCategoryKey={(categoryKey) => setCategoryKey(categoryKey)} |
||||||
|
/> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
const AuditMode: FC = () => { |
||||||
|
const [auditMode, setAuditMode] = useState(true) |
||||||
|
const [articles, setArticles] = useState<any[]>([]) |
||||||
|
const [enable, setEnable] = useState(true) |
||||||
|
useEffect(() => { |
||||||
|
publicApi.course({page: 1, pageSize: 10}).then(res => { |
||||||
|
setAuditMode(isBoolean(res.audit_mode) ? res.audit_mode : res.audit_mode === 'true') |
||||||
|
setArticles(res.articles) |
||||||
|
setEnable(false) |
||||||
|
}) |
||||||
|
}, []) |
||||||
return ( |
return ( |
||||||
<> |
<> |
||||||
<View className={styles.content}> |
<Spin enable={enable} overlay/> |
||||||
<Tabs tabList={category} onChange={tabChange} current={categoryKey}/> |
{ |
||||||
<VideoList categoryKey={categoryKey} setCategoryKey={(categoryKey) => setCategoryKey(categoryKey)}/> |
auditMode ? |
||||||
</View> |
<> |
||||||
|
<NavigationBar cancelBack leftNode={<Text className="bold font-36" style={{color:'#323635'}} >文章列表</Text>} /> |
||||||
|
<View className='bg-white rounded-20 clip m-3 px-3'> |
||||||
|
{ |
||||||
|
articles.map(d => <ArticlesBox key={d.id} data={d}/>) |
||||||
|
} |
||||||
|
</View> |
||||||
|
<PageScript/> |
||||||
|
</> |
||||||
|
: <Index/> |
||||||
|
} |
||||||
</> |
</> |
||||||
) |
) |
||||||
} |
} |
||||||
|
|
||||||
export default Index |
export default AuditMode |
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue