Files
ZDXX/2_3banben/models.py

131 lines
4.8 KiB
Python
Raw 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
# 引入 UserMixin 是 Flask 标准做法,虽然你主要用 JWT但保留它可以方便未来扩展或使用某些 Flask 插件
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from extensions import db
# =======================
# 数据库 1: 业务数据 (默认数据库 / devices.db)
# =======================
class Device(db.Model):
__tablename__ = 'devices'
# 默认数据库,无需 bind_key
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, index=True)
source = db.Column(db.String(50))
# 快照字段(爬虫自动更新)
status = db.Column(db.String(50))
current_value = db.Column(db.String(200))
latest_time = db.Column(db.String(50))
json_data = db.Column(db.Text) # 存储完整原始JSON
check_time = db.Column(db.String(50))
reason = db.Column(db.String(255))
offset = db.Column(db.String(50)) # 时间偏移量说明
# 手动录入字段 (管理员/工程师可改)
install_site = db.Column(db.String(100), default="")
is_maintaining = db.Column(db.Boolean, default=False)
is_hidden = db.Column(db.Boolean, default=False)
def to_dict(self):
"""
转换为前端友好的字典格式
"""
# 简单处理状态:只要不是明确的离线/异常,就视为 online
api_status = 'offline' if self.status in ['离线', '异常', '已离线'] else 'online'
return {
'id': self.id,
'name': self.name,
'source': self.source,
'latest_time': self.latest_time,
'status': api_status, # 给前端图标用的状态 (online/offline)
'status_text': self.status, # 显示在界面的原始状态文字
'value': self.current_value,
'reason': self.reason,
'install_site': self.install_site or '',
'is_maintaining': self.is_maintaining,
'is_hidden': self.is_hidden,
'offset': self.offset
}
class DeviceHistory(db.Model):
__tablename__ = 'device_history'
id = db.Column(db.Integer, primary_key=True)
# 这里虽有 ForeignKey但在 SQLite 中如果不开启外键约束检查通常没事
# 但建议逻辑上视为级联删除
device_id = db.Column(db.Integer, db.ForeignKey('devices.id'))
data_time = db.Column(db.String(50))
status = db.Column(db.String(50))
result_data = db.Column(db.String(200), default="")
json_data = db.Column(db.Text)
file_path = db.Column(db.String(255)) # 如果有文件下载功能
recorded_at = db.Column(db.DateTime, default=datetime.now)
class MaintenanceLog(db.Model):
__tablename__ = 'maintenance_logs'
id = db.Column(db.Integer, primary_key=True)
device_name = db.Column(db.String(100), nullable=False)
engineer = db.Column(db.String(50))
location = db.Column(db.String(100))
content = db.Column(db.Text)
timestamp = db.Column(db.DateTime, default=datetime.now)
def to_dict(self):
return {
'id': self.id,
'device_name': self.device_name,
'engineer': self.engineer or '',
'location': self.location or '',
'content': self.content,
'timestamp': self.timestamp.strftime('%Y-%m-%d %H:%M:%S')
}
# =======================
# 数据库 2: 用户管理 (users.db)
# =======================
class User(UserMixin, db.Model):
__bind_key__ = 'users_db' # 关键:指定存储在 users.db
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(128))
# 🟢 核心字段:角色权限
# 可选值: 'admin' (超管), 'engineer' (工程师), 'client' (客户)
role = db.Column(db.String(20), default='client')
created_at = db.Column(db.DateTime, default=datetime.now)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class UserDevicePermission(db.Model):
"""
关联表存储用户ID和设备ID的对应关系。
注意:因为跨数据库,这里不能使用 ForeignKey 约束指向 Device 表。
我们只存储纯整数 ID (device_id),逻辑关联在 api.py 中处理。
"""
__bind_key__ = 'users_db'
__tablename__ = 'user_device_permissions'
id = db.Column(db.Integer, primary_key=True)
# 关联 User 表 (同库)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
# 关联 Device 表 (异库,只存 ID)
device_id = db.Column(db.Integer, nullable=False)