diff --git a/frontend/src/views/tenants/detail.vue b/frontend/src/views/tenants/detail.vue index 3737a1e..bddaf70 100644 --- a/frontend/src/views/tenants/detail.vue +++ b/frontend/src/views/tenants/detail.vue @@ -230,8 +230,137 @@ watch(activeTab, (newVal) => { fetchToolConfigs() fetchConfigSchema() } + if (newVal === 'ruimeiyun' && !ruimeiyunLoaded.value) { + fetchRuimeiyunConfig() + } }) +// ======================================== +// 瑞美云配置 +// ======================================== +const ruimeiyunLoading = ref(false) +const ruimeiyunLoaded = ref(false) +const ruimeiyunTesting = ref(false) +const ruimeiyunFormRef = ref(null) +const ruimeiyunForm = reactive({ + base_url: '', + account: '', + private_key: '', + allowed_apis: '' +}) + +const ruimeiyunRules = { + base_url: [{ required: true, message: '请输入睿美云 API 地址', trigger: 'blur' }], + account: [{ required: true, message: '请输入账号', trigger: 'blur' }], + private_key: [{ required: true, message: '请输入私钥', trigger: 'blur' }] +} + +async function fetchRuimeiyunConfig() { + ruimeiyunLoading.value = true + try { + const res = await api.get('/api/tool-configs', { + params: { tenant_id: tenantId, tool_code: 'ruimeiyun', size: 100 } + }) + const items = res.data.items || [] + // 映射配置到表单 + items.forEach(item => { + if (item.config_key === 'ruimeiyun_base_url') { + ruimeiyunForm.base_url = item.config_value || '' + } else if (item.config_key === 'ruimeiyun_account') { + ruimeiyunForm.account = item.config_value || '' + } else if (item.config_key === 'ruimeiyun_private_key') { + // 加密字段显示占位符 + ruimeiyunForm.private_key = item.is_encrypted ? '********' : (item.config_value || '') + } else if (item.config_key === 'ruimeiyun_allowed_apis') { + ruimeiyunForm.allowed_apis = item.config_value || '' + } + }) + ruimeiyunLoaded.value = true + } catch (e) { + console.error('获取瑞美云配置失败:', e) + } finally { + ruimeiyunLoading.value = false + } +} + +async function saveRuimeiyunConfig() { + await ruimeiyunFormRef.value.validate() + + ruimeiyunLoading.value = true + try { + // 构建配置列表 + const configs = [ + { + config_type: 'external_api', + config_key: 'ruimeiyun_base_url', + config_value: ruimeiyunForm.base_url, + is_encrypted: 0, + description: '睿美云 API 地址' + }, + { + config_type: 'external_api', + config_key: 'ruimeiyun_account', + config_value: ruimeiyunForm.account, + is_encrypted: 0, + description: '睿美云账号' + } + ] + + // 如果私钥不是占位符,则更新 + if (ruimeiyunForm.private_key && ruimeiyunForm.private_key !== '********') { + configs.push({ + config_type: 'external_api', + config_key: 'ruimeiyun_private_key', + config_value: ruimeiyunForm.private_key, + is_encrypted: 1, + description: '睿美云私钥' + }) + } + + // 如果有接口限制 + if (ruimeiyunForm.allowed_apis) { + configs.push({ + config_type: 'external_api', + config_key: 'ruimeiyun_allowed_apis', + config_value: ruimeiyunForm.allowed_apis, + is_encrypted: 0, + description: '允许调用的接口列表' + }) + } + + await api.post('/api/tool-configs/batch', { + tenant_id: tenantId, + tool_code: 'ruimeiyun', + configs + }) + + ElMessage.success('保存成功') + // 重新加载 + ruimeiyunLoaded.value = false + fetchRuimeiyunConfig() + } catch (e) { + console.error('保存失败:', e) + } finally { + ruimeiyunLoading.value = false + } +} + +async function testRuimeiyunConnection() { + ruimeiyunTesting.value = true + try { + const res = await api.get(`/api/ruimeiyun/health/${tenantId}`) + if (res.data.status === 'connected') { + ElMessage.success(`连接成功!账号: ${res.data.account}`) + } else { + ElMessage.error(`连接失败: ${res.data.message}`) + } + } catch (e) { + ElMessage.error(`测试失败: ${e.response?.data?.detail || e.message}`) + } finally { + ruimeiyunTesting.value = false + } +} + onMounted(() => { fetchDetail() }) @@ -304,6 +433,73 @@ onMounted(() => { + + +
+ + + + + + + +
睿美云 TPOS 接口的基础地址
+
+ + + + + + + +
用于 TPOS 接口签名的 RSA 私钥,将加密存储
+
+ + + +
限制租户可调用的接口,留空表示允许所有接口
+
+ + + + 保存配置 + + + 测试连接 + + +
+
+
+
@@ -506,4 +702,15 @@ onMounted(() => { color: #909399; font-family: monospace; } + +.ruimeiyun-container { + padding: 0 4px; +} + +.form-hint { + font-size: 12px; + color: #909399; + line-height: 1.5; + margin-top: 4px; +}