Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion backend/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.env
.env
progress_wall.db
4 changes: 3 additions & 1 deletion backend/README_dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ backend/
├── controllers/ # 控制器层
│ └── ...
├── database/ # 数据库连接
│ └── database.go
| |- seed.go # 初始权限组设定
| |- migrate.go # 数据库迁移(自动建表)
│ └── database.go # 数据库连接
├── middleware/ # 中间件
│ └── ...
├── models/ # 数据模型
Expand Down
51 changes: 51 additions & 0 deletions backend/database/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package database

import (
"fmt"
"log"
"progress-wall-backend/config"

"gorm.io/driver/mysql"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)

// InitDB 初始化数据库连接
func InitDB(cfg *config.Config) (*gorm.DB, error) {
var db *gorm.DB
var err error

// 配置GORM日志
gormConfig := &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
}

switch cfg.DB.Type {
case "mysql":
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
cfg.DB.User, cfg.DB.Password, cfg.DB.Host, cfg.DB.Port, cfg.DB.Name)
db, err = gorm.Open(mysql.Open(dsn), gormConfig)
case "sqlite":
db, err = gorm.Open(sqlite.Open(cfg.DB.Name+".db"), gormConfig)
default:
return nil, fmt.Errorf("不支持的数据库类型: %s", cfg.DB.Type)
}

if err != nil {
return nil, err
}

// 配置连接池
sqlDB, err := db.DB()
if err != nil {
return nil, err
}

// 设置连接池参数
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)

log.Printf("数据库连接成功: %s", cfg.DB.Type)
return db, nil
}
44 changes: 44 additions & 0 deletions backend/database/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package database

import (
"log"
"progress-wall-backend/models"

"gorm.io/gorm"
)

// Migrate 执行数据库迁移
func Migrate(db *gorm.DB) error {
log.Println("开始执行数据库迁移...")

// 迁移所有模型
err := db.AutoMigrate(
// 用户和权限相关
&models.User{},
&models.UserPermission{},
&models.UserPermissionGroup{},
&models.UserPermissionGroupUser{},
&models.UserPermissionGroup{},

// 项目和看板相关
&models.Project{},
&models.ProjectMember{},
&models.Board{},

// 任务相关
&models.Column{},
&models.Task{},
&models.Comment{},
&models.Attachment{},
&models.Label{},
&models.TaskLabel{},
)

if err != nil {
log.Printf("数据库迁移失败: %v", err)
return err
}

log.Println("数据库迁移完成")
return nil
}
45 changes: 45 additions & 0 deletions backend/database/seed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package database

import (
"log"
"progress-wall-backend/models"

"gorm.io/gorm"
)

// Seed 初始化基础数据
func Seed(db *gorm.DB) error {
log.Println("开始初始化基础数据...")

// 创建默认用户
if err := createDefaultUsers(db); err != nil {
return err
}

// 创建默认权限
if err := createDefaultPermissions(db); err != nil {
return err
}

log.Println("基础数据初始化完成")
return nil
}

func createDefaultUsers(_ *gorm.DB) error {
// TODO: 创建默认用户,目前密码加密方法还没确定
return nil
}

func createDefaultPermissions(db *gorm.DB) error {
adminPermissionGroup := models.UserPermissionGroup{
GroupName: "admin",
PermissionStrings: "*",
}
db.Create(&adminPermissionGroup)
guestPermissionGroup := models.UserPermissionGroup{
GroupName: "guest",
PermissionStrings: "users.list;users.detail",
}
db.Create(&guestPermissionGroup)
return nil
}
3,373 changes: 3,373 additions & 0 deletions backend/docs/database/ER-structure.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added backend/docs/database/structure.mwb
Binary file not shown.
15 changes: 14 additions & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,17 @@ module progress-wall-backend

go 1.21

require github.com/joho/godotenv v1.4.0
require (
github.com/joho/godotenv v1.4.0
golang.org/x/crypto v0.15.0
gorm.io/driver/mysql v1.5.2
gorm.io/driver/sqlite v1.5.4
gorm.io/gorm v1.25.5
)

require (
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
)
17 changes: 17 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0=
gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
19 changes: 18 additions & 1 deletion backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"log"
"progress-wall-backend/config"
"progress-wall-backend/database"
)

func main() {
Expand All @@ -19,5 +20,21 @@ func main() {
fmt.Printf("- JWT密钥长度: %d\n", len(cfg.JWT.Secret))
fmt.Printf("- CORS允许来源: %s\n", cfg.CORS.AllowOrigins)

log.Println("配置加载完成")
// 初始化数据库
db, err := database.InitDB(cfg)
if err != nil {
log.Fatal("数据库初始化失败:", err)
}

// 执行数据库迁移
if err := database.Migrate(db); err != nil {
log.Fatal("数据库迁移失败:", err)
}

// 初始化基础数据
if err := database.Seed(db); err != nil {
log.Fatal("初始化基础数据失败:", err)
}

log.Println("数据库初始化完成")
}
35 changes: 35 additions & 0 deletions backend/models/attachment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package models

import (
"time"

"gorm.io/gorm"
)

// Attachment 附件表
type Attachment struct {
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
Filename string `json:"filename" gorm:"size:255;not null"`
OriginalName string `json:"original_name" gorm:"size:255;not null"`
FilePath string `json:"file_path" gorm:"size:500;not null"`
FileSize int64 `json:"file_size" gorm:"not null;comment:'文件大小(字节)'"`
MimeType string `json:"mime_type" gorm:"size:100;not null"`
TaskID uint `json:"task_id" gorm:"not null;index"`
UploaderID uint `json:"uploader_id" gorm:"not null;index"`
Status AttachmentStatus `json:"status" gorm:"type:tinyint;default:1;comment:'附件状态:1=正常,2=删除'"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`

// 关联关系
Task Task `json:"task,omitempty" gorm:"foreignKey:TaskID"`
Uploader User `json:"uploader,omitempty" gorm:"foreignKey:UploaderID"`
}

// AttachmentStatus 附件状态枚举
type AttachmentStatus int

const (
AttachmentStatusNormal AttachmentStatus = 1 // 正常
AttachmentStatusDeleted AttachmentStatus = 2 // 删除
)
35 changes: 35 additions & 0 deletions backend/models/board.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package models

import (
"time"

"gorm.io/gorm"
)

// Board 看板表
type Board struct {
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
Name string `json:"name" gorm:"size:100;not null"`
Description string `json:"description" gorm:"type:text"`
Color string `json:"color" gorm:"size:7;default:'#3498db';comment:'看板颜色,十六进制格式'"`
Status BoardStatus `json:"status" gorm:"type:tinyint;default:1;comment:'看板状态:1=活跃,2=归档'"`
ProjectID uint `json:"project_id" gorm:"not null;index"`
OwnerID uint `json:"owner_id" gorm:"not null;index"`
Position int `json:"position" gorm:"default:0;comment:'看板在项目中的排序位置'"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`

// 关联关系
Project Project `json:"project,omitempty" gorm:"foreignKey:ProjectID"`
Owner User `json:"owner,omitempty" gorm:"foreignKey:OwnerID"`
Columns []Column `json:"columns,omitempty" gorm:"foreignKey:BoardID"`
}

// BoardStatus 看板状态枚举
type BoardStatus int

const (
BoardStatusActive BoardStatus = 1 // 活跃
BoardStatusArchived BoardStatus = 2 // 归档
)
33 changes: 33 additions & 0 deletions backend/models/column.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package models

import (
"time"

"gorm.io/gorm"
)

// Column 列表
type Column struct {
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
Name string `json:"name" gorm:"size:50;not null"`
Description string `json:"description" gorm:"size:255"`
Color string `json:"color" gorm:"size:7;default:'#95a5a6';comment:'列颜色,十六进制格式'"`
Position int `json:"position" gorm:"not null;comment:'列在看板中的排序位置'"`
BoardID uint `json:"board_id" gorm:"not null;index"`
Status ColumnStatus `json:"status" gorm:"type:tinyint;default:1;comment:'列状态:1=正常,2=禁用'"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`

// 关联关系
Board Board `json:"board,omitempty" gorm:"foreignKey:BoardID"`
Tasks []Task `json:"tasks,omitempty" gorm:"foreignKey:ColumnID"`
}

// ColumnStatus 列状态枚举
type ColumnStatus int

const (
ColumnStatusActive ColumnStatus = 1 // 正常
ColumnStatusDisabled ColumnStatus = 2 // 禁用
)
35 changes: 35 additions & 0 deletions backend/models/comment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package models

import (
"time"

"gorm.io/gorm"
)

// Comment 评论表
type Comment struct {
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
Content string `json:"content" gorm:"type:text;not null"`
TaskID uint `json:"task_id" gorm:"not null;index"`
UserID uint `json:"user_id" gorm:"not null;index"`
ParentID *uint `json:"parent_id" gorm:"index;comment:'父评论ID,用于回复评论'"`
Status CommentStatus `json:"status" gorm:"type:tinyint;default:1;comment:'评论状态:1=正常,2=隐藏,3=删除'"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`

// 关联关系
Task Task `json:"task,omitempty" gorm:"foreignKey:TaskID"`
User User `json:"user,omitempty" gorm:"foreignKey:UserID"`
Parent *Comment `json:"parent,omitempty" gorm:"foreignKey:ParentID"`
Replies []Comment `json:"replies,omitempty" gorm:"foreignKey:ParentID"`
}

// CommentStatus 评论状态枚举
type CommentStatus int

const (
CommentStatusNormal CommentStatus = 1 // 正常
CommentStatusHidden CommentStatus = 2 // 隐藏
CommentStatusDeleted CommentStatus = 3 // 删除
)
Loading
Loading