207 lines
8.1 KiB
JavaScript
207 lines
8.1 KiB
JavaScript
const express = require('express');
|
|
const { v4: uuidv4 } = require('uuid');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
function createProductRoutes(db) {
|
|
const router = express.Router();
|
|
|
|
// List products (optional filter by shop_id)
|
|
router.get('/', (req, res) => {
|
|
const { shop_id } = req.query;
|
|
let products;
|
|
if (shop_id) {
|
|
products = db.prepare('SELECT * FROM products WHERE shop_id = ? ORDER BY created_at DESC').all(shop_id);
|
|
} else {
|
|
products = db.prepare('SELECT * FROM products ORDER BY created_at DESC').all();
|
|
}
|
|
// Parse shop info
|
|
const shopStmt = db.prepare('SELECT shop_name FROM shops WHERE id = ?');
|
|
products = products.map(p => ({
|
|
...p,
|
|
shop_name: shopStmt.get(p.shop_id)?.shop_name || 'Unknown'
|
|
}));
|
|
res.json(products);
|
|
});
|
|
|
|
// Export products (optional filter by shop_id)
|
|
router.get('/export', (req, res) => {
|
|
const { shop_id } = req.query;
|
|
let products;
|
|
if (shop_id) {
|
|
products = db.prepare('SELECT p.*, s.shop_name FROM products p LEFT JOIN shops s ON p.shop_id = s.id WHERE p.shop_id = ? ORDER BY p.created_at DESC').all(shop_id);
|
|
} else {
|
|
products = db.prepare('SELECT p.*, s.shop_name FROM products p LEFT JOIN shops s ON p.shop_id = s.id ORDER BY p.created_at DESC').all();
|
|
}
|
|
res.setHeader('Content-Disposition', 'attachment; filename=products.json');
|
|
res.json(products);
|
|
});
|
|
|
|
// Upload reference image for a product
|
|
router.post('/:id/image', (req, res) => {
|
|
const product = db.prepare('SELECT * FROM products WHERE id = ?').get(req.params.id);
|
|
if (!product) return res.status(404).json({ error: 'Product not found' });
|
|
const { image } = req.body;
|
|
if (!image) return res.status(400).json({ error: 'image (base64) required' });
|
|
|
|
let imagesRoot = path.join(__dirname, '..', 'images');
|
|
try {
|
|
const savePathRow = db.prepare("SELECT value FROM configs WHERE key = 'image_save_path'").get();
|
|
if (savePathRow?.value?.trim()) imagesRoot = savePathRow.value.trim();
|
|
} catch (_) {}
|
|
|
|
const imagesDir = path.join(imagesRoot, product.id);
|
|
if (!fs.existsSync(imagesDir)) fs.mkdirSync(imagesDir, { recursive: true });
|
|
|
|
const filename = 'ref.png';
|
|
const filePath = path.join(imagesDir, filename);
|
|
const base64Data = image.replace(/^data:image\/\w+;base64,/, '');
|
|
fs.writeFileSync(filePath, Buffer.from(base64Data, 'base64'));
|
|
|
|
const publicPath = `/api/images/${product.id}/${filename}`;
|
|
db.prepare("UPDATE products SET reference_image = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
|
.run(publicPath, req.params.id);
|
|
res.json({ reference_image: publicPath });
|
|
});
|
|
|
|
// Delete reference image for a product
|
|
router.delete('/:id/image', (req, res) => {
|
|
const product = db.prepare('SELECT * FROM products WHERE id = ?').get(req.params.id);
|
|
if (!product) return res.status(404).json({ error: 'Product not found' });
|
|
if (!product.reference_image) return res.json({ success: true });
|
|
|
|
let imagesRoot = path.join(__dirname, '..', 'images');
|
|
try {
|
|
const savePathRow = db.prepare("SELECT value FROM configs WHERE key = 'image_save_path'").get();
|
|
if (savePathRow?.value?.trim()) imagesRoot = savePathRow.value.trim();
|
|
} catch (_) {}
|
|
|
|
const filePath = path.join(imagesRoot, product.id, 'ref.png');
|
|
if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
|
|
|
|
db.prepare("UPDATE products SET reference_image = '', updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
|
.run(req.params.id);
|
|
res.json({ success: true });
|
|
});
|
|
|
|
// Get product by id
|
|
router.get('/:id', (req, res) => {
|
|
const product = db.prepare('SELECT * FROM products WHERE id = ?').get(req.params.id);
|
|
if (!product) return res.status(404).json({ error: 'Product not found' });
|
|
const shop = db.prepare('SELECT shop_name FROM shops WHERE id = ?').get(product.shop_id);
|
|
res.json({ ...product, shop_name: shop?.shop_name || 'Unknown' });
|
|
});
|
|
|
|
// Create product
|
|
router.post('/', (req, res) => {
|
|
const { shop_id, title } = req.body;
|
|
if (!shop_id || !title) {
|
|
return res.status(400).json({ error: 'shop_id and title are required' });
|
|
}
|
|
const shop = db.prepare('SELECT * FROM shops WHERE id = ?').get(shop_id);
|
|
if (!shop) return res.status(404).json({ error: 'Shop not found' });
|
|
|
|
const id = uuidv4();
|
|
db.prepare('INSERT INTO products (id, shop_id, title) VALUES (?, ?, ?)').run(id, shop_id, title);
|
|
res.status(201).json(db.prepare('SELECT * FROM products WHERE id = ?').get(id));
|
|
});
|
|
|
|
// Batch create products
|
|
router.post('/batch', (req, res) => {
|
|
const { shop_id, titles } = req.body;
|
|
if (!shop_id || !Array.isArray(titles) || titles.length === 0) {
|
|
return res.status(400).json({ error: 'shop_id and titles array are required' });
|
|
}
|
|
const shop = db.prepare('SELECT * FROM shops WHERE id = ?').get(shop_id);
|
|
if (!shop) return res.status(404).json({ error: 'Shop not found' });
|
|
|
|
const insert = db.prepare('INSERT INTO products (id, shop_id, title) VALUES (?, ?, ?)');
|
|
const products = [];
|
|
const batchInsert = db.transaction((titles) => {
|
|
for (const title of titles) {
|
|
const id = uuidv4();
|
|
insert.run(id, shop_id, title);
|
|
products.push(id);
|
|
}
|
|
});
|
|
batchInsert(titles);
|
|
|
|
const created = db.prepare('SELECT * FROM products WHERE id IN (' + products.map(() => '?').join(',') + ')').all(...products);
|
|
res.status(201).json(created);
|
|
});
|
|
|
|
// Update product
|
|
router.put('/:id', (req, res) => {
|
|
const { title, status } = req.body;
|
|
const product = db.prepare('SELECT * FROM products WHERE id = ?').get(req.params.id);
|
|
if (!product) return res.status(404).json({ error: 'Product not found' });
|
|
|
|
db.prepare('UPDATE products SET title = ?, status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?')
|
|
.run(title || product.title, status || product.status, req.params.id);
|
|
|
|
res.json(db.prepare('SELECT * FROM products WHERE id = ?').get(req.params.id));
|
|
});
|
|
|
|
// Batch delete products (POST because DELETE with body is not reliable)
|
|
router.post('/batch-delete', (req, res) => {
|
|
const { ids } = req.body;
|
|
if (!Array.isArray(ids) || ids.length === 0) {
|
|
return res.status(400).json({ error: 'ids array required' });
|
|
}
|
|
const placeholders = ids.map(() => '?').join(',');
|
|
const result = db.prepare('DELETE FROM products WHERE id IN (' + placeholders + ')').run(...ids);
|
|
res.json({ deleted: result.changes });
|
|
});
|
|
|
|
// Batch delete products (legacy DELETE route)
|
|
router.delete('/batch', (req, res) => {
|
|
const { ids } = req.body;
|
|
if (!Array.isArray(ids) || ids.length === 0) {
|
|
return res.status(400).json({ error: 'ids array required' });
|
|
}
|
|
const placeholders = ids.map(() => '?').join(',');
|
|
const result = db.prepare('DELETE FROM products WHERE id IN (' + placeholders + ')').run(...ids);
|
|
res.json({ deleted: result.changes });
|
|
});
|
|
|
|
// Delete product
|
|
router.delete('/:id', (req, res) => {
|
|
const result = db.prepare('DELETE FROM products WHERE id = ?').run(req.params.id);
|
|
if (result.changes === 0) return res.status(404).json({ error: 'Product not found' });
|
|
res.json({ success: true });
|
|
});
|
|
|
|
// Import products from array
|
|
router.post('/import', (req, res) => {
|
|
const { shop_id, products: importProducts } = req.body;
|
|
if (!shop_id || !Array.isArray(importProducts) || importProducts.length === 0) {
|
|
return res.status(400).json({ error: 'shop_id and products array required' });
|
|
}
|
|
const shop = db.prepare('SELECT * FROM shops WHERE id = ?').get(shop_id);
|
|
if (!shop) return res.status(404).json({ error: 'Shop not found' });
|
|
|
|
const insert = db.prepare('INSERT OR IGNORE INTO products (id, shop_id, title) VALUES (?, ?, ?)');
|
|
let imported = 0;
|
|
const batch = db.transaction(() => {
|
|
for (const p of importProducts) {
|
|
const title = typeof p === 'string' ? p : p.title;
|
|
if (!title) continue;
|
|
const id = uuidv4();
|
|
const info = insert.run(id, shop_id, title);
|
|
if (info.changes > 0) imported++;
|
|
}
|
|
});
|
|
batch();
|
|
res.json({ total: importProducts.length, imported });
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return router;
|
|
}
|
|
|
|
module.exports = createProductRoutes;
|