Bläddra i källkod

fix(收款订单页): 列表去掉「回调」列、详情去掉「回调轨迹」,EXPIRED 显示为「失败」

用户裁定(2026-10-05,仅显示层,后端一律不动):
- 订单列表**不显示**「回调」列;详情抽屉「回调轨迹」整块下线。
  后端全保留:notify-logs 接口、pay_lsy_notify_log 表、通知重试、以及 2026-09-30
  「轨迹不显示原文」的收口(rawBody @JsonIgnore)—— 要恢复只动这一页。
- EXPIRED 状态标签「已过期」→「失败」(值不变)。与旁边 FAIL=「支付失败」并存是
  **按裁定执行**,不是笔误;同一文案同步到收银台页结果屏(cashier/index.vue)。

顺带收缩:openDetail 从三条请求变两条(不再拉 notify-logs);
PROCESS_LABEL / VERIFY_LABEL / tradeTypeLabel / processLabel / verifyLabel /
isProcessAlert / notifyLogs ref 一并删除;宽度 180 与「不引入 dayjs」的注释
按现存的两处时间列改写。

验证:pnpm ts:check 与改动前逐字节相同(289 条基线,exit 2);本提交两文件与
上一条提交的两个前端文件同一批注入变异体(`const __probe_num: number = "not-a-number"`),
tsc 差分在四个注入行各读出一条新 error TS2322,还原后 sha256 逐一 OK;
全量 mvn test 1037 绿(本提交无 Java 改动)。
alphaH 1 vecka sedan
förälder
incheckning
b13f2eeb2d

+ 3 - 1
frontend/src/views/module_payment/collection/cashier/index.vue

@@ -165,7 +165,9 @@ const RESULT: Record<string, { title: string; tone: string; icon: string; detail
   FAIL: { title: "未收到款", tone: "bad", icon: "✕", detail: "这一笔没有收到钱,可以重新发起" },
   CANCELED: { title: "已撤销", tone: "muted", icon: "—" },
   CLOSED: { title: "已关闭", tone: "muted", icon: "—" },
-  EXPIRED: { title: "已过期", tone: "muted", icon: "—", detail: "二维码超时未付款,这一笔已自动结束" },
+  // ★ 2026-10-05 用户裁定:EXPIRED 显示成「失败」(值不变,只改显示文案)——
+  //   与订单页同一裁定(那边是 STATUS_OPTIONS 里那一行)。
+  EXPIRED: { title: "失败", tone: "muted", icon: "—", detail: "二维码超时未付款,这一笔已自动结束" },
   PARTIAL_REFUNDED: { title: "已部分退款", tone: "muted", icon: "—" },
   REFUNDED: { title: "已全额退款", tone: "muted", icon: "—" },
 };

+ 22 - 105
frontend/src/views/module_payment/collection/order/index.vue

@@ -140,15 +140,11 @@
           min-width="200"
           show-overflow-tooltip
         />
-        <el-table-column label="回调" width="100">
-          <template #default="{ row }">
-            <el-tag v-if="row.notify_status === 'SUCCESS'" type="success" size="small">已送达</el-tag>
-            <el-tag v-else-if="row.notify_status === 'FAIL'" type="danger" size="small">
-              失败({{ row.notify_count }})
-            </el-tag>
-            <el-tag v-else type="info" size="small">待推送</el-tag>
-          </template>
-        </el-table-column>
+        <!--
+          ★ 2026-10-05 用户裁定:列表**不显示**「回调」列(详情里的「回调轨迹」整块同时下线)。
+            别顺手补回来 —— 后端的通知重试、`notify-logs` 接口与 pay_lsy_notify_log 表都还在,
+            要恢复是这一页一处的事。
+        -->
         <el-table-column prop="created_time" label="创建时间" width="180" />
         <el-table-column label="操作" width="170" fixed="right">
           <template #default="{ row }">
@@ -256,13 +252,14 @@
             <template #default="{ row }">{{ row.refund_no || "-" }}</template>
           </el-table-column>
           <!--
-            宽度 180 与同抽屉「回调轨迹」的时间列、以及上方订单列表的「创建时间」一致 ——
-            这三处显示的是同一种值,宽度不该各写各的。
+            宽度 180 与上方订单列表的「创建时间」一致 —— 两处显示的是同一种值,
+            宽度不该各写各的。
             ★ 值的形态是**实测**的,不是估的:HTTP 层实收
               `2026-09-29T11:04:13.007374+08:00`(**微秒** 6 位,共 32 字符)。
               按「毫秒 3 位」估会少算 3 个字符、窄列里静默截断。
               所以这里挂 show-overflow-tooltip:截断至少能悬停看全,不是无声丢字。
-            本页**不**引入 dayjs 格式化 —— 同一个抽屉里两节时间长得不一样,比原样显示更难读。
+            本页**不**引入 dayjs 格式化 —— 列表的「创建时间」与这里的「完成时间」都按后端给的
+            原串显示,格式化只做一处会让同一页出现两种时间长相。
           -->
           <el-table-column label="完成时间" width="180" show-overflow-tooltip>
             <template #default="{ row }">{{ row.finish_time || "-" }}</template>
@@ -270,39 +267,12 @@
         </el-table>
       </template>
 
-      <h4 style="margin-top: 20px">回调轨迹</h4>
-      <el-table :data="notifyLogs" border size="small">
-        <el-table-column prop="created_time" label="时间" width="180" />
-        <el-table-column prop="trade_type" label="类型" width="70">
-          <template #default="{ row }">{{ tradeTypeLabel(row.trade_type) }}</template>
-        </el-table-column>
-        <el-table-column prop="verify_status" label="验签" width="80">
-          <template #default="{ row }">
-            <el-tag :type="row.verify_status === 'SUCCESS' ? 'success' : 'danger'" size="small">
-              {{ verifyLabel(row.verify_status) }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column prop="process_status" label="处理" width="130">
-          <template #default="{ row }">
-            <el-tag v-if="isProcessAlert(row.process_status)" type="danger" size="small">
-              {{ processLabel(row.process_status) }}
-            </el-tag>
-            <span v-else>{{ processLabel(row.process_status) }}</span>
-          </template>
-        </el-table-column>
-        <!--
-          ★ 这里**故意没有**「原文」这一列 —— 用户 2026-09-30 裁定:回调轨迹不显示原文。
-            别顺手补回来:那一列铺出来的是**上游自己的字段名**
-            (`alipay_order_no` / `trade_date` / `actual_money` …)和一份 JSON,
-            属上游信息,不该到使用者眼前。
-          ★ 后端也堵死了同一条路(`LsyNotifyLogEntity.rawBody` 挂 `@JsonIgnore`)——
-            只删这一列是不够的,报文照样随响应体进浏览器,F12 一看就有。
-            要查原话就查库:`pay_lsy_notify_log.raw_body`(已脱敏、已截断)。
-          ★ 这一列原本要回答的问题(「这次回调到底成没成、为什么没成」)由上面三列回答:
-            类型 / 验签 / 处理 —— 它们就是那份 JSON 的中文摘要,且不暴露上游字段。
-        -->
-      </el-table>
+      <!--
+        ★ 2026-10-05 用户裁定:「回调轨迹」整块**下线**(列表的「回调」列同时下线)。
+          别顺手补回来。后端全在:`GET .../notify-logs` 接口、`pay_lsy_notify_log` 表、
+          以及 2026-09-30 那次「轨迹不显示原文」的收口(`rawBody` 挂 `@JsonIgnore`)都没动,
+          要恢复是这一页一处的事。
+      -->
 
       <!--
         抽屉里也放一个退款入口:翻到这儿的人往往正是**看完明细才决定退**的,
@@ -464,7 +434,6 @@ import { Loading } from "@element-plus/icons-vue";
 import {
   getLsyOrderPage,
   getLsyOrderDetail,
-  getLsyNotifyLogs,
   getLsyOrderRefunds,
   getLsyRefundDetail,
   refundLsyOrder,
@@ -508,7 +477,10 @@ const STATUS_OPTIONS = [
   { label: "支付失败", value: "FAIL" },
   { label: "已撤销", value: "CANCELED" },
   { label: "已关单", value: "CLOSED" },
-  { label: "已过期", value: "EXPIRED" },
+  // ★ 2026-10-05 用户裁定:EXPIRED 显示成「失败」(值不变,只改显示文案)。
+  //   旁边还有一条 FAIL=「支付失败」,两个标签并存是**按裁定执行**,不是笔误 ——
+  //   别自作主张把它改成「支付失败」或合并两行。
+  { label: "失败", value: "EXPIRED" },
   { label: "部分退款", value: "PARTIAL_REFUNDED" },
   { label: "已全额退款", value: "REFUNDED" },
 ];
@@ -519,32 +491,6 @@ const SCENE_LABEL: Record<string, string> = {
   H5: "H5",
 };
 
-/**
- * `pay_lsy_notify_log.process_status` 的取值 → 中文。
- *
- * ★ 这 10 个词是**从 `LsyNotifyService` 全部 `logNotify(...)` 调用点逐个点出来的**,
- *   并与库里的列注释(`db/lsy-notify-process-status-comment.sql` 那句 10 词表)对过,
- *   两边一致。后端加词时这里必须同步 —— 漏一个就会让那一行退回显示英文(靠 `|| v` 兜底),
- *   不报错、只是看不懂。
- */
-const PROCESS_LABEL: Record<string, string> = {
-  RECEIVED: "已收到",
-  APPLIED: "已回写",
-  DUPLICATE: "重复回调",
-  REJECTED: "验签失败",
-  ORDER_NOT_FOUND: "订单不存在",
-  REFUND_NOT_FOUND: "退款单不存在",
-  UNKNOWN_RESULT_CODE: "未知结果码",
-  LATE_PAYMENT_AFTER_TERMINAL: "终态后到账",
-  LATE_REFUND_AFTER_TERMINAL: "终态后退款",
-  HELD_FOR_RECONCILE: "扣住待对账",
-};
-
-const VERIFY_LABEL: Record<string, string> = {
-  SUCCESS: "通过",
-  FAIL: "失败",
-};
-
 /**
  * `LsyRefundStatus` 的四个取值 → 中文。**逐个取自枚举源码**(`CREATED / REFUNDING / SUCCESS / FAIL`,
  * 见 `LsyRefundStatus.java` 的枚举体),措辞与退款列表页 `collection/refund/index.vue` 的下拉一致 ——
@@ -586,7 +532,6 @@ const total = ref(0);
 const loading = ref(false);
 const detailVisible = ref(false);
 const detail = ref<any>(null);
-const notifyLogs = ref<any[]>([]);
 const refunds = ref<any[]>([]);
 /** 正在退款的那一单的**订单号**(不是 id)—— 列表行与抽屉用的是同一个键,两处的转圈才对得上。 */
 const refundingNo = ref<string | undefined>();
@@ -920,15 +865,6 @@ function statusTagType(v: string) {
   if (v === "REFUNDED" || v === "PARTIAL_REFUNDED") return "info";
   return "info";
 }
-function tradeTypeLabel(v: string) {
-  return ({ "0": "退款", "1": "交易", "2": "云订单关单" } as Record<string, string>)[v] || v || "-";
-}
-function processLabel(v: string) {
-  return PROCESS_LABEL[v] || v || "-";
-}
-function verifyLabel(v: string) {
-  return VERIFY_LABEL[v] || v || "-";
-}
 function refundStatusLabel(v: string) {
   return REFUND_STATUS_LABEL[v] || v || "-";
 }
@@ -938,23 +874,6 @@ function refundTagType(v: string) {
   if (v === "FAIL") return "danger";
   return "warning";
 }
-/**
- * 「处理」列里**需要人看一眼**的四类,标红。
- *
- * ★ `DUPLICATE` **不在**其中,这是刻意的:良性重复回调是幂等正常工作的证据,
- *   标红会把真正的告警淹掉。后端 `LsyNotifyService` 特意把「良性重复」与
- *   「账实不符」(LATE_*_AFTER_TERMINAL)拆成两个词,就是为了这处能分开看;
- *   在界面上把它们渲染成一模一样的黑字,等于把那处区分又抹掉了。
- */
-function isProcessAlert(v: string) {
-  return (
-    v === "LATE_PAYMENT_AFTER_TERMINAL" ||
-    v === "LATE_REFUND_AFTER_TERMINAL" ||
-    v === "HELD_FOR_RECONCILE" ||
-    v === "UNKNOWN_RESULT_CODE"
-  );
-}
-
 async function loadData() {
   loading.value = true;
   try {
@@ -984,11 +903,10 @@ function handleReset() {
 }
 
 async function openDetail(row: any) {
-  // ★ 先清空、再拉取:抽屉实例是**被复用**的,三条请求里任何一条抛异常,
+  // ★ 先清空、再拉取:抽屉实例是**被复用**的,两条请求里任何一条抛异常,
   //   上一次的内容就会原样留在界面上 —— 而它看起来完全像「这一笔订单的数据」。
-  //   (清空放在最前,所以下面三条赋值不再需要各自的兜底 || []。)
+  //   (清空放在最前,所以下面两条赋值不再需要各自的兜底 || []。)
   detail.value = null;
-  notifyLogs.value = [];
   refunds.value = [];
 
   const res: any = await getLsyOrderDetail(row.out_trade_no);
@@ -997,8 +915,7 @@ async function openDetail(row: any) {
   //   写成 res.data 会把信封塞给 el-descriptions,字段全部渲染成空 —— 页面不报错,
   //   只是「什么都没显示」,是那种查半天查不出来的假成功。
   detail.value = res.data.data;
-  const logs: any = await getLsyNotifyLogs(row.out_trade_no);
-  notifyLogs.value = logs.data.data || [];
+  // 2026-10-05 起不再拉 notify-logs —— 回调轨迹整块已下线,拉了也没人显示。
   const rfs: any = await getLsyOrderRefunds(row.out_trade_no);
   refunds.value = rfs.data.data || [];
   detailVisible.value = true;