88 lines
2.8 KiB
JavaScript
88 lines
2.8 KiB
JavaScript
const { query } = require('../config/database')
|
|
|
|
function toCSV(headers, rows) {
|
|
const escape = (v) => {
|
|
if (v === null || v === undefined) return ''
|
|
const s = String(v)
|
|
if (s.includes(',') || s.includes('"') || s.includes('\n')) {
|
|
return '"' + s.replace(/"/g, '""') + '"'
|
|
}
|
|
return s
|
|
}
|
|
const lines = [headers.map(escape).join(',')]
|
|
for (const row of rows) {
|
|
lines.push(headers.map(h => escape(row[h])).join(','))
|
|
}
|
|
return lines.join('\n')
|
|
}
|
|
|
|
async function exportGoods(ctx) {
|
|
const rows = await query(
|
|
'SELECT g.id, g.name, g.price, g.original_price, g.unit, g.stock, g.sales, g.pricing_type, c.name as category_name FROM goods g LEFT JOIN categories c ON g.category_id = c.id ORDER BY g.id ASC'
|
|
)
|
|
const csv = toCSV(
|
|
['id', 'name', 'price', 'original_price', 'unit', 'stock', 'sales', 'category_name'],
|
|
rows
|
|
)
|
|
ctx.set('Content-Type', 'text/csv; charset=utf-8')
|
|
ctx.set('Content-Disposition', 'attachment; filename="goods.csv"')
|
|
ctx.body = '\uFEFF' + csv
|
|
}
|
|
|
|
async function exportOrders(ctx) {
|
|
const statusMap = { pending: '待付款', paid: '已付款', completed: '已完成', cancelled: '已取消' }
|
|
const rows = await query(
|
|
'SELECT o.id, o.total_price, o.status, o.created_at, u.phone as user_phone FROM orders o LEFT JOIN users u ON o.user_id = u.id ORDER BY o.created_at DESC'
|
|
)
|
|
const mapped = rows.map(r => ({
|
|
...r,
|
|
status: statusMap[r.status] || r.status,
|
|
total_price: parseFloat(r.total_price)
|
|
}))
|
|
const csv = toCSV(
|
|
['id', 'total_price', 'status', 'created_at', 'user_phone'],
|
|
mapped
|
|
)
|
|
ctx.set('Content-Type', 'text/csv; charset=utf-8')
|
|
ctx.set('Content-Disposition', 'attachment; filename="orders.csv"')
|
|
ctx.body = '\uFEFF' + csv
|
|
}
|
|
|
|
async function exportStock(ctx) {
|
|
const rows = await query(
|
|
'SELECT g.id, g.name, g.price, COALESCE(s.quantity, 0) as quantity FROM goods g LEFT JOIN stock s ON g.id = s.goods_id ORDER BY quantity ASC'
|
|
)
|
|
const csv = toCSV(
|
|
['id', 'name', 'price', 'quantity'],
|
|
rows
|
|
)
|
|
ctx.set('Content-Type', 'text/csv; charset=utf-8')
|
|
ctx.set('Content-Disposition', 'attachment; filename="stock.csv"')
|
|
ctx.body = '\uFEFF' + csv
|
|
}
|
|
|
|
async function exportPurchases(ctx) {
|
|
const rows = await query(
|
|
'SELECT p.id, p.supplier_name, p.total, p.status, p.created_at FROM purchases p ORDER BY p.created_at DESC'
|
|
)
|
|
const mapped = rows.map(r => ({
|
|
...r,
|
|
status: r.status === 0 ? '待入库' : r.status === 1 ? '已入库' : String(r.status),
|
|
total: parseFloat(r.total)
|
|
}))
|
|
const csv = toCSV(
|
|
['id', 'supplier_name', 'total', 'status', 'created_at'],
|
|
mapped
|
|
)
|
|
ctx.set('Content-Type', 'text/csv; charset=utf-8')
|
|
ctx.set('Content-Disposition', 'attachment; filename="purchases.csv"')
|
|
ctx.body = '\uFEFF' + csv
|
|
}
|
|
|
|
module.exports = {
|
|
exportGoods,
|
|
exportOrders,
|
|
exportStock,
|
|
exportPurchases
|
|
}
|