/api/logistics/list-c 新增这个接口,获取运费
This commit is contained in:
parent
ca5a652334
commit
cd360c8866
@ -16,6 +16,7 @@ type LogisticsApi struct{}
|
||||
|
||||
var logisticsService = service.LogisticsService{}
|
||||
|
||||
// GetLogisticsList 获取物流模板列表
|
||||
// GetLogisticsList 获取物流模板列表
|
||||
func (r *LogisticsApi) GetLogisticsList(c *gin.Context) {
|
||||
var req request.QueryLogisticsRequest
|
||||
@ -24,6 +25,10 @@ func (r *LogisticsApi) GetLogisticsList(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 从JWT中获取当前用户的about_id
|
||||
userInfo := utils.GetUserInfo(c)
|
||||
req.AboutID = userInfo.AboutID
|
||||
|
||||
list, total, err := logisticsService.GetLogisticsList(req, database.GetDB(c))
|
||||
if err != nil {
|
||||
utils.FailWithRequestLog(constant.LoggerChannelWork, "查询物流模板列表异常", err, c, req)
|
||||
|
||||
@ -275,6 +275,21 @@ func Init() {
|
||||
log.Fatal("Config表迁移失败:", err)
|
||||
}
|
||||
|
||||
err = DB.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统计表'").AutoMigrate(&models.Statist{})
|
||||
if err != nil {
|
||||
log.Fatal("Statist表迁移失败:", err)
|
||||
}
|
||||
|
||||
err = DB.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='仪表盘每日统计表'").AutoMigrate(&models.DashboardDailyStat{})
|
||||
if err != nil {
|
||||
log.Fatal("DashboardDailyStat表迁移失败:", err)
|
||||
}
|
||||
|
||||
err = DB.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户每日统计表'").AutoMigrate(&models.UserDailyStat{})
|
||||
if err != nil {
|
||||
log.Fatal("UserDailyStat表迁移失败:", err)
|
||||
}
|
||||
|
||||
// 初始化商品表
|
||||
InitProductBookTables()
|
||||
// 初始化默认管理员账号
|
||||
|
||||
5
main.go
5
main.go
@ -5,6 +5,7 @@ import (
|
||||
"psi/config"
|
||||
"psi/database"
|
||||
router "psi/routes"
|
||||
"psi/service"
|
||||
"psi/utils"
|
||||
)
|
||||
|
||||
@ -37,6 +38,10 @@ func main() {
|
||||
// ocr.StartService()
|
||||
//}()
|
||||
|
||||
// 启动统计任务调度器
|
||||
scheduler := service.NewStatistTaskScheduler()
|
||||
go scheduler.Start()
|
||||
log.Println("统计任务调度器已启动")
|
||||
// 设置路由并启动服务器
|
||||
log.Printf("[4/4] 启动服务器,端口: %s...", config.AppConfig.Server.Port)
|
||||
router.Run()
|
||||
|
||||
29
models/DashboardDailyStat.go
Normal file
29
models/DashboardDailyStat.go
Normal file
@ -0,0 +1,29 @@
|
||||
package models
|
||||
|
||||
// DashboardDailyStat 仪表盘每日统计表
|
||||
type DashboardDailyStat struct {
|
||||
ID int64 `json:"id" gorm:"primarykey;comment:ID"`
|
||||
StatDate int64 `json:"stat_date" gorm:"type:bigint;not null;default:0;comment:统计日期(YYYYMMDD格式)"`
|
||||
TotalReceivingNum int64 `json:"total_receiving_num" gorm:"not null;default:0;comment:总入库次数"`
|
||||
TotalOutboundNum int64 `json:"total_outbound_num" gorm:"not null;default:0;comment:总出库次数"`
|
||||
TotalSalesCount int64 `json:"total_sales_count" gorm:"not null;default:0;comment:总销售订单数"`
|
||||
ProductTotal int64 `json:"product_total" gorm:"not null;default:0;comment:商品总量"`
|
||||
InventoryTotal int64 `json:"inventory_total" gorm:"not null;default:0;comment:库存总量"`
|
||||
TodayInbound int64 `json:"today_inbound" gorm:"not null;default:0;comment:今日入库次数"`
|
||||
TodayOutbound int64 `json:"today_outbound" gorm:"not null;default:0;comment:今日出库次数"`
|
||||
YesterdayInbound int64 `json:"yesterday_inbound" gorm:"not null;default:0;comment:昨日入库次数"`
|
||||
YesterdayOutbound int64 `json:"yesterday_outbound" gorm:"not null;default:0;comment:昨日出库次数"`
|
||||
TodaySalesCount int64 `json:"today_sales_count" gorm:"not null;default:0;comment:今日销售订单数"`
|
||||
YesterdaySalesCount int64 `json:"yesterday_sales_count" gorm:"not null;default:0;comment:昨日销售订单数"`
|
||||
CreatedAt int64 `json:"created_at" gorm:"type:bigint;not null;default:0;comment:创建时间戳(秒)"`
|
||||
UpdatedAt int64 `json:"updated_at" gorm:"type:bigint;not null;default:0;comment:更新时间戳(秒)"`
|
||||
IsDel int8 `json:"is_del" gorm:"type:tinyint(1);not null;default:0;comment:逻辑删除标记(0:未删除,1:已删除)"`
|
||||
}
|
||||
|
||||
func (DashboardDailyStat) TableName() string {
|
||||
return "dashboard_daily_stat"
|
||||
}
|
||||
|
||||
func (DashboardDailyStat) TableOptions() string {
|
||||
return "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='仪表盘每日统计表'"
|
||||
}
|
||||
23
models/UserDailyStat.go
Normal file
23
models/UserDailyStat.go
Normal file
@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
// UserDailyStat 用户每日统计表
|
||||
type UserDailyStat struct {
|
||||
ID int64 `json:"id" gorm:"primarykey;comment:ID"`
|
||||
UserID int64 `json:"user_id" gorm:"not null;default:0;comment:用户ID"`
|
||||
UserName string `json:"user_name" gorm:"type:varchar(50);not null;default:'';comment:用户姓名"`
|
||||
StatDate int64 `json:"stat_date" gorm:"type:bigint;not null;default:0;comment:统计日期(YYYYMMDD格式)"`
|
||||
ReceivingNum int64 `json:"receiving_num" gorm:"not null;default:0;comment:入库次数"`
|
||||
OutboundNum int64 `json:"outbound_num" gorm:"not null;default:0;comment:出库次数"`
|
||||
SalesCount int64 `json:"sales_count" gorm:"not null;default:0;comment:销售订单数"`
|
||||
CreatedAt int64 `json:"created_at" gorm:"type:bigint;not null;default:0;comment:创建时间戳(秒)"`
|
||||
UpdatedAt int64 `json:"updated_at" gorm:"type:bigint;not null;default:0;comment:更新时间戳(秒)"`
|
||||
IsDel int8 `json:"is_del" gorm:"type:tinyint(1);not null;default:0;comment:逻辑删除标记(0:未删除,1:已删除)"`
|
||||
}
|
||||
|
||||
func (UserDailyStat) TableName() string {
|
||||
return "user_daily_stat"
|
||||
}
|
||||
|
||||
func (UserDailyStat) TableOptions() string {
|
||||
return "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户每日统计表'"
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
package request
|
||||
|
||||
type QueryLogisticsRequest struct {
|
||||
Keyword string `form:"keyword"`
|
||||
Status *int `form:"status"`
|
||||
Page int `form:"page,default=1"`
|
||||
PageSize int `form:"page_size,default=10"`
|
||||
Keyword string `form:"keyword"` // 物流模板名称
|
||||
Status *int `form:"status"` // 物流模板状态
|
||||
Page int `form:"page,default=1"` // 页码
|
||||
PageSize int `form:"page_size,default=10"` // 每页数量
|
||||
AboutID int64 `form:"-"` // 租户ID,从JWT中获取,不参与表单绑定
|
||||
}
|
||||
|
||||
type CreateLogisticsRequest struct {
|
||||
|
||||
@ -6,6 +6,12 @@ type DashboardStatistResponse struct {
|
||||
TotalOutboundCount int64 `json:"total_outbound_count"` // 总出库次数
|
||||
TotalSaleCount int64 `json:"total_sale_count"` // 今日商品总数
|
||||
UserStats []UserStatItem `json:"user_stats"` // 个人统计数据
|
||||
ProductTotal int64 `json:"product_total"` // 商品总量
|
||||
InventoryTotal int64 `json:"inventory_total"` // 库存量
|
||||
TodayInbound int64 `json:"today_inbound"` // 今日入库
|
||||
TodayOutbound int64 `json:"today_outbound"` // 今日出库
|
||||
YesterdayInbound int64 `json:"yesterday_inbound"` // 昨日入库
|
||||
YesterdayOutbound int64 `json:"yesterday_outbound"` // 昨日出库
|
||||
}
|
||||
|
||||
// UserStatItem 个人统计项
|
||||
|
||||
@ -91,11 +91,13 @@ func initRouter() (r *gin.Engine) {
|
||||
public.GET("/split-account-deduction-log/list", splitAccountDeductionLogApi.GetSplitAccountDeductionLogList) // 获取分账扣钱日志列表
|
||||
public.GET("/split-account-deduction-log/detail/:id", splitAccountDeductionLogApi.GetSplitAccountDeductionLogDetail) // 获取分账扣钱日志详情
|
||||
public.GET("/open/split-account-deduction-log/list", splitAccountDeductionLogApi.GetOpenSplitAccountDeductionLogList)
|
||||
public.POST("/split-account-deduction-log/update", splitAccountDeductionLogApi.UpdateSplitAccountDeductionLog) // 更新分账扣钱日志
|
||||
public.POST("/sales-order/unlock-inventory", processApi.UnlockSalesOrderInventory) // 解锁销售订单库存
|
||||
/* public.POST("/split-account-deduction-log/create", splitAccountDeductionLogApi.CreateSplitAccountDeductionLog) // 创建分账
|
||||
public.PUT("/split-account-deduction-log/update", splitAccountDeductionLogApi.UpdateSplitAccountDeductionLog) // 更新分账
|
||||
public.DELETE("/split-account-deduction-log/delete", splitAccountDeductionLogApi.DeleteSplitAccountDeductionLog) // 删除分账*/
|
||||
public.POST("/split-account-deduction-log/update", splitAccountDeductionLogApi.UpdateSplitAccountDeductionLog) // 更新分账扣钱日志
|
||||
public.POST("/sales-order/unlock-inventory", processApi.UnlockSalesOrderInventory) // 解锁销售订单库存
|
||||
public.POST("/split-account-deduction-log/create", splitAccountDeductionLogApi.CreateSplitAccountDeductionLog) // 创建分账
|
||||
public.PUT("/split-account-deduction-log/update", splitAccountDeductionLogApi.UpdateSplitAccountDeductionLog) // 更新分账
|
||||
public.DELETE("/split-account-deduction-log/delete", splitAccountDeductionLogApi.DeleteSplitAccountDeductionLog) // 删除分账
|
||||
|
||||
public.GET("/logistics/list-c", logisticsApi.GetLogisticsList) // 获取物流模板列表
|
||||
|
||||
}
|
||||
|
||||
@ -269,9 +271,9 @@ func initRouter() (r *gin.Engine) {
|
||||
auth.GET("/split-account-deduction-log/detail/:id", splitAccountDeductionLogApi.GetSplitAccountDeductionLogDetail) // 获取分账扣钱日志详情
|
||||
//public.GET("/open/split-account-deduction-log/list", splitAccountDeductionLogApi.GetOpenSplitAccountDeductionLogList) // 公开获取分账扣钱日志列表(无需签名认证)*/
|
||||
|
||||
auth.POST("/split-account-deduction-log/create", splitAccountDeductionLogApi.CreateSplitAccountDeductionLog) // 创建分账
|
||||
//auth.POST("/split-account-deduction-log/create", splitAccountDeductionLogApi.CreateSplitAccountDeductionLog) // 创建分账
|
||||
//auth.PUT("/split-account-deduction-log/update", splitAccountDeductionLogApi.UpdateSplitAccountDeductionLog) // 更新分账
|
||||
auth.DELETE("/split-account-deduction-log/delete", splitAccountDeductionLogApi.DeleteSplitAccountDeductionLog) // 删除分账*/
|
||||
//auth.DELETE("/split-account-deduction-log/delete", splitAccountDeductionLogApi.DeleteSplitAccountDeductionLog) // 删除分账*/
|
||||
// 产品日志管理
|
||||
auth.GET("/product_log/list", productApi.GetProductLogList) // 获取产品日志列表
|
||||
auth.POST("/product_log/save", productApi.SaveProductLog) // 保存产品日志
|
||||
|
||||
55
service/StatistTaskScheduler.go
Normal file
55
service/StatistTaskScheduler.go
Normal file
@ -0,0 +1,55 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// StatistTaskScheduler 统计任务调度器
|
||||
type StatistTaskScheduler struct {
|
||||
taskService *StatistTaskService
|
||||
}
|
||||
|
||||
// NewStatistTaskScheduler 创建统计任务调度器
|
||||
func NewStatistTaskScheduler() *StatistTaskScheduler {
|
||||
return &StatistTaskScheduler{
|
||||
taskService: &StatistTaskService{},
|
||||
}
|
||||
}
|
||||
|
||||
// Start 启动定时任务调度器
|
||||
func (s *StatistTaskScheduler) Start() {
|
||||
log.Println("统计任务调度器启动")
|
||||
|
||||
// 立即执行一次生成昨天的统计数据
|
||||
go func() {
|
||||
if err := s.taskService.GenerateDailyStat(); err != nil {
|
||||
log.Printf("生成每日统计失败: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 每天凌晨2点执行生成前一天的统计数据
|
||||
ticker := time.NewTicker(1 * time.Hour) // 每小时检查一次是否到了凌晨2点
|
||||
defer ticker.Stop()
|
||||
|
||||
var lastRunDate string
|
||||
|
||||
for range ticker.C {
|
||||
now := time.Now()
|
||||
currentDateStr := now.Format("2006-01-02")
|
||||
hour := now.Hour()
|
||||
|
||||
// 如果是凌晨2点且今天还没运行过
|
||||
if hour == 2 && currentDateStr != lastRunDate {
|
||||
go func(date string) {
|
||||
log.Printf("开始执行每日统计任务,日期: %s", date)
|
||||
if err := s.taskService.GenerateDailyStat(); err != nil {
|
||||
log.Printf("生成每日统计失败: %v", err)
|
||||
} else {
|
||||
log.Printf("每日统计任务执行成功,日期: %s", date)
|
||||
}
|
||||
}(currentDateStr)
|
||||
lastRunDate = currentDateStr
|
||||
}
|
||||
}
|
||||
}
|
||||
259
service/StatistTaskService.go
Normal file
259
service/StatistTaskService.go
Normal file
@ -0,0 +1,259 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"psi/database"
|
||||
"psi/models"
|
||||
"psi/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StatistTaskService struct{}
|
||||
|
||||
// GenerateDailyStat 生成每日统计数据(定时任务调用)
|
||||
// GenerateDailyStat 生成每日统计数据(定时任务调用)
|
||||
// GenerateDailyStat 生成每日统计数据(定时任务调用)
|
||||
func (s *StatistTaskService) GenerateDailyStat(db ...*gorm.DB) error {
|
||||
now := time.Now()
|
||||
|
||||
yesterday := now.AddDate(0, 0, -1)
|
||||
statDateStr := yesterday.Format("20060102")
|
||||
var statDate int64
|
||||
if _, err := fmt.Sscanf(statDateStr, "%d", &statDate); err != nil {
|
||||
return fmt.Errorf("日期格式化失败: %v", err)
|
||||
}
|
||||
|
||||
yesterdayStart := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, yesterday.Location()).Unix()
|
||||
yesterdayEnd := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 23, 59, 59, 0, yesterday.Location()).Unix()
|
||||
|
||||
mainDB := database.DB
|
||||
if len(db) > 0 && db[0] != nil {
|
||||
mainDB = db[0]
|
||||
}
|
||||
|
||||
var aboutIDs []int64
|
||||
if err := mainDB.Model(&models.Employee{}).Where("deleted_at = ?", 0).Distinct().Pluck("about_id", &aboutIDs).Error; err != nil {
|
||||
return fmt.Errorf("查询租户列表失败: %v", err)
|
||||
}
|
||||
|
||||
if len(aboutIDs) == 0 {
|
||||
utils.InfoLog("work", map[string]interface{}{
|
||||
"source": "定时任务-生成每日统计",
|
||||
"stat_date": statDate,
|
||||
"message": "没有找到任何租户",
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, aboutID := range aboutIDs {
|
||||
if aboutID == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
tenantDB, err := database.GetTenantDB(aboutID)
|
||||
if err != nil {
|
||||
utils.ErrorLog("work", map[string]interface{}{
|
||||
"source": "定时任务-生成每日统计",
|
||||
"about_id": aboutID,
|
||||
"error": fmt.Sprintf("获取租户数据库失败: %v", err),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
tx := tenantDB.Begin()
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
_, err := s.generateDashboardDailyStat(tx, statDate, yesterdayStart, yesterdayEnd)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
utils.ErrorLog("work", map[string]interface{}{
|
||||
"source": "定时任务-生成每日统计",
|
||||
"about_id": aboutID,
|
||||
"stat_date": statDate,
|
||||
"error": fmt.Sprintf("生成全局统计失败: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.generateUserDailyStat(tx, aboutID, statDate, yesterdayStart, yesterdayEnd); err != nil {
|
||||
tx.Rollback()
|
||||
utils.ErrorLog("work", map[string]interface{}{
|
||||
"source": "定时任务-生成每日统计",
|
||||
"about_id": aboutID,
|
||||
"stat_date": statDate,
|
||||
"error": fmt.Sprintf("生成用户统计失败: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
utils.ErrorLog("work", map[string]interface{}{
|
||||
"source": "定时任务-生成每日统计",
|
||||
"about_id": aboutID,
|
||||
"stat_date": statDate,
|
||||
"error": fmt.Sprintf("提交事务失败: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
utils.InfoLog("work", map[string]interface{}{
|
||||
"source": "定时任务-生成每日统计",
|
||||
"about_id": aboutID,
|
||||
"stat_date": statDate,
|
||||
"message": fmt.Sprintf("成功生成%s的统计数据", yesterday.Format("2006-01-02")),
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateDashboardDailyStat 生成全局每日统计
|
||||
func (s *StatistTaskService) generateDashboardDailyStat(tx *gorm.DB, statDate int64, startDate, endDate int64) (*models.DashboardDailyStat, error) {
|
||||
var existingStat models.DashboardDailyStat
|
||||
err := tx.Where("stat_date = ? AND is_del = ?", statDate, 0).First(&existingStat).Error
|
||||
|
||||
if err == nil {
|
||||
if err := tx.Model(&models.DashboardDailyStat{}).Where("id = ?", existingStat.ID).Update("is_del", 1).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var totalReceivingNum, totalOutboundNum int64
|
||||
tx.Model(&models.Statist{}).
|
||||
Where("stat_date <= ? AND is_del = ?", endDate, 0).
|
||||
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
|
||||
Row().Scan(&totalReceivingNum, &totalOutboundNum)
|
||||
|
||||
var todayInbound, todayOutbound int64
|
||||
tx.Model(&models.Statist{}).
|
||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", startDate, endDate, 0).
|
||||
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
|
||||
Row().Scan(&todayInbound, &todayOutbound)
|
||||
|
||||
beforeYesterdayStart := time.Date(time.Unix(startDate, 0).Year(), time.Unix(startDate, 0).Month(), time.Unix(startDate, 0).Day()-1, 0, 0, 0, 0, time.Unix(startDate, 0).Location()).Unix()
|
||||
beforeYesterdayEnd := time.Date(time.Unix(startDate, 0).Year(), time.Unix(startDate, 0).Month(), time.Unix(startDate, 0).Day()-1, 23, 59, 59, 0, time.Unix(startDate, 0).Location()).Unix()
|
||||
var yesterdayInbound, yesterdayOutbound int64
|
||||
tx.Model(&models.Statist{}).
|
||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", beforeYesterdayStart, beforeYesterdayEnd, 0).
|
||||
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
|
||||
Row().Scan(&yesterdayInbound, &yesterdayOutbound)
|
||||
|
||||
var totalSalesCount int64
|
||||
tx.Model(&models.SalesOrder{}).
|
||||
Where("created_at <= ? AND is_del = ?", endDate, 0).
|
||||
Count(&totalSalesCount)
|
||||
|
||||
var todaySalesCount int64
|
||||
tx.Model(&models.SalesOrder{}).
|
||||
Where("created_at >= ? AND created_at <= ? AND is_del = ?", startDate, endDate, 0).
|
||||
Count(&todaySalesCount)
|
||||
|
||||
var yesterdaySalesCount int64
|
||||
tx.Model(&models.SalesOrder{}).
|
||||
Where("created_at >= ? AND created_at <= ? AND is_del = ?", beforeYesterdayStart, beforeYesterdayEnd, 0).
|
||||
Count(&yesterdaySalesCount)
|
||||
|
||||
var productTotal int64
|
||||
tx.Model(&models.Product{}).
|
||||
Where("is_del = ?", 0).
|
||||
Count(&productTotal)
|
||||
|
||||
var inventoryTotal int64
|
||||
tx.Model(&models.Inventory{}).
|
||||
Where("is_del = ?", 0).
|
||||
Select("COALESCE(SUM(quantity), 0)").
|
||||
Row().Scan(&inventoryTotal)
|
||||
|
||||
now := time.Now().Unix()
|
||||
dashboardStat := &models.DashboardDailyStat{
|
||||
StatDate: statDate,
|
||||
TotalReceivingNum: totalReceivingNum,
|
||||
TotalOutboundNum: totalOutboundNum,
|
||||
TotalSalesCount: totalSalesCount,
|
||||
ProductTotal: productTotal,
|
||||
InventoryTotal: inventoryTotal,
|
||||
TodayInbound: todayInbound,
|
||||
TodayOutbound: todayOutbound,
|
||||
YesterdayInbound: yesterdayInbound,
|
||||
YesterdayOutbound: yesterdayOutbound,
|
||||
TodaySalesCount: todaySalesCount,
|
||||
YesterdaySalesCount: yesterdaySalesCount,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
IsDel: 0,
|
||||
}
|
||||
|
||||
if err := tx.Create(dashboardStat).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dashboardStat, nil
|
||||
}
|
||||
|
||||
// generateUserDailyStat 生成用户每日统计
|
||||
func (s *StatistTaskService) generateUserDailyStat(tx *gorm.DB, aboutID int64, statDate int64, startDate, endDate int64) error {
|
||||
type UserStatGroup struct {
|
||||
UserID int64 `gorm:"column:user_id"`
|
||||
UserName string `gorm:"column:user_name"`
|
||||
ReceivingNum int64 `gorm:"column:receiving_num"`
|
||||
OutboundNum int64 `gorm:"column:outbound_num"`
|
||||
SalesCount int64 `gorm:"column:sales_count"`
|
||||
}
|
||||
|
||||
var userStats []UserStatGroup
|
||||
tx.Table("employee").
|
||||
Select(`
|
||||
employee.id as user_id,
|
||||
employee.username as user_name,
|
||||
COALESCE((SELECT SUM(receiving_num) FROM statist WHERE create_by = employee.id AND stat_date >= ? AND stat_date <= ? AND is_del = ?), 0) as receiving_num,
|
||||
COALESCE((SELECT SUM(outbound_num) FROM statist WHERE create_by = employee.id AND stat_date >= ? AND stat_date <= ? AND is_del = ?), 0) as outbound_num,
|
||||
COALESCE((SELECT COUNT(*) FROM sales_order WHERE create_by = employee.id AND created_at >= ? AND created_at <= ? AND is_del = ?), 0) as sales_count
|
||||
`, startDate, endDate, 0, startDate, endDate, 0, startDate, endDate, 0).
|
||||
Where("employee.about_id = ? AND employee.is_del = ?", aboutID, 0).
|
||||
Scan(&userStats)
|
||||
|
||||
if len(userStats) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
for _, userStat := range userStats {
|
||||
var existingStat models.UserDailyStat
|
||||
err := tx.Where("user_id = ? AND stat_date = ? AND is_del = ?", userStat.UserID, statDate, 0).First(&existingStat).Error
|
||||
|
||||
if err == nil {
|
||||
if err := tx.Model(&models.UserDailyStat{}).Where("id = ?", existingStat.ID).Update("is_del", 1).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
newStat := &models.UserDailyStat{
|
||||
UserID: userStat.UserID,
|
||||
UserName: userStat.UserName,
|
||||
StatDate: statDate,
|
||||
ReceivingNum: userStat.ReceivingNum,
|
||||
OutboundNum: userStat.OutboundNum,
|
||||
SalesCount: userStat.SalesCount,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
IsDel: 0,
|
||||
}
|
||||
|
||||
if err := tx.Create(newStat).Error; err != nil {
|
||||
utils.ErrorLog("work", map[string]interface{}{
|
||||
"source": "生成用户统计",
|
||||
"user_id": userStat.UserID,
|
||||
"error": fmt.Sprintf("创建用户统计记录失败: %v", err),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -27,8 +27,28 @@ func (s *LogisticsService) GetLogisticsList(req request.QueryLogisticsRequest, d
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
// 如果提供了 about_id,先查询该租户下的所有仓库
|
||||
var warehouseIDs []int64
|
||||
if req.AboutID > 0 {
|
||||
if err := databaseConn.Model(&models.Warehouse{}).
|
||||
Where("about_id = ? AND is_del = ?", req.AboutID, 0).
|
||||
Pluck("id", &warehouseIDs).Error; err != nil {
|
||||
return nil, 0, errors.New("查询仓库信息失败")
|
||||
}
|
||||
|
||||
// 如果没有找到仓库,直接返回空结果
|
||||
if len(warehouseIDs) == 0 {
|
||||
return []response.LogisticsResponse{}, 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
query := databaseConn.Model(&models.Logistics{}).Where("del_flag = ?", "0")
|
||||
|
||||
// 如果有仓库ID列表,只查询这些仓库关联的物流模板
|
||||
if len(warehouseIDs) > 0 {
|
||||
query = query.Where("id IN (?)", warehouseIDs)
|
||||
}
|
||||
|
||||
if req.Keyword != "" {
|
||||
query = query.Where("template_name LIKE ? OR delivery_province LIKE ? OR delivery_city LIKE ?",
|
||||
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
|
||||
@ -39,7 +59,7 @@ func (s *LogisticsService) GetLogisticsList(req request.QueryLogisticsRequest, d
|
||||
}
|
||||
|
||||
// === debug: 打印完整SQL ===
|
||||
log.Printf("[GetLogisticsList] 请求参数 page=%d pageSize=%d keyword=%q", req.Page, req.PageSize, req.Keyword)
|
||||
log.Printf("[GetLogisticsList] 请求参数 page=%d pageSize=%d keyword=%q about_id=%d", req.Page, req.PageSize, req.Keyword, req.AboutID)
|
||||
// === debug end ===
|
||||
|
||||
var total int64
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"psi/database"
|
||||
"psi/models"
|
||||
@ -13,7 +14,62 @@ import (
|
||||
type StatistService struct{}
|
||||
|
||||
// DashboardStatist 获取仪表盘统计数据
|
||||
func (s *StatistService) DashboardStatist(req systemReq.DashboardStatistRequest, db ...*gorm.DB) (*systemRes.DashboardStatistResponse, error) {
|
||||
/*func (s *StatistService) DashboardStatist(req systemReq.DashboardStatistRequest, db ...*gorm.DB) (*systemRes.DashboardStatistResponse, error) {
|
||||
databaseConn := database.OptionalDB(db...)
|
||||
|
||||
now := time.Now()
|
||||
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix()
|
||||
endOfDay := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location()).Unix()
|
||||
|
||||
if req.StartDate == 0 {
|
||||
req.StartDate = startOfDay
|
||||
}
|
||||
if req.EndDate == 0 {
|
||||
req.EndDate = endOfDay
|
||||
}
|
||||
|
||||
statDateStr := now.Format("20060102")
|
||||
var statDate int64
|
||||
if _, err := fmt.Sscanf(statDateStr, "%d", &statDate); err != nil {
|
||||
return s.getDashboardStatRealtime(databaseConn, req.StartDate, req.EndDate)
|
||||
}
|
||||
|
||||
var dashboardStat models.DashboardDailyStat
|
||||
err := databaseConn.Where("stat_date = ? AND is_del = ?", statDate, 0).First(&dashboardStat).Error
|
||||
|
||||
if err != nil {
|
||||
return s.getDashboardStatRealtime(databaseConn, req.StartDate, req.EndDate)
|
||||
}
|
||||
|
||||
var userStats []systemRes.UserStatItem
|
||||
var userDailyStats []models.UserDailyStat
|
||||
if err := databaseConn.Where("stat_date = ? AND is_del = ?", statDate, 0).Find(&userDailyStats).Error; err == nil {
|
||||
for _, userStat := range userDailyStats {
|
||||
userStats = append(userStats, systemRes.UserStatItem{
|
||||
UserID: userStat.UserID,
|
||||
UserName: userStat.UserName,
|
||||
ReceivingCount: userStat.ReceivingNum,
|
||||
OutboundCount: userStat.OutboundNum,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &systemRes.DashboardStatistResponse{
|
||||
TotalReceivingCount: dashboardStat.TotalReceivingNum,
|
||||
TotalOutboundCount: dashboardStat.TotalOutboundNum,
|
||||
TotalSaleCount: dashboardStat.TodaySalesCount,
|
||||
UserStats: userStats,
|
||||
ProductTotal: dashboardStat.ProductTotal,
|
||||
InventoryTotal: dashboardStat.InventoryTotal,
|
||||
TodayInbound: dashboardStat.TodayInbound,
|
||||
TodayOutbound: dashboardStat.TodayOutbound,
|
||||
YesterdayInbound: dashboardStat.YesterdayInbound,
|
||||
YesterdayOutbound: dashboardStat.YesterdayOutbound,
|
||||
}, nil
|
||||
}*/
|
||||
|
||||
// DashboardStatist 获取仪表盘统计数据
|
||||
/*func (s *StatistService) DashboardStatist(req systemReq.DashboardStatistRequest, db ...*gorm.DB) (*systemRes.DashboardStatistResponse, error) {
|
||||
databaseConn := database.OptionalDB(db...)
|
||||
|
||||
// 计算今日的时间范围(如果未指定)
|
||||
@ -94,6 +150,152 @@ func (s *StatistService) DashboardStatist(req systemReq.DashboardStatistRequest,
|
||||
TotalSaleCount: totalSaleCount,
|
||||
UserStats: userStats,
|
||||
}, nil
|
||||
}*/
|
||||
// DashboardStatist 获取仪表盘统计数据
|
||||
func (s *StatistService) DashboardStatist(req systemReq.DashboardStatistRequest, db ...*gorm.DB) (*systemRes.DashboardStatistResponse, error) {
|
||||
databaseConn := database.OptionalDB(db...)
|
||||
|
||||
now := time.Now()
|
||||
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix()
|
||||
endOfDay := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location()).Unix()
|
||||
|
||||
if req.StartDate == 0 {
|
||||
req.StartDate = startOfDay
|
||||
}
|
||||
if req.EndDate == 0 {
|
||||
req.EndDate = endOfDay
|
||||
}
|
||||
|
||||
statDateStr := now.Format("20060102")
|
||||
var statDate int64
|
||||
if _, err := fmt.Sscanf(statDateStr, "%d", &statDate); err != nil {
|
||||
return s.getDashboardStatRealtime(databaseConn, req.StartDate, req.EndDate)
|
||||
}
|
||||
|
||||
var dashboardStat models.DashboardDailyStat
|
||||
err := databaseConn.Where("stat_date = ? AND is_del = ?", statDate, 0).First(&dashboardStat).Error
|
||||
|
||||
if err != nil {
|
||||
return s.getDashboardStatRealtime(databaseConn, req.StartDate, req.EndDate)
|
||||
}
|
||||
|
||||
var userStats []systemRes.UserStatItem
|
||||
var userDailyStats []models.UserDailyStat
|
||||
if err := databaseConn.Where("stat_date = ? AND is_del = ?", statDate, 0).Find(&userDailyStats).Error; err == nil {
|
||||
for _, userStat := range userDailyStats {
|
||||
userStats = append(userStats, systemRes.UserStatItem{
|
||||
UserID: userStat.UserID,
|
||||
UserName: userStat.UserName,
|
||||
ReceivingCount: userStat.ReceivingNum,
|
||||
OutboundCount: userStat.OutboundNum,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &systemRes.DashboardStatistResponse{
|
||||
TotalReceivingCount: dashboardStat.TotalReceivingNum,
|
||||
TotalOutboundCount: dashboardStat.TotalOutboundNum,
|
||||
TotalSaleCount: dashboardStat.TodaySalesCount,
|
||||
UserStats: userStats,
|
||||
ProductTotal: dashboardStat.ProductTotal,
|
||||
InventoryTotal: dashboardStat.InventoryTotal,
|
||||
TodayInbound: dashboardStat.TodayInbound,
|
||||
TodayOutbound: dashboardStat.TodayOutbound,
|
||||
YesterdayInbound: dashboardStat.YesterdayInbound,
|
||||
YesterdayOutbound: dashboardStat.YesterdayOutbound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getDashboardStatRealtime 实时查询仪表盘统计数据(降级方案)
|
||||
func (s *StatistService) getDashboardStatRealtime(databaseConn *gorm.DB, startDate, endDate int64) (*systemRes.DashboardStatistResponse, error) {
|
||||
var totalSaleCount int64
|
||||
saleOrderQuery := databaseConn.Model(&models.SalesOrder{}).
|
||||
Where("created_at >= ? AND created_at <= ? AND is_del = ?", startDate, endDate, 0)
|
||||
saleOrderQuery.Count(&totalSaleCount)
|
||||
|
||||
var totalReceivingCount, totalOutboundCount int64
|
||||
statistQuery := databaseConn.Model(&models.Statist{}).
|
||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", startDate, endDate, 0)
|
||||
|
||||
var statistList []models.Statist
|
||||
if err := statistQuery.Find(&statistList).Error; err != nil {
|
||||
return nil, utils.NewError("查询统计数据失败")
|
||||
}
|
||||
|
||||
if len(statistList) == 0 {
|
||||
return &systemRes.DashboardStatistResponse{
|
||||
TotalReceivingCount: 0,
|
||||
TotalOutboundCount: 0,
|
||||
TotalSaleCount: totalSaleCount,
|
||||
UserStats: []systemRes.UserStatItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
for _, stat := range statistList {
|
||||
totalReceivingCount += stat.ReceivingNum
|
||||
totalOutboundCount += stat.OutboundNum
|
||||
}
|
||||
|
||||
var userStats []systemRes.UserStatItem
|
||||
|
||||
type UserStatGroup struct {
|
||||
CreateBy int64 `gorm:"column:create_by"`
|
||||
TotalReceiving int64 `gorm:"column:total_receiving"`
|
||||
TotalOutbound int64 `gorm:"column:total_outbound"`
|
||||
}
|
||||
|
||||
var userStatGroups []UserStatGroup
|
||||
databaseConn.Model(&models.Statist{}).
|
||||
Select("create_by, SUM(receiving_num) as total_receiving, SUM(outbound_num) as total_outbound").
|
||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", startDate, endDate, 0).
|
||||
Group("create_by").
|
||||
Scan(&userStatGroups)
|
||||
|
||||
for _, group := range userStatGroups {
|
||||
var employee models.Employee
|
||||
if err := database.DB.Where("id = ?", group.CreateBy).First(&employee).Error; err == nil {
|
||||
userStats = append(userStats, systemRes.UserStatItem{
|
||||
UserID: employee.ID,
|
||||
UserName: employee.Username,
|
||||
ReceivingCount: group.TotalReceiving,
|
||||
OutboundCount: group.TotalOutbound,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var productTotal int64
|
||||
databaseConn.Model(&models.Product{}).Where("is_del = ?", 0).Count(&productTotal)
|
||||
|
||||
var inventoryTotal int64
|
||||
databaseConn.Model(&models.Inventory{}).Where("is_del = ?", 0).Select("COALESCE(SUM(quantity), 0)").Row().Scan(&inventoryTotal)
|
||||
|
||||
now := time.Now()
|
||||
yesterdayStart := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location()).Unix()
|
||||
yesterdayEnd := time.Date(now.Year(), now.Month(), now.Day()-1, 23, 59, 59, 0, now.Location()).Unix()
|
||||
|
||||
var todayInbound, todayOutbound, yesterdayInbound, yesterdayOutbound int64
|
||||
databaseConn.Model(&models.Statist{}).
|
||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", startDate, endDate, 0).
|
||||
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
|
||||
Row().Scan(&todayInbound, &todayOutbound)
|
||||
|
||||
databaseConn.Model(&models.Statist{}).
|
||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", yesterdayStart, yesterdayEnd, 0).
|
||||
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
|
||||
Row().Scan(&yesterdayInbound, &yesterdayOutbound)
|
||||
|
||||
return &systemRes.DashboardStatistResponse{
|
||||
TotalReceivingCount: totalReceivingCount,
|
||||
TotalOutboundCount: totalOutboundCount,
|
||||
TotalSaleCount: totalSaleCount,
|
||||
UserStats: userStats,
|
||||
ProductTotal: productTotal,
|
||||
InventoryTotal: inventoryTotal,
|
||||
TodayInbound: todayInbound,
|
||||
TodayOutbound: todayOutbound,
|
||||
YesterdayInbound: yesterdayInbound,
|
||||
YesterdayOutbound: yesterdayOutbound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetWarehouseStatist 获取仓库统计数据
|
||||
|
||||
Loading…
Reference in New Issue
Block a user