const express = require('express'); const db = require('../db'); const { authenticate, requireAdmin } = require('../middleware/auth'); const router = express.Router(); router.get('/', authenticate, async (req, res) => { try { const { customer_id, status } = req.query; let query = ` SELECT b.*, c.name as customer_name, u.name as manager_name FROM budget_projects b LEFT JOIN customers c ON b.customer_id = c.id LEFT JOIN users u ON b.business_manager_id = u.id `; const params = []; const conditions = []; if (customer_id) { params.push(customer_id); conditions.push(`b.customer_id = $${params.length}`); } if (status) { params.push(status); conditions.push(`b.status = $${params.length}`); } if (conditions.length > 0) { query += ' WHERE ' + conditions.join(' AND '); } query += ' ORDER BY b.created_at DESC'; const result = await db.query(query, params); const projects = await Promise.all(result.rows.map(async (project) => { let attachments = []; let survey_photos = []; try { const attResult = await db.query( "SELECT * FROM budget_attachments WHERE budget_project_id = $1 AND file_type = 'attachment'", [project.id] ); attachments = attResult.rows.map(a => a.file_url); } catch (e) {} try { const photoResult = await db.query( "SELECT * FROM budget_attachments WHERE budget_project_id = $1 AND file_type = 'survey_photo'", [project.id] ); survey_photos = photoResult.rows.map(a => a.file_url); } catch (e) {} let quotations = []; try { const qResult = await db.query( 'SELECT * FROM budget_quotations WHERE budget_project_id = $1 ORDER BY version DESC', [project.id] ); quotations = qResult.rows; } catch (e) {} const { survey_notes, intermediary_name, intermediary_fee, business_manager_id, created_by, ...rest } = project; return { ...rest, project_overview: survey_notes || rest.project_overview, intermediary: intermediary_name, intermediary_fee_value: intermediary_fee, manager_id: business_manager_id, attachments, survey_photos, quotations }; })); res.json({ success: true, data: projects, count: projects.length }); } catch (error) { console.error('获取预算项目失败:', error); res.status(500).json({ success: false, message: '获取预算项目失败' }); } }); router.get('/:id', authenticate, async (req, res) => { try { const { id } = req.params; const result = await db.query( `SELECT b.*, c.name as customer_name, u.name as manager_name FROM budget_projects b LEFT JOIN customers c ON b.customer_id = c.id LEFT JOIN users u ON b.business_manager_id = u.id WHERE b.id = $1`, [id] ); if (result.rows.length === 0) { return res.status(404).json({ success: false, message: '项目不存在' }); } const project = result.rows[0]; let attachments = []; let survey_photos = []; try { const attResult = await db.query( "SELECT * FROM budget_attachments WHERE budget_project_id = $1 AND file_type = 'attachment'", [id] ); attachments = attResult.rows.map(a => a.file_url); } catch (e) {} try { const photoResult = await db.query( "SELECT * FROM budget_attachments WHERE budget_project_id = $1 AND file_type = 'survey_photo'", [id] ); survey_photos = photoResult.rows.map(a => a.file_url); } catch (e) {} let quotations = []; try { const qResult = await db.query( 'SELECT * FROM budget_quotations WHERE budget_project_id = $1 ORDER BY version DESC', [id] ); quotations = qResult.rows; } catch (e) {} const { survey_notes, intermediary_name, intermediary_fee, business_manager_id, created_by, ...rest } = project; res.json({ success: true, data: { ...rest, project_overview: survey_notes || rest.project_overview, intermediary: intermediary_name, intermediary_fee_value: intermediary_fee, manager_id: business_manager_id, attachments, survey_photos, quotations } }); } catch (error) { console.error('获取预算项目详情失败:', error); res.status(500).json({ success: false, message: '获取项目详情失败' }); } }); router.post('/', authenticate, async (req, res) => { try { const { name, customer_id, manager_id, location, survey_date, intermediary, intermediary_fee_type, intermediary_fee_value, customer_requirements, project_overview, attachments, survey_photos, status } = req.body; if (!name) { return res.status(400).json({ success: false, message: '项目名称不能为空' }); } const codeResult = await db.query( "SELECT COUNT(*) as cnt FROM budget_projects WHERE budget_code LIKE 'BJ%'" ); const codeNum = parseInt(codeResult.rows[0].cnt) + 1; const budget_code = 'BJ' + String(codeNum).padStart(4, '0'); const result = await db.query( `INSERT INTO budget_projects (budget_code, name, customer_id, business_manager_id, location, survey_date, intermediary_name, intermediary_fee_type, intermediary_fee, customer_requirements, survey_notes, status, created_by) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) RETURNING *`, [ budget_code, name, customer_id || null, manager_id || null, location || null, survey_date || null, intermediary || null, intermediary_fee_type || 'fixed', intermediary_fee_value || 0, customer_requirements || null, project_overview || null, status || 'negotiating', req.user?.id || null ] ); const newProject = result.rows[0]; if (attachments && Array.isArray(attachments)) { for (const url of attachments) { await db.query( 'INSERT INTO budget_attachments (budget_project_id, file_url, file_type) VALUES ($1, $2, $3)', [newProject.id, url, 'attachment'] ); } } if (survey_photos && Array.isArray(survey_photos)) { for (const url of survey_photos) { await db.query( 'INSERT INTO budget_attachments (budget_project_id, file_url, file_type) VALUES ($1, $2, $3)', [newProject.id, url, 'survey_photo'] ); } } const custResult = await db.query('SELECT name FROM customers WHERE id = $1', [customer_id]); const mgrResult = await db.query('SELECT name FROM users WHERE id = $1', [manager_id]); const { survey_notes, intermediary_name, intermediary_fee, business_manager_id, created_by, ...rest } = newProject; res.json({ success: true, data: { ...rest, project_overview: survey_notes || rest.project_overview, intermediary: intermediary_name, intermediary_fee_value: intermediary_fee, manager_id: business_manager_id, customer_name: custResult.rows[0]?.name || '', manager_name: mgrResult.rows[0]?.name || '', attachments: attachments || [], survey_photos: survey_photos || [], quotations: [] } }); } catch (error) { console.error('创建预算项目失败:', error); res.status(500).json({ success: false, message: '创建预算项目失败: ' + error.message }); } }); router.put('/:id/sign', authenticate, async (req, res) => { try { const { id } = req.params; const { contract_code, contract_amount, currency, construction_method, duration_days } = req.body; const projectResult = await db.query('SELECT * FROM budget_projects WHERE id = $1', [id]); if (projectResult.rows.length === 0) { return res.status(404).json({ success: false, message: '项目不存在' }); } await db.query( "UPDATE budget_projects SET status = 'signed', updated_at = NOW() WHERE id = $1", [id] ); let project_id = projectResult.rows[0].project_id; if (!project_id) { const projResult = await db.query( `INSERT INTO projects (name, customer_id, project_manager_id, status, created_at, updated_at) SELECT name, customer_id, business_manager_id, 'active', NOW(), NOW() FROM budget_projects WHERE id = $1 RETURNING id`, [id] ); project_id = projResult.rows[0].id; await db.query('UPDATE budget_projects SET project_id = $1 WHERE id = $2', [project_id, id]); } res.json({ success: true, data: { project_id }, message: '签约成功' }); } catch (error) { console.error('签约失败:', error); res.status(500).json({ success: false, message: '签约失败: ' + error.message }); } }); router.put('/:id/unsigned', authenticate, async (req, res) => { try { const { id } = req.params; const { reason } = req.body; const projectResult = await db.query('SELECT * FROM budget_projects WHERE id = $1', [id]); if (projectResult.rows.length === 0) { return res.status(404).json({ success: false, message: '项目不存在' }); } await db.query( "UPDATE budget_projects SET status = 'unsigned', unsigned_reason = $1, updated_at = NOW() WHERE id = $2", [reason || '', id] ); res.json({ success: true, message: '已标记为未签约' }); } catch (error) { console.error('标记未签约失败:', error); res.status(500).json({ success: false, message: '操作失败' }); } }); router.delete('/:id', authenticate, async (req, res) => { try { const { id } = req.params; const projectResult = await db.query('SELECT * FROM budget_projects WHERE id = $1', [id]); if (projectResult.rows.length === 0) { return res.status(404).json({ success: false, message: '项目不存在' }); } await db.query('DELETE FROM budget_attachments WHERE budget_project_id = $1', [id]); await db.query('DELETE FROM budget_quotations WHERE budget_project_id = $1', [id]); await db.query('DELETE FROM negotiation_reminders WHERE budget_project_id = $1', [id]); await db.query('DELETE FROM budget_projects WHERE id = $1', [id]); res.json({ success: true, message: '删除成功' }); } catch (error) { console.error('删除预算项目失败:', error); res.status(500).json({ success: false, message: '删除失败' }); } }); router.post('/:id/quotations', authenticate, async (req, res) => { try { const { id } = req.params; const { version, quotation_date, amount, currency, file_url, notes, status } = req.body; const projectResult = await db.query('SELECT * FROM budget_projects WHERE id = $1', [id]); if (projectResult.rows.length === 0) { return res.status(404).json({ success: false, message: '项目不存在' }); } let nextVersion = version; if (!nextVersion) { const vResult = await db.query( 'SELECT COALESCE(MAX(version), 0) + 1 as next_ver FROM budget_quotations WHERE budget_project_id = $1', [id] ); nextVersion = vResult.rows[0].next_ver; } const result = await db.query( `INSERT INTO budget_quotations (budget_project_id, version, quotation_date, amount, currency, file_url, notes, status) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *`, [id, nextVersion, quotation_date || null, amount || 0, currency || 'CNY', file_url || null, notes || null, status || 'draft'] ); await db.query('UPDATE budget_projects SET last_quotation_at = NOW(), updated_at = NOW() WHERE id = $1', [id]); res.json({ success: true, data: result.rows[0] }); } catch (error) { console.error('创建报价版本失败:', error); res.status(500).json({ success: false, message: '创建报价版本失败: ' + error.message }); } }); router.delete('/:id/quotations/:quotationId', authenticate, async (req, res) => { try { const { id, quotationId } = req.params; const qResult = await db.query('SELECT * FROM budget_quotations WHERE id = $1 AND budget_project_id = $2', [quotationId, id]); if (qResult.rows.length === 0) { return res.status(404).json({ success: false, message: '报价版本不存在' }); } await db.query('DELETE FROM budget_quotations WHERE id = $1', [quotationId]); res.json({ success: true, message: '删除报价版本成功' }); } catch (error) { console.error('删除报价版本失败:', error); res.status(500).json({ success: false, message: '删除报价版本失败' }); } }); module.exports = router;