mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-29 18:23:59 +08:00
style: 优化移动端页面样式,调整组件布局,增强用户体验
This commit is contained in:
@@ -432,7 +432,7 @@ function loadPluginFunctions() {
|
|||||||
getPluginFunctions().then((res) => {
|
getPluginFunctions().then((res) => {
|
||||||
const processedFunctions = res?.map((item) => {
|
const processedFunctions = res?.map((item) => {
|
||||||
const meta = JSON.parse(item.fields || '[]')
|
const meta = JSON.parse(item.fields || '[]')
|
||||||
const params = meta.reduce((m, f) => {
|
const params = meta.reduce((m: any, f: any) => {
|
||||||
m[f.key] = f.default
|
m[f.key] = f.default
|
||||||
return m
|
return m
|
||||||
}, {})
|
}, {})
|
||||||
@@ -497,7 +497,7 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="page-container">
|
<view class="h-screen flex flex-col bg-[#f5f7fb]">
|
||||||
<!-- 导航栏 -->
|
<!-- 导航栏 -->
|
||||||
<wd-navbar title="助手设置" safe-area-inset-top>
|
<wd-navbar title="助手设置" safe-area-inset-top>
|
||||||
<template #left>
|
<template #left>
|
||||||
@@ -512,40 +512,40 @@ onMounted(async () => {
|
|||||||
<scroll-view
|
<scroll-view
|
||||||
scroll-y
|
scroll-y
|
||||||
:style="{ height: `calc(100vh - ${safeAreaInsets?.top || 0}px - 120rpx)` }"
|
:style="{ height: `calc(100vh - ${safeAreaInsets?.top || 0}px - 120rpx)` }"
|
||||||
class="main-content"
|
class="flex-1 px-[20rpx] bg-[#f5f7fb] box-border"
|
||||||
enable-back-to-top
|
enable-back-to-top
|
||||||
>
|
>
|
||||||
<!-- 基础信息标题 -->
|
<!-- 基础信息标题 -->
|
||||||
<view class="section-title">
|
<view class="pb-[20rpx] first:pt-[20rpx]">
|
||||||
<text class="title-text">
|
<text class="text-[36rpx] font-bold text-[#232338]">
|
||||||
基础信息
|
基础信息
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 基础信息卡片 -->
|
<!-- 基础信息卡片 -->
|
||||||
<view class="settings-card plain-card">
|
<view class="bg-[#fbfbfb] rounded-[20rpx] mb-[24rpx] p-[24rpx] border border-[#eeeeee]" style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);">
|
||||||
<view class="form-field">
|
<view class="mb-[24rpx] last:mb-0">
|
||||||
<text class="field-label">
|
<text class="block text-[28rpx] text-[#232338] font-medium mb-[12rpx]">
|
||||||
助手昵称
|
助手昵称
|
||||||
</text>
|
</text>
|
||||||
<input
|
<input
|
||||||
v-model="formData.agentName"
|
v-model="formData.agentName"
|
||||||
class="field-input"
|
class="w-full h-[80rpx] p-[16rpx_20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] text-[28rpx] text-[#232338] box-border leading-[1.4] outline-none focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入助手昵称"
|
placeholder="请输入助手昵称"
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="form-field">
|
<view class="mb-[24rpx] last:mb-0">
|
||||||
<text class="field-label">
|
<text class="block text-[28rpx] text-[#232338] font-medium mb-[12rpx]">
|
||||||
角色模式
|
角色模式
|
||||||
</text>
|
</text>
|
||||||
<view class="role-tags">
|
<view class="flex flex-wrap gap-[12rpx] mt-0">
|
||||||
<view
|
<view
|
||||||
v-for="template in roleTemplates"
|
v-for="template in roleTemplates"
|
||||||
:key="template.id"
|
:key="template.id"
|
||||||
class="role-tag"
|
class="px-[24rpx] py-[12rpx] bg-[rgba(51,108,255,0.1)] text-[#336cff] rounded-[20rpx] text-[24rpx] border border-[rgba(51,108,255,0.2)] cursor-pointer transition-all duration-300"
|
||||||
:class="{ active: selectedTemplateId === template.id }"
|
:class="{ 'bg-[#336cff] text-white border-[#336cff]': selectedTemplateId === template.id }"
|
||||||
@click="selectRoleTemplate(template.id)"
|
@click="selectRoleTemplate(template.id)"
|
||||||
>
|
>
|
||||||
{{ template.agentName }}
|
{{ template.agentName }}
|
||||||
@@ -553,129 +553,129 @@ onMounted(async () => {
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="form-field">
|
<view class="mb-[24rpx] last:mb-0">
|
||||||
<text class="field-label">
|
<text class="block text-[28rpx] text-[#232338] font-medium mb-[12rpx]">
|
||||||
角色介绍
|
角色介绍
|
||||||
</text>
|
</text>
|
||||||
<textarea
|
<textarea
|
||||||
v-model="formData.systemPrompt"
|
v-model="formData.systemPrompt"
|
||||||
:maxlength="2000"
|
:maxlength="2000"
|
||||||
placeholder="请输入角色介绍"
|
placeholder="请输入角色介绍"
|
||||||
class="field-textarea"
|
class="w-full h-[500rpx] p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] text-[26rpx] text-[#232338] leading-[1.6] resize-none box-border outline-none break-words break-all focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||||
/>
|
/>
|
||||||
<view class="char-count">
|
<view class="text-right text-[22rpx] text-[#9d9ea3] mt-[8rpx]">
|
||||||
{{ (formData.systemPrompt || '').length }}/2000
|
{{ (formData.systemPrompt || '').length }}/2000
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 模型配置标题 -->
|
<!-- 模型配置标题 -->
|
||||||
<view class="section-title">
|
<view class="pb-[20rpx]">
|
||||||
<text class="title-text">
|
<text class="text-[36rpx] font-bold text-[#232338]">
|
||||||
模型配置
|
模型配置
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 模型配置卡片 -->
|
<!-- 模型配置卡片 -->
|
||||||
<view class="settings-card plain-card">
|
<view class="bg-[#fbfbfb] rounded-[20rpx] mb-[24rpx] p-[24rpx] border border-[#eeeeee]" style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);">
|
||||||
<view class="model-grid">
|
<view class="flex flex-col gap-[16rpx]">
|
||||||
<view class="model-item" @click="openPicker('vad')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('vad')">
|
||||||
<text class="model-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
语音活动检测
|
语音活动检测
|
||||||
</text>
|
</text>
|
||||||
<text class="model-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.vad }}
|
{{ displayNames.vad }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="model-item" @click="openPicker('asr')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('asr')">
|
||||||
<text class="model-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
语音识别
|
语音识别
|
||||||
</text>
|
</text>
|
||||||
<text class="model-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.asr }}
|
{{ displayNames.asr }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="model-item" @click="openPicker('llm')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('llm')">
|
||||||
<text class="model-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
大语言模型
|
大语言模型
|
||||||
</text>
|
</text>
|
||||||
<text class="model-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.llm }}
|
{{ displayNames.llm }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="model-item" @click="openPicker('vllm')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('vllm')">
|
||||||
<text class="model-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
视觉大模型
|
视觉大模型
|
||||||
</text>
|
</text>
|
||||||
<text class="model-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.vllm }}
|
{{ displayNames.vllm }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="model-item" @click="openPicker('intent')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('intent')">
|
||||||
<text class="model-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
意图识别
|
意图识别
|
||||||
</text>
|
</text>
|
||||||
<text class="model-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.intent }}
|
{{ displayNames.intent }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="model-item collapsible" @click="openPicker('memory')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('memory')">
|
||||||
<text class="model-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
记忆
|
记忆
|
||||||
</text>
|
</text>
|
||||||
<text class="model-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.memory }}
|
{{ displayNames.memory }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 语音设置标题 -->
|
<!-- 语音设置标题 -->
|
||||||
<view class="section-title">
|
<view class="pb-[20rpx]">
|
||||||
<text class="title-text">
|
<text class="text-[36rpx] font-bold text-[#232338]">
|
||||||
语音设置
|
语音设置
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 语音设置卡片 -->
|
<!-- 语音设置卡片 -->
|
||||||
<view class="settings-card plain-card">
|
<view class="bg-[#fbfbfb] rounded-[20rpx] mb-[24rpx] p-[24rpx] border border-[#eeeeee]" style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);">
|
||||||
<view class="voice-settings">
|
<view class="flex flex-col gap-[16rpx]">
|
||||||
<view class="voice-item" @click="openPicker('tts')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('tts')">
|
||||||
<text class="voice-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
语音合成
|
语音合成
|
||||||
</text>
|
</text>
|
||||||
<text class="voice-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.tts }}
|
{{ displayNames.tts }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="voice-item" @click="openPicker('voiceprint')">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] cursor-pointer transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('voiceprint')">
|
||||||
<text class="voice-label">
|
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||||
角色音色
|
角色音色
|
||||||
</text>
|
</text>
|
||||||
<text class="voice-value">
|
<text class="flex-1 text-right text-[26rpx] text-[#65686f] mx-[16rpx]">
|
||||||
{{ displayNames.voiceprint }}
|
{{ displayNames.voiceprint }}
|
||||||
</text>
|
</text>
|
||||||
<wd-icon name="arrow-right" custom-class="arrow-icon" />
|
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="edit-functions">
|
<view class="flex items-center justify-between p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee]">
|
||||||
<view class="text-[28rpx] text-[#232338] fw-[500]">
|
<view class="text-[28rpx] text-[#232338] font-medium">
|
||||||
插件
|
插件
|
||||||
</view>
|
</view>
|
||||||
<view class="function-btn" @click="handleTools">
|
<view class="px-[24rpx] py-[12rpx] bg-[rgba(51,108,255,0.1)] text-[#336cff] rounded-[20rpx] text-[24rpx] cursor-pointer transition-all duration-300 active:bg-[#336cff] active:text-white" @click="handleTools">
|
||||||
<text>编辑功能</text>
|
<text>编辑功能</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -683,31 +683,31 @@ onMounted(async () => {
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 记忆历史标题 -->
|
<!-- 记忆历史标题 -->
|
||||||
<view class="section-title">
|
<view class="pb-[20rpx]">
|
||||||
<text class="title-text">
|
<text class="text-[36rpx] font-bold text-[#232338]">
|
||||||
历史记忆
|
历史记忆
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 记忆历史卡片 -->
|
<!-- 记忆历史卡片 -->
|
||||||
<view class="settings-card plain-card">
|
<view class="bg-[#fbfbfb] rounded-[20rpx] mb-[24rpx] p-[24rpx] border border-[#eeeeee]" style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);">
|
||||||
<view class="form-field">
|
<view class="mb-[24rpx] last:mb-0">
|
||||||
<textarea
|
<textarea
|
||||||
v-model="formData.summaryMemory"
|
v-model="formData.summaryMemory"
|
||||||
placeholder="记忆内容"
|
placeholder="记忆内容"
|
||||||
disabled
|
disabled
|
||||||
class="field-textarea disabled-textarea"
|
class="w-full h-[500rpx] p-[20rpx] bg-[#f0f0f0] text-[#65686f] opacity-80 rounded-[12rpx] border border-[#eeeeee] text-[26rpx] leading-[1.6] resize-none box-border outline-none break-words break-all"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 保存按钮 -->
|
<!-- 保存按钮 -->
|
||||||
<view class="save-section">
|
<view class="p-0 mt-[40rpx]">
|
||||||
<wd-button
|
<wd-button
|
||||||
type="primary"
|
type="primary"
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
:disabled="saving"
|
:disabled="saving"
|
||||||
custom-class="save-btn"
|
custom-class="w-full h-[80rpx] rounded-[16rpx] text-[30rpx] font-semibold bg-[#336cff] active:bg-[#2d5bd1]"
|
||||||
@click="saveAgent"
|
@click="saveAgent"
|
||||||
>
|
>
|
||||||
{{ saving ? '保存中...' : '保存' }}
|
{{ saving ? '保存中...' : '保存' }}
|
||||||
@@ -780,306 +780,4 @@ onMounted(async () => {
|
|||||||
@select="handleAgentSwitch"
|
@select="handleAgentSwitch"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.page-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100vh;
|
|
||||||
background: #f5f7fb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-bar {
|
|
||||||
background: #ffffff;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-content {
|
|
||||||
flex: 1;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
padding: 0 0 20rpx 0;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
padding-top: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-text {
|
|
||||||
font-size: 36rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #232338;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-card.plain-card {
|
|
||||||
padding: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-card {
|
|
||||||
background: #fbfbfb;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
padding: 32rpx;
|
|
||||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field {
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-label {
|
|
||||||
display: block;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #232338;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 12rpx;
|
|
||||||
|
|
||||||
&.disabled-label {
|
|
||||||
color: #65686f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 16rpx 20rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #232338;
|
|
||||||
box-sizing: border-box;
|
|
||||||
line-height: 1.4;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: #336cff;
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: #9d9ea3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-textarea {
|
|
||||||
width: 100%;
|
|
||||||
height: 500rpx;
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #232338;
|
|
||||||
line-height: 1.6;
|
|
||||||
resize: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
outline: none;
|
|
||||||
word-wrap: break-word;
|
|
||||||
word-break: break-all;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: #336cff;
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled-textarea {
|
|
||||||
background: #f0f0f0;
|
|
||||||
color: #65686f;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: #9d9ea3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.char-count {
|
|
||||||
text-align: right;
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #9d9ea3;
|
|
||||||
margin-top: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.role-tags {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12rpx;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.role-tag {
|
|
||||||
padding: 12rpx 24rpx;
|
|
||||||
background: rgba(51, 108, 255, 0.1);
|
|
||||||
color: #336cff;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
border: 1rpx solid rgba(51, 108, 255, 0.2);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: #336cff;
|
|
||||||
color: white;
|
|
||||||
border-color: #336cff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #eef3ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-label {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #232338;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-value {
|
|
||||||
flex: 1;
|
|
||||||
text-align: right;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #65686f;
|
|
||||||
margin: 0 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arrow-icon) {
|
|
||||||
font-size: 20rpx;
|
|
||||||
color: #9d9ea3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.voice-settings {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.voice-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #eef3ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.voice-label {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #232338;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.voice-value {
|
|
||||||
flex: 1;
|
|
||||||
text-align: right;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #65686f;
|
|
||||||
margin: 0 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.arrow-icon) {
|
|
||||||
font-size: 20rpx;
|
|
||||||
color: #9d9ea3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-functions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
|
|
||||||
.function-dots {
|
|
||||||
display: flex;
|
|
||||||
gap: 12rpx;
|
|
||||||
|
|
||||||
.dot {
|
|
||||||
width: 16rpx;
|
|
||||||
height: 16rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
&.red {
|
|
||||||
background: #ff4d4f;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.yellow {
|
|
||||||
background: #faad14;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.green {
|
|
||||||
background: #52c41a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.function-btn {
|
|
||||||
padding: 12rpx 24rpx;
|
|
||||||
background: rgba(51, 108, 255, 0.1);
|
|
||||||
color: #336cff;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #336cff;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-section {
|
|
||||||
padding: 0;
|
|
||||||
margin-top: 40rpx;
|
|
||||||
|
|
||||||
:deep(.save-btn) {
|
|
||||||
width: 100%;
|
|
||||||
height: 80rpx;
|
|
||||||
border-radius: 16rpx;
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
background: #336cff;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #2d5bd1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -244,7 +244,7 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="page-container">
|
<view class="h-screen flex flex-col bg-[#f5f7fb]">
|
||||||
<!-- 头部导航 -->
|
<!-- 头部导航 -->
|
||||||
<wd-navbar
|
<wd-navbar
|
||||||
title=""
|
title=""
|
||||||
@@ -261,7 +261,7 @@ onMounted(async () => {
|
|||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<scroll-view
|
<scroll-view
|
||||||
scroll-y
|
scroll-y
|
||||||
class="content-scroll-view box-border px-[20rpx]"
|
class="flex-1 box-border px-[20rpx] bg-transparent"
|
||||||
:style="{ height: 'calc(100vh - 120rpx)' }"
|
:style="{ height: 'calc(100vh - 120rpx)' }"
|
||||||
:scroll-with-animation="true"
|
:scroll-with-animation="true"
|
||||||
>
|
>
|
||||||
@@ -284,7 +284,7 @@ onMounted(async () => {
|
|||||||
<!-- 未选插件 -->
|
<!-- 未选插件 -->
|
||||||
<scroll-view
|
<scroll-view
|
||||||
v-if="currentSegmented === '未选'"
|
v-if="currentSegmented === '未选'"
|
||||||
class="plugin-scroll-view"
|
class="max-h-[600rpx] bg-transparent"
|
||||||
scroll-y
|
scroll-y
|
||||||
>
|
>
|
||||||
<view
|
<view
|
||||||
@@ -322,7 +322,7 @@ onMounted(async () => {
|
|||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<!-- 已选插件 -->
|
<!-- 已选插件 -->
|
||||||
<scroll-view v-else class="plugin-scroll-view" scroll-y>
|
<scroll-view v-else class="max-h-[600rpx] bg-transparent" scroll-y>
|
||||||
<view
|
<view
|
||||||
v-if="selectedList.length === 0"
|
v-if="selectedList.length === 0"
|
||||||
class="h-[400rpx] flex items-center justify-center"
|
class="h-[400rpx] flex items-center justify-center"
|
||||||
@@ -398,7 +398,7 @@ onMounted(async () => {
|
|||||||
</view>
|
</view>
|
||||||
<!-- 工具列表 -->
|
<!-- 工具列表 -->
|
||||||
<view class="mt-[20rpx] flex-1 overflow-hidden">
|
<view class="mt-[20rpx] flex-1 overflow-hidden">
|
||||||
<scroll-view class="plugin-scroll-view" scroll-y>
|
<scroll-view class="max-h-[600rpx] bg-transparent" scroll-y>
|
||||||
<view
|
<view
|
||||||
v-if="mcpTools && mcpTools.length === 0"
|
v-if="mcpTools && mcpTools.length === 0"
|
||||||
class="h-[400rpx] flex items-center justify-center"
|
class="h-[400rpx] flex items-center justify-center"
|
||||||
@@ -431,47 +431,48 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<scroll-view
|
<scroll-view
|
||||||
scroll-y
|
scroll-y
|
||||||
class="param-scroll-container"
|
class="bg-[#f5f7fb]"
|
||||||
:style="{ height: 'calc(75vh - 60rpx)' }"
|
:style="{ height: 'calc(75vh - 60rpx)' }"
|
||||||
>
|
>
|
||||||
<view class="param-content">
|
<view class="p-[30rpx] pb-[40rpx]">
|
||||||
<!-- 无参数提示 -->
|
<!-- 无参数提示 -->
|
||||||
<view
|
<view
|
||||||
v-if="
|
v-if="
|
||||||
!currentFunction?.fieldsMeta
|
!currentFunction?.fieldsMeta
|
||||||
|| currentFunction.fieldsMeta.length === 0
|
|| currentFunction.fieldsMeta.length === 0
|
||||||
"
|
"
|
||||||
class="empty-params"
|
class="h-[400rpx] flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<text class="empty-text">
|
<text class="text-[28rpx] text-[#999]">
|
||||||
{{ currentFunction?.name }} 无需配置参数
|
{{ currentFunction?.name }} 无需配置参数
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 参数表单 - 卡片式布局 -->
|
<!-- 参数表单 - 卡片式布局 -->
|
||||||
<view v-else class="param-cards">
|
<view v-else class="flex flex-col gap-[24rpx]">
|
||||||
<view
|
<view
|
||||||
v-for="field in currentFunction.fieldsMeta"
|
v-for="field in currentFunction.fieldsMeta"
|
||||||
:key="field.key"
|
:key="field.key"
|
||||||
class="param-card"
|
class="bg-white rounded-[20rpx] p-[30rpx] border border-[#eeeeee]"
|
||||||
|
style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);"
|
||||||
>
|
>
|
||||||
<!-- 字段信息 -->
|
<!-- 字段信息 -->
|
||||||
<view class="field-info">
|
<view class="mb-[24rpx]">
|
||||||
<text class="field-label">
|
<text class="block text-[32rpx] font-medium text-[#232338] mb-[8rpx]">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
</text>
|
</text>
|
||||||
<text v-if="getFieldRemark(field)" class="field-desc">
|
<text v-if="getFieldRemark(field)" class="block text-[24rpx] text-[#65686f] leading-[1.5]">
|
||||||
{{ getFieldRemark(field) }}
|
{{ getFieldRemark(field) }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 输入控件 -->
|
<!-- 输入控件 -->
|
||||||
<view class="field-input-container">
|
<view>
|
||||||
<!-- 字符串类型 -->
|
<!-- 字符串类型 -->
|
||||||
<input
|
<input
|
||||||
v-if="field.type === 'string'"
|
v-if="field.type === 'string'"
|
||||||
v-model="tempParams[field.key]"
|
v-model="tempParams[field.key]"
|
||||||
class="field-input"
|
class="w-full h-[80rpx] p-[16rpx_20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] text-[28rpx] text-[#232338] box-border focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="`请输入${field.label}`"
|
:placeholder="`请输入${field.label}`"
|
||||||
@input="
|
@input="
|
||||||
@@ -480,13 +481,13 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
|
|
||||||
<!-- 数组类型 -->
|
<!-- 数组类型 -->
|
||||||
<view v-else-if="field.type === 'array'" class="array-field">
|
<view v-else-if="field.type === 'array'">
|
||||||
<text class="field-hint">
|
<text class="block text-[24rpx] text-[#65686f] mb-[16rpx]">
|
||||||
每行输入一个项目
|
每行输入一个项目
|
||||||
</text>
|
</text>
|
||||||
<textarea
|
<textarea
|
||||||
v-model="arrayTextCache[field.key]"
|
v-model="arrayTextCache[field.key]"
|
||||||
class="field-textarea"
|
class="w-full min-h-[200rpx] p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] text-[26rpx] text-[#232338] leading-[1.6] box-border focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||||
:placeholder="`请输入${field.label},每行一个`"
|
:placeholder="`请输入${field.label},每行一个`"
|
||||||
@input="
|
@input="
|
||||||
handleArrayChange(field.key, $event.detail.value, field)
|
handleArrayChange(field.key, $event.detail.value, field)
|
||||||
@@ -495,13 +496,13 @@ onMounted(async () => {
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- JSON类型 -->
|
<!-- JSON类型 -->
|
||||||
<view v-else-if="field.type === 'json'" class="json-field">
|
<view v-else-if="field.type === 'json'">
|
||||||
<text class="field-hint">
|
<text class="block text-[24rpx] text-[#65686f] mb-[16rpx]">
|
||||||
请输入有效的JSON格式
|
请输入有效的JSON格式
|
||||||
</text>
|
</text>
|
||||||
<textarea
|
<textarea
|
||||||
v-model="jsonTextCache[field.key]"
|
v-model="jsonTextCache[field.key]"
|
||||||
class="field-textarea json-textarea"
|
class="w-full min-h-[300rpx] p-[20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] text-[26rpx] text-[#232338] leading-[1.6] box-border focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3] font-mono"
|
||||||
placeholder="请输入合法的JSON格式"
|
placeholder="请输入合法的JSON格式"
|
||||||
@blur="
|
@blur="
|
||||||
handleJsonChange(field.key, $event.detail.value, field)
|
handleJsonChange(field.key, $event.detail.value, field)
|
||||||
@@ -513,7 +514,7 @@ onMounted(async () => {
|
|||||||
<input
|
<input
|
||||||
v-else-if="field.type === 'number'"
|
v-else-if="field.type === 'number'"
|
||||||
v-model="tempParams[field.key]"
|
v-model="tempParams[field.key]"
|
||||||
class="field-input"
|
class="w-full h-[80rpx] p-[16rpx_20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] text-[28rpx] text-[#232338] box-border focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||||
type="number"
|
type="number"
|
||||||
:placeholder="`请输入${field.label}`"
|
:placeholder="`请输入${field.label}`"
|
||||||
@input="
|
@input="
|
||||||
@@ -528,13 +529,13 @@ onMounted(async () => {
|
|||||||
<!-- 布尔类型 -->
|
<!-- 布尔类型 -->
|
||||||
<view
|
<view
|
||||||
v-else-if="field.type === 'boolean' || field.type === 'bool'"
|
v-else-if="field.type === 'boolean' || field.type === 'bool'"
|
||||||
class="switch-field"
|
class="flex items-center justify-between py-[20rpx]"
|
||||||
>
|
>
|
||||||
<view class="switch-info">
|
<view class="flex-1">
|
||||||
<text class="switch-label">
|
<text class="block text-[28rpx] text-[#232338] mb-[8rpx]">
|
||||||
启用功能
|
启用功能
|
||||||
</text>
|
</text>
|
||||||
<text class="switch-desc">
|
<text class="block text-[24rpx] text-[#65686f]">
|
||||||
开启或关闭此功能
|
开启或关闭此功能
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -550,7 +551,7 @@ onMounted(async () => {
|
|||||||
<input
|
<input
|
||||||
v-else
|
v-else
|
||||||
v-model="tempParams[field.key]"
|
v-model="tempParams[field.key]"
|
||||||
class="field-input"
|
class="w-full h-[80rpx] p-[16rpx_20rpx] bg-[#f5f7fb] rounded-[12rpx] border border-[#eeeeee] text-[28rpx] text-[#232338] box-border focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="`请输入${field.label}`"
|
:placeholder="`请输入${field.label}`"
|
||||||
@input="
|
@input="
|
||||||
@@ -566,161 +567,3 @@ onMounted(async () => {
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.page-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100vh;
|
|
||||||
background: #f5f7fb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-scroll-view {
|
|
||||||
flex: 1;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插件列表滚动视图样式
|
|
||||||
.plugin-scroll-view {
|
|
||||||
max-height: 600rpx; // 最大高度为4个插件的高度
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 参数编辑弹窗样式
|
|
||||||
.param-scroll-container {
|
|
||||||
background: #f5f7fb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.param-content {
|
|
||||||
padding: 30rpx;
|
|
||||||
padding-bottom: 40rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-params {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 400rpx;
|
|
||||||
|
|
||||||
.empty-text {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.param-cards {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.param-card {
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
padding: 30rpx;
|
|
||||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-info {
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
.field-label {
|
|
||||||
display: block;
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #232338;
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-desc {
|
|
||||||
display: block;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #65686f;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-input-container {
|
|
||||||
.field-input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 16rpx 20rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #232338;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: #336cff;
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: #9d9ea3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-textarea {
|
|
||||||
width: 100%;
|
|
||||||
min-height: 200rpx;
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #f5f7fb;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
border: 1rpx solid #eeeeee;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #232338;
|
|
||||||
line-height: 1.6;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: #336cff;
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.json-textarea {
|
|
||||||
min-height: 300rpx;
|
|
||||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: #9d9ea3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.array-field,
|
|
||||||
.json-field {
|
|
||||||
.field-hint {
|
|
||||||
display: block;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #65686f;
|
|
||||||
margin-bottom: 16rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch-field {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
|
|
||||||
.switch-info {
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.switch-label {
|
|
||||||
display: block;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #232338;
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch-desc {
|
|
||||||
display: block;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #65686f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user