Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
水玉婷
ai-wechat
Commits
08a063fa
Commit
08a063fa
authored
Nov 28, 2025
by
水玉婷
Browse files
feat:调整项目结构
parent
203ea4e2
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/views/components/AiChat.vue
View file @
08a063fa
...
@@ -88,9 +88,9 @@ import { EventSourcePolyfill } from 'event-source-polyfill';
...
@@ -88,9 +88,9 @@ import { EventSourcePolyfill } from 'event-source-polyfill';
import
{
ref
,
onMounted
,
onBeforeUnmount
,
nextTick
,
watch
}
from
'
vue
'
;
import
{
ref
,
onMounted
,
onBeforeUnmount
,
nextTick
,
watch
}
from
'
vue
'
;
import
dayjs
from
'
dayjs
'
;
import
dayjs
from
'
dayjs
'
;
import
{
post
,
get
}
from
'
@/utils/axios.js
'
;
// 导入axios的post方法
import
{
post
,
get
}
from
'
@/utils/axios.js
'
;
// 导入axios的post方法
import
{
tableTemplate
}
from
'
./tableTemplate
'
;
import
{
tableTemplate
}
from
'
./
utils/
tableTemplate
'
;
import
{
markdownTemplate
,
isLastBlockMarkdown
,
getLastMarkdownBlockIndex
,
mergeMarkdownContent
}
from
'
./markdownTemplate
'
;
import
{
markdownTemplate
,
isLastBlockMarkdown
,
getLastMarkdownBlockIndex
,
mergeMarkdownContent
}
from
'
./
utils/
markdownTemplate
'
;
import
{
audioTemplate
,
initAudioPlayers
,
pauseAllOtherAudios
}
from
'
./audioTemplate
'
;
import
{
audioTemplate
,
initAudioPlayers
}
from
'
./
utils/
audioTemplate
'
;
import
{
SendOutlined
,
UserOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
SendOutlined
,
UserOutlined
}
from
'
@ant-design/icons-vue
'
;
import
defaultAvatar
from
'
@/assets/logo.png
'
;
import
defaultAvatar
from
'
@/assets/logo.png
'
;
import
ChartComponent
from
'
./ChartComponent.vue
'
;
// 导入独立的图表组件
import
ChartComponent
from
'
./ChartComponent.vue
'
;
// 导入独立的图表组件
...
...
src/views/components/AudioPlayer.vue
deleted
100644 → 0
View file @
203ea4e2
<
template
>
<div
class=
"audio-player"
:class=
"
{ playing: isPlaying }" @click="togglePlay">
<div
class=
"audio-icon"
>
<span
class=
"play-icon"
:style=
"
{ display: isPlaying ? 'none' : 'inline' }">▶
</span>
<span
class=
"pause-icon"
:style=
"
{ display: isPlaying ? 'inline' : 'none' }">❚❚
</span>
</div>
<div
class=
"audio-wave"
>
<div
class=
"wave-bar wave-bar-1"
></div>
<div
class=
"wave-bar wave-bar-2"
></div>
<div
class=
"wave-bar wave-bar-3"
></div>
</div>
<audio
ref=
"audioElement"
:src=
"audioUrl"
preload=
"metadata"
@
play=
"onPlay"
@
pause=
"onPause"
@
ended=
"onEnded"
@
timeupdate=
"onTimeUpdate"
></audio>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
onMounted
,
onUnmounted
,
nextTick
}
from
'
vue
'
interface
Props
{
audioUrl
:
string
}
const
props
=
defineProps
<
Props
>
()
const
audioElement
=
ref
<
HTMLAudioElement
>
()
const
isPlaying
=
ref
(
false
)
// 播放/暂停切换
const
togglePlay
=
async
()
=>
{
if
(
!
audioElement
.
value
)
return
try
{
if
(
audioElement
.
value
.
paused
)
{
// 暂停其他正在播放的音频
pauseAllOtherAudios
()
await
audioElement
.
value
.
play
()
}
else
{
audioElement
.
value
.
pause
()
}
}
catch
(
error
)
{
console
.
error
(
'
音频播放失败:
'
,
error
)
}
}
// 播放事件
const
onPlay
=
()
=>
{
isPlaying
.
value
=
true
}
// 暂停事件
const
onPause
=
()
=>
{
isPlaying
.
value
=
false
}
// 播放结束事件
const
onEnded
=
()
=>
{
isPlaying
.
value
=
false
}
// 时间更新事件
const
onTimeUpdate
=
()
=>
{
// 可以在这里添加时间更新逻辑,如果需要显示播放进度的话
}
// 暂停所有其他正在播放的音频
const
pauseAllOtherAudios
=
()
=>
{
const
allAudios
=
document
.
querySelectorAll
(
'
audio
'
)
allAudios
.
forEach
((
audio
)
=>
{
if
(
audio
!==
audioElement
.
value
&&
!
audio
.
paused
)
{
audio
.
pause
()
const
player
=
audio
.
closest
(
'
.audio-player
'
)
if
(
player
)
{
player
.
classList
.
remove
(
'
playing
'
)
}
}
})
}
// 组件挂载时初始化
onMounted
(()
=>
{
nextTick
(()
=>
{
// 确保音频元素已挂载
if
(
audioElement
.
value
)
{
// 可以在这里添加音频加载完成的逻辑
}
})
})
// 组件卸载时清理
onUnmounted
(()
=>
{
if
(
audioElement
.
value
)
{
audioElement
.
value
.
pause
()
audioElement
.
value
.
src
=
''
}
})
// 暴露方法给父组件
defineExpose
({
play
:
()
=>
audioElement
.
value
?.
play
(),
pause
:
()
=>
audioElement
.
value
?.
pause
(),
getCurrentTime
:
()
=>
audioElement
.
value
?.
currentTime
||
0
,
getDuration
:
()
=>
audioElement
.
value
?.
duration
||
0
,
isPlaying
:
()
=>
!
audioElement
.
value
?.
paused
||
false
})
</
script
>
<
style
scoped
lang=
"less"
>
.audio-player {
display: flex;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
user-select: none;
box-sizing: border-box;
&.playing {
.audio-wave .wave-bar {
animation: wechatWaveAnimation 1.2s ease-in-out infinite;
&.wave-bar-1 {
animation-delay: 0s;
animation-duration: 1.4s;
}
&.wave-bar-2 {
animation-delay: 0.2s;
animation-duration: 1.2s;
}
&.wave-bar-3 {
animation-delay: 0.4s;
animation-duration: 1.0s;
}
}
}
.audio-icon {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 8px;
color: #ffffff; // 白色图标
.play-icon,
.pause-icon {
font-size: 12px;
font-weight: bold;
}
}
.audio-wave {
display: flex;
align-items: flex-end;
gap: 1px;
margin-right: 8px;
height: 16px;
.wave-bar {
width: 3px;
background: #ffffff; // 白色波形条
border-radius: 2px 2px 0 0; // 顶部圆角,底部直角
transition: all 0.3s ease;
&.wave-bar-1 {
height: 6px;
border-radius: 3px 3px 0 0;
}
&.wave-bar-2 {
height: 10px;
border-radius: 3px 3px 0 0;
}
&.wave-bar-3 {
height: 14px;
border-radius: 3px 3px 0 0;
}
}
}
audio {
display: none; // 隐藏原生音频控件
}
}
@keyframes wechatWaveAnimation {
0%,
100% {
transform: scaleY(0.3);
opacity: 0.6;
}
25% {
transform: scaleY(0.7);
opacity: 0.8;
}
50% {
transform: scaleY(1);
opacity: 1;
}
75% {
transform: scaleY(0.7);
opacity: 0.8;
}
}
</
style
>
src/views/components/audioTemplate.ts
→
src/views/components/
utils/
audioTemplate.ts
View file @
08a063fa
File moved
src/views/components/markdownTemplate.ts
→
src/views/components/
utils/
markdownTemplate.ts
View file @
08a063fa
File moved
src/views/components/tableTemplate.ts
→
src/views/components/
utils/
tableTemplate.ts
View file @
08a063fa
File moved
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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