// routes/customers.js —— 客户管理 CRUD const { pool } = require('../db') const { getDataScope } = require('../middleware/permissions') // 提取分页参数 function pagination(query) { const page = Math.max(Number(query.page) || 1, 1) const pageSize = Math.min(Math.max(Number(query.pageSize) || 10, 1), 100) const offset = (page - 1) * pageSize return { page, pageSize, offset } } // GET /api/customers —— 列表(支持搜索、分页) async function list(req, res) { try { const { page, pageSize, offset } = pagination(req.query) const { name, phone, province, city, id } = req.query let where = 'WHERE 1=1' const params = [] // 数据范围过滤 const scope = getDataScope(req.user, 'customers') if (scope.deny) { return res.status(403).json({ code: 403, message: '无权访问此资源' }) } if (scope.where) { where += ' AND ' + scope.where params.push(...scope.values) } if (id) { where += ' AND c.id = ?' params.push(id) } if (name) { where += ' AND c.name LIKE ?' params.push(`%${name}%`) } if (phone) { where += ' AND c.phone LIKE ?' params.push(`%${phone}%`) } if (province) { where += ' AND c.province = ?' params.push(province) } if (city) { where += ' AND c.city = ?' params.push(city) } // 查总数 const [[{ total }]] = await pool.query( `SELECT COUNT(*) AS total FROM customers c ${where}`, params ) // 查分页数据(JOIN users+employees 获取负责人姓名) const [rows] = await pool.query( `SELECT c.*, e.name AS responsible_user_name FROM customers c LEFT JOIN users u ON c.responsible_user_id = u.id LEFT JOIN employees e ON u.employee_id = e.id ${where} ORDER BY c.id DESC LIMIT ? OFFSET ?`, [...params, pageSize, offset] ) res.json({ code: 0, message: 'ok', data: { list: rows, total, page, pageSize, totalPages: Math.ceil(total / pageSize), }, }) } catch (e) { console.error('[customers list] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // GET /api/customers/:id —— 详情 async function detail(req, res) { try { let sql = 'SELECT * FROM customers WHERE id = ?' const params = [req.params.id] const scope = getDataScope(req.user, 'customers') if (scope.deny) { return res.status(403).json({ code: 403, message: '无权访问此资源' }) } if (scope.where) { sql += ' AND ' + scope.where params.push(...scope.values) } const [rows] = await pool.query(sql, params) if (rows.length === 0) { return res.status(404).json({ code: 404, message: '客户不存在' }) } res.json({ code: 0, message: 'ok', data: rows[0] }) } catch (e) { console.error('[customers detail] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // POST /api/customers —— 新增 async function create(req, res) { const { name, phone, province, city, district, address, email, remark, responsible_user_id, } = req.body || {} if (!name) { return res.status(400).json({ code: 400, message: '客户姓名必填' }) } try { // 如果没指定负责人,默认设为当前用户 const ownerId = responsible_user_id || req.user.id const [result] = await pool.query( `INSERT INTO customers (name, phone, province, city, district, address, email, remark, responsible_user_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [name, phone || null, province || null, city || null, district || null, address || null, email || null, remark || null, ownerId] ) const [rows] = await pool.query('SELECT * FROM customers WHERE id = ?', [result.insertId]) res.json({ code: 0, message: 'ok', data: rows[0] }) } catch (e) { console.error('[customers create] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // PUT /api/customers/:id —— 更新 async function update(req, res) { const { id } = req.params const fields = [ 'name', 'phone', 'province', 'city', 'district', 'address', 'email', 'remark', 'responsible_user_id', ] try { // 确认记录存在且在数据范围内 let checkSql = 'SELECT id FROM customers WHERE id = ?' const checkParams = [id] const scope = getDataScope(req.user, 'customers') if (scope.deny) { return res.status(403).json({ code: 403, message: '无权访问此资源' }) } if (scope.where) { checkSql += ' AND ' + scope.where checkParams.push(...scope.values) } const [existing] = await pool.query(checkSql, checkParams) if (existing.length === 0) { return res.status(404).json({ code: 404, message: '客户不存在或无权操作' }) } // 动态构建 SET 子句(只更新传入的字段) const sets = [] const params = [] for (const f of fields) { if (req.body[f] !== undefined) { sets.push(`${f} = ?`) params.push(req.body[f]) } } if (sets.length === 0) { return res.status(400).json({ code: 400, message: '没有需要更新的字段' }) } params.push(id) await pool.query(`UPDATE customers SET ${sets.join(', ')} WHERE id = ?`, params) const [rows] = await pool.query('SELECT * FROM customers WHERE id = ?', [id]) res.json({ code: 0, message: 'ok', data: rows[0] }) } catch (e) { console.error('[customers update] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // DELETE /api/customers/:id —— 删除 async function remove(req, res) { const { id } = req.params try { let checkSql = 'SELECT id FROM customers WHERE id = ?' const checkParams = [id] const scope = getDataScope(req.user, 'customers') if (scope.deny) { return res.status(403).json({ code: 403, message: '无权访问此资源' }) } if (scope.where) { checkSql += ' AND ' + scope.where checkParams.push(...scope.values) } const [existing] = await pool.query(checkSql, checkParams) if (existing.length === 0) { return res.status(404).json({ code: 404, message: '客户不存在或无权操作' }) } await pool.query('DELETE FROM customers WHERE id = ?', [id]) res.json({ code: 0, message: 'ok' }) } catch (e) { console.error('[customers delete] error:', e) if (e.code === 'ER_ROW_IS_REFERENCED_2') { return res.status(400).json({ code: 400, message: '该客户被合同或售后记录引用,无法删除' }) } res.status(500).json({ code: 500, message: e.message }) } } module.exports = { list, detail, create, update, remove }