更改瀑布流视频封面加载状态及请求视频数据是否需要替换最新资源

master
一杯沧海 10 months ago
parent 07fed1a1e5
commit 88f1eb3720
  1. 3
      src/app.config.ts
  2. 11
      src/components/collect/collect.module.scss
  3. 8
      src/components/collect/collect.tsx
  4. 16
      src/components/image/image.tsx
  5. 2
      src/components/navigationBar/navigationBar.module.scss
  6. 36
      src/components/videoList/videoList.tsx
  7. 8
      src/components/videoPro/index.module.scss
  8. 63
      src/components/videoPro/index.tsx
  9. 73
      src/components/water-full/index.module.scss
  10. 102
      src/components/water-full/index.tsx
  11. 1
      src/hooks/pubsub.ts
  12. 3
      src/pages/business/waterFull/test.config.ts
  13. 37
      src/pages/business/waterFull/test.tsx
  14. 3
      src/pages/home/home.tsx
  15. 90
      src/pages/preview/brand/info/info.tsx
  16. 17
      src/pages/preview/health/health.module.scss
  17. 17
      src/pages/preview/health/health.tsx
  18. 65
      src/pages/preview/illness/sort/components/secondLevel.tsx
  19. 37
      src/pages/preview/illness/sort/sort.tsx
  20. 13
      src/pages/preview/profession/profession.module.scss
  21. 30
      src/pages/preview/profession/profession.tsx
  22. 15
      src/pages/preview/videoFull/videoFull.module.scss
  23. 140
      src/pages/preview/videoFull/videoFull.tsx
  24. 53
      src/utils/wfs.ts
  25. 6
      types/home.d.ts

@ -68,7 +68,8 @@ export default defineAppConfig({
'history/history',
'curHistory/curHistory',
'hourHistory/hourHistory',
'courType/courType'
'courType/courType',
'waterFull/test',
]
},
{

@ -3,25 +3,18 @@
display: flex;
align-items: center;
color: #909795;
font-size: 24rpx;
padding: 0 10rpx;
}
.collectImage {
position: relative;
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
//Image {
// width: 100%;
// height: 100%;
//}
}
.zoom {
//top: 0;
//left: 0;
position: absolute;
content: '';
width: 32rpx;

@ -1,7 +1,7 @@
import {CSSProperties, FC, useCallback, useEffect, useState} from "react";
// import star from '@/static/img/star.png'
// import starLine from '@/static/img/starLine.png'
import {View} from "@tarojs/components";
import {View,Text} from "@tarojs/components";
import styles from './collect.module.scss'
import {Profile} from "@/store"
import Taro from "@tarojs/taro";
@ -70,7 +70,11 @@ const Collect: FC<Props> = (props) => {
{/*<Image src={(select && token) ? star : starLine} className={`${loading && styles.pulse}`}/>*/}
</View>
{/*{!props.textHidden && (select ? '已收藏' : '收藏')}*/}
{!props.textHidden && '收藏'}
{
!props.textHidden &&
<Text style={{fontSize:'30rpx',lineHeight:'30rpx'}}></Text>
}
{/*<Text>{!props.textHidden && '收藏'}</Text>*/}
</View>
)
}

@ -1,5 +1,5 @@
import {FC, useEffect, useState} from "react";
import {Image, ImageProps, View} from "@tarojs/components";
import { Image, ImageProps, View } from "@tarojs/components";
import shard from '@/static/img/shard.png'
import Taro from "@tarojs/taro";
import avatar from '@/static/img/avatar.png'
@ -7,6 +7,7 @@ import healthShard from '@/static/img/healthShard.png'
import professionShard from '@/static/img/professionShard.png'
import brandSecond from '@/static/img/brandSecond.png'
import courseShard from '@/static/img/courseShard.png'
import logo from '@/static/img/logo.svg'
interface Props extends ImageProps {
width?: number | string
@ -26,6 +27,9 @@ const Img: FC<Props> = ({src, mode = 'aspectFill', width, fallback = shard, ...p
const imgAnimation = Taro.createAnimation({duration: 0}).opacity(0).step()
const [animationData, setAnimationData] = useState<TaroGeneral.IAnyObject>(imgAnimation.export())
console.log(height,'height')
console.log(loading,'loading')
useEffect(() => {
if (!isError && props.fit) {
Taro.getImageInfo({
@ -39,6 +43,7 @@ const Img: FC<Props> = ({src, mode = 'aspectFill', width, fallback = shard, ...p
setLoading(!!src)
}, [src])
useEffect(() => {
if (props.errorImage) {
setErrorUrl(props.errorImage)
@ -88,6 +93,15 @@ const Img: FC<Props> = ({src, mode = 'aspectFill', width, fallback = shard, ...p
height: height ? typeof height === 'string' ? height : `${height}rpx` : "100%",
backgroundColor: (isError || !loading) ? 'transparent' : '#F8F8F8',
}}>
{ loading &&
<View style={{width: "100%", height: '100%',display:'flex',justifyContent:'center',alignItems:'center'}}>
<Image
src={logo}
mode={"widthFix"}
style={{width: `100rpx`}}/>
</View>
}
{!isError &&
<View animation={animationData} style={{height: '100%', width: '100%'}}>
<Image

@ -19,7 +19,7 @@
.text {
position: absolute;
left: 20rpx;
left: 0;
right: 0;
margin: auto;
display: flex;

@ -4,9 +4,10 @@ import {Image, Text, View} from "@tarojs/components";
import Img from "@/components/image/image";
import Taro from "@tarojs/taro";
import videoEvent from "@/hooks/videoEvent";
import palyWhite from '@/static/img/palyWhite.png'
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
@ -14,21 +15,32 @@ interface Props {
}
const VideoList: FC<Props> = (props) => {
const [data, setData] = useState(props.data)
const [data, setData] = useState<VideList>(props.data)
const [cover,setCover] = useState<string>('')
console.log(data,'data现在的数据')
useEffect(() => {
setData(props.data)
}, [props.data])
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({
setData((data) => ({
...data,
video_view: view
})
}))
})
}, [])
Taro.useUnload(() => {
videoEvent.off(data.id)
})
@ -39,10 +51,13 @@ const VideoList: FC<Props> = (props) => {
}
return (
<>
{ data.video_height && data.video_width
&&
<View className={styles.health}>
<View key={data.id} onClick={jump} className="bg-white">
<Img src={data.url_path} mode='widthFix' errorType={props.errorType} height={346}/>
<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>
@ -50,7 +65,7 @@ const VideoList: FC<Props> = (props) => {
<View className={styles.info}>
<View className='flex'>
<View className='flex align-center mr-3'>
<Image src={palyWhite}/>
<Image src={playWhite}/>
<Text>{(data.video_view || 0)}</Text>
</View>
@ -64,7 +79,10 @@ const VideoList: FC<Props> = (props) => {
</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;
}

@ -1,6 +1,6 @@
import React, {FC, useEffect, useRef, useState, useImperativeHandle} from "react";
import {Image, Text, Video, View} from "@tarojs/components";
import "./index.module.scss"
import styles from "./index.module.scss"
import Icon from "@/components/icon";
import {AtSlider} from "taro-ui";
import Taro from "@tarojs/taro";
@ -11,9 +11,11 @@ type Props = {
src: string
onRef?: any
showFull?: boolean
height?: number
progress2bottom?: boolean
}
const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
const VideoPro:FC<Props> = ({src,onRef,showFull,height,progress2bottom}) => {
const globalData = Taro.getApp().globalData
if(onRef){
@ -27,7 +29,7 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
// 视频ui控制需要的响应式数据
const videoContext = useRef<any>()
const [isPlay, setIsPlay] = useState(false)
const [isPlay, setIsPlay] = useState(true)
const [duration,setDuration] = useState(0) // 视频长度 单位秒
const updateState = useRef(false)
const [sliderValue,setSlidervalue] = useState(0)
@ -35,7 +37,9 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
const [total_duration, set_total_duration] = useState('00:00')
const [showMenu,setShowMenu] = useState(true)
const [isFull,setIsFull] = useState(false)
const time = useRef<any>()
const time = useRef<NodeJS.Timeout>()
const [videoHeight] = useState<number>(height || 600)
useEffect(() => {
@ -54,7 +58,7 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
function onTouchEnd(){
if(time.current) {
clearTimeout(time.current)
time.current = null
time.current = undefined
}
time.current = setTimeout(() => {
setShowMenu(false)
@ -140,6 +144,8 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
if (duration) {
// 视频跳转到指定位置
videoContext.current.seek(e / 100 * duration);
videoContext.current.play()
setIsPlay(true)
updateState.current = true
setSlidervalue(e)
}
@ -149,10 +155,11 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
}
return (
<View className="container">
<View style={{width: '750rpx', height: `${videoHeight}rpx`}}>
<Video
style={{width: '750rpx', height: '600rpx'}}
style={{width: '750rpx', height: `${videoHeight}rpx`}}
id='video'
autoplay
src={src}
controls={false}
showPlayBtn={false}
@ -164,7 +171,12 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
onEnded={bindEnded}
onFullScreenChange={onFullScreenChange}
>
<View onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} style={{width:isFull?`${globalData.screenHeight}px`:'750rpx',height:isFull?'750rpx':'600rpx',display:'flex',flexDirection:'column',boxSizing:'border-box',paddingLeft:isFull?`${globalData.statusBarHeight}px`:'0',paddingRight:isFull?`${globalData.statusBarHeight}px`:'0'}}>
<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'}}>
@ -173,7 +185,7 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
}
</View>
<View className="flex align-center px-3" style={{height:'40px',boxSizing:'border-box'}}>
{ duration && showMenu &&
{ duration > 0 && showMenu && !progress2bottom &&
<>
{
isPlay ?
@ -181,9 +193,14 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
<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 &&
<>
@ -196,6 +213,34 @@ const VideoPro:FC<Props> = ({src,onRef,showFull}) => {
</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>
)
}

@ -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

@ -8,6 +8,7 @@ export default function usePubsub() {
const registers = new Map<Topic, Subscriber>()
const pub = (topic: Topic, data: any) => {
console.log("发布没有")
Taro.eventCenter.trigger(topic, data)
};

@ -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} /* 列表单项的高度 */
/>
)
}
}

@ -71,8 +71,7 @@ const Home: FC = () => {
</>
}
>
<View className={styles.headerDivider}
style={{borderBottom: `1px solid rgba(200,200,200,${navbarOpacity})`}}></View>
<View className={styles.headerDivider} style={{borderBottom: `1px solid rgba(200,200,200,${navbarOpacity})`}}></View>
</NavigationBar>
<Spin enable={enable} overlay/>
<View className={styles.content} style={{paddingBottom: token ? 0 : '100rpx'}}>

@ -22,6 +22,8 @@ const BrandInfo: FC = () => {
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
const [enable, setEnable] = useState(true)
// const [maxHeight,setMaxHeight] = useState<number>(600)
// const [maxWidth,setMaxWidth] = useState(750)
let VideoRef = React.createRef<any>()
Taro.useDidHide(() => {
@ -34,11 +36,45 @@ const BrandInfo: FC = () => {
getData()
}, [id])
useEffect(() => {
// console.log(brandInfo,'brandInfo')
// let tempArr:any[] = []
// if(brandInfo?.brand_album){
// tempArr.push(brandInfo.brand_album.split(',').map(item => {
// return item.split('?')[1].split('&')
// }))
// }
// if(brandInfo?.introductory_video_resource){
// tempArr.push([`width=${brandInfo?.introductory_video_resource.width}`,`height=${brandInfo?.introductory_video_resource.height}`])
// }
// console.log(tempArr,'tempArr')
// tempArr?.reduce((accumulator, currentValue)=>{
// return accumulator = accumulator > currentValue[1].split('=')[1] ? accumulator : currentValue
// })
}, [brandInfo]);
const getData = async () => {
try {
const data = await brandApi.info(id)
Taro.setNavigationBarTitle({title: data.name})
setBrandInfo(data)
if(data.introductory_video) {
Taro.request({
url: `https://wfs.yaojiankang.top/files/${data.introductory_video}`,
success: function (res) {
if (res.data.ok) {
setBrandInfo((data) => ({
...data!,
introductory_video_resource: {
url: res.data.data.object.path,
width: res.data.data.object.width,
height: res.data.data.object.height,
}
}))
}
}
})
}
const data1 = await brandApi.articleList(id, page)
setTotal(data1.total)
setArticleList([
@ -86,13 +122,58 @@ const BrandInfo: FC = () => {
function onChange(e) {
setCurIndex(+e.detail.current + 1)
VideoRef.current.func()
}
return (
<View className='flex flex-column' style={{display: 'flex'}}>
<Spin enable={enable} overlay/>
{
(brandInfo?.introductory_video_resource?.url || brandInfo?.brand_album)?.length > 0 &&
brandInfo?.introductory_video_resource?.url && !brandInfo?.brand_album?.length &&
<View className={styles['swiper']}>
<VideoPro onRef={VideoRef} src={brandInfo.introductory_video_resource.url}></VideoPro>
</View>
}
{
!brandInfo?.introductory_video_resource?.url && brandInfo?.brand_album?.length &&
<>
{
brandInfo?.brand_album?.length > 1 ?
<>
<Swiper
className={styles['swiper']}
indicatorColor='#999'
indicatorActiveColor='#333'
indicatorDots={false}
onChange={onChange}
>
{
brandInfo.brand_album.split(',').map((d) =>
<SwiperItem key={d}>
<Img mode={'aspectFill'} width={750} height={600} src={d} errorType='brand'/>
</SwiperItem>)
}
</Swiper>
<View className={styles.curIndexBox}>
<Text className={'font-26'}>{curIndex}</Text>
<Text>/</Text>
<Text>{(brandInfo?.brand_album?.split(',').length || 0) + ((brandInfo && brandInfo.introductory_video_resource) ? 1 : 0)}</Text>
</View>
</>
:
<>
{
brandInfo?.brand_album?.split(',').map((d) =>
<Img mode={'aspectFill'} width={750} height={600} src={d} errorType='brand'/>)
}
</>
}
</>
}
{
(brandInfo?.introductory_video_resource?.url && brandInfo?.brand_album?.length) &&
<>
<Swiper
className={styles['swiper']}
@ -101,12 +182,11 @@ const BrandInfo: FC = () => {
indicatorDots={false}
onChange={onChange}
>
{brandInfo?.introductory_video_resource?.url && <SwiperItem>
<SwiperItem>
<VideoPro onRef={VideoRef} src={brandInfo.introductory_video_resource.url}></VideoPro>
</SwiperItem>}
</SwiperItem>
{
(brandInfo?.brand_album?.length || 0) > 0
&& brandInfo?.brand_album?.split(',').map((d) =>
brandInfo.brand_album.split(',').map((d) =>
<SwiperItem key={d}>
<Img mode={'aspectFill'} width={750} height={600} src={d} errorType='brand'/>
</SwiperItem>)

@ -1,17 +1,24 @@
.container {
width: 100%;
//.container {
// width: 100%;
// padding: 0 20rpx;
// box-sizing: border-box;
// column-count: 2;
// column-gap: 20rpx;
//}
.container{
width:100%;
padding: 0 20rpx;
box-sizing: border-box;
column-count: 2;
column-gap: 20rpx;
}
.health {
border-radius: 10px;
padding-top: 20rpx;
//padding-top: 20rpx;
position: relative;
break-inside: avoid;
overflow: hidden;
margin-bottom: 20rpx;
}
.play {

@ -1,18 +1,20 @@
import {FC, useEffect, useState} from "react";
import {View} from "@tarojs/components";
import { View } from "@tarojs/components";
import {HomeApi} from "@/api";
import {useReachBottom} from "@tarojs/taro";
import styles from './health.module.scss'
import Empty from "@/components/empty/empty";
import Spin from "@/components/spinner";
import VideoList from "@/components/videoList/videoList";
// import VideoList from "@/components/videoList/videoList";
import PageScript from "@/components/pageScript/pageScript";
import WaterFull from '@/components/water-full'
const Health: FC = () => {
const [page, setPage] = useState(1)
const [data, setData] = useState<VideList[]>([])
const [total, setTotal] = useState(0)
const [enable, setEnable] = useState(true)
const [loadText,setLoadText] = useState('加载中~')
async function getData(page: number) {
try {
@ -22,6 +24,10 @@ const Health: FC = () => {
...res.data,
])
setTotal(res.total)
if(res.total < 10){
setLoadText('没有更多了')
}
} catch (e) {
}
setEnable(false)
@ -29,6 +35,7 @@ const Health: FC = () => {
useReachBottom(() => {
data.length < total && setPage(page + 1)
data.length >= total && setLoadText('没有更多了')
})
useEffect(() => {
@ -36,6 +43,7 @@ const Health: FC = () => {
}, [page])
return (
<>
<Spin enable={enable} overlay/>
@ -43,9 +51,10 @@ const Health: FC = () => {
{
data.length > 0 ? <>
<View className={styles.container}>
{data.map(d => <VideoList key={d.id} data={d} errorType='health'/>)}
{/*{data.map(d => <VideoList key={d.id} data={d} errorType='health'/>)}*/}
<WaterFull data={data}/>
</View>
<PageScript/>
<PageScript text={loadText} />
</>
: <Empty showBack onRefresh={() => getData(1)} name='暂无数据'/>
}

@ -5,27 +5,55 @@ import Empty from "@/components/empty/empty";
import {ScrollView, View} from "@tarojs/components";
import styles from "../sort.module.scss";
import Spin from "@/components/spinner";
import { illnessApi } from '@/api/illness'
interface Props {
category: Category
loading: boolean
onChange: (id?: number) => void
illness: Map<number, any[]>
secondId: number
}
const prefix = 'SORT'
const SecondLevel: FC<Props> = ({category, loading, onChange, illness}) => {
const SecondLevel: FC<Props> = ({category, loading,secondId,}) => {
const [loadings,setLoadings] = useState(loading || true)
const globalData = Taro.getApp().globalData
const [secondId, setSecondId] = useState<undefined | number>(undefined)
const [id, setId] = useState<number>(0)
const [illness, setIllness] = useState<Map<number, any[]>>(new Map)
useEffect(() => {
if (!secondId) {
setSecondId(category.resource_category?.[0]?.id)
}
onChange(secondId || category.resource_category?.[0]?.id)
}, [secondId])
setId(secondId)
}, [secondId]);
useEffect(() => {
changeSecond(id)
}, [id]);
function changeSecond(secondId?: number) {
if (secondId) {
setLoadings(true)
illnessApi.list(secondId, 1, 500).then(res => {
const data = new Map(illness)
if (data.has(secondId)) {
const newIllness = data.get(secondId)
data.delete(secondId)
data.set(secondId, res.list.reduce((pre, cur) => {
const index = pre.findIndex(d => d.id === cur.id)
if (index === -1) {
pre.push(cur)
} else {
pre.splice(index, 1, cur)
}
return pre
}, newIllness || []))
} else {
data.set(secondId, res.list)
}
setIllness(data)
setLoadings(false)
})
}
}
function jump(id: number) {
Taro.navigateTo({url: '/pages/preview/illness/list/list?id=' + id})
}
@ -40,8 +68,8 @@ const SecondLevel: FC<Props> = ({category, loading, onChange, illness}) => {
category.resource_category?.map(d => <View
id={`${prefix}-${d.id}`}
key={d.id}
onClick={() => setSecondId(d.id)}
className={secondId === d.id && styles.select}>
onClick={() => setId(d.id)}
className={id === d.id && styles.select}>
{d.name}
</View>)
}
@ -52,20 +80,25 @@ const SecondLevel: FC<Props> = ({category, loading, onChange, illness}) => {
scrollY
className={styles.tree}
scrollWithAnimation>
<Spin enable={loading} block/>
<Spin enable={loadings} block/>
{
(secondId && illness.get(secondId)?.length) ?
(secondId && illness.get(id)?.length) ?
<>
{
illness.get(secondId)?.map(d => <View
illness.get(id)?.map(d => <View
key={d.id}
className={styles.list}
onClick={() => jump(d.id)}>
{d.name}
</View>)
}
<View className='text-center font-24 text-dark mt-3'></View>
<View className='text-center font-24 text-dark mt-3 pb-2'></View>
</>
: <Empty name='暂无数据'/>
:
<>
{!loadings && <Empty name='暂无数据'/>}
</>
}
</ScrollView>
</View>

@ -3,7 +3,6 @@ import {FC, useMemo, useState} from "react";
import {Category, HomeApi} from "@/api";
import Taro from "@tarojs/taro";
import Tabs, {TabList} from "@/components/tabs/tabs";
import {illnessApi} from "@/api/illness";
import Empty from "@/components/empty/empty";
import Spin from "@/components/spinner";
import NavigationBar from "@/components/navigationBar/navigationBar";
@ -13,9 +12,10 @@ import SecondLevel from "./components/secondLevel";
const Sort: FC = () => {
const [data, setData] = useState<Category[]>([])
const [firstId, setFirstId] = useState<number | undefined>(undefined) // 一级选中
const [illness, setIllness] = useState<Map<number, any[]>>(new Map)
const [enable, setEnable] = useState(true)
const [loading, setLoading] = useState(false)
const [secondId,setSecondId] = useState<number>(0)
const globalData = Taro.getApp().globalData
async function getData() {
@ -24,6 +24,7 @@ const Sort: FC = () => {
setData(res)
if (res.length) {
setFirstId(res[0].id)
setSecondId(res[0].resource_category?.[0].id ?? 0)
}
} catch (e) {
setLoading(false)
@ -42,42 +43,18 @@ const Sort: FC = () => {
function firstIdChange(id: number) {
setFirstId(id)
const resource_category = data.find(d => d.id === id)?.resource_category
changeSecond(resource_category?.[0]?.id)
setSecondId(resource_category?.[0]?.id ?? 0)
}
Taro.useLoad(getData)
function changeSecond(secondId?: number) {
if (secondId) {
setLoading(true)
illnessApi.list(secondId, 1, 1000).then(res => {
const data = new Map(illness)
if (data.has(secondId)) {
const newIllness = data.get(secondId)
data.delete(secondId)
data.set(secondId, res.list.reduce((pre, cur) => {
const index = pre.findIndex(d => d.id === cur.id)
if (index === -1) {
pre.push(cur)
} else {
pre.splice(index, 1, cur)
}
return pre
}, newIllness || []))
} else {
data.set(secondId, res.list)
}
setIllness(data)
})
}
setLoading(false)
}
function swiperChange(e) {
const firstData = data[e.target.current]
if (!firstData) return;
setFirstId(firstData.id)
changeSecond(firstData?.resource_category?.[0]?.id)
setSecondId(firstData?.resource_category?.[0]?.id ?? 0)
}
@ -96,7 +73,7 @@ const Sort: FC = () => {
current={data.findIndex(d => d.id === firstId)}>
{
data.map(d => <SwiperItem key={d.id}>
<SecondLevel category={d} illness={illness} loading={loading} onChange={changeSecond}/>
<SecondLevel category={d} secondId={secondId} loading={loading} />
</SwiperItem>)
}
</Swiper>

@ -1,10 +1,15 @@
.container {
//.container {
// width: 100%;
// padding: 0 20rpx;
// box-sizing: border-box;
// columns: 2;
// column-gap: 20rpx;
// position: relative;
//}
.container{
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
columns: 2;
column-gap: 20rpx;
position: relative;
}
.height {

@ -6,8 +6,9 @@ import Empty from "@/components/empty/empty";
import Taro from "@tarojs/taro";
import styles from './profession.module.scss'
import Spin from "@/components/spinner";
import VideoList from "@/components/videoList/videoList";
// import VideoList from "@/components/videoList/videoList";
import PageScript from "@/components/pageScript/pageScript";
import WaterFull from '@/components/water-full/index'
interface KillData {
data: VideList[]
@ -21,6 +22,7 @@ const Profession = () => {
const [data, setData] = useState<Map<number, KillData>>(new Map)
const [enable, setEnable] = useState(true)
const [loading, setLoading] = useState(false)
const [loadText,setLoadText] = useState('加载中~')
/**
* more
@ -33,12 +35,16 @@ const Profession = () => {
/** 无更多 */
if (more && categoryData && categoryData.data.length >= categoryData.total) {
setLoadText("没有更多了")
return
}
try {
setLoading(true)
const res = await HomeApi.skillList(categoryId!, page, 10)
if(res.total < 10){
setLoadText("没有更多了")
}
const dataList = res.data.reduce((pre, cur) => {
const index = pre.findIndex(d => d.id === cur.id)
if (index === -1) {
@ -83,6 +89,7 @@ const Profession = () => {
function swiperChange(e) {
const categoryId = tabs[e.target.current].value
setCategoryId(Number(categoryId))
setLoadText("加载中~")
}
Taro.useLoad(getCategory)
@ -99,20 +106,19 @@ const Profession = () => {
onScrollToLower={() => getData(true)}
className={styles.height}>
<View className={styles.container}>
{
data.data.map(d => <VideoList data={d} errorType='profession'/>)
}
<WaterFull data={data.data}/>
{/*{*/}
{/* data.data.map(d => */}
{/* <VideoList data={d} errorType='profession'/>*/}
{/* )*/}
{/*}*/}
</View>
<PageScript/>
<PageScript text={loadText} />
</ScrollView>
)
}
if(!tabs.length){
return (
<Empty showBack onRefresh={getCategory} name='暂无数据'/>
)
}
return (
<>
@ -120,6 +126,10 @@ const Profession = () => {
<View className='bg-white'>
<Tabs tabList={tabs} onChange={tabsChange} current={categoryId!}/>
</View>
{
!tabs.length && !enable &&
<Empty showBack onRefresh={getCategory} name='暂无数据'/>
}
<Swiper
current={tabs.findIndex(d => d.value === categoryId)}

@ -2,19 +2,21 @@ page {
background: #000 !important;
min-height: 100vh;
}
.video {
.container{
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: calc(env(safe-area-inset-bottom) + 200rpx);
bottom: calc(env(safe-area-inset-bottom) + 100rpx);
margin: auto;
background: #000;
display: flex;
}
.video{
margin:auto;
}
.text {
position: fixed;
z-index: 20;
@ -32,7 +34,6 @@ page {
z-index: 10;
width: 100%;
color: #fff;
background: #000;
bottom: env(safe-area-inset-bottom);
padding: 0 50rpx;
box-sizing: border-box;
@ -45,8 +46,8 @@ page {
}
.img {
width: 48rpx;
height: 48rpx;
width: 35rpx;
height: 35rpx;
verticalAlign: middle;
margin-right: 15rpx;
}

@ -1,5 +1,5 @@
import {Video, View, Text, Image} from "@tarojs/components";
import {FC, useState} from "react";
import { View, Text, Image} from "@tarojs/components";
import React, {FC, useState} from "react";
import Taro from "@tarojs/taro";
import styles from './videoFull.module.scss'
import {brandApi, HomeApi} from "@/api";
@ -7,6 +7,8 @@ import Collect from "@/components/collect/collect";
import Spin from "@/components/spinner";
import VideoEvent from "@/hooks/videoEvent";
import palyWhite from '@/static/img/palyWhite.png'
import { getWfsInfo } from '@/utils/wfs'
import VideoPro from '@/components/videoPro'
interface Params {
id: string
@ -14,19 +16,62 @@ interface Params {
const VideoFull: FC = () => {
const {id} = Taro.useRouter().params as unknown as Params
const video = Taro.createVideoContext('myVideo')
const [palying, setpalying] = useState(false)
// const video = Taro.createVideoContext('myVideo')
// const [palying] = useState(false)
const [data, setData] = useState<VideList | null>(null)
const [enable, setEnable] = useState<boolean>(!Taro.getCurrentInstance().preloadData)
const [timing, setTiming] = useState<NodeJS.Timeout | undefined>(undefined)
const height: number = (data?.resource?.height ?? 1)/(data?.resource?.width ?? 1)*750
console.log(height,'height')
let VideoRef = React.createRef<any>()
Taro.useDidHide(() => {
console.log("页面隐藏",VideoRef.current.func)
// 视频被隐藏后自动暂停播放了,再打开自动继续播放了
// VideoRef.current.func()
})
Taro.useShareAppMessage((res) => {
if(res.from === 'button'){
}
return {
title:data?.title ?? '信桂',
path: `/pages/preview/videoFull/videoFull?id=${id}`
}
})
Taro.useShareTimeline(() => {
return {
title: '信桂'
}
})
Taro.useLoad(() => {
const preloadData: VideList = Taro.getCurrentInstance().preloadData as VideList
if (preloadData) {
setData(preloadData)
}
brandApi.videoInfo(id).then(res => {
brandApi.videoInfo(id).then( async res => {
if(res.resource_id){
await getWfsInfo(res.resource_id).then(resp => {
res.resource = { id: resp.id, name: resp.name, url: resp.object.path,thumb: resp.object.thumb,width:resp.object.width,height:resp.object.height }
}).catch(()=>{
})
// await Taro.request({
// url: `https://wfs.yaojiankang.top/files/${res.resource_id}`,
// success: function (resp) {
// if(resp.data.ok){
// res.resource = { id: 0, name: '', url: '' }
// res.resource.url = resp.data.data.object.path
// }
// }
// })
}
if (!res?.resource?.url) {
Taro.showModal({
title: '加载资源失败',
@ -67,49 +112,58 @@ const VideoFull: FC = () => {
clearTimeout(timing)
})
function click() {
if (palying) {
video.pause()
} else {
video.play()
}
}
// function click() {
// if (palying) {
// video.pause()
// } else {
// video.play()
// }
// }
function onError() {
Taro.showModal({
title: '视频播放错误',
confirmText: '退出',
showCancel: true,
success() {
Taro.navigateBack()
}
})
}
// function onError() {
// Taro.showModal({
// title: '视频播放错误',
// confirmText: '退出',
// showCancel: true,
// success() {
// Taro.navigateBack()
// }
// })
// }
return (
<View>
{
data ? <>
<Video
posterSize='100%'
id='myVideo'
onClick={click}
controls
autoplay
showBottomProgress='false'
className={styles.video}
src={data?.resource?.url}
showCenterPlayBtn
autoPauseIfOpenNative
autoPauseIfNavigate
playBtnPosition='center'
showFullscreenBtn={false}
enableProgressGesture={false}
onPlay={() => setpalying(true)}
onPause={() => setpalying(false)}
onError={onError}
/>
<View className={styles['container']}>
{
height != 750 && data?.resource?.url &&
<View style={{margin:'auto'}}>
<VideoPro onRef={VideoRef} src={data?.resource?.url} height={height} progress2bottom={true}></VideoPro>
</View>
// <Video
// style={{width:'750rpx',height:`${height}rpx`,}}
// objectFit={'fill'}
// id='myVideo'
// onClick={click}
// controls={false}
// autoplay={false}
// showBottomProgress='false'
// className={styles.video}
// src={data?.resource?.url}
// showCenterPlayBtn
// autoPauseIfOpenNative
// autoPauseIfNavigate
// playBtnPosition='center'
// showFullscreenBtn={false}
// enableProgressGesture={false}
// onPlay={() => setpalying(true)}
// onPause={() => setpalying(false)}
// onError={onError}
// onProgress={()=> video.play()}
// />
}
<View className={styles.text}>
<View className='font-32 font-weight'>{data.title}</View>
<View className='font-28 mt-2 text-ellipsis-2'>{data.introduction}</View>
@ -122,10 +176,10 @@ const VideoFull: FC = () => {
</View>
<Collect owner_id={Number(id)}
owner_type={2}
stylesImage={{width: '48rpx', height: '48rpx'}}
styles={{color: '#fff', width: 'auto'}}
styles={{color: '#fff'}}
select={data.collects}/>
</View>
</View>
</> : <Spin enable={enable} overlay/>
}

@ -0,0 +1,53 @@
import Taro from '@tarojs/taro'
/** 文件基本信息 */
interface CloudFile {
id: number;
objectId: number;
directoryId: number;
appId: number;
name: string;
object: CloudObject;
createdBy: number;
createdAt: string;
updatedAt: string;
}
/** 文件对象信息 */
interface CloudObject {
id: number;
hash: string;
size: number;
path: string;
thumb: string;
mime: string;
width: number;
height: number;
duration: number;
createdAt: string;
updatedAt: string;
}
const files: Record<number, CloudFile> = Object.create(null)
export function getWfsInfo(id: number):Promise<CloudFile>{
if (Reflect.has(files, id)) {
return Promise.resolve(files[id])
}
return new Promise((resolve, reject) => {
Taro.request({
url: `https://wfs.yaojiankang.top/files/${id}`,
success(res) {
if (res.data.ok) {
files[id] = res.data.data
resolve(res.data.data)
} else {
reject(res.data.msg)
}
},
fail(err) {
reject(err.errMsg)
}
})
})
}

6
types/home.d.ts vendored

@ -4,12 +4,15 @@ interface VideList {
introduction: string
url_path: string
resource: Resource
resource_id: number
/** 播放量 */
video_view: number
publish_time:string
collects:boolean
duration:number
collect_quantity:number
video_height?:number
video_width?:number
}
interface Brand {
@ -25,6 +28,9 @@ interface Resource {
id: number
name: string
url: string
thumb: string
width?: number
height?: number
}
// interface Kill {

Loading…
Cancel
Save