💄 update video item active
This commit is contained in:
parent
950bc59847
commit
2525358eb9
@ -105,12 +105,30 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-live{
|
||||
.live-player{
|
||||
max-height: calc(100vh - var(--app-header-header) - 130px);
|
||||
overflow: hidden;
|
||||
iframe{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
.video-item-shadow {
|
||||
box-shadow: 0 0 6px 0 var(--tw-shadow-color);
|
||||
//filter: drop-shadow(0 0 6px var(--tw-shadow-color));
|
||||
}
|
||||
.video-list-sort-container{
|
||||
height: calc(100vh - var(--app-header-header) - 300px);
|
||||
min-height: 300px;
|
||||
max-height: calc(100vh - var(--app-header-header) - 300px);
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.live-video-list-sort-container{
|
||||
min-height: 300px;
|
||||
padding-right: 10px;
|
||||
max-height: calc(100vh - var(--app-header-header) - 200px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ type Props = {
|
||||
onEdit?: () => void;
|
||||
onRemove?: () => void;
|
||||
id: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const VideoListItem = (
|
||||
@ -27,6 +28,7 @@ export const VideoListItem = (
|
||||
// index,
|
||||
id, video, onPlay, onRemove, checked,
|
||||
onCheckedChange, onEdit, active, editable,
|
||||
className,
|
||||
}: Props) => {
|
||||
const {
|
||||
attributes, listeners,
|
||||
@ -40,7 +42,7 @@ export const VideoListItem = (
|
||||
}, [checked])
|
||||
|
||||
return <div
|
||||
className={'video-item flex items-center gap-3 mb-5'}
|
||||
className={`video-item flex items-center gap-3 ${className}`}
|
||||
ref={setNodeRef} style={{transform: `translateY(${transform?.y || 0}px)`,}}>
|
||||
{/*{index && index > 0 && <div className="flex items-center px-2">*/}
|
||||
{/* <div className="index-value w-[40px] h-[40px] flex items-center justify-center bg-gray-100 rounded-3xl">{index}</div>*/}
|
||||
|
@ -4,9 +4,11 @@ import {SortableContext, arrayMove} from '@dnd-kit/sortable';
|
||||
import {DndContext} from "@dnd-kit/core";
|
||||
|
||||
import {VideoListItem} from "@/components/video/video-list-item.tsx";
|
||||
import {getList} from "@/service/api/live.ts";
|
||||
import {getList, playState} from "@/service/api/live.ts";
|
||||
|
||||
import styles from './style.module.scss'
|
||||
import {set} from "lodash";
|
||||
import {showToast} from "@/components/message.ts";
|
||||
|
||||
export default function LiveIndex() {
|
||||
const [videoData, setVideoData] = useState<LiveVideoInfo[]>([])
|
||||
@ -15,14 +17,55 @@ export default function LiveIndex() {
|
||||
const [editable, setEditable] = useState<boolean>(false)
|
||||
|
||||
const [state, setState] = useState({
|
||||
activeId: -1,
|
||||
activeIndex: -1,
|
||||
})
|
||||
|
||||
const showVideoItem = (index: number) => {
|
||||
// 找到对应video item 并显示在视图可见区域
|
||||
const container = document.querySelector('.live-video-list-sort-container')
|
||||
const item = document.querySelector(`.list-item-${index}`)
|
||||
if (item && container) {
|
||||
// 获取容器数据
|
||||
const containerRect = container.getBoundingClientRect()
|
||||
// 获取对应item的数据
|
||||
const rect = item.getBoundingClientRect()
|
||||
// 计算对应item需要在容器中滚动的距离
|
||||
const scrollDistance = rect.top - containerRect.top
|
||||
// 设置滚动高度
|
||||
container.scrollTo({
|
||||
top: index == 0 ? 0 : container.scrollTop + scrollDistance - 10,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
}
|
||||
const activeToNext = () => {
|
||||
const endToFirst = state.activeIndex >= videoData.length - 1
|
||||
const activeIndex = endToFirst ? 0 : state.activeIndex + 1
|
||||
setState(() => {
|
||||
return {
|
||||
activeIndex
|
||||
}
|
||||
})
|
||||
if (endToFirst) {
|
||||
showToast('即将播放第一条视频');
|
||||
}
|
||||
// 找到对应video item 并显示在视图可见区域
|
||||
showVideoItem(activeIndex)
|
||||
}
|
||||
const initPlayingState = (videoList?: LiveVideoInfo[] | null) => {
|
||||
const list = videoList || videoData || []
|
||||
playState().then(ret => {
|
||||
setState({
|
||||
activeIndex: 0 //list.findIndex(v => v.id === ret.id)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getList().then(res => {
|
||||
setVideoData([
|
||||
res.list = [
|
||||
{
|
||||
id: 1,
|
||||
id: 11,
|
||||
video_id: 1,
|
||||
video_title: '333专家分析丨叙土边境曼比季地理位置为何如此重要?',
|
||||
cover_url: 'https://gachafun.oss-cn-beijing.aliyuncs.com/2021/08/13/1628840269744.jpg',
|
||||
@ -32,7 +75,7 @@ export default function LiveIndex() {
|
||||
order_no: '1'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
id: 0,
|
||||
video_id: 1,
|
||||
video_title: '333专家分析丨叙土边境曼比季地理位置为何如此重要?',
|
||||
cover_url: 'https://gachafun.oss-cn-beijing.aliyuncs.com/2021/08/13/1628840269744.jpg',
|
||||
@ -42,7 +85,7 @@ export default function LiveIndex() {
|
||||
order_no: '1'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
id: 10,
|
||||
video_id: 1,
|
||||
video_title: '333专家分析丨叙土边境曼比季地理位置为何如此重要?',
|
||||
cover_url: 'https://gachafun.oss-cn-beijing.aliyuncs.com/2021/08/13/1628840269744.jpg',
|
||||
@ -91,7 +134,10 @@ export default function LiveIndex() {
|
||||
status: 1,
|
||||
order_no: '1'
|
||||
}
|
||||
])
|
||||
|
||||
]
|
||||
setVideoData(res.list || [])
|
||||
initPlayingState(res.list || [])
|
||||
})
|
||||
}, [])
|
||||
const processDeleteVideo = async (_idArray: number[]) => {
|
||||
@ -109,26 +155,25 @@ export default function LiveIndex() {
|
||||
title: '提示',
|
||||
content: '是否采纳全部编辑操作?',
|
||||
onOk: () => {
|
||||
message.info('编辑成功!!!');
|
||||
showToast('编辑成功!!!', 'info');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return (<div className="container py-10 page-live">
|
||||
{contextHolder}
|
||||
<div className="flex">
|
||||
<div className="video-player-container mr-8 flex flex-col">
|
||||
<div className="text-center text-base">数字人直播间</div>
|
||||
<div className="video-player flex justify-center flex-1 mt-5">
|
||||
<div className=" rounded overflow-hidden w-[360px] h-[700px]">
|
||||
<iframe src="https://fm.gachafun.com/" className="border-0 w-full h-full max-h-full"></iframe>
|
||||
<div className="live-player rounded overflow-hidden w-[360px] h-[700px]">
|
||||
{/*<iframe src="https://fm.gachafun.com/" className="border-0 w-full h-full max-h-full"></iframe>*/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="video-list-container flex-1 ">
|
||||
<div className=" bg-white py-8 px-6 rounded py-1">
|
||||
<div className="live-control flex justify-between mb-8">
|
||||
<div className="video-list-container flex-1">
|
||||
<div className=" bg-white py-8 px-6 rounded">
|
||||
<div className="live-control flex justify-between mb-4">
|
||||
{editable ? <>
|
||||
<div className="flex gap-2">
|
||||
<Button type="primary" onClick={handleConfirm}>确定</Button>
|
||||
@ -140,48 +185,66 @@ export default function LiveIndex() {
|
||||
</> : <div>
|
||||
<Button type="primary" onClick={() => setEditable(true)}>编辑</Button>
|
||||
</div>}
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button type="primary" onClick={showFirst}>showFirst</Button>
|
||||
<Button type="primary" onClick={activeToNext}>Next</Button>
|
||||
</div>
|
||||
</div>
|
||||
<DndContext onDragEnd={(e) => {
|
||||
const {active, over} = e;
|
||||
if (over && active.id !== over.id) {
|
||||
let oldIndex = -1, newIndex = -1;
|
||||
const originArr = [...videoData]
|
||||
setVideoData((items) => {
|
||||
oldIndex = items.findIndex(s => s.id == active.id);
|
||||
newIndex = items.findIndex(s => s.id == over.id);
|
||||
return arrayMove(items, oldIndex, newIndex);
|
||||
});
|
||||
modal.confirm({
|
||||
title: '提示',
|
||||
content: '是否要移动到指定位置',
|
||||
onCancel: () => {
|
||||
setVideoData(originArr);
|
||||
},
|
||||
onOk: () => {
|
||||
setVideoData([...videoData])
|
||||
}
|
||||
})
|
||||
}
|
||||
}}>
|
||||
<SortableContext items={videoData}>
|
||||
{videoData.map((v, index) => (
|
||||
<VideoListItem
|
||||
video={v}
|
||||
index={index + 1}
|
||||
id={v.id}
|
||||
active={state.activeId == v.id}
|
||||
key={index}
|
||||
onCheckedChange={(checked) => {
|
||||
setCheckedIdArray(idArray => {
|
||||
return checked ? idArray.concat(v.id) : idArray.filter(id => id != v.id);
|
||||
<div className="live-video-list-sort-container">
|
||||
<div className="flex">
|
||||
<div className="sort-number-container mr-2">
|
||||
{videoData.map((v, index) => (
|
||||
<div key={index} className="flex items-center px-2 h-[80px] mt-3 mb-2">
|
||||
<div
|
||||
className="index-value w-[40px] h-[40px] flex items-center justify-center bg-gray-100 rounded-3xl">{index + 1}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="sort-list-container flex-1">
|
||||
<DndContext onDragEnd={(e) => {
|
||||
const {active, over} = e;
|
||||
if (over && active.id !== over.id) {
|
||||
let oldIndex = -1, newIndex = -1;
|
||||
const originArr = [...videoData]
|
||||
setVideoData((items) => {
|
||||
oldIndex = items.findIndex(s => s.id == active.id);
|
||||
newIndex = items.findIndex(s => s.id == over.id);
|
||||
return arrayMove(items, oldIndex, newIndex);
|
||||
});
|
||||
modal.confirm({
|
||||
title: '提示',
|
||||
content: '是否要移动到指定位置',
|
||||
onCancel: () => {
|
||||
setVideoData(originArr);
|
||||
},
|
||||
onOk: () => {
|
||||
setVideoData([...videoData])
|
||||
}
|
||||
})
|
||||
}}
|
||||
onRemove={() => processDeleteVideo([v.id])}
|
||||
editable={editable}
|
||||
/>))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
}
|
||||
}}>
|
||||
<SortableContext items={videoData}>
|
||||
{videoData.map((v, index) => (
|
||||
<VideoListItem
|
||||
video={v}
|
||||
index={index + 1}
|
||||
id={v.id}
|
||||
active={state.activeIndex == index}
|
||||
key={index}
|
||||
className={`list-item-${index} mt-3 mb-2`}
|
||||
onCheckedChange={(checked) => {
|
||||
setCheckedIdArray(idArray => {
|
||||
return checked ? idArray.concat(v.id) : idArray.filter(id => id != v.id);
|
||||
})
|
||||
}}
|
||||
onRemove={() => processDeleteVideo([v.id])}
|
||||
editable={editable}
|
||||
/>))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {message, Modal} from "antd";
|
||||
import {Empty, message, Modal} from "antd";
|
||||
import React, {useEffect, useMemo, useRef, useState} from "react";
|
||||
import {DndContext} from "@dnd-kit/core";
|
||||
import {arrayMove, SortableContext} from "@dnd-kit/sortable";
|
||||
@ -43,7 +43,7 @@ export default function VideoIndex() {
|
||||
})
|
||||
}
|
||||
|
||||
const playVideo = (video: VideoInfo,playingIndex:number) => {
|
||||
const playVideo = (video: VideoInfo, playingIndex: number) => {
|
||||
setState({
|
||||
playingIndex
|
||||
})
|
||||
@ -88,58 +88,61 @@ export default function VideoIndex() {
|
||||
</div>
|
||||
</div>
|
||||
<div className={'flex video-list-sort-container'}>
|
||||
<div className="sort-number-container mr-2">
|
||||
{videoData.map((v, index) => (
|
||||
<div className="flex items-center px-2 h-[80px] mb-5">
|
||||
<div className="index-value w-[40px] h-[40px] flex items-center justify-center bg-gray-100 rounded-3xl">{index}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="sort-list-container">
|
||||
<DndContext onDragEnd={(e) => {
|
||||
const {active, over} = e;
|
||||
if (over && active.id !== over.id) {
|
||||
let oldIndex = -1, newIndex = -1;
|
||||
const originArr = [...videoData]
|
||||
setVideoData((items) => {
|
||||
oldIndex = items.findIndex(s => s.id == active.id);
|
||||
newIndex = items.findIndex(s => s.id == over.id);
|
||||
return arrayMove(items, oldIndex, newIndex);
|
||||
});
|
||||
modal.confirm({
|
||||
title: '提示',
|
||||
content: '是否要移动到指定位置',
|
||||
onCancel: () => {
|
||||
setVideoData(originArr);
|
||||
}
|
||||
})
|
||||
}
|
||||
}}>
|
||||
<SortableContext items={videoData}>
|
||||
{videoData.map((v, index) => (
|
||||
<VideoListItem
|
||||
video={v}
|
||||
index={index + 1}
|
||||
id={v.id}
|
||||
key={index}
|
||||
active={state.playingIndex == index}
|
||||
checked={checkedIdArray.includes(v.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
setCheckedIdArray(idArray => {
|
||||
const newArr = checked ? idArray.concat(v.id) : idArray.filter(id => id != v.id);
|
||||
setState({checkedAll: newArr.length == videoData.length})
|
||||
return newArr;
|
||||
})
|
||||
}}
|
||||
onPlay={() => playVideo(v,index)}
|
||||
onEdit={() => {
|
||||
setEditId(v.article_id)
|
||||
}}
|
||||
editable
|
||||
/>))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
{videoData.length == 0 ? <div className="m-auto"><Empty/></div> : <>
|
||||
<div className="sort-number-container mr-2">
|
||||
{videoData.map((v, index) => (
|
||||
<div key={index} className="flex items-center px-2 h-[80px] mb-5">
|
||||
<div
|
||||
className="index-value w-[40px] h-[40px] flex items-center justify-center bg-gray-100 rounded-3xl">{index + 1}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="sort-list-container">
|
||||
<DndContext onDragEnd={(e) => {
|
||||
const {active, over} = e;
|
||||
if (over && active.id !== over.id) {
|
||||
let oldIndex = -1, newIndex = -1;
|
||||
const originArr = [...videoData]
|
||||
setVideoData((items) => {
|
||||
oldIndex = items.findIndex(s => s.id == active.id);
|
||||
newIndex = items.findIndex(s => s.id == over.id);
|
||||
return arrayMove(items, oldIndex, newIndex);
|
||||
});
|
||||
modal.confirm({
|
||||
title: '提示',
|
||||
content: '是否要移动到指定位置',
|
||||
onCancel: () => {
|
||||
setVideoData(originArr);
|
||||
}
|
||||
})
|
||||
}
|
||||
}}>
|
||||
<SortableContext items={videoData}>
|
||||
{videoData.map((v, index) => (
|
||||
<VideoListItem
|
||||
video={v}
|
||||
index={index + 1}
|
||||
id={v.id}
|
||||
key={index}
|
||||
active={state.playingIndex == index}
|
||||
checked={checkedIdArray.includes(v.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
setCheckedIdArray(idArray => {
|
||||
const newArr = checked ? idArray.concat(v.id) : idArray.filter(id => id != v.id);
|
||||
setState({checkedAll: newArr.length == videoData.length})
|
||||
return newArr;
|
||||
})
|
||||
}}
|
||||
onPlay={() => playVideo(v, index)}
|
||||
onEdit={() => {
|
||||
setEditId(v.article_id)
|
||||
}}
|
||||
editable
|
||||
/>))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
<div className="text-right mt-10">
|
||||
<ButtonPush2Room ids={checkedIdArray}/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user