This commit is contained in:
2026-07-28 19:26:26 +08:00
parent 2e9da6c1ac
commit 05266703e8
5 changed files with 64 additions and 57 deletions

View File

@@ -1,12 +1,19 @@
// 采购相关路由
const express = require('express');
const { authMiddleware, adminOnly } = require('../middleware/auth');
const { authMiddleware } = require('../middleware/auth');
const { broadcastToRoom } = require('../ws');
const db = require('../db');
const { timestamp } = require('../utils');
const router = express.Router();
function insertChatMsg(roomId, user, text) {
const now = timestamp();
const result = db.prepare('INSERT INTO messages (room_id, user, text, timestamp) VALUES (?,?,?,?)').run(roomId, user, text, now);
const msg = { id: result.lastInsertRowid, room_id: roomId, user, text, attachments: [], timestamp: now };
broadcastToRoom(roomId, { type: 'new_message', message: msg });
}
router.get('/rooms/:roomId/purchases', authMiddleware, (req, res) => {
const purchases = db.prepare('SELECT * FROM purchases WHERE room_id = ? ORDER BY created_at DESC').all(req.params.roomId);
res.json(purchases);
@@ -14,7 +21,7 @@ router.get('/rooms/:roomId/purchases', authMiddleware, (req, res) => {
router.get('/purchases/:id', authMiddleware, (req, res) => {
const pur = db.prepare('SELECT * FROM purchases WHERE id = ?').get(req.params.id);
if (!pur) return res.status(404).json({ error: '未找到' });
if (!pur) return res.status(404).json({ error: '\u672a\u627e\u5230' });
const history = db.prepare('SELECT * FROM purchase_history WHERE purchase_id = ? ORDER BY id ASC').all(req.params.id);
const attachments = db.prepare('SELECT * FROM purchase_attachments WHERE purchase_id = ?').all(req.params.id);
res.json({ ...pur, history, attachments });
@@ -23,7 +30,7 @@ router.get('/purchases/:id', authMiddleware, (req, res) => {
// 更新采购记录
router.put('/purchases/:id', authMiddleware, (req, res) => {
const old = db.prepare('SELECT * FROM purchases WHERE id = ?').get(req.params.id);
if (!old) return res.status(404).json({ error: '未找到' });
if (!old) return res.status(404).json({ error: '\u672a\u627e\u5230' });
const now = timestamp();
const username = req.user.username;
@@ -44,21 +51,22 @@ router.put('/purchases/:id', authMiddleware, (req, res) => {
newVals.amount = newVals.quantity * newVals.unit_price + newVals.freight;
const fieldLabels = {
item: '物品', quantity: '数量', unit_price: '单价', freight: '邮费', amount: '金额',
payment_method: '付款方式', invoice_type: '发票', status: '状态', applicant: '申请人', remarks: '备注', created_at: '时间'
item: '\u7269\u54c1', quantity: '\u6570\u91cf', unit_price: '\u5355\u4ef7', freight: '\u90ae\u8d39', amount: '\u91d1\u989d',
payment_method: '\u4ed8\u6b3e\u65b9\u5f0f', invoice_type: '\u53d1\u7968', status: '\u72b6\u6001', applicant: '\u7533\u8bf7\u4eba', remarks: '\u5907\u6ce8', created_at: '\u65f6\u95f4'
};
const changes = [];
for (const [field, label] of Object.entries(fieldLabels)) {
if (String(newVals[field]) !== String(old[field])) {
changes.push(label + ': ' + (old[field] || '') + ' -> ' + newVals[field]);
changes.push(label + ': ' + (old[field] || '\u7a7a') + ' \u2192 ' + newVals[field]);
db.prepare('UPDATE purchases SET ' + field + ' = ? WHERE id = ?').run(newVals[field], old.id);
}
}
if (changes.length > 0) {
db.prepare('UPDATE purchases SET updated_at = ? WHERE id = ?').run(now, old.id);
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(old.id, '更新:' + changes.join(''), username, now);
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(old.id, '\u66f4\u65b0\uff1a' + changes.join('\uff1b'), username, now);
insertChatMsg(old.room_id, '\u5c0f\u8d22', '\ud83d\udd04 ' + username + ' \u66f4\u65b0\u4e86\u91c7\u8d2d\u300c' + newVals.item + '\u300d\uff1a' + changes.join('\uff0c'));
broadcastToRoom(old.room_id, { type: 'purchase_updated' });
res.json({ success: true, changes });
} else {
@@ -66,13 +74,16 @@ router.put('/purchases/:id', authMiddleware, (req, res) => {
}
});
// 删除采购记录(管理员)
router.delete('/purchases/:id', authMiddleware, adminOnly, (req, res) => {
// 删除采购记录
router.delete('/purchases/:id', authMiddleware, (req, res) => {
const pur = db.prepare('SELECT * FROM purchases WHERE id = ?').get(req.params.id);
if (!pur) return res.status(404).json({ error: '未找到' });
if (!pur) return res.status(404).json({ error: '\u672a\u627e\u5230' });
const username = req.user.username;
const itemName = pur.item;
db.prepare('DELETE FROM purchase_attachments WHERE purchase_id = ?').run(pur.id);
db.prepare('DELETE FROM purchase_history WHERE purchase_id = ?').run(pur.id);
db.prepare('DELETE FROM purchases WHERE id = ?').run(pur.id);
insertChatMsg(pur.room_id, '\u5c0f\u8d22', '\ud83d\uddd1 ' + username + ' \u5220\u9664\u4e86\u91c7\u8d2d\u8bb0\u5f55\u300c' + itemName + '\u300d');
broadcastToRoom(pur.room_id, { type: 'purchase_updated' });
res.json({ success: true });
});
@@ -80,26 +91,26 @@ router.delete('/purchases/:id', authMiddleware, adminOnly, (req, res) => {
// 管理附件
router.post('/purchases/:id/attachments', authMiddleware, (req, res) => {
const pur = db.prepare('SELECT * FROM purchases WHERE id = ?').get(req.params.id);
if (!pur) return res.status(404).json({ error: '未找到' });
if (!pur) return res.status(404).json({ error: '\u672a\u627e\u5230' });
const now = timestamp();
const username = req.user.username;
const { file_paths } = req.body;
if (!file_paths || !file_paths.length) return res.status(400).json({ error: '缺少文件路径' });
if (!file_paths || !file_paths.length) return res.status(400).json({ error: '\u7f3a\u5c11\u6587\u4ef6\u8def\u5f84' });
const insertAttach = db.prepare('INSERT INTO purchase_attachments (purchase_id, file_path, uploaded_by, timestamp) VALUES (?,?,?,?)');
file_paths.forEach(fp => insertAttach.run(pur.id, fp, username, now));
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(pur.id, '添加附件:' + file_paths.length + ' ', username, now);
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(pur.id, '\u6dfb\u52a0\u9644\u4ef6\uff1a' + file_paths.length + ' \u4e2a', username, now);
broadcastToRoom(pur.room_id, { type: 'purchase_updated' });
res.json({ success: true });
});
router.delete('/purchases/:id/attachments', authMiddleware, (req, res) => {
const pur = db.prepare('SELECT * FROM purchases WHERE id = ?').get(req.params.id);
if (!pur) return res.status(404).json({ error: '未找到' });
if (!pur) return res.status(404).json({ error: '\u672a\u627e\u5230' });
const username = req.user.username;
const { file_path } = req.body;
if (!file_path) return res.status(400).json({ error: '缺少文件路径' });
if (!file_path) return res.status(400).json({ error: '\u7f3a\u5c11\u6587\u4ef6\u8def\u5f84' });
db.prepare('DELETE FROM purchase_attachments WHERE purchase_id = ? AND file_path = ?').run(pur.id, file_path);
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(pur.id, '删除附件:' + file_path.split('/').pop(), username, timestamp());
db.prepare('INSERT INTO purchase_history (purchase_id, action, user, timestamp) VALUES (?,?,?,?)').run(pur.id, '\u5220\u9664\u9644\u4ef6\uff1a' + file_path.split('/').pop(), username, timestamp());
broadcastToRoom(pur.room_id, { type: 'purchase_updated' });
res.json({ success: true });
});
@@ -122,7 +133,7 @@ router.get('/summary', authMiddleware, (req, res) => {
router.get('/rooms/:roomId/purchases/export', authMiddleware, (req, res) => {
const purchases = db.prepare('SELECT * FROM purchases WHERE room_id = ?').all(req.params.roomId);
let csv = '时间,事项,数量,单价,金额,邮费,付款方式,发票类型,状态,申请人,备注\n';
let csv = '\u65f6\u95f4,\u4e8b\u9879,\u6570\u91cf,\u5355\u4ef7,\u91d1\u989d,\u90ae\u8d39,\u4ed8\u6b3e\u65b9\u5f0f,\u53d1\u7968\u7c7b\u578b,\u72b6\u6001,\u7533\u8bf7\u4eba,\u5907\u6ce8\n';
purchases.forEach(p => {
csv += p.created_at + ',"' + (p.item||'') + '",' + p.quantity + ',' + p.unit_price + ',' + p.amount + ',' + p.freight + ',"' + (p.payment_method||'') + '","' + (p.invoice_type||'') + '","' + p.status + '","' + p.applicant + '","' + (p.remarks||'') + '"\n';
});