This commit is contained in:
2025-07-07 20:11:59 +08:00
parent ab0fdbc447
commit 06e3aa2eb3
2009 changed files with 193082 additions and 0 deletions

View File

@ -0,0 +1,4 @@
package project
type Project struct {
}

44
api/app/project/req.go Normal file
View File

@ -0,0 +1,44 @@
package project
import "github.com/gogf/gf/v2/frame/g"
// 查询所有项目列表数据
type ProjectIndexModuleReq struct {
g.Meta `path:"index" method:"get" tags:"APP(项目相关)" summary:"项目列表数据【首页列表】"`
ProjectName string `json:"projectName" dc:"模糊搜索项目名"`
PageNum int `json:"pageNum" dc:"页码" v:"required"`
PageSize int `json:"pageSize" dc:"每页数量" v:"required"`
}
// 根据项目ID查询详情【基础数据】
type ProjectIndexModuleDetailReq struct {
g.Meta `path:"base" method:"get" tags:"APP(项目相关)" summary:"项目详情数据【基础数据】"`
ProjectId string `json:"projectId" v:"required" dc:"项目ID"`
}
// 根据项目ID查询详情【项目计划】
type ProjectPlanDetailReq struct {
g.Meta `path:"plan" method:"get" tags:"APP(项目相关)" summary:"项目详情数据【项目计划】"`
ProjectId string `json:"projectId" v:"required" dc:"项目ID"`
}
// 根据项目ID查询详情【视频监控】
type ProjectVideoDetailReq struct {
g.Meta `path:"video" method:"get" tags:"APP(项目相关)" summary:"项目详情数据【视频监控】"`
ProjectId string `json:"projectId" v:"required" dc:"项目ID"`
}
// 根据项目ID查询详情【施工日志】
type ProjectLogReq struct {
g.Meta `path:"log" method:"get" tags:"APP(项目相关)" summary:"项目详情数据【施工日志】"`
ProjectId int64 `json:"projectId" v:"required" dc:"项目ID"`
}
// 根据项目ID查询详情【计划详情】
type ProjectPlanDetailStatusReq struct {
g.Meta `path:"/planDetail" tags:"APP(项目相关)" method:"get" summary:"项目详情数据【计划详情】"`
ProjectID int `json:"projectId"`
Status int `json:"status" dc:"任务状态 0:待开始 1:进行中 2:已完成 3:滞后"`
PageNum int `json:"pageNum" dc:"页码" v:"required"`
PageSize int `json:"pageSize" dc:"每页数量" v:"required"`
}

126
api/app/project/res.go Normal file
View File

@ -0,0 +1,126 @@
package project
import (
"time"
"github.com/gogf/gf/v2/frame/g"
"github.com/tiger1103/gfast/v3/api/v1/common"
)
// 项目列表响应数据
type ProjectListRes struct {
ProjectTotal int `json:"projectTotal"` // 项目总数
BuildProject int `json:"buildProject"` // 在建项目数量
ProjectCapacity int `json:"projectCapacity"` // 项目容量
ProjectListModels []ProjectListModel `json:"projectListModels"` // 列表数据
}
type ProjectListModel struct {
ProjectID int `json:"projectId"` // 项目ID
ProjectName string `json:"projectName"` // 项目名称
ProductionDays int `json:"productionDays"` // 安全生产天数
Status string `json:"status"` // 项目状态
TotalQuantity int `json:"totalQuantity"` // 总数量
CompletedQuantity int `json:"completedQuantity"` // 已完成数量
ProjectLeader string `json:"projectLeader"` // 项目负责人
OnStreamTime string `json:"onStreamTime"` // 开工时间
}
// 项目详情响应数据【基础数据部分】
type ProjectDetailModelRes struct {
ProjectID int `json:"projectId"` // 项目ID
ProjectName string `json:"projectName"` // 项目名称
ProjectLeader string `json:"projectLeader"` // 项目负责人
OnStreamTime string `json:"onStreamTime"` // 开工时间(计划开工)
ProductionDays int `json:"productionDays"` // 安全生产天数
TotalQuantity int `json:"totalQuantity"` // 总数量
CompletedQuantity int `json:"completedQuantity"` // 已完成数量
}
// 项目详情响应数据【项目计划】
type ProjectPlanDetailRes struct {
ProjectPlan
}
type ProjectPlan struct {
PendingPlan int `json:"pendingTasks"` // 待开始计划
ProcessingPlan int `json:"processingTasks"` // 进行中计划
CompletedPlan int `json:"completedTasks"` // 已完成计划
DeferredPlan int `json:"deferredTasks"` // 滞后计划
}
type ProjectPlanDetailStatusRes struct {
g.Meta `mime:"application/json"`
common.ListRes
List []SchduleList `json:"list"`
}
// SchduleList 计划详情
type SchduleList struct {
// 工作名称
WorkName string `json:"work_name"`
// 计划数量
PlanNum int `json:"plan_num"`
// 实际完成数量
FinishedNum int `json:"finished_num"`
// 开始时间
StartTime string `json:"start_at"`
// 结束时间
EndTime string `json:"end_at"`
// 工日
WorkDay int `json:"work_day"`
// 工作量百分比
WorkPercent int `json:"work_percent"`
// 负责人
Leader string `json:"principal"`
}
// 项目详情响应数据【视频监控】
type ProjectVideoDetailRes struct {
YS7Devices []YS7Device
}
type YS7Device struct {
ID int `json:"id"`
CreatedAt time.Time `json:"createdAt"`
DeviceSerial string `json:"deviceSerial"`
DeviceName string `json:"deviceName"`
DeviceType string `json:"deviceType"`
Status int `json:"status"`
Defence int `json:"defence"`
DeviceVersion string `json:"deviceVersion"`
ProjectID string `json:"projectId"`
Detail string `json:"detail"`
Position string `json:"position"`
Remark string `json:"remark"`
VideoEncrypted int `json:"videoEncrypted"`
}
// 项目详情响应数据【施工日志】
type ProjectLogRes struct {
Logs []ConstructionLog `json:"logs"`
}
type ConstructionLog struct {
ID int64 `json:"id"`
DateOfOccurrence string `json:"dateOfOccurrence"`
Condition string `json:"condition"`
TechnologyQuality string `json:"technologyQuality"`
Remark string `json:"remark"`
Path string `json:"path"`
CreatedBy string `json:"createdBy"`
UpdatedBy string `json:"updatedBy"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
DeletedAt time.Time `json:"deletedAt"`
}
type VisualProgress struct {
Id int64 `json:"id" dc:"主键"`
ProjectID int64 `json:"projectId" dc:"项目ID"`
ProjectName string `json:"projectName" dc:"项目名称"`
ReporterID int64 `json:"reporterId" dc:"上报人ID"`
ReporterName string `json:"reporterName" dc:"上报人名字"`
ReportTime time.Time `json:"reportTime" dc:"上报时间"`
Title string `json:"title" dc:"形象标题"`
ProgressDesc string `json:"progressDesc" dc:"进度描述"`
AttachmentURL string `json:"attachmentUrl" dc:"附件URL"`
}

279
api/app/project/service.go Normal file
View File

@ -0,0 +1,279 @@
package project
import (
"context"
"fmt"
"time"
"github.com/gogf/gf/v2/frame/g"
"github.com/jinzhu/copier"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
)
// 项目首页信息列表
func (p Project) ProjectIndex(ctx context.Context, req *ProjectIndexModuleReq) (res *ProjectListRes, err error) {
res = new(ProjectListRes)
// 查询所有项目总数
count, err := g.Model("sys_project").Ctx(ctx).Count()
if err != nil {
return nil, err
}
res.ProjectTotal = count
// 查询所有项目的总容量之和
var capacity struct{ ProjectCapacity int }
err = g.Model("sys_project").Fields("SUM(actual) AS ProjectCapacity").Ctx(ctx).Scan(&capacity)
if err != nil {
return nil, err
}
res.ProjectCapacity = capacity.ProjectCapacity
// 分页查询大项目基础信息,然后遍历信息去补全其他的数据
var projects []struct {
ProjectID int `json:"projectId"`
ProjectName string `json:"projectName"`
ProjectLeader string `json:"projectLeader"`
OnStreamTime string `json:"onStreamTime"`
}
// 构建查询模型
query := g.Model("sys_project").Ctx(ctx).
Fields("id AS ProjectID, project_name AS ProjectName, on_stream_time AS OnStreamTime, principal AS ProjectLeader")
if req.ProjectName != "" {
query = query.Where("project_name LIKE ?", "%"+req.ProjectName+"%")
}
err = query.Scan(&projects)
if err != nil {
return nil, err
}
buildProjectCount := 0 // 初始化在建项目数量计数器
for _, project := range projects {
// 初始化列表模型
projectModel := ProjectListModel{
ProjectID: project.ProjectID,
ProjectName: project.ProjectName,
ProjectLeader: project.ProjectLeader,
OnStreamTime: project.OnStreamTime,
}
// 首先将字符串转换为 JSON
onStreamTime, err := time.Parse("2006-01-02", project.OnStreamTime)
if err != nil {
return nil, err
}
// 检查该项目的所有子项目是否均有完成时间
subProjectCount, err := g.Model("sub_project").Ctx(ctx).Where("project_id = ? AND done_time IS NOT NULL", project.ProjectID).Count()
totalSubProjects, err := g.Model("sub_project").Ctx(ctx).Where("project_id = ?", project.ProjectID).Count()
if err != nil {
return nil, err
}
// 如果所有子项目的完成时间都不为空则设置为竣工
if subProjectCount == totalSubProjects && totalSubProjects != 0 {
var latestDoneTimeString string
// 查询子项目最后完成的任务的时间
err = g.Model("sub_project").Ctx(ctx).
Fields("MAX(done_time)").
Where("project_id = ?", project.ProjectID).
Scan(&latestDoneTimeString)
if err != nil {
return nil, err
}
latestDoneTime, err := time.Parse("2006-01-02", latestDoneTimeString)
if err != nil {
return nil, err
}
// 安全生产天数等于最后任务的完成时间减去项目的开始时间
projectModel.ProductionDays = int(latestDoneTime.Unix()-onStreamTime.Unix()) / 86400
projectModel.Status = "竣工"
} else {
// 安全生产天数等于当前的时间减去项目的开始时间
projectModel.ProductionDays = int(time.Now().Unix()-onStreamTime.Unix()) / 86400
projectModel.Status = "在建"
buildProjectCount++ // 累加在建项目数量
}
// 查询相关工作计划的总量与完成量
var work struct {
TotalQuantity int `json:"totalQuantity"`
CompletedQuantity int `json:"completedQuantity"`
}
err = g.Model("work_schedule").Ctx(ctx).
Fields("SUM(plan_num) AS totalQuantity, SUM(finished_num) AS completedQuantity").
Where("project_id = ?", project.ProjectID).
Scan(&work)
if err != nil {
return nil, err
}
projectModel.TotalQuantity = work.TotalQuantity
projectModel.CompletedQuantity = work.CompletedQuantity
// 添加到结果列表中
res.ProjectListModels = append(res.ProjectListModels, projectModel)
}
// 设置在建项目数量
res.BuildProject = buildProjectCount
return res, nil
}
// 根据项目ID查询详情【基础数据】
func (p Project) ProjectDetail(ctx context.Context, req *ProjectIndexModuleDetailReq) (res *ProjectDetailModelRes, err error) {
res = new(ProjectDetailModelRes)
// 初始化查询模型,用于获取项目的基础信息
var project struct {
ProjectID int `db:"ProjectID"`
ProjectName string `db:"ProjectName"`
ProjectLeader string `db:"ProjectLeader"`
OnStreamTime string `db:"OnStreamTime"`
}
err = g.Model("sys_project").Ctx(ctx).
Fields("id AS ProjectID, project_name AS ProjectName, principal AS ProjectLeader, on_stream_time AS OnStreamTime").
Where("id = ?", req.ProjectId).
Scan(&project)
if err != nil {
return nil, err
}
// 将基本信息设置到响应结构体中
res.ProjectID = project.ProjectID
res.ProjectName = project.ProjectName
res.ProjectLeader = project.ProjectLeader
res.OnStreamTime = project.OnStreamTime
// 计算安全生产天数
onStreamDate, err := time.Parse("2006-01-02", project.OnStreamTime)
if err != nil {
return nil, err
}
res.ProductionDays = int(time.Since(onStreamDate).Hours() / 24) // 将时间差转换为天数
// 获取总数量和已完成数量
var quantities struct {
TotalQuantity int `db:"TotalQuantity"`
CompletedQuantity int `db:"CompletedQuantity"`
}
err = g.Model("work_schedule").Ctx(ctx).
Fields("SUM(plan_num) AS TotalQuantity, SUM(finished_num) AS CompletedQuantity").
Where("project_id = ?", project.ProjectID).
Scan(&quantities)
if err != nil {
return nil, err
}
res.TotalQuantity = quantities.TotalQuantity
res.CompletedQuantity = quantities.CompletedQuantity
return res, nil
}
// 根据项目ID查询详情【项目计划】
func (p Project) ProjectPlanDetail(ctx context.Context, req *ProjectPlanDetailReq) (res *ProjectPlanDetailRes, err error) {
res = new(ProjectPlanDetailRes)
// 使用结构体来接收查询结果
var planCounts struct {
PendingPlan int `db:"PendingPlan"` // 待开始
ProcessingPlan int `db:"ProcessingPlan"` // 进行中
CompletedPlan int `db:"CompletedPlan"` // 已完成
DeferredPlan int `db:"DeferredPlan"` // 滞后
}
// 构建查询语句以聚合不同状态的计划数量
err = g.Model("work_schedule").Ctx(ctx).
Fields(
"SUM(case when status = 0 then 1 else 0 end) AS PendingPlan",
"SUM(case when status = 1 then 1 else 0 end) AS ProcessingPlan",
"SUM(case when status = 2 then 1 else 0 end) AS CompletedPlan",
"SUM(case when status = 3 then 1 else 0 end) AS DeferredPlan",
).
Where("project_id = ?", req.ProjectId).
Scan(&planCounts)
if err != nil {
return nil, err
}
// 将查询结果映射到响应结构体中
res.ProjectPlan = ProjectPlan{
PendingPlan: planCounts.PendingPlan,
ProcessingPlan: planCounts.ProcessingPlan,
CompletedPlan: planCounts.CompletedPlan,
DeferredPlan: planCounts.DeferredPlan,
}
return res, nil
}
// 根据项目ID查询详情【项目计划详情】
func (p Project) ProjectPlanDetailStatus(ctx context.Context, req *ProjectPlanDetailStatusReq) (res *ProjectPlanDetailStatusRes, err error) {
res = new(ProjectPlanDetailStatusRes)
list := []model.SchduleDetail{}
m := dao.WorkSchedule.Ctx(ctx).As("wc").
LeftJoin("work_status as ws", "wc.work_id = ws.work_id").
LeftJoin("sys_project as sp", "wc.project_id = sp.id").
Where("wc.status = ? AND wc.project_id = ?", req.Status, req.ProjectID)
res.Total, err = m.Count()
if err != nil {
return nil, fmt.Errorf("failed to count: %w", err)
}
res.CurrentPage = req.PageNum
// 查询工作计划详情
m = m.Fields("ws.work_name,wc.plan_num,wc.finished_num,wc.start_at,wc.end_at,sp.principal")
err = m.Page(req.PageNum, req.PageSize).Scan(&list)
if err != nil {
return nil, fmt.Errorf("failed to fetch page: %w", err)
}
res.List = make([]SchduleList, 0, len(list))
copier.Copy(&res.List, &list)
return res, nil
}
// 根据项目ID查询详情【视频监控】
func (p Project) ProjectVideoDetail(ctx context.Context, req *ProjectVideoDetailReq) (res *ProjectVideoDetailRes, err error) {
res = new(ProjectVideoDetailRes)
err = g.Model("ys7devices").Ctx(ctx).
Fields(
"id AS ID, created_at AS CreatedAt, DeviceSerial, DeviceName, DeviceType, Status, Defence, DeviceVersion, ProjectId, Detail, Position, Remark, VideoEncrypted").
Where("ProjectId = ?", req.ProjectId).
Order("CreatedAt DESC").
Scan(&res.YS7Devices)
if err != nil {
return nil, err
}
return res, nil
}
// 根据项目ID查询详情【施工日志】
func (p Project) GetConstructionLogs(ctx context.Context, req *ProjectLogReq) (res *ProjectLogRes, err error) {
res = new(ProjectLogRes)
err = g.Model("bus_construction_log").Ctx(ctx).
Fields(
"id, date_of_occurrence, condition, technology_quality, remark, path, created_by, updated_by, created_at, updated_at, deleted_at").
Where("project_id = ? AND deleted_at IS NULL", req.ProjectId).
Order("date_of_occurrence DESC").
Scan(&res.Logs)
if err != nil {
return nil, err
}
return res, nil
}