Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
AI_BOOK_TOOL
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_BOOK_TOOL
Commits
b5a849da
Commit
b5a849da
authored
Aug 01, 2025
by
liujiangnan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat
parent
78402008
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
350238 additions
and
3065 deletions
+350238
-3065
index.html
form/index.html
+6
-20
index.js
form/index.js
+33
-142
defaultData_1.json
play/defaultData_1.json
+350199
-2903
No files found.
form/index.html
View file @
b5a849da
...
...
@@ -537,7 +537,7 @@
<el-button
@
click=
"handleZoomOut"
:disabled=
"!wavesurfer || audioLoading || zoomLevel <= minZoom"
>
<i
class=
"el-icon-zoom-out"
></i>
</el-button>
<el-button
@
click=
"togglePageLock"
:disabled=
"!wavesurfer || audioLoading || !currentPage
|| isPreviewMode
"
>
<el-button
@
click=
"togglePageLock"
:disabled=
"!wavesurfer || audioLoading || !currentPage"
>
<i
:class=
"isPageLocked ? 'el-icon-lock' : 'el-icon-unlock'"
></i>
<span
v-if=
"isPageLocked"
>
解锁
</span>
<span
v-else
>
锁定页
</span>
...
...
@@ -545,31 +545,17 @@
<el-button
@
click=
"togglePreviewMode"
:disabled=
"!wavesurfer || audioLoading"
:type=
"isPreviewMode ? 'danger' : 'default'
"
type=
"primary
"
>
<i
:class=
"isPreviewMode ? 'el-icon-switch-button' : 'el-icon-view'
"
></i>
{{ isPreviewMode ? '退出预览' : '预览' }}
<i
class=
"el-icon-view
"
></i>
预览
</el-button>
</el-button-group>
<!-- 播放速度选择 -->
<el-select
v-model=
"currentPlaybackRate"
size=
"small"
style=
"width: 120px; margin-left: 10px;"
:disabled=
"!isPreviewMode"
@
change=
"changePlaybackRate"
>
<el-option
v-for=
"rate in playbackRates"
:key=
"rate"
:label=
"rate + 'x'"
:value=
"rate"
/>
</el-select>
<div
style=
"margin-left: 10px; display: inline-block; width: 200px;"
>
当前时间:
<div
style=
"display: inline-block; width: 50px;"
>
{{ formatTime(currentTime) }}
</div>
秒
</div>
<el-button
:disabled=
"!isDataModified
&& !isPreviewMode
"
type=
"success"
@
click=
"save()"
>
<el-button
:disabled=
"!isDataModified"
type=
"success"
@
click=
"save()"
>
保存修改
</el-button>
</div>
...
...
form/index.js
View file @
b5a849da
...
...
@@ -81,12 +81,7 @@ new Vue({
lockedPageEnd
:
null
,
previousZoomLevel
:
null
,
// 新增:预览模式相关
isPreviewMode
:
false
,
playbackRates
:
[
0.5
,
1
,
1.5
,
2
,
4
,
8
,
10
],
currentPlaybackRate
:
1
,
previewTimer
:
null
,
lastCheckedTime
:
0
,
// 用于优化检查间隔
isDataModified
:
false
,
...
...
@@ -121,6 +116,16 @@ new Vue({
},
mounted
()
{
// 根据 staging 字符串,判断是否为 staging 环境
const
isStaging
=
window
.
location
.
href
.
includes
(
'
staging
'
);
const
isLocalhost
=
window
.
location
.
hostname
===
'
localhost
'
||
window
.
location
.
hostname
===
'
127.0.0.1
'
;
if
(
isLocalhost
)
{
this
.
AI_SERVER_URL
=
'
http://localhost:1339
'
;
}
else
if
(
isStaging
)
{
this
.
AI_SERVER_URL
=
'
https://stagingopensource.iteachabc.com
'
;
}
else
{
this
.
AI_SERVER_URL
=
'
https://opensource.iteachabc.com
'
;
}
this
.
$nextTick
(()
=>
{
// 先加载数据
this
.
loadDefaultData
().
then
(()
=>
{
...
...
@@ -515,13 +520,7 @@ new Vue({
}
}
// 在预览模式下,手动调整位置时也同步页面和组的选中状态
if
(
this
.
isPreviewMode
)
{
// 重置最后检查时间,确保定时器能立即开始新的检查
this
.
lastCheckedTime
=
0
;
this
.
checkAndSwitchPage
(
this
.
currentTime
);
this
.
checkAndSelectGroup
(
this
.
currentTime
);
}
});
// 加载音频
...
...
@@ -922,7 +921,7 @@ new Vue({
// 页面选择
handlePageChange
(
page
)
{
if
(
!
this
.
wavesurfer
||
this
.
isPreviewMode
)
return
;
if
(
!
this
.
wavesurfer
)
return
;
// 检查页面锁定状态
if
(
this
.
isPageLocked
)
{
...
...
@@ -1047,7 +1046,7 @@ new Vue({
// 选择文本组
selectGroup
(
index
)
{
if
(
!
this
.
currentPage
||
!
this
.
currentPage
.
groups
||
this
.
isPreviewMode
)
return
;
if
(
!
this
.
currentPage
||
!
this
.
currentPage
.
groups
)
return
;
// 如果点击已选中的组,则取消选中
if
(
this
.
selectedGroup
===
index
)
{
...
...
@@ -1062,7 +1061,6 @@ new Vue({
// 开始拖拽
startDrag
(
event
,
groupIndex
,
itemIndex
)
{
if
(
event
.
target
.
classList
.
contains
(
'
resize-handle
'
))
return
;
if
(
this
.
isPreviewMode
)
return
;
// 获取图片容器的位置信息
const
imageWrapper
=
this
.
$refs
.
imageContainer
.
querySelector
(
'
.image-wrapper
'
);
...
...
@@ -1093,7 +1091,7 @@ new Vue({
// 开始调整大小
startResize
(
event
,
groupIndex
,
itemIndex
)
{
if
(
!
this
.
imageLoaded
||
this
.
isPreviewMode
)
return
;
if
(
!
this
.
imageLoaded
)
return
;
this
.
isResizing
=
true
;
this
.
dragStartX
=
event
.
clientX
;
...
...
@@ -1241,7 +1239,7 @@ new Vue({
// 从组中删除矩形框
deleteRectFromGroup
(
groupIndex
,
itemIndex
)
{
if
(
!
this
.
currentPage
||
!
this
.
currentPage
.
groups
[
groupIndex
]
||
this
.
isPreviewMode
)
return
;
if
(
!
this
.
currentPage
||
!
this
.
currentPage
.
groups
[
groupIndex
])
return
;
const
group
=
this
.
currentPage
.
groups
[
groupIndex
];
if
(
!
group
.
group
[
itemIndex
])
return
;
...
...
@@ -1289,7 +1287,7 @@ new Vue({
// 删除整个分组
deleteGroup
()
{
if
(
this
.
selectedGroup
===
null
||
!
this
.
currentPage
||
this
.
isPreviewMode
)
return
;
if
(
this
.
selectedGroup
===
null
||
!
this
.
currentPage
)
return
;
this
.
$confirm
(
'
确认删除该组及其所有矩形框吗?
'
,
'
提示
'
,
{
confirmButtonText
:
'
确定
'
,
...
...
@@ -1325,7 +1323,7 @@ new Vue({
// 处理矩形列表行点击
handleRectRowClick
(
row
,
oldRow
)
{
if
(
!
row
||
this
.
isPreviewMode
)
{
if
(
!
row
)
{
this
.
selectedItemIndex
=
null
;
return
;
}
...
...
@@ -1455,7 +1453,7 @@ new Vue({
// 拾取当前时间点
pickCurrentTime
(
target
)
{
if
(
!
this
.
wavesurfer
||
this
.
isPreviewMode
)
return
;
if
(
!
this
.
wavesurfer
)
return
;
// 激活保存按钮
this
.
isDataModified
=
true
;
...
...
@@ -1478,7 +1476,6 @@ new Vue({
// 处理图片区域点击
handleImageClick
(
event
)
{
if
(
this
.
isPreviewMode
)
return
;
// 如果点击的是矩形框或其相关元素,不处理
if
(
event
.
target
.
closest
(
'
.text-rect
'
)
||
...
...
@@ -1497,7 +1494,6 @@ new Vue({
// 处理全屏图片区域点击
handleFullscreenImageClick
(
event
)
{
if
(
this
.
isPreviewMode
)
return
;
// 如果点击的是矩形框或其相关元素,不处理
if
(
event
.
target
.
closest
(
'
.text-rect
'
)
||
...
...
@@ -1581,7 +1577,7 @@ new Vue({
// 新增:切换页面锁定状态
togglePageLock
()
{
if
(
!
this
.
currentPage
||
this
.
isPreviewMode
)
return
;
if
(
!
this
.
currentPage
)
return
;
if
(
!
this
.
isPageLocked
)
{
// 保存当前缩放级别
...
...
@@ -2118,127 +2114,25 @@ new Vue({
// 新增:切换预览模式
togglePreviewMode
()
{
// 如果页面处于锁定状态,提示用户先解锁
if
(
this
.
isPageLocked
)
{
this
.
$message
.
warning
(
'
请先解锁页面
'
);
return
;
}
if
(
!
this
.
isPreviewMode
)
{
// 进入预览模式
this
.
isPreviewMode
=
true
;
document
.
body
.
classList
.
add
(
'
preview-mode
'
);
// 从当前位置开始播放
this
.
wavesurfer
.
play
();
this
.
isPlaying
=
true
;
// 设置播放速度
this
.
wavesurfer
.
setPlaybackRate
(
this
.
currentPlaybackRate
);
// 开始监听播放位置
this
.
startPreviewMonitoring
();
// 判断是否为本地启动的服务
const
isLocalhost
=
window
.
location
.
hostname
===
'
localhost
'
||
window
.
location
.
hostname
===
'
127.0.0.1
'
;
if
(
isLocalhost
)
{
// 本地启动,跳转到本地预览页面
window
.
open
(
'
http://localhost:3000/play/index.html
'
,
'
_blank
'
);
}
else
{
// 退出预览模式
this
.
exitPreviewMode
();
}
},
// 新增:退出预览模式
exitPreviewMode
()
{
this
.
isPreviewMode
=
false
;
document
.
body
.
classList
.
remove
(
'
preview-mode
'
);
// 停止播放
if
(
this
.
isPlaying
)
{
this
.
wavesurfer
.
pause
();
this
.
isPlaying
=
false
;
}
// 清理监听器
this
.
stopPreviewMonitoring
();
// 重置播放速度
this
.
wavesurfer
.
setPlaybackRate
(
1
);
this
.
currentPlaybackRate
=
1
;
},
// 新增:开始预览监听
startPreviewMonitoring
()
{
// 清理可能存在的旧定时器
this
.
stopPreviewMonitoring
();
// 创建新的监听定时器
this
.
previewTimer
=
setInterval
(()
=>
{
if
(
!
this
.
isPreviewMode
)
return
;
const
currentTime
=
this
.
wavesurfer
.
getCurrentTime
();
// 优化:每50ms检查一次
if
(
currentTime
-
this
.
lastCheckedTime
<
0.05
)
return
;
this
.
lastCheckedTime
=
currentTime
;
// 检查是否需要切换页面和选中组
this
.
checkAndSwitchPage
(
currentTime
);
this
.
checkAndSelectGroup
(
currentTime
);
},
50
);
},
// 新增:停止预览监听
stopPreviewMonitoring
()
{
if
(
this
.
previewTimer
)
{
clearInterval
(
this
.
previewTimer
);
this
.
previewTimer
=
null
;
}
},
// 新增:检查并切换页面
checkAndSwitchPage
(
currentTime
)
{
if
(
!
this
.
pages
||
!
this
.
pages
.
length
)
return
;
// 找到当前时间所在的页面
const
targetPage
=
this
.
pages
.
find
(
page
=>
currentTime
>=
page
.
start
&&
currentTime
<=
page
.
end
);
if
(
targetPage
)
{
const
targetIndex
=
this
.
pages
.
indexOf
(
targetPage
)
+
1
;
if
(
targetIndex
!==
this
.
currentPageIndex
)
{
this
.
currentPageIndex
=
targetIndex
;
this
.
currentPage
=
targetPage
;
// 克隆currentPage
this
.
tempPage
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
currentPage
));
}
}
},
// 新增:检查并选中组
checkAndSelectGroup
(
currentTime
)
{
if
(
!
this
.
currentPage
||
!
this
.
currentPage
.
groups
)
return
;
// 找到当前时间所在的组
const
targetGroup
=
this
.
currentPage
.
groups
.
findIndex
(
group
=>
currentTime
>=
group
.
start
&&
currentTime
<=
group
.
end
);
if
(
targetGroup
!==
-
1
)
{
if
(
this
.
selectedGroup
!==
targetGroup
)
{
this
.
selectedGroup
=
targetGroup
;
this
.
currentGroup
=
this
.
currentPage
.
groups
[
targetGroup
];
}
// 非本地环境
const
isInIframe
=
window
!==
window
.
top
;
if
(
isInIframe
)
{
callServerMethod
(
'
openNewPreview
'
);
}
else
{
this
.
selectedGroup
=
null
;
this
.
currentGroup
=
null
;
// 不在 iframe 中,直接使用当前域名
const
previewUrl
=
window
.
location
.
href
.
replace
(
'
form/index.html
'
,
'
play/index.html
'
);
window
.
open
(
previewUrl
,
'
_blank
'
);
}
}
},
// 新增:修改播放速度
changePlaybackRate
(
rate
)
{
if
(
!
this
.
isPreviewMode
)
return
;
this
.
currentPlaybackRate
=
rate
;
this
.
wavesurfer
.
setPlaybackRate
(
rate
);
},
save
()
{
if
(
!
this
.
isDataModified
)
return
;
...
...
@@ -2585,9 +2479,6 @@ new Vue({
// 清理定时器
this
.
clearPlayTimer
();
// 清理预览模式的定时器
this
.
stopPreviewMonitoring
();
// 销毁波形图
if
(
this
.
wavesurfer
)
{
try
{
...
...
play/defaultData_1.json
View file @
b5a849da
This source diff could not be displayed because it is too large. You can
view the blob
instead.
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