fix: 飞书群绑定租户完善
- tenants.js 去掉已删除的 appid/appsecret 元素引用 - showEditTenantModal 改为从 API 加载完整租户数据(不再传参拼接) - saveTenant 保留已有的非 feishu 配置,只更新 chat_groups - 租户列表显示绑定群数量或'未绑定飞书群' - 飞书 bot/longconn 复用已有会话时同步更新 tenant_id(群重新绑定后立即生效) - 删除租户后同步刷新租户选择器
This commit is contained in:
Binary file not shown.
@@ -150,6 +150,9 @@ class FeishuLongConnService:
|
|||||||
for session in active_sessions:
|
for session in active_sessions:
|
||||||
if session.get('user_id') == session_user_id:
|
if session.get('user_id') == session_user_id:
|
||||||
session_id = session.get('session_id')
|
session_id = session.get('session_id')
|
||||||
|
# 更新会话的 tenant_id(群可能重新绑定了租户)
|
||||||
|
if session_id in chat_manager.active_sessions:
|
||||||
|
chat_manager.active_sessions[session_id]['tenant_id'] = tenant_id
|
||||||
logger.info(f"✅ 找到已有会话: {session_id}")
|
logger.info(f"✅ 找到已有会话: {session_id}")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ def _process_message_in_background(app, event_data: dict):
|
|||||||
for session in active_sessions:
|
for session in active_sessions:
|
||||||
if session.get('user_id') == user_id:
|
if session.get('user_id') == user_id:
|
||||||
session_id = session.get('session_id')
|
session_id = session.get('session_id')
|
||||||
|
# 更新会话的 tenant_id(群可能重新绑定了租户)
|
||||||
|
if session_id in chat_manager.active_sessions:
|
||||||
|
chat_manager.active_sessions[session_id]['tenant_id'] = tenant_id
|
||||||
logger.info(f"[Feishu Bot] 找到已有会话: {session_id}")
|
logger.info(f"[Feishu Bot] 找到已有会话: {session_id}")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ Object.assign(TSPDashboard.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = tenants.map(t => {
|
container.innerHTML = tenants.map(t => {
|
||||||
const feishuCfg = t.config?.feishu || {};
|
const chatGroups = t.config?.feishu?.chat_groups || [];
|
||||||
const groupCount = (feishuCfg.chat_groups || []).length;
|
|
||||||
const hasFeishu = feishuCfg.app_id || groupCount > 0;
|
|
||||||
return `
|
return `
|
||||||
<div class="card mb-2">
|
<div class="card mb-2">
|
||||||
<div class="card-body d-flex justify-content-between align-items-center py-2">
|
<div class="card-body d-flex justify-content-between align-items-center py-2">
|
||||||
@@ -26,10 +24,10 @@ Object.assign(TSPDashboard.prototype, {
|
|||||||
<span class="text-muted ms-2">(${t.tenant_id})</span>
|
<span class="text-muted ms-2">(${t.tenant_id})</span>
|
||||||
${t.description ? `<br><small class="text-muted">${t.description}</small>` : ''}
|
${t.description ? `<br><small class="text-muted">${t.description}</small>` : ''}
|
||||||
${!t.is_active ? '<span class="badge bg-secondary ms-2">已禁用</span>' : ''}
|
${!t.is_active ? '<span class="badge bg-secondary ms-2">已禁用</span>' : ''}
|
||||||
${hasFeishu ? `<span class="badge bg-info ms-2"><i class="fas fa-robot me-1"></i>飞书${groupCount > 0 ? ` (${groupCount}群)` : ''}</span>` : ''}
|
${chatGroups.length > 0 ? `<span class="badge bg-info ms-2"><i class="fas fa-comments me-1"></i>${chatGroups.length} 个飞书群</span>` : '<span class="badge bg-light text-muted ms-2">未绑定飞书群</span>'}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group btn-group-sm">
|
<div class="btn-group btn-group-sm">
|
||||||
<button class="btn btn-outline-primary" onclick="dashboard.showEditTenantModal('${t.tenant_id}', '${(t.name || '').replace(/'/g, "\\'")}', '${(t.description || '').replace(/'/g, "\\'")}')">
|
<button class="btn btn-outline-primary" onclick="dashboard.showEditTenantModal('${t.tenant_id}')">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
${t.tenant_id !== 'default' ? `
|
${t.tenant_id !== 'default' ? `
|
||||||
@@ -54,33 +52,30 @@ Object.assign(TSPDashboard.prototype, {
|
|||||||
document.getElementById('tenant-id-group').style.display = '';
|
document.getElementById('tenant-id-group').style.display = '';
|
||||||
document.getElementById('tenant-name-input').value = '';
|
document.getElementById('tenant-name-input').value = '';
|
||||||
document.getElementById('tenant-desc-input').value = '';
|
document.getElementById('tenant-desc-input').value = '';
|
||||||
document.getElementById('tenant-feishu-appid').value = '';
|
|
||||||
document.getElementById('tenant-feishu-appsecret').value = '';
|
|
||||||
document.getElementById('tenant-feishu-chatgroups').value = '';
|
document.getElementById('tenant-feishu-chatgroups').value = '';
|
||||||
new bootstrap.Modal(document.getElementById('tenantModal')).show();
|
new bootstrap.Modal(document.getElementById('tenantModal')).show();
|
||||||
},
|
},
|
||||||
|
|
||||||
async showEditTenantModal(tenantId, name, description) {
|
async showEditTenantModal(tenantId) {
|
||||||
document.getElementById('tenantModalTitle').textContent = '编辑租户';
|
document.getElementById('tenantModalTitle').textContent = '编辑租户';
|
||||||
document.getElementById('tenant-edit-id').value = tenantId;
|
document.getElementById('tenant-edit-id').value = tenantId;
|
||||||
document.getElementById('tenant-id-input').value = tenantId;
|
document.getElementById('tenant-id-input').value = tenantId;
|
||||||
document.getElementById('tenant-id-input').disabled = true;
|
document.getElementById('tenant-id-input').disabled = true;
|
||||||
document.getElementById('tenant-name-input').value = name;
|
document.getElementById('tenant-id-group').style.display = 'none';
|
||||||
document.getElementById('tenant-desc-input').value = description;
|
|
||||||
|
|
||||||
// 加载租户的飞书配置
|
// 加载租户完整数据
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('/api/tenants');
|
const resp = await fetch('/api/tenants');
|
||||||
const tenants = await resp.json();
|
const tenants = await resp.json();
|
||||||
const tenant = tenants.find(t => t.tenant_id === tenantId);
|
const tenant = tenants.find(t => t.tenant_id === tenantId);
|
||||||
const feishuCfg = tenant?.config?.feishu || {};
|
if (tenant) {
|
||||||
document.getElementById('tenant-feishu-appid').value = feishuCfg.app_id || '';
|
document.getElementById('tenant-name-input').value = tenant.name || '';
|
||||||
document.getElementById('tenant-feishu-appsecret').value = feishuCfg.app_secret || '';
|
document.getElementById('tenant-desc-input').value = tenant.description || '';
|
||||||
document.getElementById('tenant-feishu-chatgroups').value = (feishuCfg.chat_groups || []).join('\n');
|
const chatGroups = tenant.config?.feishu?.chat_groups || [];
|
||||||
|
document.getElementById('tenant-feishu-chatgroups').value = chatGroups.join('\n');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.getElementById('tenant-feishu-appid').value = '';
|
console.warn('加载租户数据失败:', e);
|
||||||
document.getElementById('tenant-feishu-appsecret').value = '';
|
|
||||||
document.getElementById('tenant-feishu-chatgroups').value = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new bootstrap.Modal(document.getElementById('tenantModal')).show();
|
new bootstrap.Modal(document.getElementById('tenantModal')).show();
|
||||||
@@ -92,24 +87,32 @@ Object.assign(TSPDashboard.prototype, {
|
|||||||
const name = document.getElementById('tenant-name-input').value.trim();
|
const name = document.getElementById('tenant-name-input').value.trim();
|
||||||
const description = document.getElementById('tenant-desc-input').value.trim();
|
const description = document.getElementById('tenant-desc-input').value.trim();
|
||||||
|
|
||||||
// 飞书配置
|
// 飞书群绑定
|
||||||
const feishuAppId = document.getElementById('tenant-feishu-appid').value.trim();
|
|
||||||
const feishuAppSecret = document.getElementById('tenant-feishu-appsecret').value.trim();
|
|
||||||
const chatGroupsText = document.getElementById('tenant-feishu-chatgroups').value.trim();
|
const chatGroupsText = document.getElementById('tenant-feishu-chatgroups').value.trim();
|
||||||
const chatGroups = chatGroupsText ? chatGroupsText.split('\n').map(s => s.trim()).filter(Boolean) : [];
|
const chatGroups = chatGroupsText ? chatGroupsText.split('\n').map(s => s.trim()).filter(Boolean) : [];
|
||||||
|
|
||||||
const config = {};
|
// 构建 config,保留已有的非 feishu 配置
|
||||||
if (feishuAppId || feishuAppSecret || chatGroups.length > 0) {
|
let existingConfig = {};
|
||||||
config.feishu = {};
|
if (editId) {
|
||||||
if (feishuAppId) config.feishu.app_id = feishuAppId;
|
try {
|
||||||
if (feishuAppSecret) config.feishu.app_secret = feishuAppSecret;
|
const resp = await fetch('/api/tenants');
|
||||||
if (chatGroups.length > 0) config.feishu.chat_groups = chatGroups;
|
const tenants = await resp.json();
|
||||||
|
const tenant = tenants.find(t => t.tenant_id === editId);
|
||||||
|
existingConfig = tenant?.config || {};
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
const config = { ...existingConfig };
|
||||||
|
if (chatGroups.length > 0) {
|
||||||
|
config.feishu = { ...(config.feishu || {}), chat_groups: chatGroups };
|
||||||
|
} else {
|
||||||
|
// 清空飞书群绑定
|
||||||
|
if (config.feishu) {
|
||||||
|
delete config.feishu.chat_groups;
|
||||||
|
if (Object.keys(config.feishu).length === 0) delete config.feishu;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!name) {
|
if (!name) { this.showNotification('租户名称不能为空', 'error'); return; }
|
||||||
this.showNotification('租户名称不能为空', 'error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let response;
|
let response;
|
||||||
@@ -120,10 +123,7 @@ Object.assign(TSPDashboard.prototype, {
|
|||||||
body: JSON.stringify({ name, description, config })
|
body: JSON.stringify({ name, description, config })
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (!tenantId) {
|
if (!tenantId) { this.showNotification('租户标识不能为空', 'error'); return; }
|
||||||
this.showNotification('租户标识不能为空', 'error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
response = await fetch('/api/tenants', {
|
response = await fetch('/api/tenants', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@@ -154,6 +154,7 @@ Object.assign(TSPDashboard.prototype, {
|
|||||||
if (data.success) {
|
if (data.success) {
|
||||||
this.showNotification('租户已删除', 'success');
|
this.showNotification('租户已删除', 'success');
|
||||||
this.loadTenantList();
|
this.loadTenantList();
|
||||||
|
this.populateTenantSelectors();
|
||||||
} else {
|
} else {
|
||||||
this.showNotification(data.error || '删除失败', 'error');
|
this.showNotification(data.error || '删除失败', 'error');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user