更新完善页面

This commit is contained in:
董海洋
2026-06-03 14:15:55 +08:00
parent 4b7ae9c933
commit 1675662537
57 changed files with 7625 additions and 883 deletions
+126 -50
View File
@@ -37,8 +37,12 @@ async function getGoods(ctx) {
}
if (ctx.query.keyword) {
sql += ' AND name LIKE ?'
params.push(`%${ctx.query.keyword}%`)
const kw = String(ctx.query.keyword).trim().slice(0, 50)
if (kw) {
const escaped = kw.replace(/[\\%_]/g, c => '\\' + c)
sql += ' AND name LIKE ?'
params.push(`%${escaped}%`)
}
}
if (ctx.query.inStock === '1') {
@@ -59,7 +63,7 @@ async function getGoods(ctx) {
sql += ' LIMIT ?'
params.push(parseInt(ctx.query.limit))
const goods = await query(sql, params)
ctx.body = { code: 200, data: processGoodsImages(goods) }
ctx.body = { code: 0, data: processGoodsImages(goods) }
return
}
@@ -67,7 +71,7 @@ async function getGoods(ctx) {
if (result.data) result.data = processGoodsImages(result.data)
ctx.body = {
code: 200,
code: 0,
...result
}
}
@@ -91,7 +95,7 @@ async function getGoodsById(ctx) {
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,
@@ -99,6 +103,14 @@ async function createGoods(ctx) {
}
return
}
if (stock !== undefined && stock !== 0) {
ctx.body = {
code: 400,
message: '新建商品请保持库存为 0,通过「入库/采购」或「库存调整」接口补充'
}
return
}
// 将图片URL转换为相对路径存储
const relativeImages = (images || []).map(img => toRelativeUrl(img))
@@ -139,10 +151,29 @@ async function createGoods(ctx) {
}
}
const GOODS_UPDATEABLE_FIELDS = [
'name', 'price', 'originalPrice', 'unit', 'categoryId',
'images', 'pricingType', 'isHot', 'isNew', 'description', 'goodsNo', 'barcode', 'remark'
]
async function updateGoods(ctx) {
const goodsId = parseInt(ctx.params.id)
const { name, price, unit, categoryId, images, stock, pricingType, isHot, isNew, description } = ctx.request.body
const body = ctx.request.body
if ('stock' in body) {
ctx.body = { code: 400, message: '请通过「库存调整」接口修改库存,不能直接编辑' }
return
}
const filtered = {}
for (const key of GOODS_UPDATEABLE_FIELDS) {
if (key in body) {
filtered[key] = body[key]
}
}
const { name, price, unit, pricingType, isHot, isNew, description } = filtered
if (!name || !price || !unit) {
ctx.body = {
code: 400,
@@ -150,54 +181,57 @@ async function updateGoods(ctx) {
}
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 setFields = []
const params = []
setFields.push('name = ?', 'price = ?', 'original_price = ?', 'unit = ?')
params.push(name, parseFloat(price), parseFloat(filtered.originalPrice || 0), unit)
setFields.push('category_id = ?')
params.push(filtered.categoryId || null)
if (filtered.images !== undefined) {
const relativeImages = (filtered.images || []).map(img => toRelativeUrl(img))
setFields.push('images = ?')
params.push(JSON.stringify(relativeImages))
const existing = await query('SELECT images FROM goods WHERE id = ?', [goodsId])
const result = await query(sql, params)
if (existing.length > 0) {
const oldImages = parseImages(existing[0].images)
const oldFiles = oldImages.filter(u => u.startsWith('/uploads/') && !relativeImages.includes(u))
deleteImageFiles(oldFiles)
}
}
if (filtered.goodsNo !== undefined) {
setFields.push('goods_no = ?')
params.push(filtered.goodsNo || '')
}
if (filtered.barcode !== undefined) {
setFields.push('barcode = ?')
params.push(filtered.barcode || '')
}
if (filtered.remark !== undefined) {
setFields.push('remark = ?')
params.push(filtered.remark || '')
}
setFields.push('pricing_type = ?', 'is_hot = ?', 'is_new = ?', 'description = ?')
params.push(parseInt(pricingType) || 1, parseInt(isHot) || 0, parseInt(isNew) || 0, description || '')
params.push(goodsId)
try {
const result = await query(`UPDATE goods SET ${setFields.join(', ')} WHERE id = ?`, 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: '更新成功'
}
ctx.body = { code: 200, message: '更新成功' }
} else {
ctx.body = {
code: 404,
message: '商品不存在'
}
ctx.body = { code: 404, message: '商品不存在' }
}
} catch (error) {
console.error('更新商品失败:', error)
ctx.body = {
code: 500,
message: '更新失败'
}
ctx.body = { code: 500, message: '更新失败' }
}
}
@@ -231,10 +265,52 @@ async function deleteGoods(ctx) {
}
}
// 批量更新商品
async function batchUpdate(ctx) {
const { ids, isOnSale } = ctx.request.body
if (!Array.isArray(ids) || ids.length === 0) {
ctx.body = { code: 400, message: '请选择要操作的商品' }
return
}
// 允许批量更新的字段
const setFields = []
const params = []
if (isOnSale !== undefined) {
setFields.push('is_on_sale = ?')
params.push(parseInt(isOnSale))
}
if (setFields.length === 0) {
ctx.body = { code: 400, message: '缺少更新字段' }
return
}
// 构建 IN 占位符
const placeholders = ids.map(() => '?').join(', ')
params.push(...ids)
try {
const sql = `UPDATE goods SET ${setFields.join(', ')} WHERE id IN (${placeholders})`
const result = await query(sql, params)
ctx.body = {
code: 200,
message: `成功更新${result.affectedRows}个商品`,
data: { affectedRows: result.affectedRows }
}
} catch (error) {
console.error('批量更新商品失败:', error)
ctx.body = { code: 500, message: '批量更新失败' }
}
}
module.exports = {
getGoods,
getGoodsById,
createGoods,
updateGoods,
deleteGoods
deleteGoods,
batchUpdate
}