From 523365960513f297024a419f94b2b42eccd9456f Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期四, 09 四月 2026 11:21:41 +0800
Subject: [PATCH] #

---
 rsf-design/src/api/asn-order-log.js                                                              |    7 
 rsf-design/src/views/dashboard/console/index.vue                                                 |  279 +++++--------
 rsf-server/src/main/resources/mapper/manager/AsnOrderMapper.xml                                  |   14 
 rsf-design/src/views/orders/asn-order-log/index.vue                                              |  200 +++++++--
 rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageResult.java              |   43 ++
 rsf-design/package.json                                                                          |    1 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/AsnOrderMapper.java               |    9 
 rsf-design/src/plugins/iconify.collections.js                                                    |   51 +
 rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java            |  195 +++++++++
 rsf-design/scripts/build-local-iconify-collections.mjs                                           |    2 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderLogController.java    |   30 +
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java    |  140 +++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderLog.java                  |   31 -
 rsf-design/pnpm-lock.yaml                                                                        |   10 
 rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageParam.java               |   68 +++
 rsf-design/src/views/orders/asn-order-log/asnOrderLogPage.helpers.js                             |   20 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/AsnOrderPressureSchedules.java |  131 ++---
 17 files changed, 855 insertions(+), 376 deletions(-)

diff --git a/rsf-design/package.json b/rsf-design/package.json
index 50c1f4f..d93dcac 100644
--- a/rsf-design/package.json
+++ b/rsf-design/package.json
@@ -26,6 +26,7 @@
     "@iconify-json/ix": "^1.2.11",
     "@iconify-json/line-md": "^1.2.16",
     "@iconify-json/ri": "^1.2.10",
+    "@iconify-json/solar": "^1.2.5",
     "@iconify-json/svg-spinners": "^1.2.4",
     "@iconify-json/system-uicons": "^1.2.4",
     "@iconify-json/vaadin": "^1.2.1",
diff --git a/rsf-design/pnpm-lock.yaml b/rsf-design/pnpm-lock.yaml
index f72aaef..6c53174 100644
--- a/rsf-design/pnpm-lock.yaml
+++ b/rsf-design/pnpm-lock.yaml
@@ -29,6 +29,9 @@
       '@iconify-json/ri':
         specifier: ^1.2.10
         version: 1.2.10
+      '@iconify-json/solar':
+        specifier: ^1.2.5
+        version: 1.2.5
       '@iconify-json/svg-spinners':
         specifier: ^1.2.4
         version: 1.2.4
@@ -628,6 +631,9 @@
 
   '@iconify-json/ri@1.2.10':
     resolution: {integrity: sha512-WWMhoncVVM+Xmu9T5fgu2lhYRrKTEWhKk3Com0KiM111EeEsRLiASjpsFKnC/SrB6covhUp95r2mH8tGxhgd5Q==}
+
+  '@iconify-json/solar@1.2.5':
+    resolution: {integrity: sha512-WMAiNwchU8zhfrySww6KQBRIBbsQ6SvgIu2yA+CHGyMima/0KQwT5MXogrZPJGoQF+1Ye3Qj6K+1CiyNn3YkoA==}
 
   '@iconify-json/svg-spinners@1.2.4':
     resolution: {integrity: sha512-ayn0pogFPwJA1WFZpDnoq9/hjDxN+keeCMyThaX4d3gSJ3y0mdKUxIA/b1YXWGtY9wVtZmxwcvOIeEieG4+JNg==}
@@ -3537,6 +3543,10 @@
     dependencies:
       '@iconify/types': 2.0.0
 
+  '@iconify-json/solar@1.2.5':
+    dependencies:
+      '@iconify/types': 2.0.0
+
   '@iconify-json/svg-spinners@1.2.4':
     dependencies:
       '@iconify/types': 2.0.0
diff --git a/rsf-design/scripts/build-local-iconify-collections.mjs b/rsf-design/scripts/build-local-iconify-collections.mjs
index ca02615..e5fbd27 100644
--- a/rsf-design/scripts/build-local-iconify-collections.mjs
+++ b/rsf-design/scripts/build-local-iconify-collections.mjs
@@ -9,6 +9,7 @@
 import { icons as ixIcons } from '@iconify-json/ix'
 import { icons as lineMdIcons } from '@iconify-json/line-md'
 import { icons as remixIcons } from '@iconify-json/ri'
+import { icons as solarIcons } from '@iconify-json/solar'
 import { icons as svgSpinnersIcons } from '@iconify-json/svg-spinners'
 import { icons as systemUiconsIcons } from '@iconify-json/system-uicons'
 import { icons as vaadinIcons } from '@iconify-json/vaadin'
@@ -25,6 +26,7 @@
   ix: ixIcons,
   'line-md': lineMdIcons,
   ri: remixIcons,
+  solar: solarIcons,
   'svg-spinners': svgSpinnersIcons,
   'system-uicons': systemUiconsIcons,
   vaadin: vaadinIcons
diff --git a/rsf-design/src/api/asn-order-log.js b/rsf-design/src/api/asn-order-log.js
index e0d5bff..1fec1e2 100644
--- a/rsf-design/src/api/asn-order-log.js
+++ b/rsf-design/src/api/asn-order-log.js
@@ -1,4 +1,5 @@
 import request from '@/utils/http'
+import { buildAsnOrderLogPageQueryParams } from '@/views/orders/asn-order-log/asnOrderLogPage.helpers'
 
 function normalizeText(value) {
   return typeof value === 'string' ? value.trim() : value
@@ -31,11 +32,7 @@
 }
 
 export function buildAsnOrderLogPageParams(params = {}) {
-  return {
-    current: params.current || 1,
-    pageSize: params.pageSize || params.size || 20,
-    ...filterParams(params, ['current', 'pageSize', 'size'])
-  }
+  return buildAsnOrderLogPageQueryParams(params)
 }
 
 export function buildAsnOrderItemLogPageParams(params = {}) {
diff --git a/rsf-design/src/plugins/iconify.collections.js b/rsf-design/src/plugins/iconify.collections.js
index d729dbb..a8795f90 100644
--- a/rsf-design/src/plugins/iconify.collections.js
+++ b/rsf-design/src/plugins/iconify.collections.js
@@ -112,8 +112,11 @@
       'book-2-line': {
         body: '<path fill="currentColor" d="M21 18H6a1 1 0 1 0 0 2h15v2H6a3 3 0 0 1-3-3V4a2 2 0 0 1 2-2h16zM5 16.05q.243-.05.5-.05H19V4H5zM16 9H8V7h8z"/>'
       },
-      'chat-1-line': {
-        body: '<path fill="currentColor" d="M10 3h4a8 8 0 1 1 0 16v3.5c-5-2-12-5-12-11.5a8 8 0 0 1 8-8m2 14h2a6 6 0 0 0 0-12h-4a6 6 0 0 0-6 6c0 3.61 2.462 5.966 8 8.48z"/>'
+      'chat-3-line': {
+        body: '<path fill="currentColor" d="M7.291 20.824L2 22l1.176-5.291A9.96 9.96 0 0 1 2 12C2 6.477 6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10a9.96 9.96 0 0 1-4.709-1.176m.29-2.113l.653.35A7.96 7.96 0 0 0 12 20a8 8 0 1 0-8-8c0 1.335.325 2.617.94 3.766l.349.653l-.655 2.947z"/>'
+      },
+      'chat-history-line': {
+        body: '<path fill="currentColor" d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10a9.96 9.96 0 0 1-4.708-1.175L2 22l1.176-5.29A9.96 9.96 0 0 1 2 12C2 6.477 6.477 2 12 2m0 2a8 8 0 0 0-8 8c0 1.335.326 2.618.94 3.766l.35.654l-.656 2.946l2.948-.654l.653.349A7.96 7.96 0 0 0 12 20a8 8 0 1 0 0-16m1 3v5h4v2h-6V7z"/>'
       },
       'check-fill': {
         body: '<path fill="currentColor" d="m10 15.17l9.192-9.191l1.414 1.414L10 17.999l-6.364-6.364l1.414-1.414z"/>'
@@ -136,6 +139,9 @@
       'close-large-fill': {
         body: '<path fill="currentColor" d="M10.586 12L2.793 4.207l1.414-1.414L12 10.586l7.793-7.793l1.414 1.414L13.414 12l7.793 7.793l-1.414 1.414L12 13.414l-7.793 7.793l-1.414-1.414z"/>'
       },
+      'close-line': {
+        body: '<path fill="currentColor" d="m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z"/>'
+      },
       'coin-line': {
         body: '<path fill="currentColor" d="M12.005 4.003c6.075 0 11 2.686 11 6v4c0 3.314-4.925 6-11 6c-5.967 0-10.824-2.591-10.995-5.823l-.005-.177v-4c0-3.314 4.925-6 11-6m0 12c-3.72 0-7.01-1.008-9-2.55v.55c0 1.882 3.883 4 9 4c5.01 0 8.838-2.03 8.995-3.882l.005-.118l.001-.55c-1.99 1.542-5.28 2.55-9.001 2.55m0-10c-5.117 0-9 2.118-9 4s3.883 4 9 4s9-2.118 9-4s-3.883-4-9-4"/>'
       },
@@ -145,6 +151,9 @@
       'computer-line': {
         body: '<path fill="currentColor" d="M4 16h16V5H4zm9 2v2h4v2H7v-2h4v-2H2.992A1 1 0 0 1 2 16.992V4.008C2 3.451 2.455 3 2.992 3h18.016c.548 0 .992.449.992 1.007v12.985c0 .557-.455 1.008-.992 1.008z"/>'
       },
+      'cpu-line': {
+        body: '<path fill="currentColor" d="M6 18h12V6H6zm8 2h-4v2H8v-2H5a1 1 0 0 1-1-1v-3H2v-2h2v-4H2V8h2V5a1 1 0 0 1 1-1h3V2h2v2h4V2h2v2h3a1 1 0 0 1 1 1v3h2v2h-2v4h2v2h-2v3a1 1 0 0 1-1 1h-3v2h-2zM8 8h8v8H8z"/>'
+      },
       'delete-bin-4-line': {
         body: '<path fill="currentColor" d="M20 7v14a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7H2V5h20v2zM6 7v13h12V7zm1-5h10v2H7zm4 8h2v7h-2z"/>'
       },
@@ -153,6 +162,9 @@
       },
       'delete-bin-6-line': {
         body: '<path fill="currentColor" d="M7 4V2h10v2h5v2h-2v15a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6H2V4zM6 6v14h12V6zm3 3h2v8H9zm4 0h2v8h-2z"/>'
+      },
+      'delete-bin-line': {
+        body: '<path fill="currentColor" d="M17 6h5v2h-2v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V8H2V6h5V3a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1zm1 2H6v12h12zm-9 3h2v6H9zm4 0h2v6h-2zM9 4v2h6V4z"/>'
       },
       'drag-move-2-fill': {
         body: '<path fill="currentColor" d="M18 11V8l4 4l-4 4v-3h-5v5h3l-4 4l-4-4h3v-5H6v3l-4-4l4-4v3h5V6H8l4-4l4 4h-3v5z"/>'
@@ -165,6 +177,9 @@
       },
       'edit-2-line': {
         body: '<path fill="currentColor" d="M5 18.89h1.414l9.314-9.314l-1.414-1.414L5 17.476zm16 2H3v-4.243L16.435 3.212a1 1 0 0 1 1.414 0l2.829 2.829a1 1 0 0 1 0 1.414L9.243 18.89H21zM15.728 6.748l1.414 1.414l1.414-1.414l-1.414-1.414z"/>'
+      },
+      'edit-line': {
+        body: '<path fill="currentColor" d="M6.414 15.89L16.556 5.748l-1.414-1.414L5 14.476v1.414zm.829 2H3v-4.243L14.435 2.212a1 1 0 0 1 1.414 0l2.829 2.829a1 1 0 0 1 0 1.414zM3 19.89h18v2H3z"/>'
       },
       'error-warning-line': {
         body: '<path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10m0-2a8 8 0 1 0 0-16a8 8 0 0 0 0 16m-1-5h2v2h-2zm0-8h2v6h-2z"/>'
@@ -193,12 +208,6 @@
       'fullscreen-line': {
         body: '<path fill="currentColor" d="M8 3v2H4v4H2V3zM2 21v-6h2v4h4v2zm20 0h-6v-2h4v-4h2zm0-12h-2V5h-4V3h6z"/>'
       },
-      'function-line': {
-        body: '<path fill="currentColor" d="M3 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1zm0 10a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1zM13 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1zm0 10a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1zm2-9v4h4V5zm0 10v4h4v-4zM5 5v4h4V5zm0 10v4h4v-4z"/>'
-      },
-      'github-line': {
-        body: '<path fill="currentColor" d="M5.884 18.653c-.3-.2-.558-.455-.86-.816a51 51 0 0 1-.466-.579c-.463-.575-.755-.841-1.056-.95a1 1 0 1 1 .675-1.882c.752.27 1.261.735 1.947 1.588c-.094-.117.34.427.433.539c.19.227.33.365.44.438c.204.137.588.196 1.15.14c.024-.382.094-.753.202-1.095c-2.968-.726-4.648-2.64-4.648-6.396c0-1.24.37-2.356 1.058-3.292c-.218-.894-.185-1.975.302-3.192a1 1 0 0 1 .63-.582c.081-.024.127-.035.208-.047c.803-.124 1.937.17 3.415 1.096a11.7 11.7 0 0 1 2.687-.308c.912 0 1.819.104 2.684.308c1.477-.933 2.614-1.227 3.422-1.096q.128.02.218.05a1 1 0 0 1 .616.58c.487 1.216.52 2.296.302 3.19c.691.936 1.058 2.045 1.058 3.293c0 3.757-1.674 5.665-4.642 6.392c.125.415.19.878.19 1.38c0 .665-.002 1.299-.007 2.01c0 .19-.002.394-.005.706a1 1 0 0 1-.018 1.958c-1.14.227-1.984-.532-1.984-1.525l.002-.447l.005-.705c.005-.707.008-1.337.008-1.997c0-.697-.184-1.152-.426-1.361c-.661-.57-.326-1.654.541-1.751c2.966-.333 4.336-1.482 4.336-4.66c0-.955-.312-1.744-.913-2.404A1 1 0 0 1 17.2 6.19c.166-.414.236-.957.095-1.614l-.01.003c-.491.139-1.11.44-1.858.949a1 1 0 0 1-.833.135a9.6 9.6 0 0 0-2.592-.349c-.89 0-1.772.118-2.592.35a1 1 0 0 1-.829-.134c-.753-.507-1.374-.807-1.87-.947c-.143.653-.072 1.194.093 1.607a1 1 0 0 1-.189 1.045c-.597.655-.913 1.458-.913 2.404c0 3.172 1.371 4.328 4.322 4.66c.865.097 1.202 1.177.545 1.748c-.193.168-.43.732-.43 1.364v3.15c0 .985-.834 1.725-1.96 1.528a1 1 0 0 1-.04-1.962v-.99c-.91.061-1.661-.088-2.254-.485"/>'
-      },
       'group-line': {
         body: '<path fill="currentColor" d="M2 22a8 8 0 1 1 16 0h-2a6 6 0 0 0-12 0zm8-9c-3.315 0-6-2.685-6-6s2.685-6 6-6s6 2.685 6 6s-2.685 6-6 6m0-2c2.21 0 4-1.79 4-4s-1.79-4-4-4s-4 1.79-4 4s1.79 4 4 4m8.284 3.703A8 8 0 0 1 23 22h-2a6 6 0 0 0-3.537-5.473zm-.688-11.29A5.5 5.5 0 0 1 21 8.5a5.5 5.5 0 0 1-5 5.478v-2.013a3.5 3.5 0 0 0 1.041-6.609z"/>'
       },
@@ -226,8 +235,14 @@
       'line-chart-line': {
         body: '<path fill="currentColor" d="M5 3v16h16v2H3V3zm15.293 3.293l1.414 1.414L16 13.414l-3-2.999l-4.293 4.292l-1.414-1.414L13 7.586l3 2.999z"/>'
       },
+      'list-check-3': {
+        body: '<path fill="currentColor" d="M8 6v3H5V6zM3 4v7h7V4zm10 0h8v2h-8zm0 7h8v2h-8zm0 7h8v2h-8zm-2.293-1.793l-1.414-1.414L6 18.086l-1.793-1.793l-1.414 1.414L6 20.914z"/>'
+      },
       'lock-line': {
         body: '<path fill="currentColor" d="M19 10h1a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V11a1 1 0 0 1 1-1h1V9a7 7 0 0 1 14 0zM5 12v8h14v-8zm6 2h2v4h-2zm6-4V9A5 5 0 0 0 7 9v1z"/>'
+      },
+      'magic-line': {
+        body: '<path fill="currentColor" d="M15.199 9.944a2.6 2.6 0 0 1-.79-1.55l-.403-3.083l-2.731 1.486a2.6 2.6 0 0 1-1.719.272L6.5 6.5l.57 3.056a2.6 2.6 0 0 1-.273 1.72l-1.486 2.73l3.083.403a2.6 2.6 0 0 1 1.55.79l2.138 2.257l1.336-2.807a2.6 2.6 0 0 1 1.23-1.231l2.808-1.336zm.025 5.564l-2.213 4.65a.6.6 0 0 1-.977.155l-3.542-3.739a.6.6 0 0 0-.358-.182l-5.106-.668a.6.6 0 0 1-.45-.881l2.462-4.524a.6.6 0 0 0 .063-.396L4.16 4.86a.6.6 0 0 1 .7-.7l5.062.943a.6.6 0 0 0 .397-.063l4.523-2.46a.6.6 0 0 1 .882.448l.668 5.107a.6.6 0 0 0 .182.357l3.739 3.542a.6.6 0 0 1-.155.977l-4.65 2.213a.6.6 0 0 0-.284.284m.797 1.927l1.414-1.414l4.243 4.242l-1.415 1.415z"/>'
       },
       'mail-line': {
         body: '<path fill="currentColor" d="M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1m17 4.238l-7.928 7.1L4 7.216V19h16zM4.511 5l7.55 6.662L19.502 5z"/>'
@@ -253,8 +268,8 @@
       'more-2-fill': {
         body: '<path fill="currentColor" d="M12 3c-1.1 0-2 .9-2 2s.9 2 2 2s2-.9 2-2s-.9-2-2-2m0 14c-1.1 0-2 .9-2 2s.9 2 2 2s2-.9 2-2s-.9-2-2-2m0-7c-1.1 0-2 .9-2 2s.9 2 2 2s2-.9 2-2s-.9-2-2-2"/>'
       },
-      'notification-2-line': {
-        body: '<path fill="currentColor" d="M22 20H2v-2h1v-6.969C3 6.043 7.03 2 12 2s9 4.043 9 9.031V18h1zM5 18h14v-6.969C19 7.148 15.866 4 12 4s-7 3.148-7 7.031zm4.5 3h5a2.5 2.5 0 0 1-5 0"/>'
+      'node-tree': {
+        body: '<path fill="currentColor" d="M10 2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H8v2h5V9a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1v-1H8v6h5v-1a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1v-1H7a1 1 0 0 1-1-1V8H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1zm9 16h-4v2h4zm0-8h-4v2h4zM9 4H5v2h4z"/>'
       },
       'notification-3-line': {
         body: '<path fill="currentColor" d="M20 17h2v2H2v-2h2v-7a8 8 0 1 1 16 0zm-2 0v-7a6 6 0 0 0-12 0v7zm-9 4h6v2H9z"/>'
@@ -319,6 +334,9 @@
       'search-line': {
         body: '<path fill="currentColor" d="m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z"/>'
       },
+      'send-plane-2-line': {
+        body: '<path fill="currentColor" d="M3.5 1.346a.5.5 0 0 1 .241.061l18.462 10.155a.5.5 0 0 1 0 .876L3.741 22.592A.5.5 0 0 1 3 22.154V1.846a.5.5 0 0 1 .5-.5M5 4.382V11h5v2H5v6.617L18.85 12z"/>'
+      },
       'send-plane-line': {
         body: '<path fill="currentColor" d="m21.727 2.957l-5.454 19.086c-.15.529-.475.553-.717.07L11 13L1.923 9.37c-.51-.205-.503-.51.034-.689L21.043 2.32c.529-.176.832.12.684.638m-2.692 2.14L6.812 9.17l5.637 2.255l3.04 6.08z"/>'
       },
@@ -333,6 +351,9 @@
       },
       'shield-check-line': {
         body: '<path fill="currentColor" d="m12 1l8.217 1.826a1 1 0 0 1 .783.976v9.987a6 6 0 0 1-2.672 4.992L12 23l-6.328-4.219A6 6 0 0 1 3 13.79V3.802a1 1 0 0 1 .783-.976zm0 2.049L5 4.604v9.185a4 4 0 0 0 1.781 3.328L12 20.597l5.219-3.48A4 4 0 0 0 19 13.79V4.604zm4.452 5.173l1.415 1.414L11.503 16L7.26 11.757l1.414-1.414l2.828 2.828z"/>'
+      },
+      'sidebar-unfold-line': {
+        body: '<path fill="currentColor" d="M5 5h8v14H5zm14 14h-4V5h4zM4 3a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1zm7 9L7 8.5v7z"/>'
       },
       'smartphone-line': {
         body: '<path fill="currentColor" d="M7 4v16h10V4zM6 2h12a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1m6 15a1 1 0 1 1 0 2a1 1 0 0 1 0-2"/>'
@@ -389,6 +410,16 @@
     prefix: 'ri',
     width: 24
   },
+  solar: {
+    height: 24,
+    icons: {
+      'double-alt-arrow-right-linear': {
+        body: '<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="m11 19l6-7l-6-7"/><path d="m7 19l6-7l-6-7"/></g>'
+      }
+    },
+    prefix: 'solar',
+    width: 24
+  },
   vaadin: {
     icons: {
       'ctrl-a': {
diff --git a/rsf-design/src/views/dashboard/console/index.vue b/rsf-design/src/views/dashboard/console/index.vue
index 1a2f229..9bfbcc2 100644
--- a/rsf-design/src/views/dashboard/console/index.vue
+++ b/rsf-design/src/views/dashboard/console/index.vue
@@ -1,143 +1,114 @@
 <template>
-  <div class="art-full-height flex flex-col gap-6">
-    <section class="grid gap-6 md:grid-cols-2 xl:grid-cols-4" v-loading="sectionLoading.summary">
+  <div class="art-full-height flex flex-col gap-6 lg:min-h-0 lg:overflow-hidden lg:gap-2">
+    <section class="grid gap-3 md:grid-cols-2 lg:grid-cols-4 lg:shrink-0" v-loading="sectionLoading.summary">
       <div
         v-for="item in summaryCardItems"
         :key="item.title"
-        class="art-card flex items-start justify-between rounded-3xl px-7 py-6"
+        class="art-card flex items-start justify-between rounded-3xl px-4 py-4 lg:px-4 lg:py-3 xl:px-5"
       >
-        <div class="min-w-0 pr-6">
-          <p class="text-sm font-medium text-g-700">{{ item.title }}</p>
-          <ArtCountTo class="mt-3 block text-[2.3rem] font-semibold leading-none text-g-900" :target="item.count" :duration="1400" />
-          <div class="mt-4 flex items-center gap-2 text-sm">
-            <span :class="item.metaTone">{{ item.metaLabel }}</span>
-            <span class="text-g-500">{{ item.metaValue }}</span>
+        <div class="min-w-0 flex-1 pr-3">
+          <p class="truncate text-sm font-medium text-g-700 lg:text-[13px]">{{ item.title }}</p>
+          <ArtCountTo
+            class="mt-1 block truncate text-[1.95rem] font-semibold leading-none text-g-900 lg:text-[1.72rem] xl:text-[1.92rem]"
+            :target="item.count"
+            :duration="1400"
+          />
+          <div class="mt-1.5 flex items-center gap-1 text-xs lg:text-[12px] xl:text-sm">
+            <span :class="item.metaTone" class="shrink-0">{{ item.metaLabel }}</span>
+            <span class="truncate text-g-500">{{ item.metaValue }}</span>
           </div>
         </div>
-        <div class="flex size-13 shrink-0 items-center justify-center rounded-2xl" :class="item.iconBoxClass">
-          <ArtSvgIcon :icon="item.icon" class="text-2xl" :class="item.iconClass" />
+        <div class="flex size-10 shrink-0 items-center justify-center rounded-2xl lg:size-9 xl:size-11" :class="item.iconBoxClass">
+          <ArtSvgIcon :icon="item.icon" class="text-xl xl:text-2xl" :class="item.iconClass" />
         </div>
       </div>
     </section>
 
-    <section class="grid gap-6 xl:grid-cols-[1.35fr_1fr]">
-      <div class="art-card h-115 overflow-hidden p-6 box-border">
-        <div class="art-card-header">
-          <div class="title">
-            <h4>杩� 30 澶╁嚭鍏ュ簱瓒嬪娍</h4>
-            <p>鐪熷疄閾捐矾 <span class="text-success">宸叉帴閫�</span></p>
+    <section class="flex min-h-0 flex-1 flex-col gap-2">
+      <div class="grid min-h-0 flex-1 gap-2 lg:grid-cols-[1.35fr_1fr]">
+        <div class="art-card box-border flex h-full min-h-0 flex-col overflow-hidden p-4 lg:p-5">
+          <div class="art-card-header">
+            <div class="title">
+              <h4>杩� 30 澶╁嚭鍏ュ簱瓒嬪娍</h4>
+              <p>鐪熷疄閾捐矾 <span class="text-success">宸叉帴閫�</span></p>
+            </div>
+          </div>
+          <div class="mt-3 min-h-0 flex-1">
+            <ArtBarChart
+              height="100%"
+              :loading="sectionLoading.trend"
+              :data="trendChartSeries"
+              :x-axis-data="trendChartXAxisData"
+              :show-axis-line="false"
+              :show-legend="true"
+              :show-split-line="true"
+              legend-position="top"
+              bar-width="38%"
+            />
           </div>
         </div>
-        <div class="h-[calc(100%-4.5rem)]">
-          <ArtBarChart
-            height="22rem"
-            :loading="sectionLoading.trend"
-            :data="trendChartSeries"
-            :x-axis-data="trendChartXAxisData"
-            :show-axis-line="false"
-            :show-legend="true"
-            :show-split-line="true"
-            legend-position="top"
-            bar-width="38%"
-          />
-        </div>
-      </div>
 
-      <div class="art-card h-115 overflow-hidden p-6 box-border" v-loading="sectionLoading.locUsage">
-        <div class="art-card-header">
-          <div class="title">
-            <h4>搴撲綅浣跨敤鍒嗗竷</h4>
-            <p>{{ usageLegendCount }} 涓淮搴�</p>
+        <div class="art-card box-border flex h-full min-h-0 flex-col overflow-hidden p-4 lg:p-5" v-loading="sectionLoading.locUsage">
+          <div class="art-card-header">
+            <div class="title">
+              <h4>搴撲綅浣跨敤鍒嗗竷</h4>
+              <p>{{ usageLegendCount }} 涓淮搴�</p>
+            </div>
           </div>
-        </div>
-        <div class="grid h-[calc(100%-4.5rem)] gap-6 lg:grid-cols-[1fr_0.95fr] lg:items-center">
-          <ArtRingChart
-            height="21rem"
-            :data="locUsageList"
-            center-text="搴撲綅鍗犳瘮"
-            :show-legend="false"
-            :show-label="false"
-          />
-
-          <div class="space-y-1">
-            <div
-              v-for="item in usageLegend"
-              :key="item.name"
-              class="flex items-center justify-between border-b border-[var(--art-border-color)] py-4 last:border-b-0"
-            >
-              <div class="flex items-center gap-3">
-                <span class="size-2.5 rounded-full" :style="{ backgroundColor: item.color }"></span>
-                <span class="text-sm text-[var(--art-gray-900)]">{{ item.name }}</span>
-              </div>
-              <span class="text-sm font-medium text-[var(--art-gray-700)]">{{ item.value }}%</span>
+          <div class="mt-3 grid min-h-0 flex-1 gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(220px,0.92fr)] lg:items-center">
+            <div class="min-h-0 h-full">
+              <ArtRingChart
+                height="100%"
+                :data="locUsageList"
+                center-text="搴撲綅鍗犳瘮"
+                :show-legend="false"
+                :show-label="false"
+              />
             </div>
 
-            <ElEmpty v-if="!locUsageList.length" description="鏆傛棤搴撲綅浣跨敤鏁版嵁" :image-size="88" />
-          </div>
-        </div>
-      </div>
-    </section>
-
-    <section class="grid gap-6 xl:grid-cols-[0.95fr_1.05fr]">
-      <div class="art-card h-98 p-5 box-border" v-loading="sectionLoading.tasks">
-        <div class="art-card-header">
-          <div class="title">
-            <h4>鎵ц涓换鍔�</h4>
-            <p>{{ taskSubtitle }}</p>
-          </div>
-        </div>
-
-        <div class="mt-3 h-[calc(100%-3.75rem)] overflow-hidden">
-          <ElScrollbar>
-            <div
-              v-for="item in taskCardItems"
-              :key="`${item.time}-${item.title}`"
-              class="flex gap-4 border-b border-g-300 py-4 last:border-b-0"
-            >
-              <div class="flex flex-col items-center pt-1">
-                <span class="size-3 rounded-full bg-[var(--el-color-primary)]"></span>
-                <span class="mt-2 min-h-10 w-px bg-[var(--art-border-color)]"></span>
-              </div>
-              <div class="min-w-0 flex-1">
-                <p class="text-xs text-g-500">{{ item.time }}</p>
-                <div class="mt-2 flex items-center gap-2">
-                  <p class="truncate text-base font-medium text-[var(--art-gray-900)]">
-                    {{ item.title }}
-                  </p>
-                  <ElTag size="small" effect="light" :type="item.tagType">{{ item.tagText }}</ElTag>
+            <div class="min-h-0 overflow-hidden">
+              <div
+                v-for="item in usageLegend"
+                :key="item.name"
+                class="flex items-center justify-between gap-3 border-b border-[var(--art-border-color)] py-3 last:border-b-0"
+              >
+                <div class="flex items-center gap-3">
+                  <span class="size-2.5 rounded-full" :style="{ backgroundColor: item.color }"></span>
+                  <span class="truncate text-sm text-[var(--art-gray-900)]">{{ item.name }}</span>
                 </div>
-                <p class="mt-2 text-sm text-g-600">{{ item.subtitle }}</p>
+                <span class="text-sm font-medium text-[var(--art-gray-700)]">{{ item.value }}%</span>
               </div>
+
+              <ElEmpty v-if="!locUsageList.length" description="鏆傛棤搴撲綅浣跨敤鏁版嵁" :image-size="88" />
             </div>
-          </ElScrollbar>
+          </div>
         </div>
       </div>
 
-      <div class="art-card h-98 p-5 box-border" v-loading="sectionLoading.deadStock">
+      <div class="art-card box-border flex shrink-0 flex-col p-4 lg:p-3.5">
         <div class="art-card-header">
           <div class="title">
-            <h4>搴撳瓨鏈�杩戝姩鎬�</h4>
-            <p>{{ deadStockSubtitle }}</p>
+            <h4>蹇嵎璺宠浆</h4>
+            <p>蹇�熻繘鍏ヤ换鍔¢〉鍜屽簱瀛橀〉</p>
           </div>
         </div>
 
-        <div class="mt-3 h-[calc(100%-3.75rem)] overflow-hidden">
-          <ElScrollbar>
-            <div
-              v-for="item in stockCardItems"
-              :key="`${item.title}-${item.time}`"
-              class="flex items-center gap-4 border-b border-g-300 py-4 last:border-b-0"
-            >
-              <div class="size-12 rounded-2xl bg-[var(--el-color-primary-light-9)] flex-cc">
-                <ArtSvgIcon :icon="item.icon" class="text-xl text-[var(--el-color-primary)]" />
-              </div>
-              <div class="min-w-0 flex-1">
-                <p class="truncate text-base font-medium text-[var(--art-gray-900)]">{{ item.title }}</p>
-                <p class="mt-1 text-sm text-g-500">{{ item.status }}</p>
-              </div>
-              <div class="max-w-40 text-right text-sm text-g-500">{{ item.time }}</div>
+        <div class="mt-2.5 grid gap-2 md:grid-cols-2">
+          <button
+            v-for="item in quickLinkCards"
+            :key="item.title"
+            type="button"
+            class="flex items-start justify-between rounded-3xl border border-[var(--art-border-color)] bg-[var(--art-main-bg-color)] px-4 py-3 text-left transition hover:border-[var(--el-color-primary-light-5)] hover:bg-[var(--el-color-primary-light-9)]"
+            @click="navigateTo(item.path)"
+          >
+            <div class="min-w-0 pr-4">
+              <p class="text-base font-medium text-[var(--art-gray-900)]">{{ item.title }}</p>
+              <p class="mt-0.5 text-sm text-g-500">{{ item.description }}</p>
             </div>
-          </ElScrollbar>
+            <div class="flex size-11 shrink-0 items-center justify-center rounded-2xl" :class="item.iconBoxClass">
+              <ArtSvgIcon :icon="item.icon" class="text-xl" :class="item.iconClass" />
+            </div>
+          </button>
         </div>
       </div>
     </section>
@@ -145,44 +116,55 @@
 </template>
 
 <script setup>
+  import { useRouter } from 'vue-router'
   import { storeToRefs } from 'pinia'
   import { useUserStore } from '@/store/modules/user'
   import {
     fetchDashboardHeader,
     fetchDashboardTrend,
-    fetchDashboardDeadStock,
-    fetchDashboardLocUsage,
-    fetchDashboardTasks
+    fetchDashboardLocUsage
   } from '@/api/dashboard'
   import {
     EMPTY_SUMMARY,
-    buildDashboardDeadStockQuery,
-    buildDashboardTaskQuery,
     normalizeDashboardSummary,
     normalizeDashboardTrend,
-    normalizeDashboardTaskList,
     normalizeDashboardLocUsage,
-    normalizeDashboardDeadStockList,
     withDashboardRequestGuard
   } from './consolePage.helpers'
 
   defineOptions({ name: 'Console' })
 
+  const router = useRouter()
   const summary = ref({ ...EMPTY_SUMMARY })
   const trendModel = ref(normalizeDashboardTrend())
-  const taskList = ref([])
-  const deadStockList = ref([])
   const locUsageList = ref([])
   const sectionLoading = reactive({
     summary: false,
     trend: false,
-    deadStock: false,
-    locUsage: false,
-    tasks: false
+    locUsage: false
   })
 
   const userStore = useUserStore()
   const { getUserInfo } = storeToRefs(userStore)
+
+  const quickLinkCards = [
+    {
+      title: '浠诲姟椤�',
+      description: '鏌ョ湅鍜屽鐞嗕换鍔$鐞嗘暟鎹�',
+      path: '/manager/task',
+      icon: 'ri:task-line',
+      iconBoxClass: 'bg-[var(--el-color-primary-light-9)]',
+      iconClass: 'text-[var(--el-color-primary)]'
+    },
+    {
+      title: '搴撳瓨椤�',
+      description: '鏌ョ湅褰撳墠搴撳瓨涓庡簱瀛樻槑缁�',
+      path: '/manager/stock',
+      icon: 'ri:archive-stack-line',
+      iconBoxClass: 'bg-[rgba(20,222,186,0.14)]',
+      iconClass: 'text-[#14DEBA]'
+    }
+  ]
 
   const currentUser = computed(() => getUserInfo.value || {})
   const currentUserName = computed(() => {
@@ -291,8 +273,6 @@
   })
   const trendChartXAxisData = computed(() => trendDisplayModel.value.xAxisData)
   const trendChartSeries = computed(() => trendDisplayModel.value.series)
-  const taskSubtitle = computed(() => `鏈�杩� ${taskList.value.length} 鏉′换鍔″姩鎬乣)
-  const deadStockSubtitle = computed(() => `鏈�杩� ${deadStockList.value.length} 鏉″簱瀛樿褰昤)
   const usageLegendCount = computed(() => locUsageList.value.length)
   const usageLegend = computed(() => {
     const palette = ['#5B8FF9', '#5AD8A6', '#5D7092', '#F6BD16', '#E8684A', '#6DC8EC']
@@ -301,16 +281,6 @@
       color: palette[index % palette.length]
     }))
   })
-  const taskCardItems = computed(() =>
-    taskList.value.slice(0, 6).map((item) => ({
-      title: item.title,
-      time: item.time,
-      subtitle: item.status,
-      tagText: resolveTaskTagText(item.status),
-      tagType: resolveTaskTagType(item.class)
-    }))
-  )
-  const stockCardItems = computed(() => deadStockList.value.slice(0, 6))
 
   onMounted(() => {
     loadDashboard()
@@ -319,9 +289,7 @@
   function loadDashboard() {
     void loadSummarySection()
     void loadTrendSection()
-    void loadDeadStockSection()
     void loadLocUsageSection()
-    void loadTaskSection()
   }
 
   async function loadSummarySection() {
@@ -338,16 +306,6 @@
     sectionLoading.trend = false
   }
 
-  async function loadDeadStockSection() {
-    sectionLoading.deadStock = true
-    const payload = await withDashboardRequestGuard(
-      fetchDashboardDeadStock(buildDashboardDeadStockQuery()),
-      {}
-    )
-    deadStockList.value = normalizeDashboardDeadStockList(payload || {})
-    sectionLoading.deadStock = false
-  }
-
   async function loadLocUsageSection() {
     sectionLoading.locUsage = true
     const payload = await withDashboardRequestGuard(fetchDashboardLocUsage(), null)
@@ -355,29 +313,8 @@
     sectionLoading.locUsage = false
   }
 
-  async function loadTaskSection() {
-    sectionLoading.tasks = true
-    const payload = await withDashboardRequestGuard(
-      fetchDashboardTasks(buildDashboardTaskQuery()),
-      {}
-    )
-    taskList.value = normalizeDashboardTaskList(payload || {})
-    sectionLoading.tasks = false
-  }
-
-  function resolveTaskTagType(statusClass) {
-    const text = String(statusClass || '')
-    if (text.includes('emerald')) return 'success'
-    if (text.includes('rose')) return 'danger'
-    return 'primary'
-  }
-
-  function resolveTaskTagText(statusText) {
-    const text = String(statusText || '')
-      .replace(/\b\d+\./g, '')
-      .replace(/\s+/g, ' ')
-      .trim()
-    const parts = text.split('路').map((item) => item.trim()).filter(Boolean)
-    return parts[parts.length - 1] || '澶勭悊涓�'
+  function navigateTo(path) {
+    if (!path) return
+    router.push(path)
   }
 </script>
diff --git a/rsf-design/src/views/orders/asn-order-log/asnOrderLogPage.helpers.js b/rsf-design/src/views/orders/asn-order-log/asnOrderLogPage.helpers.js
index 49a1d8c..3c8a7d5 100644
--- a/rsf-design/src/views/orders/asn-order-log/asnOrderLogPage.helpers.js
+++ b/rsf-design/src/views/orders/asn-order-log/asnOrderLogPage.helpers.js
@@ -6,6 +6,7 @@
   density: 'compact',
   showSequence: true
 }
+export const DEFAULT_ASN_ORDER_LOG_PAGE_SIZE = 20
 
 const RLE_STATUS_META = {
   0: { text: '姝e父', type: 'info' },
@@ -33,6 +34,14 @@
   }
   const parsed = Number(value)
   return Number.isNaN(parsed) ? fallback : parsed
+}
+
+function normalizePositiveInteger(value, fallback) {
+  const parsed = normalizeNumber(value, fallback)
+  if (!Number.isInteger(parsed) || parsed <= 0) {
+    return fallback
+  }
+  return parsed
 }
 
 function normalizeDateText(value) {
@@ -119,8 +128,13 @@
 
 export function buildAsnOrderLogPageQueryParams(params = {}) {
   return {
-    current: params.current || 1,
-    pageSize: params.pageSize || params.size || 20,
+    pageSize: normalizePositiveInteger(
+      params.pageSize ?? params.size,
+      DEFAULT_ASN_ORDER_LOG_PAGE_SIZE
+    ),
+    ...(params.cursor !== undefined && params.cursor !== null && params.cursor !== ''
+      ? { cursor: normalizeNumber(params.cursor) }
+      : {}),
     ...buildAsnOrderLogSearchParams(params)
   }
 }
@@ -129,7 +143,7 @@
   return {
     logId: params.logId,
     current: params.current || 1,
-    pageSize: params.pageSize || params.size || 20
+    pageSize: params.pageSize || params.size || DEFAULT_ASN_ORDER_LOG_PAGE_SIZE
   }
 }
 
diff --git a/rsf-design/src/views/orders/asn-order-log/index.vue b/rsf-design/src/views/orders/asn-order-log/index.vue
index 968c48a..d1fc896 100644
--- a/rsf-design/src/views/orders/asn-order-log/index.vue
+++ b/rsf-design/src/views/orders/asn-order-log/index.vue
@@ -34,6 +34,7 @@
         :data="data"
         :columns="columns"
         :pagination="pagination"
+        :pagination-options="mainPaginationOptions"
         @selection-change="handleSelectionChange"
         @pagination:size-change="handleSizeChange"
         @pagination:current-change="handleCurrentChange"
@@ -59,20 +60,20 @@
   import { computed, onMounted, reactive, ref } from 'vue'
   import { ElMessage } from 'element-plus'
   import { useUserStore } from '@/store/modules/user'
-  import { useTable } from '@/hooks/core/useTable'
+  import { useTableColumns } from '@/hooks/core/useTableColumns'
   import { usePrintExportPage } from '@/views/system/common/usePrintExportPage'
   import ListExportPrint from '@/components/biz/list-export-print/index.vue'
   import { defaultResponseAdapter } from '@/utils/table/tableUtils'
   import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
   import { fetchDictDataPage } from '@/api/system-manage'
   import {
+    DEFAULT_ASN_ORDER_LOG_PAGE_SIZE,
     buildAsnOrderLogDetailQueryParams,
     buildAsnOrderLogPageQueryParams,
     buildAsnOrderLogPrintRows,
     buildAsnOrderLogReportMeta,
     buildAsnOrderLogSearchParams,
     createAsnOrderLogSearchState,
-    getAsnOrderLogExceStatusOptions,
     getAsnOrderLogNtyStatusOptions,
     getAsnOrderLogRleStatusOptions,
     getAsnOrderLogStatusOptions,
@@ -101,6 +102,8 @@
   const reportTitle = ASN_ORDER_LOG_REPORT_TITLE
   const searchForm = ref(createAsnOrderLogSearchState())
   const selectedRows = ref([])
+  const data = ref([])
+  const loading = ref(false)
   const detailDrawerVisible = ref(false)
   const detailLoading = ref(false)
   const detailItemsLoading = ref(false)
@@ -111,6 +114,10 @@
   const wkTypeOptions = ref([])
   const exceStatusOptions = ref([])
   const detailItemColumns = createAsnOrderItemLogColumns()
+  const pageSize = ref(DEFAULT_ASN_ORDER_LOG_PAGE_SIZE)
+  const cursorHistory = ref([null])
+  const nextCursor = ref(null)
+  const hasNext = ref(false)
 
   const detailPagination = reactive({
     current: 1,
@@ -119,6 +126,22 @@
   })
 
   const reportQueryParams = computed(() => buildAsnOrderLogSearchParams(searchForm.value))
+  const mainPaginationOptions = {
+    layout: 'prev, next, sizes',
+    hideOnSinglePage: false
+  }
+  const pagination = computed(() => {
+    const current = Math.max(1, cursorHistory.value.length || 1)
+    const size = Number(pageSize.value) > 0 ? Number(pageSize.value) : DEFAULT_ASN_ORDER_LOG_PAGE_SIZE
+    const recordCount = Math.max(0, Number(data.value.length) || 0)
+    const total = hasNext.value ? current * size + 1 : (current - 1) * size + recordCount
+
+    return {
+      current,
+      size,
+      total
+    }
+  })
 
   const searchItems = computed(() => [
     {
@@ -236,10 +259,48 @@
     }
   ])
 
-  function updatePaginationState(target, response, fallbackCurrent, fallbackSize) {
-    target.total = Number(response?.total || 0)
-    target.current = Number(response?.current || fallbackCurrent || 1)
-    target.size = Number(response?.size || fallbackSize || target.size || 20)
+  const { columns, columnChecks } = useTableColumns(() =>
+    createAsnOrderLogTableColumns({ handleView: openDetail })
+  )
+
+  async function loadMainList({ history = cursorHistory.value } = {}) {
+    loading.value = true
+    try {
+      const normalizedHistory =
+        Array.isArray(history) && history.length > 0 ? [...history] : [null]
+      const response = await guardRequestWithMessage(
+        fetchAsnOrderLogPage(
+          buildAsnOrderLogPageQueryParams({
+            ...searchForm.value,
+            cursor: normalizedHistory[normalizedHistory.length - 1] ?? null,
+            pageSize: pageSize.value
+          })
+        ),
+        {
+          records: [],
+          pageSize: pageSize.value,
+          nextCursor: null,
+          hasNext: false
+        },
+        {
+          timeoutMessage: '鍘嗗彶閫氱煡鍗曞垪琛ㄥ姞杞借秴鏃讹紝宸插仠姝㈢瓑寰�'
+        }
+      )
+
+      cursorHistory.value = normalizedHistory
+      data.value = Array.isArray(response?.records)
+        ? response.records.map((item) => normalizeAsnOrderLogRow(item))
+        : []
+      nextCursor.value = response?.nextCursor ?? null
+      hasNext.value = Boolean(
+        response?.hasNext && response?.nextCursor !== null && response?.nextCursor !== undefined
+      )
+      selectedRows.value = []
+    } catch (error) {
+      ElMessage.error(error?.message || '鑾峰彇鍘嗗彶閫氱煡鍗曞垪琛ㄥけ璐�')
+    } finally {
+      loading.value = false
+    }
   }
 
   function openDetail(row) {
@@ -248,30 +309,6 @@
     detailDrawerVisible.value = true
     loadDetailResources()
   }
-
-  const {
-    columns,
-    columnChecks,
-    data,
-    loading,
-    pagination,
-    replaceSearchParams,
-    resetSearchParams,
-    handleSizeChange,
-    handleCurrentChange,
-    refreshData,
-    getData
-  } = useTable({
-    core: {
-      apiFn: fetchAsnOrderLogPage,
-      apiParams: buildAsnOrderLogPageQueryParams(searchForm.value),
-      columnsFactory: () => createAsnOrderLogTableColumns({ handleView: openDetail })
-    },
-    transform: {
-      dataTransformer: (records) =>
-        Array.isArray(records) ? records.map((item) => normalizeAsnOrderLogRow(item)) : []
-    }
-  })
 
   async function loadDetailResources() {
     if (!activeLogId.value) {
@@ -309,12 +346,9 @@
       detailItemRows.value = Array.isArray(itemResult.records)
         ? itemResult.records.map((item) => normalizeAsnOrderItemLogRow(item))
         : []
-      updatePaginationState(
-        detailPagination,
-        itemResult,
-        detailPagination.current,
-        detailPagination.size
-      )
+      detailPagination.total = Number(itemResult?.total || 0)
+      detailPagination.current = Number(itemResult?.current || detailPagination.current || 1)
+      detailPagination.size = Number(itemResult?.size || detailPagination.size || 20)
     } catch (error) {
       detailDrawerVisible.value = false
       detailData.value = {}
@@ -330,18 +364,56 @@
     selectedRows.value = Array.isArray(rows) ? rows : []
   }
 
-  function handleSearch(params) {
+  async function handleSearch(params) {
     searchForm.value = {
       ...searchForm.value,
       ...params
     }
-    replaceSearchParams(buildAsnOrderLogSearchParams(searchForm.value))
-    getData()
+    await loadMainList({ history: [null] })
   }
 
-  function handleReset() {
+  async function handleReset() {
     searchForm.value = createAsnOrderLogSearchState()
-    resetSearchParams()
+    await loadMainList({ history: [null] })
+  }
+
+  async function handleSizeChange(size) {
+    if (Number(size) <= 0) {
+      return
+    }
+    pageSize.value = Number(size)
+    await loadMainList({ history: [null] })
+  }
+
+  async function handleCurrentChange(current) {
+    const targetPage = Number(current)
+    const currentPage = Number(pagination.value.current)
+
+    if (!Number.isInteger(targetPage) || targetPage <= 0 || targetPage === currentPage) {
+      return
+    }
+    if (loading.value) {
+      return
+    }
+
+    if (targetPage === currentPage + 1) {
+      if (!hasNext.value || nextCursor.value === null || nextCursor.value === undefined) {
+        return
+      }
+      const nextHistory = [...cursorHistory.value, Number(nextCursor.value)]
+      await loadMainList({ history: nextHistory })
+      return
+    }
+
+    if (targetPage === currentPage - 1) {
+      await loadMainList({
+        history: cursorHistory.value.length > 1 ? cursorHistory.value.slice(0, -1) : [null]
+      })
+    }
+  }
+
+  async function refreshData() {
+    await loadMainList()
   }
 
   function handleDetailSizeChange(size) {
@@ -368,18 +440,41 @@
     }
   }
 
+  async function fetchAllPrintableRecords(queryParams = {}, maxResults = 1000) {
+    const records = []
+    let cursor = null
+    const batchSize = Math.max(Number(pageSize.value) || DEFAULT_ASN_ORDER_LOG_PAGE_SIZE, 100)
+
+    while (records.length < maxResults) {
+      const response = await fetchAsnOrderLogPage(
+        buildAsnOrderLogPageQueryParams({
+          ...queryParams,
+          cursor,
+          pageSize: batchSize
+        })
+      )
+      const pageRecords = Array.isArray(response?.records) ? response.records : []
+
+      if (pageRecords.length === 0) {
+        break
+      }
+
+      records.push(...pageRecords)
+
+      if (!response?.hasNext || response?.nextCursor === null || response?.nextCursor === undefined) {
+        break
+      }
+      cursor = response.nextCursor
+    }
+
+    return records.slice(0, maxResults)
+  }
+
   async function resolvePrintRecords(payload) {
     if (Array.isArray(payload?.ids) && payload.ids.length > 0) {
       return defaultResponseAdapter(await fetchGetAsnOrderLogMany(payload.ids)).records
     }
-    return defaultResponseAdapter(
-      await fetchAsnOrderLogPage({
-        ...reportQueryParams.value,
-        current: 1,
-        pageSize:
-          Number(pagination.total) > 0 ? Number(pagination.total) : Number(payload?.pageSize) || 20
-      })
-    ).records
+    return fetchAllPrintableRecords(reportQueryParams.value)
   }
 
   const {
@@ -463,6 +558,11 @@
   }
 
   onMounted(async () => {
-    await Promise.allSettled([loadTypeOptions(), loadWkTypeOptions(), loadExceStatusOptions()])
+    await Promise.allSettled([
+      loadTypeOptions(),
+      loadWkTypeOptions(),
+      loadExceStatusOptions(),
+      loadMainList()
+    ])
   })
 </script>
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageParam.java b/rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageParam.java
new file mode 100644
index 0000000..34406db
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageParam.java
@@ -0,0 +1,68 @@
+package com.vincent.rsf.server.common.domain;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Map;
+
+/**
+ * 閫氱敤娓告爣鍒嗛〉鍙傛暟銆�
+ *
+ * <p>杩欎釜绫诲湪鐜版湁 {@link BaseParam} 鐨勫熀纭�涓婂彧澧炲姞涓�涓� {@code cursor} 瀛楁锛�
+ * 鐢ㄦ潵琛ㄧず鈥滀笅涓�椤典粠鍝噷缁х画鏌モ�濄��</p>
+ *
+ * <p>褰撳墠椤圭洰閲岀殑鏅�氬垎椤垫帴鍙eぇ澶氳繕鏄� {@code current + pageSize} 妯″紡锛�
+ * 浣嗘父鏍囧垎椤靛彧渚濊禆锛�</p>
+ * <ul>
+ *     <li>{@code pageSize}锛氭瘡椤靛ぇ灏�</li>
+ *     <li>{@code cursor}锛氫笂涓�椤垫渶鍚庝竴鏉¤褰曠殑娓告爣鍊�</li>
+ * </ul>
+ *
+ * <p>杩欓噷浠嶇劧缁ф壙 {@link BaseParam}锛岀洰鐨勬槸缁х画澶嶇敤鍘熸湁鐨勶細</p>
+ * <ul>
+ *     <li>绛涢�夋潯浠惰В鏋�</li>
+ *     <li>{@code condition / timeStart / timeEnd} 绛夐�氱敤鍙傛暟</li>
+ *     <li>鍜� {@link com.vincent.rsf.server.common.domain.PageParam} 鐨勫崗浣滆兘鍔�</li>
+ * </ul>
+ *
+ * <p>娉ㄦ剰锛氬墠绔嵆浣跨户缁紶 {@code current}锛岃繖閲屼篃涓嶄細鎶ラ敊锛�
+ * {@link BaseParam#syncMap(Map)} 浼氭甯歌В鏋愬畠锛屼絾鍚庣画閫氱敤娓告爣鍒嗛〉閫昏緫涓嶄細浣跨敤瀹冦��</p>
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CursorPageParam extends BaseParam {
+
+    /**
+     * 褰撳墠椤电殑璧峰娓告爣銆�
+     *
+     * <p>绾﹀畾鍚箟鏄細鍙煡璇⑩�滄瘮杩欎釜娓告爣鏇存棫鈥濈殑鏁版嵁锛�
+     * 渚嬪鎸� {@code id desc} 缈婚〉鏃讹紝浼氱敓鎴� {@code id < cursor} 鐨勬潯浠躲��</p>
+     */
+    private Long cursor;
+
+    @Override
+    public void syncMap(Map<String, Object> map) {
+        // 鍏堝鐢� BaseParam 鐨勯�氱敤鍙傛暟瑙f瀽鑳藉姏锛�
+        // 淇濊瘉 pageSize銆乧ondition銆乼imeStart銆乼imeEnd 绛夊瓧娈电収甯稿伐浣溿��
+        super.syncMap(map);
+        if (map == null) {
+            return;
+        }
+        Object cursorValue = map.get("cursor");
+        if (cursorValue == null) {
+            return;
+        }
+        String normalizedValue = String.valueOf(cursorValue).trim();
+        if (normalizedValue.isEmpty()) {
+            // 绌哄瓧绗︿覆娓告爣绛変环浜庘�滈灞忔病鏈夋父鏍団�濓紝杩欓噷鐩存帴绉婚櫎锛岄伩鍏嶅悗缁鍙備笌 SQL銆�
+            map.remove("cursor");
+            return;
+        }
+        // 鐩墠閫氱敤鏂规缁熶竴鎶婃父鏍囩害鏉熶负 Long锛�
+        // 杩欐牱鍙互瑕嗙洊褰撳墠鎸変富閿�/鏁板瓧瀛楁鍊掑簭缈婚〉鐨勪笟鍔″満鏅��
+        this.cursor = Long.parseLong(normalizedValue);
+        // 瑙f瀽瀹屾垚鍚庤浠� map 涓Щ闄わ紝閬垮厤 PageParam.buildWrapper(true)
+        // 鎶� cursor 褰撴垚鏅�氱瓫閫夊瓧娈靛啀娆℃嫾杩� where 鏉′欢銆�
+        map.remove("cursor");
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageResult.java b/rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageResult.java
new file mode 100644
index 0000000..e3a6c21
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/common/domain/CursorPageResult.java
@@ -0,0 +1,43 @@
+package com.vincent.rsf.server.common.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 閫氱敤娓告爣鍒嗛〉杩斿洖浣撱��
+ *
+ * <p>瀵瑰鍝嶅簲缁撴瀯鍒绘剰淇濇寔绠�鍗曪紝鍙毚闇叉父鏍囧垎椤电湡姝i渶瑕佺殑 4 涓瓧娈碉紝
+ * 涓嶅啀杩斿洖浼犵粺椤电爜鍒嗛〉閲岀殑 {@code total/current/pages}銆�</p>
+ *
+ * <p>瀛楁璇箟绾﹀畾锛�</p>
+ * <ul>
+ *     <li>{@code records}锛氬綋鍓嶉〉瀹為檯杩斿洖鐨勬暟鎹�</li>
+ *     <li>{@code pageSize}锛氭湰娆℃煡璇㈡渶缁堥噰鐢ㄧ殑鍒嗛〉澶у皬锛堝寘鍚粯璁ゅ�煎洖閫�鍚庣殑缁撴灉锛�</li>
+ *     <li>{@code nextCursor}锛氫笅涓�椤靛簲褰撲娇鐢ㄧ殑娓告爣锛涙病鏈変笅涓�椤垫椂涓� {@code null}</li>
+ *     <li>{@code hasNext}锛氭槸鍚﹁繕鏈変笅涓�椤�</li>
+ * </ul>
+ *
+ * <p>杩欐牱璁捐鐨勭洰鐨勬槸璁� controller 鐩存帴 {@code R.ok().add(result)}锛�
+ * 鍚屾椂璁╁墠绔彧鍏冲績鈥滄湁娌℃湁涓嬩竴椤碘�濆拰鈥滀笅涓�椤佃甯︿粈涔� cursor鈥濄��</p>
+ */
+@Data
+public class CursorPageResult<T> {
+
+    /** 褰撳墠椤垫暟鎹垪琛ㄣ�� */
+    private List<T> records;
+
+    /** 褰撳墠璇锋眰鏈�缁堢敓鏁堢殑鍒嗛〉澶у皬銆� */
+    private Integer pageSize;
+
+    /**
+     * 涓嬩竴椤佃鎼哄甫鐨勬父鏍囧�笺��
+     *
+     * <p>绾﹀畾鍙栤�滃綋鍓嶉〉鏈�鍚庝竴鏉¤褰曗�濈殑娓告爣瀛楁鍊笺��
+     * 濡傛灉娌℃湁涓嬩竴椤碉紝鍒欒繑鍥� null銆�</p>
+     */
+    private Long nextCursor;
+
+    /** 鏄惁杩樺瓨鍦ㄤ笅涓�椤点�� */
+    private Boolean hasNext;
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderLogController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderLogController.java
index fcf243d..2b8aea5 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderLogController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderLogController.java
@@ -8,11 +8,11 @@
 import com.vincent.rsf.framework.common.R;
 import com.vincent.rsf.server.common.utils.ExcelUtil;
 import com.vincent.rsf.server.common.annotation.OperationLog;
-import com.vincent.rsf.server.common.domain.BaseParam;
+import com.vincent.rsf.server.common.domain.CursorPageParam;
 import com.vincent.rsf.server.common.domain.KeyValVo;
-import com.vincent.rsf.server.common.domain.PageParam;
 import com.vincent.rsf.server.manager.entity.AsnOrderLog;
 import com.vincent.rsf.server.manager.service.AsnOrderLogService;
+import com.vincent.rsf.server.manager.utils.buildPageRowsUtils;
 import com.vincent.rsf.server.system.controller.BaseController;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -25,15 +25,35 @@
 @RestController
 public class AsnOrderLogController extends BaseController {
 
+    private static final int DEFAULT_CURSOR_PAGE_SIZE = 20;
+
     @Autowired
     private AsnOrderLogService asnOrderLogService;
 
     @PreAuthorize("hasAuthority('manager:asnOrderLog:list')")
     @PostMapping("/asnOrderLog/page")
     public R page(@RequestBody Map<String, Object> map) {
-        BaseParam baseParam = buildParam(map, BaseParam.class);
-        PageParam<AsnOrderLog, BaseParam> pageParam = new PageParam<>(baseParam, AsnOrderLog.class);
-        return R.ok().add(asnOrderLogService.page(pageParam, pageParam.buildWrapper(true)));
+        // 杩欓噷宸茬粡涓嶅啀鎵嬪啓娓告爣鍒嗛〉缁嗚妭锛岃�屾槸鐩存帴澶嶇敤 BaseController 鐨勯�氱敤瀹炵幇銆�
+        //
+        // 褰撳墠杩欏嚑涓弬鏁板垎鍒〃杈撅細
+        // 1. map锛氬墠绔師濮嬭姹傚弬鏁�
+        // 2. CursorPageParam.class锛氶�氱敤娓告爣鍙傛暟瑙f瀽鍣�
+        // 3. AsnOrderLog.class锛氱敤浜庨�氱敤绛涢�夊拰 condition 妯$硦鎼滅储
+        // 4. asnOrderLogService锛氬疄闄呮墽琛屾煡璇㈢殑 service
+        // 5. "id"锛氭湰鎺ュ彛鐨勬父鏍囧瓧娈碉紝鍥哄畾鎸� id desc 鍋氬垎椤�
+        // 6. DEFAULT_CURSOR_PAGE_SIZE锛氶粯璁ゆ瘡椤靛ぇ灏�
+        // 7. null锛氬綋鍓嶆病鏈夐澶栫殑 where 鏉′欢鎵╁睍
+        // 8. buildPageRowsUtils::userNameMap锛氱粨鏋滃悗澶勭悊锛屾壒閲忚ˉ createBy$/updateBy$
+        return R.ok().add(cursorPage(
+                map,
+                CursorPageParam.class,
+                AsnOrderLog.class,
+                asnOrderLogService,
+                "id",
+                DEFAULT_CURSOR_PAGE_SIZE,
+                null,
+                buildPageRowsUtils::userNameMap
+        ));
     }
 
     @PreAuthorize("hasAuthority('manager:asnOrderLog:list')")
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderLog.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderLog.java
index 9389780..406b882 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderLog.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderLog.java
@@ -3,22 +3,19 @@
 import java.text.SimpleDateFormat;
 import java.util.*;
 
+import com.baomidou.mybatisplus.annotation.*;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.vincent.rsf.server.system.constant.DictTypeCode;
 import com.vincent.rsf.server.system.entity.DictData;
 import com.vincent.rsf.server.system.service.DictDataService;
 import org.springframework.format.annotation.DateTimeFormat;
-import com.baomidou.mybatisplus.annotation.TableLogic;
+
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableLogic;
-import com.baomidou.mybatisplus.annotation.TableName;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -141,6 +138,9 @@
     @ApiModelProperty(value= "娣诲姞浜哄憳")
     private Long createBy;
 
+    @TableField(exist = false)
+    private String createBy$;
+
     /**
      * 娣诲姞鏃堕棿
      */
@@ -154,6 +154,9 @@
      */
     @ApiModelProperty(value= "淇敼浜哄憳")
     private Long updateBy;
+
+    @TableField(exist = false)
+    private String updateBy$;
 
     /**
      * 淇敼鏃堕棿
@@ -296,29 +299,11 @@
         }
     }
 
-    public String getCreateBy$(){
-        UserService service = SpringUtils.getBean(UserService.class);
-        User user = service.getById(this.createBy);
-        if (!Cools.isEmpty(user)){
-            return String.valueOf(user.getNickname());
-        }
-        return null;
-    }
-
     public String getCreateTime$(){
         if (Cools.isEmpty(this.createTime)){
             return "";
         }
         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
-    }
-
-    public String getUpdateBy$(){
-        UserService service = SpringUtils.getBean(UserService.class);
-        User user = service.getById(this.updateBy);
-        if (!Cools.isEmpty(user)){
-            return String.valueOf(user.getNickname());
-        }
-        return null;
     }
 
     public String getUpdateTime$(){
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/AsnOrderMapper.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/AsnOrderMapper.java
index 1b0f90e..731dba0 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/AsnOrderMapper.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/AsnOrderMapper.java
@@ -1,14 +1,9 @@
 package com.vincent.rsf.server.manager.mapper;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.Constants;
-import com.vincent.rsf.server.manager.controller.dto.DashboardDto;
 import com.vincent.rsf.server.manager.controller.dto.StockTransItemDto;
-import com.vincent.rsf.server.manager.entity.StockStatistic;
 import com.vincent.rsf.server.manager.entity.WkOrder;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;
@@ -17,7 +12,5 @@
 @Repository
 public interface AsnOrderMapper extends BaseMapper<WkOrder> {
 
-    DashboardDto getDashbord(@Param("type") String type, @Param("taskType") String taskType);
-
-    List<StockTransItemDto> getStockTrand(@Param(Constants.WRAPPER) LambdaQueryWrapper<StockStatistic> queryWrapper);
+    List<StockTransItemDto> getStockTrand();
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/AsnOrderPressureSchedules.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/AsnOrderPressureSchedules.java
index 2262b15..7d4818e 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/AsnOrderPressureSchedules.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/AsnOrderPressureSchedules.java
@@ -2,11 +2,11 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.vincent.rsf.framework.exception.CoolException;
+import com.vincent.rsf.server.manager.entity.AsnOrderItemLog;
+import com.vincent.rsf.server.manager.entity.AsnOrderLog;
 import com.vincent.rsf.server.manager.entity.Matnr;
-import com.vincent.rsf.server.manager.entity.WkOrder;
-import com.vincent.rsf.server.manager.entity.WkOrderItem;
-import com.vincent.rsf.server.manager.service.AsnOrderItemService;
-import com.vincent.rsf.server.manager.service.AsnOrderService;
+import com.vincent.rsf.server.manager.service.AsnOrderItemLogService;
+import com.vincent.rsf.server.manager.service.AsnOrderLogService;
 import com.vincent.rsf.server.manager.service.MatnrService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -22,7 +22,9 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -41,9 +43,9 @@
     private final AtomicBoolean running = new AtomicBoolean(false);
 
     @Autowired
-    private AsnOrderService asnOrderService;
+    private AsnOrderLogService asnOrderLogService;
     @Autowired
-    private AsnOrderItemService asnOrderItemService;
+    private AsnOrderItemLogService asnOrderItemLogService;
     @Autowired
     private MatnrService matnrService;
 
@@ -87,23 +89,33 @@
             LocalDateTime nowTime = LocalDateTime.now();
             double totalQty = itemCountPerOrder * itemQty;
 
-            List<WkOrder> orders = new ArrayList<>(orderCountPerRun);
+            List<AsnOrderLog> orders = new ArrayList<>(orderCountPerRun);
             for (int i = 0; i < orderCountPerRun; i++) {
                 orders.add(buildOrder(now, nowTime, totalQty, i));
             }
-            if (!asnOrderService.saveBatch(orders, 200)) {
+            if (!asnOrderLogService.saveBatch(orders, 200)) {
                 throw new CoolException("ASN鍘嬫祴涓诲崟鎻掑叆澶辫触");
             }
 
-            List<WkOrderItem> items = new ArrayList<>(orderCountPerRun * itemCountPerOrder);
+            List<AsnOrderLog> persistedOrders = asnOrderLogService.list(new LambdaQueryWrapper<AsnOrderLog>()
+                    .in(AsnOrderLog::getCode, extractOrderCodes(orders)));
+            Map<String, AsnOrderLog> orderMap = new HashMap<>(persistedOrders.size());
+            for (AsnOrderLog order : persistedOrders) {
+                orderMap.put(order.getCode(), order);
+            }
+
+            List<AsnOrderItemLog> items = new ArrayList<>(orderCountPerRun * itemCountPerOrder);
             for (int orderIndex = 0; orderIndex < orders.size(); orderIndex++) {
-                WkOrder order = orders.get(orderIndex);
+                AsnOrderLog order = orderMap.get(orders.get(orderIndex).getCode());
+                if (order == null) {
+                    throw new CoolException("ASN鍘嬫祴涓诲崟鍥炴煡澶辫触");
+                }
                 for (int itemIndex = 0; itemIndex < itemCountPerOrder; itemIndex++) {
                     Matnr matnr = matnrs.get((orderIndex * itemCountPerOrder + itemIndex) % matnrs.size());
                     items.add(buildOrderItem(order, matnr, now, orderIndex, itemIndex));
                 }
             }
-            if (!asnOrderItemService.saveBatch(items, 500)) {
+            if (!asnOrderItemLogService.saveBatch(items, 500)) {
                 throw new CoolException("ASN鍘嬫祴鏄庣粏鎻掑叆澶辫触");
             }
 
@@ -126,89 +138,69 @@
                 .last("limit " + needCount));
     }
 
-    private WkOrder buildOrder(Date now, LocalDateTime nowTime, double totalQty, int sequence) {
+    private List<String> extractOrderCodes(List<AsnOrderLog> orders) {
+        List<String> codes = new ArrayList<>(orders.size());
+        for (AsnOrderLog order : orders) {
+            codes.add(order.getCode());
+        }
+        return codes;
+    }
+
+    private AsnOrderLog buildOrder(Date now, LocalDateTime nowTime, double totalQty, int sequence) {
         String suffix = String.format("%04d", sequence + 1);
         String code = "erp" + nowTime.format(ORDER_CODE_FORMATTER) + suffix;
         long serialNo = System.currentTimeMillis() * 1000 + sequence;
 
-        return new WkOrder()
-                .setCode(code)
-                .setPoCode(code)
-                .setPoId(serialNo)
-                .setType(ORDER_TYPE)
-                .setWkType(ORDER_WORK_TYPE)
-                .setAnfme(totalQty)
-                .setQty(totalQty)
-                .setWorkQty(0.0)
-                .setCheckType(0)
-                .setRleStatus((short) 0)
-                .setNtyStatus(0)
-                .setExceStatus((short) 4)
-                .setStatus(1)
-                .setDeleted(0)
-                .setTenantId(TENANT_ID)
-                .setCreateBy(USER_ID)
-                .setCreateTime(now)
-                .setUpdateBy(USER_ID)
-                .setUpdateTime(now)
-                .setMemo(MEMO)
-                .setReportOnce(4)
-                .setBusinessTime(now)
-                .setStationId("1215")
-                .setOrderInternalCode(String.valueOf(serialNo))
-                .setStockDirect("stockDirect")
-                .setCustomerId("custom1")
-                .setCustomerName("瀹㈡埛1")
-                .setSupplierId("gongys1")
-                .setSupplierName("渚涘簲鍟�1")
-                .setStockOrgId("stockYH")
-                .setStockOrgName("娴欐睙閾舵箹绠卞寘鏈夐檺鍏徃浠撳簱")
-                .setPurchaseOrgId("yhcaigou")
-                .setPurchaseOrgName("娴欐睙閾舵箹绠卞寘鏈夐檺鍏徃閲囪喘")
-                .setPurchaseUserId("caigouyuan1")
-                .setPurchaseUserName("閲囪喘鍛�1")
-                .setPrdOrgId("prdYH")
-                .setPrdOrgName("娴欐睙閾舵箹绠卞寘鏈夐檺鍏徃")
-                .setSaleOrgId("sale1")
-                .setSaleOrgName("鐢熶骇缁�1")
-                .setSaleUserId("shengchanyuan1")
-                .setSaleUserName("鐢熶骇鍛�1")
-                .setVersion(0);
+        AsnOrderLog order = new AsnOrderLog();
+        order.setCode(code);
+        order.setPoCode(code);
+        order.setPoId(serialNo);
+        order.setType(ORDER_TYPE);
+        order.setWkType(ORDER_WORK_TYPE);
+        order.setAnfme(totalQty);
+        order.setQty(totalQty);
+        order.setRleStatus((short) 0);
+        order.setNtyStatus((short) 0);
+        order.setExceStatus((short) 4);
+        order.setStatus(1);
+        order.setDeleted(0);
+        order.setTenantId(TENANT_ID);
+        order.setCreateBy(USER_ID);
+        order.setCreateTime(now);
+        order.setUpdateBy(USER_ID);
+        order.setUpdateTime(now);
+        order.setMemo(MEMO);
+        return order;
     }
 
-    private WkOrderItem buildOrderItem(WkOrder order, Matnr matnr, Date now, int orderIndex, int itemIndex) {
+    private AsnOrderItemLog buildOrderItem(AsnOrderLog order, Matnr matnr, Date now, int orderIndex, int itemIndex) {
         String stockUnit = StringUtils.firstNonBlank(matnr.getStockUnit(), matnr.getPurUnit(), matnr.getUnit(), matnr.getBaseUnit());
         String purUnit = StringUtils.firstNonBlank(matnr.getPurUnit(), matnr.getUnit(), matnr.getStockUnit(), matnr.getBaseUnit());
-        String baseUnit = StringUtils.firstNonBlank(matnr.getBaseUnit(), matnr.getUnit(), matnr.getStockUnit(), matnr.getPurUnit());
         String batchCode = "B" + new SimpleDateFormat("yyyyMMddHHmmss").format(now)
                 + String.format("%02d%02d", orderIndex + 1, itemIndex + 1);
         String trackCode = "T" + System.currentTimeMillis() + String.format("%02d%02d", orderIndex + 1, itemIndex + 1);
 
-        return new WkOrderItem()
-                .setOrderId(order.getId())
-                .setOrderCode(order.getCode())
+        return new AsnOrderItemLog()
+                .setLogId(order.getId())
+                .setAsnId(order.getAsnId())
+                .setAsnCode(order.getCode())
                 .setPlatItemId("M" + (itemIndex + 1))
                 .setPoCode(order.getPoCode())
                 .setFieldsIndex(matnr.getFieldsIndex())
                 .setMatnrId(matnr.getId())
                 .setMatnrCode(matnr.getCode())
                 .setMaktx(matnr.getName())
-                .setSpec(matnr.getSpec())
-                .setModel(matnr.getModel())
                 .setAnfme(itemQty)
-                .setWorkQty(0.0)
                 .setPurQty(itemQty)
                 .setQty(itemQty)
                 .setStockUnit(stockUnit)
                 .setPurUnit(purUnit)
-                .setBatch(batchCode)
                 .setSplrBatch(batchCode)
                 .setSplrCode("gongys1")
                 .setSplrName("渚涘簲鍟�1")
                 .setTrackCode(trackCode)
                 .setBarcode(trackCode)
-                .setProdTime(new SimpleDateFormat("yyyy-MM-dd").format(now))
-                .setNtyStatus(0)
+                .setNtyStatus((short) 0)
                 .setStatus(1)
                 .setDeleted(0)
                 .setTenantId(TENANT_ID)
@@ -216,11 +208,6 @@
                 .setCreateTime(now)
                 .setUpdateBy(USER_ID)
                 .setUpdateTime(now)
-                .setMemo(MEMO)
-                .setBaseUnit(baseUnit)
-                .setUseOrgId(matnr.getUseOrgId())
-                .setUseOrgName(matnr.getUseOrgName())
-                .setErpClsId(matnr.getErpClsId())
-                .setPriceUnitId(baseUnit);
+                .setMemo(MEMO);
     }
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java
index ab223ec..c74cd30 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java
@@ -8,6 +8,7 @@
 import com.vincent.rsf.framework.exception.CoolException;
 import com.vincent.rsf.server.api.entity.dto.PoItemsDto;
 import com.vincent.rsf.server.api.service.ReportMsgService;
+import com.vincent.rsf.server.common.service.RedisService;
 import com.vincent.rsf.server.common.utils.DateUtils;
 import com.vincent.rsf.server.manager.controller.dto.DashboardDto;
 import com.vincent.rsf.server.manager.controller.dto.StockTrandDto;
@@ -17,12 +18,14 @@
 import com.vincent.rsf.server.manager.entity.*;
 import com.vincent.rsf.server.manager.enums.*;
 import com.vincent.rsf.server.manager.mapper.AsnOrderMapper;
+import com.vincent.rsf.server.manager.mapper.TaskLogMapper;
 import com.vincent.rsf.server.manager.mapper.TaskMapper;
 import com.vincent.rsf.server.manager.service.*;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.vincent.rsf.server.system.constant.SerialRuleCode;
 import com.vincent.rsf.server.system.mapper.SerialRuleMapper;
 import com.vincent.rsf.server.system.utils.SerialRuleUtils;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,6 +33,9 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import jakarta.annotation.Resource;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.text.DateFormat;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
@@ -43,8 +49,16 @@
  * @return
  * @time 2025/3/7 08:02
  */
+@Slf4j
 @Service("asnOrderService")
 public class AsnOrderServiceImpl extends ServiceImpl<AsnOrderMapper, WkOrder> implements AsnOrderService {
+
+    private static final String DASHBOARD_HEADER_CACHE_FLAG = "DASHBOARD_HEADER";
+    private static final String DASHBOARD_HEADER_CACHE_FRESH_SUFFIX = "FRESH";
+    private static final String DASHBOARD_HEADER_CACHE_STALE_SUFFIX = "STALE";
+    private static final int DASHBOARD_HEADER_CACHE_FRESH_TTL_SECONDS = 300;
+    private static final int DASHBOARD_HEADER_CACHE_STALE_TTL_SECONDS = 86400;
+    private static final DateTimeFormatter DASHBOARD_CACHE_DATE_FORMATTER = DateTimeFormatter.BASIC_ISO_DATE;
 
     @Autowired
     private ReportMsgService reportMsgService;
@@ -65,6 +79,10 @@
     private PurchaseItemService purchaseItemService;
     @Autowired
     private TaskMapper taskMapper;
+    @Autowired
+    private TaskLogMapper taskLogMapper;
+    @Autowired
+    private RedisService redisService;
 
     @Override
     public boolean notifyInspect(List<WkOrder> orders) {
@@ -430,21 +448,29 @@
      */
     @Override
     public R getDashbord() {
-        DashboardDto dto = new DashboardDto();
-        //鑾峰彇鍏ュ簱鏁伴噺
-        DashboardDto trandDto = this.baseMapper.getDashbord(OrderType.ORDER_IN.type, TaskType.TASK_TYPE_IN.type + "");
-        dto.setInAnf(trandDto.getAnfme()).setTaskIn(trandDto.getRealAnfme()).setTotalIn(trandDto.getAnfme() + trandDto.getRealAnfme());
-
-        //鑾峰彇鍑哄簱鍗曟暟閲�
-        DashboardDto outTrand = this.baseMapper.getDashbord(OrderType.ORDER_OUT.type, TaskType.TASK_TYPE_OUT.type + "");
-        dto.setOutAnf(outTrand.getAnfme()).setTaskOut(outTrand.getRealAnfme()).setTotalOut(outTrand.getAnfme() + outTrand.getRealAnfme());
-
-        //鑾峰彇鎵ц涓换鍔℃暟閲�
-        List<Task> tasks = taskMapper.selectList(new LambdaQueryWrapper<>());
-        if (!tasks.isEmpty()) {
-            dto.setTaskQty(tasks.size());
+        String freshCacheKey = buildDashboardCacheKey(DASHBOARD_HEADER_CACHE_FRESH_SUFFIX);
+        DashboardDto freshSnapshot = getDashboardCache(freshCacheKey);
+        if (freshSnapshot != null) {
+            return R.ok().add(freshSnapshot);
         }
-        return R.ok().add(dto);
+        String staleCacheKey = buildDashboardCacheKey(DASHBOARD_HEADER_CACHE_STALE_SUFFIX);
+        Exception dbException = null;
+        try {
+            DashboardDto snapshot = buildDashboardSnapshot();
+            cacheDashboard(freshCacheKey, snapshot, DASHBOARD_HEADER_CACHE_FRESH_TTL_SECONDS);
+            cacheDashboard(staleCacheKey, snapshot, DASHBOARD_HEADER_CACHE_STALE_TTL_SECONDS);
+            return R.ok().add(snapshot);
+        } catch (Exception ex) {
+            dbException = ex;
+            log.warn("Load dashboard snapshot from database failed, fallback to stale cache. message={}", ex.getMessage(), ex);
+        }
+
+        DashboardDto staleSnapshot = getDashboardCache(staleCacheKey);
+        if (staleSnapshot != null) {
+            return R.ok().add(staleSnapshot);
+        }
+        log.error("Load dashboard snapshot failed, returning empty snapshot.", dbException);
+        return R.ok().add(emptyDashboardSnapshot());
     }
 
     /**
@@ -454,9 +480,7 @@
     @Override
     public R getStockTrand() {
         List<String> days = DateUtils.getLastMonthDays("yyyy-MM-dd");
-        LambdaQueryWrapper<StockStatistic> queryWrapper = new LambdaQueryWrapper<StockStatistic>()
-                .in(StockStatistic::getTaskType, Arrays.asList(TaskType.TASK_TYPE_IN.type, TaskType.TASK_TYPE_OUT.type));
-       List<StockTransItemDto> items = this.baseMapper.getStockTrand(queryWrapper);
+       List<StockTransItemDto> items = this.baseMapper.getStockTrand();
        if (items.isEmpty()) {
            return R.ok();
        }
@@ -542,4 +566,86 @@
             throw new CoolException("鍘熷崟鎹垹闄ゅけ璐ワ紒锛�");
         }
     }
+
+    private DashboardDto buildDashboardSnapshot() {
+        Date[] todayRange = buildTodayRange();
+        Date todayStart = todayRange[0];
+        Date tomorrowStart = todayRange[1];
+
+        int inAnf = safeToInt(this.count(new LambdaQueryWrapper<WkOrder>()
+                .eq(WkOrder::getType, OrderType.ORDER_IN.type)
+                .ge(WkOrder::getCreateTime, todayStart)
+                .lt(WkOrder::getCreateTime, tomorrowStart)));
+        int outAnf = safeToInt(this.count(new LambdaQueryWrapper<WkOrder>()
+                .eq(WkOrder::getType, OrderType.ORDER_OUT.type)
+                .ge(WkOrder::getCreateTime, todayStart)
+                .lt(WkOrder::getCreateTime, tomorrowStart)));
+        int taskIn = safeToInt(taskLogMapper.selectCount(new LambdaQueryWrapper<TaskLog>()
+                .eq(TaskLog::getTaskType, TaskType.TASK_TYPE_IN.type)
+                .ge(TaskLog::getCreateTime, todayStart)
+                .lt(TaskLog::getCreateTime, tomorrowStart)));
+        int taskOut = safeToInt(taskLogMapper.selectCount(new LambdaQueryWrapper<TaskLog>()
+                .eq(TaskLog::getTaskType, TaskType.TASK_TYPE_OUT.type)
+                .ge(TaskLog::getCreateTime, todayStart)
+                .lt(TaskLog::getCreateTime, tomorrowStart)));
+        int taskQty = safeToInt(taskMapper.selectCount(new LambdaQueryWrapper<Task>()));
+
+        return new DashboardDto()
+                .setInAnf(inAnf)
+                .setOutAnf(outAnf)
+                .setTaskIn(taskIn)
+                .setTaskOut(taskOut)
+                .setTaskQty(taskQty)
+                .setTotalIn(inAnf + taskIn)
+                .setTotalOut(outAnf + taskOut);
+    }
+
+    private DashboardDto getDashboardCache(String cacheKey) {
+        try {
+            String cacheValue = redisService.getValue(DASHBOARD_HEADER_CACHE_FLAG, cacheKey);
+            if (StringUtils.isBlank(cacheValue)) {
+                return null;
+            }
+            return JSONObject.parseObject(cacheValue, DashboardDto.class);
+        } catch (Exception ex) {
+            log.warn("Read dashboard cache failed, key={}, message={}", cacheKey, ex.getMessage(), ex);
+            return null;
+        }
+    }
+
+    private void cacheDashboard(String cacheKey, DashboardDto dto, int ttlSeconds) {
+        try {
+            redisService.setValue(DASHBOARD_HEADER_CACHE_FLAG, cacheKey, JSONObject.toJSONString(dto), ttlSeconds);
+        } catch (Exception ex) {
+            log.warn("Write dashboard cache failed, key={}, message={}", cacheKey, ex.getMessage(), ex);
+        }
+    }
+
+    private String buildDashboardCacheKey(String suffix) {
+        String dateBucket = LocalDate.now().format(DASHBOARD_CACHE_DATE_FORMATTER);
+        return dateBucket + "." + suffix;
+    }
+
+    private Date[] buildTodayRange() {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDate today = LocalDate.now(zoneId);
+        Date todayStart = Date.from(today.atStartOfDay(zoneId).toInstant());
+        Date tomorrowStart = Date.from(today.plusDays(1).atStartOfDay(zoneId).toInstant());
+        return new Date[]{todayStart, tomorrowStart};
+    }
+
+    private DashboardDto emptyDashboardSnapshot() {
+        return new DashboardDto()
+                .setInAnf(0)
+                .setOutAnf(0)
+                .setTaskIn(0)
+                .setTaskOut(0)
+                .setTaskQty(0)
+                .setTotalIn(0)
+                .setTotalOut(0);
+    }
+
+    private int safeToInt(Long count) {
+        return count == null ? 0 : count.intValue();
+    }
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java
index abd9cef..1511caf 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java
@@ -1,16 +1,27 @@
 package com.vincent.rsf.server.system.controller;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.vincent.rsf.common.utils.Utils;
 import com.vincent.rsf.framework.common.Cools;
 import com.vincent.rsf.server.common.domain.BaseParam;
+import com.vincent.rsf.server.common.domain.CursorPageParam;
+import com.vincent.rsf.server.common.domain.CursorPageResult;
+import com.vincent.rsf.server.common.domain.PageParam;
 import com.vincent.rsf.server.system.entity.User;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * Created by vincent on 1/30/2024
@@ -105,5 +116,189 @@
         return true;
     }
 
+    /**
+     * 閫氱敤娓告爣鍒嗛〉瀹炵幇銆�
+     *
+     * <p>杩欎釜鏂规硶鐨勭洰鏍囦笉鏄浛浠f墍鏈夊垎椤碉紝鑰屾槸鎶娾�滃崟瀛楁銆佸�掑簭銆佸悜鍚庣炕椤碘�濈殑娓告爣鍒嗛〉
+     * 鏀舵暃鎴愪竴濂楃粺涓�瀹炵幇锛岄伩鍏嶅悇涓� controller 閲嶅鍐欎笅闈㈣繖浜涙牱鏉块�昏緫锛�</p>
+     * <ul>
+     *     <li>buildParam</li>
+     *     <li>蹇界暐鍓嶇浼犲叆鐨� orderBy</li>
+     *     <li>buildWrapper(true) 鏋勫缓閫氱敤绛涢��</li>
+     *     <li>cursor 鏉′欢</li>
+     *     <li>鎸夊浐瀹氬瓧娈靛�掑簭</li>
+     *     <li>澶氭煡涓�鏉″垽鏂� hasNext</li>
+     *     <li>鎴柇缁撴灉骞剁敓鎴� nextCursor</li>
+     * </ul>
+     *
+     * <p>閫傜敤鍓嶆彁锛�</p>
+     * <ul>
+     *     <li>娓告爣瀛楁鏄崟涓�瀛楁</li>
+     *     <li>娓告爣瀛楁鐨勫�肩ǔ瀹氥�佸彲姣旇緝锛屽苟涓旇兘鏄犲皠鎴� Long</li>
+     *     <li>鍒嗛〉鏂瑰悜鍥哄畾涓衡�滄寜璇ュ瓧娈靛�掑簭锛屽悜鏇村皬鐨勫�肩炕椤碘��</li>
+     * </ul>
+     *
+     * <p>鍙傛暟璇存槑锛�</p>
+     * <ul>
+     *     <li>{@code map}锛氬師濮嬭姹傚弬鏁�</li>
+     *     <li>{@code paramClass}锛氭父鏍囧弬鏁扮被鍨嬶紝閫氬父浼� {@link CursorPageParam}</li>
+     *     <li>{@code entityClass}锛氬疄浣撶被锛岀敤浜� PageParam 鏉′欢鏋勫缓鍜� condition 妯$硦鏌ヨ</li>
+     *     <li>{@code service}锛歁yBatis-Plus 鐨� IService锛岃礋璐f墽琛� page 鏌ヨ</li>
+     *     <li>{@code cursorField}锛氬疄浣撳瓧娈靛悕锛屼笉鏄暟鎹簱鍒楀悕锛屼緥濡備紶 {@code id}</li>
+     *     <li>{@code defaultPageSize}锛氬綋鍓嶆帴鍙g殑榛樿鍒嗛〉澶у皬</li>
+     *     <li>{@code wrapperConsumer}锛氬彲閫夌殑棰濆 where 鏉′欢鎵╁睍閽╁瓙</li>
+     *     <li>{@code recordsConsumer}锛氬彲閫夌殑缁撴灉鍚庡鐞嗛挬瀛愶紝渚嬪琛ュ厖 createBy$/updateBy$</li>
+     * </ul>
+     */
+    protected <T, U extends CursorPageParam> CursorPageResult<T> cursorPage(
+            Map<String, Object> map,
+            Class<U> paramClass,
+            Class<T> entityClass,
+            IService<T> service,
+            String cursorField,
+            int defaultPageSize,
+            Consumer<QueryWrapper<T>> wrapperConsumer,
+            Consumer<List<T>> recordsConsumer
+    ) {
+        // 鍏佽 controller 浼� null锛屽唴閮ㄧ粺涓�鍏滃簳鎴愮┖ map锛�
+        // 杩欐牱 buildParam 涓嶉渶瑕佹瘡涓皟鐢ㄦ柟鑷繁鍏堝垽绌恒��
+        U baseParam = buildParam(map == null ? new HashMap<>() : map, paramClass);
+
+        // 娓告爣鍒嗛〉涓嶅厑璁稿鎴风鑷畾涔夋帓搴忥紝
+        // 鍚﹀垯鈥滀笂涓�椤垫渶鍚庝竴鏉′綔涓轰笅涓�椤垫父鏍団�濈殑鍓嶆彁浼氳鐮村潖銆�
+        baseParam.setOrderBy(null);
+
+        // pageSize 鍏佽浠庤姹傞噷甯﹀叆锛屼絾闈炴硶鍊硷紙null銆�0銆佽礋鏁帮級缁熶竴鍥為��鍒版帴鍙i粯璁ゅ�笺��
+        int pageSize = resolveCursorPageSize(baseParam.getPageSize(), defaultPageSize);
+
+        // controller 浼犵殑鏄疄浣撳瓧娈靛悕锛屼緥濡� "id" / "poId"锛�
+        // 杩欓噷缁熶竴杞垚鏁版嵁搴撳垪鍚嶅苟琛ュ弽寮曞彿锛岄伩鍏嶆瘡涓笟鍔¤嚜宸辨墜鍐� SQL 鐗囨銆�
+        String cursorColumn = resolveCursorColumn(cursorField);
+
+        // 鍏堝鐢ㄧ郴缁熺幇鏈夌殑 PageParam + buildWrapper(true) 鏈哄埗锛�
+        // 淇濈暀鍘熸潵鐨勬潯浠惰В鏋愩�佹椂闂磋寖鍥淬�乧ondition 妯$硦鎼滅储绛夎兘鍔涖��
+        PageParam<T, U> pageParam = new PageParam<>(baseParam, entityClass);
+        QueryWrapper<T> wrapper = pageParam.buildWrapper(true);
+
+        // 缁欎笟鍔¢鐣欓澶� where 鏉′欢鐨勬墿灞曠偣锛�
+        // 濡傛灉鏌愪釜鎺ュ彛闄や簡閫氱敤绛涢�夊锛岃繕瑕佹嫾鎺ラ澶栭檺鍒讹紝鍙互鍦ㄨ繖閲岃ˉ銆�
+        if (wrapperConsumer != null) {
+            wrapperConsumer.accept(wrapper);
+        }
+
+        // 娓告爣鍒嗛〉鐨勬牳蹇冩潯浠讹細
+        // 褰撳墠绾﹀畾鏄�滄寜 cursorField 鍊掑簭鏌ョ湅鏇存棫鐨勬暟鎹�濓紝鎵�浠ユ潯浠跺浐瀹氫负 < cursor銆�
+        if (baseParam.getCursor() != null) {
+            wrapper.lt(cursorColumn, baseParam.getCursor());
+        }
+
+        // 寮哄埗鎸夋父鏍囧瓧娈靛�掑簭鎺掑簭锛屼繚璇佹瘡涓�椤电殑鏁版嵁椤哄簭绋冲畾銆�
+        wrapper.orderByDesc(cursorColumn);
+
+        // 澶氭煡涓�鏉℃槸娓告爣鍒嗛〉鍒ゆ柇 hasNext 鐨勫父瑙佸仛娉曪細
+        // 瀹為檯瑕� 20 鏉★紝灏辨煡 21 鏉★紱澶氬嚭鏉ラ偅涓�鏉″彧鐢ㄦ潵鍒ゆ柇鏄惁杩樻湁涓嬩竴椤点��
+        Page<T> queryPage = new Page<>(1L, pageSize + 1L, false);
+        List<T> records = service.page(queryPage, wrapper).getRecords();
+        List<T> pageRecords = Cools.isEmpty(records) ? new ArrayList<>() : new ArrayList<>(records);
+
+        // 濡傛灉鏌ュ嚭鏉ョ殑鏁伴噺澶т簬 pageSize锛岃鏄庤嚦灏戣繕鏈変笅涓�椤点��
+        boolean hasNext = pageRecords.size() > pageSize;
+        if (hasNext) {
+            // 鍙妸鐪熸闇�瑕佽繑鍥炵粰鍓嶇鐨� pageSize 鏉℃暟鎹暀鍦ㄥ綋鍓嶉〉銆�
+            pageRecords = new ArrayList<>(pageRecords.subList(0, pageSize));
+        }
+
+        // 缁欎笟鍔′晶涓�涓�滅粨鏋滃嚭搴撳墠澶勭悊鈥濈殑鏈轰細銆�
+        // 鍏稿瀷鍦烘櫙鏄壒閲忚ˉ鍏呯敤鎴峰悕銆佸瓧鍏告枃鏈�佺紦瀛樺瓧娈电瓑锛�
+        // 杩欐牱鍏叡鍒嗛〉閫昏緫涓嶅叧蹇冧笟鍔$粏鑺傦紝浣嗕笟鍔′篃涓嶉渶瑕佸洖鍒� controller 鑷繁閲嶅啓鍒嗛〉銆�
+        if (recordsConsumer != null && !Cools.isEmpty(pageRecords)) {
+            recordsConsumer.accept(pageRecords);
+        }
+
+        CursorPageResult<T> result = new CursorPageResult<>();
+        result.setRecords(pageRecords);
+        result.setPageSize(pageSize);
+        result.setHasNext(hasNext);
+        // nextCursor 鍙湁鍦ㄨ繕鏈変笅涓�椤垫椂鎵嶆湁鎰忎箟锛�
+        // 绾﹀畾鍙栤�滃綋鍓嶉〉鏈�鍚庝竴鏉¤褰曗�濈殑娓告爣瀛楁鍊笺��
+        result.setNextCursor(hasNext ? extractCursorValue(pageRecords, cursorField) : null);
+        return result;
+    }
+
+    /**
+     * 缁熶竴瑙f瀽褰撳墠鎺ュ彛瀹為檯浣跨敤鐨� pageSize銆�
+     *
+     * <p>鍙鍓嶇娌′紶銆佷紶浜� 0銆佹垨鑰呬紶浜嗚礋鏁帮紝灏卞洖閫�鍒� controller 浼犲叆鐨勯粯璁ゅ�笺��</p>
+     */
+    private int resolveCursorPageSize(Integer pageSize, int defaultPageSize) {
+        if (pageSize == null || pageSize <= 0) {
+            return defaultPageSize;
+        }
+        return pageSize;
+    }
+
+    /**
+     * 鎶婂疄浣撳瓧娈靛悕杞崲鎴愭暟鎹簱鍒楀悕銆�
+     *
+     * <p>渚嬪锛�</p>
+     * <ul>
+     *     <li>{@code id -> `id`}</li>
+     *     <li>{@code poId -> `po_id`}</li>
+     * </ul>
+     *
+     * <p>杩欐牱 controller 璋冪敤鏃跺彧闇�瑕佸叧蹇� Java 瀛楁鍚嶏紝涓嶉渶瑕佽嚜宸辨嫾 SQL銆�</p>
+     */
+    private String resolveCursorColumn(String cursorField) {
+        return "`" + Utils.toSymbolCase(cursorField, '_') + "`";
+    }
+
+    /**
+     * 浠庡綋鍓嶉〉鏈�鍚庝竴鏉¤褰曚腑鎻愬彇 nextCursor銆�
+     *
+     * <p>杩欓噷浣跨敤鍙嶅皠鑰屼笉鏄澶栧畾涔夋帴鍙o紝鐩殑鏄檷浣庢帴鍏ユ垚鏈細
+     * 鍙瀹炰綋閲屽瓨鍦ㄥ悓鍚嶅瓧娈碉紝灏辫兘鐩存帴澶嶇敤閫氱敤鏂规硶銆�</p>
+     *
+     * <p>鏀寔鐨勫瓧娈靛�肩被鍨嬶細</p>
+     * <ul>
+     *     <li>{@link Long}</li>
+     *     <li>鍏朵粬 {@link Number}</li>
+     *     <li>鍙浆鎴� Long 鐨勫瓧绗︿覆</li>
+     * </ul>
+     *
+     * <p>濡傛灉瀛楁涓嶅瓨鍦ㄣ�佷负绌恒�佹垨鏃犳硶杞垚 Long锛屽垯杩斿洖 null銆�</p>
+     */
+    private <T> Long extractCursorValue(List<T> records, String cursorField) {
+        if (Cools.isEmpty(records)) {
+            return null;
+        }
+        T lastRecord = records.get(records.size() - 1);
+        if (lastRecord == null || Cools.isEmpty(cursorField)) {
+            return null;
+        }
+        Field field = Cools.getField(lastRecord.getClass(), cursorField);
+        if (field == null) {
+            return null;
+        }
+        boolean accessible = field.isAccessible();
+        try {
+            field.setAccessible(true);
+            Object value = field.get(lastRecord);
+            if (value instanceof Long) {
+                return (Long) value;
+            }
+            if (value instanceof Number) {
+                return ((Number) value).longValue();
+            }
+            if (value instanceof String && !((String) value).trim().isEmpty()) {
+                return Long.parseLong(((String) value).trim());
+            }
+        } catch (IllegalAccessException | NumberFormatException ignored) {
+            return null;
+        } finally {
+            field.setAccessible(accessible);
+        }
+        return null;
+    }
+
 }
 
diff --git a/rsf-server/src/main/resources/mapper/manager/AsnOrderMapper.xml b/rsf-server/src/main/resources/mapper/manager/AsnOrderMapper.xml
index 01399ca..24ded44 100644
--- a/rsf-server/src/main/resources/mapper/manager/AsnOrderMapper.xml
+++ b/rsf-server/src/main/resources/mapper/manager/AsnOrderMapper.xml
@@ -1,17 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.vincent.rsf.server.manager.mapper.AsnOrderMapper">
-    <select id="getDashbord" resultType="com.vincent.rsf.server.manager.controller.dto.DashboardDto">
-        SELECT
-            ( SELECT COUNT( 1 ) FROM man_asn_order WHERE DATE(create_time) = CURRENT_DATE()  AND `type` = #{type} ) AS anfme,
-            COUNT( id ) AS real_anfme
-        FROM
-            man_task_log
-        WHERE
-            DATE(create_time) = CURRENT_DATE()
-          AND task_type = #{taskType}
-    </select>
-
     <select id="getStockTrand" resultType="com.vincent.rsf.server.manager.controller.dto.StockTransItemDto">
         SELECT * FROM
             (
@@ -26,11 +15,12 @@
                 FROM
                     view_stock_statistic
                 WHERE
+                    task_type IN (1, 101)
+                  AND
                     `day_time` BETWEEN ( CURDATE() - INTERVAL 1 MONTH )
                         AND CURDATE()
                 GROUP BY
                     `day_time`, task_type,id
             ) t
-        ${ew.customSqlSegment}
     </select>
 </mapper>

--
Gitblit v1.9.1