backup codes

This commit is contained in:
2026-07-28 18:38:11 +08:00
parent 3f9f95b5ef
commit 2964917c14
3 changed files with 99 additions and 64 deletions

View File

@@ -112,9 +112,9 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-
.detail-modal { max-height: 90vh; overflow-y: auto; padding: 0; } .detail-modal { max-height: 90vh; overflow-y: auto; padding: 0; }
.detail-modal input, .detail-modal select, .detail-modal textarea { margin: 0; } .detail-modal input, .detail-modal select, .detail-modal textarea { margin: 0; }
.detail-header { background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); color: #fff; padding: 8px 12px 8px 16px; display: flex; align-items: center; gap: 8px; position: sticky; top: 0; z-index: 1; } .detail-header { background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); color: #fff; padding: 8px 12px 8px 16px; display: flex; align-items: center; gap: 8px; position: sticky; top: 0; z-index: 1; }
.detail-header .icon-btn { flex-shrink: 0; margin-left: auto; } .detail-header .icon-btn { padding:0; margin-right:0; flex-shrink: 0; margin-left: auto; }
.detail-header .icon-btn svg { stroke: #fff; } .detail-header .icon-btn svg { stroke: #fff; }
.detail-title-input { flex: 1; font-size: 18px; font-weight: 600; color: #fff; background: transparent; border: none; outline: none; padding: 4px 0; min-width: 0; } .modal .detail-title-input { flex: 1; font-size: 18px; font-weight: 600; color: #fff; background: transparent; border: none; outline: none; padding: 4px 0; min-width: 0; }
.detail-title-input::placeholder { color: rgba(255,255,255,0.6); } .detail-title-input::placeholder { color: rgba(255,255,255,0.6); }
.detail-title-input:focus { border: none; outline: none; } .detail-title-input:focus { border: none; outline: none; }
.edit-form { padding: 12px 16px 16px 16px; } .edit-form { padding: 12px 16px 16px 16px; }
@@ -127,6 +127,13 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-
.amount-row { font-weight: 600; } .amount-row { font-weight: 600; }
.amount-row label { color: #333; } .amount-row label { color: #333; }
.edit-amount { flex: 1; font-size: 17px; color: #e53e3e; font-weight: 700; } .edit-amount { flex: 1; font-size: 17px; color: #e53e3e; font-weight: 700; }
.edit-group { margin-bottom: 8px; }
.edit-group-summary { display: flex; align-items: center; gap: 8px; padding: 7px 0; cursor: pointer; border-bottom: 1px solid #f0f0f0; }
.edit-group-summary label { min-width: 48px; font-size: 13px; color: #777; text-align: right; flex-shrink: 0; }
.edit-group-summary span { flex: 1; font-size: 14px; color: #333; }
.group-arrow { width: 14px; height: 14px; stroke: #aaa; fill: none; stroke-width: 2; flex-shrink: 0; }
.edit-group-detail { padding: 4px 0; }
.edit-group-detail .edit-row { margin-bottom: 4px; }
.edit-section { margin-top: 8px; border-top: 1px solid #eee; padding-top: 8px; } .edit-section { margin-top: 8px; border-top: 1px solid #eee; padding-top: 8px; }
.edit-section-header { font-size: 13px; font-weight: 600; color: #555; cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 2px 0; } .edit-section-header { font-size: 13px; font-weight: 600; color: #555; cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 2px 0; }
.edit-section-header svg { width: 16px; height: 16px; stroke: #888; fill: none; stroke-width: 2; } .edit-section-header svg { width: 16px; height: 16px; stroke: #888; fill: none; stroke-width: 2; }
@@ -137,7 +144,7 @@ details[open] .history-summary::after { content: '收起'; }
.attach-gallery { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; } .attach-gallery { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.attach-thumb-wrap { position: relative; display: inline-block; } .attach-thumb-wrap { position: relative; display: inline-block; }
.attach-thumb { width: 56px; height: 56px; object-fit: cover; border-radius: 6px; border: 1px solid #eee; } .attach-thumb { width: 56px; height: 56px; object-fit: cover; border-radius: 6px; border: 1px solid #eee; }
.attach-del-btn { position: absolute; top: -4px; right: -4px; width: 18px; height: 18px; border-radius: 50%; background: rgba(0,0,0,0.5); border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; } .attach-gallery .attach-del-btn { position: absolute; top: -4px; right: -4px; width: 18px; height: 18px; border-radius: 50%; background: rgba(0,0,0,0.5); border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }
.attach-del-btn svg { width: 10px; height: 10px; stroke: #fff; fill: none; stroke-width: 2.5; } .attach-del-btn svg { width: 10px; height: 10px; stroke: #fff; fill: none; stroke-width: 2.5; }
.attach-add-btn { cursor: pointer; display: flex; align-items: center; } .attach-add-btn { cursor: pointer; display: flex; align-items: center; }
.attach-add-btn svg { width: 18px; height: 18px; stroke: #3b82f6; fill: none; stroke-width: 2; } .attach-add-btn svg { width: 18px; height: 18px; stroke: #3b82f6; fill: none; stroke-width: 2; }

View File

@@ -151,36 +151,49 @@
</button> </button>
</div> </div>
<div class="edit-form"> <div class="edit-form">
<div class="edit-row"> <!-- 金额组:折叠 -->
<label>数量</label><input type="number" id="edit-quantity" inputmode="decimal" min="0" step="1"> <div class="edit-group">
<div class="edit-group-summary" onclick="toggleEditGroup('amount-group')">
<label>金额</label>
<span id="amount-summary">0</span>
<svg class="group-arrow" viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"></polyline></svg>
</div>
<div class="edit-group-detail hidden" id="amount-group">
<div class="edit-row"><label>数量</label><input type="number" id="edit-quantity" inputmode="decimal" min="0" step="1" oninput="updateAmountSummary()"></div>
<div class="edit-row"><label>单价</label><input type="number" id="edit-unit-price" inputmode="decimal" min="0" step="0.01" oninput="updateAmountSummary()"></div>
<div class="edit-row"><label>邮费</label><input type="number" id="edit-freight" inputmode="decimal" min="0" step="0.01" oninput="updateAmountSummary()"></div>
</div>
</div> </div>
<div class="edit-row">
<label>单价</label><input type="number" id="edit-unit-price" inputmode="decimal" min="0" step="0.01"> <!-- 状态组:折叠 -->
</div> <div class="edit-group">
<div class="edit-row"> <div class="edit-group-summary" onclick="toggleEditGroup('status-group')">
<label>邮费</label><input type="number" id="edit-freight" inputmode="decimal" min="0" step="0.01"> <label>状态</label>
</div> <span id="status-summary">待付款</span>
<div class="edit-row amount-row"> <svg class="group-arrow" viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"></polyline></svg>
<label>金额</label><span class="edit-amount" id="edit-amount">0</span> </div>
</div> <div class="edit-group-detail hidden" id="status-group">
<div class="edit-row"> <div class="edit-row">
<label>付款</label> <label>付款</label>
<select id="edit-payment-method"> <select id="edit-payment-method" onchange="updateStatusSummary()">
<option>未指定</option><option>支付宝</option><option>微信</option><option>银行卡</option><option>现金</option><option>对公转账</option> <option>未指定</option><option>支付宝</option><option>微信</option><option>银行卡</option><option>现金</option><option>对公转账</option>
</select> </select>
</div> </div>
<div class="edit-row"> <div class="edit-row">
<label>发票</label> <label>发票</label>
<select id="edit-invoice-type"> <select id="edit-invoice-type" onchange="updateStatusSummary()">
<option>无票</option><option>普票</option><option>专票</option> <option>无票</option><option>普票</option><option>专票</option>
</select> </select>
</div> </div>
<div class="edit-row"> <div class="edit-row">
<label>状态</label> <label>状态</label>
<select id="edit-status"> <select id="edit-status" onchange="updateStatusSummary()">
<option>待付款</option><option>已付款</option><option>已收货</option><option>已完成</option> <option>待付款</option><option>已付款</option><option>已收货</option><option>已完成</option>
</select> </select>
</div>
</div>
</div> </div>
<div class="edit-row"> <div class="edit-row">
<label>申请人</label><input type="text" id="edit-applicant"> <label>申请人</label><input type="text" id="edit-applicant">
</div> </div>
@@ -235,12 +248,6 @@
if (e.target.id === 'msg-input' && e.key === 'Enter' && !e.ctrlKey) { e.preventDefault(); sendMessage(); } if (e.target.id === 'msg-input' && e.key === 'Enter' && !e.ctrlKey) { e.preventDefault(); sendMessage(); }
if (e.target.id === 'purchase-msg-input' && e.key === 'Enter' && !e.ctrlKey) { e.preventDefault(); sendFromPurchase(); } if (e.target.id === 'purchase-msg-input' && e.key === 'Enter' && !e.ctrlKey) { e.preventDefault(); sendFromPurchase(); }
}); });
// 实时计算金额
document.addEventListener('input', function(e) {
if (['edit-quantity','edit-unit-price','edit-freight'].includes(e.target.id)) {
updateEditAmount();
}
});
init(); init();
</script> </script>
</body> </body>

View File

@@ -31,7 +31,7 @@ function renderPurchasePanel(items) {
<div class="item-main"><span class="item-name">${escapeHtml(item.item)}</span><span class="item-amount">${item.amount}</span></div> <div class="item-main"><span class="item-name">${escapeHtml(item.item)}</span><span class="item-amount">${item.amount}</span></div>
<div class="item-meta"> <div class="item-meta">
<span>${dateShort} ${timeShort}</span> <span>${dateShort} ${timeShort}</span>
<span>${item.quantity} ${item.invoice_type !== '无票' ? '· ' + item.invoice_type : ''}</span> <span>${item.quantity} ${item.invoice_type !== '无票' ? '\u00b7 ' + item.invoice_type : ''}</span>
<span class="status-badge ${item.status==='已完成'?'done':''}">${item.status}</span> <span class="status-badge ${item.status==='已完成'?'done':''}">${item.status}</span>
</div> </div>
</div>`; </div>`;
@@ -44,7 +44,7 @@ function renderPurchasePanel(items) {
function formatMonth(dateStr) { function formatMonth(dateStr) {
const clean = dateStr.replace(/-/g, '/'); const clean = dateStr.replace(/-/g, '/');
const parts = clean.split('/'); const parts = clean.split('/');
if (parts.length >= 2) return parts[0] + '' + parseInt(parts[1], 10) + ''; if (parts.length >= 2) return parts[0] + '\u5e74' + parseInt(parts[1], 10) + '\u6708';
return dateStr.substring(0,7); return dateStr.substring(0,7);
} }
@@ -60,10 +60,11 @@ async function openDetail(pid) {
document.getElementById('edit-quantity').value = p.quantity || 0; document.getElementById('edit-quantity').value = p.quantity || 0;
document.getElementById('edit-unit-price').value = p.unit_price || 0; document.getElementById('edit-unit-price').value = p.unit_price || 0;
document.getElementById('edit-freight').value = p.freight || 0; document.getElementById('edit-freight').value = p.freight || 0;
updateEditAmount(); updateAmountSummary();
document.getElementById('edit-payment-method').value = p.payment_method || '未指定'; document.getElementById('edit-payment-method').value = p.payment_method || '\u672a\u6307\u5b9a';
document.getElementById('edit-invoice-type').value = p.invoice_type || '无票'; document.getElementById('edit-invoice-type').value = p.invoice_type || '\u65e0\u7968';
document.getElementById('edit-status').value = p.status || '待付款'; document.getElementById('edit-status').value = p.status || '\u5f85\u4ed8\u6b3e';
updateStatusSummary();
document.getElementById('edit-applicant').value = p.applicant || ''; document.getElementById('edit-applicant').value = p.applicant || '';
document.getElementById('edit-time').value = p.created_at || ''; document.getElementById('edit-time').value = p.created_at || '';
document.getElementById('edit-remarks').value = p.remarks || ''; document.getElementById('edit-remarks').value = p.remarks || '';
@@ -89,6 +90,9 @@ async function openDetail(pid) {
delBtn.style.marginLeft = '0'; delBtn.style.marginLeft = '0';
} }
// 折叠所有编辑组
document.querySelectorAll('.edit-group-detail').forEach(el => el.classList.add('hidden'));
document.getElementById('detail-modal').classList.remove('hidden'); document.getElementById('detail-modal').classList.remove('hidden');
} }
@@ -108,11 +112,32 @@ function renderEditAttachments(attachments) {
).join(''); ).join('');
} }
function updateEditAmount() { function updateAmountSummary() {
const q = parseFloat(document.getElementById('edit-quantity').value) || 0; const q = parseFloat(document.getElementById('edit-quantity').value) || 0;
const up = parseFloat(document.getElementById('edit-unit-price').value) || 0; const up = parseFloat(document.getElementById('edit-unit-price').value) || 0;
const f = parseFloat(document.getElementById('edit-freight').value) || 0; const f = parseFloat(document.getElementById('edit-freight').value) || 0;
document.getElementById('edit-amount').textContent = (q * up + f).toFixed(2); const total = (q * up + f).toFixed(2);
document.getElementById('amount-summary').textContent = total + ', \u6570\u91cf' + q + ', \u5355\u4ef7' + up + ', \u90ae\u8d39' + f;
}
function updateStatusSummary() {
const pm = document.getElementById('edit-payment-method').value;
const iv = document.getElementById('edit-invoice-type').value;
const st = document.getElementById('edit-status').value;
document.getElementById('status-summary').textContent = st + ', ' + pm + ', ' + iv;
}
function toggleEditGroup(groupId) {
const detail = document.getElementById(groupId);
const summary = detail.previousElementSibling;
const isOpen = !detail.classList.contains('hidden');
if (isOpen) {
detail.classList.add('hidden');
summary.classList.remove('hidden');
} else {
detail.classList.remove('hidden');
summary.classList.add('hidden');
}
} }
async function savePurchase() { async function savePurchase() {
@@ -140,13 +165,13 @@ async function savePurchase() {
closeDetailModal(); closeDetailModal();
loadPurchases(); loadPurchases();
} else { } else {
alert('保存失败:' + (result.error || '未知错误')); alert('\u4fdd\u5b58\u5931\u8d25\uff1a' + (result.error || '\u672a\u77e5\u9519\u8bef'));
} }
} }
async function deletePurchaseDetail() { async function deletePurchaseDetail() {
if (!editPid) return; if (!editPid) return;
if (!confirm('确定要删除此采购记录吗?')) return; if (!confirm('\u786e\u5b9a\u8981\u5220\u9664\u6b64\u91c7\u8d2d\u8bb0\u5f55\u5417\uff1f')) return;
const token = Store.getToken(); const token = Store.getToken();
const res = await fetch('/api/purchases/' + editPid, { const res = await fetch('/api/purchases/' + editPid, {
method: 'DELETE', method: 'DELETE',
@@ -157,14 +182,14 @@ async function deletePurchaseDetail() {
loadPurchases(); loadPurchases();
} else { } else {
const err = await res.json(); const err = await res.json();
alert('删除失败:' + (err.error || '未知错误')); alert('\u5220\u9664\u5931\u8d25\uff1a' + (err.error || '\u672a\u77e5\u9519\u8bef'));
} }
} }
async function deleteAttachment(event, encodedPath) { async function deleteAttachment(event, encodedPath) {
event.stopPropagation(); event.stopPropagation();
const filePath = decodeURIComponent(encodedPath); const filePath = decodeURIComponent(encodedPath);
if (!confirm('确定删除此附件吗?')) return; if (!confirm('\u786e\u5b9a\u5220\u9664\u6b64\u9644\u4ef6\u5417\uff1f')) return;
const token = Store.getToken(); const token = Store.getToken();
const res = await fetch('/api/purchases/' + editPid + '/attachments', { const res = await fetch('/api/purchases/' + editPid + '/attachments', {
method: 'DELETE', method: 'DELETE',
@@ -172,7 +197,6 @@ async function deleteAttachment(event, encodedPath) {
body: JSON.stringify({ file_path: filePath }) body: JSON.stringify({ file_path: filePath })
}); });
if (res.ok) { if (res.ok) {
// 重新加载详情
openDetail(editPid); openDetail(editPid);
} }
} }
@@ -199,7 +223,7 @@ async function handleDetailFileUpload(event) {
}); });
openDetail(editPid); openDetail(editPid);
} }
} catch(e) { alert('上传失败,请重试'); } } catch(e) { alert('\u4e0a\u4f20\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5'); }
} }
function closeDetailModal() { function closeDetailModal() {
@@ -222,14 +246,13 @@ async function handlePurchaseFileSelect(event) {
const data = await res.json(); const data = await res.json();
if (data.path) Store.pendingUploads.push(data.path); if (data.path) Store.pendingUploads.push(data.path);
} }
} catch(e) { alert('图片上传失败'); } } catch(e) { alert('\u56fe\u7247\u4e0a\u4f20\u5931\u8d25'); }
} }
function sendFromPurchase() { function sendFromPurchase() {
const input = document.getElementById('purchase-msg-input'); const input = document.getElementById('purchase-msg-input');
const text = input.value.trim(); const text = input.value.trim();
if (!text && Store.pendingUploads.length === 0) return; if (!text && Store.pendingUploads.length === 0) return;
// 记录文本,跳转到聊天页面后发送
Store.pendingPurchaseText = text; Store.pendingPurchaseText = text;
input.value = ''; input.value = '';
openChatFromPurchase(); openChatFromPurchase();
@@ -242,13 +265,13 @@ async function openSummary() {
const res = await fetch('/api/summary', { headers: { 'Authorization': 'Bearer ' + token } }); const res = await fetch('/api/summary', { headers: { 'Authorization': 'Bearer ' + token } });
const summary = await res.json(); const summary = await res.json();
let html = ''; let html = '';
if (summary.length === 0) html = '<p>暂无采购记录</p>'; if (summary.length === 0) html = '<p>\u6682\u65e0\u91c7\u8d2d\u8bb0\u5f55</p>';
else { else {
summary.forEach(s => { summary.forEach(s => {
html += '<div class="summary-card" onclick="event.stopPropagation(); closeSummaryModal(); openPurchasePage(\'' + s.room_id + '\')" style="margin:8px 0;"><h4>' + escapeHtml(s.room_name) + '</h4><p>' + s.purchase_count + ' 条,合计 ' + s.total_amount + '</p></div>'; html += '<div class="summary-card" onclick="event.stopPropagation(); closeSummaryModal(); openPurchasePage(\'' + s.room_id + '\')" style="margin:8px 0;"><h4>' + escapeHtml(s.room_name) + '</h4><p>' + s.purchase_count + ' \u6761\uff0c\u5408\u8ba1 ' + s.total_amount + '</p></div>';
}); });
} }
document.getElementById('summary-title').textContent = '采购汇总'; document.getElementById('summary-title').textContent = '\u91c7\u8d2d\u6c47\u603b';
document.getElementById('summary-content').innerHTML = html; document.getElementById('summary-content').innerHTML = html;
document.getElementById('summary-modal').classList.remove('hidden'); document.getElementById('summary-modal').classList.remove('hidden');
} }
@@ -259,7 +282,7 @@ function openCreateRoom() { document.getElementById('create-modal').classList.re
function closeCreateModal() { document.getElementById('create-modal').classList.add('hidden'); } function closeCreateModal() { document.getElementById('create-modal').classList.add('hidden'); }
async function confirmCreateRoom() { async function confirmCreateRoom() {
const name = document.getElementById('new-room-name').value.trim(); const name = document.getElementById('new-room-name').value.trim();
if (!name) return alert('请输入名称'); if (!name) return alert('\u8bf7\u8f93\u5165\u540d\u79f0');
const whiteList = document.getElementById('white-list').value.trim(); const whiteList = document.getElementById('white-list').value.trim();
const token = Store.getToken(); const token = Store.getToken();
await fetch('/api/rooms', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify({ name, whiteList }) }); await fetch('/api/rooms', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify({ name, whiteList }) });
@@ -270,7 +293,7 @@ async function confirmCreateRoom() {
function openManageRoom(roomId) { function openManageRoom(roomId) {
const room = Store.rooms.find(r => r.id === roomId); const room = Store.rooms.find(r => r.id === roomId);
if (!room) return; if (!room) return;
document.getElementById('manage-title').textContent = '编辑群聊'; document.getElementById('manage-title').textContent = '\u7f16\u8f91\u7fa4\u804a';
document.getElementById('manage-room-name').value = room.name; document.getElementById('manage-room-name').value = room.name;
document.getElementById('manage-white-list').value = room.white_list || ''; document.getElementById('manage-white-list').value = room.white_list || '';
document.getElementById('manage-modal').dataset.roomId = roomId; document.getElementById('manage-modal').dataset.roomId = roomId;
@@ -283,18 +306,18 @@ async function saveRoom() {
const roomId = document.getElementById('manage-modal').dataset.roomId; const roomId = document.getElementById('manage-modal').dataset.roomId;
const name = document.getElementById('manage-room-name').value.trim(); const name = document.getElementById('manage-room-name').value.trim();
const whiteList = document.getElementById('manage-white-list').value.trim(); const whiteList = document.getElementById('manage-white-list').value.trim();
if (!name) return alert('请输入群聊名称'); if (!name) return alert('\u8bf7\u8f93\u5165\u7fa4\u804a\u540d\u79f0');
const token = Store.getToken(); const token = Store.getToken();
const res = await fetch('/api/rooms/' + roomId, { const res = await fetch('/api/rooms/' + roomId, {
method: 'PUT', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, method: 'PUT', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
body: JSON.stringify({ name, whiteList }) body: JSON.stringify({ name, whiteList })
}); });
if (res.ok) { closeManageModal(); loadRooms(); } if (res.ok) { closeManageModal(); loadRooms(); }
else { const err = await res.json(); alert(err.error || '更新失败'); } else { const err = await res.json(); alert(err.error || '\u66f4\u65b0\u5931\u8d25'); }
} }
async function deleteRoom() { async function deleteRoom() {
if (!confirm('确定要删除该群聊吗?所有消息和采购数据将被永久删除。')) return; if (!confirm('\u786e\u5b9a\u8981\u5220\u9664\u8be5\u7fa4\u804a\u5417\uff1f\u6240\u6709\u6d88\u606f\u548c\u91c7\u8d2d\u6570\u636e\u5c06\u88ab\u6c38\u4e45\u5220\u9664\u3002')) return;
const roomId = document.getElementById('manage-modal').dataset.roomId; const roomId = document.getElementById('manage-modal').dataset.roomId;
const token = Store.getToken(); const token = Store.getToken();
const res = await fetch('/api/rooms/' + roomId, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token } }); const res = await fetch('/api/rooms/' + roomId, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token } });
@@ -302,7 +325,7 @@ async function deleteRoom() {
closeManageModal(); closeManageModal();
loadRooms(); loadRooms();
if (Store.currentRoom === roomId) showList(); if (Store.currentRoom === roomId) showList();
} else { const err = await res.json(); alert(err.error || '删除失败'); } } else { const err = await res.json(); alert(err.error || '\u5220\u9664\u5931\u8d25'); }
} }
// ============ 滑动手势 ============ // ============ 滑动手势 ============
@@ -312,7 +335,6 @@ function initSwipeGestures() {
const chatPage = document.getElementById('chat-page'); const chatPage = document.getElementById('chat-page');
let startX = 0; let startX = 0;
// 采购页:右滑回列表,左滑进聊天
purchasePage.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }, { passive: true }); purchasePage.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }, { passive: true });
purchasePage.addEventListener('touchend', (e) => { purchasePage.addEventListener('touchend', (e) => {
if (!startX) return; if (!startX) return;
@@ -324,7 +346,6 @@ function initSwipeGestures() {
startX = 0; startX = 0;
}, { passive: true }); }, { passive: true });
// 聊天页:左右滑回采购页
chatPage.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }, { passive: true }); chatPage.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }, { passive: true });
chatPage.addEventListener('touchend', (e) => { chatPage.addEventListener('touchend', (e) => {
if (!startX) return; if (!startX) return;