Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yaoai-video
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
姚珂
yaoai-video
Commits
ac99d10f
Commit
ac99d10f
authored
May 23, 2026
by
黄同智
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
实现拖拽功能
parent
c03e0d22
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
35 additions
and
294 deletions
+35
-294
progress.svg
doc/h5/src/static/imgs/progress.svg
+0
-2
Episode.vue
doc/h5/src/views/project/components/Episode.vue
+35
-12
StepFour copy 2.vue
doc/h5/src/views/project/components/StepFour copy 2.vue
+0
-263
StepFour copy.vue
doc/h5/src/views/project/components/StepFour copy.vue
+0
-0
StepThree.vue
doc/h5/src/views/project/components/StepThree.vue
+0
-17
No files found.
doc/h5/src/static/imgs/progress.svg
deleted
100644 → 0
View file @
c03e0d22
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"12"
height=
"208"
fill=
"none"
viewBox=
"0 0 12 208"
><path
fill=
"#000"
d=
"M1 0h10v10.951a2 2 0 0 1-.731 1.547l-3 2.461a2 2 0 0 1-2.538 0l-3-2.461A2 2 0 0 1 1 10.95z"
/><path
stroke=
"#000"
d=
"M6 13v204"
/></svg>
\ No newline at end of file
doc/h5/src/views/project/components/Episode.vue
View file @
ac99d10f
<
template
>
<
template
>
<draggable
v-model=
"list"
item-key=
"id"
class=
"list-group"
@
end=
"onDragEnd"
handle=
".tuoz"
>
<template
#
item=
"
{ element, index }">
<section
class=
"box rounded-16 p-10 my-10"
style=
"min-width: 1110px;"
>
<section
class=
"box rounded-16 p-10 my-10"
style=
"min-width: 1110px;"
>
<div
class=
"flex-align-center justify-between"
>
<div
class=
"flex-align-center justify-between"
>
<div
class=
"flex-align-center gap-4"
>
<div
class=
"flex-align-center gap-4"
>
<div
class=
"tuoz flex-align-center"
id=
"anzhu"
>
<div
class=
"relative"
>
<div
class=
"tuoz flex-align-center"
id=
"anzhu"
@
mousedown=
"isHidden = true"
@
mouseup=
"isHidden = false"
@
mouseleave=
"isHidden = false"
>
<img
src=
"@/static/imgs/tuoz.png"
alt=
""
class=
"h-16"
>
<img
src=
"@/static/imgs/tuoz.png"
alt=
""
class=
"h-16"
>
</div>
</div>
<span
class=
"fs-12"
>
分镜1
</span>
</div>
<span
class=
"fs-12"
>
分镜
{{
index
+
1
}}
</span>
<span
class=
"fs-10 py-2 px-4 rounded-4 bg-e3e9ff"
>
ID
</span>
<span
class=
"fs-10 py-2 px-4 rounded-4 bg-e3e9ff"
>
ID
</span>
<div
class=
"flex-align-center ml-10 bg-f4f6ff py-6 px-14 rounded-8 btnsborder gap-4"
>
<div
class=
"flex-align-center ml-10 bg-f4f6ff py-6 px-14 rounded-8 btnsborder gap-4"
>
<el-icon
color=
"#5252ff"
size=
"14"
>
<el-icon
color=
"#5252ff"
size=
"14"
>
...
@@ -20,7 +25,7 @@
...
@@ -20,7 +25,7 @@
<el-button
text
:icon=
"Delete"
circle
/>
<el-button
text
:icon=
"Delete"
circle
/>
</div>
</div>
</div>
</div>
<div
class=
"flex gap-10 h-b100 content
"
>
<div
class=
"flex gap-10 h-b100"
:style=
"
{ display: isHidden ? 'none' : 'flex' }
">
<section
class=
"w-400 p-14 bg-fff rounded-16 mt-10"
>
<section
class=
"w-400 p-14 bg-fff rounded-16 mt-10"
>
<div>
分镜信息
</div>
<div>
分镜信息
</div>
<div
class=
"h-548 hide-scrollbar"
>
<div
class=
"h-548 hide-scrollbar"
>
...
@@ -110,7 +115,8 @@
...
@@ -110,7 +115,8 @@
</el-upload>
</el-upload>
</div>
</div>
<div
class=
"flex-1 overflow-y-auto my-8 hide-scrollbar"
style=
"max-height: 412px"
>
<div
class=
"flex-1 overflow-y-auto my-8 hide-scrollbar"
style=
"max-height: 412px"
>
<div
contenteditable=
"true"
class=
"bg-f5 p-10 text-333 rounded-8 custom"
style=
"min-height: 412px"
></div>
<div
contenteditable=
"true"
class=
"bg-f5 p-10 text-333 rounded-8 custom"
style=
"min-height: 412px"
>
</div>
</div>
</div>
<div
class=
""
>
<div
class=
""
>
<div
v-if=
"isShowtip"
class=
"hint flex-between-center px-10"
>
<div
v-if=
"isShowtip"
class=
"hint flex-between-center px-10"
>
...
@@ -131,8 +137,7 @@
...
@@ -131,8 +137,7 @@
<el-select
v-model=
"secondVal"
placeholder=
"Select"
style=
"width: 80px;"
>
<el-select
v-model=
"secondVal"
placeholder=
"Select"
style=
"width: 80px;"
>
<el-option
v-for=
"item in options2"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
<el-option
v-for=
"item in options2"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-select>
<el-button
size=
"small"
class=
"h-32 rounded-8"
<el-button
size=
"small"
class=
"h-32 rounded-8"
@
click=
"isShowtip = false"
>
@
</el-button>
@
click=
"isShowtip = false"
>
@
</el-button>
</div>
</div>
<div
class=
"flex-align-center h-32 px-10 rounded-4 jinbi"
>
<div
class=
"flex-align-center h-32 px-10 rounded-4 jinbi"
>
<svg
t=
"1779335788481"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
<svg
t=
"1779335788481"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
...
@@ -160,16 +165,20 @@
...
@@ -160,16 +165,20 @@
</section>
</section>
</div>
</div>
</section>
</section>
</
template
>
</draggable>
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
;
import
{
ref
}
from
'vue'
;
import
{
Plus
,
DocumentCopy
,
CopyDocument
,
CircleCloseFilled
,
MoreFilled
,
Delete
,
HelpFilled
,
Warning
}
from
'@element-plus/icons-vue'
import
{
Plus
,
DocumentCopy
,
CopyDocument
,
CircleCloseFilled
,
MoreFilled
,
Delete
,
HelpFilled
,
Warning
}
from
'@element-plus/icons-vue'
import
Empty
from
'./Empty.vue'
;
import
Empty
from
'./Empty.vue'
;
import
draggable
from
'vuedraggable'
const
fenjDesc
=
ref
(
''
)
const
fenjDesc
=
ref
(
''
)
const
aiTypeVal
=
ref
(
'1'
)
const
aiTypeVal
=
ref
(
'1'
)
const
isShowtip
=
ref
(
true
)
const
isShowtip
=
ref
(
true
)
const
secondVal
=
ref
(
5
)
const
secondVal
=
ref
(
5
)
const
isHidden
=
ref
(
false
)
const
options
=
[
const
options
=
[
{
{
...
@@ -257,6 +266,17 @@ const videoIndex = ref(0)
...
@@ -257,6 +266,17 @@ const videoIndex = ref(0)
const
changeVideo
=
(
item
:
any
,
index
:
number
)
=>
{
const
changeVideo
=
(
item
:
any
,
index
:
number
)
=>
{
videoIndex
.
value
=
index
videoIndex
.
value
=
index
}
}
const
list
=
ref
([
{
id
:
1
,
name
:
'第1集 凌晨的咖啡与雨'
,
time
:
'00:00:00'
},
{
id
:
2
,
name
:
'第2集 早餐的阳光与微笑'
,
time
:
'00:00:00'
},
{
id
:
3
,
name
:
'第3集 午餐的温暖与关怀'
,
time
:
'00:00:00'
},
])
const
onDragEnd
=
(
evt
:
any
)
=>
{
console
.
log
(
'拖拽结束'
,
list
.
value
)
}
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.box
{
.box
{
...
@@ -340,20 +360,22 @@ const changeVideo = (item: any, index: number) => {
...
@@ -340,20 +360,22 @@ const changeVideo = (item: any, index: number) => {
background-color
:
#4747e7
;
background-color
:
#4747e7
;
}
}
}
}
.custom
{
.custom
{
outline
:
none
;
outline
:
none
;
box-shadow
:
none
;
box-shadow
:
none
;
border-color
:
transparent
;
border-color
:
transparent
;
}
}
.tuoz
{
.tuoz
{
cursor
:
all-scroll
;
cursor
:
all-scroll
;
}
}
.content
{
// .content1
{
display
:
block
;
// // display: inline-
block;
}
//
}
#anzhu
:active
~
.content
{
// section.box:has(#anzhu:active) .content1
{
display
:
none
;
// display: none !important
;
}
//
}
</
style
>
</
style
>
\ No newline at end of file
doc/h5/src/views/project/components/StepFour copy 2.vue
deleted
100644 → 0
View file @
c03e0d22
<
template
>
<div
class=
"video-wrapper"
@
mouseenter=
"showControls = true"
@
mouseleave=
"showControls = false"
>
<!-- 1. 视频本体 (隐藏自带控件) -->
<video
ref=
"videoRef"
src=
"https://www.w3schools.com/html/mov_bbb.mp4"
@
timeupdate=
"handleTimeUpdate"
@
loadedmetadata=
"handleLoadedMetadata"
@
ended=
"handleEnded"
></video>
<!-- 2. 自定义控制层 (只在悬停时显示) -->
<div
class=
"custom-controls"
:class=
"
{ 'visible': showControls || isPlaying }">
<!-- 底部区域:包含时间和进度条 -->
<div
class=
"control-bottom"
>
<!-- 时间显示 (左) -->
<div
class=
"time-display"
>
{{
formatTime
(
currentTime
)
}}
/
{{
formatTime
(
duration
)
}}
</div>
<!-- 进度条轨道 (中) -->
<div
class=
"progress-track"
ref=
"progressTrack"
@
click=
"seekVideo"
@
mousemove=
"handleHoverMove"
@
mouseleave=
"hoverTime = null"
>
<!-- 进度填充条 -->
<div
class=
"progress-fill"
:style=
"
{ width: progressPercentage + '%' }">
</div>
<!-- 拖动滑块 (圆点) -->
<div
class=
"progress-thumb"
:style=
"
{ left: progressPercentage + '%' }">
</div>
<!-- 悬停预览气泡 (Tooltip) -->
<div
class=
"hover-tooltip"
v-if=
"hoverTime !== null"
:style=
"
{ left: hoverPercent + '%' }"
>
{{
formatTime
(
hoverTime
)
}}
</div>
</div>
<!-- 播放/暂停按钮 (右) -->
<button
class=
"play-btn"
@
click=
"togglePlay"
>
{{
isPlaying
?
'⏸'
:
'▶'
}}
</button>
</div>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
computed
,
onMounted
,
onUnmounted
}
from
'vue'
// ----- 状态 -----
const
videoRef
=
ref
(
null
)
const
isPlaying
=
ref
(
false
)
const
currentTime
=
ref
(
0
)
const
duration
=
ref
(
0
)
const
showControls
=
ref
(
false
)
// 悬停状态
const
hoverTime
=
ref
(
null
)
// 悬停时的秒数
const
hoverPercent
=
ref
(
0
)
// 悬停时的百分比
// ----- 计算属性 -----
const
progressPercentage
=
computed
(()
=>
{
if
(
duration
.
value
===
0
)
return
0
return
(
currentTime
.
value
/
duration
.
value
)
*
100
})
// ----- 核心逻辑 -----
// 1. 格式化时间 (00:00)
const
formatTime
=
(
seconds
)
=>
{
if
(
!
seconds
&&
seconds
!==
0
)
return
'00:00'
const
m
=
Math
.
floor
(
seconds
/
60
)
const
s
=
Math
.
floor
(
seconds
%
60
)
return
`
${
m
.
toString
().
padStart
(
2
,
'0'
)}
:
${
s
.
toString
().
padStart
(
2
,
'0'
)}
`
}
// 2. 视频加载完成,获取总时长
const
handleLoadedMetadata
=
()
=>
{
if
(
videoRef
.
value
)
duration
.
value
=
videoRef
.
value
.
duration
}
// 3. 播放过程中更新进度
const
handleTimeUpdate
=
()
=>
{
if
(
videoRef
.
value
)
currentTime
.
value
=
videoRef
.
value
.
currentTime
}
// 4. 播放结束重置
const
handleEnded
=
()
=>
{
isPlaying
.
value
=
false
}
// 5. 切换播放/暂停
const
togglePlay
=
()
=>
{
if
(
!
videoRef
.
value
)
return
if
(
videoRef
.
value
.
paused
)
{
videoRef
.
value
.
play
()
isPlaying
.
value
=
true
}
else
{
videoRef
.
value
.
pause
()
isPlaying
.
value
=
false
}
}
// 6. 点击进度条跳转
const
seekVideo
=
(
event
)
=>
{
const
track
=
event
.
currentTarget
const
rect
=
track
.
getBoundingClientRect
()
const
x
=
event
.
clientX
-
rect
.
left
const
percent
=
Math
.
min
(
100
,
Math
.
max
(
0
,
(
x
/
rect
.
width
)
*
100
))
if
(
duration
.
value
>
0
)
{
const
newTime
=
(
percent
/
100
)
*
duration
.
value
videoRef
.
value
.
currentTime
=
newTime
currentTime
.
value
=
newTime
}
}
// 7. 鼠标悬停计算位置和时间
const
handleHoverMove
=
(
event
)
=>
{
const
track
=
event
.
currentTarget
const
rect
=
track
.
getBoundingClientRect
()
const
x
=
event
.
clientX
-
rect
.
left
const
percent
=
Math
.
min
(
100
,
Math
.
max
(
0
,
(
x
/
rect
.
width
)
*
100
))
hoverPercent
.
value
=
percent
if
(
duration
.
value
>
0
)
{
hoverTime
.
value
=
(
percent
/
100
)
*
duration
.
value
}
}
</
script
>
<
style
scoped
>
/* 容器 */
.video-wrapper
{
position
:
relative
;
width
:
100%
;
max-width
:
800px
;
background
:
#000
;
aspect-ratio
:
16
/
9
;
/* overflow: hidden; */
border-radius
:
8px
;
}
video
{
width
:
100%
;
height
:
100%
;
display
:
block
;
object-fit
:
cover
;
}
/* 控制层 (初始透明,悬停显示) */
.custom-controls
{
/* position: absolute;
bottom: 0;
left: 0;
right: 0; */
padding
:
20px
;
background
:
linear-gradient
(
to
top
,
rgba
(
0
,
0
,
0
,
0.7
),
transparent
);
/* opacity: 0; */
transition
:
opacity
0.3s
ease
;
pointer-events
:
none
;
/* 鼠标穿透 */
}
.custom-controls.visible
{
opacity
:
1
;
pointer-events
:
auto
;
}
/* 底部布局 */
.control-bottom
{
display
:
flex
;
align-items
:
center
;
gap
:
15px
;
}
/* 时间文本 */
.time-display
{
color
:
rgba
(
255
,
255
,
255
,
0.9
);
font-size
:
13px
;
font-family
:
-apple-system
,
BlinkMacSystemFont
,
"Segoe UI"
,
Roboto
,
sans-serif
;
min-width
:
70px
;
}
/* 进度条轨道 */
.progress-track
{
flex-grow
:
1
;
height
:
6px
;
/* 更细的轨道 */
background
:
rgba
(
1
,
255
,
56
,
0.3
);
/* 半透明灰 */
border-radius
:
4px
;
position
:
relative
;
cursor
:
pointer
;
height
:
100px
;
}
/* 填充条 */
.progress-fill
{
height
:
100%
;
background
:
#ff0000
;
/* 纯白填充 */
border-radius
:
4px
;
width
:
0%
;
transition
:
width
0.1s
linear
;
}
/* 滑块 (圆点) - 核心视觉 */
.progress-thumb
{
position
:
absolute
;
top
:
50%
;
width
:
12px
;
height
:
12px
;
background
:
#fff
;
border-radius
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
box-shadow
:
0
0
6px
rgba
(
0
,
0
,
0
,
0.5
);
opacity
:
0
;
transition
:
opacity
0.2s
;
}
/* 悬停或播放时显示圆点 */
.progress-track
:hover
.progress-thumb
,
.custom-controls.visible
.progress-thumb
{
opacity
:
1
;
}
/* 悬停气泡 (Tooltip) */
.hover-tooltip
{
position
:
absolute
;
bottom
:
25px
;
transform
:
translateX
(
-50%
);
background
:
rgba
(
0
,
0
,
0
,
0.75
);
color
:
#fff
;
padding
:
2px
8px
;
border-radius
:
4px
;
font-size
:
12px
;
font-family
:
sans-serif
;
pointer-events
:
none
;
}
/* 播放按钮 */
.play-btn
{
background
:
none
;
border
:
none
;
color
:
#fff
;
font-size
:
20px
;
cursor
:
pointer
;
padding
:
5px
;
transition
:
transform
0.2s
;
}
.play-btn
:hover
{
transform
:
scale
(
1.1
);
}
</
style
>
\ No newline at end of file
doc/h5/src/views/project/components/StepFour copy.vue
deleted
100644 → 0
View file @
c03e0d22
This diff is collapsed.
Click to expand it.
doc/h5/src/views/project/components/StepThree.vue
View file @
ac99d10f
...
@@ -34,15 +34,8 @@
...
@@ -34,15 +34,8 @@
</div>
</div>
</el-popover>
</el-popover>
</div>
</div>
<div
v-for=
"(item, index) in 1"
:key=
"index"
class=
"pb-20"
>
<Episode
/>
<Episode
/>
</div>
</div>
<!-- <draggable v-model="list" item-key="id" class="list-group" @end="onDragEnd" handle=".tuoz">
<template #item="{ element, index }">
<Episode />
</template>
</draggable> -->
</div>
</section>
</section>
</section>
</section>
</template>
</template>
...
@@ -50,7 +43,6 @@
...
@@ -50,7 +43,6 @@
import
{
ref
}
from
'vue'
;
import
{
ref
}
from
'vue'
;
import
{
DocumentCopy
}
from
'@element-plus/icons-vue'
import
{
DocumentCopy
}
from
'@element-plus/icons-vue'
import
Episode
from
'./Episode.vue'
;
import
Episode
from
'./Episode.vue'
;
import
draggable
from
'vuedraggable'
const
indexVal
=
ref
(
0
)
const
indexVal
=
ref
(
0
)
const
aiTypeVal
=
ref
(
''
)
const
aiTypeVal
=
ref
(
''
)
...
@@ -66,15 +58,6 @@ const options = [
...
@@ -66,15 +58,6 @@ const options = [
]
]
const
list
=
ref
([
{
id
:
1
,
name
:
'第1集 凌晨的咖啡与雨'
,
time
:
'00:00:00'
},
{
id
:
2
,
name
:
'第2集 早餐的阳光与微笑'
,
time
:
'00:00:00'
},
{
id
:
3
,
name
:
'第3集 午餐的温暖与关怀'
,
time
:
'00:00:00'
},
])
const
onDragEnd
=
(
evt
:
any
)
=>
{
console
.
log
(
'拖拽结束'
,
list
.
value
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment