feat: 优化飞书集成、知识库、Agent、工单管理及AI建议功能,统一前端对话字体样式并移除工单模板文件。
This commit is contained in:
@@ -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);
|
||||
});
|
||||
Reference in New Issue
Block a user