feat(admin): 店铺数据重复检查撞款抽屉样式优化与导入测试按钮
Build Backend JAR / build (push) Has been cancelled

- 撞款详情抽屉:上架时间默认降序(晚到早)、去掉列头(按时间升序)小括号、加宽至 760px、
  去掉全屏遮罩(底层仍可点击)、抽屉贴到「撞款详情」区块位置而非浏览器顶部
- 修复抽屉 fixed 定位失效:.tab-panel.active 入场动画带 transform 会成为包含块,
  打开时把 drawer mask 挂到 body 下恢复视口定位
- 新增导入(新增-测试)/ 导入(删除-测试)按钮与上传弹窗,对应后端端点
  /api/admin/shop-data-crawl/duplicate-check-import(ADD=按店名替换基线记录、DELETE=移除该店记录)
- 新增 ShopDataDuplicateCheckImportService 导入服务(复用 WorkbookParser/Aggregator,与扫描共用 Redis 锁)
- 新增 3 个单测:导入替换重聚合、删除移除、无基线报错
- _preview_mock.py 加入 .gitignore(本地预览工具不入库)
This commit is contained in:
2026-09-04 12:25:31 +08:00
parent 8241cd704e
commit 05bda8915a
8 changed files with 766 additions and 130 deletions
+30 -1
View File
@@ -4647,6 +4647,9 @@
.drawer-mask { display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(45, 66, 86, 0.36); backdrop-filter: blur(4px); }
.drawer-mask.show { display: block; animation: modal-fade-in 0.16s ease; }
.drawer { position: absolute; top: 0; right: 0; bottom: 0; display: flex; flex-direction: column; width: min(460px, 100%); background: #ffffff; border-left: 1px solid #c7d7e5; box-shadow: var(--shadow-pop); animation: drawer-slide-in 0.18s ease; }
/* 撞款明细抽屉:无遮罩图层(底层仍可点击) + 加宽 + 从撞款详情块位置开始 */
.dup-drawer-mask { background: none; backdrop-filter: none; pointer-events: none; z-index: 990; }
.dup-drawer-mask .drawer { pointer-events: auto; top: 24px; right: 24px; bottom: 24px; width: min(760px, calc(100% - 48px)); max-width: 860px; border-radius: 12px; border: 1px solid #dbe4ec; box-shadow: 0 14px 44px rgba(15, 42, 65, 0.22); }
@keyframes drawer-slide-in { from { transform: translateX(26px); opacity: 0.4; } to { transform: none; opacity: 1; } }
.drawer-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 20px 22px 14px; border-bottom: 1px solid #e6edf4; }
.drawer-header h3 { margin: 0; font-size: 15px; font-weight: 600; color: var(--c-text); }
@@ -5673,6 +5676,8 @@
<button class="btn shop-data-refresh-btn" id="btnRefreshShopDataDuplicates"
type="button">重新分析</button>
<button class="btn btn-secondary" id="btnExportShopDataDuplicates" type="button">导出</button>
<button class="btn btn-secondary" id="btnOpenDupCheckImportAdd" type="button">导入(新增-测试)</button>
<button class="btn btn-secondary" id="btnOpenDupCheckImportDelete" type="button">导入(删除-测试)</button>
<span class="image-video-download-progress" id="shopDataDuplicateProgress"
aria-live="polite"></span>
</div>
@@ -5689,7 +5694,7 @@
<div class="dup-check-detail-cards" id="dupCheckDetailCards"></div>
<div class="pagination" id="dupCheckDetailPagination" style="margin-top:12px;"></div>
</div>
<div class="drawer-mask" id="dupCheckDrawerMask">
<div class="drawer-mask dup-drawer-mask" id="dupCheckDrawerMask" data-drawer-anchor="dupCheckDetailBlock">
<aside class="drawer" role="dialog" aria-modal="true" aria-label="ASIN 详情">
<div class="drawer-header">
<div>
@@ -5702,6 +5707,30 @@
<div class="drawer-body" id="dupCheckDrawerBody"></div>
</aside>
</div>
<!-- 撞款:导入(新增-测试)/导入(删除-测试)弹窗 -->
<div class="modal-mask" id="dupCheckImportModal">
<div class="modal">
<h3 id="dupCheckImportTitle">导入(新增-测试)</h3>
<div class="form-group">
<label>店铺名称(新增=以导入文件替换该店记录;删除=从基线移除该店)</label>
<input type="text" id="dupCheckImportShopName" placeholder="如:小曾">
</div>
<div class="form-group">
<label>国家代码(可选,逗号分隔,如 UK,DE。缺失时按 Excel 的 sheet 名推断)</label>
<input type="text" id="dupCheckImportCountryCodes" placeholder="如:UK,DE">
</div>
<div class="form-group">
<label>上传 Excel 文件(读取 ASIN 列,可含 日期/价格/品牌 列)</label>
<input type="file" id="dupCheckImportFile" accept=".xlsx,.xls">
</div>
<p class="msg" id="msgDupCheckImport"></p>
<div style="margin-top:16px;display:flex;gap:8px;">
<button class="btn" id="btnDupCheckImportSubmit">上传并导入</button>
<button class="btn btn-secondary" id="btnCloseDupCheckImportModal" type="button">取消</button>
</div>
</div>
</div>
</div>
</div>
</div>