From 71fcaf8628e10b57e848a8b4b633513df78ecd63 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 03 三月 2026 13:13:17 +0800
Subject: [PATCH] #AI LLM路由
---
src/main/webapp/views/ai/llm_config.html | 144 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 143 insertions(+), 1 deletions(-)
diff --git a/src/main/webapp/views/ai/llm_config.html b/src/main/webapp/views/ai/llm_config.html
index e5c052e..c80314c 100644
--- a/src/main/webapp/views/ai/llm_config.html
+++ b/src/main/webapp/views/ai/llm_config.html
@@ -47,6 +47,13 @@
font-size: 12px;
opacity: 0.9;
}
+ .hero-actions {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ }
.summary-grid {
margin-top: 10px;
display: grid;
@@ -260,8 +267,10 @@
<div class="sub">鏀寔澶欰PI銆佸妯″瀷銆佸Key锛岄搴﹁�楀敖鎴栨晠闅滆嚜鍔ㄥ垏鎹�</div>
</div>
</div>
- <div>
+ <div class="hero-actions">
<el-button type="primary" size="mini" @click="addRoute">鏂板璺敱</el-button>
+ <el-button size="mini" @click="exportRoutes">瀵煎嚭JSON</el-button>
+ <el-button size="mini" @click="triggerImport">瀵煎叆JSON</el-button>
<el-button size="mini" @click="loadRoutes">鍒锋柊</el-button>
<el-button size="mini" @click="openLogDialog">璋冪敤鏃ュ織</el-button>
</div>
@@ -289,6 +298,7 @@
</div>
</div>
</div>
+ <input ref="importFileInput" type="file" accept="application/json,.json" style="display:none;" @change="handleImportFileChange" />
<div class="route-board" v-loading="loading">
<div v-if="!routes || routes.length === 0" class="empty-shell">
@@ -597,6 +607,138 @@
authHeaders: function() {
return { 'token': localStorage.getItem('token') };
},
+ exportRoutes: function() {
+ var self = this;
+ fetch(baseUrl + '/ai/llm/config/export/auth', { headers: self.authHeaders() })
+ .then(function(r){ return r.json(); })
+ .then(function(res){
+ if (!res || res.code !== 200) {
+ self.$message.error((res && res.msg) ? res.msg : '瀵煎嚭澶辫触');
+ return;
+ }
+ var payload = res.data || {};
+ var text = JSON.stringify(payload, null, 2);
+ var name = 'llm_routes_' + self.buildExportTimestamp() + '.json';
+ var blob = new Blob([text], { type: 'application/json;charset=utf-8' });
+ var a = document.createElement('a');
+ a.href = URL.createObjectURL(blob);
+ a.download = name;
+ document.body.appendChild(a);
+ a.click();
+ setTimeout(function() {
+ URL.revokeObjectURL(a.href);
+ document.body.removeChild(a);
+ }, 0);
+ self.$message.success('瀵煎嚭鎴愬姛');
+ })
+ .catch(function(){
+ self.$message.error('瀵煎嚭澶辫触');
+ });
+ },
+ buildExportTimestamp: function() {
+ var d = new Date();
+ var pad = function(n) { return n < 10 ? ('0' + n) : String(n); };
+ return d.getFullYear()
+ + pad(d.getMonth() + 1)
+ + pad(d.getDate())
+ + '_'
+ + pad(d.getHours())
+ + pad(d.getMinutes())
+ + pad(d.getSeconds());
+ },
+ triggerImport: function() {
+ var input = this.$refs.importFileInput;
+ if (!input) return;
+ input.value = '';
+ input.click();
+ },
+ handleImportFileChange: function(evt) {
+ var self = this;
+ var files = evt && evt.target && evt.target.files ? evt.target.files : null;
+ var file = files && files.length > 0 ? files[0] : null;
+ if (!file) return;
+ var reader = new FileReader();
+ reader.onload = function(e) {
+ var text = e && e.target ? e.target.result : '';
+ var parsed;
+ try {
+ parsed = JSON.parse(text || '{}');
+ } catch (err) {
+ self.$message.error('JSON 鏍煎紡涓嶆纭�');
+ return;
+ }
+ var routes = self.extractImportRoutes(parsed);
+ if (!routes || routes.length === 0) {
+ self.$message.warning('鏈壘鍒板彲瀵煎叆鐨� routes');
+ return;
+ }
+ self.$confirm(
+ '璇烽�夋嫨瀵煎叆鏂瑰紡锛氳鐩栧鍏ヤ細鍏堟竻绌虹幇鏈夎矾鐢憋紱鐐瑰嚮鈥滃悎骞跺鍏モ�濆垯鎸塈D鏇存柊鎴栨柊澧炪��',
+ '瀵煎叆纭',
+ {
+ type: 'warning',
+ distinguishCancelAndClose: true,
+ confirmButtonText: '瑕嗙洊瀵煎叆',
+ cancelButtonText: '鍚堝苟瀵煎叆',
+ closeOnClickModal: false
+ }
+ ).then(function() {
+ self.doImportRoutes(routes, true);
+ }).catch(function(action) {
+ if (action === 'cancel') {
+ self.doImportRoutes(routes, false);
+ }
+ });
+ };
+ reader.onerror = function() {
+ self.$message.error('璇诲彇鏂囦欢澶辫触');
+ };
+ reader.readAsText(file, 'utf-8');
+ },
+ extractImportRoutes: function(parsed) {
+ if (Array.isArray(parsed)) return parsed;
+ if (!parsed || typeof parsed !== 'object') return [];
+ if (Array.isArray(parsed.routes)) return parsed.routes;
+ if (parsed.data && Array.isArray(parsed.data.routes)) return parsed.data.routes;
+ if (Array.isArray(parsed.data)) return parsed.data;
+ return [];
+ },
+ doImportRoutes: function(routes, replace) {
+ var self = this;
+ fetch(baseUrl + '/ai/llm/config/import/auth', {
+ method: 'POST',
+ headers: Object.assign({ 'Content-Type': 'application/json' }, self.authHeaders()),
+ body: JSON.stringify({
+ replace: replace === true,
+ routes: routes
+ })
+ })
+ .then(function(r){ return r.json(); })
+ .then(function(res){
+ if (!res || res.code !== 200) {
+ self.$message.error((res && res.msg) ? res.msg : '瀵煎叆澶辫触');
+ return;
+ }
+ var d = res.data || {};
+ var msg = '瀵煎叆瀹屾垚锛氭柊澧� ' + (d.inserted || 0)
+ + '锛屾洿鏂� ' + (d.updated || 0)
+ + '锛岃烦杩� ' + (d.skipped || 0);
+ if (d.errorCount && d.errorCount > 0) {
+ msg += '锛屽紓甯� ' + d.errorCount;
+ }
+ self.$message.success(msg);
+ if (Array.isArray(d.errors) && d.errors.length > 0) {
+ self.$alert(d.errors.join('\n'), '瀵煎叆寮傚父鏄庣粏锛堟渶澶�20鏉★級', {
+ confirmButtonText: '纭畾',
+ type: 'warning'
+ });
+ }
+ self.loadRoutes();
+ })
+ .catch(function(){
+ self.$message.error('瀵煎叆澶辫触');
+ });
+ },
handleRouteCommand: function(command, route, idx) {
if (command === 'test') return this.testRoute(route);
if (command === 'save') return this.saveRoute(route);
--
Gitblit v1.9.1