Files
gitpm/internal/models/epic.go
huxunan 885fad6c64 Initial commit: Gitea Project Management System
Features:
- Complete project management system with Epic/Story/Task hierarchy
- Vue.js 3 + Element Plus frontend with kanban board
- Go backend with Gin framework and GORM
- OAuth2 integration with Gitea
- Docker containerization with MySQL
- RESTful API for project, task, and user management
- JWT authentication and authorization
- Responsive web interface with dashboard
2025-09-22 14:53:53 +08:00

129 lines
3.6 KiB
Go

package models
import (
"time"
"gorm.io/gorm"
)
type Epic struct {
ID uint `json:"id" gorm:"primaryKey"`
ProjectID uint `json:"project_id"`
Title string `json:"title" gorm:"not null"`
Description string `json:"description"`
Status string `json:"status" gorm:"default:'backlog'"`
Priority string `json:"priority" gorm:"default:'medium'"`
AssigneeID *uint `json:"assignee_id"`
ReporterID uint `json:"reporter_id"`
StartDate *time.Time `json:"start_date"`
DueDate *time.Time `json:"due_date"`
EstimatedHours *float64 `json:"estimated_hours"`
ActualHours float64 `json:"actual_hours" gorm:"default:0"`
ProgressPercentage int `json:"progress_percentage" gorm:"default:0"`
Project Project `json:"project" gorm:"foreignKey:ProjectID"`
Assignee *User `json:"assignee" gorm:"foreignKey:AssigneeID"`
Reporter User `json:"reporter" gorm:"foreignKey:ReporterID"`
Stories []Story `json:"stories" gorm:"foreignKey:EpicID"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type EpicStatus string
const (
EpicStatusBacklog EpicStatus = "backlog"
EpicStatusPlanning EpicStatus = "planning"
EpicStatusInProgress EpicStatus = "in_progress"
EpicStatusTesting EpicStatus = "testing"
EpicStatusDone EpicStatus = "done"
EpicStatusCancelled EpicStatus = "cancelled"
)
func (e *Epic) BeforeCreate(tx *gorm.DB) error {
return nil
}
func (e *Epic) UpdateProgress() error {
var totalStories int64
var completedStories int64
err := DB.Model(&Story{}).Where("epic_id = ?", e.ID).Count(&totalStories).Error
if err != nil {
return err
}
if totalStories == 0 {
e.ProgressPercentage = 0
return DB.Save(e).Error
}
err = DB.Model(&Story{}).Where("epic_id = ? AND status = 'done'", e.ID).Count(&completedStories).Error
if err != nil {
return err
}
e.ProgressPercentage = int(float64(completedStories) / float64(totalStories) * 100)
return DB.Save(e).Error
}
func (e *Epic) GetStories() ([]Story, error) {
var stories []Story
err := DB.Where("epic_id = ?", e.ID).Preload("Assignee").Find(&stories).Error
return stories, err
}
func CreateEpic(epic *Epic) error {
return DB.Create(epic).Error
}
func GetEpicByID(id uint) (*Epic, error) {
var epic Epic
err := DB.Preload("Project").Preload("Assignee").Preload("Reporter").
Preload("Stories").First(&epic, id).Error
return &epic, err
}
func GetEpicsByProject(projectID uint) ([]Epic, error) {
var epics []Epic
err := DB.Where("project_id = ?", projectID).
Preload("Assignee").Preload("Reporter").
Find(&epics).Error
return epics, err
}
func UpdateEpic(epic *Epic) error {
return DB.Save(epic).Error
}
func DeleteEpic(id uint) error {
return DB.Delete(&Epic{}, id).Error
}
func ListEpics(offset, limit int, filters map[string]interface{}) ([]Epic, int64, error) {
var epics []Epic
var total int64
query := DB.Model(&Epic{})
for key, value := range filters {
switch key {
case "project_id":
query = query.Where("project_id = ?", value)
case "status":
query = query.Where("status = ?", value)
case "priority":
query = query.Where("priority = ?", value)
case "assignee_id":
query = query.Where("assignee_id = ?", value)
}
}
err := query.Count(&total).Error
if err != nil {
return nil, 0, err
}
err = query.Preload("Project").Preload("Assignee").Preload("Reporter").
Offset(offset).Limit(limit).Find(&epics).Error
return epics, total, err
}