spring
2026-10-08 e0fc86fda41a8777a0cec5a9de7aa9f1474f5dc8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import InventoryOperationApi from "@/api/product/inventoryOperation";
import TwistApi from "@/api/product/twist";
import { MOCK_BOBBIN, MOCK_ENABLED, MOCK_SOURCE_STOCK } from "./mock";
 
/** 操作类型 */
export const OP_SPLIT = "SPLIT";
export const OP_STRAND_REWIND = "STRAND_REWIND";
 
/** 物料类型:源盘与目标盘都走「成品」(与 PC 端成品拆盘一致) */
export const MATERIAL_TYPE_FG = "成品";
 
/** 上一步扫码领用到的源盘,通过本地缓存传给办理页 */
export const SOURCE_STORAGE_KEY = "inventoryOperationSourceReel";
 
/** 可选的两种操作 */
export const OPERATION_TYPES = [
  {
    value: OP_SPLIT,
    label: "成品拆盘",
    desc: "一个源盘拆成多个子盘",
    icon: "fork",
  },
  {
    value: OP_STRAND_REWIND,
    label: "绞线复绕",
    desc: "整盘复绕,可沿用原盘号或生成新盘号",
    icon: "rotate",
  },
];
 
/** 扫码内容里可能表示「盘号」的字段 */
export const REEL_CODE_KEYS = [
  "batchCode",
  "dishNo",
  "monofilamentNumber",
  "systemNo",
  "code",
  "盘号",
  "批次号",
];
 
/** 扫码内容里可能表示「盘具编号」的字段 */
export const DISH_CODE_KEYS = [
  "weighingCode",
  "weighingNo",
  "dishCode",
  "receiveDishNo",
  "code",
  "称重编号",
  "盘具编号",
];
 
/** 解析扫码内容:兼容 JSON 与纯文本 */
export function parseScanCode(payload: any) {
  const raw = payload?.code ?? payload;
  if (raw === undefined || raw === null) return null;
  if (typeof raw === "object") return raw;
  const text = String(raw).trim();
  if (!text) return null;
  if (text.startsWith("{")) {
    try {
      return JSON.parse(text);
    } catch {
      // JSON 解析失败时按纯文本编号处理
    }
  }
  return { code: text };
}
 
/** 从解析后的对象里按候选字段取编号 */
export function pickValue(data: any, keys: string[]) {
  for (const key of keys) {
    const value = data?.[key];
    if (value !== undefined && value !== null && String(value).trim() !== "") {
      return String(value).trim();
    }
  }
  return "";
}
 
/** 统一从分页/数组响应里取列表 */
function pickRecords(data: any): any[] {
  const pageData: any = data ?? {};
  return (
    pageData?.records ??
    pageData?.list ??
    pageData?.rows ??
    (Array.isArray(pageData) ? pageData : [])
  );
}
 
/**
 * 源盘(成品库存)查询:真实接口优先;接口未联调/查不到时回落模拟数据。
 * 模拟模式下盘号取扫码/输入的值,方便连续测试。
 * @returns record 为 null 表示确实查不到
 */
export async function findSourceStock(code: string) {
  try {
    const { data } = await InventoryOperationApi.searchStock({
      keyword: code,
      materialType: MATERIAL_TYPE_FG,
      ncReturnFlag: "Y",
    });
    const records = pickRecords(data);
    const exact = (records || []).find((row: any) => String(row?.batchCode ?? "").trim() === code);
    const record = exact ?? (records?.length === 1 ? records[0] : null);
    if (record) return { record, mocked: false };
  } catch {
    // 接口未就绪,走下面的模拟数据
  }
  if (!MOCK_ENABLED) return { record: null, mocked: false };
  return { record: { ...MOCK_SOURCE_STOCK, batchCode: code }, mocked: true };
}
 
/**
 * 盘具(盘具称重台账)查询:真实接口优先;接口未联调/查不到时回落模拟数据。
 * 模拟模式下盘具编号取扫码/输入的值,方便一个单子里测试多个盘具。
 * @returns record 为 null 表示确实查不到
 */
export async function findBobbin(code: string) {
  try {
    const { data } = await TwistApi.queryBobbinWeighingPage({
      current: 1,
      size: 50,
      weighingCode: code,
    });
    const records = pickRecords(data);
    const exact = (records || []).find(
      (row: any) => String(row?.weighingCode ?? "").trim() === code
    );
    const record = exact ?? (records?.length === 1 ? records[0] : null);
    if (record) return { record, mocked: false };
  } catch {
    // 接口未就绪,走下面的模拟数据
  }
  if (!MOCK_ENABLED) return { record: null, mocked: false };
  return { record: { ...MOCK_BOBBIN, weighingCode: code }, mocked: true };
}
 
/** 盘具是否已被领用 */
export function isBobbinReceived(row: any) {
  const value = row?.received ?? row?.isReceived;
  return [true, 1, "1", "true", "是"].includes(value);
}