Browse Source

修复:TDesign <t-space> 内部 v-if 导致按钮动作错位

TDesign-Vue-Next-1.20.6
wanghanlin 3 weeks ago
parent
commit
1fe6a19366
  1. 7
      client/dist/chatbot-sdk.js
  2. 2
      client/dist/chatbot-sdk.min.js
  3. 7
      client/src/config.ts
  4. 10
      frontend/src/views/ApiKeyManager.vue
  5. 2
      frontend/src/views/DocList.vue
  6. 2
      frontend/src/views/LogViewer.vue
  7. 10
      frontend/src/views/ModelConfigManager.vue
  8. 2
      frontend/src/views/RoleManager.vue
  9. 12
      src/main/java/com/wok/supportbot/service/ApiKeyService.java
  10. 7
      src/main/resources/static/sdk/chatbot-sdk.js
  11. 2
      src/main/resources/static/sdk/chatbot-sdk.min.js

7
client/dist/chatbot-sdk.js

@ -73,8 +73,6 @@ var ChatbotSDK = (function () {
},
};
/** 默认悬浮按钮图标 — 指向 SDK 同目录下的外置 logo 文件 */
const DEFAULT_LAUNCHER_ICON = '<img src="/sdk/launcher-logo.png" alt="" draggable="false" />';
/**
* 解析并校验用户传入的配置填充默认值
*/
@ -101,8 +99,9 @@ var ChatbotSDK = (function () {
}
// integrateId 统一转为字符串(后端 roleId 为 Long,但 query param 传字符串也可接收)
const integrateIdStr = String(raw.integrateId).trim();
// 解析图标:用户传入优先,否则使用默认极光粒子图标
const resolvedLauncherIcon = raw.launcherIcon || DEFAULT_LAUNCHER_ICON;
// 解析图标:用户传入优先,否则使用 requestDomain + /sdk/launcher-logo.png
const domain = raw.requestDomain.replace(/\/+$/, '');
const resolvedLauncherIcon = raw.launcherIcon || `<img src="${domain}/sdk/launcher-logo.png" alt="" draggable="false" />`;
const resolvedPrimaryColor = raw.primaryColor || '#4F46E5';
// 填充默认值
const config = {

2
client/dist/chatbot-sdk.min.js
File diff suppressed because it is too large
View File

7
client/src/config.ts

@ -9,8 +9,6 @@
import { SDKConfig, ResolvedConfig } from './types';
import { logger } from './logger';
/** 默认悬浮按钮图标 — 指向 SDK 同目录下的外置 logo 文件 */
const DEFAULT_LAUNCHER_ICON = '<img src="/sdk/launcher-logo.png" alt="" draggable="false" />';
/**
*
@ -40,8 +38,9 @@ export function parseConfig(raw: SDKConfig): ResolvedConfig | null {
// integrateId 统一转为字符串(后端 roleId 为 Long,但 query param 传字符串也可接收)
const integrateIdStr = String(raw.integrateId).trim();
// 解析图标:用户传入优先,否则使用默认极光粒子图标
const resolvedLauncherIcon = raw.launcherIcon || DEFAULT_LAUNCHER_ICON;
// 解析图标:用户传入优先,否则使用 requestDomain + /sdk/launcher-logo.png
const domain = raw.requestDomain.replace(/\/+$/, '');
const resolvedLauncherIcon = raw.launcherIcon || `<img src="${domain}/sdk/launcher-logo.png" alt="" draggable="false" />`;
const resolvedPrimaryColor = raw.primaryColor || '#4F46E5';
// 填充默认值

10
frontend/src/views/ApiKeyManager.vue

@ -20,8 +20,8 @@
<t-space :size="4">
<t-button size="small" variant="text" @click="openEditDialog(row)">编辑</t-button>
<t-button size="small" variant="text" @click="openRoleDialog(row)">绑定角色</t-button>
<t-button v-if="row.enabled" size="small" variant="text" theme="danger" @click="doRevoke(row.id)">吊销</t-button>
<t-button v-else size="small" variant="text" theme="success" @click="doEnable(row.id)">启用</t-button>
<t-button v-show="row.enabled" size="small" variant="text" theme="danger" @click="doRevoke(row.id)">吊销</t-button>
<t-button v-show="!row.enabled" size="small" variant="text" theme="success" @click="doEnable(row.id)">启用</t-button>
<t-button size="small" variant="text" theme="danger" @click="doDelete(row.id)">删除</t-button>
</t-space>
</template>
@ -44,7 +44,7 @@
<div class="dialog-footer">
<t-button variant="outline" @click="showCreateDialog=false">关闭</t-button>
<t-button theme="primary" @click="doCreate" :disabled="!form.name">创建</t-button>
<t-button theme="primary" @click="doCreate" :loading="creating" :disabled="!form.name || creating">创建</t-button>
</div>
</t-dialog>
@ -86,7 +86,7 @@ import { useConfirm } from '@/composables/useConfirm'
const { confirm } = useConfirm()
const keys=ref<any[]>([]);const loading=ref(false);const page=ref(1);const pageSize=ref(20);const total=ref(0)
const keys=ref<any[]>([]);const loading=ref(false);const creating=ref(false);const page=ref(1);const pageSize=ref(20);const total=ref(0)
const showCreateDialog=ref(false);const showRoleDialog=ref(false)
const showEditDialog=ref(false)
const editingKeyId=ref<any>(null);const editingKeyName=ref('')
@ -110,7 +110,7 @@ async function loadRoles(){try{const r=await getAllRoles();if(r.success)allRoles
function openCreateDialog(){createdKey.value='';form.value={name:'',description:'',rateLimit:60};showCreateDialog.value=true}
async function doCreate(){try{const r=await createApiKey(form.value);if(r.success){createdKey.value=r.data?.apiKey||r.data?.key||'';toast('创建成功','success');loadList()}else toast(r.message||'创建失败','error')}catch(e:any){toast('创建失败:'+e.message,'error')}}
async function doCreate(){if(creating.value)return;creating.value=true;try{const r=await createApiKey(form.value);if(r.success){createdKey.value=r.data?.apiKey||r.data?.key||r.data?.keyValue||'';toast('创建成功,请复制 Key','success');loadList()}else toast(r.message||'创建失败','error')}catch(e:any){toast('创建失败:'+e.message,'error')}finally{creating.value=false}}
async function doRevoke(id:string){if(!await confirm('确定吊销?'))return;try{const r=await revokeApiKey(id);if(r.success){toast('已吊销','success');loadList()}else toast(r.message||'吊销失败','error')}catch(e:any){toast('吊销失败:'+e.message,'error')}}

2
frontend/src/views/DocList.vue

@ -50,7 +50,7 @@
<template #op="{ row }">
<t-space :size="2">
<t-button size="small" variant="text" @click="viewDetail(row.id)">查看</t-button>
<t-button v-if="row.filePath" size="small" variant="text" @click="download(row.id)">下载</t-button>
<t-button v-show="row.filePath" size="small" variant="text" @click="download(row.id)">下载</t-button>
<t-button size="small" variant="text" @click="reprocess(row.id)">重新处理</t-button>
<t-button size="small" variant="text" theme="danger" @click="remove(row.id)">删除</t-button>
</t-space>

2
frontend/src/views/LogViewer.vue

@ -63,7 +63,7 @@
<t-space :size="8">
<t-checkbox v-model="autoRefresh" @change="onAutoRefreshToggle">自动刷新</t-checkbox>
<t-select
v-if="autoRefresh"
v-show="autoRefresh"
v-model="refreshInterval"
:options="refreshOptions"
size="small"

10
frontend/src/views/ModelConfigManager.vue

@ -99,9 +99,9 @@
<t-button size="small" variant="text" @click="openEditModal(row)" title="编辑"></t-button>
<t-button size="small" variant="text" @click="testConnection(row)" :disabled="testLoading[row.id]" title="测试连接">{{ testLoading[row.id] ? '⏳' : '🔌' }}</t-button>
<t-button size="small" variant="text" @click="duplicateConfig(row)" title="复制">📋</t-button>
<t-button v-if="!row.is_active" size="small" variant="text" theme="primary" @click="activate(row.id)" title="激活"></t-button>
<t-button v-if="row.is_active" size="small" variant="text" @click="deactivateConfig(row.id)" title="停用"></t-button>
<t-button v-if="!row.is_active" size="small" variant="text" theme="danger" @click="remove(row.id, row.name)" title="删除">🗑</t-button>
<t-button v-show="!row.is_active" size="small" variant="text" theme="primary" @click="activate(row.id)" title="激活"></t-button>
<t-button v-show="row.is_active" size="small" variant="text" @click="deactivateConfig(row.id)" title="停用"></t-button>
<t-button v-show="!row.is_active" size="small" variant="text" theme="danger" @click="remove(row.id, row.name)" title="删除">🗑</t-button>
</t-space>
</template>
</t-table>
@ -153,7 +153,7 @@
<t-space size="small" style="font-size:12px;margin-top:4px;align-items:center;">
<span style="color:#6b7280;">快捷选择</span>
<t-select v-model="editModal.form.provider" :options="providerOptions" style="max-width:200px;" size="small" @change="onProviderChange" />
<span v-if="providerTip" style="color:#3b82f6;">💡 {{ providerTip }}</span>
<span v-show="providerTip" style="color:#3b82f6;">💡 {{ providerTip }}</span>
</t-space>
</template>
</t-form-item>
@ -166,7 +166,7 @@
@keydown.down.prevent="onDropdownKeyDown('down')" @keydown.up.prevent="onDropdownKeyDown('up')"
@keydown.enter.prevent="onDropdownKeyDown('enter')" @keydown.escape="modelDropdownOpen = false">
<template #suffix>
<t-button v-if="editModal.form.model_name" variant="text" size="small"
<t-button v-show="editModal.form.model_name" variant="text" size="small"
@click="editModal.form.model_name = ''; modelDropdownOpen = false; updateNameSuggestion()" style="color:#9ca3af;"></t-button>
</template>
</t-input>

2
frontend/src/views/RoleManager.vue

@ -12,7 +12,7 @@
<t-textarea v-model="form.prompt" :autosize="{minRows:2,maxRows:3}" placeholder="角色人设/风格提示词" style="margin-top:8px;" />
<t-space style="margin-top:8px;">
<t-button theme="success" size="small" @click="submit">{{ editingId?'保存修改':'新增角色' }}</t-button>
<t-button v-if="editingId" variant="outline" size="small" @click="resetForm">取消编辑</t-button>
<t-button v-show="editingId" variant="outline" size="small" @click="resetForm">取消编辑</t-button>
<t-button variant="outline" size="small" @click="reload">刷新</t-button>
</t-space>
</div>

12
src/main/java/com/wok/supportbot/service/ApiKeyService.java

@ -101,6 +101,7 @@ public class ApiKeyService {
/**
* 吊销 API Key设置 enabled=false
* 使用 JdbcTemplate 避免 MyBatis-Plus role_ids JSONB 类型不匹配
*
* @param id Key ID
*/
@ -109,13 +110,15 @@ public class ApiKeyService {
if (existing == null) {
throw new IllegalArgumentException("API Key 不存在,ID:" + id);
}
existing.setEnabled(false);
apiKeyMapper.updateById(existing);
jdbcTemplate.update(
"UPDATE api_key SET enabled = false, update_time = CURRENT_TIMESTAMP WHERE id = ? AND is_delete = false",
id);
log.info("吊销 API Key: id={}, name={}", id, existing.getName());
}
/**
* 启用 API Key
* 使用 JdbcTemplate 避免 MyBatis-Plus role_ids JSONB 类型不匹配
*
* @param id Key ID
*/
@ -124,8 +127,9 @@ public class ApiKeyService {
if (existing == null) {
throw new IllegalArgumentException("API Key 不存在,ID:" + id);
}
existing.setEnabled(true);
apiKeyMapper.updateById(existing);
jdbcTemplate.update(
"UPDATE api_key SET enabled = true, update_time = CURRENT_TIMESTAMP WHERE id = ? AND is_delete = false",
id);
log.info("启用 API Key: id={}, name={}", id, existing.getName());
}

7
src/main/resources/static/sdk/chatbot-sdk.js

@ -73,8 +73,6 @@ var ChatbotSDK = (function () {
},
};
/** 默认悬浮按钮图标 — 指向 SDK 同目录下的外置 logo 文件 */
const DEFAULT_LAUNCHER_ICON = '<img src="/sdk/launcher-logo.png" alt="" draggable="false" />';
/**
* 解析并校验用户传入的配置填充默认值
*/
@ -101,8 +99,9 @@ var ChatbotSDK = (function () {
}
// integrateId 统一转为字符串(后端 roleId 为 Long,但 query param 传字符串也可接收)
const integrateIdStr = String(raw.integrateId).trim();
// 解析图标:用户传入优先,否则使用默认极光粒子图标
const resolvedLauncherIcon = raw.launcherIcon || DEFAULT_LAUNCHER_ICON;
// 解析图标:用户传入优先,否则使用 requestDomain + /sdk/launcher-logo.png
const domain = raw.requestDomain.replace(/\/+$/, '');
const resolvedLauncherIcon = raw.launcherIcon || `<img src="${domain}/sdk/launcher-logo.png" alt="" draggable="false" />`;
const resolvedPrimaryColor = raw.primaryColor || '#4F46E5';
// 填充默认值
const config = {

2
src/main/resources/static/sdk/chatbot-sdk.min.js
File diff suppressed because it is too large
View File

Loading…
Cancel
Save