mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-26 00:53:54 +08:00
Merge pull request #2082 from xinnan-tech/fix_mobile
fix:修复mcp地址显示慢,增加服务端地址校验
This commit is contained in:
@@ -28,6 +28,11 @@ const agentId = computed(() => pluginStore.currentAgentId)
|
|||||||
const mcpAddress = ref('')
|
const mcpAddress = ref('')
|
||||||
const mcpTools = ref<string[]>([])
|
const mcpTools = ref<string[]>([])
|
||||||
|
|
||||||
|
// 初始化时从本地存储加载MCP地址
|
||||||
|
if (uni.getStorageSync('cachedMcpAddress_' + agentId.value)) {
|
||||||
|
mcpAddress.value = uni.getStorageSync('cachedMcpAddress_' + agentId.value)
|
||||||
|
}
|
||||||
|
|
||||||
// 参数编辑相关
|
// 参数编辑相关
|
||||||
const showParamDialog = ref(false)
|
const showParamDialog = ref(false)
|
||||||
const currentFunction = ref<any>(null)
|
const currentFunction = ref<any>(null)
|
||||||
@@ -56,12 +61,23 @@ async function mergeFunctions() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (agentId.value) {
|
if (agentId.value) {
|
||||||
const [address, tools] = await Promise.all([
|
// 优先获取并显示MCP地址
|
||||||
getMcpAddress(agentId.value),
|
try {
|
||||||
getMcpTools(agentId.value),
|
const address = await getMcpAddress(agentId.value)
|
||||||
])
|
mcpAddress.value = address
|
||||||
mcpAddress.value = address
|
// 缓存到本地存储,下次打开页面可以立即显示
|
||||||
mcpTools.value = tools || []
|
uni.setStorageSync('cachedMcpAddress_' + agentId.value, address)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取MCP地址失败:', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步获取MCP工具列表,不阻塞UI显示
|
||||||
|
try {
|
||||||
|
const tools = await getMcpTools(agentId.value)
|
||||||
|
mcpTools.value = tools || []
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取MCP工具列表失败:', error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const cacheInfo = reactive({
|
|||||||
|
|
||||||
// 服务端地址设置
|
// 服务端地址设置
|
||||||
const baseUrlInput = ref('')
|
const baseUrlInput = ref('')
|
||||||
|
const urlError = ref('')
|
||||||
|
|
||||||
// 系统信息(保留)
|
// 系统信息(保留)
|
||||||
const systemInfo = computed(() => {
|
const systemInfo = computed(() => {
|
||||||
@@ -52,10 +53,58 @@ function getCacheInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证URL格式
|
||||||
|
function validateUrl() {
|
||||||
|
urlError.value = ''
|
||||||
|
|
||||||
|
if (!baseUrlInput.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^https?:\/\/.+\/xiaozhi$/.test(baseUrlInput.value)) {
|
||||||
|
urlError.value = '请输入有效的服务端地址(以 http 或 https 开头,并以 /xiaozhi 结尾)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试服务端地址
|
||||||
|
async function testServerBaseUrl() {
|
||||||
|
// 先清除错误信息
|
||||||
|
urlError.value = ''
|
||||||
|
|
||||||
|
if (!baseUrlInput.value || !/^https?:\/\/.+\/xiaozhi$/.test(baseUrlInput.value)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await uni.request({
|
||||||
|
url: `${baseUrlInput.value}/api/ping`,
|
||||||
|
method: 'GET',
|
||||||
|
timeout: 3000
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
toast.error('无效地址,请检查服务端是否启动或网络连接是否正常')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('测试服务端地址失败:', error)
|
||||||
|
toast.error('无效地址,请检查服务端是否启动或网络连接是否正常')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 保存服务端地址
|
// 保存服务端地址
|
||||||
function saveServerBaseUrl() {
|
async function saveServerBaseUrl() {
|
||||||
if (!baseUrlInput.value || !/^https?:\/\//.test(baseUrlInput.value)) {
|
if (!baseUrlInput.value || !/^https?:\/\/.+\/xiaozhi$/.test(baseUrlInput.value)) {
|
||||||
toast.warning('请输入有效的服务端地址(以 http 或 https 开头)')
|
toast.warning('请输入有效的服务端地址(以 http 或 https 开头,并以 /xiaozhi 结尾)')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试地址有效性
|
||||||
|
const isServerValid = await testServerBaseUrl()
|
||||||
|
if (!isServerValid) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setServerBaseUrlOverride(baseUrlInput.value)
|
setServerBaseUrlOverride(baseUrlInput.value)
|
||||||
@@ -64,20 +113,20 @@ function saveServerBaseUrl() {
|
|||||||
clearAllCacheAfterUrlChange()
|
clearAllCacheAfterUrlChange()
|
||||||
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '重启应用',
|
title: '重启应用',
|
||||||
content: '服务端地址已保存并清空缓存,是否立即重启生效?',
|
content: '服务端地址已保存并清空缓存,是否立即重启生效?',
|
||||||
confirmText: '立即重启',
|
confirmText: '立即重启',
|
||||||
cancelText: '稍后',
|
cancelText: '稍后',
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
restartApp()
|
restartApp()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
toast.success('已保存,可稍后手动重启应用')
|
toast.success('已保存,可稍后手动重启应用')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置为 env 默认
|
// 重置为 env 默认
|
||||||
function resetServerBaseUrl() {
|
function resetServerBaseUrl() {
|
||||||
@@ -173,7 +222,7 @@ function showAbout() {
|
|||||||
title: `关于${import.meta.env.VITE_APP_TITLE}`,
|
title: `关于${import.meta.env.VITE_APP_TITLE}`,
|
||||||
content: `${import.meta.env.VITE_APP_TITLE}\n\n基于 Vue.js 3 + uni-app 构建的跨平台移动端管理应用,为小智ESP32智能硬件提供设备管理、智能体配置等功能。\n\n© 2025 xiaozhi-esp32-server`,
|
content: `${import.meta.env.VITE_APP_TITLE}\n\n基于 Vue.js 3 + uni-app 构建的跨平台移动端管理应用,为小智ESP32智能硬件提供设备管理、智能体配置等功能。\n\n© 2025 xiaozhi-esp32-server`,
|
||||||
title: `关于小智智控台`,
|
title: `关于小智智控台`,
|
||||||
content: `小智智控台\n\n基于 Vue.js 3 + uni-app 构建的跨平台移动端管理应用,为小智智控台ESP32智能硬件提供设备管理、智能体配置等功能。\n\n© 2025 xiaozhi-esp32-server 0.7.5`,
|
content: `小智智控台\n\n基于 Vue.js 3 + uni-app 构建的跨平台移动端管理应用,为小智ESP32智能硬件提供设备管理、智能体配置等功能。\n\n© 2025 xiaozhi-esp32-server 0.7.5`,
|
||||||
showCancel: false,
|
showCancel: false,
|
||||||
confirmText: '确定',
|
confirmText: '确定',
|
||||||
})
|
})
|
||||||
@@ -201,7 +250,6 @@ onMounted(async () => {
|
|||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="border border-[#eeeeee] rounded-[24rpx] bg-[#fbfbfb] p-[32rpx]"
|
|
||||||
<view class="border border-[#eeeeee] rounded-[24rpx] bg-[#fbfbfb] p-[32rpx] overflow-hidden"
|
<view class="border border-[#eeeeee] rounded-[24rpx] bg-[#fbfbfb] p-[32rpx] overflow-hidden"
|
||||||
style="box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);">
|
style="box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);">
|
||||||
<view class="mb-[24rpx]">
|
<view class="mb-[24rpx]">
|
||||||
@@ -214,20 +262,22 @@ onMounted(async () => {
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="mb-[24rpx]">
|
<view class="mb-[24rpx]">
|
||||||
<input v-model="baseUrlInput"
|
|
||||||
class="h-[88rpx] w-full border border-[#eeeeee] rounded-[16rpx] bg-[#f5f7fb] px-[24rpx] text-[28rpx] text-[#232338] transition-all focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3] focus:shadow-[0_0_0_4rpx_rgba(51,108,255,0.1)]"
|
|
||||||
type="text" placeholder="输入服务端地址,如 https://example.com/api">
|
|
||||||
<view class="w-full rounded-[16rpx] border border-[#eeeeee] bg-[#f5f7fb] overflow-hidden">
|
<view class="w-full rounded-[16rpx] border border-[#eeeeee] bg-[#f5f7fb] overflow-hidden">
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="baseUrlInput"
|
v-model="baseUrlInput"
|
||||||
type="text"
|
type="text"
|
||||||
clearable
|
clearable
|
||||||
:maxlength="200"
|
:maxlength="200"
|
||||||
placeholder="输入服务端地址,如 https://example.com/api"
|
placeholder="输入服务端地址,如 https://example.com/xiaozhi"
|
||||||
custom-class="!border-none !bg-transparent h-[88rpx] px-[24rpx] items-center"
|
custom-class="!border-none !bg-transparent h-[88rpx] px-[24rpx] items-center"
|
||||||
input-class="text-[28rpx] text-[#232338]"
|
input-class="text-[28rpx] text-[#232338]"
|
||||||
|
@input="validateUrl"
|
||||||
|
@blur="validateUrl"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
<text v-if="urlError" class="mt-[8rpx] block text-[24rpx] text-[#ff4d4f]">
|
||||||
|
{{ urlError }}
|
||||||
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="flex gap-[16rpx]">
|
<view class="flex gap-[16rpx]">
|
||||||
@@ -320,7 +370,8 @@ onMounted(async () => {
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部安全距离 -->
|
<!-- 底部安全距离 -->
|
||||||
<view style="height: env(safe-area-inset-bottom);" />
|
<!-- 底部安全距离 -->
|
||||||
|
<view style="height: env(safe-area-inset-bottom);" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user