备份:修复前完整项目快照 2026-04-19
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
const express = require('express');
|
||||
const db = require('../db');
|
||||
const { authenticate, requireAdmin } = require('../middleware/auth');
|
||||
const LedgerService = require('../services/ledgerService');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const result = await db.query(`
|
||||
SELECT * FROM customers
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 50
|
||||
`);
|
||||
|
||||
// 为每个客户获取联系人和收款信息
|
||||
const customersWithDetails = await Promise.all(
|
||||
result.rows.map(async (customer) => {
|
||||
// 获取联系人信息
|
||||
const contactsResult = await db.query(
|
||||
`SELECT * FROM contacts WHERE entity_id = $1 AND entity_type = 'customer' ORDER BY is_primary DESC`,
|
||||
[customer.id]
|
||||
);
|
||||
|
||||
const contacts = contactsResult.rows.map(contact => ({
|
||||
name: contact.name || '未命名',
|
||||
position: contact.position || '',
|
||||
phone: contact.phone || '',
|
||||
is_primary: contact.is_primary === 1
|
||||
}));
|
||||
|
||||
// 获取收款信息
|
||||
const paymentInfosResult = await db.query(
|
||||
`SELECT * FROM supplier_payment_infos WHERE supplier_id = $1 ORDER BY is_default DESC`,
|
||||
[customer.id]
|
||||
);
|
||||
|
||||
const paymentInfos = paymentInfosResult.rows.map(payment => ({
|
||||
id: payment.id,
|
||||
account_name: payment.account_name,
|
||||
bank_account: payment.account_number,
|
||||
bank_name: payment.bank_name,
|
||||
qr_code: payment.qr_code,
|
||||
is_primary: payment.is_default === 1
|
||||
}));
|
||||
|
||||
return {
|
||||
...customer,
|
||||
contacts: contacts.length > 0 ? contacts : [],
|
||||
payment_infos: paymentInfos.length > 0 ? paymentInfos : []
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: customersWithDetails,
|
||||
count: customersWithDetails.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取客户失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取客户失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
// 获取客户基本信息
|
||||
const customerResult = await db.query(`
|
||||
SELECT * FROM customers
|
||||
WHERE id = ?
|
||||
`, [id]);
|
||||
|
||||
if (customerResult.rows.length > 0) {
|
||||
const customer = customerResult.rows[0];
|
||||
|
||||
// 获取客户的所有联系人
|
||||
const contactsResult = await db.query(`
|
||||
SELECT * FROM contacts
|
||||
WHERE entity_id = ? AND entity_type = 'customer'
|
||||
ORDER BY is_primary DESC
|
||||
`, [id]);
|
||||
|
||||
// 转换联系人数据结构
|
||||
const contacts = contactsResult.rows.map(contact => ({
|
||||
name: contact.name || '未命名',
|
||||
position: contact.position || '',
|
||||
phone: contact.phone || '',
|
||||
is_primary: contact.is_primary === 1
|
||||
}));
|
||||
|
||||
// 获取客户的所有收款信息
|
||||
const paymentInfosResult = await db.query(`
|
||||
SELECT * FROM supplier_payment_infos
|
||||
WHERE supplier_id = ?
|
||||
ORDER BY is_default DESC
|
||||
`, [id]);
|
||||
|
||||
// 转换收款信息数据结构
|
||||
const payment_infos = paymentInfosResult.rows.map(info => ({
|
||||
id: info.id,
|
||||
account_name: info.account_name || '',
|
||||
bank_name: info.bank_name || '',
|
||||
bank_account: info.account_number || '',
|
||||
qr_code: info.qr_code || '',
|
||||
is_primary: info.is_default === 1
|
||||
}));
|
||||
|
||||
const ledger = await LedgerService.getCustomerLedger(id);
|
||||
|
||||
const formattedCustomer = {
|
||||
id: customer.id,
|
||||
code: `C${String(customer.id).padStart(4, '0')}`,
|
||||
name: customer.name,
|
||||
address: customer.address,
|
||||
contacts: contacts.length > 0 ? contacts : [],
|
||||
payment_infos: payment_infos.length > 0 ? payment_infos : [],
|
||||
remark: customer.remark || '',
|
||||
total_contract_amount: ledger.summary.total_contract_amount,
|
||||
total_received: ledger.summary.total_received_amount,
|
||||
total_receivable: ledger.summary.total_receivable_amount,
|
||||
ledger: ledger,
|
||||
created_at: customer.created_at
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: formattedCustomer
|
||||
});
|
||||
} else {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
message: '客户不存在'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取客户详情失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取客户详情失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
const { name, address, remark, contacts, payment_infos } = req.body;
|
||||
|
||||
// 从contacts中获取主联系人信息
|
||||
const primaryContact = contacts?.find(c => c.is_primary) || contacts?.[0];
|
||||
const contact = primaryContact?.name || '';
|
||||
const position = primaryContact?.position || '';
|
||||
const phone = primaryContact?.phone || '';
|
||||
const email = ''; // 前端没有email字段
|
||||
|
||||
const result = await db.query(
|
||||
`INSERT INTO customers (name, address, contact, position, phone, email, remark, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
[name, address, contact, position, phone, email, remark]
|
||||
);
|
||||
|
||||
const customerId = (result.rows[0]?.id || result.rows?.[0]?.id);
|
||||
|
||||
// 插入联系人数据
|
||||
if (contacts && contacts.length > 0) {
|
||||
for (const contactItem of contacts) {
|
||||
await db.query(
|
||||
`INSERT INTO contacts (entity_id, entity_type, name, position, phone, is_primary, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
[customerId, 'customer', contactItem.name, contactItem.position, contactItem.phone, contactItem.is_primary ? 1 : 0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 插入收款信息数据
|
||||
if (payment_infos && payment_infos.length > 0) {
|
||||
for (const paymentItem of payment_infos) {
|
||||
await db.query(
|
||||
`INSERT INTO supplier_payment_infos (supplier_id, account_name, bank_name, bank_account, qr_code, is_primary, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
[customerId, paymentItem.account_name, paymentItem.bank_name, paymentItem.bank_account, paymentItem.qr_code, paymentItem.is_primary ? 1 : 0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '客户创建成功',
|
||||
data: {
|
||||
id: customerId,
|
||||
code: `C${String(customerId).padStart(4, '0')}`,
|
||||
name,
|
||||
address,
|
||||
contacts: contacts || [],
|
||||
payment_infos: payment_infos || [],
|
||||
remark,
|
||||
total_contract_amount: 0,
|
||||
total_received: 0,
|
||||
total_receivable: 0,
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建客户失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '创建客户失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { name, address, remark, contacts, payment_infos } = req.body;
|
||||
|
||||
// 从contacts中获取主联系人信息
|
||||
const primaryContact = contacts?.find(c => c.is_primary) || contacts?.[0];
|
||||
const contact = primaryContact?.name || '';
|
||||
const position = primaryContact?.position || '';
|
||||
const phone = primaryContact?.phone || '';
|
||||
const email = ''; // 前端没有email字段
|
||||
|
||||
await db.query(
|
||||
`UPDATE customers
|
||||
SET name = ?, address = ?, contact = ?, position = ?, phone = ?, email = ?, remark = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?`,
|
||||
[name, address, contact, position, phone, email, remark, id]
|
||||
);
|
||||
|
||||
// 删除旧的联系人数据
|
||||
await db.query(`DELETE FROM contacts WHERE entity_id = $1 AND entity_type = 'customer'`, [id]);
|
||||
|
||||
// 插入新的联系人数据
|
||||
if (contacts && contacts.length > 0) {
|
||||
for (const contactItem of contacts) {
|
||||
await db.query(
|
||||
`INSERT INTO contacts (entity_id, entity_type, name, position, phone, is_primary, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
[id, 'customer', contactItem.name, contactItem.position, contactItem.phone, contactItem.is_primary ? 1 : 0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除旧的收款信息数据
|
||||
await db.query(`DELETE FROM supplier_payment_infos WHERE supplier_id = $1`, [id]);
|
||||
|
||||
// 插入新的收款信息数据
|
||||
if (payment_infos && payment_infos.length > 0) {
|
||||
for (const paymentItem of payment_infos) {
|
||||
await db.query(
|
||||
`INSERT INTO supplier_payment_infos (supplier_id, account_name, bank_name, bank_account, qr_code, is_primary, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
|
||||
[id, paymentItem.account_name, paymentItem.bank_name, paymentItem.bank_account, paymentItem.qr_code, paymentItem.is_primary ? 1 : 0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '客户更新成功',
|
||||
data: {
|
||||
id,
|
||||
code: `C${String(id).padStart(4, '0')}`,
|
||||
name,
|
||||
address,
|
||||
contacts: contacts || [],
|
||||
payment_infos: payment_infos || [],
|
||||
remark,
|
||||
total_contract_amount: 0,
|
||||
total_received: 0,
|
||||
total_receivable: 0,
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新客户失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '更新客户失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
// 先删除关联的联系人数据
|
||||
await db.query(`DELETE FROM contacts WHERE entity_id = $1 AND entity_type = 'customer'`, [id]);
|
||||
|
||||
// 再删除客户数据
|
||||
const result = await db.query(`DELETE FROM customers WHERE id = $1`, [id]);
|
||||
|
||||
if (result.changes > 0) {
|
||||
res.json({
|
||||
success: true,
|
||||
message: '客户删除成功'
|
||||
});
|
||||
} else {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
message: '客户不存在'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除客户失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '删除客户失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user