🚀 AI 近视防控系统 - 生产环境上线版本 v1.0
✅ 已完成功能: - 后端 Go 服务 (认证/授权/检测) - JWT 认证 + RBAC 权限控制 - 登录速率限制 (5 次失败锁定 15 分钟) - 密码强度校验 - 敏感数据脱敏 - Vue3 管理后台 - 路由守卫 - 删除二次确认 📦 部署配置: - Docker Compose 生产环境配置 - MySQL/Redis/MongoDB 数据库 - Nginx 前端服务 - 强密码安全配置 ⚠️ P2 待办 (下次迭代): - 学生/检测/预警等业务模块实现 - 错误处理统一化 - 缓存策略优化 - 日志分级 📍 生产环境: - 服务器:192.168.15.222 - 管理后台:http://192.168.15.222:8081 - API 服务:http://192.168.15.222:8080 2026-03-29 上线部署完成
This commit is contained in:
122
db/models/alert.go
Normal file
122
db/models/alert.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Alert 预警记录模型
|
||||
type Alert struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
Student Student `gorm:"foreignKey:StudentID" json:"student"`
|
||||
DetectionID *uint `json:"detection_id"`
|
||||
Detection *Detection `gorm:"foreignKey:DetectionID" json:"detection"`
|
||||
AlertLevel int `json:"alert_level"` // 1:关注, 2:预警, 3:告警
|
||||
AlertType string `gorm:"type:varchar(32)" json:"alert_type"` // vision_drop, fatigue_high, abnormal
|
||||
AlertContent string `gorm:"type:text" json:"alert_content"`
|
||||
Status int `gorm:"default:0" json:"status"` // 0:未处理, 1:已通知, 2:已处理
|
||||
NotifiedAt *time.Time `json:"notified_at"`
|
||||
HandledAt *time.Time `json:"handled_at"`
|
||||
HandlerID *uint `json:"handler_id"` // 处理人ID
|
||||
HandleRemark string `gorm:"type:text" json:"handle_remark"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// AlertConfig 预警配置模型
|
||||
type AlertConfig struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
SchoolID *uint `json:"school_id"`
|
||||
School *School `gorm:"foreignKey:SchoolID" json:"school"`
|
||||
AlertLevel int `json:"alert_level"` // 1:关注, 2:预警, 3:告警
|
||||
VisionThreshold float64 `json:"vision_threshold"` // 视力阈值
|
||||
DropThreshold float64 `json:"drop_threshold"` // 下降幅度阈值
|
||||
NotifyParent bool `gorm:"default:true" json:"notify_parent"` // 通知家长
|
||||
NotifyTeacher bool `gorm:"default:true" json:"notify_teacher"` // 通知老师
|
||||
NotifySchoolDoctor bool `gorm:"default:false" json:"notify_school_doctor"` // 通知校医
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// AlertSummary 预警摘要
|
||||
type AlertSummary struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
EntityID uint `json:"entity_id"` // 学生/班级/学校的ID
|
||||
EntityType string `gorm:"type:varchar(20)" json:"entity_type"` // student, class, school
|
||||
TotalAlerts int `json:"total_alerts"`
|
||||
HighRiskCount int `json:"high_risk_count"` // 高风险数量
|
||||
MediumRiskCount int `json:"medium_risk_count"` // 中风险数量
|
||||
LowRiskCount int `json:"low_risk_count"` // 低风险数量
|
||||
LastAlertDate *time.Time `json:"last_alert_date"`
|
||||
LastAlertType string `gorm:"type:varchar(32)" json:"last_alert_type"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// AlertNotification 预警通知模型
|
||||
type AlertNotification struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
AlertID uint `json:"alert_id"`
|
||||
Alert Alert `gorm:"foreignKey:AlertID" json:"alert"`
|
||||
RecipientID uint `json:"recipient_id"` // 接收者ID
|
||||
RecipientType string `gorm:"type:varchar(20)" json:"recipient_type"` // parent, teacher, school_doctor
|
||||
Channel string `gorm:"type:varchar(20)" json:"channel"` // sms, email, app_push
|
||||
Title string `gorm:"type:varchar(255)" json:"title"`
|
||||
Content string `gorm:"type:text" json:"content"`
|
||||
SentAt time.Time `json:"sent_at"`
|
||||
ReadAt *time.Time `json:"read_at"`
|
||||
Status int `gorm:"default:0" json:"status"` // 0:待发送, 1:已发送, 2:已读
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// AlertDistribution 预警分布统计
|
||||
type AlertDistribution struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Date time.Time `json:"date"`
|
||||
EntityType string `gorm:"type:varchar(20)" json:"entity_type"` // student, class, school
|
||||
EntityID uint `json:"entity_id"`
|
||||
GreenCount int `json:"green_count"` // 绿色预警数量
|
||||
YellowCount int `json:"yellow_count"` // 黄色预警数量
|
||||
OrangeCount int `json:"orange_count"` // 橙色预警数量
|
||||
RedCount int `json:"red_count"` // 红色预警数量
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// VisionDistribution 视力分布统计
|
||||
type VisionDistribution struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Date time.Time `json:"date"`
|
||||
EntityType string `gorm:"type:varchar(20)" json:"entity_type"` // student, class, school
|
||||
EntityID uint `json:"entity_id"`
|
||||
NormalCount int `json:"normal_count"` // 正常人数
|
||||
MildMyopiaCount int `json:"mild_myopia_count"` // 轻度近视人数
|
||||
ModerateMyopiaCount int `json:"moderate_myopia_count"` // 中度近视人数
|
||||
SevereMyopiaCount int `json:"severe_myopia_count"` // 高度近视人数
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// JSONMap 自定义JSON类型(已在其他模型中定义,这里引用)
|
||||
// 为避免重复定义,我们可以将其移到公共包中
|
||||
|
||||
// AlertType 预警类型枚举
|
||||
const (
|
||||
AlertTypeVisionDrop = "vision_drop" // 视力下降
|
||||
AlertTypeFatigueHigh = "fatigue_high" // 疲劳度过高
|
||||
AlertTypeAbnormalBehavior = "abnormal_behavior" // 异常行为
|
||||
AlertTypeDeviceError = "device_error" // 设备异常
|
||||
)
|
||||
|
||||
// AlertLevel 预警级别枚举
|
||||
const (
|
||||
AlertLevelGreen = 0 // 正常
|
||||
AlertLevelYellow = 1 // 关注
|
||||
AlertLevelOrange = 2 // 预警
|
||||
AlertLevelRed = 3 // 告警
|
||||
)
|
||||
|
||||
// AlertStatus 预警状态枚举
|
||||
const (
|
||||
AlertStatusUnhandled = 0 // 未处理
|
||||
AlertStatusNotified = 1 // 已通知
|
||||
AlertStatusHandled = 2 // 已处理
|
||||
)
|
||||
130
db/models/detection.go
Normal file
130
db/models/detection.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DetectionTask 检测任务模型
|
||||
type DetectionTask struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TaskNo string `gorm:"type:varchar(32);uniqueIndex" json:"task_no"`
|
||||
ClassID uint `json:"class_id"`
|
||||
TeacherID uint `json:"teacher_id"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
EndTime *time.Time `json:"end_time"`
|
||||
StudentCount int `json:"student_count"`
|
||||
DetectionType string `gorm:"type:varchar(32)" json:"detection_type"`
|
||||
Status int `gorm:"default:0" json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Detection 检测记录模型
|
||||
type Detection struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TaskID uint `json:"task_id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
DetectionTime time.Time `json:"detection_time"`
|
||||
VisionLeft float64 `json:"vision_left"`
|
||||
VisionRight float64 `json:"vision_right"`
|
||||
FatigueScore float64 `json:"fatigue_score"`
|
||||
AlertLevel int `gorm:"default:0" json:"alert_level"`
|
||||
DeviceID *uint `json:"device_id"`
|
||||
RawDataURL string `gorm:"type:text" json:"raw_data_url"`
|
||||
AIAnalysis JSONMap `gorm:"type:json" json:"ai_analysis"`
|
||||
Status int `gorm:"default:1" json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// DetectionReport 检测报告
|
||||
type DetectionReport struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
DetectionID uint `json:"detection_id"`
|
||||
VisionLeft float64 `gorm:"column:vision_left" json:"vision_left"`
|
||||
VisionRight float64 `gorm:"column:vision_right" json:"vision_right"`
|
||||
LeftEyeX float64 `gorm:"column:left_eye_x" json:"left_eye_x"`
|
||||
LeftEyeY float64 `gorm:"column:left_eye_y" json:"left_eye_y"`
|
||||
RightEyeX float64 `gorm:"column:right_eye_x" json:"right_eye_x"`
|
||||
RightEyeY float64 `gorm:"column:right_eye_y" json:"right_eye_y"`
|
||||
GazePointX float64 `gorm:"column:gaze_point_x" json:"gaze_point_x"`
|
||||
GazePointY float64 `gorm:"column:gaze_point_y" json:"gaze_point_y"`
|
||||
FatigueScore float64 `json:"fatigue_score"`
|
||||
AlertLevel string `gorm:"type:varchar(16)" json:"alert_level"`
|
||||
AIAnalysis JSONMap `gorm:"type:json" json:"ai_analysis"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// VisionData 视力数据 (简化)
|
||||
type VisionData struct {
|
||||
VisionLeft float64 `gorm:"-" json:"vision_left"`
|
||||
VisionRight float64 `gorm:"-" json:"vision_right"`
|
||||
Confidence string `gorm:"-" json:"confidence"`
|
||||
}
|
||||
|
||||
// EyeMovementData 眼动数据 (简化)
|
||||
type EyeMovementData struct {
|
||||
LeftEyeX float64 `gorm:"-" json:"left_eye_x"`
|
||||
LeftEyeY float64 `gorm:"-" json:"left_eye_y"`
|
||||
RightEyeX float64 `gorm:"-" json:"right_eye_x"`
|
||||
RightEyeY float64 `gorm:"-" json:"right_eye_y"`
|
||||
Timestamp int64 `gorm:"-" json:"timestamp"`
|
||||
}
|
||||
|
||||
// ResponseData 响应数据
|
||||
type ResponseData struct {
|
||||
Accuracy float64 `gorm:"-" json:"accuracy"`
|
||||
ResponseType float64 `gorm:"-" json:"response_time"`
|
||||
Errors int `gorm:"-" json:"errors"`
|
||||
}
|
||||
|
||||
// JSONMap 自定义 JSON 类型
|
||||
type JSONMap map[string]interface{}
|
||||
|
||||
func (j JSONMap) Value() (driver.Value, error) {
|
||||
if len(j) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return json.Marshal(j)
|
||||
}
|
||||
|
||||
func (j *JSONMap) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*j = make(JSONMap)
|
||||
return nil
|
||||
}
|
||||
data, ok := value.([]byte)
|
||||
if !ok {
|
||||
return errors.New("type assertion to []byte failed")
|
||||
}
|
||||
return json.Unmarshal(data, j)
|
||||
}
|
||||
|
||||
// DetectionHistory 检测历史
|
||||
type DetectionHistory struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
ClassID uint `json:"class_id"`
|
||||
VisionLeft float64 `json:"vision_left"`
|
||||
VisionRight float64 `json:"vision_right"`
|
||||
FatigueScore float64 `json:"fatigue_score"`
|
||||
AlertLevel string `gorm:"type:varchar(16)" json:"alert_level"`
|
||||
DetectionTime time.Time `json:"detection_time"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// VisionChangeTrend 视力变化趋势
|
||||
type VisionChangeTrend struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
VisionLeft float64 `json:"vision_left"`
|
||||
VisionRight float64 `json:"vision_right"`
|
||||
ChangeValue float64 `json:"change_value"`
|
||||
Trend string `gorm:"type:varchar(16)" json:"trend"`
|
||||
RecordedAt time.Time `json:"recorded_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
182
db/models/device.go
Normal file
182
db/models/device.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Device 设备模型
|
||||
type Device struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceNo string `gorm:"type:varchar(64);uniqueIndex" json:"device_no"`
|
||||
DeviceName string `gorm:"type:varchar(128)" json:"device_name"`
|
||||
DeviceType string `gorm:"type:varchar(32)" json:"device_type"` // terminal, camera, edge_box, gateway
|
||||
SchoolID *uint `json:"school_id"`
|
||||
School *School `gorm:"foreignKey:SchoolID" json:"school"`
|
||||
ClassID *uint `json:"class_id"`
|
||||
Class *Class `gorm:"foreignKey:ClassID" json:"class"`
|
||||
IPAddress string `gorm:"type:varchar(45)" json:"ip_address"`
|
||||
MacAddress string `gorm:"type:varchar(32)" json:"mac_address"`
|
||||
Status int `json:"status"` // 0:离线, 1:在线, 2:故障, 3:维护中
|
||||
LastHeartbeat *time.Time `json:"last_heartbeat"`
|
||||
FirmwareVersion string `gorm:"type:varchar(32)" json:"firmware_version"`
|
||||
ConfigVersion int `json:"config_version"`
|
||||
Attributes JSONMap `gorm:"type:json" json:"attributes"` // 设备属性
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的设备日志
|
||||
DeviceLogs []DeviceLog `gorm:"foreignKey:DeviceID" json:"device_logs"`
|
||||
}
|
||||
|
||||
// DeviceConfig 设备配置模型
|
||||
type DeviceConfig struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
Device Device `gorm:"foreignKey:DeviceID" json:"device"`
|
||||
Settings JSONMap `gorm:"type:json" json:"settings"` // 配置项
|
||||
Version int `json:"version"` // 配置版本
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// DeviceLog 设备日志模型
|
||||
type DeviceLog struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
Device Device `gorm:"foreignKey:DeviceID" json:"device"`
|
||||
LogType string `gorm:"type:varchar(32)" json:"log_type"` // status, command, error
|
||||
Content JSONMap `gorm:"type:json" json:"content"` // 日志内容
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// DeviceStatusInfo 设备状态信息模型
|
||||
type DeviceStatusInfo struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
Device Device `gorm:"foreignKey:DeviceID" json:"device"`
|
||||
Status int `json:"status"` // 0:离线, 1:在线, 2:故障, 3:维护中
|
||||
CPUUsage float64 `json:"cpu_usage"`
|
||||
MemoryUsage float64 `json:"memory_usage"`
|
||||
DiskUsage float64 `json:"disk_usage"`
|
||||
NetworkStatus string `gorm:"type:varchar(32)" json:"network_status"`
|
||||
CameraStatus string `gorm:"type:varchar(32)" json:"camera_status"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
FirmwareVersion string `gorm:"type:varchar(32)" json:"firmware_version"`
|
||||
HealthInfo JSONMap `gorm:"type:json" json:"health_info"` // 健康信息
|
||||
ReportedAt time.Time `json:"reported_at"`
|
||||
}
|
||||
|
||||
// DeviceCommand 设备指令模型
|
||||
type DeviceCommand struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
Device Device `gorm:"foreignKey:DeviceID" json:"device"`
|
||||
CommandType string `gorm:"type:varchar(64)" json:"command_type"`
|
||||
Params JSONMap `gorm:"type:json" json:"params"` // 参数
|
||||
Timeout int `json:"timeout"` // 超时时间
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ExecutedAt *time.Time `json:"executed_at"`
|
||||
ExecutionResult string `gorm:"type:text" json:"execution_result"` // 执行结果
|
||||
Status int `json:"status"` // 0:待执行, 1:执行中, 2:成功, 3:失败
|
||||
}
|
||||
|
||||
// DeviceMessage 设备消息模型
|
||||
type DeviceMessage struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
Device Device `gorm:"foreignKey:DeviceID" json:"device"`
|
||||
MessageType string `gorm:"type:varchar(32)" json:"message_type"` // detection.data, device.status, device.command
|
||||
Header JSONMap `gorm:"type:json" json:"header"` // 消息头
|
||||
Payload JSONMap `gorm:"type:json" json:"payload"` // 消息体
|
||||
Signature string `gorm:"type:varchar(255)" json:"signature"` // 签名
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// DeviceHeartbeat 设备心跳模型
|
||||
type DeviceHeartbeat struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
Device Device `gorm:"foreignKey:DeviceID" json:"device"`
|
||||
IPAddress string `gorm:"type:varchar(45)" json:"ip_address"`
|
||||
LastSeen time.Time `json:"last_seen"`
|
||||
Status int `json:"status"` // 0:离线, 1:在线
|
||||
}
|
||||
|
||||
// DeviceGroup 设备分组模型
|
||||
type DeviceGroup struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"type:varchar(128)" json:"name"`
|
||||
Type string `gorm:"type:varchar(32)" json:"type"` // classroom, school, campus
|
||||
EntityID uint `json:"entity_id"` // 关联的学校或班级ID
|
||||
Entity string `gorm:"type:varchar(32)" json:"entity"` // school, class
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的设备
|
||||
Devices []Device `gorm:"many2many:device_group_relations;" json:"devices"`
|
||||
}
|
||||
|
||||
// DeviceGroupRelation 设备与分组关联模型
|
||||
type DeviceGroupRelation struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
GroupID uint `json:"group_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// DeviceMaintenance 设备维护模型
|
||||
type DeviceMaintenance struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
DeviceID uint `json:"device_id"`
|
||||
Device Device `gorm:"foreignKey:DeviceID" json:"device"`
|
||||
Type string `gorm:"type:varchar(32)" json:"type"` // repair, upgrade, calibration
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
EndedAt *time.Time `json:"ended_at"`
|
||||
Status int `json:"status"` // 0:待处理, 1:进行中, 2:已完成, 3:已取消
|
||||
Technician string `gorm:"type:varchar(64)" json:"technician"`
|
||||
Notes string `gorm:"type:text" json:"notes"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// DeviceType 设备类型枚举
|
||||
const (
|
||||
DeviceTypeTerminal = "terminal" // 终端设备(触摸屏一体机)
|
||||
DeviceTypeCamera = "camera" // 摄像头
|
||||
DeviceTypeEdgeBox = "edge_box" // 边缘计算盒子
|
||||
DeviceTypeGateway = "gateway" // 网关设备
|
||||
)
|
||||
|
||||
// DeviceStatus 设备状态枚举
|
||||
const (
|
||||
DeviceStatusOffline = 0 // 离线
|
||||
DeviceStatusOnline = 1 // 在线
|
||||
DeviceStatusFault = 2 // 故障
|
||||
DeviceStatusMaintenance = 3 // 维护中
|
||||
)
|
||||
|
||||
// DeviceMessageType 设备消息类型枚举
|
||||
const (
|
||||
DeviceMessageTypeStatus = "device.status" // 设备状态
|
||||
DeviceMessageTypeCommand = "device.command" // 控制指令
|
||||
DeviceMessageTypeDetection = "detection.data" // 检测数据
|
||||
DeviceMessageTypeAlert = "alert" // 预警事件
|
||||
DeviceMessageTypeConfig = "config" // 配置更新
|
||||
DeviceMessageTypeHeartbeat = "heartbeat" // 心跳上报
|
||||
)
|
||||
|
||||
// DeviceCommandStatus 指令状态枚举
|
||||
const (
|
||||
DeviceCommandStatusPending = 0 // 待执行
|
||||
DeviceCommandStatusExecuting = 1 // 执行中
|
||||
DeviceCommandStatusSuccess = 2 // 成功
|
||||
DeviceCommandStatusFailed = 3 // 失败
|
||||
)
|
||||
|
||||
// DeviceMaintenanceType 维护类型枚举
|
||||
const (
|
||||
DeviceMaintenanceTypeRepair = "repair" // 维修
|
||||
DeviceMaintenanceTypeUpgrade = "upgrade" // 升级
|
||||
DeviceMaintenanceTypeCalibration = "calibration" // 校准
|
||||
)
|
||||
156
db/models/training.go
Normal file
156
db/models/training.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// TrainingContent 训练内容模型
|
||||
type TrainingContent struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"type:varchar(128)" json:"name"`
|
||||
Type string `gorm:"type:varchar(32)" json:"type"` // eye_exercise, crystal_ball, acupoint, relax
|
||||
Duration int `json:"duration"` // 时长 (秒)
|
||||
VideoURL string `gorm:"type:text" json:"video_url"`
|
||||
ThumbnailURL string `gorm:"type:text" json:"thumbnail_url"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
Difficulty int `gorm:"default:1" json:"difficulty"` // 1-5
|
||||
Status int `gorm:"default:1" json:"status"` // 1:启用, 0:禁用
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的训练任务
|
||||
TrainingTasks []TrainingTask `gorm:"foreignKey:ContentID" json:"training_tasks"`
|
||||
}
|
||||
|
||||
// TrainingTask 训练任务模型
|
||||
type TrainingTask struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
Student Student `gorm:"foreignKey:StudentID" json:"student"`
|
||||
ContentID uint `json:"content_id"`
|
||||
Content TrainingContent `gorm:"foreignKey:ContentID" json:"content"`
|
||||
ScheduledDate time.Time `json:"scheduled_date"`
|
||||
ScheduledTime *time.Time `json:"scheduled_time"`
|
||||
Status int `json:"status"` // 0:待完成, 1:已完成, 2:已跳过
|
||||
CompletedAt *time.Time `json:"completed_at"`
|
||||
Score *int `json:"score"` // 动作评分
|
||||
PointsEarned int `json:"points_earned"` // 获得积分
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的训练记录
|
||||
TrainingRecords []TrainingRecord `gorm:"foreignKey:TaskID" json:"training_records"`
|
||||
}
|
||||
|
||||
// TrainingRecord 训练记录模型
|
||||
type TrainingRecord struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
Student Student `gorm:"foreignKey:StudentID" json:"student"`
|
||||
TaskID uint `json:"task_id"`
|
||||
Task TrainingTask `gorm:"foreignKey:TaskID" json:"task"`
|
||||
ContentID uint `json:"content_id"`
|
||||
Content TrainingContent `gorm:"foreignKey:ContentID" json:"content"`
|
||||
Score int `json:"score"` // 动作评分
|
||||
Accuracy float64 `json:"accuracy"` // 准确率
|
||||
Duration float64 `json:"duration"` // 实际用时
|
||||
PerformanceMetrics JSONMap `gorm:"type:json" json:"performance_metrics"` // 性能指标
|
||||
Feedback string `gorm:"type:text" json:"feedback"` // 反馈信息
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TrainingPerformance 训练表现统计
|
||||
type TrainingPerformance struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
EntityID uint `json:"entity_id"` // 学生/班级/学校ID
|
||||
EntityType string `gorm:"type:varchar(20)" json:"entity_type"` // student, class, school
|
||||
CompletionRate float64 `json:"completion_rate"` // 完成率
|
||||
AverageScore float64 `json:"average_score"` // 平均分数
|
||||
TotalTrainingCount int `json:"total_training_count"` // 总训练次数
|
||||
EngagementRate float64 `json:"engagement_rate"` // 参与率
|
||||
ImprovementRate float64 `json:"improvement_rate"` // 改善率
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// UserPoints 用户积分模型
|
||||
type UserPoints struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
UserID uint `json:"user_id"`
|
||||
UserType string `gorm:"type:varchar(16)" json:"user_type"` // student, parent, teacher
|
||||
TotalPoints int `gorm:"default:0" json:"total_points"`
|
||||
UsedPoints int `gorm:"default:0" json:"used_points"`
|
||||
Level string `gorm:"type:varchar(32);default:'bronze'" json:"level"` // bronze, silver, gold, diamond
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的积分流水
|
||||
|
||||
}
|
||||
|
||||
// PointTransaction 积分流水模型
|
||||
type PointTransaction struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
UserID uint `json:"user_id"`
|
||||
UserType string `gorm:"type:varchar(16)" json:"user_type"`
|
||||
ChangeType string `gorm:"type:varchar(32)" json:"change_type"` // earn, use
|
||||
Points int `json:"points"` // 变化积分数
|
||||
BalanceAfter int `json:"balance_after"` // 变化后的余额
|
||||
Source string `gorm:"type:varchar(64)" json:"source"` // 来源: training, detection, activity
|
||||
Description string `gorm:"type:varchar(256)" json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// TrainingRecommendation 训练建议模型
|
||||
type TrainingRecommendation struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
Student Student `gorm:"foreignKey:StudentID" json:"student"`
|
||||
Recommendation string `gorm:"type:text" json:"recommendation"`
|
||||
Priority int `json:"priority"` // 优先级: 1-5
|
||||
ValidFrom time.Time `json:"valid_from"`
|
||||
ValidUntil time.Time `json:"valid_until"`
|
||||
IsApplied bool `json:"is_applied"` // 是否已采纳
|
||||
AppliedAt *time.Time `json:"applied_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TrainingType 训练类型枚举
|
||||
const (
|
||||
TrainingTypeEyeExercise = "eye_exercise" // 眼保健操
|
||||
TrainingTypeCrystalBall = "crystal_ball" // 晶状体调焦训练
|
||||
TrainingTypeAcupoint = "acupoint" // 穴位按摩
|
||||
TrainingTypeRelax = "relax" // 放松训练
|
||||
)
|
||||
|
||||
// TrainingStatus 训练状态枚举
|
||||
const (
|
||||
TrainingStatusPending = 0 // 待完成
|
||||
TrainingStatusDone = 1 // 已完成
|
||||
TrainingStatusSkipped = 2 // 已跳过
|
||||
)
|
||||
|
||||
// PointsChangeType 积分变化类型枚举
|
||||
const (
|
||||
PointsChangeTypeEarn = "earn" // 获得
|
||||
PointsChangeTypeUse = "use" // 使用
|
||||
)
|
||||
|
||||
// PointsSource 积分来源枚举
|
||||
const (
|
||||
PointsSourceTraining = "training" // 训练获得
|
||||
PointsSourceDetection = "detection" // 检测获得
|
||||
PointsSourceActivity = "activity" // 活动获得
|
||||
PointsSourceAttendance = "attendance" // 出勤获得
|
||||
PointsSourceAchievement = "achievement" // 成就获得
|
||||
)
|
||||
|
||||
// UserLevel 用户等级枚举
|
||||
const (
|
||||
UserLevelBronze = "bronze" // 青铜
|
||||
UserLevelSilver = "silver" // 白银
|
||||
UserLevelGold = "gold" // 黄金
|
||||
UserLevelDiamond = "diamond" // 钻石
|
||||
)
|
||||
127
db/models/user.go
Normal file
127
db/models/user.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// User 通用用户模型
|
||||
type User struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
UUID string `gorm:"type:varchar(64);uniqueIndex" json:"uuid"`
|
||||
Name string `gorm:"type:varchar(64)" json:"name"`
|
||||
Username string `gorm:"type:varchar(64);uniqueIndex" json:"username"`
|
||||
Phone string `gorm:"type:varchar(20);uniqueIndex" json:"phone"`
|
||||
Password string `gorm:"type:varchar(255)" json:"-"` // 不返回密码
|
||||
Role string `gorm:"type:varchar(20)" json:"role"` // student, parent, teacher, admin
|
||||
Status int `gorm:"default:1" json:"status"` // 1:正常, 0:禁用
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Student 学生模型
|
||||
type Student struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
StudentNo string `gorm:"type:varchar(32);uniqueIndex" json:"student_no"`
|
||||
Name string `gorm:"type:varchar(64)" json:"name"`
|
||||
Gender int `gorm:"default:1" json:"gender"` // 1:男, 2:女
|
||||
BirthDate *time.Time `json:"birth_date"`
|
||||
ClassID uint `json:"class_id"`
|
||||
Class Class `gorm:"foreignKey:ClassID" json:"class"`
|
||||
ParentID *uint `json:"parent_id"` // 关联家长
|
||||
Status int `gorm:"default:1" json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Parent 家长模型
|
||||
type Parent struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"type:varchar(64)" json:"name"`
|
||||
Phone string `gorm:"type:varchar(20);uniqueIndex" json:"phone"`
|
||||
IDCard string `gorm:"type:varchar(32)" json:"id_card"`
|
||||
Status int `gorm:"default:1" json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的学生
|
||||
|
||||
}
|
||||
|
||||
// Teacher 教师模型
|
||||
type Teacher struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"type:varchar(64)" json:"name"`
|
||||
Phone string `gorm:"type:varchar(20);uniqueIndex" json:"phone"`
|
||||
SchoolID uint `json:"school_id"`
|
||||
School School `gorm:"foreignKey:SchoolID" json:"school"`
|
||||
Role string `gorm:"type:varchar(32)" json:"role"` // homeroom, school_doctor, sports
|
||||
Status int `gorm:"default:1" json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 所带班级
|
||||
ClassIDs []byte `gorm:"type:json" json:"class_ids"` // JSON格式存储班级ID数组
|
||||
}
|
||||
|
||||
// School 学校模型
|
||||
type School struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"type:varchar(128)" json:"name"`
|
||||
Code string `gorm:"type:varchar(32);uniqueIndex" json:"code"`
|
||||
Address string `gorm:"type:varchar(256)" json:"address"`
|
||||
ContactName string `gorm:"type:varchar(64)" json:"contact_name"`
|
||||
ContactPhone string `gorm:"type:varchar(20)" json:"contact_phone"`
|
||||
Status int `gorm:"default:1" json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的班级和教师
|
||||
Classes []Class `gorm:"foreignKey:SchoolID" json:"classes"`
|
||||
Teachers []Teacher `gorm:"foreignKey:SchoolID" json:"teachers"`
|
||||
}
|
||||
|
||||
// Class 班级模型
|
||||
type Class struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"type:varchar(64)" json:"name"`
|
||||
Grade string `gorm:"type:varchar(16)" json:"grade"` // 年级
|
||||
SchoolID uint `json:"school_id"`
|
||||
School School `gorm:"foreignKey:SchoolID" json:"school"`
|
||||
TeacherID *uint `json:"teacher_id"` // 班主任
|
||||
Teacher *Teacher `gorm:"foreignKey:TeacherID" json:"teacher"`
|
||||
StudentCount int `gorm:"default:0" json:"student_count"`
|
||||
Status int `gorm:"default:1" json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 关联的学生
|
||||
Students []Student `gorm:"foreignKey:ClassID" json:"students"`
|
||||
}
|
||||
|
||||
// ParentStudentRel 家长-学生关联表
|
||||
type ParentStudentRel struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
ParentID uint `json:"parent_id"`
|
||||
StudentID uint `json:"student_id"`
|
||||
Relation string `gorm:"type:varchar(16)" json:"relation"` // father, mother, other
|
||||
IsPrimary bool `gorm:"default:false" json:"is_primary"` // 是否主要监护人
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// UserAccount 用户账号模型(统一账号体系)
|
||||
type UserAccount struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Username string `gorm:"type:varchar(64);uniqueIndex" json:"username"`
|
||||
PasswordHash string `gorm:"type:varchar(128)" json:"-"`
|
||||
Phone string `gorm:"type:varchar(20);uniqueIndex" json:"phone"`
|
||||
UserType string `gorm:"type:varchar(16)" json:"user_type"` // student, parent, teacher, admin
|
||||
UserID uint `json:"user_id"` // 关联的具体用户ID
|
||||
Status int `gorm:"default:1" json:"status"`
|
||||
LastLoginAt *time.Time `json:"last_login_at"`
|
||||
LastLoginIP string `gorm:"type:varchar(45)" json:"last_login_ip"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
Reference in New Issue
Block a user