Compare commits

...

3 Commits

Author SHA1 Message Date
bac5e0a26a fix: 手机左右滑动切换 tab 不生效
All checks were successful
PR Preview / test (pull_request) Has been skipped
Deploy Production / test (push) Successful in 7s
PR Preview / teardown-preview (pull_request) Successful in 14s
PR Preview / deploy-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 6s
Test / build-check (push) Successful in 4s
Deploy Production / deploy (push) Successful in 6s
Test / e2e-test (push) Successful in 3m1s
- 加 touch-action: pan-y 阻止浏览器抢占水平手势
- 用 touchmove 实时跟踪手指位置(比 touchend.changedTouches 更可靠)
- 用 touchstart 的 target 判断 no-swipe 区域(手指移动后 target 可能变)
- 弹窗/遮罩层打开时跳过滑动切换
- 阈值从 50px 调到 60px 减少误触

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 13:34:48 +00:00
b429cd1264 ci: retrigger after CI backend crash
Some checks failed
PR Preview / test (pull_request) Has been skipped
Deploy Production / test (push) Successful in 6s
PR Preview / teardown-preview (pull_request) Successful in 13s
PR Preview / deploy-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 3s
Deploy Production / deploy (push) Successful in 5s
Test / e2e-test (push) Failing after 6m1s
2026-04-16 11:32:43 +00:00
5bc3600384 fix: 精油价目 Excel 导出补全所有卡片字段
Some checks failed
Test / unit-test (push) Successful in 7s
PR Preview / teardown-preview (pull_request) Has been skipped
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 6s
PR Preview / deploy-preview (pull_request) Successful in 14s
Test / e2e-test (push) Failing after 45s
列:功效、使用方法、使用方式(香薰/涂抹/内用)、注意事项

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:18:12 +00:00
2 changed files with 28 additions and 13 deletions

View File

@@ -38,7 +38,7 @@
</div> </div>
<!-- Main content --> <!-- Main content -->
<div class="main" @touchstart="onSwipeStart" @touchend="onSwipeEnd"> <div class="main" @touchstart.passive="onSwipeStart" @touchmove.passive="onSwipeMove" @touchend="onSwipeEnd" style="touch-action: pan-y">
<router-view /> <router-view />
</div> </div>
@@ -167,23 +167,36 @@ function toggleUserMenu() {
} }
// ── 左右滑动切换 tab ── // ── 左右滑动切换 tab ──
// 滑动顺序 = visibleTabs 的顺序(根据用户角色动态决定) // touch-action: pan-y on .main tells the browser to only handle vertical scroll natively,
// 轮播区域data-no-tab-swipe内的滑动不触发 tab 切换 // leaving horizontal swipe gestures to our JS handler.
const swipeStartX = ref(0) const swipeStartX = ref(0)
const swipeStartY = ref(0) const swipeStartY = ref(0)
const swipeEndX = ref(0)
const swipeEndY = ref(0)
const swipeStartTarget = ref(null)
function onSwipeStart(e) { function onSwipeStart(e) {
swipeStartX.value = e.touches[0].clientX swipeStartX.value = e.touches[0].clientX
swipeStartY.value = e.touches[0].clientY swipeStartY.value = e.touches[0].clientY
swipeEndX.value = e.touches[0].clientX
swipeEndY.value = e.touches[0].clientY
swipeStartTarget.value = e.target
} }
function onSwipeEnd(e) { function onSwipeMove(e) {
const dx = e.changedTouches[0].clientX - swipeStartX.value swipeEndX.value = e.touches[0].clientX
const dy = e.changedTouches[0].clientY - swipeStartY.value swipeEndY.value = e.touches[0].clientY
// 必须是水平滑动 > 50px且水平距离大于垂直距离 }
if (Math.abs(dx) < 50 || Math.abs(dy) > Math.abs(dx)) return
// 轮播区域内不触发 tab 切换 function onSwipeEnd() {
if (e.target.closest && e.target.closest('[data-no-tab-swipe]')) return const dx = swipeEndX.value - swipeStartX.value
const dy = swipeEndY.value - swipeStartY.value
// Must be primarily horizontal (>60px) and more horizontal than vertical
if (Math.abs(dx) < 60 || Math.abs(dy) > Math.abs(dx)) return
// Carousel area excluded
if (swipeStartTarget.value?.closest?.('[data-no-tab-swipe]')) return
// Skip when modal/overlay is open
if (document.querySelector('.modal-overlay, .detail-overlay, .dialog-overlay')) return
const tabs = visibleTabs.value.map(t => t.key) const tabs = visibleTabs.value.map(t => t.key)
const currentIdx = tabs.indexOf(ui.currentSection) const currentIdx = tabs.indexOf(ui.currentSection)
@@ -193,8 +206,7 @@ function onSwipeEnd(e) {
if (dx < 0 && currentIdx < tabs.length - 1) nextIdx = currentIdx + 1 if (dx < 0 && currentIdx < tabs.length - 1) nextIdx = currentIdx + 1
else if (dx > 0 && currentIdx > 0) nextIdx = currentIdx - 1 else if (dx > 0 && currentIdx > 0) nextIdx = currentIdx - 1
if (nextIdx >= 0) { if (nextIdx >= 0) {
const tab = visibleTabs.value[nextIdx] handleTabClick(visibleTabs.value[nextIdx])
handleTabClick(tab)
} }
} }

View File

@@ -913,12 +913,15 @@ async function exportExcel() {
'容量': vol, '容量': vol,
'单价': ppdNum ? `¥${ppdNum.toFixed(2)}/${unit}` : '', '单价': ppdNum ? `¥${ppdNum.toFixed(2)}/${unit}` : '',
'功效': card?.effects || '', '功效': card?.effects || '',
'使用方法': card?.usage || '',
'使用方式': card?.method || '',
'注意事项': card?.caution || '',
'状态': meta.isActive === false ? '下架' : '在售', '状态': meta.isActive === false ? '下架' : '在售',
}) })
} }
const ws = XLSX.utils.json_to_sheet(rows) const ws = XLSX.utils.json_to_sheet(rows)
ws['!cols'] = [{ wch: 16 }, { wch: 28 }, { wch: 10 }, { wch: 10 }, { wch: 12 }, { wch: 16 }, { wch: 40 }, { wch: 8 }] ws['!cols'] = [{ wch: 16 }, { wch: 28 }, { wch: 10 }, { wch: 10 }, { wch: 12 }, { wch: 16 }, { wch: 40 }, { wch: 40 }, { wch: 20 }, { wch: 24 }, { wch: 8 }]
const wb = XLSX.utils.book_new() const wb = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(wb, ws, '精油价目表') XLSX.utils.book_append_sheet(wb, ws, '精油价目表')
XLSX.writeFile(wb, `精油价目表${dateStr}.xlsx`) XLSX.writeFile(wb, `精油价目表${dateStr}.xlsx`)