Kamixitong/app/web/templates/user/ticket.html
2025-11-19 22:49:24 +08:00

410 lines
16 KiB
HTML

{% extends "user/base.html" %}
{% block title %}售后服务 - {{ config.SITE_NAME or '软件授权管理系统' }}{% endblock %}
{% block extra_css %}
<style>
.ticket-form {
background: #f8f9fa;
border-radius: 10px;
padding: 2rem;
}
.ticket-history {
border-left: 3px solid #667eea;
}
.ticket-item {
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1rem;
}
.ticket-status-open {
background-color: #d1ecf1;
border-color: #bee5eb;
}
.ticket-status-closed {
background-color: #d4edda;
border-color: #c3e6cb;
}
.emergency-contact {
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
color: white;
border-radius: 10px;
padding: 2rem;
text-align: center;
}
</style>
{% endblock %}
{% block content %}
<div class="container py-4">
<div class="row">
<div class="col-12">
<h1 class="mb-4">售后服务</h1>
</div>
</div>
<div class="row">
<!-- 紧急通道 -->
<div class="col-lg-4 mb-4">
<div class="emergency-contact">
<h3 class="mb-3">
<i class="fas fa-exclamation-circle me-2"></i>
紧急通道
</h3>
<p class="mb-4">遇到紧急问题?立即联系我们</p>
<button class="btn btn-light" data-bs-toggle="modal" data-bs-target="#wechatModal">
<i class="fab fa-weixin me-2"></i>微信紧急联系
</button>
</div>
</div>
<!-- 工单提交表单 -->
<div class="col-lg-8 mb-4">
<div class="card shadow-sm">
<div class="card-header">
<h5 class="mb-0">提交工单</h5>
</div>
<div class="card-body">
<form id="ticketForm" class="ticket-form">
<div class="mb-3">
<label for="contactName" class="form-label">联系人姓名</label>
<input type="text" class="form-control" id="contactName" required>
</div>
<div class="mb-3">
<label for="contactPhone" class="form-label">联系电话</label>
<input type="tel" class="form-control" id="contactPhone" required>
</div>
<div class="mb-3">
<label for="contactEmail" class="form-label">联系邮箱</label>
<input type="email" class="form-control" id="contactEmail" required>
</div>
<div class="mb-3">
<label for="productSelect" class="form-label">相关产品</label>
<select class="form-select" id="productSelect" required>
<option value="">请选择相关产品</option>
<option value="1">产品一</option>
<option value="2">产品二</option>
<option value="3">产品三</option>
</select>
</div>
<div class="mb-3">
<label for="ticketTitle" class="form-label">工单标题</label>
<input type="text" class="form-control" id="ticketTitle" required>
</div>
<div class="mb-3">
<label for="ticketContent" class="form-label">问题描述</label>
<textarea class="form-control" id="ticketContent" rows="5" required></textarea>
</div>
<div class="mb-3">
<label for="prioritySelect" class="form-label">优先级</label>
<select class="form-select" id="prioritySelect">
<option value="1"></option>
<option value="2" selected></option>
<option value="3"></option>
<option value="4">紧急</option>
</select>
</div>
<button type="submit" class="btn btn-primary w-100" id="submitTicketBtn">
<i class="fas fa-paper-plane me-2"></i>提交工单
</button>
</form>
</div>
</div>
</div>
</div>
<!-- 工单历史 -->
<div class="row">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header">
<h5 class="mb-0">工单历史</h5>
</div>
<div class="card-body">
<div id="ticketsContainer">
<!-- 工单列表将通过JavaScript动态加载 -->
<div class="text-center py-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
<p class="mt-2">正在加载工单历史...</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 微信二维码模态框 -->
<div class="modal fade" id="wechatModal" tabindex="-1" aria-labelledby="wechatModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="wechatModalLabel">紧急联系</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<p>扫码添加微信,快速响应紧急需求</p>
<img src="/static/images/wechat-qrcode.jpg" alt="微信二维码" class="img-fluid mb-3" style="max-width: 200px;">
<p class="text-muted small">微信ID: TaiYiSupport</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// 售后服务页面JavaScript
document.addEventListener('DOMContentLoaded', function() {
console.log('售后服务页面加载完成');
// 初始化产品列表
loadProducts();
// 初始化工单历史
loadTickets();
// 工单提交表单事件
document.getElementById('ticketForm').addEventListener('submit', function(e) {
e.preventDefault();
submitTicket();
});
});
// 提交工单
function submitTicket() {
const formData = {
contact_name: document.getElementById('contactName').value.trim(),
contact_phone: document.getElementById('contactPhone').value.trim(),
contact_email: document.getElementById('contactEmail').value.trim(),
product_id: document.getElementById('productSelect').value,
title: document.getElementById('ticketTitle').value.trim(),
content: document.getElementById('ticketContent').value.trim(),
priority: document.getElementById('prioritySelect').value
};
// 基础验证
if (!formData.contact_name || !formData.contact_phone || !formData.contact_email ||
!formData.product_id || !formData.title || !formData.content) {
showNotification('请填写所有必填字段', 'warning');
return;
}
// 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(formData.contact_phone)) {
showNotification('请输入正确的手机号码', 'warning');
return;
}
// 验证邮箱格式
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.contact_email)) {
showNotification('请输入正确的邮箱地址', 'warning');
return;
}
// 显示加载状态
const submitBtn = document.getElementById('submitTicketBtn');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status"></span>提交中...';
submitBtn.disabled = true;
// 调用API提交工单
apiRequest('/api/v1/user/tickets', {
method: 'POST',
body: JSON.stringify(formData)
})
.then(data => {
if (data.success) {
showNotification('工单提交成功!', 'success');
document.getElementById('ticketForm').reset();
loadTickets(); // 重新加载工单列表
} else {
showNotification('工单提交失败: ' + data.message, 'error');
}
})
.catch(error => {
showNotification('工单提交失败,请稍后重试', 'error');
console.error('提交工单失败:', error);
})
.finally(() => {
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
});
}
// 加载工单历史
function loadTickets() {
// 获取手机号
const phone = document.getElementById('contactPhone').value.trim();
// 如果没有输入手机号,不加载工单列表
if (!phone) {
document.getElementById('ticketsContainer').innerHTML = `
<div class="text-center py-5">
<i class="fas fa-info-circle fa-2x text-muted mb-3"></i>
<h4 class="text-muted">请输入手机号查看工单历史</h4>
<p class="text-muted">输入手机号后将自动显示相关工单记录</p>
</div>
`;
return;
}
// 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(phone)) {
document.getElementById('ticketsContainer').innerHTML = `
<div class="text-center py-5">
<i class="fas fa-exclamation-circle fa-2x text-warning mb-3"></i>
<h4 class="text-warning">手机号格式不正确</h4>
<p class="text-muted">请输入正确的11位手机号码</p>
</div>
`;
return;
}
// 显示加载状态
document.getElementById('ticketsContainer').innerHTML = `
<div class="text-center py-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
<p class="mt-2">正在加载工单历史...</p>
</div>
`;
// 调用API获取工单列表
apiRequest(`/api/v1/user/tickets?phone=${phone}`)
.then(data => {
if (data.success) {
renderTickets(data.data);
} else {
showNotification('加载工单历史失败: ' + data.message, 'error');
}
})
.catch(error => {
showNotification('加载工单历史失败,请稍后重试', 'error');
console.error('加载工单历史失败:', error);
});
}
// 渲染工单列表
function renderTickets(tickets) {
const container = document.getElementById('ticketsContainer');
if (tickets.length === 0) {
container.innerHTML = `
<div class="text-center py-5">
<i class="fas fa-ticket-alt fa-3x text-muted mb-3"></i>
<h4 class="text-muted">暂无工单记录</h4>
<p class="text-muted">您还没有提交过工单</p>
</div>
`;
return;
}
let ticketsHtml = '';
tickets.forEach(ticket => {
const statusClass = ticket.status === 1 ? 'ticket-status-open' : 'ticket-status-closed';
const statusText = ticket.status === 1 ? '处理中' : '已关闭';
const priorityText = ['未知', '低', '中', '高', '紧急'][ticket.priority] || '未知';
ticketsHtml += `
<div class="ticket-item ${statusClass}">
<div class="row">
<div class="col-md-9">
<h5 class="mb-2">${ticket.title}</h5>
<p class="mb-2">${ticket.description.substring(0, 100)}${ticket.description.length > 100 ? '...' : ''}</p>
<div class="d-flex flex-wrap gap-3 text-muted">
<small><i class="fas fa-calendar me-1"></i> ${formatDate(ticket.create_time)}</small>
<small><i class="fas fa-user me-1"></i> ${ticket.contact_person}</small>
<small><i class="fas fa-box me-1"></i> ${ticket.product_name || '未知产品'}</small>
<small><i class="fas fa-exclamation-circle me-1"></i> ${priorityText}</small>
</div>
</div>
<div class="col-md-3 text-md-end">
<span class="badge ${ticket.status === 1 ? 'bg-info' : 'bg-success'}">
${statusText}
</span>
<div class="mt-2">
<button class="btn btn-sm btn-outline-primary" onclick="viewTicket('${ticket.ticket_number}')">
<i class="fas fa-eye me-1"></i>查看
</button>
</div>
</div>
</div>
</div>
`;
});
container.innerHTML = ticketsHtml;
}
// 查看工单详情
function viewTicket(ticketId) {
showNotification('查看工单详情功能待实现', 'info');
// 这里可以跳转到工单详情页面或显示模态框
}
// 加载产品列表
function loadProducts() {
// 调用API获取产品列表
apiRequest('/api/v1/user/products')
.then(data => {
if (data.success) {
renderProducts(data.data.products || []);
} else {
showNotification('加载产品列表失败: ' + data.message, 'error');
}
})
.catch(error => {
showNotification('加载产品列表失败,请稍后重试', 'error');
console.error('加载产品列表失败:', error);
});
}
// 渲染产品列表
function renderProducts(products) {
const select = document.getElementById('productSelect');
// 清空现有选项(保留默认选项)
select.innerHTML = '<option value="">请选择相关产品</option>';
// 添加产品选项
products.forEach(product => {
const option = document.createElement('option');
option.value = product.product_id;
option.textContent = product.product_name;
select.appendChild(option);
});
}
// 监听手机号输入框变化,自动加载工单历史
document.getElementById('contactPhone').addEventListener('input', function() {
// 延迟加载,避免频繁请求
clearTimeout(this.loadTimer);
this.loadTimer = setTimeout(() => {
loadTickets();
}, 500);
});
</script>
{% endblock %}