更新完善页面
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
const { query, transaction } = require('../config/database')
|
||||
const { paginate } = require('../utils/pagination')
|
||||
|
||||
const REFUNDABLE_STATUSES = ['paid', 'completed']
|
||||
|
||||
function currentUserId(ctx) {
|
||||
return ctx.state.user ? ctx.state.user.id : null
|
||||
}
|
||||
|
||||
function currentUser(ctx) {
|
||||
return ctx.state.user
|
||||
}
|
||||
|
||||
async function getRefunds(ctx) {
|
||||
const { page, pageSize, status } = ctx.query
|
||||
let sql = `
|
||||
SELECT
|
||||
r.*,
|
||||
o.status as order_status,
|
||||
o.total_price as order_amount,
|
||||
u.phone as user_phone,
|
||||
u.name as user_name
|
||||
FROM refunds r
|
||||
LEFT JOIN orders o ON r.order_id = o.id
|
||||
LEFT JOIN users u ON r.user_id = u.id
|
||||
WHERE 1=1
|
||||
`
|
||||
const params = []
|
||||
|
||||
if (status !== undefined && status !== '') {
|
||||
sql += ' AND r.status = ?'
|
||||
params.push(parseInt(status))
|
||||
}
|
||||
|
||||
sql += ' ORDER BY r.created_at DESC'
|
||||
|
||||
const result = await paginate(query, sql, params, ctx.query.page, ctx.query.pageSize)
|
||||
|
||||
const rows = (result.data || []).map(item => ({
|
||||
id: item.id,
|
||||
orderId: item.order_id,
|
||||
userId: item.user_id,
|
||||
userPhone: item.user_phone,
|
||||
userName: item.user_name,
|
||||
type: item.type,
|
||||
reason: item.reason,
|
||||
amount: parseFloat(item.amount),
|
||||
status: item.status,
|
||||
adminRemark: item.admin_remark,
|
||||
orderStatus: item.order_status,
|
||||
orderAmount: parseFloat(item.order_amount),
|
||||
processedAt: item.processed_at,
|
||||
createdAt: item.created_at
|
||||
}))
|
||||
result.data = rows
|
||||
|
||||
ctx.body = {
|
||||
code: 200,
|
||||
...result
|
||||
}
|
||||
}
|
||||
|
||||
async function getRefundById(ctx) {
|
||||
const refundId = parseInt(ctx.params.id)
|
||||
const refunds = await query(`
|
||||
SELECT
|
||||
r.*,
|
||||
o.status as order_status,
|
||||
o.total_price as order_amount,
|
||||
u.phone as user_phone,
|
||||
u.name as user_name
|
||||
FROM refunds r
|
||||
LEFT JOIN orders o ON r.order_id = o.id
|
||||
LEFT JOIN users u ON r.user_id = u.id
|
||||
WHERE r.id = ?
|
||||
`, [refundId])
|
||||
|
||||
if (refunds.length === 0) {
|
||||
ctx.status = 404
|
||||
ctx.body = { code: 404, message: '退款申请不存在' }
|
||||
return
|
||||
}
|
||||
|
||||
const item = refunds[0]
|
||||
const user = currentUser(ctx)
|
||||
if (user.role !== 2 && user.role !== 1 && item.user_id !== user.id) {
|
||||
ctx.status = 403
|
||||
ctx.body = { code: 403, message: '无权查看该退款' }
|
||||
return
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
code: 200,
|
||||
data: {
|
||||
id: item.id,
|
||||
orderId: item.order_id,
|
||||
userId: item.user_id,
|
||||
userPhone: item.user_phone,
|
||||
userName: item.user_name,
|
||||
type: item.type,
|
||||
reason: item.reason,
|
||||
amount: parseFloat(item.amount),
|
||||
status: item.status,
|
||||
adminRemark: item.admin_remark,
|
||||
orderStatus: item.order_status,
|
||||
orderAmount: parseFloat(item.order_amount),
|
||||
processedAt: item.processed_at,
|
||||
createdAt: item.created_at
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createRefund(ctx) {
|
||||
const user = currentUser(ctx)
|
||||
if (!user) {
|
||||
ctx.status = 401
|
||||
ctx.body = { code: 401, message: '未登录' }
|
||||
return
|
||||
}
|
||||
const { orderId, type, reason, amount } = ctx.request.body || {}
|
||||
|
||||
if (!orderId || !reason) {
|
||||
ctx.body = { code: 400, message: '缺少必要参数' }
|
||||
return
|
||||
}
|
||||
|
||||
const userId = user.id
|
||||
const orders = await query('SELECT * FROM orders WHERE id = ? AND user_id = ?', [orderId, userId])
|
||||
if (orders.length === 0) {
|
||||
ctx.body = { code: 404, message: '订单不存在' }
|
||||
return
|
||||
}
|
||||
|
||||
const order = orders[0]
|
||||
if (!REFUNDABLE_STATUSES.includes(order.status)) {
|
||||
ctx.body = { code: 400, message: `订单当前状态(${order.status})不可申请退款` }
|
||||
return
|
||||
}
|
||||
|
||||
const existingRefund = await query('SELECT * FROM refunds WHERE order_id = ? AND status = 0', [orderId])
|
||||
if (existingRefund.length > 0) {
|
||||
ctx.body = { code: 400, message: '该订单已有待处理的退款申请' }
|
||||
return
|
||||
}
|
||||
|
||||
const orderTotal = parseFloat(order.total_price)
|
||||
let refundAmount = orderTotal
|
||||
if (amount !== undefined && amount !== null) {
|
||||
const parsed = parseFloat(amount)
|
||||
if (isNaN(parsed) || parsed <= 0) {
|
||||
ctx.body = { code: 400, message: '退款金额无效' }
|
||||
return
|
||||
}
|
||||
if (parsed > orderTotal) {
|
||||
ctx.body = { code: 400, message: `退款金额不能超过订单金额 ¥${orderTotal.toFixed(2)}` }
|
||||
return
|
||||
}
|
||||
refundAmount = parsed
|
||||
}
|
||||
|
||||
const result = await transaction(async (conn) => {
|
||||
const [refundResult] = await conn.execute(
|
||||
'INSERT INTO refunds (order_id, user_id, type, reason, amount) VALUES (?, ?, ?, ?, ?)',
|
||||
[orderId, userId, type || 1, reason, refundAmount]
|
||||
)
|
||||
await conn.execute("UPDATE orders SET status = 'refunding' WHERE id = ?", [orderId])
|
||||
return refundResult.insertId
|
||||
})
|
||||
|
||||
ctx.body = {
|
||||
code: 200,
|
||||
message: '退款申请已提交',
|
||||
data: { id: result, orderId, amount: refundAmount }
|
||||
}
|
||||
}
|
||||
|
||||
async function processRefund(ctx) {
|
||||
const refundId = parseInt(ctx.params.id)
|
||||
const { status, adminRemark } = ctx.request.body || {}
|
||||
|
||||
if (status !== 1 && status !== 2) {
|
||||
ctx.body = { code: 400, message: '请选择正确的处理结果' }
|
||||
return
|
||||
}
|
||||
|
||||
const refunds = await query('SELECT * FROM refunds WHERE id = ?', [refundId])
|
||||
if (refunds.length === 0) {
|
||||
ctx.body = { code: 404, message: '退款申请不存在' }
|
||||
return
|
||||
}
|
||||
|
||||
const refund = refunds[0]
|
||||
|
||||
if (refund.status !== 0) {
|
||||
ctx.body = { code: 400, message: '该退款申请已处理' }
|
||||
return
|
||||
}
|
||||
|
||||
await transaction(async (conn) => {
|
||||
await conn.execute(
|
||||
'UPDATE refunds SET status = ?, admin_remark = ?, processed_at = NOW() WHERE id = ?',
|
||||
[status, adminRemark || '', refundId]
|
||||
)
|
||||
|
||||
if (status === 1) {
|
||||
await conn.execute("UPDATE orders SET status = 'refunded' WHERE id = ?", [refund.order_id])
|
||||
|
||||
const [userRows] = await conn.execute('SELECT points FROM users WHERE id = ?', [refund.user_id])
|
||||
if (userRows.length > 0) {
|
||||
const deductPoints = Math.min(Math.floor(refund.amount), userRows[0].points)
|
||||
if (deductPoints > 0) {
|
||||
const newPoints = userRows[0].points - deductPoints
|
||||
await conn.execute('UPDATE users SET points = ? WHERE id = ?', [newPoints, refund.user_id])
|
||||
await conn.execute(
|
||||
'INSERT INTO points_logs (user_id, type, amount, description) VALUES (?, ?, ?, ?)',
|
||||
[refund.user_id, 'spend', deductPoints, `订单退款扣除积分: ${refund.order_id}`]
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await conn.execute("UPDATE orders SET status = 'completed' WHERE id = ?", [refund.order_id])
|
||||
}
|
||||
})
|
||||
|
||||
ctx.body = {
|
||||
code: 200,
|
||||
message: status === 1 ? '已同意退款' : '已拒绝退款'
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserRefunds(ctx) {
|
||||
const user = currentUser(ctx)
|
||||
if (!user) {
|
||||
ctx.status = 401
|
||||
ctx.body = { code: 401, message: '未登录' }
|
||||
return
|
||||
}
|
||||
const requestedId = parseInt(ctx.query.userId)
|
||||
const userId = (user.role === 2 || user.role === 1) && requestedId ? requestedId : user.id
|
||||
|
||||
const refunds = await query(`
|
||||
SELECT
|
||||
r.*,
|
||||
o.status as order_status
|
||||
FROM refunds r
|
||||
LEFT JOIN orders o ON r.order_id = o.id
|
||||
WHERE r.user_id = ?
|
||||
ORDER BY r.created_at DESC
|
||||
`, [userId])
|
||||
|
||||
const rows = refunds.map(item => ({
|
||||
id: item.id,
|
||||
orderId: item.order_id,
|
||||
type: item.type,
|
||||
reason: item.reason,
|
||||
amount: parseFloat(item.amount),
|
||||
status: item.status,
|
||||
adminRemark: item.admin_remark,
|
||||
orderStatus: item.order_status,
|
||||
processedAt: item.processed_at,
|
||||
createdAt: item.created_at
|
||||
}))
|
||||
|
||||
ctx.body = {
|
||||
code: 200,
|
||||
data: rows
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getRefunds,
|
||||
getRefundById,
|
||||
createRefund,
|
||||
processRefund,
|
||||
getUserRefunds
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user