gaoluyang
8 天以前 57a496e7d0aa5630180e841f31d9c6b1215cc7a2
列表插槽列的时间也只展示年月日

- 新增 toDateOnlyVNode:递归截断插槽渲染出的 vnode 文本里的日期时间
- main.js 包装 ElTableColumn.setup,列插槽(含 PIMTable 插槽列)统一兜底,
不再出现 2026-11-02 16:02:23 这类带时分秒的显示
- 计划模板卡片、安全动态列表改为 formatDateOnly

Co-Authored-By: Claude Code <noreply@anthropic.com>
已修改4个文件
88 ■■■■■ 文件已修改
src/main.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dateDisplay.js 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/planTemplate/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/safetyDashboard/components/center-top.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js
@@ -58,7 +58,7 @@
import PageHeader from "@/components/PageHeader/index.vue";
import { getToken } from "@/utils/auth";
import { toDateOnly } from "@/utils/dateDisplay";
import { toDateOnly, toDateOnlyVNode } from "@/utils/dateDisplay";
import {
  calculateTaxExclusiveTotalPrice,
  summarizeTable,
@@ -133,4 +133,31 @@
  }
}
// 列表时间统一只展示年月日(插槽列):<template #default> 里的内容不走列 formatter,
// 这里把 el-table-column 的所有插槽输出过一遍,纯文本中的日期时间只保留年月日。
const tableColumn = app._context.components.ElTableColumn;
if (
  tableColumn &&
  typeof tableColumn.setup === "function" &&
  !tableColumn.__dateOnlyPatched
) {
  const originalSetup = tableColumn.setup;
  tableColumn.setup = function (props, ctx) {
    try {
      const slots = ctx.slots;
      if (slots) {
        Object.keys(slots).forEach((name) => {
          const original = slots[name];
          if (typeof original !== "function") return;
          slots[name] = (scope) => toDateOnlyVNode(original(scope));
        });
      }
    } catch (e) {
      // 插槽只读时退回列 formatter 兜底,不影响表格渲染
    }
    return originalSetup(props, ctx);
  };
  tableColumn.__dateOnlyPatched = true;
}
app.mount("#app");
src/utils/dateDisplay.js
@@ -2,6 +2,8 @@
 * 列表展示用的日期处理:带时分秒的日期时间只保留年月日,
 * 本来就是日期、时间或其它内容的值原样返回。
 */
import { cloneVNode } from "vue";
const DATE_TIME_PATTERN =
  /^(\d{4})[-/年](\d{1,2})[-/月](\d{1,2})日?[ T]\d{1,2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/;
@@ -30,3 +32,56 @@
  return `${matched[1]}-${pad2(matched[2])}-${pad2(matched[3])}`;
}
/**
 * 递归处理插槽渲染出的 vnode:把其中的纯文本按 toDateOnly 截断。
 * 表格列的插槽内容(<template #default>)不会走列 formatter,
 * 这里在 vnode 层统一兜底,列表里就不会再冒出时分秒。
 */
export function toDateOnlyVNode(node) {
  if (node == null || typeof node === "number" || typeof node === "boolean") {
    return node;
  }
  if (Array.isArray(node)) {
    return mapIfChanged(node, toDateOnlyVNode);
  }
  if (typeof node === "string") {
    return toDateOnly(node);
  }
  // vnode:文本子节点
  const children = node.children;
  if (children == null) return node;
  if (typeof children === "string") {
    const next = toDateOnly(children);
    return next === children ? node : withChildren(node, next);
  }
  if (Array.isArray(children)) {
    const next = mapIfChanged(children, toDateOnlyVNode);
    return next === children ? node : withChildren(node, next);
  }
  // 组件插槽对象等其它形态不处理
  return node;
}
// cloneVNode 的第二个参数只合并到 props,children 要单独赋值
function withChildren(vnode, children) {
  const cloned = cloneVNode(vnode);
  cloned.children = children;
  return cloned;
}
function mapIfChanged(list, mapper) {
  let changed = false;
  const mapped = list.map((item) => {
    const next = mapper(item);
    if (next !== item) changed = true;
    return next;
  });
  return changed ? mapped : list;
}
src/views/collaborativeApproval/planTemplate/index.vue
@@ -144,7 +144,7 @@
              <div class="plan-meta">
                <div class="meta-item">
                  <el-icon><Calendar /></el-icon>
                  <span>{{ plan.startDate }} - {{ plan.endDate }}</span>
                  <span>{{ formatDateOnly(plan.startDate) }} - {{ formatDateOnly(plan.endDate) }}</span>
                </div>
                <div class="meta-item">
                  <el-icon><User /></el-icon>
src/views/reportAnalysis/safetyDashboard/components/center-top.vue
@@ -59,7 +59,7 @@
            </div>
            <div class="event-meta">
              <span>{{ item.location || '—' }}</span>
              <span>{{ item.eventTime }}</span>
              <span>{{ formatDateOnly(item.eventTime) }}</span>
            </div>
          </li>
        </ul>