Files
ai-xiaocai/server/public/js/purchases.js
2026-07-28 17:12:30 +08:00

157 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 采购相关功能
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 = '<p style="text-align:center;color:#888;padding:40px;">暂无采购记录</p>'; 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 += `<div class="purchase-month-group"><div class="purchase-month-header"><span>${month}</span><span>¥${monthTotal}</span></div>`;
monthItems.forEach(item => {
const timeShort = item.created_at.split(' ')[1]?.substring(0,5) || '';
const dateShort = item.created_at.split(' ')[0]?.substring(5) || '';
html += `
<div class="purchase-item" onclick="openDetail('${item.id}')">
<div class="item-main"><span class="item-name">${escapeHtml(item.item)}</span><span class="item-amount">¥${item.amount}</span></div>
<div class="item-meta">
<span>${dateShort} ${timeShort}</span>
<span>×${item.quantity} ${item.invoice_type !== '无票' ? '· ' + item.invoice_type : ''}</span>
<span class="status-badge ${item.status==='已完成'?'done':''}">${item.status}</span>
</div>
</div>`;
});
html += '</div>';
});
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();
document.getElementById('detail-title').textContent = p.item;
let attachHtml = '';
if (p.attachments?.length) attachHtml = '<div class="attachments">' + p.attachments.map(a => `<img class="img-thumb" src="${a.file_path}" alt="${a.file_path}" ondblclick="onImgThumbDblClick(this)">`).join('') + '</div>';
const historyHtml = p.history?.map(h => `<li><span class="history-time">${h.timestamp}</span> ${h.user}: ${h.action}</li>`).join('') || '';
document.getElementById('detail-content').innerHTML = `
<div class="detail-row"><strong>数量:</strong>${p.quantity}</div>
<div class="detail-row"><strong>单价:</strong>¥${p.unit_price}</div>
<div class="detail-row"><strong>邮费:</strong>¥${p.freight}</div>
<div class="detail-row"><strong>总金额:</strong>¥${p.amount}</div>
<div class="detail-row"><strong>付款方式:</strong>${p.payment_method || '未指定'}</div>
<div class="detail-row"><strong>发票:</strong>${p.invoice_type || '无票'}</div>
<div class="detail-row"><strong>状态:</strong>${p.status}</div>
<div class="detail-row"><strong>申请人:</strong>${p.applicant}</div>
<div class="detail-row"><strong>采购时间:</strong>${p.created_at}</div>
<div class="detail-row"><strong>备注:</strong>${p.remarks || '无'}</div>
${attachHtml}
<h4 style="margin-top:12px;">操作历史</h4>
<ul class="history-list">${historyHtml}</ul>`;
document.getElementById('detail-modal').classList.remove('hidden');
}
function closeDetailModal() { document.getElementById('detail-modal').classList.add('hidden'); }
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 = '<p>暂无采购记录</p>';
else {
summary.forEach(s => {
html += `<div class="summary-card" onclick="event.stopPropagation(); closeDetailModal(); openPurchasePage('${s.room_id}')" style="margin:8px 0;"><h4>${escapeHtml(s.room_name)}</h4><p>${s.purchase_count} 条,合计 ¥${s.total_amount}</p></div>`;
});
}
document.getElementById('detail-title').textContent = '采购汇总';
document.getElementById('detail-content').innerHTML = html;
document.getElementById('detail-modal').classList.remove('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 chatPage = document.getElementById('chat-page');
let startX = 0;
chatPage.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }, { passive: true });
chatPage.addEventListener('touchend', (e) => {
if (!startX) return;
const endX = e.changedTouches[0].clientX;
const diffX = endX - startX;
if (diffX > 50) backToPurchase();
startX = 0;
}, { passive: true });
}