Commit bcbe92bd authored by liujiangnan's avatar liujiangnan

feat: 拆分句子

parent ec3615d7
......@@ -270,6 +270,33 @@
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,
.video-section,
......
......@@ -270,10 +270,30 @@
<div style="display:flex; gap:12px; margin-top:8px; flex-wrap:wrap;">
<div style="flex:1; min-width:300px;">
<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">
<template slot-scope="s">
<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>
</el-table-column>
<el-table-column label="end" width="90">
......
......@@ -735,9 +735,91 @@ function initVueApp(savedData) {
}
// 从可视列表中移除当前条目
list.splice(idx, 1);
// 重新编号
list.forEach((it, i) => { it.index = i + 1; });
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 中提取数组(优先常见字段,其次深度搜索)
extractArrayFromJson(root, type) {
if (!root) return [];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment