163 lines
5.6 KiB
Go
163 lines
5.6 KiB
Go
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)
|
|
}
|