feat: 优化飞书集成、知识库、Agent、工单管理及AI建议功能,统一前端对话字体样式并移除工单模板文件。

This commit is contained in:
zhaojie
2026-02-11 22:53:08 +08:00
parent f8f3738134
commit d0dd18342f
31 changed files with 1384 additions and 211 deletions

View File

@@ -108,6 +108,88 @@ export default class WorkOrders {
</nav>
</div>
</div>
<!-- 工单详情模态框 -->
<div class="modal fade" id="workorder-detail-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header bg-light">
<h5 class="modal-title">
<i class="fas fa-file-alt text-primary me-2"></i>工单详情
<span class="badge bg-secondary ms-2" id="modal-status-badge">加载中...</span>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-0">
<div class="row g-0 h-100">
<!-- 左侧:基本信息 -->
<div class="col-md-7 border-end p-4">
<h3 id="modal-title" class="mb-3">工单标题</h3>
<div class="row g-3 mb-4">
<div class="col-6 col-md-4">
<label class="form-label text-muted small">工单ID</label>
<div class="fw-bold" id="modal-id">-</div>
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted small">优先级</label>
<div id="modal-priority">-</div>
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted small">分类</label>
<div id="modal-category">-</div>
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted small">创建时间</label>
<div id="modal-created-at">-</div>
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted small">用户/VIN</label>
<div id="modal-user">-</div>
</div>
</div>
<div class="mb-4">
<label class="form-label fw-bold">问题描述</label>
<div class="bg-light p-3 rounded" id="modal-description" style="min-height: 80px;">
-
</div>
</div>
<div class="mb-4">
<label class="form-label fw-bold text-primary">
<i class="fas fa-robot me-1"></i>AI 智能分析与建议
</label>
<div class="card border-primary-lt">
<div class="card-body bg-azure-lt" id="modal-ai-analysis">
暂无 AI 分析
</div>
</div>
</div>
</div>
<!-- 右侧:对话历史/详细记录 -->
<div class="col-md-5 bg-light p-0 d-flex flex-column" style="height: 600px;">
<div class="p-3 border-bottom bg-white">
<h6 class="mb-0 fw-bold"><i class="fas fa-history me-2"></i>处理记录 / 对话历史</h6>
</div>
<div class="flex-grow-1 p-3 overflow-auto" id="modal-chat-history">
<!-- 聊天记录将动态插入这里 -->
<div class="text-center text-muted mt-5">
<i class="fas fa-comments fa-2x mb-3"></i>
<p>暂无相关对话记录</p>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="modal-edit-btn">编辑工单</button>
</div>
</div>
</div>
</div>
`;
}
@@ -302,9 +384,112 @@ export default class WorkOrders {
}
// 全局函数供表格操作使用
window.viewWorkOrder = function(id) {
if (window.showToast) {
window.showToast(`查看工单 ${id} 功能开发中`, 'info');
window.viewWorkOrder = async function(id) {
try {
// 显示模态框(先显示加载状态)
const modalEl = document.getElementById('workorder-detail-modal');
const modal = new bootstrap.Modal(modalEl);
modal.show();
// 重置内容
document.getElementById('modal-status-badge').innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
document.getElementById('modal-ai-analysis').innerHTML = '<div class="spinner-border spinner-border-sm text-primary"></div> 正在分析...';
document.getElementById('modal-chat-history').innerHTML = '<div class="text-center mt-5"><i class="fas fa-spinner fa-spin fa-2x"></i></div>';
// 获取详情
const response = await fetch(`/api/workorders/${id}`);
const result = await response.json();
if (!result.success) {
alert('获取工单详情失败');
return;
}
const wo = result.workorder;
// 填充基本信息
document.getElementById('modal-title').textContent = wo.title;
document.getElementById('modal-id').textContent = wo.order_id || wo.id;
document.getElementById('modal-category').textContent = wo.category || '-';
document.getElementById('modal-created-at').textContent = new Date(wo.created_at).toLocaleString();
document.getElementById('modal-user').textContent = wo.user_id || '-';
document.getElementById('modal-description').textContent = wo.description || '无描述';
// 状态徽章
const statusMap = {
'open': '<span class="badge bg-danger">待处理</span>',
'in_progress': '<span class="badge bg-warning">处理中</span>',
'resolved': '<span class="badge bg-success">已解决</span>',
'closed': '<span class="badge bg-secondary">已关闭</span>'
};
document.getElementById('modal-status-badge').innerHTML = statusMap[wo.status] || wo.status;
// 优先级
const priorityMap = {
'low': '<span class="badge bg-info">低</span>',
'medium': '<span class="badge bg-warning">中</span>',
'high': '<span class="badge bg-danger">高</span>',
'urgent': '<span class="badge bg-dark">紧急</span>'
};
document.getElementById('modal-priority').innerHTML = priorityMap[wo.priority] || wo.priority;
// AI 分析/建议
if (wo.resolution) {
document.getElementById('modal-ai-analysis').innerHTML = `
<div style="white-space: pre-wrap; font-family: inherit;">${wo.resolution}</div>
`;
} else {
document.getElementById('modal-ai-analysis').textContent = '暂无 AI 分析建议';
}
// 渲染对话/处理历史 (模拟数据或真实数据)
const historyContainer = document.getElementById('modal-chat-history');
// 这里假设后端返回的详情中包含 history 或 timeline
// 如果没有,暂时显示描述作为第一条记录
let historyHtml = '';
// 模拟一条初始记录
historyHtml += `
<div class="mb-3">
<div class="d-flex align-items-center mb-1">
<span class="badge bg-blue-lt me-2">用户</span>
<small class="text-muted">${new Date(wo.created_at).toLocaleString()}</small>
</div>
<div class="bg-white p-3 border rounded">
${wo.description}
</div>
</div>
`;
if (wo.timeline && wo.timeline.length > 0) {
// 如果有真实的时间轴数据
historyHtml = wo.timeline.map(item => `
<div class="mb-3">
<div class="d-flex align-items-center mb-1">
<span class="badge bg-${item.type === 'ai' ? 'purple-lt' : 'blue-lt'} me-2">
${item.author || (item.type === 'ai' ? 'AI 助手' : '系统')}
</span>
<small class="text-muted">${new Date(item.timestamp).toLocaleString()}</small>
</div>
<div class="bg-${item.type === 'ai' ? 'azure-lt' : 'white'} p-3 border rounded">
${item.content}
</div>
</div>
`).join('');
}
historyContainer.innerHTML = historyHtml;
// 绑定编辑按钮
document.getElementById('modal-edit-btn').onclick = () => {
modal.hide();
editWorkOrder(id);
};
} catch (e) {
console.error('查看工单详情失败', e);
alert('查看详情失败: ' + e.message);
}
};
@@ -315,15 +500,50 @@ window.editWorkOrder = function(id) {
};
window.deleteWorkOrder = function(id) {
if (confirm(`确定要删除工单 ${id} 吗?`)) {
if (window.showToast) {
window.showToast('删除功能开发中', 'info');
}
if (!confirm(`确定要删除工单 ${id} 吗?`)) {
return;
}
(async () => {
try {
const response = await fetch(`/api/workorders/${id}`, {
method: 'DELETE'
});
const result = await response.json();
if (response.ok && result.success) {
if (window.showToast) {
window.showToast(result.message || `工单 ${id} 删除成功`, 'success');
}
// 通知当前页面刷新工单列表(保持当前页)
const event = new CustomEvent('workorder-deleted', { detail: { id } });
document.dispatchEvent(event);
} else {
if (window.showToast) {
window.showToast(result.message || '删除工单失败', 'error');
} else {
alert(result.message || '删除工单失败');
}
}
} catch (error) {
console.error('删除工单失败:', error);
if (window.showToast) {
window.showToast('删除失败,请检查网络或查看控制台日志', 'error');
} else {
alert('删除失败,请检查网络或查看控制台日志');
}
}
})();
};
window.changePage = function(page) {
// 重新加载当前页面实例
const event = new CustomEvent('changePage', { detail: { page } });
document.dispatchEvent(event);
};
};
// 监听删除事件,触发当前 WorkOrders 列表刷新(保持当前页)
document.addEventListener('workorder-deleted', () => {
const event = new CustomEvent('reloadWorkOrders');
document.dispatchEvent(event);
});