Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
ai_fundub
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
template admin
ai_fundub
Commits
bcbe92bd
Commit
bcbe92bd
authored
Feb 05, 2026
by
liujiangnan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 拆分句子
parent
ec3615d7
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
131 additions
and
2 deletions
+131
-2
index.css
form/index.css
+27
-0
index.html
form/index.html
+22
-2
index.js
form/index.js
+82
-0
No files found.
form/index.css
View file @
bcbe92bd
...
@@ -270,6 +270,33 @@
...
@@ -270,6 +270,33 @@
display
:
inline-block
;
display
:
inline-block
;
}
}
/* 分词表 - 悬浮行底边高亮与左侧拆分按钮 */
.swords-table
.el-table__body
tr
.sw-hover
td
{
border-bottom
:
2px
solid
#409eff
!important
;
}
.swords-start-cell
{
position
:
relative
;
}
.row-split-trigger
{
position
:
absolute
;
left
:
-12px
;
/* 稍微伸出单元格左侧 */
bottom
:
-1px
;
/* 贴近行底边 */
width
:
18px
;
height
:
18px
;
border-radius
:
50%
;
background
:
#409eff
;
color
:
#fff
;
font-size
:
12px
;
line-height
:
18px
;
text-align
:
center
;
box-shadow
:
0
2px
6px
rgba
(
64
,
158
,
255
,
0.35
);
cursor
:
pointer
;
user-select
:
none
;
}
.row-split-trigger
:hover
{
background
:
#66b1ff
;
}
/* 卡片悬停效果 */
/* 卡片悬停效果 */
.upload-section
,
.upload-section
,
.video-section
,
.video-section
,
...
...
form/index.html
View file @
bcbe92bd
...
@@ -270,10 +270,30 @@
...
@@ -270,10 +270,30 @@
<div
style=
"display:flex; gap:12px; margin-top:8px; flex-wrap:wrap;"
>
<div
style=
"display:flex; gap:12px; margin-top:8px; flex-wrap:wrap;"
>
<div
style=
"flex:1; min-width:300px;"
>
<div
style=
"flex:1; min-width:300px;"
>
<div
style=
"font-weight:500; margin-bottom:4px;"
>
原文分词
</div>
<div
style=
"font-weight:500; margin-bottom:4px;"
>
原文分词
</div>
<el-table
:data=
"item.sWordsRef || []"
size=
"mini"
border
>
<el-table
class=
"swords-table"
:data=
"item.sWordsRef || []"
size=
"mini"
border
:row-class-name=
"({row, rowIndex}) => getSWordsRowClass(item, idx, row, rowIndex)"
@
cell-mouse-enter=
"(row, column, cell, event) => onSWordsCellEnter(idx, row, column, cell, event)"
@
cell-mouse-leave=
"(row, column, cell, event) => onSWordsCellLeave(idx, row, column, cell, event)"
>
<el-table-column
label=
"start"
width=
"90"
>
<el-table-column
label=
"start"
width=
"90"
>
<template
slot-scope=
"s"
>
<template
slot-scope=
"s"
>
{{ formatTimeNumeric(s.row.start) }}
<div
class=
"swords-start-cell"
>
{{ formatTimeNumeric(s.row.start) }}
<el-tooltip
v-if=
"item._hoveredSIndex === s.$index && !isAnyTaskRunning() && s.$index < (item.sWordsRef ? item.sWordsRef.length - 1 : 0)"
content=
"在此处拆分为两句"
placement=
"left"
>
<span
class=
"row-split-trigger"
@
click=
"splitAtSWordsRow(idx, s.$index)"
>
拆
</span>
</el-tooltip>
</div>
</template>
</template>
</el-table-column>
</el-table-column>
<el-table-column
label=
"end"
width=
"90"
>
<el-table-column
label=
"end"
width=
"90"
>
...
...
form/index.js
View file @
bcbe92bd
...
@@ -735,9 +735,91 @@ function initVueApp(savedData) {
...
@@ -735,9 +735,91 @@ function initVueApp(savedData) {
}
}
// 从可视列表中移除当前条目
// 从可视列表中移除当前条目
list
.
splice
(
idx
,
1
);
list
.
splice
(
idx
,
1
);
// 重新编号
list
.
forEach
((
it
,
i
)
=>
{
it
.
index
=
i
+
1
;
});
this
.
$message
.
success
(
'
已与上一句合并
'
);
this
.
$message
.
success
(
'
已与上一句合并
'
);
},
},
// hover 分词表行:进入/离开
onSWordsCellEnter
(
tlIndex
,
row
,
column
,
cell
,
event
)
{
const
item
=
this
.
subtitleEditor
.
mergedList
&&
this
.
subtitleEditor
.
mergedList
[
tlIndex
];
if
(
!
item
||
!
Array
.
isArray
(
item
.
sWordsRef
))
return
;
const
rIndex
=
item
.
sWordsRef
.
indexOf
(
row
);
if
(
rIndex
>=
0
&&
rIndex
<
item
.
sWordsRef
.
length
-
1
)
{
this
.
$set
(
item
,
'
_hoveredSIndex
'
,
rIndex
);
}
else
{
this
.
$set
(
item
,
'
_hoveredSIndex
'
,
-
1
);
}
},
onSWordsCellLeave
(
tlIndex
,
row
,
column
,
cell
,
event
)
{
const
item
=
this
.
subtitleEditor
.
mergedList
&&
this
.
subtitleEditor
.
mergedList
[
tlIndex
];
if
(
!
item
)
return
;
this
.
$set
(
item
,
'
_hoveredSIndex
'
,
-
1
);
},
getSWordsRowClass
(
item
,
tlIndex
,
row
,
rowIndex
)
{
if
(
!
item
||
!
Array
.
isArray
(
item
.
sWordsRef
))
return
''
;
const
isLast
=
rowIndex
>=
item
.
sWordsRef
.
length
-
1
;
return
item
.
_hoveredSIndex
===
rowIndex
&&
!
isLast
?
'
sw-hover
'
:
''
;
},
// 在某个分词行底部拆分为两句
splitAtSWordsRow
(
tlIndex
,
rowIndex
)
{
if
(
this
.
isAnyTaskRunning
&&
this
.
isAnyTaskRunning
())
{
this
.
$message
.
warning
(
'
有任务进行中,拆分已锁定
'
);
return
;
}
const
list
=
this
.
subtitleEditor
.
mergedList
||
[];
const
item
=
list
[
tlIndex
];
if
(
!
item
||
!
Array
.
isArray
(
item
.
sWordsRef
))
return
;
if
(
rowIndex
<
0
||
rowIndex
>=
item
.
sWordsRef
.
length
-
1
)
{
this
.
$message
.
warning
(
'
请选择中间行进行拆分
'
);
return
;
}
const
leftWords
=
item
.
sWordsRef
.
slice
(
0
,
rowIndex
+
1
);
const
rightWords
=
item
.
sWordsRef
.
slice
(
rowIndex
+
1
);
const
splitPointSec
=
this
.
parseTimeToSeconds
(
item
.
sWordsRef
[
rowIndex
].
end
);
const
nextStartSec
=
this
.
parseTimeToSeconds
(
item
.
sWordsRef
[
rowIndex
+
1
].
start
);
// 构造新条目
const
newItem
=
{
index
:
item
.
index
+
1
,
sIndex
:
item
.
sIndex
!=
null
?
item
.
sIndex
+
1
:
null
,
tIndex
:
item
.
tIndex
!=
null
?
item
.
tIndex
+
1
:
null
,
start
:
this
.
toDisplayTime
(
nextStartSec
),
end
:
item
.
end
,
subtitleText
:
''
,
subtitleWordString
:
''
,
translatedText
:
''
,
translatedTranslated
:
''
,
translatedItemsString
:
''
,
sWordsRef
:
rightWords
,
tItemsRef
:
[]
};
// 原条目更新为左半部分
item
.
sWordsRef
=
leftWords
;
item
.
end
=
this
.
toDisplayTime
(
splitPointSec
);
// 翻译分段按时间粗略分割
if
(
Array
.
isArray
(
item
.
tItemsRef
))
{
const
leftT
=
[];
const
rightT
=
[];
for
(
const
it
of
item
.
tItemsRef
)
{
const
st
=
this
.
parseTimeToSeconds
(
it
&&
it
.
start
);
const
et
=
this
.
parseTimeToSeconds
(
it
&&
it
.
end
);
if
(
!
isNaN
(
et
)
&&
et
<=
splitPointSec
)
leftT
.
push
(
it
);
else
if
(
!
isNaN
(
st
)
&&
st
>=
splitPointSec
)
rightT
.
push
(
it
);
else
{
// 交叉的分段归到后半部分,避免信息丢失
rightT
.
push
(
it
);
}
}
item
.
tItemsRef
=
leftT
;
newItem
.
tItemsRef
=
rightT
;
}
// 插入新条目并重排索引
list
.
splice
(
tlIndex
+
1
,
0
,
newItem
);
list
.
forEach
((
it
,
i
)
=>
{
it
.
index
=
i
+
1
;
});
this
.
$message
.
success
(
'
已按此处拆分为两句
'
);
},
// 从任意 JSON 中提取数组(优先常见字段,其次深度搜索)
// 从任意 JSON 中提取数组(优先常见字段,其次深度搜索)
extractArrayFromJson
(
root
,
type
)
{
extractArrayFromJson
(
root
,
type
)
{
if
(
!
root
)
return
[];
if
(
!
root
)
return
[];
...
...
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