yyb
2026-05-11 3682ad63b5bdb47228325dea1efe2bb9069254a5
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import { productList } from "@/api/salesManagement/salesLedger";
 
/** 台账/产品发货状态:1-未发货 … 5-已发货 6-部分发货(与后端枚举对齐,兼容多种字段名) */
export const LEDGER_SHIPPING_LABELS = {
  1: "未发货",
  2: "审批中",
  3: "审批不通过",
  4: "审批通过",
  5: "已发货",
  6: "部分发货",
};
 
export const normalizeShippingStatusToCode = v => {
  if (v === null || v === undefined || v === "") return 1;
  const n = Number(v);
  if (!Number.isNaN(n) && n >= 1 && n <= 6) return n;
  const s = String(v).trim();
  const textMap = {
    未发货: 1,
    待发货: 1,
    审批中: 2,
    审核中: 2,
    待审核: 2,
    审批不通过: 3,
    审核拒绝: 3,
    审批通过: 4,
    审核通过: 4,
    已发货: 5,
    发货完成: 5,
    已完成发货: 5,
    部分发货: 6,
    部分已发货: 6,
  };
  return textMap[s] ?? 1;
};
 
export const getLedgerShippingStatusCode = item => {
  if (!item) return 1;
  const raw =
    item.deliveryStatus ??
    item.shippingApprovalStatus ??
    item.shipmentApproveStatus ??
    item.ledgerShippingStatus;
  if (raw !== null && raw !== undefined && raw !== "") {
    return normalizeShippingStatusToCode(raw);
  }
  if (item.shippingStatus !== null && item.shippingStatus !== undefined && item.shippingStatus !== "") {
    return normalizeShippingStatusToCode(item.shippingStatus);
  }
  return 1;
};
 
export const getLedgerShippingLabel = item =>
  LEDGER_SHIPPING_LABELS[getLedgerShippingStatusCode(item)] ?? "未发货";
 
export const getLedgerShippingTagType = item => {
  const t = {
    1: "info",
    2: "warning",
    3: "error",
    4: "primary",
    5: "success",
    6: "warning",
  };
  return t[getLedgerShippingStatusCode(item)] ?? "info";
};
 
/** 台账级是否允许发起/继续发货(含部分发货后继续发剩余) */
export const canLedgerShip = item => {
  const c = getLedgerShippingStatusCode(item);
  return c === 1 || c === 3 || c === 6;
};
 
/** productStockStatus:0 未出库 — 不允许发货(与业务端展示一致) */
export const isProductStockStatusUnOutbound = row => {
  if (!row) return false;
  const v = row.productStockStatus;
  return v === 0 || v === "0";
};
 
/**
 * 单行产品是否允许进入发货页(充足 + 非未出库;待发货/审核拒绝/部分发货可继续)
 * 部分发货行可能已有 shippingDate/车牌,仍允许再次发货
 */
export const canShipProductRow = row => {
  if (!row) return false;
  if (isProductStockStatusUnOutbound(row)) return false;
  if (row.approveStatus !== 1) return false;
 
  const statusStr = row.shippingStatus ? String(row.shippingStatus).trim() : "";
  let rowCode = 1;
  if (row.deliveryStatus !== null && row.deliveryStatus !== undefined && String(row.deliveryStatus).trim() !== "") {
    rowCode = normalizeShippingStatusToCode(row.deliveryStatus);
  } else if (statusStr) {
    rowCode = normalizeShippingStatusToCode(statusStr);
  }
 
  if (rowCode === 5) return false;
 
  const isPartialRow = rowCode === 6 || statusStr === "部分发货" || statusStr === "部分已发货";
  if ((row.shippingDate || row.shippingCarNumber) && !isPartialRow) return false;
 
  if (row.deliveryStatus !== null && row.deliveryStatus !== undefined && String(row.deliveryStatus).trim() !== "") {
    const code = normalizeShippingStatusToCode(row.deliveryStatus);
    if (code === 5) return false;
  }
 
  return (
    statusStr === "待发货" ||
    statusStr === "审核拒绝" ||
    statusStr === "部分发货" ||
    statusStr === "部分已发货" ||
    rowCode === 6
  );
};
 
export const productLabelForShip = row => {
  if (!row) return "产品";
  const parts = [row.productCategory, row.floorCode, row.specificationModel].filter(Boolean);
  return parts.length ? parts.join(" / ") : row.productName || row.goodsName || "产品";
};
 
/** 判断是否存在已发货、部分发货或已有发货痕迹的产品(删除台账等场景) */
export const hasShippedProducts = products => {
  if (!products || products.length === 0) return false;
  return products.some(p => {
    const statusCode = normalizeShippingStatusToCode(p.deliveryStatus ?? p.shippingStatus);
    const statusStr = (p.shippingStatus ?? "").toString().trim();
    return (
      statusCode === 5 ||
      statusCode === 6 ||
      statusStr === "已发货" ||
      statusStr === "发货完成" ||
      statusStr === "已完成发货" ||
      statusStr === "部分发货" ||
      statusStr === "部分已发货" ||
      !!p.shippingDate ||
      !!p.shippingCarNumber
    );
  });
};
 
const showLoadingToast = message => {
  uni.showLoading({ title: message, mask: true });
};
const closeToast = () => {
  uni.hideLoading();
};
 
/**
 * 与销售台账「发货」按钮一致:校验台账状态 → 拉产品 → 校验库存与可发货行 → 跳转 goOut
 * @param {Record<string, any>} ledgerItem 至少含 id;含发货审批字段时先做 canLedgerShip 校验
 */
export async function executeSalesLedgerShip(ledgerItem) {
  if (!canLedgerShip(ledgerItem)) {
    uni.showToast({
      title: "仅未发货、审批不通过或部分发货时可继续发货",
      icon: "none",
    });
    return;
  }
  if (!ledgerItem?.id) return;
  showLoadingToast("加载中...");
  try {
    const res = await productList({ salesLedgerId: ledgerItem.id, type: 1 });
    const products = res.data || res.records || [];
    closeToast();
    if (!products.length) {
      uni.showToast({ title: "没有产品数据", icon: "none" });
      return;
    }
    const insufficient = products.filter(p => p?.approveStatus !== 1);
    if (insufficient.length) {
      const names = insufficient.slice(0, 3).map(productLabelForShip).join("、");
      uni.showToast({
        title: `存在库存不足产品:${names}${insufficient.length > 3 ? "…" : ""}`,
        icon: "none",
        duration: 2500,
      });
      return;
    }
    const unOutbound = products.filter(p => isProductStockStatusUnOutbound(p));
    if (unOutbound.length) {
      const names = unOutbound.slice(0, 3).map(productLabelForShip).join("、");
      uni.showToast({
        title: `存在未出库产品,不能发货:${names}${unOutbound.length > 3 ? "…" : ""}`,
        icon: "none",
        duration: 2500,
      });
      return;
    }
    const row = products.find(p => canShipProductRow(p));
    if (!row) {
      uni.showToast({
        title: "没有可发货的产品(待发货、审核拒绝或部分发货可继续)",
        icon: "none",
        duration: 2500,
      });
      return;
    }
    uni.setStorageSync("goOutData", JSON.stringify(row));
    uni.navigateTo({
      url: "/pages/sales/salesAccount/goOut",
    });
  } catch (e) {
    closeToast();
    uni.showToast({ title: "加载产品失败", icon: "none" });
  }
}