Files
backend/internal/model/material.go
lan ee78071d4d
All checks were successful
Build Backend / build (push) Successful in 3m2s
Build Backend / build-docker (push) Successful in 2m44s
refactor: improve system stability, performance, and code structure
This commit introduces several architectural improvements and optimizations across the codebase:

- **Performance & Reliability**:
  - Implemented Redis pipelining in `ConversationCache.CacheMessage` to reduce network round-trips.
  - Added a circuit breaker to the JPush client to prevent cascading failures.
  - Introduced batch deletion and batch member addition capabilities in repositories.
  - Added message idempotency support using `client_msg_id` and a Redis-based cache.
  - Optimized WebSocket handling with connection limits (total and per-user) and improved error logging.

- **Code Refactoring**:
  - Refactored `Router` to use a `RouterDeps` struct, simplifying the constructor and improving maintainability.
  - Unified model ID generation logic using new `id_helper.go` (supporting UUID and Snowflake).
  - Standardized JSON serialization/deserialization in models using `json_helper.go`.
  - Refactored DTO conversion logic, specifically for `UserResponse` (using functional options) and `Report` responses.
  - Removed redundant/deprecated DTOs like `PostDetailResponse` and `TradeItemDetailResponse`.

- **Cache Improvements**:
  - Enhanced `LayeredCache` with `SetRaw` to avoid double-encoding when promoting values from Redis to local cache.
  - Added `DeleteBatch` support to the cache interface.

- **Other Changes**:
  - Cleaned up `config.go` by removing redundant default values and explicit environment variable overrides.
  - Improved WebSocket registration flow to handle connection limits gracefully.
2026-05-04 13:07:03 +08:00

104 lines
3.6 KiB
Go
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.
package model
import (
"database/sql/driver"
"time"
"gorm.io/gorm"
)
// MaterialFileType 文件类型
type MaterialFileType string
const (
MaterialFileTypePDF MaterialFileType = "pdf"
MaterialFileTypeWord MaterialFileType = "word"
MaterialFileTypePPT MaterialFileType = "ppt"
)
// MaterialStatus 资料状态
type MaterialStatus string
const (
MaterialStatusActive MaterialStatus = "active"
MaterialStatusInactive MaterialStatus = "inactive"
)
// MaterialSubject 学科分类
type MaterialSubject struct {
ID string `json:"id" gorm:"type:varchar(36);primaryKey"`
Name string `json:"name" gorm:"type:varchar(100);not null"`
Icon string `json:"icon" gorm:"type:varchar(50)"` // MaterialCommunityIcons name
Color string `json:"color" gorm:"type:varchar(20)"` // 主题色
Description string `json:"description" gorm:"type:varchar(255)"` // 描述
SortOrder int `json:"sort_order" gorm:"default:0;index"` // 排序权重
IsActive bool `json:"is_active" gorm:"default:true;index"` // 是否启用
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// 关联
Materials []MaterialFile `json:"materials,omitempty" gorm:"foreignKey:SubjectID"`
}
// BeforeCreate 创建前生成UUID
func (s *MaterialSubject) BeforeCreate(tx *gorm.DB) error {
SetUUIDIfEmpty(&s.ID)
return nil
}
func (MaterialSubject) TableName() string {
return "material_subjects"
}
// StringArray 字符串数组类型用于tags
type StringArray []string
// Value 实现 driver.Valuer 接口
func (a StringArray) Value() (driver.Value, error) {
if a == nil {
return nil, nil
}
return ValueJSON(a)
}
// Scan 实现 sql.Scanner 接口
func (a *StringArray) Scan(value any) error {
if value == nil {
*a = nil
return nil
}
return ScanJSON(a, value)
}
// MaterialFile 文件资料
type MaterialFile struct {
ID string `json:"id" gorm:"type:varchar(36);primaryKey"`
SubjectID string `json:"subject_id" gorm:"type:varchar(36);index;not null"`
Title string `json:"title" gorm:"type:varchar(200);not null"`
Description string `json:"description" gorm:"type:text"`
FileType MaterialFileType `json:"file_type" gorm:"type:varchar(20);not null;index"`
FileSize int64 `json:"file_size" gorm:"default:0"` // 文件大小(字节)
FileURL string `json:"file_url" gorm:"type:text;not null"` // 文件URL
FileName string `json:"file_name" gorm:"type:varchar(255)"` // 原始文件名
DownloadCount int `json:"download_count" gorm:"default:0"` // 下载次数
AuthorID string `json:"author_id" gorm:"type:varchar(36);index"` // 上传者ID
Tags StringArray `json:"tags" gorm:"type:json"` // 标签
Status MaterialStatus `json:"status" gorm:"type:varchar(20);default:active;index"` // 状态
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime;index"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
// 关联
Subject *MaterialSubject `json:"subject,omitempty" gorm:"foreignKey:SubjectID"`
Author *User `json:"author,omitempty" gorm:"foreignKey:AuthorID"`
}
// BeforeCreate 创建前生成UUID
func (f *MaterialFile) BeforeCreate(tx *gorm.DB) error {
SetUUIDIfEmpty(&f.ID)
return nil
}
func (MaterialFile) TableName() string {
return "material_files"
}