135 lines
3.7 KiB
JavaScript
135 lines
3.7 KiB
JavaScript
const express = require('express');
|
|
const sqlite3 = require('sqlite3').verbose();
|
|
const path = require('path');
|
|
const app = express();
|
|
|
|
// Middleware
|
|
app.use(express.json());
|
|
app.use(express.static('public'));
|
|
|
|
// Initialize SQLite database
|
|
const db = new sqlite3.Database('./products.db', (err) => {
|
|
if (err) console.error(err.message);
|
|
console.log('Connected to products database.');
|
|
});
|
|
|
|
// Create products table
|
|
db.run(`CREATE TABLE IF NOT EXISTS products (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
mpn TEXT NOT NULL,
|
|
sn TEXT NOT NULL,
|
|
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
createdBy TEXT NOT NULL
|
|
)`);
|
|
|
|
// API Routes
|
|
|
|
// Create products (batch insert)
|
|
app.post('/api/product/create', (req, res) => {
|
|
const products = req.body;
|
|
|
|
if (!Array.isArray(products) || products.length === 0) {
|
|
return res.status(400).json({ error: 'Expected an array of products' });
|
|
}
|
|
|
|
const stmt = db.prepare('INSERT INTO products (mpn, sn, createdBy) VALUES (?, ?, ?)');
|
|
let inserted = 0;
|
|
let errors = [];
|
|
|
|
products.forEach((product, index) => {
|
|
if (!product.mpn || !product.sn || !product.createdBy) {
|
|
errors.push(`Product at index ${index} is missing required fields`);
|
|
return;
|
|
}
|
|
|
|
stmt.run(product.mpn, product.sn, product.createdBy, (err) => {
|
|
if (err) errors.push(`Error inserting product at index ${index}: ${err.message}`);
|
|
else inserted++;
|
|
});
|
|
});
|
|
|
|
stmt.finalize(() => {
|
|
res.json({
|
|
success: true,
|
|
inserted,
|
|
errors: errors.length > 0 ? errors : undefined
|
|
});
|
|
});
|
|
});
|
|
|
|
// Get products with pagination, search, and sort
|
|
app.get('/api/product/get', (req, res) => {
|
|
const page = parseInt(req.query.page) || 1;
|
|
const limit = parseInt(req.query.limit) || 50;
|
|
const search = req.query.search || '';
|
|
const sortBy = req.query.sortBy || 'id';
|
|
const sortOrder = req.query.sortOrder || 'DESC';
|
|
const offset = (page - 1) * limit;
|
|
|
|
// Validate sortBy to prevent SQL injection
|
|
const validColumns = ['id', 'mpn', 'sn', 'createdAt', 'createdBy'];
|
|
const column = validColumns.includes(sortBy) ? sortBy : 'id';
|
|
const order = sortOrder.toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
|
|
|
|
let query = 'SELECT * FROM products';
|
|
let countQuery = 'SELECT COUNT(*) as total FROM products';
|
|
let params = [];
|
|
|
|
if (search) {
|
|
const searchCondition = ` WHERE mpn LIKE ? OR sn LIKE ? OR createdBy LIKE ? OR id LIKE ?`;
|
|
query += searchCondition;
|
|
countQuery += searchCondition;
|
|
const searchParam = `%${search}%`;
|
|
params = [searchParam, searchParam, searchParam, searchParam];
|
|
}
|
|
|
|
query += ` ORDER BY ${column} ${order} LIMIT ? OFFSET ?`;
|
|
params.push(limit, offset);
|
|
|
|
db.get(countQuery, search ? params.slice(0, 4) : [], (err, countRow) => {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
|
|
db.all(query, params, (err, rows) => {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
|
|
res.json({
|
|
products: rows,
|
|
total: countRow.total,
|
|
page,
|
|
limit,
|
|
totalPages: Math.ceil(countRow.total / limit)
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// Delete product
|
|
app.delete('/api/product/delete/:id', (req, res) => {
|
|
const id = req.params.id;
|
|
|
|
db.run('DELETE FROM products WHERE id = ?', id, function(err) {
|
|
if (err) {
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
|
|
if (this.changes === 0) {
|
|
return res.status(404).json({ error: 'Product not found' });
|
|
}
|
|
|
|
res.json({ success: true, deleted: this.changes });
|
|
});
|
|
});
|
|
|
|
// Serve HTML UI
|
|
app.get('/', (req, res) => {
|
|
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
|
});
|
|
|
|
const PORT = process.env.PORT || 4444;
|
|
app.listen(PORT, () => {
|
|
console.log(`Server is running on http://localhost:${PORT}`);
|
|
}); |