181 lines
6.7 KiB
Python
181 lines
6.7 KiB
Python
from datetime import datetime
|
||
from app import db
|
||
from sqlalchemy.orm import relationship
|
||
|
||
class TicketReply(db.Model):
|
||
"""工单回复模型"""
|
||
__tablename__ = 'ticket_reply'
|
||
|
||
reply_id = db.Column(db.Integer, primary_key=True)
|
||
ticket_id = db.Column(db.Integer, db.ForeignKey('ticket.ticket_id'), nullable=False)
|
||
content = db.Column(db.Text, nullable=False) # 回复内容(支持HTML)
|
||
creator = db.Column(db.String(32), nullable=True) # 回复人(管理员账号或系统)
|
||
create_time = db.Column(db.DateTime, default=datetime.utcnow)
|
||
|
||
def to_dict(self):
|
||
"""转换为字典"""
|
||
return {
|
||
'reply_id': self.reply_id,
|
||
'ticket_id': self.ticket_id,
|
||
'content': self.content,
|
||
'creator': self.creator,
|
||
'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None
|
||
}
|
||
|
||
class Ticket(db.Model):
|
||
"""工单模型"""
|
||
__tablename__ = 'ticket'
|
||
|
||
ticket_id = db.Column(db.Integer, primary_key=True)
|
||
ticket_number = db.Column(db.String(32), unique=True, nullable=False) # 工单编号
|
||
title = db.Column(db.String(128), nullable=False)
|
||
product_id = db.Column(db.String(32), db.ForeignKey('product.product_id'), nullable=False)
|
||
software_version = db.Column(db.String(16), nullable=True)
|
||
machine_code = db.Column(db.String(64), nullable=True)
|
||
license_key = db.Column(db.String(32), nullable=True)
|
||
description = db.Column(db.Text, nullable=False)
|
||
priority = db.Column(db.Integer, nullable=False, default=1) # 0=低, 1=中, 2=高
|
||
status = db.Column(db.Integer, nullable=False, default=0) # 0=待处理, 1=处理中, 2=已解决, 3=已关闭
|
||
operator = db.Column(db.String(32), nullable=True) # 处理人(管理员账号)
|
||
remark = db.Column(db.Text, nullable=True) # 处理备注
|
||
contact_person = db.Column(db.String(64), nullable=True) # 联系人姓名
|
||
phone = db.Column(db.String(20), nullable=True) # 联系电话
|
||
create_time = db.Column(db.DateTime, default=datetime.utcnow)
|
||
update_time = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||
resolve_time = db.Column(db.DateTime, nullable=True) # 解决时间
|
||
close_time = db.Column(db.DateTime, nullable=True) # 关闭时间
|
||
|
||
# 关系
|
||
replies = relationship('TicketReply', backref='ticket', lazy='dynamic', cascade='all, delete-orphan')
|
||
|
||
def __init__(self, **kwargs):
|
||
super(Ticket, self).__init__(**kwargs)
|
||
# 如果没有提供工单编号,则自动生成
|
||
if not self.ticket_number:
|
||
self.ticket_number = self.generate_ticket_number()
|
||
|
||
def generate_ticket_number(self):
|
||
"""生成工单编号 TKT+日期+4位序号"""
|
||
from datetime import datetime
|
||
import random
|
||
date_str = datetime.now().strftime('%Y%m%d')
|
||
random_str = str(random.randint(1000, 9999))
|
||
return f"TKT{date_str}{random_str}"
|
||
|
||
def get_priority_name(self):
|
||
"""获取优先级名称"""
|
||
priority_map = {
|
||
0: '低',
|
||
1: '中',
|
||
2: '高'
|
||
}
|
||
return priority_map.get(self.priority, '未知')
|
||
|
||
def get_status_name(self):
|
||
"""获取状态名称"""
|
||
status_map = {
|
||
0: '待处理',
|
||
1: '处理中',
|
||
2: '已解决',
|
||
3: '已关闭'
|
||
}
|
||
return status_map.get(self.status, '未知')
|
||
|
||
def is_pending(self):
|
||
"""是否待处理"""
|
||
return self.status == 0
|
||
|
||
def is_processing(self):
|
||
"""是否处理中"""
|
||
return self.status == 1
|
||
|
||
def is_resolved(self):
|
||
"""是否已解决"""
|
||
return self.status == 2
|
||
|
||
def is_closed(self):
|
||
"""是否已关闭"""
|
||
return self.status == 3
|
||
|
||
def assign_to(self, operator):
|
||
"""分配给处理人"""
|
||
self.operator = operator
|
||
if self.status == 0:
|
||
self.status = 1 # 待处理 -> 处理中
|
||
db.session.commit()
|
||
|
||
def resolve(self, remark=None):
|
||
"""解决工单"""
|
||
self.status = 2
|
||
self.resolve_time = datetime.utcnow()
|
||
if remark:
|
||
self.remark = remark
|
||
db.session.commit()
|
||
|
||
def close(self, remark=None):
|
||
"""关闭工单"""
|
||
self.status = 3
|
||
self.close_time = datetime.utcnow()
|
||
if remark:
|
||
self.remark = remark
|
||
db.session.commit()
|
||
|
||
def reopen(self):
|
||
"""重新打开工单"""
|
||
self.status = 1 # 处理中
|
||
self.resolve_time = None
|
||
self.close_time = None
|
||
db.session.commit()
|
||
|
||
def update_status(self, status, remark=None):
|
||
"""更新工单状态"""
|
||
old_status = self.status
|
||
self.status = status
|
||
|
||
# 更新时间戳
|
||
if status == 2 and old_status != 2:
|
||
self.resolve_time = datetime.utcnow()
|
||
elif status == 3 and old_status != 3:
|
||
self.close_time = datetime.utcnow()
|
||
|
||
if remark:
|
||
self.remark = remark
|
||
|
||
db.session.commit()
|
||
|
||
def get_processing_days(self):
|
||
"""获取处理天数"""
|
||
if self.resolve_time:
|
||
return (self.resolve_time - self.create_time).days
|
||
return (datetime.utcnow() - self.create_time).days
|
||
|
||
def to_dict(self):
|
||
"""转换为字典"""
|
||
return {
|
||
'ticket_id': self.ticket_id,
|
||
'ticket_number': self.ticket_number,
|
||
'title': self.title,
|
||
'product_id': self.product_id,
|
||
'product_name': self.product.product_name if self.product else None,
|
||
'software_version': self.software_version,
|
||
'machine_code': self.machine_code,
|
||
'license_key': self.license_key,
|
||
'description': self.description,
|
||
'priority': self.priority,
|
||
'priority_name': self.get_priority_name(),
|
||
'status': self.status,
|
||
'status_name': self.get_status_name(),
|
||
'operator': self.operator,
|
||
'remark': self.remark,
|
||
'contact_person': self.contact_person,
|
||
'phone': self.phone,
|
||
'processing_days': self.get_processing_days(),
|
||
'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None,
|
||
'update_time': self.update_time.strftime('%Y-%m-%d %H:%M:%S') if self.update_time else None,
|
||
'resolve_time': self.resolve_time.strftime('%Y-%m-%d %H:%M:%S') if self.resolve_time else None,
|
||
'close_time': self.close_time.strftime('%Y-%m-%d %H:%M:%S') if self.close_time else None,
|
||
'replies': [reply.to_dict() for reply in self.replies.order_by(TicketReply.create_time.asc()).all()]
|
||
}
|
||
|
||
def __repr__(self):
|
||
return f'<Ticket {self.ticket_id}: {self.title}>' |