mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +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 mcpTools = ref<string[]>([])
|
||||
|
||||
// 初始化时从本地存储加载MCP地址
|
||||
if (uni.getStorageSync('cachedMcpAddress_' + agentId.value)) {
|
||||
mcpAddress.value = uni.getStorageSync('cachedMcpAddress_' + agentId.value)
|
||||
}
|
||||
|
||||
// 参数编辑相关
|
||||
const showParamDialog = ref(false)
|
||||
const currentFunction = ref<any>(null)
|
||||
@@ -56,12 +61,23 @@ async function mergeFunctions() {
|
||||
)
|
||||
|
||||
if (agentId.value) {
|
||||
const [address, tools] = await Promise.all([
|
||||
getMcpAddress(agentId.value),
|
||||
getMcpTools(agentId.value),
|
||||
])
|
||||
mcpAddress.value = address
|
||||
mcpTools.value = tools || []
|
||||
// 优先获取并显示MCP地址
|
||||
try {
|
||||
const address = await getMcpAddress(agentId.value)
|
||||
mcpAddress.value = address
|
||||
// 缓存到本地存储,下次打开页面可以立即显示
|
||||
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 urlError = ref('')
|
||||
|
||||
// 系统信息(保留)
|
||||
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() {
|
||||
if (!baseUrlInput.value || !/^https?:\/\//.test(baseUrlInput.value)) {
|
||||
toast.warning('请输入有效的服务端地址(以 http 或 https 开头)')
|
||||
async function saveServerBaseUrl() {
|
||||
if (!baseUrlInput.value || !/^https?:\/\/.+\/xiaozhi$/.test(baseUrlInput.value)) {
|
||||
toast.warning('请输入有效的服务端地址(以 http 或 https 开头,并以 /xiaozhi 结尾)')
|
||||
return
|
||||
}
|
||||
|
||||
// 测试地址有效性
|
||||
const isServerValid = await testServerBaseUrl()
|
||||
if (!isServerValid) {
|
||||
return
|
||||
}
|
||||
setServerBaseUrlOverride(baseUrlInput.value)
|
||||
@@ -64,20 +113,20 @@ function saveServerBaseUrl() {
|
||||
clearAllCacheAfterUrlChange()
|
||||
|
||||
uni.showModal({
|
||||
title: '重启应用',
|
||||
content: '服务端地址已保存并清空缓存,是否立即重启生效?',
|
||||
confirmText: '立即重启',
|
||||
cancelText: '稍后',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
restartApp()
|
||||
}
|
||||
else {
|
||||
toast.success('已保存,可稍后手动重启应用')
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
title: '重启应用',
|
||||
content: '服务端地址已保存并清空缓存,是否立即重启生效?',
|
||||
confirmText: '立即重启',
|
||||
cancelText: '稍后',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
restartApp()
|
||||
}
|
||||
else {
|
||||
toast.success('已保存,可稍后手动重启应用')
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 重置为 env 默认
|
||||
function resetServerBaseUrl() {
|
||||
@@ -173,7 +222,7 @@ function showAbout() {
|
||||
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`,
|
||||
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,
|
||||
confirmText: '确定',
|
||||
})
|
||||
@@ -201,7 +250,6 @@ onMounted(async () => {
|
||||
</text>
|
||||
</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"
|
||||
style="box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);">
|
||||
<view class="mb-[24rpx]">
|
||||
@@ -214,20 +262,22 @@ onMounted(async () => {
|
||||
</view>
|
||||
|
||||
<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">
|
||||
<wd-input
|
||||
v-model="baseUrlInput"
|
||||
type="text"
|
||||
clearable
|
||||
:maxlength="200"
|
||||
placeholder="输入服务端地址,如 https://example.com/api"
|
||||
placeholder="输入服务端地址,如 https://example.com/xiaozhi"
|
||||
custom-class="!border-none !bg-transparent h-[88rpx] px-[24rpx] items-center"
|
||||
input-class="text-[28rpx] text-[#232338]"
|
||||
@input="validateUrl"
|
||||
@blur="validateUrl"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="urlError" class="mt-[8rpx] block text-[24rpx] text-[#ff4d4f]">
|
||||
{{ urlError }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="flex gap-[16rpx]">
|
||||
@@ -320,7 +370,8 @@ onMounted(async () => {
|
||||
</view>
|
||||
|
||||
<!-- 底部安全距离 -->
|
||||
<view style="height: env(safe-area-inset-bottom);" />
|
||||
<!-- 底部安全距离 -->
|
||||
<view style="height: env(safe-area-inset-bottom);" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user