// 采购相关功能 let editPid = null; // 当前正在编辑的采购ID async function loadPurchases() { if (!Store.currentRoom) return; const token = Store.getToken(); const res = await fetch('/api/rooms/' + Store.currentRoom + '/purchases', { headers: { 'Authorization': 'Bearer ' + token } }); const items = await res.json(); renderPurchasePanel(items); } function renderPurchasePanel(items) { const container = document.getElementById('purchase-panel-body'); if (items.length === 0) { container.innerHTML = '

暂无采购记录

'; return; } const groups = {}; items.forEach(item => { const month = formatMonth(item.created_at); if (!groups[month]) groups[month] = []; groups[month].push(item); }); let html = ''; Object.keys(groups).sort().reverse().forEach(month => { const monthItems = groups[month]; const monthTotal = monthItems.reduce((s, i) => s + (i.amount||0), 0); html += '
' + month + '' + monthTotal + '
'; monthItems.forEach(item => { const timeShort = item.created_at.split(' ')[1]?.substring(0,5) || ''; const dateShort = item.created_at.split(' ')[0]?.substring(5) || ''; html += `
${escapeHtml(item.item)}${item.amount}
${dateShort} ${timeShort} ${item.quantity} ${item.invoice_type !== '无票' ? '· ' + item.invoice_type : ''} ${item.status}
`; }); html += '
'; }); container.innerHTML = html; } function formatMonth(dateStr) { const clean = dateStr.replace(/-/g, '/'); const parts = clean.split('/'); if (parts.length >= 2) return parts[0] + '年' + parseInt(parts[1], 10) + '月'; return dateStr.substring(0,7); } // ============ 可编辑详情弹窗 ============ async function openDetail(pid) { const token = Store.getToken(); const res = await fetch('/api/purchases/' + pid, { headers: { 'Authorization': 'Bearer ' + token } }); const p = await res.json(); editPid = pid; document.getElementById('edit-item').value = p.item || ''; document.getElementById('edit-quantity').value = p.quantity || 0; document.getElementById('edit-unit-price').value = p.unit_price || 0; document.getElementById('edit-freight').value = p.freight || 0; updateEditAmount(); document.getElementById('edit-payment-method').value = p.payment_method || '未指定'; document.getElementById('edit-invoice-type').value = p.invoice_type || '无票'; document.getElementById('edit-status').value = p.status || '待付款'; document.getElementById('edit-applicant').value = p.applicant || ''; document.getElementById('edit-time').value = p.created_at || ''; document.getElementById('edit-remarks').value = p.remarks || ''; // 附件 renderEditAttachments(p.attachments || []); // 操作历史 const historyHtml = (p.history || []).map(h => '
  • ' + h.timestamp + ' ' + escapeHtml(h.user) + ': ' + escapeHtml(h.action) + '
  • ' ).join(''); document.getElementById('edit-history').innerHTML = historyHtml || '
  • 暂无操作记录
  • '; document.getElementById('edit-history-section').open = false; // 删除按钮仅管理员可见 const isAdmin = localStorage.getItem('isAdmin') === 'true'; document.getElementById('delete-purchase-btn').style.display = isAdmin ? '' : 'none'; document.getElementById('detail-modal').classList.remove('hidden'); } function renderEditAttachments(attachments) { const container = document.getElementById('edit-attachments'); if (!attachments || attachments.length === 0) { container.innerHTML = '暂无附件'; return; } container.innerHTML = attachments.map(a => '
    ' + '' + '' + '
    ' ).join(''); } function updateEditAmount() { const q = parseFloat(document.getElementById('edit-quantity').value) || 0; const up = parseFloat(document.getElementById('edit-unit-price').value) || 0; const f = parseFloat(document.getElementById('edit-freight').value) || 0; document.getElementById('edit-amount').textContent = (q * up + f).toFixed(2); } async function savePurchase() { if (!editPid) return; const token = Store.getToken(); const body = { item: document.getElementById('edit-item').value, quantity: parseFloat(document.getElementById('edit-quantity').value) || 0, unit_price: parseFloat(document.getElementById('edit-unit-price').value) || 0, freight: parseFloat(document.getElementById('edit-freight').value) || 0, payment_method: document.getElementById('edit-payment-method').value, invoice_type: document.getElementById('edit-invoice-type').value, status: document.getElementById('edit-status').value, applicant: document.getElementById('edit-applicant').value, remarks: document.getElementById('edit-remarks').value, created_at: document.getElementById('edit-time').value }; const res = await fetch('/api/purchases/' + editPid, { method: 'PUT', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); const result = await res.json(); if (result.success) { closeDetailModal(); loadPurchases(); } else { alert('保存失败:' + (result.error || '未知错误')); } } async function deletePurchaseDetail() { if (!editPid) return; if (!confirm('确定要删除此采购记录吗?')) return; const token = Store.getToken(); const res = await fetch('/api/purchases/' + editPid, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token } }); if (res.ok) { closeDetailModal(); loadPurchases(); } else { const err = await res.json(); alert('删除失败:' + (err.error || '未知错误')); } } async function deleteAttachment(event, encodedPath) { event.stopPropagation(); const filePath = decodeURIComponent(encodedPath); if (!confirm('确定删除此附件吗?')) return; const token = Store.getToken(); const res = await fetch('/api/purchases/' + editPid + '/attachments', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify({ file_path: filePath }) }); if (res.ok) { // 重新加载详情 openDetail(editPid); } } async function handleDetailFileUpload(event) { const files = event.target.files; if (!files.length) return; const token = Store.getToken(); const paths = []; try { for (let file of files) { let blob = file; if (file.size > 1 * 1024 * 1024) blob = await compressImage(file); const formData = new FormData(); formData.append('file', blob, file.name || 'image.jpg'); const res = await fetch('/api/upload', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token }, body: formData }); const data = await res.json(); if (data.path) paths.push(data.path); } if (paths.length) { await fetch('/api/purchases/' + editPid + '/attachments', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify({ file_paths: paths }) }); openDetail(editPid); } } catch(e) { alert('上传失败,请重试'); } } function closeDetailModal() { document.getElementById('detail-modal').classList.add('hidden'); editPid = null; } // ============ 采购页面输入区 ============ async function handlePurchaseFileSelect(event) { const files = event.target.files; if (!files.length) return; const token = Store.getToken(); try { for (let file of files) { let blob = file; if (file.size > 1 * 1024 * 1024) blob = await compressImage(file); const formData = new FormData(); formData.append('file', blob, file.name || 'image.jpg'); const res = await fetch('/api/upload', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token }, body: formData }); const data = await res.json(); if (data.path) Store.pendingUploads.push(data.path); } } catch(e) { alert('图片上传失败'); } } function sendFromPurchase() { const input = document.getElementById('purchase-msg-input'); const text = input.value.trim(); if (!text && Store.pendingUploads.length === 0) return; // 记录文本,跳转到聊天页面后发送 Store.pendingPurchaseText = text; input.value = ''; openChatFromPurchase(); } // ============ 汇总 & 群聊管理 ============ async function openSummary() { const token = Store.getToken(); const res = await fetch('/api/summary', { headers: { 'Authorization': 'Bearer ' + token } }); const summary = await res.json(); let html = ''; if (summary.length === 0) html = '

    暂无采购记录

    '; else { summary.forEach(s => { html += '

    ' + escapeHtml(s.room_name) + '

    ' + s.purchase_count + ' 条,合计 ' + s.total_amount + '

    '; }); } document.getElementById('summary-title').textContent = '采购汇总'; document.getElementById('summary-content').innerHTML = html; document.getElementById('summary-modal').classList.remove('hidden'); } function closeSummaryModal() { document.getElementById('summary-modal').classList.add('hidden'); } function openCreateRoom() { document.getElementById('create-modal').classList.remove('hidden'); } function closeCreateModal() { document.getElementById('create-modal').classList.add('hidden'); } async function confirmCreateRoom() { const name = document.getElementById('new-room-name').value.trim(); if (!name) return alert('请输入名称'); const whiteList = document.getElementById('white-list').value.trim(); const token = Store.getToken(); await fetch('/api/rooms', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify({ name, whiteList }) }); closeCreateModal(); loadRooms(); } function openManageRoom(roomId) { const room = Store.rooms.find(r => r.id === roomId); if (!room) return; document.getElementById('manage-title').textContent = '编辑群聊'; document.getElementById('manage-room-name').value = room.name; document.getElementById('manage-white-list').value = room.white_list || ''; document.getElementById('manage-modal').dataset.roomId = roomId; document.getElementById('manage-modal').classList.remove('hidden'); } function closeManageModal() { document.getElementById('manage-modal').classList.add('hidden'); } async function saveRoom() { const roomId = document.getElementById('manage-modal').dataset.roomId; const name = document.getElementById('manage-room-name').value.trim(); const whiteList = document.getElementById('manage-white-list').value.trim(); if (!name) return alert('请输入群聊名称'); const token = Store.getToken(); const res = await fetch('/api/rooms/' + roomId, { method: 'PUT', headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, body: JSON.stringify({ name, whiteList }) }); if (res.ok) { closeManageModal(); loadRooms(); } else { const err = await res.json(); alert(err.error || '更新失败'); } } async function deleteRoom() { if (!confirm('确定要删除该群聊吗?所有消息和采购数据将被永久删除。')) return; const roomId = document.getElementById('manage-modal').dataset.roomId; const token = Store.getToken(); const res = await fetch('/api/rooms/' + roomId, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token } }); if (res.ok) { closeManageModal(); loadRooms(); if (Store.currentRoom === roomId) showList(); } else { const err = await res.json(); alert(err.error || '删除失败'); } } // ============ 滑动手势 ============ function initSwipeGestures() { const purchasePage = document.getElementById('purchase-page'); const chatPage = document.getElementById('chat-page'); let startX = 0; // 采购页:右滑回列表,左滑进聊天 purchasePage.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }, { passive: true }); purchasePage.addEventListener('touchend', (e) => { if (!startX) return; const diffX = e.changedTouches[0].clientX - startX; if (Math.abs(diffX) > 50) { if (diffX > 30) showList(); else if (diffX < -30) openChatFromPurchase(); } startX = 0; }, { passive: true }); // 聊天页:左右滑回采购页 chatPage.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }, { passive: true }); chatPage.addEventListener('touchend', (e) => { if (!startX) return; const diffX = e.changedTouches[0].clientX - startX; if (Math.abs(diffX) > 50) backToPurchase(); startX = 0; }, { passive: true }); }