feat: 增加档口入库码独立页面 (#233)
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
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.InnerCodeApplying), "回写中"},
|
||||
{string(model.InnerCodeUpdated), "已回写"},
|
||||
{string(model.InnerCodeAlreadyFilled), "已存在"},
|
||||
{string(model.InnerCodeSkipped), "已跳过"},
|
||||
{string(model.InnerCodeFailed), "失败"},
|
||||
{string(model.InnerCodeNeedsCheck), "需核对"},
|
||||
}
|
||||
|
||||
// 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
|
||||
CanSelect 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 校验筛选并返回统一 20 条 SQL 分页结果。
|
||||
func ListInnerCodePage(db *sql.DB, businessDate, status, keyword string, requestedPage int) (*InnerCodeListPage, error) {
|
||||
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)
|
||||
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.InnerCodeApplying: "回写中", model.InnerCodeUpdated: "已回写",
|
||||
model.InnerCodeAlreadyFilled: "已存在", model.InnerCodeSkipped: "已跳过",
|
||||
model.InnerCodeFailed: "失败", model.InnerCodeNeedsCheck: "需核对",
|
||||
}[record.Status]
|
||||
if statusText == "" {
|
||||
statusText = "未知"
|
||||
}
|
||||
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),
|
||||
CanSelect: record.Status == model.InnerCodeReady,
|
||||
HasRemoteOldCode: record.Status == model.InnerCodeReady && 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 条",
|
||||
page.Counts.Total, page.Counts.Ready, page.Counts.NeedsCheck, page.Total)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"cmautobuy/admin/model"
|
||||
)
|
||||
|
||||
func TestInnerCodeRowView_只有可回写记录可选择(t *testing.T) {
|
||||
for _, status := range []model.InnerCodeStatus{
|
||||
model.InnerCodePending, model.InnerCodeReady, model.InnerCodeApplying,
|
||||
model.InnerCodeUpdated, model.InnerCodeAlreadyFilled, model.InnerCodeSkipped,
|
||||
model.InnerCodeFailed, model.InnerCodeNeedsCheck,
|
||||
} {
|
||||
view := innerCodeRowView(model.InnerCodeRecord{Status: status, RemoteInnerCode: "OLD"})
|
||||
if view.CanSelect != (status == model.InnerCodeReady) {
|
||||
t.Errorf("status=%s CanSelect=%v", status, view.CanSelect)
|
||||
}
|
||||
if view.CanRecheck != (status == model.InnerCodeNeedsCheck) {
|
||||
t.Errorf("status=%s CanRecheck=%v", status, view.CanRecheck)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInnerCodeStatusOptions_覆盖所有状态(t *testing.T) {
|
||||
options := InnerCodeStatusOptions()
|
||||
if len(options) != 9 || options[0].Value != "" {
|
||||
t.Fatalf("状态筛选项不完整: %+v", options)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user