diff --git a/src/web/blueprints/workorders.py b/src/web/blueprints/workorders.py index 30ca154..93ed8ad 100644 --- a/src/web/blueprints/workorders.py +++ b/src/web/blueprints/workorders.py @@ -84,6 +84,7 @@ def get_workorders(): per_page = request.args.get('per_page', 10, type=int) status_filter = request.args.get('status', '') priority_filter = request.args.get('priority', '') + tenant_id = request.args.get('tenant_id', '') # 从数据库获取分页数据 from src.core.database import db_manager @@ -98,6 +99,8 @@ def get_workorders(): query = query.filter(WorkOrder.status == status_filter) if priority_filter: query = query.filter(WorkOrder.priority == priority_filter) + if tenant_id: + query = query.filter(WorkOrder.tenant_id == tenant_id) # 按创建时间倒序排列 query = query.order_by(WorkOrder.created_at.desc()) @@ -114,6 +117,7 @@ def get_workorders(): workorders_data.append({ 'id': workorder.id, 'order_id': workorder.order_id, + 'tenant_id': workorder.tenant_id, 'title': workorder.title, 'description': workorder.description, 'category': workorder.category, @@ -184,6 +188,7 @@ def get_workorder_details(workorder_id): workorder = { "id": w.id, "order_id": w.order_id, + "tenant_id": w.tenant_id, "title": w.title, "description": w.description, "category": w.category, @@ -315,15 +320,15 @@ def generate_workorder_ai_suggestion(workorder_id): if not w: return jsonify({"error": "工单不存在"}), 404 # 调用知识库搜索与LLM生成 - # 使用问题描述(title)而不是处理过程(description)作为主要查询依据 - query = f"{w.title}" + # 使用 title + description 作为查询依据,获取更精准的知识库匹配 + query = f"{w.title} {w.description or ''}" kb_results = service_manager.get_assistant().search_knowledge(query, top_k=3) kb_list = kb_results.get('results', []) if isinstance(kb_results, dict) else [] # 组装提示词 context = "\n".join([f"Q: {k.get('question','')}\nA: {k.get('answer','')}" for k in kb_list]) from src.core.llm_client import QwenClient llm = QwenClient() - prompt = f"请基于以下工单问题描述与知识库片段,给出简洁、可执行的处理建议。\n\n问题描述:\n{w.title}\n\n处理过程(仅供参考):\n{w.description}\n\n知识库片段:\n{context}\n\n请直接输出建议文本:" + prompt = f"请基于以下工单问题与知识库片段,给出简洁、可执行的处理建议。\n\n问题标题:\n{w.title}\n\n问题详细描述:\n{w.description or '无'}\n\n知识库片段:\n{context}\n\n请直接输出建议文本:" llm_resp = llm.chat_completion(messages=[{"role":"user","content":prompt}], temperature=0.3, max_tokens=800) suggestion = "" if llm_resp and 'choices' in llm_resp: @@ -432,10 +437,18 @@ def approve_workorder_to_knowledge(workorder_id): return jsonify({"error": "未找到可入库的内容"}), 400 # 入库为知识条目 + # question 使用标题+描述,确保知识条目的问题完整 + question_text = w.title or '' + if w.description: + question_text = f"{w.title}\n{w.description}" if w.title else w.description + if not question_text: + question_text = '工单问题' + entry = KnowledgeEntry( - question=w.title or (w.description[:20] if w.description else '工单问题'), + question=question_text, answer=answer_content, category=w.category or '其他', + tenant_id=w.tenant_id, confidence_score=confidence_score, is_active=True, is_verified=True, diff --git a/src/web/static/js/dashboard.js b/src/web/static/js/dashboard.js index 4d8d4c4..03f9bd0 100644 --- a/src/web/static/js/dashboard.js +++ b/src/web/static/js/dashboard.js @@ -386,13 +386,23 @@ class TSPDashboard { const tenants = await response.json(); if (!Array.isArray(tenants)) return; - const selectors = document.querySelectorAll('#chat-tenant-id'); - selectors.forEach(select => { - const currentVal = select.value; - select.innerHTML = tenants.map(t => + // 填充对话租户选择器 + const chatSelect = document.getElementById('chat-tenant-id'); + if (chatSelect) { + const currentVal = chatSelect.value; + chatSelect.innerHTML = tenants.map(t => `` ).join(''); - }); + } + + // 填充工单租户筛选器 + const woFilter = document.getElementById('workorder-tenant-filter'); + if (woFilter) { + const currentVal = woFilter.value; + woFilter.innerHTML = '' + tenants.map(t => + `` + ).join(''); + } } catch (e) { console.warn('加载租户列表失败:', e); } @@ -2800,6 +2810,7 @@ class TSPDashboard { try { const statusFilter = document.getElementById('workorder-status-filter')?.value || 'all'; const priorityFilter = document.getElementById('workorder-priority-filter')?.value || 'all'; + const tenantFilter = document.getElementById('workorder-tenant-filter')?.value || 'all'; let url = '/api/workorders'; const params = new URLSearchParams(); @@ -2808,6 +2819,7 @@ class TSPDashboard { params.append('per_page', pageSize.toString()); if (statusFilter !== 'all') params.append('status', statusFilter); if (priorityFilter !== 'all') params.append('priority', priorityFilter); + if (tenantFilter !== 'all') params.append('tenant_id', tenantFilter); // 添加强制刷新参数 if (forceRefresh) { @@ -2872,7 +2884,7 @@ class TSPDashboard {
${workorder.description ? workorder.description.substring(0, 100) + (workorder.description.length > 100 ? '...' : '') : '无处理过程'}
+${workorder.description ? workorder.description.substring(0, 100) + (workorder.description.length > 100 ? '...' : '') : '无问题描述'}