const { query } = require('../config/database') const { toRelativeUrl, processGoodsImages } = require('../utils/image-url') const { paginate } = require('../utils/pagination') const path = require('path') const fs = require('fs') function parseImages(images) { if (!images) return [] try { const parsed = typeof images === 'string' ? JSON.parse(images) : images return Array.isArray(parsed) ? parsed : [] } catch { return [] } } function deleteImageFiles(urls) { for (const url of urls) { const filePath = path.join(__dirname, '..', 'public', url.replace(/^\//, '')) fs.unlink(filePath, () => {}) } } async function getGoods(ctx) { let sql = 'SELECT * FROM goods WHERE 1=1' const params = [] if (ctx.query.hot === '1') { sql += ' AND is_hot = 1' } if (ctx.query.isNew === '1') { sql += ' AND is_new = 1' } if (ctx.query.category_id) { sql += ' AND category_id = ?' params.push(parseInt(ctx.query.category_id)) } if (ctx.query.keyword) { sql += ' AND name LIKE ?' params.push(`%${ctx.query.keyword}%`) } if (ctx.query.inStock === '1') { sql += ' AND stock > 0' } const sortField = ctx.query.sortBy || 'id' const sortOrder = ctx.query.sortOrder === 'asc' ? 'ASC' : 'DESC' const validSortFields = ['id', 'price', 'sales', 'stock', 'created_at'] if (validSortFields.includes(sortField)) { sql += ` ORDER BY ${sortField} ${sortOrder}` } else { sql += ' ORDER BY id DESC' } if (ctx.query.limit && !ctx.query.page) { sql += ' LIMIT ?' params.push(parseInt(ctx.query.limit)) const goods = await query(sql, params) ctx.body = { code: 200, data: processGoodsImages(goods) } return } const result = await paginate(query, sql, params, ctx.query.page, ctx.query.pageSize) if (result.data) result.data = processGoodsImages(result.data) ctx.body = { code: 200, ...result } } async function getGoodsById(ctx) { const goodsId = parseInt(ctx.params.id) const goods = await query('SELECT * FROM goods WHERE id = ?', [goodsId]) if (goods.length > 0) { ctx.body = { code: 200, data: processGoodsImages(goods)[0] } } else { ctx.body = { code: 404, message: '商品不存在' } } } async function createGoods(ctx) { const { name, price, unit, categoryId, images, stock, pricingType, isHot, isNew, remark, goodsNo, barcode } = ctx.request.body if (!name || !price || !unit) { ctx.body = { code: 400, message: '缺少必填字段' } return } // 将图片URL转换为相对路径存储 const relativeImages = (images || []).map(img => toRelativeUrl(img)) const sql = `INSERT INTO goods (name, price, cost_price, unit, category_id, images, stock, pricing_type, is_hot, is_new, remark, goods_no, barcode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` const params = [ name, parseFloat(price), parseFloat(ctx.request.body.costPrice || 0), unit, categoryId || null, JSON.stringify(relativeImages), parseInt(stock) || 0, parseInt(pricingType) || 1, parseInt(isHot) || 0, parseInt(isNew) || 0, remark || '', goodsNo || '', barcode || '' ] try { const result = await query(sql, params) ctx.body = { code: 200, message: '添加成功', data: { id: result.insertId } } } catch (error) { console.error('添加商品失败:', error) ctx.body = { code: 500, message: '添加失败' } } } async function updateGoods(ctx) { const goodsId = parseInt(ctx.params.id) const { name, price, unit, categoryId, images, stock, pricingType, isHot, isNew, description } = ctx.request.body if (!name || !price || !unit) { ctx.body = { code: 400, message: '缺少必填字段' } return } const relativeImages = (images || []).map(img => toRelativeUrl(img)) const sql = `UPDATE goods SET name = ?, price = ?, original_price = ?, unit = ?, category_id = ?, images = ?, stock = ?, pricing_type = ?, is_hot = ?, is_new = ?, description = ? WHERE id = ?` const params = [ name, parseFloat(price), parseFloat(ctx.request.body.originalPrice || 0), unit, categoryId || null, JSON.stringify(relativeImages), parseInt(stock) || 0, parseInt(pricingType) || 1, parseInt(isHot) || 0, parseInt(isNew) || 0, description || '', goodsId ] try { const existing = await query('SELECT images FROM goods WHERE id = ?', [goodsId]) const result = await query(sql, params) if (result.affectedRows > 0) { if (existing.length > 0 && images) { const oldImages = parseImages(existing[0].images) const oldFiles = oldImages.filter(u => u.startsWith('/uploads/') && !relativeImages.includes(u)) deleteImageFiles(oldFiles) } ctx.body = { code: 200, message: '更新成功' } } else { ctx.body = { code: 404, message: '商品不存在' } } } catch (error) { console.error('更新商品失败:', error) ctx.body = { code: 500, message: '更新失败' } } } async function deleteGoods(ctx) { const goodsId = parseInt(ctx.params.id) try { const existing = await query('SELECT images FROM goods WHERE id = ?', [goodsId]) const result = await query('DELETE FROM goods WHERE id = ?', [goodsId]) if (result.affectedRows > 0) { if (existing.length > 0) { const oldImages = parseImages(existing[0].images) deleteImageFiles(oldImages.filter(u => u.startsWith('/uploads/'))) } ctx.body = { code: 200, message: '删除成功' } } else { ctx.body = { code: 404, message: '商品不存在' } } } catch (error) { console.error('删除商品失败:', error) ctx.body = { code: 500, message: '删除失败' } } } module.exports = { getGoods, getGoodsById, createGoods, updateGoods, deleteGoods }