2026-03-13 08:35:54 +00:00
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
|
"myschools.me/heritage/heritage-api/model"
|
|
|
|
|
"myschools.me/heritage/heritage-api/mysql"
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-19 14:51:31 +00:00
|
|
|
func ProjectCreate(p *model.Project) (*model.Project, error) {
|
2026-03-13 08:35:54 +00:00
|
|
|
if p == nil {
|
|
|
|
|
return nil, errors.New("invalid project")
|
|
|
|
|
}
|
|
|
|
|
p.ID = strings.TrimSpace(p.ID)
|
|
|
|
|
if p.ID == "" {
|
|
|
|
|
p.ID = newProjectID()
|
|
|
|
|
}
|
|
|
|
|
p.ProjectNo = strings.TrimSpace(p.ProjectNo)
|
|
|
|
|
if p.ProjectNo == "" {
|
|
|
|
|
p.ProjectNo = strings.ToUpper(newID())
|
|
|
|
|
}
|
|
|
|
|
p.Name = strings.TrimSpace(p.Name)
|
|
|
|
|
p.TypeCode = strings.TrimSpace(p.TypeCode)
|
|
|
|
|
p.BuildingIDs = strings.TrimSpace(p.BuildingIDs)
|
|
|
|
|
p.StatusCode = strings.TrimSpace(p.StatusCode)
|
|
|
|
|
p.ResponsibleOrgID = strings.TrimSpace(p.ResponsibleOrgID)
|
|
|
|
|
p.ImplementOrgIDs = strings.TrimSpace(p.ImplementOrgIDs)
|
|
|
|
|
p.LeaderPersonID = strings.TrimSpace(p.LeaderPersonID)
|
|
|
|
|
p.ParticipantPersonIDs = strings.TrimSpace(p.ParticipantPersonIDs)
|
|
|
|
|
p.Description = strings.TrimSpace(p.Description)
|
|
|
|
|
p.Attachments = strings.TrimSpace(p.Attachments)
|
|
|
|
|
p.OrgID = strings.TrimSpace(p.OrgID)
|
|
|
|
|
p.CreatorUserID = strings.TrimSpace(p.CreatorUserID)
|
|
|
|
|
p.Remark = strings.TrimSpace(p.Remark)
|
|
|
|
|
|
|
|
|
|
if p.Name == "" || p.TypeCode == "" || p.BuildingIDs == "" || p.StatusCode == "" || p.ResponsibleOrgID == "" || p.LeaderPersonID == "" || p.OrgID == "" || p.CreatorUserID == "" {
|
|
|
|
|
return nil, errors.New("missing required fields")
|
|
|
|
|
}
|
|
|
|
|
if p.StartAt.IsZero() || p.EndAt.IsZero() {
|
|
|
|
|
return nil, errors.New("startAt/endAt required")
|
|
|
|
|
}
|
|
|
|
|
if p.EndAt.Before(p.StartAt) {
|
|
|
|
|
return nil, errors.New("endAt before startAt")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := mysql.ProjectCreate(p); err != nil {
|
|
|
|
|
logrus.WithFields(logrus.Fields{
|
2026-03-19 14:51:31 +00:00
|
|
|
"func": "ProjectCreate",
|
2026-03-13 08:35:54 +00:00
|
|
|
}).Warnf("mysql.ProjectCreate: %v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return p, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 14:51:31 +00:00
|
|
|
func ProjectUpdate(idv string, patch *model.Project) (*model.Project, error) {
|
2026-03-13 08:35:54 +00:00
|
|
|
pid := strings.TrimSpace(idv)
|
|
|
|
|
if pid == "" {
|
|
|
|
|
return nil, ErrNotFound
|
|
|
|
|
}
|
2026-03-19 14:51:31 +00:00
|
|
|
existing, err := mysql.ProjectFirst(&pid)
|
2026-03-13 08:35:54 +00:00
|
|
|
if err != nil {
|
|
|
|
|
logrus.WithFields(logrus.Fields{
|
2026-03-19 14:51:31 +00:00
|
|
|
"func": "ProjectUpdate",
|
|
|
|
|
}).Warnf("mysql.ProjectFirst: %v", err)
|
2026-03-13 08:35:54 +00:00
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-03-19 14:51:31 +00:00
|
|
|
if existing == nil || existing.ID == "" {
|
2026-03-13 08:35:54 +00:00
|
|
|
logrus.WithFields(logrus.Fields{
|
2026-03-19 14:51:31 +00:00
|
|
|
"func": "ProjectUpdate",
|
|
|
|
|
}).Warnf("mysql.ProjectFirst: not found")
|
2026-03-13 08:35:54 +00:00
|
|
|
return nil, ErrNotFound
|
|
|
|
|
}
|
|
|
|
|
if patch == nil {
|
|
|
|
|
return existing, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s := strings.TrimSpace(patch.Name); s != "" {
|
|
|
|
|
existing.Name = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.TypeCode); s != "" {
|
|
|
|
|
existing.TypeCode = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.BuildingIDs); s != "" {
|
|
|
|
|
existing.BuildingIDs = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.StatusCode); s != "" {
|
|
|
|
|
existing.StatusCode = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.ResponsibleOrgID); s != "" {
|
|
|
|
|
existing.ResponsibleOrgID = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.ImplementOrgIDs); s != "" {
|
|
|
|
|
existing.ImplementOrgIDs = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.LeaderPersonID); s != "" {
|
|
|
|
|
existing.LeaderPersonID = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.ParticipantPersonIDs); s != "" {
|
|
|
|
|
existing.ParticipantPersonIDs = s
|
|
|
|
|
}
|
|
|
|
|
if !patch.StartAt.IsZero() {
|
|
|
|
|
existing.StartAt = patch.StartAt
|
|
|
|
|
}
|
|
|
|
|
if !patch.EndAt.IsZero() {
|
|
|
|
|
existing.EndAt = patch.EndAt
|
|
|
|
|
}
|
|
|
|
|
if patch.CompletedAt != nil {
|
|
|
|
|
t := *patch.CompletedAt
|
|
|
|
|
existing.CompletedAt = &t
|
|
|
|
|
}
|
|
|
|
|
if patch.CompletedAt == nil && patch.Description == "" && patch.Attachments == "" {
|
|
|
|
|
}
|
|
|
|
|
if patch.Description != "" {
|
|
|
|
|
existing.Description = strings.TrimSpace(patch.Description)
|
|
|
|
|
}
|
|
|
|
|
if patch.Attachments != "" {
|
|
|
|
|
existing.Attachments = strings.TrimSpace(patch.Attachments)
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.OrgID); s != "" {
|
|
|
|
|
existing.OrgID = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.CreatorUserID); s != "" {
|
|
|
|
|
existing.CreatorUserID = s
|
|
|
|
|
}
|
|
|
|
|
if s := strings.TrimSpace(patch.Remark); s != "" {
|
|
|
|
|
existing.Remark = s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if existing.EndAt.Before(existing.StartAt) {
|
|
|
|
|
return nil, errors.New("endAt before startAt")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ok, err := mysql.ProjectUpdate(existing)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logrus.WithFields(logrus.Fields{
|
2026-03-19 14:51:31 +00:00
|
|
|
"func": "ProjectUpdate",
|
2026-03-13 08:35:54 +00:00
|
|
|
}).Warnf("mysql.ProjectUpdate: %v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if !ok {
|
|
|
|
|
logrus.WithFields(logrus.Fields{
|
2026-03-19 14:51:31 +00:00
|
|
|
"func": "ProjectUpdate",
|
2026-03-13 08:35:54 +00:00
|
|
|
}).Warnf("mysql.ProjectUpdate: not found")
|
|
|
|
|
return nil, ErrNotFound
|
|
|
|
|
}
|
|
|
|
|
return existing, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 14:51:31 +00:00
|
|
|
func ProjectDelete(usr *model.User, pid *string) error {
|
|
|
|
|
project, err := mysql.ProjectFirst(pid)
|
2026-03-13 08:35:54 +00:00
|
|
|
if err != nil {
|
|
|
|
|
logrus.WithFields(logrus.Fields{
|
|
|
|
|
"func": "ProjectDelete",
|
2026-03-19 14:51:31 +00:00
|
|
|
}).Warnf("mysql.ProjectFirst: %v", err)
|
2026-03-13 08:35:54 +00:00
|
|
|
return err
|
|
|
|
|
}
|
2026-03-19 14:51:31 +00:00
|
|
|
if project.OrgID != usr.OrgID {
|
|
|
|
|
return errors.New("not in org")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := mysql.ProjectDelete(pid); err != nil {
|
2026-03-13 08:35:54 +00:00
|
|
|
logrus.WithFields(logrus.Fields{
|
|
|
|
|
"func": "ProjectDelete",
|
2026-03-19 14:51:31 +00:00
|
|
|
}).Warnf("mysql.ProjectDelete: %v", err)
|
|
|
|
|
return err
|
2026-03-13 08:35:54 +00:00
|
|
|
}
|
2026-03-19 14:51:31 +00:00
|
|
|
|
2026-03-13 08:35:54 +00:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ProjectGet(idv string) (*model.Project, error) {
|
|
|
|
|
pid := strings.TrimSpace(idv)
|
|
|
|
|
if pid == "" {
|
|
|
|
|
return nil, ErrNotFound
|
|
|
|
|
}
|
2026-03-19 14:51:31 +00:00
|
|
|
p, err := mysql.ProjectFirst(&pid)
|
2026-03-13 08:35:54 +00:00
|
|
|
if err != nil {
|
|
|
|
|
logrus.WithFields(logrus.Fields{
|
|
|
|
|
"func": "ProjectGet",
|
2026-03-19 14:51:31 +00:00
|
|
|
}).Warnf("mysql.ProjectFirst: %v", err)
|
2026-03-13 08:35:54 +00:00
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-03-19 14:51:31 +00:00
|
|
|
if p == nil || p.ID == "" {
|
2026-03-13 08:35:54 +00:00
|
|
|
logrus.WithFields(logrus.Fields{
|
|
|
|
|
"func": "ProjectGet",
|
2026-03-19 14:51:31 +00:00
|
|
|
}).Warnf("mysql.ProjectFirst: not found")
|
2026-03-13 08:35:54 +00:00
|
|
|
return nil, ErrNotFound
|
|
|
|
|
}
|
|
|
|
|
return p, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 14:51:31 +00:00
|
|
|
func ProjectPage(orgID, keyword *string, page, size int) ([]model.Project, int64, error) {
|
2026-03-13 08:35:54 +00:00
|
|
|
if page < 1 {
|
|
|
|
|
page = 1
|
|
|
|
|
}
|
|
|
|
|
if size < 1 {
|
|
|
|
|
size = 20
|
|
|
|
|
}
|
|
|
|
|
if size > 200 {
|
|
|
|
|
size = 200
|
|
|
|
|
}
|
|
|
|
|
offset := (page - 1) * size
|
|
|
|
|
return mysql.ProjectList(orgID, keyword, &offset, &size)
|
|
|
|
|
}
|