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
e32996f4
Commit
e32996f4
authored
Nov 27, 2025
by
水玉婷
Browse files
feat:添加env环境变量配置
parent
86790086
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/utils/axios.js
View file @
e32996f4
...
@@ -9,6 +9,9 @@ const instance = axios.create({
...
@@ -9,6 +9,9 @@ const instance = axios.create({
}
}
})
})
// 防止重复跳转的标志
let
isNavigatingToLogin
=
false
// 请求拦截器 - 添加认证信息
// 请求拦截器 - 添加认证信息
instance
.
interceptors
.
request
.
use
(
instance
.
interceptors
.
request
.
use
(
(
config
)
=>
{
(
config
)
=>
{
...
@@ -44,11 +47,24 @@ instance.interceptors.response.use(
...
@@ -44,11 +47,24 @@ instance.interceptors.response.use(
// 处理401未授权错误
// 处理401未授权错误
if
(
status
===
401
)
{
if
(
status
===
401
)
{
// 检查是否已经在跳转过程中,防止无限循环
if
(
isNavigatingToLogin
)
{
return
Promise
.
reject
(
new
Error
(
'
正在跳转到登录页面
'
))
}
// 设置跳转标志
isNavigatingToLogin
=
true
// 清除本地存储的用户信息
// 清除本地存储的用户信息
localStorage
.
removeItem
(
'
wechat_user
'
)
localStorage
.
removeItem
(
'
wechat_user
'
)
// 使用全局路由管理器跳转
// 使用全局路由管理器跳转
navigateToLogin
()
navigateToLogin
()
// 3秒后重置跳转标志,防止长时间锁定
setTimeout
(()
=>
{
isNavigatingToLogin
=
false
},
3000
)
return
Promise
.
reject
(
new
Error
(
'
未授权访问,请重新登录
'
))
return
Promise
.
reject
(
new
Error
(
'
未授权访问,请重新登录
'
))
}
}
...
...
src/views/Home.vue
View file @
e32996f4
...
@@ -14,22 +14,34 @@
...
@@ -14,22 +14,34 @@
import
AiChat
from
'
./components/AiChat.vue
'
;
import
AiChat
from
'
./components/AiChat.vue
'
;
import
{
ref
}
from
'
vue
'
;
import
{
ref
}
from
'
vue
'
;
const
apiBaseUrl
=
'
/pedapi
'
;
// 动态处理API基础路径
const
getApiBaseUrl
=
()
=>
{
const
basePath
=
import
.
meta
.
env
.
VITE_API_BASE_PATH
;
// 如果设置为'/',则返回空字符串,避免双斜杠
if
(
basePath
===
'
/
'
)
{
return
''
;
}
return
basePath
;
};
const
apiBaseUrl
=
getApiBaseUrl
();
// 获取token
// 获取token
const
userInfo
=
localStorage
.
getItem
(
'
wechat_user
'
)
const
userInfo
=
localStorage
.
getItem
(
'
wechat_user
'
)
const
{
extMap
=
{}}
=
JSON
.
parse
(
userInfo
||
'
{}
'
)
const
{
extMap
=
{}}
=
JSON
.
parse
(
userInfo
||
'
{}
'
)
const
userToken
=
extMap
.
sessionId
;
const
userToken
=
extMap
.
sessionId
;
//
添加APP_CODE配置
//
使用环境变量代替硬编码
const
appCode
=
'
ped.qywx
'
;
const
appCode
=
import
.
meta
.
env
.
VITE_APP_CODE
||
'
ped.qywx
'
;
const
chatParams
=
{
const
chatParams
=
{
appId
:
'
83b2664019a945d0a438abe6339758d8
'
,
appId
:
'
83b2664019a945d0a438abe6339758d8
'
,
stage
:
'
wechat-demo
'
,
stage
:
'
wechat-demo
'
,
};
};
//
const dialogSessionId = '20251028143404893-00045166';
const
dialogSessionId
=
'
20251028143404893-00045166
'
;
const
dialogSessionId
=
''
;
//
const dialogSessionId = '';
const
detailData
=
ref
({
const
detailData
=
ref
({
title
:
'
国械小智
'
,
title
:
'
国械小智
'
,
});
});
...
...
src/views/components/AiChat.vue
View file @
e32996f4
...
@@ -87,38 +87,58 @@
...
@@ -87,38 +87,58 @@
import
{
EventSourcePolyfill
}
from
'
event-source-polyfill
'
;
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
}
from
'
@/utils/axios.js
'
;
// 导入axios的post方法
import
{
post
,
get
}
from
'
@/utils/axios.js
'
;
// 导入axios的post方法
import
tableTemplate
from
'
./tableTemplate
'
;
import
tableTemplate
from
'
./tableTemplate
'
;
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
'
;
// 导入独立的图表组件
import
VoiceRecognition
from
'
./VoiceRecognition.vue
'
;
// 导入语音识别组件
import
VoiceRecognition
from
'
./VoiceRecognition.vue
'
;
// 导入语音识别组件
// 组件属性
// 定义组件属性
const
props
=
withDefaults
(
const
props
=
defineProps
({
defineProps
<
{
// 对话会话ID
params
?:
ChatParams
;
dialogSessionId
:
{
dialogSessionId
?:
string
;
type
:
String
,
detailData
?:
{
default
:
''
title
?:
string
;
},
};
// API基础URL
apiBaseUrl
?:
string
;
apiBaseUrl
:
{
token
?:
string
;
type
:
String
,
appCode
?:
string
;
default
:
import
.
meta
.
env
.
VITE_API_BASE_PATH
||
'
/pedapi
'
logoUrl
?:
string
;
},
onMessageSend
?:
(
message
:
string
)
=>
Promise
<
any
>
;
// 应用代码
onGetChatRecord
?:
(
dialogSessionId
:
string
)
=>
Promise
<
any
>
;
appCode
:
{
customClass
?:
string
;
type
:
String
,
}
>
(),
default
:
import
.
meta
.
env
.
VITE_APP_CODE
||
'
ped.qywx
'
{
},
params
:
()
=>
({
token
:
{
type
:
String
,
default
:
''
},
logoUrl
:
{
type
:
String
,
default
:
''
},
onMessageSend
:
{
type
:
Function
,
default
:
undefined
},
onGetChatRecord
:
{
type
:
Function
,
default
:
undefined
},
customClass
:
{
type
:
String
,
default
:
''
},
params
:
{
type
:
Object
,
default
:
()
=>
({
appId
:
'
app-test
'
,
appId
:
'
app-test
'
,
stage
:
'
wechat-demo
'
,
stage
:
'
wechat-demo
'
,
}),
})
apiBaseUrl
:
'
/pedapi
'
,
}
logoUrl
:
''
,
});
},
);
// 内容模板生成器 - 简化版本,表格功能已抽离
// 内容模板生成器 - 简化版本,表格功能已抽离
const
contentTemplates
=
{
const
contentTemplates
=
{
...
@@ -251,13 +271,6 @@ interface Message {
...
@@ -251,13 +271,6 @@ interface Message {
}[];
}[];
}
}
// 检查是否为音频消息的辅助函数
const
isAudioMessage
=
(
messageData
:
any
):
boolean
=>
{
return
messageData
.
questionType
===
'
audio
'
||
(
messageData
.
question
&&
typeof
messageData
.
question
===
'
object
'
&&
(
messageData
.
question
.
audioUrl
||
messageData
.
question
.
audioData
));
};
interface
SSEData
{
interface
SSEData
{
message
:
any
;
message
:
any
;
status
:
number
|
string
;
status
:
number
|
string
;
...
@@ -340,7 +353,6 @@ const sendAudioMessage = async (audioUrl: string) => {
...
@@ -340,7 +353,6 @@ const sendAudioMessage = async (audioUrl: string) => {
await
props
.
onMessageSend
(
audioUrl
);
await
props
.
onMessageSend
(
audioUrl
);
}
else
{
}
else
{
// 默认的API调用逻辑 - 使用与sendMessage相同的逻辑,只是参数不同
// 默认的API调用逻辑 - 使用与sendMessage相同的逻辑,只是参数不同
console
.
log
(
'
默认音频API调用逻辑
'
);
const
response
=
await
post
(
`
${
props
.
apiBaseUrl
}
/aiService/ask/app/
${
props
.
params
?.
appId
}
`
,
{
const
response
=
await
post
(
`
${
props
.
apiBaseUrl
}
/aiService/ask/app/
${
props
.
params
?.
appId
}
`
,
{
questionLocalAudioFilePath
:
audioUrl
,
questionLocalAudioFilePath
:
audioUrl
,
...
props
.
params
,
...
props
.
params
,
...
@@ -349,7 +361,6 @@ const sendAudioMessage = async (audioUrl: string) => {
...
@@ -349,7 +361,6 @@ const sendAudioMessage = async (audioUrl: string) => {
Token
:
props
.
token
||
''
,
Token
:
props
.
token
||
''
,
'
x-session-id
'
:
props
.
token
||
''
,
'
x-session-id
'
:
props
.
token
||
''
,
'
x-app-code
'
:
props
.
appCode
||
''
,
'
x-app-code
'
:
props
.
appCode
||
''
,
'
Content-Type
'
:
'
multipart/form-data
'
,
}
}
});
});
...
@@ -370,76 +381,6 @@ const startConversation = () => {
...
@@ -370,76 +381,6 @@ const startConversation = () => {
hasStartedConversation
.
value
=
true
;
hasStartedConversation
.
value
=
true
;
};
};
// 模拟status为3、type为options的数据返回
const
simulateOptionData
=
()
=>
{
// 第一个消息:展示三个options
const
firstOptionData
=
{
status
:
3
,
type
:
'
option
'
,
message
:
{
tips
:
"
以下是三个可选的报表链接:
"
,
options
:
[
{
title
:
"
月度销售报表
"
,
url
:
"
https://example.com/report/monthly
"
},
{
title
:
"
季度业绩分析
"
,
url
:
"
https://example.com/report/quarterly
"
},
{
title
:
"
年度总结报告
"
,
url
:
"
https://example.com/report/annual
"
}
]
}
};
// 第二个消息:展示一个options(会走iframe逻辑)
const
secondOptionData
=
{
status
:
3
,
type
:
'
option
'
,
message
:
{
tips
:
"
这是单个报表的预览:
"
,
options
:
[
{
title
:
"
销售指标看板
"
,
url
:
"
/WeChatOauth2/MobileReport_Monthly/MonthlyReport_index.aspx?postage=384b67414b334f2f693177644246313756704a724d513d3d&company=器械整体&typename=整体指标
"
}
]
}
};
// 创建AI响应消息
const
aiMessage
=
{
messageType
:
'
received
'
,
avatar
:
'
AI
'
,
recordId
:
'
simulate-001
'
,
promptTokens
:
100
,
completionTokens
:
50
,
totalTokens
:
150
,
date
:
dayjs
().
format
(
'
HH:mm
'
),
contentBlocks
:
[]
};
// 处理第一个选项数据(三个options)
const
firstResult
=
processSSEMessage
(
firstOptionData
,
aiMessage
,
false
,
-
1
,
false
);
// 处理第二个选项数据(一个options)
const
secondResult
=
processSSEMessage
(
secondOptionData
,
firstResult
.
updatedResponse
,
false
,
-
1
,
false
);
// 将处理后的消息添加到消息列表
if
(
secondResult
.
updatedResponse
)
{
messages
.
value
.
push
(
secondResult
.
updatedResponse
);
nextTick
(()
=>
{
scrollToBottom
();
});
}
};
// 发送消息
// 发送消息
const
sendMessage
=
async
()
=>
{
const
sendMessage
=
async
()
=>
{
loading
.
value
=
true
;
loading
.
value
=
true
;
...
@@ -480,13 +421,6 @@ const sendMessage = async () => {
...
@@ -480,13 +421,6 @@ const sendMessage = async () => {
try
{
try
{
messageText
.
value
=
''
;
messageText
.
value
=
''
;
// 可选:在发送消息后模拟选项数据返回
// 取消注释以下代码来启用模拟
setTimeout
(()
=>
{
simulateOptionData
();
loading
.
value
=
false
;
},
1000
);
// 调用外部传入的消息发送函数
// 调用外部传入的消息发送函数
if
(
props
.
onMessageSend
)
{
if
(
props
.
onMessageSend
)
{
console
.
log
(
'
调用外部消息发送函数
'
,
message
);
console
.
log
(
'
调用外部消息发送函数
'
,
message
);
...
@@ -555,7 +489,7 @@ const processSSEMessage = (
...
@@ -555,7 +489,7 @@ const processSSEMessage = (
case
3
:
// 图表数据
case
3
:
// 图表数据
if
(
updatedResponse
)
{
if
(
updatedResponse
)
{
switch
(
contentType
)
{
switch
(
contentType
)
{
case
'
table
'
:
// 表格数据
case
2
:
// 表格数据
const
{
rows
}
=
messageContent
;
const
{
rows
}
=
messageContent
;
// 表格数据处理
// 表格数据处理
updatedResponse
.
contentBlocks
.
push
({
updatedResponse
.
contentBlocks
.
push
({
...
@@ -574,7 +508,7 @@ const processSSEMessage = (
...
@@ -574,7 +508,7 @@ const processSSEMessage = (
chartType
:
3
,
chartType
:
3
,
});
});
break
;
break
;
case
'
option
'
:
// 选项数据
case
3
:
// 选项数据
const
{
tips
,
options
}
=
messageContent
;
const
{
tips
,
options
}
=
messageContent
;
if
(
options
?.
length
)
{
if
(
options
?.
length
)
{
if
(
options
?.
length
===
1
)
{
if
(
options
?.
length
===
1
)
{
...
@@ -609,7 +543,7 @@ const processSSEMessage = (
...
@@ -609,7 +543,7 @@ const processSSEMessage = (
break
;
break
;
}
}
}
}
break
;
break
;
case
10
:
// 思考开始
case
10
:
// 思考开始
updatedIsThinking
=
true
;
updatedIsThinking
=
true
;
if
(
updatedBlockIndex
===
-
1
&&
updatedResponse
)
{
if
(
updatedBlockIndex
===
-
1
&&
updatedResponse
)
{
...
@@ -883,30 +817,25 @@ onBeforeUnmount(() => {
...
@@ -883,30 +817,25 @@ onBeforeUnmount(() => {
isInThinkingMode
.
value
=
false
;
isInThinkingMode
.
value
=
false
;
});
});
// 处理历史记录数据
// 处理历史记录数据
const
processHistoryData
=
(
data
:
any
):
Message
[]
=>
{
const
processHistoryData
=
(
data
Array
:
any
[]
)
=>
{
const
result
:
Message
[]
=
[];
const
result
:
Message
[]
=
[];
const
date
=
dayjs
(
data
.
createTime
).
format
(
'
HH:mm
'
);
dataArray
.
forEach
((
data
)
=>
{
let
date
=
dayjs
(
data
.
startTime
).
format
(
'
YYYY-MM-DD HH:mm:ss
'
);
// 处理问题消息
// 处理问题消息
if
(
data
.
question
)
{
if
(
data
.
question
||
data
.
audioPath
)
{
let
questionContent
=
''
;
let
questionContent
=
''
;
// 检查是否为音频消息
// 检查是否为音频消息
if
(
isAudioMessage
(
data
)
)
{
if
(
data
.
audioPath
)
{
// 处理音频消息
// 处理音频消息
const
audioData
=
data
.
question
;
questionContent
=
contentTemplates
.
audio
({
questionContent
=
contentTemplates
.
audio
({
audioUrl
:
audioData
.
audioUrl
,
audioUrl
:
data
.
audioPath
audioBlob
:
audioData
.
audioBlob
});
});
}
else
{
}
else
{
// 处理文本消息
// 处理文本消息
questionContent
=
contentTemplates
.
text
(
questionContent
=
contentTemplates
.
text
(
data
.
question
);
typeof
data
.
question
===
'
string
'
?
data
.
question
:
data
.
question
.
content
||
''
);
}
}
result
.
push
({
result
.
push
({
messageType
:
'
sent
'
,
messageType
:
'
sent
'
,
avatar
:
'
我
'
,
avatar
:
'
我
'
,
...
@@ -925,8 +854,7 @@ const processHistoryData = (data: any): Message[] => {
...
@@ -925,8 +854,7 @@ const processHistoryData = (data: any): Message[] => {
],
],
});
});
}
}
// 处理AI回答消息
// 处理AI回答消息
if
(
data
.
answerInfoList
&&
Array
.
isArray
(
data
.
answerInfoList
))
{
if
(
data
.
answerInfoList
&&
Array
.
isArray
(
data
.
answerInfoList
))
{
const
aiMessage
:
Message
=
{
const
aiMessage
:
Message
=
{
messageType
:
'
received
'
,
messageType
:
'
received
'
,
...
@@ -970,9 +898,10 @@ const processHistoryData = (data: any): Message[] => {
...
@@ -970,9 +898,10 @@ const processHistoryData = (data: any): Message[] => {
result
.
push
(
aiMessage
);
result
.
push
(
aiMessage
);
}
}
}
}
});
return
result
;
return
result
;
};
};
// 获取历史会话消息
// 获取历史会话消息
const
getChatRecord
=
async
(
dialogSessionId
:
string
)
=>
{
const
getChatRecord
=
async
(
dialogSessionId
:
string
)
=>
{
...
@@ -983,7 +912,7 @@ const getChatRecord = async (dialogSessionId: string) => {
...
@@ -983,7 +912,7 @@ const getChatRecord = async (dialogSessionId: string) => {
messages
.
value
=
[...
recordList
];
messages
.
value
=
[...
recordList
];
}
}
}
else
{
}
else
{
const
response
=
await
pos
t
(
`
${
props
.
apiBaseUrl
}
/aiService/ask/list/chat/
${
dialogSessionId
}
`
,
{
},
{
const
response
=
await
ge
t
(
`
${
props
.
apiBaseUrl
}
/aiService/ask/list/chat/
${
dialogSessionId
}
`
,
{
headers
:
{
headers
:
{
Token
:
props
.
token
||
''
,
Token
:
props
.
token
||
''
,
'
x-session-id
'
:
props
.
token
||
''
,
'
x-session-id
'
:
props
.
token
||
''
,
...
@@ -1082,26 +1011,28 @@ const setupAudioPlayers = () => {
...
@@ -1082,26 +1011,28 @@ const setupAudioPlayers = () => {
const
audioPlayers
=
document
.
querySelectorAll
(
'
.audio-player
'
);
const
audioPlayers
=
document
.
querySelectorAll
(
'
.audio-player
'
);
audioPlayers
.
forEach
((
player
)
=>
{
audioPlayers
.
forEach
((
player
)
=>
{
// 移除之前的事件监听器,避免重复绑定
// 检查是否已经绑定过事件监听器
const
newPlayer
=
player
.
cloneNode
(
true
);
if
(
player
.
hasAttribute
(
'
data-audio-bound
'
))
{
player
.
parentNode
.
replaceChild
(
newPlayer
,
player
);
return
;
// 如果已经绑定过,跳过
}
const
audioMessage
=
newPlayer
.
closest
(
'
.audio-message
'
);
// 标记为已绑定
player
.
setAttribute
(
'
data-audio-bound
'
,
'
true
'
);
const
audioMessage
=
player
.
closest
(
'
.audio-message
'
);
const
audioId
=
audioMessage
?.
getAttribute
(
'
data-audio-id
'
);
const
audioId
=
audioMessage
?.
getAttribute
(
'
data-audio-id
'
);
// 修复:在DOM替换后重新获取音频元素
const
audioElement
=
audioId
?
document
.
getElementById
(
audioId
)
:
null
;
const
audioElement
=
audioId
?
document
.
getElementById
(
audioId
)
:
null
;
if
(
!
audioElement
)
{
if
(
!
audioElement
)
{
console
.
warn
(
'
未找到音频元素,audioId:
'
,
audioId
);
console
.
warn
(
'
未找到音频元素,audioId:
'
,
audioId
);
return
;
return
;
}
}
console
.
log
(
'
音频元素:
'
,
audioElement
);
// 音频播放结束,重置为总时长 - 已移除
// 音频播放结束,重置为总时长 - 已移除
audioElement
.
addEventListener
(
'
ended
'
,
()
=>
{
audioElement
.
addEventListener
(
'
ended
'
,
()
=>
{
newP
layer
.
classList
.
remove
(
'
playing
'
);
p
layer
.
classList
.
remove
(
'
playing
'
);
const
playIcon
=
newP
layer
.
querySelector
(
'
.play-icon
'
);
const
playIcon
=
p
layer
.
querySelector
(
'
.play-icon
'
);
const
pauseIcon
=
newP
layer
.
querySelector
(
'
.pause-icon
'
);
const
pauseIcon
=
p
layer
.
querySelector
(
'
.pause-icon
'
);
if
(
playIcon
&&
pauseIcon
)
{
if
(
playIcon
&&
pauseIcon
)
{
playIcon
.
style
.
display
=
'
inline
'
;
playIcon
.
style
.
display
=
'
inline
'
;
pauseIcon
.
style
.
display
=
'
none
'
;
pauseIcon
.
style
.
display
=
'
none
'
;
...
@@ -1109,7 +1040,7 @@ const setupAudioPlayers = () => {
...
@@ -1109,7 +1040,7 @@ const setupAudioPlayers = () => {
});
});
// 设置播放/暂停事件
// 设置播放/暂停事件
newP
layer
.
addEventListener
(
'
click
'
,
(
e
)
=>
{
p
layer
.
addEventListener
(
'
click
'
,
(
e
)
=>
{
e
.
stopPropagation
();
e
.
stopPropagation
();
if
(
audioElement
.
paused
)
{
if
(
audioElement
.
paused
)
{
...
@@ -1118,18 +1049,18 @@ const setupAudioPlayers = () => {
...
@@ -1118,18 +1049,18 @@ const setupAudioPlayers = () => {
audioElement
.
play
().
catch
(
error
=>
{
audioElement
.
play
().
catch
(
error
=>
{
console
.
error
(
'
播放音频失败:
'
,
error
);
console
.
error
(
'
播放音频失败:
'
,
error
);
});
});
newP
layer
.
classList
.
add
(
'
playing
'
);
p
layer
.
classList
.
add
(
'
playing
'
);
}
else
{
}
else
{
audioElement
.
pause
();
audioElement
.
pause
();
newP
layer
.
classList
.
remove
(
'
playing
'
);
p
layer
.
classList
.
remove
(
'
playing
'
);
}
}
});
});
// 音频播放事件
// 音频播放事件
audioElement
.
addEventListener
(
'
play
'
,
()
=>
{
audioElement
.
addEventListener
(
'
play
'
,
()
=>
{
newP
layer
.
classList
.
add
(
'
playing
'
);
p
layer
.
classList
.
add
(
'
playing
'
);
const
playIcon
=
newP
layer
.
querySelector
(
'
.play-icon
'
);
const
playIcon
=
p
layer
.
querySelector
(
'
.play-icon
'
);
const
pauseIcon
=
newP
layer
.
querySelector
(
'
.pause-icon
'
);
const
pauseIcon
=
p
layer
.
querySelector
(
'
.pause-icon
'
);
if
(
playIcon
&&
pauseIcon
)
{
if
(
playIcon
&&
pauseIcon
)
{
playIcon
.
style
.
display
=
'
none
'
;
playIcon
.
style
.
display
=
'
none
'
;
pauseIcon
.
style
.
display
=
'
inline
'
;
pauseIcon
.
style
.
display
=
'
inline
'
;
...
@@ -1138,9 +1069,9 @@ const setupAudioPlayers = () => {
...
@@ -1138,9 +1069,9 @@ const setupAudioPlayers = () => {
// 音频暂停事件
// 音频暂停事件
audioElement
.
addEventListener
(
'
pause
'
,
()
=>
{
audioElement
.
addEventListener
(
'
pause
'
,
()
=>
{
newP
layer
.
classList
.
remove
(
'
playing
'
);
p
layer
.
classList
.
remove
(
'
playing
'
);
const
playIcon
=
newP
layer
.
querySelector
(
'
.play-icon
'
);
const
playIcon
=
p
layer
.
querySelector
(
'
.play-icon
'
);
const
pauseIcon
=
newP
layer
.
querySelector
(
'
.pause-icon
'
);
const
pauseIcon
=
p
layer
.
querySelector
(
'
.pause-icon
'
);
if
(
playIcon
&&
pauseIcon
)
{
if
(
playIcon
&&
pauseIcon
)
{
playIcon
.
style
.
display
=
'
inline
'
;
playIcon
.
style
.
display
=
'
inline
'
;
pauseIcon
.
style
.
display
=
'
none
'
;
pauseIcon
.
style
.
display
=
'
none
'
;
...
...
src/views/components/VoiceRecognition.vue
View file @
e32996f4
...
@@ -241,14 +241,13 @@ const uploadAudioFile = async (audioBlob: Blob): Promise<string> => {
...
@@ -241,14 +241,13 @@ const uploadAudioFile = async (audioBlob: Blob): Promise<string> => {
formData
.
append
(
'
fileFolder
'
,
'
AI_TEMP
'
);
formData
.
append
(
'
fileFolder
'
,
'
AI_TEMP
'
);
// 使用项目中的axios post方法调用上传接口
// 使用项目中的axios post方法调用上传接口
const
result
=
await
post
(
'
/pedapi
/platformService/upload/v2
'
,
formData
,
{
const
result
=
await
post
(
`
${
import
.
meta
.
env
.
VITE_API_BASE_PATH
}
/platformService/upload/v2
`
,
formData
,
{
headers
:
{
headers
:
{
'
Content-Type
'
:
'
multipart/form-data
'
,
'
Content-Type
'
:
'
multipart/form-data
'
,
'
x-app-code
'
:
'
ped.qywx
'
'
x-app-code
'
:
'
ped.qywx
'
}
}
});
});
console
.
log
(
'
上传接口返回数据:
'
,
result
);
if
(
result
.
data
.
code
===
0
)
{
if
(
result
.
data
.
code
===
0
)
{
const
filePath
=
result
.
data
.
data
.
filePath
;
const
filePath
=
result
.
data
.
data
.
filePath
;
return
filePath
;
return
filePath
;
...
@@ -275,7 +274,6 @@ const sendRecordedAudio = async () => {
...
@@ -275,7 +274,6 @@ const sendRecordedAudio = async () => {
// 先调用上传接口获取URL
// 先调用上传接口获取URL
const
audioUrl
=
await
uploadAudioFile
(
audioBlob
);
const
audioUrl
=
await
uploadAudioFile
(
audioBlob
);
console
.
log
(
'
上传接口返回的filePath:
'
,
audioUrl
);
// 上传成功后触发audio事件,传递URL和Blob
// 上传成功后触发audio事件,传递URL和Blob
emit
(
'
audio
'
,
audioUrl
,
audioBlob
);
emit
(
'
audio
'
,
audioUrl
,
audioBlob
);
...
...
vite.config.js
View file @
e32996f4
import
{
defineConfig
}
from
'
vite
'
import
{
defineConfig
,
loadEnv
}
from
'
vite
'
import
vue
from
'
@vitejs/plugin-vue
'
import
vue
from
'
@vitejs/plugin-vue
'
import
{
resolve
}
from
'
path
'
;
import
{
resolve
}
from
'
path
'
;
import
fs
from
'
fs
'
;
import
fs
from
'
fs
'
;
export
default
defineConfig
({
base
:
'
/ai/
'
,
// 添加基础路径前缀
export
default
defineConfig
(({
mode
})
=>
{
plugins
:
[
vue
()],
// 加载环境变量
server
:
{
const
env
=
loadEnv
(
mode
,
process
.
cwd
(),
''
)
host
:
'
0.0.0.0
'
,
port
:
3000
,
// 清理API基础URL,移除末尾的斜杠
https
:
{
const
apiBaseUrl
=
(
env
.
VITE_API_BASE_URL
).
replace
(
/
\/
+$/
,
''
);
key
:
fs
.
readFileSync
(
'
./localhost-key.pem
'
),
const
basePath
=
env
.
VITE_BASE_PATH
;
cert
:
fs
.
readFileSync
(
'
./localhost.pem
'
)
},
return
{
// 添加history fallback配置
base
:
basePath
,
historyApiFallback
:
{
plugins
:
[
vue
()],
rewrites
:
[
server
:
{
{
from
:
/^
\/
ai
\/
.*$/
,
to
:
'
/ai/index.html
'
}
host
:
'
0.0.0.0
'
,
]
port
:
3000
,
},
https
:
{
proxy
:
{
key
:
fs
.
readFileSync
(
'
./localhost-key.pem
'
),
'
/pedapi
'
:
{
cert
:
fs
.
readFileSync
(
'
./localhost.pem
'
)
target
:
'
http://peddev.cmic.com.cn
'
,
changeOrigin
:
true
,
// 解决跨域问题
secure
:
false
,
// 允许不安全的SSL连接
configure
:
(
proxy
,
options
)
=>
{
proxy
.
on
(
'
error
'
,
(
err
,
req
,
res
)
=>
{
console
.
log
(
'
代理错误:
'
,
err
);
});
proxy
.
on
(
'
proxyReq
'
,
(
proxyReq
,
req
,
res
)
=>
{
console
.
log
(
'
发送请求到:
'
,
options
.
target
);
});
}
},
},
'
/ifile
'
:
{
// 添加history fallback配置
target
:
'
http://peddev.cmic.com.cn
'
,
historyApiFallback
:
{
changeOrigin
:
true
,
// 解决跨域问题
rewrites
:
[
secure
:
false
,
// 允许不安全的SSL连接
{
from
:
/^
\/
ai
\/
.*$/
,
to
:
'
/ai/index.html
'
}
]
},
},
'
/WeChatOauth2
'
:
{
proxy
:
{
target
:
'
http://peddev.cmic.com.cn
'
,
// 同时配置两种路径的代理
changeOrigin
:
true
,
// 解决跨域问题
'
/pedapi
'
:
{
secure
:
false
,
// 允许不安全的SSL连接
target
:
apiBaseUrl
,
changeOrigin
:
true
,
secure
:
false
,
configure
:
(
proxy
,
options
)
=>
{
proxy
.
on
(
'
error
'
,
(
err
,
req
,
res
)
=>
{
console
.
log
(
'
代理错误:
'
,
err
);
});
proxy
.
on
(
'
proxyReq
'
,
(
proxyReq
,
req
,
res
)
=>
{
console
.
log
(
'
发送请求到:
'
,
options
.
target
);
});
}
},
'
/aiService
'
:
{
target
:
apiBaseUrl
,
changeOrigin
:
true
,
secure
:
false
,
},
'
/ifile
'
:
{
target
:
apiBaseUrl
,
changeOrigin
:
true
,
secure
:
false
,
},
'
/WeChatOauth2
'
:
{
target
:
apiBaseUrl
,
changeOrigin
:
true
,
secure
:
false
,
}
},
},
build
:
{
outDir
:
'
dist
'
,
assetsDir
:
'
assets
'
,
sourcemap
:
false
},
resolve
:
{
alias
:
{
'
@
'
:
resolve
(
__dirname
,
'
src
'
),
'
echarts
'
:
'
echarts/dist/echarts.esm.js
'
}
}
},
},
},
}
build
:
{
outDir
:
'
dist
'
,
assetsDir
:
'
assets
'
,
sourcemap
:
false
},
resolve
:
{
alias
:
{
'
@
'
:
resolve
(
__dirname
,
'
src
'
),
'
echarts
'
:
'
echarts/dist/echarts.esm.js
'
}
},
})
})
\ No newline at end of file
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