Kamixitong/app/models/ticket.py
2025-12-12 11:35:14 +08:00

181 lines
6.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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}>'