Files
cmautobuy/admin/service/inner_code_page.go
T

163 lines
5.6 KiB
Go
Raw Normal View History

package service
import (
"database/sql"
"fmt"
"strings"
"cmautobuy/admin/model"
"cmautobuy/admin/repository"
)
// InnerCodeStatusOption 是页面状态筛选项。
type InnerCodeStatusOption struct {
Value string
Text string
}
var innerCodeStatusOptions = []InnerCodeStatusOption{
{"", "全部状态"},
{string(model.InnerCodePending), "待匹配"},
{string(model.InnerCodeReady), "可回写"},
{string(model.InnerCodeQueued), "排队中"},
{string(model.InnerCodeApplying), "回写中"},
{string(model.InnerCodeUpdated), "已回写"},
{string(model.InnerCodeAlreadyFilled), "已存在"},
{string(model.InnerCodeSkipped), "已跳过"},
{string(model.InnerCodeFailed), "失败"},
{string(model.InnerCodeNeedsCheck), "需核对"},
}
// 删除只改本地数据库,可覆盖最大单页。回写已改为后台队列,不再限制选择 20 条。
const InnerCodeDeleteBatchLimit = 100
// InnerCodeRowView 是正式页面的一行。
type InnerCodeRowView struct {
ID int64
BusinessDate string
OrderNumber string
Stall string
SpecRaw string
SybSpec string
InnerCode string
RemoteInnerCode string
Status string
StatusText string
StatusClass string
ResultMessage string
UpdatedAt string
CanMatch bool
CanApply bool
HasRemoteOldCode bool
CanRecheck bool
}
// InnerCodeListPage 是列表、分页和底栏统计。
type InnerCodeListPage struct {
Rows []InnerCodeRowView
Total int
Page int
TotalPages int
Status string
Keyword string
Date string
Counts repository.InnerCodeStatusCounts
IsFiltered bool
}
// InnerCodeStatusOptions 返回稳定顺序的筛选项副本。
func InnerCodeStatusOptions() []InnerCodeStatusOption {
return append([]InnerCodeStatusOption(nil), innerCodeStatusOptions...)
}
// ListInnerCodePage 使用默认页容量返回档口入库码列表。
func ListInnerCodePage(db *sql.DB, businessDate, status, keyword string, requestedPage int) (*InnerCodeListPage, error) {
return ListInnerCodePageWithPageSize(db, businessDate, status, keyword, requestedPage, DefaultPageSize)
}
// ListInnerCodePageWithPageSize 校验筛选并按白名单页容量执行 SQL 分页。
func ListInnerCodePageWithPageSize(db *sql.DB, businessDate, status, keyword string, requestedPage, pageSize int) (*InnerCodeListPage, error) {
pageSize = NormalizePageSize(pageSize)
status = strings.TrimSpace(status)
if !validInnerCodeStatusFilter(status) {
status = ""
}
keyword = strings.TrimSpace(keyword)
filter := repository.InnerCodeListFilter{BusinessDate: businessDate, Status: status, Keyword: keyword}
total, err := repository.CountInnerCodeRecords(db, filter)
if err != nil {
return nil, err
}
totalPages := TotalPages(total, pageSize)
page := ClampPage(requestedPage, totalPages)
records, err := repository.ListInnerCodeRecords(db, filter, pageSize, (page-1)*pageSize)
if err != nil {
return nil, err
}
counts, err := repository.CountInnerCodeStatuses(db, businessDate)
if err != nil {
return nil, err
}
result := &InnerCodeListPage{Total: total, Page: page, TotalPages: totalPages,
Status: status, Keyword: keyword, Date: businessDate, Counts: counts,
IsFiltered: status != "" || keyword != ""}
result.Rows = make([]InnerCodeRowView, 0, len(records))
for _, record := range records {
result.Rows = append(result.Rows, innerCodeRowView(record))
}
return result, nil
}
func validInnerCodeStatusFilter(status string) bool {
for _, option := range innerCodeStatusOptions {
if option.Value == status {
return true
}
}
return false
}
func innerCodeRowView(record model.InnerCodeRecord) InnerCodeRowView {
statusText := map[model.InnerCodeStatus]string{
model.InnerCodePending: "待匹配", model.InnerCodeReady: "可回写",
model.InnerCodeQueued: "排队中",
model.InnerCodeApplying: "回写中", model.InnerCodeUpdated: "已回写",
model.InnerCodeAlreadyFilled: "已存在", model.InnerCodeSkipped: "已跳过",
model.InnerCodeFailed: "失败", model.InnerCodeNeedsCheck: "需核对",
}[record.Status]
if statusText == "" {
statusText = "未知"
}
canMatch := record.Status == model.InnerCodePending ||
record.Status == model.InnerCodeReady ||
record.Status == model.InnerCodeSkipped ||
record.Status == model.InnerCodeFailed
canApply := record.Status == model.InnerCodeReady
return InnerCodeRowView{
ID: record.ID, BusinessDate: record.BusinessDate, OrderNumber: record.OrderNumber,
Stall: displayInnerCodeValue(record.Stall), SpecRaw: displayInnerCodeValue(record.SpecRaw),
SybSpec: displayInnerCodeValue(record.SybSpec), InnerCode: record.InnerCode,
RemoteInnerCode: displayInnerCodeValue(record.RemoteInnerCode), Status: string(record.Status),
StatusText: statusText, StatusClass: "inner-code-status-" + string(record.Status),
ResultMessage: displayInnerCodeValue(record.ResultMessage), UpdatedAt: formatLocalTime(record.UpdatedAt),
CanMatch: canMatch,
CanApply: canApply,
HasRemoteOldCode: canApply && record.RemoteInnerCode != "",
CanRecheck: record.Status == model.InnerCodeNeedsCheck,
}
}
func displayInnerCodeValue(value string) string {
if strings.TrimSpace(value) == "" {
return "—"
}
return value
}
// InnerCodeStatusMessage 生成底栏可读统计。
func InnerCodeStatusMessage(page *InnerCodeListPage) string {
return fmt.Sprintf("共 %d 条,可回写 %d 条,排队中 %d 条,回写中 %d 条,需核对 %d 条;当前筛选 %d 条",
page.Counts.Total, page.Counts.Ready, page.Counts.Queued, page.Counts.Applying,
page.Counts.NeedsCheck, page.Total)
}