Files
backmanager-server/routes/customers.js
2026-06-25 21:18:13 +08:00

220 lines
6.7 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.
// 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 }