Explorar o código

fix: 仓储看板筛选默认值与下钻继承修复

- 首页仓库默认全部授权仓库、基本单位默认取后端 defaultUnit(KG)
- 下钻明细继承首页当前筛选;返回首页按快照还原,列表筛选不再反写首页
- 筛选键统一预置空串,修复下钻页仓库/物料下拉渲染为空白
- 「查询」在参数未变时强制刷新,避免路由去重导致按钮无响应
- 修复下钻/业务页内容不足一屏时下方露白(布局链深色 + 内容区拉伸)
- 标题带间距与标题框尺寸微调,主标题字号 23px
lihaiting hai 11 horas
pai
achega
b8f20f6cf0

+ 15 - 4
src/views/warehouseManagement/index/dashboard-theme.scss

@@ -58,7 +58,7 @@
 
 /* 大屏标题带:居中六边形科技框 + 两侧光翼与菱形(HR overview-title 同款结构)。
    2026-10-30 用户确认:去掉顶部英文眉题行(Warehouse Data Center),只留主标题。 */
-.screen-band{margin:0 -20px 16px;padding:22px 20px 18px;position:relative;display:flex;align-items:center;justify-content:center;gap:16px;text-align:center;}
+.screen-band{margin:0 -20px 6px;padding:18px 20px 12px;position:relative;display:flex;align-items:center;justify-content:center;gap:16px;text-align:center;}
 .band-wing{display:flex;align-items:center;gap:6px;opacity:.85;}
 .band-wing i{display:block;height:2px;background:linear-gradient(90deg,transparent,var(--cyan),transparent);box-shadow:0 0 10px rgba(0,230,255,.65);animation:wms-breathe 3s ease-in-out infinite;}
 .band-wing i:nth-child(1){width:54px;}
@@ -67,7 +67,7 @@
 .band-wing.right{flex-direction:row-reverse;}
 /* 六边形标题框:HR overview-title__frame 1:1 —— 34px 斜切角 + 两端斜纹填充 + 框内菱形装饰 + 流光 */
 .band-frame{position:relative;display:flex;align-items:center;justify-content:center;
-  min-width:min(520px,78vw);min-height:58px;padding:6px 52px 8px;overflow:hidden;
+  min-width:min(520px,78vw);min-height:52px;padding:2px 52px 3px;overflow:hidden;
   background:linear-gradient(180deg, rgba(0,90,140,.55), rgba(0,28,55,.25) 55%, rgba(0,40,70,.4));
   clip-path:polygon(34px 0,calc(100% - 34px) 0,100% 50%,calc(100% - 34px) 100%,34px 100%,0 50%);
   box-shadow:0 0 0 1px rgba(0,230,255,.45) inset, 0 0 32px rgba(0,190,255,.28), 0 10px 30px rgba(0,0,0,.35);}
@@ -86,7 +86,7 @@
   transform:translateY(-50%) rotate(45deg);box-shadow:0 0 14px rgba(0,230,255,.8);animation:wms-breathe 2.8s ease-in-out infinite;}
 .band-deco.left{left:16px;}
 .band-deco.right{right:16px;animation-delay:1.2s;}
-.screen-band h1{position:relative;z-index:1;margin:0;font-size:26px;font-weight:700;letter-spacing:.32em;text-indent:.32em;color:#f2fcff;
+.screen-band h1{position:relative;z-index:1;margin:0;font-size:23px;font-weight:700;letter-spacing:.32em;text-indent:.32em;color:#f2fcff;
   text-shadow:0 0 12px rgba(0,230,255,.75), 0 0 28px rgba(0,160,255,.35);}
 .screen-band .meta{position:absolute;right:20px;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;white-space:nowrap;gap:7px;
   font-size:13px;color:var(--t2);padding:5px 12px;
@@ -425,8 +425,19 @@ table.tbl tr:hover td{background:rgba(0,200,255,.06);}
   .todo-icon svg{width:19px;height:19px;}
   .screen-band{flex-wrap:wrap;}
   .band-wing{display:none;}
-  .band-frame{min-width:min(420px,86vw);min-height:50px;padding:5px 40px 7px;}
+  .band-frame{min-width:min(520px,86vw);min-height:52px;padding:2px 40px 3px;}
   .screen-band .meta{position:static;transform:none;margin-top:10px;}
 }
 
 }
+
+/* ========== 修复:下钻/业务页内容不足一屏时下方露白 ==========
+   白底来自 ele-admin 布局根节点 .ele-admin-layout 的 $--layout-body-background;
+   .wms-home 高度只随内容撑开,矮内容页(如批次库龄明细)下面就会露出系统白底。
+   看板打开期间(body.wms-dashboard-open)把布局链背景改成看板深底色,
+   并让 .wms-home 在内容区里拉伸占满剩余高度,所有下钻视图一并生效。 */
+body.wms-dashboard-open{
+  .ele-admin-layout,.ele-admin-body,.ele-admin-content,.ele-admin-content-view{background:#00060d;}
+  .ele-admin-content-view{display:flex;flex-direction:column;}
+  .wms-home{flex:1 0 auto;min-height:100%;}
+}

+ 36 - 11
src/views/warehouseManagement/index/dashboard.vue

@@ -34,7 +34,7 @@ export default {
   name: 'WmsHome',
   components: { HomeOverview, DashboardDetail, DashboardActions },
   data() { return {
-    view: 'home', warehouseId: '', unit: '', filters: {}, options: {}, summary: {}, result: {}, updatedAt: '', error: '', loading: false, exporting: false, portalRoots: [], optionsLoaded: false, receiveQueue: [], preparedReceipts: [], receiving: false, homeLoading: true
+    view: 'home', warehouseId: '', unit: '', filters: {}, homeFilters: null, options: {}, summary: {}, result: {}, updatedAt: '', error: '', loading: false, exporting: false, portalRoots: [], optionsLoaded: false, receiveQueue: [], preparedReceipts: [], receiving: false, homeLoading: true
   }; },
   computed: {
     // 呆滞阈值向下透传:优先用首页已请求到的同一份 home-summary.stagnantDays(不额外发请求),
@@ -66,7 +66,8 @@ export default {
     this.readRoute();
     try {
       this.options = await homeOptions({ warehouseId: this.warehouseId }); this.optionsLoaded = true;
-      // 默认单位来自筛选项(后缀 defaultUnit),第一条 readRoute 时 options 还没到,这里必须再兜一次。
+      // 首页默认单位:仓库默认「全部授权仓库」,但基本单位必须默认选中后端给的 defaultUnit(当前是 KG)——
+      // 多基本单位下不选单位,库存总量/周转天数/库龄/分类分布会整片为空。首条 readRoute 时 options 还没到,这里补一次。
       this.applyDefaultUnit(Object.prototype.hasOwnProperty.call(this.$route.query, 'unit'));
       this.filters = { ...this.filters, unit: this.unit };
       await this.refresh();
@@ -86,12 +87,20 @@ export default {
       const query = this.$route.query;
       const knownView = screens[query.dashboardView] || businessViews[query.dashboardView] || query.dashboardView === 'home';
       this.view = knownView ? query.dashboardView : 'home';
-      this.filters = filterKeys.reduce((r,key) => { if (query[key] != null) r[key] = query[key]; return r; }, { ...monthRange(), page: 1 });
+      // 筛选键先统一落「空字符串 = 全部」:URL 上没有的键不能留成 undefined,
+      // 否则下钻页 select 的 v-model 匹配不上 value="" 的「全部」选项,下拉会渲染成空白(仓库/物料空白就是这么来的)。
+      const blanks = { warehouseId:'', factoryId:'', unit:'', categoryId:'', keyword:'', type:'', direction:'', stockBatchId:'', age:'', level:'', inspection:'', status:'' };
+      this.filters = filterKeys.reduce((r,key) => { if (query[key] != null) r[key] = query[key]; return r; }, { ...blanks, ...monthRange(), page: 1 });
       this.warehouseId = this.filters.warehouseId || ''; this.unit = this.filters.unit || '';
-      if (this.view === 'home') this.applyDefaultUnit(Object.prototype.hasOwnProperty.call(query, 'unit'));
+      if (this.view === 'home') {
+        // 首页默认单位兜底(仓库保持「全部授权仓库」):URL 没写 unit 时才算没表态,显式 unit=(全部单位)不动。
+        this.applyDefaultUnit(Object.prototype.hasOwnProperty.call(query, 'unit'));
+        // 首页筛选快照:只存首页真正拥有的两项(仓库/基本单位)。下钻时用它当基线带过去,
+        // 回首页时用它还原,明细里改的仓库/物料/关键词不会反写首页(单位默认值补完后才快照)。
+        this.homeFilters = { warehouseId: this.filters.warehouseId || '', unit: this.filters.unit || '' };
+      }
     },
-    // 首页默认基本单位:多基本单位下不选单位,库存总量/周转天数/库龄/分类分布会整片为空,
-    // 用户进首页看到的就是「没有数据」。优先用后端 home-options 的 defaultUnit(已按授权仓库算好),
+    // 首页默认基本单位:优先用后端 home-options 的 defaultUnit(已按授权仓库算好,当前是 KG),
     // 缺失时回退 units 里的第一个非空单位。
     defaultUnit() {
       const options = this.options || {};
@@ -107,10 +116,13 @@ export default {
       if (!unit) return;
       this.unit = unit;
       this.filters = { ...this.filters, unit };
+      // 首屏 readRoute 时 options 还没到,快照里存的是空单位;这里补完默认单位必须同步刷快照,
+      // 否则「返回首页」会从快照还原成全部单位,和首次进入的 KG 不一致。
+      if (this.view === 'home') this.homeFilters = { warehouseId: this.filters.warehouseId || '', unit };
     },
     route(view, filters, replace = false) {
       const query = cleanQuery({ ...filters, unit: filters.unit || '', dashboard: '1', dashboardView: view });
-      // 单位始终写进 query:空值也要显式落成 unit=,代表用户主动选了「全部单位」,下钻/返回时不能被默认单位覆盖。
+      // 单位始终写进 query:空值也要显式落成 unit=,代表「全部单位」,下钻/返回时不会被当成未表态。
       query.unit = filters.unit || '';
       if (this.$route.query.dashboardView === view && JSON.stringify(query) === JSON.stringify(this.$route.query)) return;
       this.$router[replace ? 'replace' : 'push']({ path: this.$route.path, query }).catch((e) => { if (e.name !== 'NavigationDuplicated') this.$message.error(e.message); });
@@ -124,7 +136,11 @@ export default {
       // 没有 extra 时 query 是 {},与改动前的「只跳转不过滤」完全等价。
       // 顺手吞掉 NavigationDuplicated:重复点击「查看台账」不应该弹错误提示。
       if (view === 'stockLedger') return this.$router.push({ path: '/warehouseManagement/stockLedger', query: cleanQuery(extra) }).catch((e) => { if (e.name !== 'NavigationDuplicated') this.$message.error(e.message); });
-      const filters = { ...this.filters, page: 1, ...extra };
+      // 首页 → 明细:筛选条原样继承首页当前的选择(仓库/单位是什么就带什么);
+      // 明细 → 首页:回到进入明细前的首页筛选快照,避免明细里选的仓库/物料/关键词反写首页,
+      // 否则下次再下钻就会带着上次列表里的筛选(「仓库/物料不是全部」就是这么来的)。
+      const base = view === 'home' ? (this.homeFilters || this.filters) : this.filters;
+      const filters = { ...base, page: 1, ...extra };
       if (view !== this.view) ['stockBatchId','age','level','inspection','type','direction'].forEach((key) => { if (!(key in extra)) delete filters[key]; });
       if (view === 'ioapp' && !filters.direction) filters.direction = 'in';
       if (['ioapp','inapp'].includes(view)) {
@@ -132,15 +148,24 @@ export default {
         // 出入库申请/入总库申请按单位过滤会把申请单筛空,这两个视图不继承首页单位。
         delete filters.categoryId; filters.unit = ''; Object.assign(filters,monthRange());
       }
-      // 回到首页时把单位补回来:上面的业务视图清了 unit,不补就会落到「全部单位」,KPI 又变成没有数据。
-      if (view === 'home' && this.view !== 'home' && !filters.unit) filters.unit = this.defaultUnit();
+      // 回到首页:按首页快照还原;只有拿不到快照(直接带 URL 进出明细页)且单位为空时才补默认单位,
+      // 用户首页显式选的「全部单位」不会被覆盖。
+      if (view === 'home' && this.view !== 'home' && !this.homeFilters && !filters.unit) filters.unit = this.defaultUnit();
       this.route(view, filters);
     },
     // 切换仓库不再清空基本单位:单位列表是「全部授权仓库」口径,与单仓无关;
     // 清空后落到「全部单位」会立刻变成没有数据,正是要避免的情况。
     setWarehouse(warehouseId) { this.route('home', { ...this.filters, warehouseId, page: 1 }); },
     setUnit(unit) { this.route('home', { ...this.filters, unit, page: 1 }); },
-    search(filters) { this.route(this.view, filters); },
+    search(filters) {
+      // 「查询」必须每次都真实生效:参数与当前 URL 完全一致时 route() 会因去重直接 return,
+      // 一个请求都不发,按钮看起来失灵。这种情况跳过路由去重,强制整页重新拉一次明细(带 loading)。
+      const query = cleanQuery({ ...filters, unit: filters.unit || '', dashboard: '1', dashboardView: this.view });
+      query.unit = filters.unit || '';
+      const same = this.$route.query.dashboardView === this.view && JSON.stringify(query) === JSON.stringify(this.$route.query);
+      if (same) return this.refresh();
+      this.route(this.view, filters);
+    },
     parameters(extra = {}) { return cleanQuery({ ...this.filters, ...extra }); },
     async refresh() {
       // 全量刷新入口:路由切换、手动重试、15 分钟定时器都会走到这里,先记录触发上下文。