Files
backmanager-server/routes/afterSales.js
2026-06-24 22:44:14 +08:00

249 lines
7.9 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/afterSales.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 }
}
const LIST_SELECT = `
SELECT
a.*,
cu.name AS customer_name,
e.name AS employee_name
FROM after_sales a
LEFT JOIN customers cu ON a.customer_id = cu.id
LEFT JOIN employees e ON a.employee_id = e.id
`
// GET /api/after-sales —— 列表
async function list(req, res) {
try {
const { page, pageSize, offset } = pagination(req.query)
const { handle_status, customer_name } = req.query
let where = 'WHERE 1=1'
const params = []
// 数据范围过滤
const scope = getDataScope(req.user, 'after_sales')
if (scope.deny) {
return res.status(403).json({ code: 403, message: '无权访问此资源' })
}
if (scope.where) {
// list 查询有 JOIN需要表别名前缀避免列名歧义
const scopeCol = scope.tableAlias ? scope.where.replace('responsible_user_id', `${scope.tableAlias}.responsible_user_id`) : scope.where
where += ' AND ' + scopeCol
params.push(...scope.values)
}
if (handle_status) {
where += ' AND a.handle_status = ?'
params.push(handle_status)
}
if (customer_name) {
where += ' AND cu.name LIKE ?'
params.push(`%${customer_name}%`)
}
const [[{ total }]] = await pool.query(
`SELECT COUNT(*) AS total FROM after_sales a
LEFT JOIN customers cu ON a.customer_id = cu.id
LEFT JOIN employees e ON a.employee_id = e.id
${where}`,
params
)
const [rows] = await pool.query(
`${LIST_SELECT} ${where} ORDER BY a.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('[after-sales list] error:', e)
res.status(500).json({ code: 500, message: e.message })
}
}
// GET /api/after-sales/:id —— 详情
async function detail(req, res) {
try {
let sql = `${LIST_SELECT} WHERE a.id = ?`
const params = [req.params.id]
const scope = getDataScope(req.user, 'after_sales')
if (scope.deny) {
return res.status(403).json({ code: 403, message: '无权访问此资源' })
}
if (scope.where) {
const scopeCol = scope.tableAlias ? scope.where.replace('responsible_user_id', `${scope.tableAlias}.responsible_user_id`) : scope.where
sql += ' AND ' + scopeCol
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('[after-sales detail] error:', e)
res.status(500).json({ code: 500, message: e.message })
}
}
// POST /api/after-sales —— 新增
async function create(req, res) {
const {
customer_id, feedback, employee_id, handle_method,
handle_status, service_date, remark, responsible_user_id,
} = req.body || {}
if (!customer_id) {
return res.status(400).json({ code: 400, message: '客户ID必填' })
}
if (!feedback) {
return res.status(400).json({ code: 400, message: '售后反馈内容必填' })
}
try {
// 校验客户存在
const [cust] = await pool.query('SELECT id FROM customers WHERE id = ?', [customer_id])
if (cust.length === 0) {
return res.status(400).json({ code: 400, message: '关联客户不存在' })
}
// 校验业务员
if (employee_id) {
const [emp] = await pool.query('SELECT id FROM employees WHERE id = ?', [employee_id])
if (emp.length === 0) {
return res.status(400).json({ code: 400, message: '关联业务员不存在' })
}
}
// 如果没指定负责人,默认设为当前用户
const ownerId = responsible_user_id || req.user.id
const [result] = await pool.query(
`INSERT INTO after_sales
(customer_id, feedback, employee_id, handle_method, handle_status, service_date, remark, responsible_user_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[customer_id, feedback,
employee_id || null,
handle_method || null,
handle_status || '待处理',
service_date || null,
remark || null,
ownerId]
)
const [rows] = await pool.query(`${LIST_SELECT} WHERE a.id = ?`, [result.insertId])
res.json({ code: 0, message: 'ok', data: rows[0] })
} catch (e) {
console.error('[after-sales create] error:', e)
res.status(500).json({ code: 500, message: e.message })
}
}
// PUT /api/after-sales/:id —— 更新
async function update(req, res) {
const { id } = req.params
const fields = [
'customer_id', 'feedback', 'employee_id', 'handle_method',
'handle_status', 'service_date', 'remark', 'responsible_user_id',
]
try {
// 确认记录存在且在数据范围内
let checkSql = 'SELECT id FROM after_sales WHERE id = ?'
const checkParams = [id]
const scope = getDataScope(req.user, 'after_sales')
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: '售后记录不存在或无权操作' })
}
if (req.body.customer_id) {
const [cust] = await pool.query('SELECT id FROM customers WHERE id = ?', [req.body.customer_id])
if (cust.length === 0) {
return res.status(400).json({ code: 400, message: '关联客户不存在' })
}
}
if (req.body.employee_id) {
const [emp] = await pool.query('SELECT id FROM employees WHERE id = ?', [req.body.employee_id])
if (emp.length === 0) {
return res.status(400).json({ code: 400, message: '关联业务员不存在' })
}
}
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 after_sales SET ${sets.join(', ')} WHERE id = ?`, params)
const [rows] = await pool.query(`${LIST_SELECT} WHERE a.id = ?`, [id])
res.json({ code: 0, message: 'ok', data: rows[0] })
} catch (e) {
console.error('[after-sales update] error:', e)
res.status(500).json({ code: 500, message: e.message })
}
}
// DELETE /api/after-sales/:id —— 删除
async function remove(req, res) {
const { id } = req.params
try {
let checkSql = 'SELECT id FROM after_sales WHERE id = ?'
const checkParams = [id]
const scope = getDataScope(req.user, 'after_sales')
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 after_sales WHERE id = ?', [id])
res.json({ code: 0, message: 'ok' })
} catch (e) {
console.error('[after-sales delete] error:', e)
res.status(500).json({ code: 500, message: e.message })
}
}
module.exports = { list, detail, create, update, remove }