=== LiteMall Backend Source Code ===
=== Generated: 2026-05-28 12:58 ===

===== server/src/app.js =====
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const path = require('path');
const rateLimit = require('express-rate-limit');
const config = require('../config');
const { initDatabase } = require('./init-db');

// 初始化数据库
initDatabase();

const app = express();

// 中间件
app.use(helmet({ contentSecurityPolicy: false }));
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

// 静态文件
app.use('/uploads', express.static(path.join(__dirname, '..', 'uploads')));
app.use('/admin', express.static(path.join(__dirname, '..', '..', 'admin')));
app.use('/mobile', express.static(path.join(__dirname, '..', '..', 'mobile')));
app.use('/lib', express.static(path.join(__dirname, '..', 'public', 'lib')));

// 限流
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 1000,
  message: { code: 429, message: '请求过于频繁，请稍后再试' }
});
app.use('/api', limiter);

// 安全中间件（对API路由生效）
const { sanitizeRequest } = require('./middleware/security');
app.use('/api', sanitizeRequest);

// 路由
app.use('/api/user', require('./routes/user'));
app.use('/api/product', require('./routes/product'));
app.use('/api/cart', require('./routes/cart'));
app.use('/api/order', require('./routes/order'));
app.use('/api/membership', require('./routes/membership'));
app.use('/api/distribution', require('./routes/distribution'));
app.use('/api/marketing', require('./routes/marketing'));
app.use('/api/ai', require('./routes/ai'));
app.use('/api/upload', require('./routes/upload'));
app.use('/api/config', require('./routes/config'));
app.use('/api/banner', require('./routes/banner'));
app.use('/api/category', require('./routes/category'));
const { loginLimiter } = require('./middleware/security');
app.use('/api/admin', require('./routes/admin'));
app.use('/api/stats', require('./routes/stats'));
app.use('/api/system', require('./routes/system'));
app.use('/api/payment', require('./routes/payment'));
app.use('/api/pagebuilder', require('./routes/pagebuilder'));
app.use('/api/collector', require('./routes/collector'));
app.use('/api/captcha', require('./routes/captcha'));
app.use('/api/review', require('./routes/review'));
app.use('/api/address', require('./routes/address'));

// 静态页fallback
// SPA fallback
app.get('/admin', (req, res) => res.sendFile(path.join(__dirname, '..', '..', 'admin', 'index.html')));
app.get('/admin/*', (req, res) => res.sendFile(path.join(__dirname, '..', '..', 'admin', 'index.html')));
app.get('/mobile', (req, res) => res.sendFile(path.join(__dirname, '..', '..', 'mobile', 'index.html')));
app.get('/', (req, res) => res.redirect('/admin'));

// 错误处理
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({
    code: err.status || 500,
    message: err.message || '服务器内部错误'
  });
});

// 404
app.use((req, res) => {
  res.status(404).json({ code: 404, message: '接口不存在' });
});

// ========== 定时任务：超时订单自动取消 ==========
const TIMEOUT_MINUTES = 30;
const CHECK_INTERVAL = 5 * 60 * 1000;

setInterval(() => {
  const { get, run, all, transaction } = require('./utils/db');
  try {
    const expired = all(`SELECT id, order_no FROM orders WHERE status='pending_pay' AND 
      datetime(created_at, '+${TIMEOUT_MINUTES} minutes') < datetime('now','localtime')`);
    if (expired.length > 0) {
      transaction(() => {
        for (const order of expired) {
          run("UPDATE orders SET status='closed', close_reason='超时未支付', close_time=datetime('now','localtime') WHERE id=?", [order.id]);
          run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order.id, 'auto_close', '系统自动关闭超时订单']);
          const items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
          for (const item of items) {
            if (item.sku_id) {
              run('UPDATE product_skus SET stock=stock+? WHERE id=?', [item.quantity, item.sku_id]);
            } else {
              run('UPDATE products SET stock=stock+? WHERE id=?', [item.quantity, item.product_id]);
            }
          }
        }
      });
      console.log('[定时任务] 已自动关闭 ' + expired.length + ' 个超时订单');
    }
  } catch(e) { /* silent */ }
}, CHECK_INTERVAL);

app.listen(config.port, config.host, () => {
  console.log('LiteMall 轻商城 API 已启动: http://' + config.host + ':' + config.port);
});

===== server/src/utils/db.js =====
const Database = require('better-sqlite3');
const path = require('path');
const config = require('../../config');

let db = null;

function getDb() {
  if (!db) {
    db = new Database(config.dbPath);
    db.pragma('journal_mode = WAL');
    db.pragma('foreign_keys = ON');
  }
  return db;
}

// Normalize params to array for better-sqlite3
function normalize(params) {
  if (params === null || params === undefined) return [];
  if (Array.isArray(params)) return params;
  if (typeof params === 'object') return Object.values(params);
  return [params];
}

function query(sql, params = []) {
  const db = getDb();
  return db.prepare(sql).all(normalize(params));
}

function get(sql, params = []) {
  return getDb().prepare(sql).get(normalize(params));
}

function run(sql, params = []) {
  return getDb().prepare(sql).run(normalize(params));
}

function all(sql, params = []) {
  return getDb().prepare(sql).all(normalize(params));
}

function transaction(fn) {
  const db = getDb();
  return db.transaction(fn)();
}

function close() {
  if (db) { db.close(); db = null; }
}

module.exports = { getDb, query, get, run, all, transaction, close };

===== server/src/utils/response.js =====
module.exports = {
  success(data = null, message = '操作成功') {
    return { code: 0, message, data };
  },
  
  fail(message = '操作失败', code = 1) {
    return { code, message, data: null };
  },

  page(list, total, page, pageSize) {
    return {
      code: 0,
      message: '操作成功',
      data: {
        list,
        total,
        page,
        pageSize,
        totalPages: Math.ceil(total / pageSize)
      }
    };
  }
};

===== server/src/middleware/auth.js =====
const jwt = require('jsonwebtoken');
const config = require('../../config');
const { get } = require('../utils/db');

function authUser(req, res, next) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  if (!token) return res.status(401).json({ code: 401, message: '请先登录' });
  try {
    const decoded = jwt.verify(token, config.jwtSecret);
    const user = get('SELECT id, nickname, avatar, phone, level_id, experience, balance FROM users WHERE id = ?', [decoded.userId]);
    if (!user) return res.status(401).json({ code: 401, message: '用户不存在' });
    req.user = user;
    req.userId = user.id;
    next();
  } catch (err) {
    return res.status(401).json({ code: 401, message: '登录已过期，请重新登录' });
  }
}

function authAdmin(req, res, next) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  if (!token) return res.status(401).json({ code: 401, message: '请先登录' });
  try {
    const decoded = jwt.verify(token, config.jwtSecret);
    const user = get('SELECT id, nickname, phone, level_id FROM users WHERE id = ?', [decoded.userId]);
    if (!user || user.phone !== 'admin') return res.status(403).json({ code: 403, message: '无管理员权限' });
    req.user = user;
    req.userId = user.id;
    next();
  } catch (err) {
    return res.status(401).json({ code: 401, message: '登录已过期' });
  }
}

function optionalAuth(req, res, next) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  if (token) {
    try {
      const decoded = jwt.verify(token, config.jwtSecret);
      const user = get('SELECT id, nickname, avatar, phone, level_id FROM users WHERE id = ?', [decoded.userId]);
      if (user) { req.user = user; req.userId = user.id; }
    } catch (e) {}
  }
  next();
}

module.exports = { authUser, authAdmin, optionalAuth };

===== server/src/middleware/security.js =====
const { get } = require('../utils/db');
const rateLimit = require('express-rate-limit');

// 登录频率限制 (按IP)
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15分钟
  max: 10, // 每个IP最多10次尝试
  message: { code: 429, message: '登录尝试过于频繁，请15分钟后再试' },
  standardHeaders: true,
  legacyHeaders: false,
  skipSuccessfulRequests: true,
});

// API频率限制
const apiLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 60,
  message: { code: 429, message: '请求过于频繁，请稍后再试' },
});

// 基础防注入检查
function sanitizeInput(value) {
  if (typeof value === 'string') {
    // 移除可能导致注入的特殊字符序列
    return value.replace(/['";\\$`<>]/g, '').trim();
  }
  return value;
}

// 请求参数清洗中间件
function sanitizeRequest(req, res, next) {
  if (req.body) {
    for (const key in req.body) {
      if (typeof req.body[key] === 'string') {
        req.body[key] = sanitizeInput(req.body[key]);
      }
    }
  }
  if (req.query) {
    for (const key in req.query) {
      if (typeof req.query[key] === 'string') {
        req.query[key] = sanitizeInput(req.query[key]);
      }
    }
  }
  next();
}

// 管理员权限校验中间件
function requirePermission(permission) {
  return (req, res, next) => {
    // 超级管理员 (ID=1) 全部放行
    if (req.userId === 1) return next();
    
    // 角色权限映射
    const rolePerms = {
      2: 'products,orders,users,marketing,distribution,ai',      // 运营
      3: 'orders,users,distribution,stats,export',               // 财务
      4: 'orders,users,ai',                                       // 客服
    };
    
    const user = get('SELECT level_id FROM users WHERE id=?', [req.userId]);
    if (!user) return res.status(403).json({ code: 403, message: '用户不存在' });
    
    const allowedPerms = rolePerms[user.level_id] || '';
    if (allowedPerms === 'all' || allowedPerms.includes(permission)) return next();
    
    return res.status(403).json({ code: 403, message: '无此操作权限' });
  };
}

// 检查密码强度
function checkPasswordStrength(password) {
  const errors = [];
  if (password.length < 6) errors.push('密码长度不能少于6位');
  if (password.length > 32) errors.push('密码长度不能超过32位');
  if (!/[A-Za-z]/.test(password) && !/[0-9]/.test(password)) errors.push('密码需包含字母或数字');
  return errors;
}

module.exports = { loginLimiter, apiLimiter, sanitizeRequest, requirePermission, checkPasswordStrength };

===== server/src/routes/admin.js =====
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('../../config');
const { get, run, all, transaction } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authAdmin } = require('../middleware/auth');

// ========== 管理员登录 ==========
router.post('/login', async (req, res) => {
  try {
    const { phone, password } = req.body;
    const ip = req.ip || req.headers['x-forwarded-for'] || '';
    
    const user = get('SELECT * FROM users WHERE phone=? AND phone=\'admin\'', [phone]);
    if (!user || !await bcrypt.compare(password, user.password)) {
      run('INSERT INTO login_logs(user_id,phone,ip,user_agent,result,reason) VALUES(?,?,?,?,?,?)',
        [null, phone, ip, (req.headers['user-agent']||'').slice(0,200), 'fail', '账号或密码错误']);
      return res.json(fail('账号或密码错误'));
    }
    const token = jwt.sign({ userId: user.id }, config.jwtSecret, { expiresIn: config.jwtExpiresIn });
    run('INSERT INTO login_logs(user_id,phone,ip,user_agent,result,reason) VALUES(?,?,?,?,?,?)',
      [user.id, phone, ip, (req.headers['user-agent']||'').slice(0,200), 'success', '']);
    return res.json(success({ token }, '登录成功'));
  } catch (e) { return res.json(fail('登录失败')); }
});

// 复制商品
router.post('/products/:id/copy', authAdmin, (req, res) => {
  try {
    const p = get('SELECT * FROM products WHERE id=?', [req.params.id]);
    if (!p) return res.json(fail('商品不存在'));
    const r = run(`INSERT INTO products(name,subtitle,category_id,image,images,price,original_price,cost_price,stock,unit,spec_type,description,is_new,is_hot,is_recommend,sort,weight,seo_keywords,seo_description)
      VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
      [p.name+'(复制)', p.subtitle, p.category_id, p.image, p.images, p.price, p.original_price, p.cost_price, p.stock||0, p.unit||'件', p.spec_type||0, p.description, 0, 0, 0, 0, p.weight||0, p.seo_keywords||'', p.seo_description||'']);
    // 复制SKU
    const skus = all('SELECT * FROM product_skus WHERE product_id=?', [p.id]);
    for (const sku of skus) {
      run('INSERT INTO product_skus(product_id,sku_code,image,specs,price,original_price,cost_price,stock,weight,sort) VALUES(?,?,?,?,?,?,?,?,?,?)',
        [r.lastInsertRowid, sku.sku_code||'', sku.image||'', sku.specs||'[]', sku.price, sku.original_price||0, sku.cost_price||0, sku.stock||0, sku.weight||0, sku.sort||0]);
    }
    logAction(req.userId, 'copy', 'product', r.lastInsertRowid, '复制商品: '+p.name, req.ip);
    return res.json(success({id: r.lastInsertRowid}, '复制成功'));
  } catch(e) { return res.json(fail('复制失败')); }
});

// 批量更新库存
router.post('/products/batch-stock', authAdmin, (req, res) => {
  try {
    const { items } = req.body; // [{product_id, stock}]
    if (!items || !items.length) return res.json(fail('请提供数据'));
    for (const item of items) {
      run('UPDATE products SET stock=?,updated_at=datetime(\'now\',\'localtime\') WHERE id=?', [item.stock, item.product_id]);
    }
    return res.json(success(null, '更新成功'));
  } catch(e) { return res.json(fail('更新失败')); }
});

// 修改管理员密码
router.put('/password', authAdmin, async (req, res) => {
  try {
    const { old_password, new_password } = req.body;
    const user = get('SELECT password FROM users WHERE id=?', [req.userId]);
    if (!await bcrypt.compare(old_password, user.password)) return res.json(fail('旧密码错误'));
    run('UPDATE users SET password=? WHERE id=?', [await bcrypt.hash(new_password, 10), req.userId]);
    return res.json(success(null, '修改成功'));
  } catch (e) { return res.json(fail('修改失败')); }
});

// ========== 商品SKU/规格管理 ==========
router.post('/products/:id/skus', authAdmin, (req, res) => {
  try {
    const { sku_code, image, specs, price, original_price, cost_price, stock, weight, bar_code, sort } = req.body;
    const p = get('SELECT id FROM products WHERE id=?', [req.params.id]);
    if (!p) return res.json(fail('商品不存在'));
    const r = run(`INSERT INTO product_skus(product_id,sku_code,image,specs,price,original_price,cost_price,stock,weight,bar_code,sort)
      VALUES(?,?,?,?,?,?,?,?,?,?,?)`,
      [req.params.id, sku_code||'', image||'', JSON.stringify(specs||[]), price, original_price||0, cost_price||0, stock||0, weight||0, bar_code||'', sort||0]);
    logAction(req.userId, 'add_sku', 'product', req.params.id, `添加SKU`, req.ip);
    return res.json(success({id: r.lastInsertRowid}, '添加成功'));
  } catch(e) { return res.json(fail('添加失败')); }
});

router.put('/products/:id/skus/:sid', authAdmin, (req, res) => {
  try {
    const { sku_code, image, specs, price, original_price, cost_price, stock, weight, bar_code, sort } = req.body;
    run(`UPDATE product_skus SET sku_code=?,image=?,specs=?,price=?,original_price=?,cost_price=?,stock=?,weight=?,bar_code=?,sort=? WHERE id=? AND product_id=?`,
      [sku_code||'', image||'', JSON.stringify(specs||[]), price, original_price||0, cost_price||0, stock||0, weight||0, bar_code||'', sort||0, req.params.sid, req.params.id]);
    logAction(req.userId, 'update_sku', 'product', req.params.id, `更新SKU`, req.ip);
    return res.json(success(null, '更新成功'));
  } catch(e) { return res.json(fail('更新失败')); }
});

router.delete('/products/:id/skus/:sid', authAdmin, (req, res) => {
  try {
    run('DELETE FROM product_skus WHERE id=? AND product_id=?', [req.params.sid, req.params.id]);
    logAction(req.userId, 'delete_sku', 'product', req.params.id, `删除SKU`, req.ip);
    return res.json(success(null, '删除成功'));
  } catch(e) { return res.json(fail('删除失败')); }
});

router.post('/products/:id/specs', authAdmin, (req, res) => {
  try {
    const { name, spec_values, sort } = req.body;
    const p = get('SELECT id FROM products WHERE id=?', [req.params.id]);
    if (!p) return res.json(fail('商品不存在'));
    const r = run('INSERT INTO product_specs(product_id,name,spec_values,sort) VALUES(?,?,?,?)',
      [req.params.id, name, JSON.stringify(spec_values||[]), sort||0]);
    logAction(req.userId, 'add_spec', 'product', req.params.id, `添加规格: ${name}`, req.ip);
    return res.json(success({id: r.lastInsertRowid}, '添加成功'));
  } catch(e) { return res.json(fail('添加失败')); }
});

router.delete('/products/:id/specs/:sid', authAdmin, (req, res) => {
  try {
    run('DELETE FROM product_specs WHERE id=? AND product_id=?', [req.params.sid, req.params.id]);
    logAction(req.userId, 'delete_spec', 'product', req.params.id, `删除规格`, req.ip);
    return res.json(success(null, '删除成功'));
  } catch(e) { return res.json(fail('删除失败')); }
});

// 辅助：记录操作日志
function logAction(adminId, action, module, targetId, detail, ip) {
  try {
    run('INSERT INTO operation_logs(admin_id,action,module,target_id,detail,ip) VALUES(?,?,?,?,?,?)',
      [adminId, action, module, targetId||null, detail||'', ip||'']);
  } catch(e) {}
}

// ========== 仪表盘 ==========
router.get('/dashboard', authAdmin, (req, res) => {
  const totalUsers = get("SELECT COUNT(*) as c FROM users WHERE phone!='admin'").c;
  const pendingShip = get("SELECT COUNT(*) as c FROM orders WHERE status='pending_ship'").c;
  const pendingRefund = get("SELECT COUNT(*) as c FROM orders WHERE status='refunding'").c;
  const totalSales = get("SELECT COALESCE(SUM(pay_amount),0) as s FROM orders WHERE status NOT IN ('pending_pay','closed')").s;
  const today = get("SELECT COUNT(*) as c, COALESCE(SUM(pay_amount),0) as s FROM orders WHERE date(created_at)=date('now','localtime') AND status NOT IN ('pending_pay')");
  const lowStockCount = get('SELECT COUNT(*) as c FROM products WHERE status=1 AND stock<=10').c;

  return res.json(success({
    today_orders: today.c,
    today_sales: today.s,
    total_users: totalUsers,
    total_sales: totalSales,
    pending_ship: pendingShip,
    pending_refund: pendingRefund,
    low_stock: lowStockCount,
    total_orders: get('SELECT COUNT(*) as c FROM orders').c
  }));
});

router.get('/dashboard/chart', authAdmin, (req, res) => {
  const { days = 7 } = req.query;
  const chart = all(`SELECT date(created_at) as d, COUNT(*) as orders, COALESCE(SUM(pay_amount),0) as sales 
    FROM orders WHERE created_at >= date('now','localtime','-${days} day') GROUP BY d ORDER BY d`);
  return res.json(success(chart));
});

// ========== 商品管理 ==========
router.get('/products', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20, keyword, category_id, status } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE 1=1';
  const params = [];
  if (keyword) { where += ' AND name LIKE ?'; params.push(`%${keyword}%`); }
  if (category_id) { where += ' AND category_id=?'; params.push(category_id); }
  if (status !== undefined && status !== '') { where += ' AND status=?'; params.push(status); }

  const total = get(`SELECT COUNT(*) as c FROM products ${where}`, params).c;
  const list = all(`SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id=c.id ${where} ORDER BY p.id DESC LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

router.post('/products', authAdmin, (req, res) => {
  try {
    const { name, subtitle, category_id, image, images, price, original_price, cost_price, stock, unit,
      spec_type, description, is_new, is_hot, is_recommend, sort, weight, shipping_template_id, seo_keywords, seo_description } = req.body;
    if (!name || name.length > 200) return res.json(fail('请输入商品名称（200字以内）'));
    if (!price || price <= 0) return res.json(fail('价格必须大于0'));

    const r = run(`INSERT INTO products(name,subtitle,category_id,image,images,price,original_price,cost_price,stock,unit,
      spec_type,description,is_new,is_hot,is_recommend,sort,weight,shipping_template_id,seo_keywords,seo_description)
      VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
      [name, subtitle||'', category_id||null, image||'', JSON.stringify(images||[]), price, original_price||0, cost_price||0, stock||0, unit||'件',
       spec_type||0, description||'', is_new||0, is_hot||0, is_recommend||0, sort||0, weight||0, shipping_template_id||null, seo_keywords||'', seo_description||'']);
    logAction(req.userId, 'add', 'product', r.lastInsertRowid, `添加商品: ${name}`, req.ip);
    return res.json(success({ id: r.lastInsertRowid }, '添加成功'));
  } catch (e) { return res.json(fail('添加失败')); }
});

router.get('/products/:id', authAdmin, (req, res) => {
  const product = get('SELECT * FROM products WHERE id=?', [req.params.id]);
  if (!product) return res.json(fail('商品不存在'));
  product.images = JSON.parse(product.images || '[]');
  product.skus = all('SELECT * FROM product_skus WHERE product_id=? ORDER BY sort', [product.id]);
  product.specs = all('SELECT * FROM product_specs WHERE product_id=? ORDER BY sort', [product.id]);
  product.specs.forEach(s => s.values = JSON.parse(s.spec_values || '[]'));
  return res.json(success(product));
});

router.put('/products/:id', authAdmin, (req, res) => {
  try {
    const { name, subtitle, category_id, image, images, price, original_price, cost_price, stock, unit,
      spec_type, description, is_new, is_hot, is_recommend, sort, weight, shipping_template_id, seo_keywords, seo_description, status, skus, specs } = req.body;
    if (!name) return res.json(fail('商品名称不能为空'));
    
    run(`UPDATE products SET name=?,subtitle=?,category_id=?,image=?,images=?,price=?,original_price=?,cost_price=?,
      stock=?,unit=?,spec_type=?,description=?,is_new=?,is_hot=?,is_recommend=?,sort=?,weight=?,shipping_template_id=?,
      seo_keywords=?,seo_description=?,status=?,updated_at=datetime('now','localtime') WHERE id=?`,
      [name, subtitle||'', category_id||null, image||'', JSON.stringify(images||[]), price, original_price||0, cost_price||0,
       stock||0, unit||'件', spec_type||0, description||'', is_new||0, is_hot||0, is_recommend||0, sort||0, weight||0,
       shipping_template_id||null, seo_keywords||'', seo_description||'', status||1, req.params.id]);

    // 更新SKU
    if (skus && Array.isArray(skus)) {
      run('DELETE FROM product_skus WHERE product_id=?', [req.params.id]);
      for (const sku of skus) {
        run('INSERT INTO product_skus(product_id,sku_code,image,specs,price,original_price,cost_price,stock,weight,sort) VALUES(?,?,?,?,?,?,?,?,?,?)',
          [req.params.id, sku.sku_code||'', sku.image||'', JSON.stringify(sku.specs||[]), sku.price, sku.original_price||0, sku.cost_price||0, sku.stock||0, sku.weight||0, sku.sort||0]);
      }
    }
    // 更新规格
    if (specs && Array.isArray(specs)) {
      run('DELETE FROM product_specs WHERE product_id=?', [req.params.id]);
      for (const spec of specs) {
        run('INSERT INTO product_specs(product_id,name,spec_values,sort) VALUES(?,?,?,?)',
          [req.params.id, spec.name, JSON.stringify(spec.values||[]), spec.sort||0]);
      }
    }

    logAction(req.userId, 'update', 'product', +req.params.id, `更新商品: ${name}`, req.ip);
    return res.json(success(null, '更新成功'));
  } catch (e) { return res.json(fail('更新失败')); }
});

router.delete('/products/:id', authAdmin, (req, res) => {
  const p = get('SELECT name FROM products WHERE id=?', [req.params.id]);
  run('DELETE FROM product_skus WHERE product_id=?', [req.params.id]);
  run('DELETE FROM product_specs WHERE product_id=?', [req.params.id]);
  run('DELETE FROM product_images WHERE product_id=?', [req.params.id]);
  run('DELETE FROM products WHERE id=?', [req.params.id]);
  logAction(req.userId, 'delete', 'product', +req.params.id, `删除商品: ${p?.name||''}`, req.ip);
  return res.json(success(null, '删除成功'));
});

router.put('/products/:id/status', authAdmin, (req, res) => {
  const { status } = req.body;
  const p = get('SELECT name FROM products WHERE id=?', [req.params.id]);
  run('UPDATE products SET status=?,updated_at=datetime(\'now\',\'localtime\') WHERE id=?', [status, req.params.id]);
  logAction(req.userId, status?'online':'offline', 'product', +req.params.id, `${status?'上架':'下架'}商品: ${p?.name||''}`, req.ip);
  return res.json(success(null, status ? '已上架' : '已下架'));
});

// ========== 分类管理 ==========
router.get('/categories', authAdmin, (req, res) => {
  const list = all('SELECT * FROM categories ORDER BY sort ASC');
  return res.json(success(list));
});

router.post('/categories', authAdmin, (req, res) => {
  const { name, pid, icon, image, sort } = req.body;
  if (!name) return res.json(fail('分类名称不能为空'));
  const r = run('INSERT INTO categories(name,pid,icon,image,sort) VALUES(?,?,?,?,?)',
    [name, pid||0, icon||'', image||'', sort||0]);
  return res.json(success({ id: r.lastInsertRowid }, '添加成功'));
});

router.put('/categories/:id', authAdmin, (req, res) => {
  const { name, pid, icon, image, sort, status } = req.body;
  run('UPDATE categories SET name=?,pid=?,icon=?,image=?,sort=?,status=? WHERE id=?',
    [name, pid||0, icon||'', image||'', sort||0, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/categories/:id', authAdmin, (req, res) => {
  run('DELETE FROM categories WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

// ========== 订单管理 ==========
router.get('/orders', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20, status, keyword } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE 1=1';
  const params = [];
  if (status) { where += ' AND o.status=?'; params.push(status); }
  if (keyword) { where += ' AND (o.order_no LIKE ? OR o.consignee LIKE ? OR o.phone LIKE ?)'; params.push(`%${keyword}%`, `%${keyword}%`, `%${keyword}%`); }

  const total = get(`SELECT COUNT(*) as c FROM orders o ${where}`, params).c;
  const list = all(`SELECT o.*, u.nickname FROM orders o LEFT JOIN users u ON o.user_id=u.id ${where} ORDER BY o.id DESC LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]);
  for (const order of list) {
    order.items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
  }
  return res.json(page(list, total, pageNum, size));
});

router.get('/orders/:orderNo', authAdmin, (req, res) => {
  const order = get('SELECT o.*, u.nickname, u.phone as user_phone FROM orders o LEFT JOIN users u ON o.user_id=u.id WHERE o.order_no=?', [req.params.orderNo]);
  if (!order) return res.json(fail('订单不存在'));
  order.items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
  order.logs = all('SELECT * FROM order_logs WHERE order_id=? ORDER BY id ASC', [order.id]);
  return res.json(success(order));
});

router.post('/orders/:orderNo/ship', authAdmin, (req, res) => {
  const { shipping_company, shipping_no } = req.body;
  const order = get('SELECT * FROM orders WHERE order_no=?', [req.params.orderNo]);
  if (!order) return res.json(fail('订单不存在'));
  run('UPDATE orders SET status=?,shipping_company=?,shipping_no=?,shipping_time=datetime(\'now\',\'localtime\') WHERE id=?',
    ['shipped', shipping_company||'', shipping_no||'', order.id]);
  run('INSERT INTO order_logs(order_id,action,content,operator) VALUES(?,?,?,?)', [order.id, 'ship', `发货:${shipping_company||''} ${shipping_no||''}`, 'admin']);
  return res.json(success(null, '发货成功'));
});

router.post('/orders/:orderNo/complete', authAdmin, (req, res) => {
  run("UPDATE orders SET status='completed',updated_at=datetime('now','localtime') WHERE order_no=?", [req.params.orderNo]);
  return res.json(success(null, '操作成功'));
});

router.post('/orders/:orderNo/close', authAdmin, (req, res) => {
  run("UPDATE orders SET status='closed',close_time=datetime('now','localtime') WHERE order_no=?", [req.params.orderNo]);
  return res.json(success(null, '已关闭'));
});

// ========== 会员管理 ==========
router.get('/users', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20, keyword, level_id } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = "WHERE phone != 'admin'";
  const params = [];
  if (keyword) { where += ' AND (nickname LIKE ? OR phone LIKE ?)'; params.push(`%${keyword}%`, `%${keyword}%`); }
  if (level_id) { where += ' AND level_id=?'; params.push(level_id); }

  const total = get(`SELECT COUNT(*) as c FROM users ${where}`, params).c;
  const list = all(`SELECT u.*, l.name as level_name FROM users u LEFT JOIN user_levels l ON u.level_id=l.id ${where} ORDER BY u.id DESC LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]);
  list.forEach(u => delete u.password);
  return res.json(page(list, total, pageNum, size));
});

router.get('/users/:id', authAdmin, (req, res) => {
  const user = get('SELECT u.*, l.name as level_name FROM users u LEFT JOIN user_levels l ON u.level_id=l.id WHERE u.id=?', [req.params.id]);
  if (!user) return res.json(fail('用户不存在'));
  delete user.password;
  return res.json(success(user));
});

router.put('/users/:id', authAdmin, (req, res) => {
  const { nickname, phone, level_id, status, balance } = req.body;
  run('UPDATE users SET nickname=?,phone=?,level_id=?,status=?,balance=? WHERE id=?',
    [nickname, phone, level_id, status||1, balance||0, req.params.id]);
  return res.json(success(null, '更新成功'));
});

// 用户等级管理
router.get('/levels', authAdmin, (req, res) => {
  const list = all('SELECT * FROM user_levels ORDER BY level ASC');
  return res.json(success(list));
});

router.post('/levels', authAdmin, (req, res) => {
  const { name, level, min_experience, discount, icon, description } = req.body;
  run('INSERT INTO user_levels(name,level,min_experience,discount,icon,description) VALUES(?,?,?,?,?,?)',
    [name, level, min_experience||0, discount||1.00, icon||'', description||'']);
  return res.json(success(null, '添加成功'));
});

router.put('/levels/:id', authAdmin, (req, res) => {
  const { name, min_experience, discount, icon, description } = req.body;
  run('UPDATE user_levels SET name=?,min_experience=?,discount=?,icon=?,description=? WHERE id=?',
    [name, min_experience||0, discount||1.00, icon||'', description||'', req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/levels/:id', authAdmin, (req, res) => {
  run('DELETE FROM user_levels WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

// 会员套餐
router.get('/plans', authAdmin, (req, res) => {
  const list = all('SELECT mp.*, l.name as level_name FROM membership_plans mp LEFT JOIN user_levels l ON mp.level_id=l.id ORDER BY mp.sort ASC');
  return res.json(success(list));
});

router.post('/plans', authAdmin, (req, res) => {
  const { name, type, price, original_price, level_id, give_experience, give_coupon_ids, description, sort } = req.body;
  run('INSERT INTO membership_plans(name,type,price,original_price,level_id,give_experience,give_coupon_ids,description,sort) VALUES(?,?,?,?,?,?,?,?,?)',
    [name, type, price, original_price||0, level_id||null, give_experience||0, give_coupon_ids||'', description||'', sort||0]);
  return res.json(success(null, '添加成功'));
});

router.put('/plans/:id', authAdmin, (req, res) => {
  const { name, type, price, original_price, level_id, give_experience, give_coupon_ids, description, sort, status } = req.body;
  run('UPDATE membership_plans SET name=?,type=?,price=?,original_price=?,level_id=?,give_experience=?,give_coupon_ids=?,description=?,sort=?,status=? WHERE id=?',
    [name, type, price, original_price||0, level_id||null, give_experience||0, give_coupon_ids||'', description||'', sort||0, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/plans/:id', authAdmin, (req, res) => {
  run('DELETE FROM membership_plans WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

// ========== 分销管理 ==========
router.get('/distribution/users', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20, keyword } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = "WHERE u.parent_id IS NOT NULL AND u.phone != 'admin'";
  const params = [];
  if (keyword) { where += ' AND (u.nickname LIKE ? OR u.phone LIKE ?)'; params.push(`%${keyword}%`, `%${keyword}%`); }

  const total = get(`SELECT COUNT(DISTINCT u.id) as c FROM users u ${where}`, params).c;
  const list = all(`SELECT u.id,u.nickname,u.avatar,u.phone,u.team_count,u.total_consumed,u.created_at,
    (SELECT COALESCE(SUM(commission),0) FROM distribution_records WHERE user_id=u.id AND status='settled') as total_commission
    FROM users u ${where} ORDER BY u.id DESC LIMIT ? OFFSET ?`, [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

router.get('/distribution/commissions', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20, status } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE 1=1';
  const params = [];
  if (status) { where += ' AND dr.status=?'; params.push(status); }

  const total = get(`SELECT COUNT(*) as c FROM distribution_records dr ${where}`, params).c;
  const list = all(`SELECT dr.*, u.nickname, u.phone, o.order_no FROM distribution_records dr 
    LEFT JOIN users u ON dr.user_id=u.id LEFT JOIN orders o ON dr.order_id=o.id ${where} ORDER BY dr.id DESC LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

router.post('/distribution/commission/:id/settle', authAdmin, (req, res) => {
  run("UPDATE distribution_records SET status='settled',settled_at=datetime('now','localtime') WHERE id=?", [req.params.id]);
  return res.json(success(null, '已结算'));
});

router.get('/distribution/withdraws', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20, status } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE 1=1';
  const params = [];
  if (status) { where += ' AND wr.status=?'; params.push(status); }

  const total = get(`SELECT COUNT(*) as c FROM withdraw_requests wr ${where}`, params).c;
  const list = all(`SELECT wr.*, u.nickname, u.phone FROM withdraw_requests wr LEFT JOIN users u ON wr.user_id=u.id ${where} ORDER BY wr.id DESC LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

router.post('/distribution/withdraw/:id/approve', authAdmin, (req, res) => {
  const wr = get('SELECT * FROM withdraw_requests WHERE id=?', [req.params.id]);
  if (!wr) return res.json(fail('记录不存在'));
  transaction(() => {
    run("UPDATE withdraw_requests SET status='approved',completed_at=datetime('now','localtime') WHERE id=?", [req.params.id]);
    run('UPDATE users SET freeze_balance=freeze_balance-?,balance=balance-? WHERE id=?', [wr.amount, wr.amount, wr.user_id]);
  });
  return res.json(success(null, '审核通过'));
});

router.post('/distribution/withdraw/:id/reject', authAdmin, (req, res) => {
  const { reject_reason } = req.body;
  const wr = get('SELECT * FROM withdraw_requests WHERE id=?', [req.params.id]);
  if (!wr) return res.json(fail('记录不存在'));
  transaction(() => {
    run('UPDATE withdraw_requests SET status=?,reject_reason=? WHERE id=?', ['rejected', reject_reason||'', req.params.id]);
    run('UPDATE users SET freeze_balance=freeze_balance-? WHERE id=?', [wr.amount, wr.user_id]);
  });
  return res.json(success(null, '已拒绝'));
});

router.get('/distribution/levels', authAdmin, (req, res) => {
  const list = all('SELECT * FROM distribution_levels ORDER BY level ASC');
  return res.json(success(list));
});

router.post('/distribution/levels', authAdmin, (req, res) => {
  const { name, level, min_team_count, min_team_sales, commission_rate, commission_rate2, commission_rate3 } = req.body;
  run('INSERT INTO distribution_levels(name,level,min_team_count,min_team_sales,commission_rate,commission_rate2,commission_rate3) VALUES(?,?,?,?,?,?,?)',
    [name, level, min_team_count||0, min_team_sales||0, commission_rate||0, commission_rate2||0, commission_rate3||0]);
  return res.json(success(null, '添加成功'));
});

router.put('/distribution/levels/:id', authAdmin, (req, res) => {
  const { name, min_team_count, min_team_sales, commission_rate, commission_rate2, commission_rate3, status } = req.body;
  run('UPDATE distribution_levels SET name=?,min_team_count=?,min_team_sales=?,commission_rate=?,commission_rate2=?,commission_rate3=?,status=? WHERE id=?',
    [name, min_team_count||0, min_team_sales||0, commission_rate||0, commission_rate2||0, commission_rate3||0, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/distribution/levels/:id', authAdmin, (req, res) => {
  run('DELETE FROM distribution_levels WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

router.put('/distribution/config', authAdmin, (req, res) => {
  const { configs } = req.body; // [{key, value}]
  for (const c of configs) {
    run('UPDATE distribution_config SET value=? WHERE key=?', [c.value, c.key]);
  }
  return res.json(success(null, '更新成功'));
});

// ========== 营销管理 ==========
router.get('/coupons', authAdmin, (req, res) => {
  const list = all('SELECT * FROM coupons ORDER BY id DESC');
  return res.json(success(list));
});

router.post('/coupons', authAdmin, (req, res) => {
  const { name, type, value, min_amount, max_amount, total_count, per_limit, valid_days, start_time, end_time } = req.body;
  run('INSERT INTO coupons(name,type,value,min_amount,max_amount,total_count,per_limit,valid_days,start_time,end_time) VALUES(?,?,?,?,?,?,?,?,?,?)',
    [name, type, value, min_amount||0, max_amount||0, total_count||0, per_limit||1, valid_days||30, start_time||null, end_time||null]);
  return res.json(success(null, '添加成功'));
});

router.put('/coupons/:id', authAdmin, (req, res) => {
  const { name, type, value, min_amount, max_amount, total_count, per_limit, valid_days, start_time, end_time, status } = req.body;
  run('UPDATE coupons SET name=?,type=?,value=?,min_amount=?,max_amount=?,total_count=?,per_limit=?,valid_days=?,start_time=?,end_time=?,status=? WHERE id=?',
    [name, type, value, min_amount||0, max_amount||0, total_count||0, per_limit||1, valid_days||30, start_time||null, end_time||null, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/coupons/:id', authAdmin, (req, res) => {
  run('DELETE FROM coupons WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

router.get('/seckill', authAdmin, (req, res) => {
  const list = all('SELECT sp.*, p.name,p.image FROM seckill_products sp JOIN products p ON sp.product_id=p.id ORDER BY sp.id DESC');
  return res.json(success(list));
});

router.post('/seckill', authAdmin, (req, res) => {
  const { product_id, seckill_price, stock, per_limit, start_time, end_time } = req.body;
  run('INSERT INTO seckill_products(product_id,seckill_price,stock,per_limit,start_time,end_time) VALUES(?,?,?,?,?,?)',
    [product_id, seckill_price, stock||0, per_limit||1, start_time, end_time]);
  return res.json(success(null, '添加成功'));
});

router.put('/seckill/:id', authAdmin, (req, res) => {
  const { seckill_price, stock, per_limit, start_time, end_time, status } = req.body;
  run('UPDATE seckill_products SET seckill_price=?,stock=?,per_limit=?,start_time=?,end_time=?,status=? WHERE id=?',
    [seckill_price, stock||0, per_limit||1, start_time, end_time, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/seckill/:id', authAdmin, (req, res) => {
  run('DELETE FROM seckill_products WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

router.get('/group-buy', authAdmin, (req, res) => {
  const list = all('SELECT gb.*, p.name,p.image FROM group_buy_products gb JOIN products p ON gb.product_id=p.id ORDER BY gb.id DESC');
  return res.json(success(list));
});

router.post('/group-buy', authAdmin, (req, res) => {
  const { product_id, group_price, min_people, stock, start_time, end_time } = req.body;
  run('INSERT INTO group_buy_products(product_id,group_price,min_people,stock,start_time,end_time) VALUES(?,?,?,?,?,?)',
    [product_id, group_price, min_people||2, stock||0, start_time, end_time]);
  return res.json(success(null, '添加成功'));
});

router.put('/group-buy/:id', authAdmin, (req, res) => {
  const { group_price, min_people, stock, start_time, end_time, status } = req.body;
  run('UPDATE group_buy_products SET group_price=?,min_people=?,stock=?,start_time=?,end_time=?,status=? WHERE id=?',
    [group_price, min_people||2, stock||0, start_time, end_time, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/group-buy/:id', authAdmin, (req, res) => {
  run('DELETE FROM group_buy_products WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

// ========== 系统配置 ==========
router.get('/config', authAdmin, (req, res) => {
  const list = all('SELECT * FROM system_config ORDER BY group_name, sort');
  const grouped = {};
  list.forEach(c => {
    if (!grouped[c.group_name]) grouped[c.group_name] = [];
    grouped[c.group_name].push(c);
  });
  return res.json(success(grouped));
});

router.put('/config', authAdmin, (req, res) => {
  const { configs } = req.body;
  for (const c of configs) {
    run('UPDATE system_config SET value=? WHERE key=?', [c.value, c.key]);
  }
  return res.json(success(null, '更新成功'));
});

router.put('/config/:key', authAdmin, (req, res) => {
  const { value } = req.body;
  run('UPDATE system_config SET value=? WHERE key=?', [value, req.params.key]);
  return res.json(success(null, '更新成功'));
});

// 轮播图
router.get('/banners', authAdmin, (req, res) => {
  const list = all('SELECT * FROM banners ORDER BY sort ASC');
  return res.json(success(list));
});

router.post('/banners', authAdmin, (req, res) => {
  const { title, image, url, sort } = req.body;
  run('INSERT INTO banners(title,image,url,sort) VALUES(?,?,?,?)', [title||'', image, url||'', sort||0]);
  return res.json(success(null, '添加成功'));
});

router.put('/banners/:id', authAdmin, (req, res) => {
  const { title, image, url, sort, status } = req.body;
  run('UPDATE banners SET title=?,image=?,url=?,sort=?,status=? WHERE id=?',
    [title||'', image, url||'', sort||0, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/banners/:id', authAdmin, (req, res) => {
  run('DELETE FROM banners WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

// CMS页面
router.get('/pages', authAdmin, (req, res) => {
  const list = all('SELECT id, title, type, status, created_at FROM pages ORDER BY id ASC');
  return res.json(success(list));
});

router.get('/pages/:id', authAdmin, (req, res) => {
  const page = get('SELECT * FROM pages WHERE id=?', [req.params.id]);
  return res.json(success(page));
});

router.put('/pages/:id', authAdmin, (req, res) => {
  const { title, content } = req.body;
  run("UPDATE pages SET title=?,content=?,updated_at=datetime('now','localtime') WHERE id=?", [title, content, req.params.id]);
  return res.json(success(null, '更新成功'));
});

// 运费模板
router.get('/shipping-templates', authAdmin, (req, res) => {
  const list = all('SELECT * FROM shipping_templates ORDER BY id DESC');
  return res.json(success(list));
});

router.post('/shipping-templates', authAdmin, (req, res) => {
  const { name, type, free_shipping_amount, first_piece, first_fee, extra_piece, extra_fee } = req.body;
  run('INSERT INTO shipping_templates(name,type,free_shipping_amount,first_piece,first_fee,extra_piece,extra_fee) VALUES(?,?,?,?,?,?,?)',
    [name, type||'piece', free_shipping_amount||0, first_piece||1, first_fee||0, extra_piece||1, extra_fee||0]);
  return res.json(success(null, '添加成功'));
});

router.put('/shipping-templates/:id', authAdmin, (req, res) => {
  const { name, type, free_shipping_amount, first_piece, first_fee, extra_piece, extra_fee, status } = req.body;
  run('UPDATE shipping_templates SET name=?,type=?,free_shipping_amount=?,first_piece=?,first_fee=?,extra_piece=?,extra_fee=?,status=? WHERE id=?',
    [name, type, free_shipping_amount||0, first_piece||1, first_fee||0, extra_piece||1, extra_fee||0, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/shipping-templates/:id', authAdmin, (req, res) => {
  run('DELETE FROM shipping_templates WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

// ========== AI知识库管理 ==========
router.get('/knowledge', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20, keyword } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE 1=1';
  const params = [];
  if (keyword) { where += ' AND (question LIKE ? OR answer LIKE ? OR keywords LIKE ?)'; params.push(`%${keyword}%`, `%${keyword}%`, `%${keyword}%`); }
  const total = get(`SELECT COUNT(*) as c FROM ai_knowledge_base ${where}`, params).c;
  const list = all(`SELECT * FROM ai_knowledge_base ${where} ORDER BY weight DESC LIMIT ? OFFSET ?`, [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

router.post('/knowledge', authAdmin, (req, res) => {
  const { category, question, answer, keywords, weight } = req.body;
  run('INSERT INTO ai_knowledge_base(category,question,answer,keywords,weight) VALUES(?,?,?,?,?)',
    [category||'', question, answer, keywords||'', weight||0]);
  return res.json(success(null, '添加成功'));
});

router.put('/knowledge/:id', authAdmin, (req, res) => {
  const { category, question, answer, keywords, weight, status } = req.body;
  run("UPDATE ai_knowledge_base SET category=?,question=?,answer=?,keywords=?,weight=?,status=?,updated_at=datetime('now','localtime') WHERE id=?",
    [category||'', question, answer, keywords||'', weight||0, status||1, req.params.id]);
  return res.json(success(null, '更新成功'));
});

router.delete('/knowledge/:id', authAdmin, (req, res) => {
  run('DELETE FROM ai_knowledge_base WHERE id=?', [req.params.id]);
  return res.json(success(null, '删除成功'));
});

router.post('/knowledge/import', authAdmin, (req, res) => {
  const { items } = req.body;
  if (!items || !items.length) return res.json(fail('请提供数据'));
  for (const item of items) {
    run('INSERT INTO ai_knowledge_base(category,question,answer,keywords,weight) VALUES(?,?,?,?,?)',
      [item.category||'', item.question, item.answer, item.keywords||'', item.weight||0]);
  }
  return res.json(success(null, `成功导入${items.length}条`));
});

module.exports = router;

===== server/src/routes/user.js =====
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { nanoid } = require('nanoid');
const config = require('../../config');
const { get, run, all } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authUser } = require('../middleware/auth');

// 注册
router.post('/register', async (req, res) => {
  try {
    const { phone, password, nickname, parent_id } = req.body;
    if (!phone || !password) return res.json(fail('手机号和密码不能为空'));
    if (!/^1\d{10}$/.test(phone)) return res.json(fail('手机号格式不正确'));
    if (password.length < 6) return res.json(fail('密码长度不能少于6位'));

    const exist = get('SELECT id FROM users WHERE phone = ?', [phone]);
    if (exist) return res.json(fail('该手机号已注册'));

    const hash = await bcrypt.hash(password, 10);
    const name = nickname || `用户${phone.slice(-4)}`;

    const result = run(
      'INSERT INTO users (phone, password, nickname, parent_id, created_at) VALUES (?,?,?,?,datetime(\'now\',\'localtime\'))',
      [phone, hash, name, parent_id || null]
    );

    return res.json(success({ id: result.lastInsertRowid }, '注册成功'));
  } catch (e) {
    console.error('注册失败:', e);
    return res.json(fail('注册失败'));
  }
});

// 登录
router.post('/login', async (req, res) => {
  try {
    const { phone, password } = req.body;
    if (!phone || !password) return res.json(fail('手机号和密码不能为空'));
    const ip = req.ip || req.headers['x-forwarded-for'] || '';

    const user = get('SELECT * FROM users WHERE phone = ?', [phone]);
    if (!user) {
      run('INSERT INTO login_logs(user_id,phone,ip,user_agent,result,reason) VALUES(?,?,?,?,?,?)',
        [null, phone, ip, (req.headers['user-agent']||'').slice(0,200), 'fail', '用户不存在']);
      return res.json(fail('用户不存在'));
    }
    if (user.status === 0) {
      run('INSERT INTO login_logs(user_id,phone,ip,user_agent,result,reason) VALUES(?,?,?,?,?,?)',
        [user.id, phone, ip, (req.headers['user-agent']||'').slice(0,200), 'fail', '账号被禁用']);
      return res.json(fail('账号已被禁用'));
    }

    const valid = await bcrypt.compare(password, user.password);
    if (!valid) {
      run('INSERT INTO login_logs(user_id,phone,ip,user_agent,result,reason) VALUES(?,?,?,?,?,?)',
        [user.id, phone, ip, (req.headers['user-agent']||'').slice(0,200), 'fail', '密码错误']);
      return res.json(fail('密码错误'));
    }

    const token = jwt.sign({ userId: user.id }, config.jwtSecret, { expiresIn: config.jwtExpiresIn });
    run('INSERT INTO login_logs(user_id,phone,ip,user_agent,result,reason) VALUES(?,?,?,?,?,?)',
      [user.id, phone, ip, (req.headers['user-agent']||'').slice(0,200), 'success', '']);

    return res.json(success({
      token,
      user: { id: user.id, phone: user.phone, nickname: user.nickname, avatar: user.avatar, level_id: user.level_id }
    }, '登录成功'));
  } catch (e) {
    console.error('登录失败:', e);
    return res.json(fail('登录失败'));
  }
});

// 获取用户信息
router.get('/info', authUser, (req, res) => {
  try {
    const user = get(`SELECT u.*, l.name as level_name, l.discount as level_discount 
      FROM users u LEFT JOIN user_levels l ON u.level_id = l.id WHERE u.id = ?`, [req.userId]);
    if (!user) return res.json(fail('用户不存在'));
    delete user.password;
    return res.json(success(user));
  } catch (e) {
    return res.json(fail('获取信息失败'));
  }
});

// 更新个人信息
router.put('/info', authUser, (req, res) => {
  try {
    const { nickname, avatar } = req.body;
    if (nickname) run('UPDATE users SET nickname=? WHERE id=?', [nickname, req.userId]);
    if (avatar) run('UPDATE users SET avatar=? WHERE id=?', [avatar, req.userId]);
    return res.json(success(null, '更新成功'));
  } catch (e) {
    return res.json(fail('更新失败'));
  }
});

// 地址列表
router.get('/address', authUser, (req, res) => {
  const list = all('SELECT * FROM user_addresses WHERE user_id=? ORDER BY is_default DESC, id DESC', [req.userId]);
  return res.json(success(list));
});

// 新增地址
router.post('/address', authUser, (req, res) => {
  try {
    const { name, phone, province, city, district, detail, zip_code, is_default } = req.body;
    if (!name || !phone) return res.json(fail('请填写完整信息'));
    
    if (is_default) run('UPDATE user_addresses SET is_default=0 WHERE user_id=?', [req.userId]);
    const count = get('SELECT COUNT(*) as c FROM user_addresses WHERE user_id=?', [req.userId]);
    const def = is_default || count.c === 0 ? 1 : 0;

    const r = run(
      'INSERT INTO user_addresses(user_id,name,phone,province,city,district,detail,zip_code,is_default) VALUES(?,?,?,?,?,?,?,?,?)',
      [req.userId, name, phone, province||'', city||'', district||'', detail||'', zip_code||'', def]
    );
    return res.json(success({ id: r.lastInsertRowid }, '新增成功'));
  } catch (e) {
    return res.json(fail('新增失败'));
  }
});

// 编辑地址
router.put('/address/:id', authUser, (req, res) => {
  try {
    const addr = get('SELECT id FROM user_addresses WHERE id=? AND user_id=?', [req.params.id, req.userId]);
    if (!addr) return res.json(fail('地址不存在'));
    const { name, phone, province, city, district, detail, zip_code, is_default } = req.body;
    
    if (is_default) run('UPDATE user_addresses SET is_default=0 WHERE user_id=?', [req.userId]);
    
    run(`UPDATE user_addresses SET name=?,phone=?,province=?,city=?,district=?,detail=?,zip_code=?,is_default=?
      WHERE id=?`, [name, phone, province||'', city||'', district||'', detail||'', zip_code||'', is_default?1:0, req.params.id]);
    return res.json(success(null, '更新成功'));
  } catch (e) {
    return res.json(fail('更新失败'));
  }
});

// 删除地址
router.delete('/address/:id', authUser, (req, res) => {
  run('DELETE FROM user_addresses WHERE id=? AND user_id=?', [req.params.id, req.userId]);
  return res.json(success(null, '删除成功'));
});

// 设为默认
router.put('/address/:id/default', authUser, (req, res) => {
  run('UPDATE user_addresses SET is_default=0 WHERE user_id=?', [req.userId]);
  run('UPDATE user_addresses SET is_default=1 WHERE id=? AND user_id=?', [req.params.id, req.userId]);
  return res.json(success(null, '设置成功'));
});

// 用户等级信息
router.get('/level', authUser, (req, res) => {
  const user = get('SELECT level_id, experience FROM users WHERE id=?', [req.userId]);
  const current = get('SELECT * FROM user_levels WHERE id=?', [user.level_id]);
  const next = get('SELECT * FROM user_levels WHERE min_experience>? ORDER BY min_experience ASC LIMIT 1', [user.experience]);
  return res.json(success({ experience: user.experience, current_level: current, next_level: next }));
});

// 修改密码
router.put('/password', authUser, async (req, res) => {
  try {
    const { old_password, new_password } = req.body;
    if (!old_password || !new_password) return res.json(fail('请填写完整'));
    if (new_password.length < 6) return res.json(fail('密码长度不能少于6位'));
    
    const user = get('SELECT password FROM users WHERE id=?', [req.userId]);
    if (!await bcrypt.compare(old_password, user.password)) return res.json(fail('旧密码错误'));
    
    run('UPDATE users SET password=? WHERE id=?', [await bcrypt.hash(new_password, 10), req.userId]);
    return res.json(success(null, '修改成功'));
  } catch (e) {
    return res.json(fail('修改失败'));
  }
});

// ========== 收藏 ==========
// 添加收藏
router.post('/favorite', authUser, (req, res) => {
  try {
    const { product_id } = req.body;
    if (!product_id) return res.json(fail('参数错误'));
    const exist = get('SELECT id FROM user_favorites WHERE user_id=? AND product_id=?', [req.userId, product_id]);
    if (exist) return res.json(fail('已收藏'));
    run('INSERT INTO user_favorites(user_id,product_id) VALUES(?,?)', [req.userId, product_id]);
    return res.json(success(null, '收藏成功'));
  } catch (e) { return res.json(fail('收藏失败')); }
});

// 取消收藏
router.delete('/favorite/:productId', authUser, (req, res) => {
  run('DELETE FROM user_favorites WHERE user_id=? AND product_id=?', [req.userId, req.params.productId]);
  return res.json(success(null, '已取消收藏'));
});

// 收藏列表（支持检查单个商品是否收藏）
router.get('/favorites', authUser, (req, res) => {
  const { product_id } = req.query;
  if (product_id) {
    const fav = get('SELECT id FROM user_favorites WHERE user_id=? AND product_id=?', [req.userId, +product_id]);
    return res.json(success({ some: !!fav }));
  }
  const list = all(`SELECT uf.product_id, uf.created_at, p.name, p.image, p.price 
    FROM user_favorites uf JOIN products p ON uf.product_id=p.id 
    WHERE uf.user_id=? ORDER BY uf.id DESC`, [req.userId]);
  return res.json(success(list));
});

// ========== 用户通知 ==========
router.get('/notifications', authUser, (req, res) => {
  const list = all('SELECT * FROM notifications WHERE user_id=? OR user_id=0 ORDER BY id DESC LIMIT 50', [req.userId]);
  return res.json(success(list));
});

// 标记通知已读
router.put('/notifications/read', authUser, (req, res) => {
  run('UPDATE notifications SET is_read=1 WHERE user_id=?', [req.userId]);
  return res.json(success(null, '已读'));
});

// ========== 短信验证码登录 ==========
// 接收 captchaStore（在 captcha.js 中定义的内存存储）
const smsLoginRouter = express.Router();

router.post('/sms-login', async (req, res) => {
  try {
    const { phone, sms_code } = req.body;
    if (!phone || !sms_code) return res.json(fail('手机号和验证码不能为空'));
    
    // 验证码已由前端调用 /captcha/verify 验证通过，此处直接处理登录
    // 查找或创建用户
    let user = get('SELECT * FROM users WHERE phone = ?', [phone]);
    
    if (!user) {
      // 自动注册新用户
      const hash = await bcrypt.hash(sms_code, 10);
      const nick = '用户' + phone.slice(-4);
      run("INSERT INTO users (phone, password, nickname, status, created_at, updated_at) VALUES (?, ?, ?, 1, datetime('now','localtime'), datetime('now','localtime'))",
        [phone, hash, nick]);
      user = get('SELECT * FROM users WHERE phone = ?', [phone]);
    }
    
    if (!user) return res.json(fail('登录失败'));
    if (user.status === 0) return res.json(fail('账号已被禁用'));
    
    const token = jwt.sign({ userId: user.id }, config.jwtSecret, { expiresIn: config.jwtExpiresIn });
    
    const ip = req.ip || req.headers['x-forwarded-for'] || '';
    run('INSERT INTO login_logs(user_id,phone,ip,user_agent,result,reason) VALUES(?,?,?,?,?,?)',
      [user.id, phone, ip, (req.headers['user-agent']||'').slice(0,200), 'success', '短信登录']);
    
    return res.json(success({
      token,
      user: {
        id: user.id,
        nickname: user.nickname,
        avatar: user.avatar,
        phone: user.phone,
        balance: user.balance,
        level_id: user.level_id
      }
    }, '登录成功'));
  } catch (e) {
    console.error('短信登录异常:', e);
    return res.json(fail('登录失败'));
  }
});

module.exports = router;

===== server/src/routes/product.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, page } = require('../utils/response');

// 商品列表
router.get('/list', (req, res) => {
  const { page: p = 1, pageSize = 20, category_id, keyword, sort, order } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE p.status=1';
  const params = [];

  if (category_id) { where += ' AND p.category_id=?'; params.push(category_id); }
  if (keyword) { where += ' AND p.name LIKE ?'; params.push(`%${keyword}%`); }

  let orderBy = 'p.sort ASC, p.id DESC';
  if (sort === 'price') orderBy = `p.price ${order === 'asc' ? 'ASC' : 'DESC'}`;
  if (sort === 'sales') orderBy = 'p.sales DESC';
  if (sort === 'new') orderBy = 'p.created_at DESC';

  const total = get(`SELECT COUNT(*) as c FROM products p ${where}`, params).c;
  const list = all(
    `SELECT p.id,p.name,p.image,p.price,p.original_price,p.sales,p.stock,p.unit,p.subtitle 
     FROM products p ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]
  );

  return res.json(page(list, total, pageNum, size));
});

// 商品详情
router.get('/detail/:id', (req, res) => {
  const product = get('SELECT * FROM products WHERE id=?', [req.params.id]);
  if (!product) return res.json({ code: 1, message: '商品不存在' });

  product.images = JSON.parse(product.images || '[]');
  product.skus = all('SELECT * FROM product_skus WHERE product_id=? ORDER BY sort ASC', [product.id]);
  product.specs = all('SELECT * FROM product_specs WHERE product_id=? ORDER BY sort ASC', [product.id]);
  product.specs.forEach(s => { s.values = JSON.parse(s.spec_values || '[]'); });

  return res.json(success(product));
});

// 热销商品
router.get('/hot', (req, res) => {
  const list = all('SELECT id,name,image,price,sales FROM products WHERE status=1 AND is_hot=1 ORDER BY sales DESC LIMIT 10');
  return res.json(success(list));
});

// 新品推荐
router.get('/new', (req, res) => {
  const list = all('SELECT id,name,image,price FROM products WHERE status=1 AND is_new=1 ORDER BY id DESC LIMIT 10');
  return res.json(success(list));
});

// 推荐商品
router.get('/recommend', (req, res) => {
  const list = all('SELECT id,name,image,price,sales FROM products WHERE status=1 AND is_recommend=1 ORDER BY sort ASC LIMIT 10');
  return res.json(success(list));
});

// 分类下商品
router.get('/category/:id', (req, res) => {
  const { page: p = 1, pageSize = 20 } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  const total = get('SELECT COUNT(*) as c FROM products WHERE category_id=? AND status=1', [req.params.id]).c;
  const list = all('SELECT id,name,image,price,sales FROM products WHERE category_id=? AND status=1 ORDER BY sort ASC LIMIT ? OFFSET ?',
    [req.params.id, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 批量获取
router.post('/list-by-ids', (req, res) => {
  const { ids } = req.body;
  if (!ids || !ids.length) return res.json(success([]));
  const placeholders = ids.map(() => '?').join(',');
  const list = all(`SELECT id,name,image,price FROM products WHERE id IN (${placeholders})`, ids);
  return res.json(success(list));
});

// 获取商品评价列表
router.get('/reviews/:id', (req, res) => {
  try {
    const { get, run, all } = require('../utils/db');
    const { success } = require('../utils/response');
    const productId = req.params.id;
    const { page: p = 1, pageSize = 10 } = req.query;
    const pageNum = Math.max(1, +p);
    const size = Math.min(50, Math.max(1, +pageSize));

    const total = get('SELECT COUNT(*) as c FROM product_reviews WHERE product_id=? AND status=1', [productId]).c;
    const list = all(`SELECT pr.*, u.nickname, u.avatar FROM product_reviews pr 
      LEFT JOIN users u ON pr.user_id=u.id 
      WHERE pr.product_id=? AND pr.status=1 
      ORDER BY pr.id DESC LIMIT ? OFFSET ?`,
      [productId, size, (pageNum - 1) * size]);

    list.forEach(r => { r.images = JSON.parse(r.images || '[]'); });

    const stats = get('SELECT COUNT(*) as total, AVG(rating) as avg_rating, SUM(CASE WHEN rating=5 THEN 1 ELSE 0 END) as f5, SUM(CASE WHEN rating=4 THEN 1 ELSE 0 END) as f4, SUM(CASE WHEN rating=3 THEN 1 ELSE 0 END) as f3, SUM(CASE WHEN rating=2 THEN 1 ELSE 0 END) as f2, SUM(CASE WHEN rating=1 THEN 1 ELSE 0 END) as f1 FROM product_reviews WHERE product_id=? AND status=1', [productId]);

    return res.json(success({
      list,
      total,
      page: pageNum,
      pageSize: size,
      stats: {
        total: stats.total,
        avg_rating: stats.avg_rating ? Math.round(stats.avg_rating * 10) / 10 : 0,
        distribution: {
          5: stats.f5 || 0, 4: stats.f4 || 0, 3: stats.f3 || 0, 2: stats.f2 || 0, 1: stats.f1 || 0
        }
      }
    }));
  } catch (e) {
    return res.json({ code: 1, message: '获取评价失败' });
  }
});

module.exports = router;

===== server/src/routes/cart.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success } = require('../utils/response');
const { authUser } = require('../middleware/auth');

router.use(authUser);

// 购物车列表
router.get('/list', (req, res) => {
  const list = all(`SELECT c.id,c.product_id,c.sku_id,c.quantity,c.selected,
    p.name as product_name,p.image as product_image,p.price,p.subtitle,
    ps.price as sku_price,ps.image as sku_image,ps.specs,ps.stock as sku_stock
    FROM carts c 
    JOIN products p ON c.product_id=p.id
    LEFT JOIN product_skus ps ON c.sku_id=ps.id
    WHERE c.user_id=? ORDER BY c.id DESC`, [req.userId]);
  list.forEach(item => {
    if (item.specs) item.specs = JSON.parse(item.specs);
  });
  return res.json(success(list));
});

// 添加商品
router.post('/add', (req, res) => {
  const { product_id, sku_id, quantity = 1 } = req.body;
  if (!product_id) return res.json({ code: 1, message: '参数错误' });

  const exist = get('SELECT id,quantity FROM carts WHERE user_id=? AND product_id=? AND (sku_id=? OR (sku_id IS NULL AND ? IS NULL))',
    [req.userId, product_id, sku_id || null, sku_id || null]);

  if (exist) {
    run('UPDATE carts SET quantity=quantity+? WHERE id=?', [quantity, exist.id]);
  } else {
    run('INSERT INTO carts(user_id,product_id,sku_id,quantity) VALUES(?,?,?,?)',
      [req.userId, product_id, sku_id || null, quantity]);
  }
  return res.json(success(null, '已加入购物车'));
});

// 修改数量
router.put('/:id', (req, res) => {
  const { quantity } = req.body;
  if (quantity < 1) return res.json({ code: 1, message: '数量不能少于1' });
  run('UPDATE carts SET quantity=? WHERE id=? AND user_id=?', [quantity, req.params.id, req.userId]);
  return res.json(success(null, '更新成功'));
});

// 删除
router.delete('/:id', (req, res) => {
  run('DELETE FROM carts WHERE id=? AND user_id=?', [req.params.id, req.userId]);
  return res.json(success(null, '删除成功'));
});

// 清空
router.delete('/', (req, res) => {
  run('DELETE FROM carts WHERE user_id=?', [req.userId]);
  return res.json(success(null, '已清空'));
});

// 选中/取消选中
router.post('/toggle-select', (req, res) => {
  const { id, selected } = req.body;
  run('UPDATE carts SET selected=? WHERE id=? AND user_id=?', [selected ? 1 : 0, id, req.userId]);
  return res.json(success(null, '更新成功'));
});

// 全选/取消全选
router.post('/select-all', (req, res) => {
  const { selected } = req.body;
  run('UPDATE carts SET selected=? WHERE user_id=?', [selected ? 1 : 0, req.userId]);
  return res.json(success(null, '更新成功'));
});

module.exports = router;

===== server/src/routes/order.js =====
const express = require('express');
const router = express.Router();
const { get, run, all, transaction, getDb } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authUser } = require('../middleware/auth');

function genOrderNo() {
  const now = new Date();
  const date = `${now.getFullYear()}${String(now.getMonth()+1).padStart(2,'0')}${String(now.getDate()).padStart(2,'0')}`;
  const rand = String(Math.floor(Math.random() * 1000000)).padStart(6, '0');
  return `DD${date}${rand}`;
}

function genRefundNo() {
  return `TK${Date.now()}${Math.floor(Math.random()*1000)}`;
}

// 预计算金额
router.post('/calc-amount', authUser, (req, res) => {
  try {
    const { items } = req.body; // [{product_id, sku_id, quantity}]
    let total = 0;
    const detail = [];

    for (const item of items) {
      let price = 0, name = '', image = '';
      if (item.sku_id) {
        const sku = get('SELECT ps.*,p.name,p.image FROM product_skus ps JOIN products p ON ps.product_id=p.id WHERE ps.id=?', [item.sku_id]);
        if (!sku) continue;
        price = sku.price;
        name = sku.name || sku.product_name;
        image = sku.image || sku.product_image;
      } else {
        const p = get('SELECT * FROM products WHERE id=?', [item.product_id]);
        if (!p) continue;
        price = p.price;
        name = p.name;
        image = p.image;
      }
      const subtotal = price * item.quantity;
      total += subtotal;
      detail.push({ product_id: item.product_id, sku_id: item.sku_id, name, image, price, quantity: item.quantity, subtotal });
    }

    // 等级折扣
    const user = get('SELECT u.level_id, l.discount FROM users u JOIN user_levels l ON u.level_id=l.id WHERE u.id=?', [req.userId]);
    const discount = user ? user.discount : 1.00;
    const discountAmount = Math.round(total * (1 - discount) * 100) / 100;
    const payAmount = Math.round((total - discountAmount) * 100) / 100;

    return res.json(success({ items: detail, total_amount: total, discount_amount: discountAmount, pay_amount: payAmount, level_discount: discount }));
  } catch (e) {
    return res.json(fail('计算失败'));
  }
});

// 创建订单
router.post('/create', authUser, (req, res) => {
  try {
    const { items, address_id, remark, use_coupon_ids } = req.body;
    if (!items || !items.length) return res.json(fail('请选择商品'));

    const result = transaction(() => {
      const orderNo = genOrderNo();
      let totalAmount = 0;
      const orderItems = [];

      for (const item of items) {
        let price = 0, skuInfo = '', image = '', productName = '', stock = 0;
        const product = get('SELECT * FROM products WHERE id=? AND status=1', [item.product_id]);
        if (!product) throw new Error(`商品不存在: ${item.product_id}`);

        if (item.sku_id) {
          const sku = get('SELECT * FROM product_skus WHERE id=? AND product_id=?', [item.sku_id, item.product_id]);
          if (!sku || sku.stock < item.quantity) throw new Error(`库存不足: ${product.name}`);
          price = sku.price;
          stock = sku.stock;
          skuInfo = JSON.stringify(sku.specs || []);
          image = sku.image || product.image;
          run('UPDATE product_skus SET stock=stock-?,sales=sales+? WHERE id=?', [item.quantity, item.quantity, sku.id]);
        } else {
          if (product.stock < item.quantity) throw new Error(`库存不足: ${product.name}`);
          price = product.price;
          stock = product.stock;
          image = product.image;
          run('UPDATE products SET stock=stock-? WHERE id=?', [item.quantity, product.id]);
        }
        
        productName = product.name;
        const subtotal = +(price * item.quantity).toFixed(2);
        totalAmount += subtotal;
        orderItems.push({ product_id: product.id, sku_id: item.sku_id || null, product_name: productName, sku_info: skuInfo, image, price, quantity: item.quantity, subtotal });
        run('UPDATE products SET sales=sales+? WHERE id=?', [item.quantity, product.id]);
      }

      // 等级折扣
      const user = get('SELECT u.level_id, l.discount FROM users u JOIN user_levels l ON u.level_id=l.id WHERE u.id=?', [req.userId]);
      const discount = user ? user.discount : 1.00;
      const discountAmount = +(totalAmount * (1 - discount)).toFixed(2);
      const payAmount = +(totalAmount - discountAmount).toFixed(2);

      // 地址
      let consignee = '', phone = '', province = '', city = '', district = '', address = '';
      if (address_id) {
        const addr = get('SELECT * FROM user_addresses WHERE id=? AND user_id=?', [address_id, req.userId]);
        if (addr) { consignee = addr.name; phone = addr.phone; province = addr.province; city = addr.city; district = addr.district; address = addr.detail; }
      }

      run(`INSERT INTO orders(order_no,user_id,total_amount,discount_amount,pay_amount,consignee,phone,province,city,district,address,remark)
        VALUES(?,?,?,?,?,?,?,?,?,?,?,?)`,
        [orderNo, req.userId, totalAmount, discountAmount, payAmount, consignee, phone, province, city, district, address, remark || '']);

      const order = get('SELECT id FROM orders WHERE order_no=?', [orderNo]);
      const stmt = getDb().prepare('INSERT INTO order_items(order_id,product_id,sku_id,product_name,sku_info,image,price,quantity,subtotal) VALUES(?,?,?,?,?,?,?,?,?)');
      for (const oi of orderItems) stmt.run(order.id, oi.product_id, oi.sku_id, oi.product_name, oi.sku_info, oi.image, oi.price, oi.quantity, oi.subtotal);

      run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order.id, 'create', '订单创建成功']);

      // 清除已选购物车
      const cartIds = items.filter(i => i.cart_id).map(i => i.cart_id);
      if (cartIds.length) {
        const placeholders = cartIds.map(() => '?').join(',');
        run(`DELETE FROM carts WHERE id IN (${placeholders}) AND user_id=?`, [...cartIds, req.userId]);
      }

      return { orderNo, payAmount, discountAmount };
    });

    return res.json(success(result, '下单成功'));
  } catch (e) {
    console.error('创建订单失败:', e);
    return res.json(fail(e.message || '下单失败'));
  }
});

// 订单列表
router.get('/list', authUser, (req, res) => {
  const { page: p = 1, pageSize = 10, status } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(50, Math.max(1, +pageSize));
  let where = 'WHERE user_id=?';
  const params = [req.userId];
  if (status) { where += ' AND status=?'; params.push(status); }

  const total = get(`SELECT COUNT(*) as c FROM orders ${where}`, params).c;
  const list = all(`SELECT * FROM orders ${where} ORDER BY id DESC LIMIT ? OFFSET ?`, [...params, size, (pageNum - 1) * size]);

  // 填充商品
  for (const order of list) {
    order.items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
  }

  return res.json(page(list, total, pageNum, size));
});

// 订单详情
router.get('/detail/:orderNo', authUser, (req, res) => {
  const order = get('SELECT * FROM orders WHERE order_no=? AND user_id=?', [req.params.orderNo, req.userId]);
  if (!order) return res.json(fail('订单不存在'));
  order.items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
  order.logs = all('SELECT * FROM order_logs WHERE order_id=? ORDER BY id ASC', [order.id]);
  return res.json(success(order));
});

// 取消订单
router.post('/:orderNo/cancel', authUser, (req, res) => {
  const { close_reason } = req.body;
  const order = get('SELECT * FROM orders WHERE order_no=? AND user_id=?', [req.params.orderNo, req.userId]);
  if (!order) return res.json(fail('订单不存在'));
  if (order.status !== 'pending_pay') return res.json(fail('当前状态不可取消'));

  transaction(() => {
    run('UPDATE orders SET status=?,close_reason=?,close_time=datetime(\'now\',\'localtime\') WHERE id=?', ['closed', close_reason || '用户取消', order.id]);
    run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order.id, 'cancel', '订单已取消']);
    // 归还库存
    const items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
    for (const item of items) {
      if (item.sku_id) {
        run('UPDATE product_skus SET stock=stock+?,sales=sales-? WHERE id=?', [item.quantity, item.quantity, item.sku_id]);
      } else {
        run('UPDATE products SET stock=stock+?,sales=sales-? WHERE id=?', [item.quantity, item.quantity, item.product_id]);
      }
    }
  });
  return res.json(success(null, '取消成功'));
});

// 确认收货
router.post('/:orderNo/confirm', authUser, (req, res) => {
  const order = get('SELECT * FROM orders WHERE order_no=? AND user_id=?', [req.params.orderNo, req.userId]);
  if (!order) return res.json(fail('订单不存在'));
  if (order.status !== 'shipped') return res.json(fail('当前状态不可确认收货'));

  run('UPDATE orders SET status=?,confirm_time=datetime(\'now\',\'localtime\') WHERE id=?', ['received', order.id]);
  run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order.id, 'confirm', '用户确认收货']);

  // 更新用户消费统计
  run('UPDATE users SET total_consumed=total_consumed+?,order_count=order_count+1 WHERE id=?', [order.pay_amount, req.userId]);

  return res.json(success(null, '确认收货成功'));
});

// 支付（模拟）
router.post('/:orderNo/pay', authUser, (req, res) => {
  const { payment_method } = req.body;
  const order = get('SELECT * FROM orders WHERE order_no=? AND user_id=?', [req.params.orderNo, req.userId]);
  if (!order) return res.json(fail('订单不存在'));
  if (order.status !== 'pending_pay') return res.json(fail('当前状态不可支付'));

  transaction(() => {
    run('UPDATE orders SET status=?,payment_method=?,paid_amount=?,updated_at=datetime(\'now\',\'localtime\') WHERE id=?',
      ['pending_ship', payment_method || 'wechat', order.pay_amount, order.id]);
    run('INSERT INTO payment_records(trade_no,order_id,user_id,amount,method,status,pay_time) VALUES(?,?,?,?,?,?,datetime(\'now\',\'localtime\'))',
      [`PAY${Date.now()}`, order.id, req.userId, order.pay_amount, payment_method || 'wechat', 'success']);
    run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order.id, 'pay', `支付成功(${order.pay_amount}元)`]);
  });

  return res.json(success(null, '支付成功'));
});

// 申请退款
router.post('/refund', authUser, (req, res) => {
  try {
    const { order_id, order_item_id, type, reason, amount } = req.body;
    const order = get('SELECT * FROM orders WHERE id=? AND user_id=?', [order_id, req.userId]);
    if (!order) return res.json(fail('订单不存在'));

    const r = run('INSERT INTO refunds(refund_no,order_id,order_item_id,user_id,type,reason,amount,status) VALUES(?,?,?,?,?,?,?,?)',
      [genRefundNo(), order_id, order_item_id || null, req.userId, type || 'only_refund', reason || '', amount || order.pay_amount, 'pending']);
    
    run('UPDATE orders SET status=? WHERE id=?', ['refunding', order_id]);
    run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order_id, 'refund_apply', '用户申请退款']);
    
    return res.json(success({ id: r.lastInsertRowid }, '申请成功'));
  } catch (e) {
    return res.json(fail('申请失败'));
  }
});

// 退款列表
router.get('/refund/list', authUser, (req, res) => {
  const { page: p = 1, pageSize = 10 } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(50, Math.max(1, +pageSize));
  const total = get('SELECT COUNT(*) as c FROM refunds WHERE user_id=?', [req.userId]).c;
  const list = all('SELECT * FROM refunds WHERE user_id=? ORDER BY id DESC LIMIT ? OFFSET ?', [req.userId, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 取消退款
router.post('/refund/:id/cancel', authUser, (req, res) => {
  const refund = get('SELECT * FROM refunds WHERE id=? AND user_id=?', [req.params.id, req.userId]);
  if (!refund) return res.json(fail('退款申请不存在'));
  run('UPDATE refunds SET status=? WHERE id=?', ['cancelled', refund.id]);
  run('UPDATE orders SET status=? WHERE id=?', ['pending_ship', refund.order_id]);
  return res.json(success(null, '已取消退款'));
});

// 订单日志
router.post('/:orderNo/log', authUser, (req, res) => {
  const order = get('SELECT id FROM orders WHERE order_no=? AND user_id=?', [req.params.orderNo, req.userId]);
  if (!order) return res.json(fail('订单不存在'));
  run('INSERT INTO order_logs(order_id,action,content,operator) VALUES(?,?,?,?)', [order.id, 'user_action', req.body.content || '', 'user']);
  return res.json(success(null, '记录成功'));
});

// 快递公司列表
const SHIPPING_COMPANIES = [
  { code: 'SF', name: '顺丰快递' }, { code: 'EMS', name: 'EMS' }, { code: 'STO', name: '申通快递' },
  { code: 'YTO', name: '圆通速递' }, { code: 'ZTO', name: '中通快递' }, { code: 'YUNDA', name: '韵达快递' },
  { code: 'JT', name: '极兔速递' }, { code: 'BSHT', name: '百世快递' }, { code: 'TTKD', name: '天天快递' },
  { code: 'UC', name: '优速快递' }, { code: 'DBL', name: '德邦快递' }, { code: 'ZJS', name: '宅急送' },
];

router.get('/shipping-companies', (req, res) => {
  return res.json(success(SHIPPING_COMPANIES));
});

module.exports = router;

===== server/src/routes/category.js =====
const express = require('express');
const router = express.Router();
const { all } = require('../utils/db');
const { success } = require('../utils/response');

router.get('/list', (req, res) => {
  const list = all('SELECT * FROM categories WHERE status=1 ORDER BY sort ASC');
  return res.json(success(list));
});

module.exports = router;

===== server/src/routes/banner.js =====
const express = require('express');
const router = express.Router();
const { all } = require('../utils/db');
const { success } = require('../utils/response');

router.get('/list', (req, res) => {
  const list = all('SELECT * FROM banners WHERE status=1 ORDER BY sort ASC');
  return res.json(success(list));
});

module.exports = router;

===== server/src/routes/membership.js =====
const express = require('express');
const router = express.Router();
const { get, run, all, transaction } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authUser } = require('../middleware/auth');

// 会员套餐列表
router.get('/plans', (req, res) => {
  const plans = all('SELECT * FROM membership_plans WHERE status=1 ORDER BY sort ASC');
  return res.json(success(plans));
});

// 购买会员
router.post('/buy', authUser, (req, res) => {
  try {
    const { plan_id, payment_method } = req.body;
    const plan = get('SELECT * FROM membership_plans WHERE id=? AND status=1', [plan_id]);
    if (!plan) return res.json(fail('套餐不存在'));

    transaction(() => {
      // 创建订单
      const orderNo = `VIP${Date.now()}${Math.floor(Math.random()*1000)}`;
      run(`INSERT INTO orders(order_no,user_id,total_amount,pay_amount,payment_method,status,remark)
        VALUES(?,?,?,?,?,?,?)`,
        [orderNo, req.userId, plan.price, plan.price, payment_method || 'wechat', 'pending_ship', `购买会员:${plan.name}`]);

      // 记录会员
      const now = new Date();
      let endTime = new Date(now);
      if (plan.type === 'monthly') endTime.setMonth(endTime.getMonth() + 1);
      else if (plan.type === 'quarterly') endTime.setMonth(endTime.getMonth() + 3);
      else if (plan.type === 'yearly') endTime.setFullYear(endTime.getFullYear() + 1);
      else if (plan.type === 'permanent') endTime.setFullYear(endTime.getFullYear() + 50);

      run('INSERT INTO user_memberships(user_id,plan_id,start_time,end_time,status) VALUES(?,?,?,?,?)',
        [req.userId, plan_id, now.toISOString(), endTime.toISOString(), 'active']);

      // 加经验和等级
      if (plan.give_experience > 0) {
        run('UPDATE users SET experience=experience+?, level_id=CASE WHEN ?>=8000 THEN 4 WHEN ?>=2000 THEN 3 WHEN ?>=500 THEN 2 ELSE level_id END WHERE id=?',
          [plan.give_experience, plan.give_experience, plan.give_experience, plan.give_experience, req.userId]);
      }

      // 送优惠券
      if (plan.give_coupon_ids) {
        const couponIds = plan.give_coupon_ids.split(',').map(Number).filter(Boolean);
        for (const cid of couponIds) {
          const coupon = get('SELECT * FROM coupons WHERE id=?', [cid]);
          if (coupon) {
            const expired = new Date();
            expired.setDate(expired.getDate() + (coupon.valid_days || 30));
            run('INSERT INTO user_coupons(user_id,coupon_id,expired_time) VALUES(?,?,?)', [req.userId, cid, expired.toISOString()]);
          }
        }
      }
    });

    return res.json(success(null, '购买成功'));
  } catch (e) {
    return res.json(fail('购买失败'));
  }
});

// 我的会员
router.get('/my', authUser, (req, res) => {
  const membership = get(`SELECT um.*, mp.name as plan_name, mp.type, mp.price 
    FROM user_memberships um JOIN membership_plans mp ON um.plan_id=mp.id 
    WHERE um.user_id=? AND um.status='active' ORDER BY um.id DESC LIMIT 1`, [req.userId]);
  const user = get('SELECT level_id, experience FROM users WHERE id=?', [req.userId]);
  const level = get('SELECT * FROM user_levels WHERE id=?', [user.level_id]);
  return res.json(success({ membership, level, experience: user.experience }));
});

// 购买记录
router.get('/history', authUser, (req, res) => {
  const list = all(`SELECT um.*, mp.name as plan_name, mp.price 
    FROM user_memberships um JOIN membership_plans mp ON um.plan_id=mp.id 
    WHERE um.user_id=? ORDER BY um.id DESC LIMIT 20`, [req.userId]);
  return res.json(success(list));
});

module.exports = router;

===== server/src/routes/distribution.js =====
const express = require('express');
const router = express.Router();
const { get, run, all, transaction } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authUser } = require('../middleware/auth');

router.use(authUser);

// 分销概况
router.get('/info', (req, res) => {
  const user = get('SELECT id,parent_id,team_count FROM users WHERE id=?', [req.userId]);
  const totalCommission = get('SELECT COALESCE(SUM(commission),0) as c FROM distribution_records WHERE user_id=?', [req.userId]).c;
  const settled = get('SELECT COALESCE(SUM(commission),0) as c FROM distribution_records WHERE user_id=? AND status=\'settled\'', [req.userId]).c;
  const pending = get('SELECT COALESCE(SUM(commission),0) as c FROM distribution_records WHERE user_id=? AND status=\'pending\'', [req.userId]).c;
  const withdrawable = settled - get('SELECT COALESCE(SUM(amount),0) as c FROM withdraw_requests WHERE user_id=? AND status IN (\'pending\',\'approved\')', [req.userId]).c;
  
  const distConfig = all('SELECT key,value FROM distribution_config');
  const configMap = {};
  distConfig.forEach(c => configMap[c.key] = c.value);

  return res.json(success({ team_count: user.team_count, total_commission: totalCommission, settled, pending, withdrawable, config: configMap }));
});

// 团队列表
router.get('/team', (req, res) => {
  const { page: p = 1, pageSize = 20 } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  const total = get('SELECT COUNT(*) as c FROM users WHERE parent_id=?', [req.userId]).c;
  const list = all('SELECT id,nickname,avatar,phone,level_id,order_count,total_consumed,created_at FROM users WHERE parent_id=? ORDER BY id DESC LIMIT ? OFFSET ?',
    [req.userId, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 佣金记录
router.get('/commission', (req, res) => {
  const { page: p = 1, pageSize = 20, status } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE user_id=?';
  const params = [req.userId];
  if (status) { where += ' AND status=?'; params.push(status); }

  const total = get(`SELECT COUNT(*) as c FROM distribution_records ${where}`, params).c;
  const list = all(`SELECT dr.*, o.order_no FROM distribution_records dr LEFT JOIN orders o ON dr.order_id=o.id ${where} ORDER BY dr.id DESC LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 佣金统计
router.get('/commission/stat', (req, res) => {
  const stats = {
    today: get('SELECT COALESCE(SUM(commission),0) as c FROM distribution_records WHERE user_id=? AND date(created_at)=date(\'now\',\'localtime\')', [req.userId]).c,
    month: get("SELECT COALESCE(SUM(commission),0) as c FROM distribution_records WHERE user_id=? AND strftime('%Y-%m',created_at)=strftime('%Y-%m','now','localtime')", [req.userId]).c,
    total: get('SELECT COALESCE(SUM(commission),0) as c FROM distribution_records WHERE user_id=? AND status=\'settled\'', [req.userId]).c,
  };
  return res.json(success(stats));
});

// 分销等级
router.get('/level', (req, res) => {
  const levels = all('SELECT * FROM distribution_levels WHERE status=1 ORDER BY level ASC');
  return res.json(success(levels));
});

// 申请提现
router.post('/withdraw', (req, res) => {
  try {
    const { amount, account_type, account_info } = req.body;
    const minWithdraw = +(get('SELECT value FROM distribution_config WHERE key=?', ['min_withdraw'])?.value || 10);
    if (!amount || amount < minWithdraw) return res.json(fail(`最低提现金额${minWithdraw}元`));

    const user = get('SELECT id,freeze_balance FROM users WHERE id=?', [req.userId]);
    const settled = get('SELECT COALESCE(SUM(commission),0) as c FROM distribution_records WHERE user_id=? AND status=\'settled\'', [req.userId]).c;
    const used = get('SELECT COALESCE(SUM(amount),0) as c FROM withdraw_requests WHERE user_id=? AND status IN (\'pending\',\'approved\')', [req.userId]).c;
    const available = +(settled - used).toFixed(2);

    if (amount > available) return res.json(fail('可提现金额不足'));

    const fee = +(amount * (+(get('SELECT value FROM distribution_config WHERE key=?', ['withdraw_fee_rate'])?.value || 0) / 100)).toFixed(2);
    const realAmount = +(amount - fee).toFixed(2);

    run('INSERT INTO withdraw_requests(user_id,amount,fee,real_amount,account_type,account_info) VALUES(?,?,?,?,?,?)',
      [req.userId, amount, fee, realAmount, account_type || 'wechat', account_info || '']);
    run('UPDATE users SET freeze_balance=freeze_balance+? WHERE id=?', [amount, req.userId]);

    return res.json(success(null, '申请成功，等待审核'));
  } catch (e) {
    return res.json(fail('申请失败'));
  }
});

// 提现记录
router.get('/withdraw/list', (req, res) => {
  const { page: p = 1, pageSize = 20 } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  const total = get('SELECT COUNT(*) as c FROM withdraw_requests WHERE user_id=?', [req.userId]).c;
  const list = all('SELECT * FROM withdraw_requests WHERE user_id=? ORDER BY id DESC LIMIT ? OFFSET ?', [req.userId, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 分销二维码（简化为分享链接）
router.get('/qrcode', (req, res) => {
  const inviteUrl = `${req.protocol}://${req.get('host')}/mobile/#/?parent_id=${req.userId}`;
  return res.json(success({ url: inviteUrl, user_id: req.userId }));
});

// 绑定上级
router.post('/bind', (req, res) => {
  try {
    const { parent_id } = req.body;
    if (!parent_id || parent_id == req.userId) return res.json(fail('无效的上级'));
    const user = get('SELECT parent_id FROM users WHERE id=?', [req.userId]);
    if (user.parent_id) return res.json(fail('已绑定上级，不可更改'));
    
    const parent = get('SELECT id FROM users WHERE id=?', [parent_id]);
    if (!parent) return res.json(fail('上级用户不存在'));

    run('UPDATE users SET parent_id=? WHERE id=?', [parent_id, req.userId]);
    run('UPDATE users SET team_count=team_count+1 WHERE id=?', [parent_id]);
    return res.json(success(null, '绑定成功'));
  } catch (e) {
    return res.json(fail('绑定失败'));
  }
});

module.exports = router;

===== server/src/routes/marketing.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authUser } = require('../middleware/auth');

// 可领优惠券
router.get('/coupons', (req, res) => {
  const now = new Date().toISOString();
  const list = all("SELECT * FROM coupons WHERE status=1 AND (end_time IS NULL OR end_time>=?) ORDER BY id DESC", [now]);
  return res.json(success(list));
});

// 领券
router.post('/coupon/receive', authUser, (req, res) => {
  try {
    const { coupon_id } = req.body;
    const coupon = get('SELECT * FROM coupons WHERE id=? AND status=1', [coupon_id]);
    if (!coupon) return res.json(fail('优惠券不存在'));

    const count = get('SELECT COUNT(*) as c FROM user_coupons WHERE user_id=? AND coupon_id=?', [req.userId, coupon_id]).c;
    if (count >= coupon.per_limit) return res.json(fail('已领完该优惠券'));

    const totalUsed = get('SELECT COUNT(*) as c FROM user_coupons WHERE coupon_id=?', [coupon_id]).c;
    if (totalUsed >= coupon.total_count) return res.json(fail('优惠券已被领完'));

    const expired = new Date();
    if (coupon.valid_days) {
      expired.setDate(expired.getDate() + coupon.valid_days);
    } else if (coupon.end_time) {
      expired.setTime(new Date(coupon.end_time).getTime());
    } else {
      expired.setDate(expired.getDate() + 30);
    }

    run('INSERT INTO user_coupons(user_id,coupon_id,expired_time) VALUES(?,?,?)', [req.userId, coupon_id, expired.toISOString()]);
    run('UPDATE coupons SET used_count=used_count+1 WHERE id=?', [coupon_id]);

    return res.json(success(null, '领券成功'));
  } catch (e) {
    return res.json(fail('领券失败'));
  }
});

// 我的优惠券
router.get('/my-coupons', authUser, (req, res) => {
  const { status } = req.query;
  let where = 'WHERE uc.user_id=?';
  const params = [req.userId];
  if (status === 'unused') { where += " AND uc.status='unused'"; }
  else if (status === 'used') { where += " AND uc.status='used'"; }
  else if (status === 'expired') { where += " AND uc.status='expired'"; }

  const list = all(`SELECT uc.*, c.name,c.type,c.value,c.min_amount,c.max_amount
    FROM user_coupons uc JOIN coupons c ON uc.coupon_id=c.id ${where} ORDER BY uc.id DESC`, params);
  return res.json(success(list));
});

// 秒杀列表
router.get('/seckill/list', (req, res) => {
  const now = new Date().toISOString();
  const list = all("SELECT sp.*, p.name,p.image,p.price as original_price FROM seckill_products sp JOIN products p ON sp.product_id=p.id WHERE sp.status=1 AND sp.start_time<=? AND sp.end_time>=? ORDER BY sp.id DESC", [now, now]);
  return res.json(success(list));
});

// 秒杀详情
router.get('/seckill/:id', (req, res) => {
  const item = get("SELECT sp.*, p.name,p.image,p.price as original_price,p.description FROM seckill_products sp JOIN products p ON sp.product_id=p.id WHERE sp.id=?", [req.params.id]);
  if (!item) return res.json(fail('秒杀活动不存在'));
  return res.json(success(item));
});

// 拼团列表
router.get('/group-buy/list', (req, res) => {
  const now = new Date().toISOString();
  const list = all("SELECT gb.*, p.name,p.image,p.price as original_price FROM group_buy_products gb JOIN products p ON gb.product_id=p.id WHERE gb.status=1 AND gb.start_time<=? AND gb.end_time>=? ORDER BY gb.id DESC", [now, now]);
  return res.json(success(list));
});

// 拼团详情
router.get('/group-buy/:id', (req, res) => {
  const item = get("SELECT gb.*, p.name,p.image,p.price as original_price,p.description FROM group_buy_products gb JOIN products p ON gb.product_id=p.id WHERE gb.id=?", [req.params.id]);
  if (!item) return res.json(fail('拼团活动不存在'));
  return res.json(success(item));
});

module.exports = router;

===== server/src/routes/ai.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, fail } = require('../utils/response');
const { authUser } = require('../middleware/auth');

router.use(authUser);

// 创建会话
router.post('/conversation', (req, res) => {
  const r = run('INSERT INTO chat_conversations(user_id) VALUES(?)', [req.userId]);
  return res.json(success({ id: r.lastInsertRowid }, '创建成功'));
});

// 会话列表
router.get('/conversations', (req, res) => {
  const list = all('SELECT * FROM chat_conversations WHERE user_id=? ORDER BY id DESC LIMIT 20', [req.userId]);
  return res.json(success(list));
});

// 获取消息
router.get('/messages/:convId', (req, res) => {
  const { page: p = 1, pageSize = 50 } = req.query;
  const msgs = all('SELECT * FROM chat_messages WHERE conversation_id=? ORDER BY id ASC LIMIT ? OFFSET ?',
    [req.params.convId, pageSize, (Math.max(1, +p) - 1) * pageSize]);
  return res.json(success(msgs));
});

// 发送消息（含AI自动回复）
router.post('/message', (req, res) => {
  try {
    const { conversation_id, content } = req.body;
    if (!content) return res.json(fail('消息不能为空'));

    // 保存用户消息
    run('INSERT INTO chat_messages(conversation_id,role,content) VALUES(?,?,?)', [conversation_id, 'user', content]);

    // 匹配知识库
    const aiEnabled = get("SELECT value FROM system_config WHERE key='ai_enabled'")?.value;
    let reply = '';
    
    if (aiEnabled === '1') {
      const matched = all(`SELECT answer FROM ai_knowledge_base WHERE status=1 AND (
        question LIKE ? OR keywords LIKE ? OR ? LIKE question
      ) ORDER BY weight DESC LIMIT 1`, [`%${content}%`, `%${content}%`, content]);
      
      reply = matched.length > 0 
        ? matched[0].answer 
        : (get("SELECT value FROM system_config WHERE key='ai_auto_reply'")?.value === '1'
          ? (get("SELECT value FROM system_config WHERE key='ai_fallback'")?.value || '您好，请稍等，我将为您转接人工客服。')
          : '');
    } else {
      reply = (get("SELECT value FROM system_config WHERE key='ai_welcome'")?.value || 'AI客服暂未开启，请联系人工客服。');
    }

    if (reply) {
      run('INSERT INTO chat_messages(conversation_id,role,content) VALUES(?,?,?)', [conversation_id, 'assistant', reply]);
    }

    return res.json(success({ reply }, '发送成功'));
  } catch (e) {
    return res.json(fail('发送失败'));
  }
});

// 删除会话
router.delete('/conversation/:id', (req, res) => {
  run('DELETE FROM chat_messages WHERE conversation_id=?', [req.params.id]);
  run('DELETE FROM chat_conversations WHERE id=? AND user_id=?', [req.params.id, req.userId]);
  return res.json(success(null, '删除成功'));
});

// 知识库搜索
router.get('/knowledge', (req, res) => {
  const { keyword } = req.query;
  let where = 'WHERE status=1';
  const params = [];
  if (keyword) { where += ' AND (question LIKE ? OR keywords LIKE ?)'; params.push(`%${keyword}%`, `%${keyword}%`); }
  const list = all(`SELECT * FROM ai_knowledge_base ${where} ORDER BY weight DESC LIMIT 50`, params);
  return res.json(success(list));
});

module.exports = router;

===== server/src/routes/payment.js =====
const express = require('express');
const router = express.Router();
const { get, run, all, transaction } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authUser, authAdmin } = require('../middleware/auth');

// ===================================================================
// 支付模块 - 完整实现（支持模拟/生产模式）
// ===================================================================
// 支付流程:
// 用户提交订单 -> POST /api/payment/create (生成支付单) 
//   -> 用户完成支付 -> POST /api/payment/notify (支付回调)
//   -> 前端轮询 GET /api/payment/status/:orderNo 
// 退款流程:
// 用户申请 -> POST /api/payment/refund/create
// 管理员审核 -> POST /api/payment/refund/process
// ===================================================================

// 生产模式检测：检查是否配置了微信/支付宝商户参数
function isProductionMode() {
  const wechatMchid = get("SELECT value FROM system_config WHERE key='wechat_mchid'").value;
  const alipayAppid = get("SELECT value FROM system_config WHERE key='alipay_appid'").value;
  // 有商户号且不为空，则认为需要生产模式验证
  return (wechatMchid && wechatMchid !== '') || (alipayAppid && alipayAppid !== '');
}

// 生成支付单号（TN + 日期 + 随机数）
function genTradeNo() {
  const now = new Date();
  const date = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`;
  const time = String(now.getHours()).padStart(2, '0') + String(now.getMinutes()).padStart(2, '0') + String(now.getSeconds()).padStart(2, '0');
  const rand = String(Math.floor(Math.random() * 100000)).padStart(5, '0');
  return `TN${date}${time}${rand}`;
}

// 生成退款单号
function genRefundNo() {
  return `TK${Date.now()}${Math.floor(Math.random() * 10000)}`;
}

// ===================================================================
// 1. 创建支付 - POST /api/payment/create
// 接收: { order_no, method (wechat/alipay) }
// 流程:
//   a) 验证订单属于当前用户且状态为 pending_pay
//   b) 生成支付单号 trade_no
//   c) 插入 payment_records 记录
//   d) 返回支付参数（模拟模式返回模拟支付链接，生产模式返回微信/支付宝参数）
// ===================================================================
router.post('/create', authUser, (req, res) => {
  try {
    const { order_no, method } = req.body;
    // 参数校验
    if (!order_no) return res.json(fail('订单号不能为空'));
    if (!method || !['wechat', 'alipay'].includes(method)) {
      return res.json(fail('请选择支付方式（wechat/alipay）'));
    }

    // 查询订单并验证归属
    const order = get('SELECT * FROM orders WHERE order_no=? AND user_id=?', [order_no, req.userId]);
    if (!order) return res.json(fail('订单不存在'));
    if (order.status !== 'pending_pay') {
      return res.json(fail('订单状态异常，无法支付（当前状态: ' + order.status + '）'));
    }

    // 检查是否已有支付记录
    const existing = get('SELECT * FROM payment_records WHERE order_id=? AND status=?', [order.id, 'pending']);
    if (existing) {
      // 已有未完成支付单，直接返回
      const payUrl = isProductionMode()
        ? (method === 'wechat' ? generateWechatPay(existing.trade_no, order.pay_amount) : generateAlipay(existing.trade_no, order.pay_amount))
        : `/api/payment/mock-pay?trade_no=${existing.trade_no}&order_no=${order_no}`;
      return res.json(success({
        trade_no: existing.trade_no,
        amount: order.pay_amount,
        method: existing.method,
        pay_url: payUrl,
        is_mock: !isProductionMode()
      }, '已有待支付记录'));
    }

    // 生成支付单号并插入记录
    const tradeNo = genTradeNo();
    run("INSERT INTO payment_records(trade_no, order_id, user_id, amount, method, status, created_at) VALUES(?,?,?,?,?,?, datetime('now','localtime'))",
      [tradeNo, order.id, req.userId, order.pay_amount, method, 'pending']);

    // 构造支付参数
    let payUrl = '';
    let payParams = {};

    if (isProductionMode()) {
      // ====== 生产模式：生成微信/支付宝支付参数 ======
      if (method === 'wechat') {
        payUrl = generateWechatPay(tradeNo, order.pay_amount);
        // 微信支付通常返回 prepay_id 等参数给前端调起支付
        payParams = {
          appId: get("SELECT value FROM system_config WHERE key='wechat_appid'").value || '',
          timeStamp: Math.floor(Date.now() / 1000).toString(),
          nonceStr: Math.random().toString(36).substring(2, 15),
          package: 'prepay_id=' + tradeNo,
          signType: 'MD5',
          // 实际签名需用微信密钥计算，此处为占位
          paySign: 'MOCK_SIGN_PLEASE_USE_REAL'
        };
      } else if (method === 'alipay') {
        // 支付宝：返回支付链接或 trade_no
        payUrl = generateAlipay(tradeNo, order.pay_amount);
        payParams = {
          trade_no: tradeNo,
          total_amount: order.pay_amount,
          subject: '商城订单-' + order_no,
          // 支付宝跳转链接
          pay_url: payUrl
        };
      }
    } else {
      // ====== 模拟模式：返回一个模拟支付页面链接 ======
      payUrl = `/api/payment/mock-pay?trade_no=${tradeNo}&order_no=${order_no}`;
      payParams = {
        trade_no: tradeNo,
        order_no: order_no,
        amount: order.pay_amount,
        method: method,
        pay_url: payUrl
      };
    }

    // 写入支付日志
    run('INSERT INTO order_logs(order_id, action, content, operator) VALUES(?,?,?,?)',
      [order.id, 'payment_create', '创建支付单: ' + tradeNo + ', 方式: ' + method + ', 金额: ¥' + order.pay_amount, 'system']);

    return res.json(success({
      trade_no: tradeNo,
      order_no: order_no,
      amount: order.pay_amount,
      method: method,
      pay_url: payUrl,
      pay_params: payParams,
      is_mock: !isProductionMode()
    }, '支付创建成功'));
  } catch (e) {
    console.error('创建支付失败:', e);
    return res.json(fail('创建支付失败: ' + e.message));
  }
});

// ===================================================================
// 2. 模拟支付页面重定向（模拟模式使用）
// 访问此链接时，返回一个模拟支付确认页面
// ===================================================================
router.get('/mock-pay', (req, res) => {
  const { trade_no, order_no } = req.query;
  if (!trade_no) return res.status(400).send('参数错误');

  const record = get('SELECT * FROM payment_records WHERE trade_no=?', [trade_no]);
  if (!record) return res.status(404).send('支付记录不存在');

  const order = get('SELECT * FROM orders WHERE id=?', [record.order_id]);

  // 返回一个简洁的模拟支付 HTML 页面
  res.send(`<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><title>模拟支付</title><style>
    *{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,PingFang SC,sans-serif;background:#f5f6fa;display:flex;justify-content:center;align-items:center;min-height:100vh}
    .card{background:#fff;border-radius:16px;padding:40px 32px;width:360px;max-width:90%;text-align:center;box-shadow:0 4px 20px rgba(0,0,0,.08)}
    .amount{font-size:36px;font-weight:700;color:#F53F3F;margin:16px 0}
    .amount span{font-size:20px}
    .order-info{font-size:13px;color:#6B7280;margin:8px 0}
    .btn{margin-top:24px;width:100%;padding:14px;background:linear-gradient(135deg,#4A7CF7,#7C9FFF);color:#fff;border:none;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all .2s}
    .btn:active{transform:scale(.96);opacity:.85}
    .btn:hover{box-shadow:0 4px 12px rgba(74,124,247,.3)}
    .btn.disabled{background:#d1d5db;cursor:not-allowed}
    .hint{font-size:12px;color:#b0b7c3;margin-top:12px}
    .success-icon{display:none;font-size:64px;margin-bottom:12px}
  </style></head><body>
  <div class="card" id="app">
    <div id="loading" style="font-size:16px;color:#6B7280">⏳ 正在加载支付信息...</div>
    <div id="content" style="display:none">
      <div class="success-icon" id="successIcon">✅</div>
      <div style="font-size:18px;font-weight:600" id="title">订单支付</div>
      <div class="order-info">订单号: ${order_no || order?.order_no || ''}</div>
      <div class="amount"><span>¥</span>${record.amount.toFixed(2)}</div>
      <div class="order-info">支付方式: ${record.method === 'wechat' ? '微信支付' : '支付宝'}</div>
      <button class="btn" id="payBtn" onclick="payNow()">✅ 模拟支付成功</button>
      <div class="hint">⚠️ 模拟模式下点击即可完成支付</div>
    </div>
  </div>
  <script>
    document.getElementById('loading').style.display='none';
    document.getElementById('content').style.display='block';

    async function payNow() {
      const btn = document.getElementById('payBtn');
      btn.disabled = true;
      btn.className = 'btn disabled';
      btn.textContent = '处理中...';

      try {
        const r = await fetch('/api/payment/mock-notify', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            order_no: '${order_no || order?.order_no || ''}',
            trade_no: '${trade_no}',
            payment_method: '${record.method}'
          })
        });
        const data = await r.json();
        if (data.code === 0) {
          document.getElementById('title').textContent = '🎉 支付成功';
          document.getElementById('successIcon').style.display = 'block';
          btn.textContent = '✅ 支付已完成';
          btn.className = 'btn disabled';
          // 自动关闭并通知父页面
          if (window.opener) {
            window.opener.postMessage({ type: 'payment_success', order_no: '${order_no || order?.order_no || ''}' }, '*');
          }
          setTimeout(() => window.close(), 2000);
        } else {
          alert('支付失败: ' + data.message);
          btn.disabled = false;
          btn.className = 'btn';
          btn.textContent = '✅ 模拟支付成功';
        }
      } catch(e) {
        alert('网络错误: ' + e.message);
        btn.disabled = false;
        btn.className = 'btn';
        btn.textContent = '✅ 模拟支付成功';
      }
    }
  </script>
  </body></html>`);
});

// ===================================================================
// 3. 支付回调通知 - POST /api/payment/notify
// 微信/支付宝统一的回调入口
// 模拟模式下直接通过，生产模式下需验证签名
// ===================================================================
router.post('/notify', (req, res) => {
  try {
    // 解析回调参数（微信/支付宝格式不同，统一处理）
    const body = req.body;
    const tradeNo = body.trade_no || body.out_trade_no || '';
    const transactionId = body.transaction_id || body.trade_no || '';
    const payTime = body.pay_time || body.gmt_payment || '';

    // 检查必要参数
    if (!tradeNo) return res.status(400).send('fail');

    // 查询支付记录
    const record = get('SELECT * FROM payment_records WHERE trade_no=?', [tradeNo]);
    if (!record) return res.status(404).send('支付记录不存在');

    // 防止重复回调
    if (record.status === 'success') {
      // 微信/支付宝要求返回 success 确认收到
      return res.type('text/plain').send('success');
    }

    // ====== 生产模式：验证签名 ======
    if (isProductionMode()) {
      // 微信支付签名验证（简化处理，实际需按微信文档验证）
      // 此处省略具体验证逻辑，生产部署时需补充真实签名验证
      const signVerified = true; // TODO: 实际生产环境需要验证微信/支付宝签名
      if (!signVerified) {
        console.error('[支付回调] 签名验证失败:', tradeNo);
        return res.type('text/plain').send('sign fail');
      }
    }

    // ====== 更新支付记录和订单状态 ======
    transaction(() => {
      // 1. 更新支付记录为成功
      run("UPDATE payment_records SET status='success', transaction_id=?, pay_time=COALESCE(?, datetime('now','localtime')) WHERE trade_no=?",
        [transactionId || '', payTime || '', tradeNo]);

      // 2. 更新订单状态为 pending_ship（待发货）
      const orderId = record.order_id;
      const order = get('SELECT * FROM orders WHERE id=?', [orderId]);
      if (order && order.status === 'pending_pay') {
        run("UPDATE orders SET status='pending_ship', payment_method=?, paid_amount=?, updated_at=datetime('now','localtime') WHERE id=?",
          [record.method, record.amount, orderId]);

        // 3. 写入订单日志
        run('INSERT INTO order_logs(order_id, action, content, operator) VALUES(?,?,?,?)',
          [orderId, 'pay', '支付成功，金额: ¥' + record.amount + '，方式: ' + record.method + '，交易号: ' + transactionId, 'system']);
      }
    });

    console.log('[支付回调] 成功处理: trade_no=' + tradeNo + ', amount=' + record.amount);
    // 微信/支付宝要求返回 success
    return res.type('text/plain').send('success');
  } catch (e) {
    console.error('[支付回调] 处理异常:', e);
    return res.type('text/plain').send('fail');
  }
});

// ===================================================================
// 4. 查询支付状态 - GET /api/payment/status/:orderNo
// 返回: { paid: bool, trade_no, pay_time, amount, method, status }
// ===================================================================
router.get('/status/:orderNo', authUser, (req, res) => {
  try {
    const { orderNo } = req.params;

    // 查询订单并验证归属
    const order = get('SELECT * FROM orders WHERE order_no=? AND user_id=?', [orderNo, req.userId]);
    if (!order) return res.json(fail('订单不存在'));

    // 查询该订单的最新支付记录
    const record = get('SELECT * FROM payment_records WHERE order_id=? ORDER BY id DESC LIMIT 1', [order.id]);

    // 判断支付状态：如果订单不是 pending_pay 且 paid_amount > 0 视为已支付
    const isPaid = order.status !== 'pending_pay' && (order.paid_amount > 0 || record?.status === 'success');

    return res.json(success({
      paid: isPaid,
      order_no: orderNo,
      order_status: order.status,
      trade_no: record?.trade_no || '',
      pay_time: record?.pay_time || null,
      amount: record?.amount || order.pay_amount,
      method: record?.method || order.payment_method || '',
      status: record?.status || (isPaid ? 'success' : 'pending')
    }, '查询成功'));
  } catch (e) {
    console.error('查询支付状态失败:', e);
    return res.json(fail('查询失败'));
  }
});

// ===================================================================
// 5. 创建退款申请 - POST /api/payment/refund/create
// 用户申请退款（不修改现有schema，用已有refunds表）
// ===================================================================
router.post('/refund/create', authUser, (req, res) => {
  try {
    const { order_no, reason, amount } = req.body;
    if (!order_no) return res.json(fail('订单号不能为空'));

    // 查询订单
    const order = get('SELECT * FROM orders WHERE order_no=? AND user_id=?', [order_no, req.userId]);
    if (!order) return res.json(fail('订单不存在'));

    // 检查订单状态是否可退款
    const refundableStatuses = ['pending_ship', 'shipped', 'received'];
    if (!refundableStatuses.includes(order.status)) {
      return res.json(fail('当前订单状态不可申请退款'));
    }

    // 检查是否有在途的退款申请
    const pendingRefund = get('SELECT * FROM refunds WHERE order_id=? AND status=?', [order.id, 'pending']);
    if (pendingRefund) return res.json(fail('已有退款申请正在处理中'));

    // 检查退款金额是否超过可退金额
    const refundAmount = Math.min(parseFloat(amount || order.paid_amount || order.pay_amount), parseFloat(order.paid_amount || order.pay_amount));
    if (refundAmount <= 0) return res.json(fail('退款金额无效'));

    // 创建退款申请
    const refundNo = genRefundNo();
    const result = run(
      "INSERT INTO refunds(refund_no, order_id, order_item_id, user_id, type, reason, amount, status, created_at) VALUES(?,?,?,?,?,?,?,?, datetime('now','localtime'))",
      [refundNo, order.id, null, req.userId, 'only_refund', reason || '用户申请退款', refundAmount, 'pending']
    );

    // 更新订单状态为 refunding
    run("UPDATE orders SET status='refunding', updated_at=datetime('now','localtime') WHERE id=?", [order.id]);

    // 写入订单日志
    run('INSERT INTO order_logs(order_id, action, content, operator) VALUES(?,?,?,?)',
      [order.id, 'refund_apply', '用户申请退款，金额: ¥' + refundAmount + '，原因: ' + (reason || '无'), 'user']);

    // 同时写入一条 payment_records 退款记录（不修改schema）
    run("INSERT INTO payment_records(trade_no, order_id, user_id, amount, method, status, created_at) VALUES(?,?,?,?,?,?, datetime('now','localtime'))",
      [refundNo, order.id, req.userId, refundAmount, order.payment_method || 'wechat', 'refunded']);

    return res.json(success({
      refund_id: result.lastInsertRowid,
      refund_no: refundNo,
      amount: refundAmount
    }, '退款申请已提交'));
  } catch (e) {
    console.error('创建退款申请失败:', e);
    return res.json(fail('创建退款申请失败: ' + e.message));
  }
});

// ===================================================================
// 6. 处理退款（管理员审核）- POST /api/payment/refund/process
// ===================================================================
router.post('/refund/process', authAdmin, (req, res) => {
  try {
    const { refund_id, action, reject_reason } = req.body;
    // action: 'approve' | 'reject'
    if (!refund_id) return res.json(fail('退款ID不能为空'));
    if (!action || !['approve', 'reject'].includes(action)) {
      return res.json(fail('操作类型无效（approve/reject）'));
    }

    const refund = get('SELECT * FROM refunds WHERE id=?', [refund_id]);
    if (!refund) return res.json(fail('退款申请不存在'));
    if (refund.status !== 'pending') return res.json(fail('该申请已处理'));

    const order = get('SELECT * FROM orders WHERE id=?', [refund.order_id]);

    transaction(() => {
      if (action === 'approve') {
        // 审核通过
        run("UPDATE refunds SET status='completed', updated_at=datetime('now','localtime') WHERE id=?", [refund_id]);

        if (order) {
          // 更新订单为已退款
          run("UPDATE orders SET status='refunded', refund_status='completed', updated_at=datetime('now','localtime') WHERE id=?", [order.id]);

          // 更新对应支付记录的退款状态
          run("UPDATE payment_records SET status='refunded' WHERE order_id=? AND status='success'", [order.id]);

          // 归还库存
          const items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
          for (const item of items) {
            if (item.sku_id) {
              run('UPDATE product_skus SET stock=stock+?, sales=sales-? WHERE id=?', [item.quantity, item.quantity, item.sku_id]);
            } else {
              run('UPDATE products SET stock=stock+?, sales=sales-? WHERE id=?', [item.quantity, item.quantity, item.product_id]);
            }
          }
        }

        run('INSERT INTO order_logs(order_id, action, content, operator) VALUES(?,?,?,?)',
          [refund.order_id, 'refund_approve', '退款审核通过，金额: ¥' + refund.amount, 'admin']);
      } else {
        // 审核驳回
        run("UPDATE refunds SET status='rejected', reject_reason=?, updated_at=datetime('now','localtime') WHERE id=?", [reject_reason || '', refund_id]);

        if (order) {
          // 恢复到退款前的状态（取上一个有效状态）
          const prevStatus = order.status === 'refunding' ? 'received' : order.status;
          run("UPDATE orders SET status=?, updated_at=datetime('now','localtime') WHERE id=?", [prevStatus, order.id]);
        }

        run('INSERT INTO order_logs(order_id, action, content, operator) VALUES(?,?,?,?)',
          [refund.order_id, 'refund_reject', '退款审核驳回: ' + (reject_reason || '无'), 'admin']);
      }
    });

    return res.json(success(null, action === 'approve' ? '退款已通过' : '已驳回'));
  } catch (e) {
    console.error('处理退款失败:', e);
    return res.json(fail('操作失败: ' + e.message));
  }
});

// ===================================================================
// 7. 退款列表（管理员端）- GET /api/payment/refunds
// ===================================================================
router.get('/refunds', authAdmin, (req, res) => {
  try {
    const { page: p = 1, pageSize = 20, status } = req.query;
    const pageNum = Math.max(1, +p);
    const size = Math.min(100, Math.max(1, +pageSize));

    let where = 'WHERE 1=1';
    const params = [];
    if (status) {
      where += ' AND r.status=?';
      params.push(status);
    }

    const total = get(`SELECT COUNT(*) as c FROM refunds r ${where}`, params).c;
    const list = all(`SELECT r.*, u.nickname, u.phone as user_phone, o.order_no 
      FROM refunds r 
      LEFT JOIN users u ON r.user_id=u.id 
      LEFT JOIN orders o ON r.order_id=o.id 
      ${where} 
      ORDER BY r.id DESC 
      LIMIT ? OFFSET ?`,
      [...params, size, (pageNum - 1) * size]);

    return res.json({
      code: 0,
      message: '操作成功',
      data: {
        list,
        total,
        page: pageNum,
        pageSize: size,
        totalPages: Math.ceil(total / size)
      }
    });
  } catch (e) {
    console.error('查询退款列表失败:', e);
    return res.json(fail('查询失败'));
  }
});

// ===================================================================
// 8. 我的退款申请列表（用户端）- GET /api/payment/refund/my
// 查询当前登录用户的退款记录
// ===================================================================
router.get('/refund/my', authUser, (req, res) => {
  try {
    const { page: p = 1, pageSize = 10 } = req.query;
    const pageNum = Math.max(1, +p);
    const size = Math.min(50, Math.max(1, +pageSize));

    const total = get('SELECT COUNT(*) as c FROM refunds WHERE user_id=?', [req.userId]).c;
    const list = all(`SELECT r.*, o.order_no 
      FROM refunds r 
      LEFT JOIN orders o ON r.order_id=o.id 
      WHERE r.user_id=? 
      ORDER BY r.id DESC 
      LIMIT ? OFFSET ?`,
      [req.userId, size, (pageNum - 1) * size]);

    return res.json(page(list, total, pageNum, size));
  } catch (e) {
    console.error('查询我的退款失败:', e);
    return res.json(fail('查询失败'));
  }
});

// ===================================================================
// 9. 异步订单超时关闭（供定时任务调用）
// ===================================================================
router.post('/timeout-cancel', (req, res) => {
  try {
    const timeoutMinutes = +(req.body.minutes || 30);
    const result = transaction(() => {
      const expired = all(`SELECT id, order_no FROM orders WHERE status='pending_pay' AND 
        datetime(created_at, '+' || ? || ' minutes') < datetime('now','localtime')`, [timeoutMinutes]);

      for (const order of expired) {
        run("UPDATE orders SET status='closed', close_reason='超时未支付', close_time=datetime('now','localtime') WHERE id=?", [order.id]);
        run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order.id, 'auto_close', '系统自动关闭超时订单']);

        // 归还库存
        const items = all('SELECT * FROM order_items WHERE order_id=?', [order.id]);
        for (const item of items) {
          if (item.sku_id) {
            run('UPDATE product_skus SET stock=stock+? WHERE id=?', [item.quantity, item.sku_id]);
          } else {
            run('UPDATE products SET stock=stock+? WHERE id=?', [item.quantity, item.product_id]);
          }
        }
      }
      return expired.length;
    });
    return res.json(success({ cancelled: result }, '处理完成'));
  } catch (e) {
    return res.json(fail('处理失败'));
  }
});

// ===================================================================
// 10. 支付通知模拟（测试模式用）- 保留原有接口
// ===================================================================
router.post('/mock-notify', (req, res) => {
  const { order_no, trade_no, payment_method } = req.body;
  const order = get('SELECT * FROM orders WHERE order_no=?', [order_no]);
  if (!order) return res.json(fail('订单不存在'));
  if (order.status !== 'pending_pay') return res.json(fail('订单状态不正确'));

  transaction(() => {
    run("UPDATE orders SET status='pending_ship', payment_method=?, paid_amount=pay_amount, updated_at=datetime('now','localtime') WHERE id=?",
      [payment_method || 'wechat', order.id]);
    run("INSERT INTO payment_records(trade_no,order_id,user_id,amount,method,status,pay_time) VALUES(?,?,?,?,?,?,datetime('now','localtime'))",
      [trade_no || ('MOCK' + Date.now()), order.id, order.user_id, order.pay_amount, payment_method || 'wechat', 'success']);
    run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [order.id, 'pay', '支付通知回调成功（模拟）']);
  });

  return res.json({ code: 0, message: 'success' });
});

// ===================================================================
// 辅助函数 - 生成微信支付参数
// ===================================================================
function generateWechatPay(tradeNo, amount) {
  // 实际项目需调用微信JSAPI/Native支付接口
  // 这里返回占位值
  return 'wechat://pay?trade_no=' + tradeNo + '&amount=' + amount;
}

// 辅助函数 - 生成支付宝支付链接
function generateAlipay(tradeNo, amount) {
  // 实际项目需调用支付宝接口生成支付链接
  return 'https://openapi.alipay.com/gateway.do?trade_no=' + tradeNo;
}

module.exports = router;

===== server/src/routes/upload.js =====
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { success, fail } = require('../utils/response');
const { authAdmin } = require('../middleware/auth');

const uploadDir = path.join(__dirname, '..', '..', 'uploads');
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });

const storage = multer.diskStorage({
  destination: (req, file, cb) => cb(null, uploadDir),
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname);
    cb(null, `${Date.now()}${Math.random().toString(36).slice(2,8)}${ext}`);
  }
});

const upload = multer({
  storage,
  limits: { fileSize: 10 * 1024 * 1024 },
  fileFilter: (req, file, cb) => {
    const types = /jpeg|jpg|png|gif|webp|svg/;
    cb(null, types.test(path.extname(file.originalname).toLowerCase()));
  }
});

// 上传图片
router.post('/image', authAdmin, upload.single('file'), (req, res) => {
  if (!req.file) return res.json(fail('请选择图片'));
  const url = `/uploads/${req.file.filename}`;
  return res.json(success({ url, filename: req.file.filename }, '上传成功'));
});

// 多图上传
router.post('/images', authAdmin, upload.array('files', 10), (req, res) => {
  if (!req.files || !req.files.length) return res.json(fail('请选择图片'));
  const urls = req.files.map(f => ({ url: `/uploads/${f.filename}`, filename: f.filename }));
  return res.json(success(urls, '上传成功'));
});

module.exports = router;

===== server/src/routes/config.js =====
const express = require('express');
const router = express.Router();
const { all, get } = require('../utils/db');
const { success } = require('../utils/response');

// 公开配置
router.get('/public', (req, res) => {
  const configs = all("SELECT key,value FROM system_config WHERE group_name IN ('base','payment','share','ai')");
  const map = {};
  configs.forEach(c => map[c.key] = c.value);
  return res.json(success(map));
});

// 支付配置
router.get('/payment', (req, res) => {
  const configs = all("SELECT key,value FROM system_config WHERE group_name='payment'");
  const map = {};
  configs.forEach(c => map[c.key] = c.value);
  return res.json(success(map));
});

// 分享配置
router.get('/share', (req, res) => {
  const configs = all("SELECT key,value FROM system_config WHERE group_name='share'");
  const map = {};
  configs.forEach(c => map[c.key] = c.value);
  return res.json(success(map));
});

module.exports = router;

===== server/src/routes/stats.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authAdmin } = require('../middleware/auth');

router.use(authAdmin);

// 📊 销售趋势（按日/周/月）
router.get('/sales-trend', (req, res) => {
  const { range = 7, unit = 'day' } = req.query;
  let fmt = "date(created_at)";
  let interval = `-${range} day`;
  if (unit === 'week') { fmt = "strftime('%Y-W%W', created_at)"; interval = `-${range*7} day`; }
  if (unit === 'month') { fmt = "strftime('%Y-%m', created_at)"; interval = `-${range*30} day`; }

  const data = all(`SELECT ${fmt} as d, 
    COUNT(*) as order_count, 
    COALESCE(SUM(pay_amount),0) as sales_amount,
    COALESCE(AVG(pay_amount),0) as avg_amount
    FROM orders WHERE status NOT IN ('pending_pay','closed') 
    AND created_at >= date('now','localtime','${interval}')
    GROUP BY d ORDER BY d ASC`);
  return res.json(success(data));
});

// 📊 热销商品 Top
router.get('/top-products', (req, res) => {
  const { limit = 10 } = req.query;
  const data = all(`SELECT oi.product_id, oi.product_name, oi.image,
    SUM(oi.quantity) as total_qty, SUM(oi.subtotal) as total_amount,
    COUNT(DISTINCT oi.order_id) as order_count
    FROM order_items oi JOIN orders o ON oi.order_id=o.id
    WHERE o.status NOT IN ('pending_pay','closed')
    GROUP BY oi.product_id ORDER BY total_qty DESC LIMIT ?`, [+limit]);
  return res.json(success(data));
});

// 📊 用户增长趋势
router.get('/user-growth', (req, res) => {
  const { days = 7 } = req.query;
  const data = all(`SELECT date(created_at) as d, COUNT(*) as new_users 
    FROM users WHERE phone != 'admin' 
    AND created_at >= date('now','localtime','-${+days} day')
    GROUP BY d ORDER BY d ASC`, []);
  return res.json(success(data));
});

// 📊 会员统计
router.get('/membership-stats', (req, res) => {
  const totalUsers = get("SELECT COUNT(*) as c FROM users WHERE phone != 'admin'").c;
  const vipUsers = get("SELECT COUNT(DISTINCT user_id) as c FROM user_memberships WHERE status='active'").c;
  const levelDist = all(`SELECT l.name, l.level, COUNT(u.id) as user_count 
    FROM user_levels l LEFT JOIN users u ON u.level_id=l.id AND u.phone!='admin'
    GROUP BY l.id ORDER BY l.level ASC`);
  const revenue = get("SELECT COALESCE(SUM(price),0) as s FROM membership_plans mp JOIN user_memberships um ON mp.id=um.plan_id").s;
  return res.json(success({ total_users: totalUsers, vip_users: vipUsers, vip_rate: totalUsers ? +(vipUsers/totalUsers*100).toFixed(1) : 0, level_distribution: levelDist, total_revenue: revenue }));
});

// 📊 订单状态分布
router.get('/order-status', (req, res) => {
  const data = all(`SELECT status, COUNT(*) as count, COALESCE(SUM(pay_amount),0) as amount 
    FROM orders GROUP BY status ORDER BY count DESC`);
  return res.json(success(data));
});

// 📊 今日/本周/本月概览
router.get('/overview', (req, res) => {
  const today = get("SELECT COUNT(*) as orders, COALESCE(SUM(pay_amount),0) as sales FROM orders WHERE date(created_at)=date('now','localtime') AND status NOT IN ('pending_pay','closed')");
  const week = get("SELECT COUNT(*) as orders, COALESCE(SUM(pay_amount),0) as sales FROM orders WHERE created_at>=date('now','localtime','-7 day') AND status NOT IN ('pending_pay','closed')");
  const month = get("SELECT COUNT(*) as orders, COALESCE(SUM(pay_amount),0) as sales FROM orders WHERE strftime('%Y-%m',created_at)=strftime('%Y-%m','now','localtime') AND status NOT IN ('pending_pay','closed')");
  return res.json(success({ today, week, month }));
});

// 📊 库存预警
router.get('/low-stock', (req, res) => {
  const { threshold = 10 } = req.query;
  const products = all(`SELECT id, name, image, stock, sales, price FROM products 
    WHERE status=1 AND stock <= ? ORDER BY stock ASC LIMIT 50`, [+threshold]);
  const skus = all(`SELECT ps.id, ps.product_id, p.name, ps.sku_code, ps.image, ps.stock, ps.price 
    FROM product_skus ps JOIN products p ON ps.product_id=p.id 
    WHERE ps.status=1 AND ps.stock <= ? ORDER BY ps.stock ASC LIMIT 50`, [+threshold]);
  return res.json(success({ products, skus, threshold: +threshold }));
});

// 📤 导出订单 CSV
router.get('/export/orders', (req, res) => {
  const { status, start_date, end_date } = req.query;
  let where = "WHERE o.status NOT IN ('pending_pay','closed')";
  const params = [];
  if (status) { where += ' AND o.status=?'; params.push(status); }
  if (start_date) { where += ' AND date(o.created_at)>=?'; params.push(start_date); }
  if (end_date) { where += ' AND date(o.created_at)<=?'; params.push(end_date); }

  const orders = all(`SELECT o.order_no,o.created_at,o.status,o.pay_amount,o.total_amount,
    o.discount_amount,o.payment_method,o.consignee,o.phone,o.province||o.city||o.district||o.address as full_address,
    o.remark,u.nickname,u.phone as user_phone
    FROM orders o LEFT JOIN users u ON o.user_id=u.id ${where} ORDER BY o.id DESC`, params);

  const header = '订单号,下单时间,状态,支付金额,商品总额,优惠金额,支付方式,收货人,联系电话,收货地址,备注,用户昵称,用户手机\n';
  const statusMap = { pending_pay:'待付款',pending_ship:'待发货',shipped:'已发货',received:'已收货',completed:'已完成',closed:'已关闭',refunding:'退款中',refunded:'已退款' };
  const rows = orders.map(o => 
    `"${o.order_no}","${o.created_at}","${statusMap[o.status]||o.status}","${o.pay_amount}","${o.total_amount}","${o.discount_amount}","${o.payment_method||'-'}","${o.consignee||'-'}","${o.phone||'-'}","${o.full_address||'-'}","${o.remark||'-'}","${o.nickname||'-'}","${o.user_phone||'-'}"`
  ).join('\n');

  res.setHeader('Content-Type', 'text/csv; charset=utf-8');
  res.setHeader('Content-Disposition', 'attachment; filename=orders.csv');
  res.send('\uFEFF' + header + rows);
});

// 📤 导出用户 CSV
router.get('/export/users', (req, res) => {
  const { start_date, end_date } = req.query;
  let where = "WHERE phone != 'admin'";
  const params = [];
  if (start_date) { where += ' AND date(created_at)>=?'; params.push(start_date); }
  if (end_date) { where += ' AND date(created_at)<=?'; params.push(end_date); }

  const users = all(`SELECT u.id,u.nickname,u.phone,u.balance,u.total_consumed,u.order_count,
    u.experience,u.team_count,u.created_at,l.name as level_name
    FROM users u LEFT JOIN user_levels l ON u.level_id=l.id ${where} ORDER BY u.id DESC`, params);

  const header = '用户ID,昵称,手机号,余额,累计消费,订单数,经验值,团队人数,等级,注册时间\n';
  const rows = users.map(u => 
    `"${u.id}","${u.nickname}","${u.phone}","${u.balance}","${u.total_consumed}","${u.order_count}","${u.experience}","${u.team_count}","${u.level_name}","${u.created_at}"`
  ).join('\n');

  res.setHeader('Content-Type', 'text/csv; charset=utf-8');
  res.setHeader('Content-Disposition', 'attachment; filename=users.csv');
  res.send('\uFEFF' + header + rows);
});

// 📤 导出商品 CSV
router.get('/export/products', (req, res) => {
  const products = all(`SELECT p.id,p.name,p.price,p.original_price,p.cost_price,p.stock,p.sales,
    p.unit,p.status,p.created_at,c.name as category_name
    FROM products p LEFT JOIN categories c ON p.category_id=c.id ORDER BY p.id DESC`);

  const header = '商品ID,商品名,售价,原价,成本价,库存,销量,单位,状态,分类,创建时间\n';
  const rows = products.map(p => 
    `"${p.id}","${p.name}","${p.price}","${p.original_price}","${p.cost_price}","${p.stock}","${p.sales}","${p.unit||'件'}","${p.status?'上架':'下架'}","${p.category_name||'-'}","${p.created_at}"`
  ).join('\n');

  res.setHeader('Content-Type', 'text/csv; charset=utf-8');
  res.setHeader('Content-Disposition', 'attachment; filename=products.csv');
  res.send('\uFEFF' + header + rows);
});

// 🔔 操作日志查询
router.get('/operation-logs', (req, res) => {
  const { page: p = 1, pageSize = 30, module, action } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE 1=1';
  const params = [];
  if (module) { where += ' AND module=?'; params.push(module); }
  if (action) { where += ' AND action LIKE ?'; params.push(`%${action}%`); }
  const total = get(`SELECT COUNT(*) as c FROM operation_logs ${where}`, params).c;
  const list = all(`SELECT * FROM operation_logs ${where} ORDER BY id DESC LIMIT ? OFFSET ?`,
    [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 📋 最近活动（用于首页）
router.get('/recent-activity', (req, res) => {
  const recentOrders = all("SELECT order_no,pay_amount,created_at FROM orders WHERE status NOT IN ('pending_pay') ORDER BY id DESC LIMIT 10");
  const newUsers = all("SELECT id,nickname,phone,created_at FROM users WHERE phone != 'admin' ORDER BY id DESC LIMIT 10");
  return res.json(success({ recent_orders: recentOrders, new_users: newUsers }));
});

// 🔔 系统通知 - 发送给用户
router.post('/send-notification', authAdmin, (req, res) => {
  const { user_id, type, title, content } = req.body;
  if (!title) return res.json(fail('标题不能为空'));
  
  if (user_id && user_id !== 'all') {
    run('INSERT INTO notifications(user_id,type,title,content) VALUES(?,?,?,?)', [user_id, type||'system', title, content||'']);
    return res.json(success(null, '发送成功'));
  }
  // 发送给所有用户
  run('INSERT INTO notifications(user_id,type,title,content) VALUES(0,?,?,?)', [type||'system', title, content||'']);
  return res.json(success(null, '已发送给全站用户'));
});

// 🔔 通知列表（管理端）
router.get('/notifications', authAdmin, (req, res) => {
  const { page: p = 1, pageSize = 20 } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  const total = get('SELECT COUNT(*) as c FROM notifications', []).c;
  const list = all('SELECT * FROM notifications ORDER BY id DESC LIMIT ? OFFSET ?', [size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 🏷️ 批量操作 - 批量上下架
router.post('/batch/product-status', authAdmin, (req, res) => {
  const { ids, status } = req.body;
  if (!ids || !ids.length) return res.json(fail('请选择商品'));
  const stmt = get('?').constructor; // placeholder
  const placeholders = ids.map(() => '?').join(',');
  run(`UPDATE products SET status=?,updated_at=datetime('now','localtime') WHERE id IN (${placeholders})`, [status, ...ids]);
  return res.json(success(null, `已${status?'上架':'下架'}${ids.length}个商品`));
});

// 🏷️ 批量发货
router.post('/batch/ship', authAdmin, (req, res) => {
  const { order_ids, shipping_company, shipping_no } = req.body;
  if (!order_ids || !order_ids.length) return res.json(fail('请选择订单'));
  for (const oid of order_ids) {
    run(`UPDATE orders SET status='shipped',shipping_company=?,shipping_no=?,shipping_time=datetime('now','localtime') WHERE id=? AND status='pending_ship'`,
      [shipping_company||'', shipping_no||'', oid]);
    run('INSERT INTO order_logs(order_id,action,content) VALUES(?,?,?)', [oid, 'ship', `批量发货:${shipping_company||''}`]);
  }
  return res.json(success(null, `已批量发货${order_ids.length}单`));
});

module.exports = router;

===== server/src/routes/system.js =====
const express = require('express');
const router = express.Router();
const { get, run, all, transaction } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authAdmin } = require('../middleware/auth');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('../../config');

router.use(authAdmin);

// ============================
//  1. 系统配置管理 (可视化配置面板)
// ============================

// 获取所有配置 (按组)
router.get('/config', (req, res) => {
  const configs = all('SELECT * FROM system_config ORDER BY group_name, id ASC');
  const grouped = {};
  for (const c of configs) {
    if (!grouped[c.group_name]) grouped[c.group_name] = [];
    grouped[c.group_name].push(c);
  }
  return res.json(success(grouped));
});

// 更新配置 (批量)
router.put('/config', (req, res) => {
  try {
    const { updates } = req.body;
    if (!updates || !updates.length) return res.json(fail('无更新数据'));
    
    transaction(() => {
      for (const u of updates) {
        run('UPDATE system_config SET value=? WHERE key=?', [String(u.value), u.key]);
      }
    });
    return res.json(success(null, '配置更新成功'));
  } catch (e) {
    console.error('配置更新失败:', e);
    return res.json(fail('配置更新失败'));
  }
});

// ============================
//  2. 模块开关状态
// ============================
router.get('/modules', (req, res) => {
  const modules = all("SELECT key, value, description FROM system_config WHERE group_name='module'");
  const map = {};
  modules.forEach(m => map[m.key.replace('module_', '')] = m.value === '1');
  return res.json(success(map));
});

// ============================
//  3. 管理员列表
// ============================
router.get('/admins', (req, res) => {
  const list = all("SELECT id, nickname, phone, avatar, status, created_at FROM users ORDER BY id ASC");
  return res.json(success(list));
});

// 创建管理员
router.post('/admins', async (req, res) => {
  try {
    const { phone, password, nickname } = req.body;
    if (!phone || !password) return res.json(fail('手机号和密码不能为空'));
    if (password.length < 6) return res.json(fail('密码长度不能少于6位'));
    
    const exist = get('SELECT id FROM users WHERE phone=?', [phone]);
    if (exist) return res.json(fail('该账号已存在'));
    
    const hash = await bcrypt.hash(password, 10);
    run('INSERT INTO users(phone,password,nickname) VALUES(?,?,?)',
      [phone, hash, nickname || phone]);
    return res.json(success(null, '创建成功'));
  } catch (e) {
    return res.json(fail('创建失败'));
  }
});

// 修改管理员状态
router.put('/admins/:id/status', (req, res) => {
  const { status } = req.body;
  const id = +req.params.id;
  if (id === 1) return res.json(fail('不能操作超级管理员'));
  run('UPDATE users SET status=? WHERE id=?', [status, id]);
  return res.json(success(null, status ? '已启用' : '已禁用'));
});

// 删除管理员
router.delete('/admins/:id', (req, res) => {
  const id = +req.params.id;
  if (id === 1) return res.json(fail('不能删除超级管理员'));
  run('DELETE FROM users WHERE id=?', [id]);
  return res.json(success(null, '删除成功'));
});

// ============================
//  4. 角色权限
// ============================
router.get('/roles', (req, res) => {
  const perms = [
    { id: 1, name: '超级管理员', permissions: 'all', desc: '系统全部权限，无限制' },
    { id: 2, name: '运营', permissions: 'products,orders,users,marketing,distribution,ai', desc: '商品、订单、用户、营销管理' },
    { id: 3, name: '财务', permissions: 'orders,users,distribution,stats,export', desc: '订单查看、数据统计、导出' },
    { id: 4, name: '客服', permissions: 'orders,users,ai', desc: '订单处理、用户查询、AI客服管理' },
  ];
  return res.json(success(perms));
});

// ============================
//  5. 数据库备份
// ============================
router.post('/backup', (req, res) => {
  try {
    const fs = require('fs');
    const path = require('path');
    const src = config.dbPath;
    const backupDir = path.join(path.dirname(src), 'backup');
    if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
    
    const date = new Date();
    const stamp = `${date.getFullYear()}${String(date.getMonth()+1).padStart(2,'0')}${String(date.getDate()).padStart(2,'0')}_${String(date.getHours()).padStart(2,'0')}${String(date.getMinutes()).padStart(2,'0')}`;
    const dest = path.join(backupDir, 'litemall_' + stamp + '.db');
    
    fs.copyFileSync(src, dest);
    const size = fs.statSync(dest).size;
    
    const keepDays = +(get("SELECT value FROM system_config WHERE key='backup_keep_days'")?.value || 7);
    const files = fs.readdirSync(backupDir).filter(f => f.startsWith('litemall_') && f.endsWith('.db'));
    const now = Date.now();
    for (const f of files) {
      const fp = path.join(backupDir, f);
      const age = (now - fs.statSync(fp).mtimeMs) / 86400000;
      if (age > keepDays) fs.unlinkSync(fp);
    }
    
    return res.json(success({ path: dest, size, keepDays }, '备份成功'));
  } catch (e) {
    return res.json(fail('备份失败: ' + e.message));
  }
});

// 备份列表
router.get('/backups', (req, res) => {
  try {
    const fs = require('fs');
    const path = require('path');
    const backupDir = path.join(path.dirname(config.dbPath), 'backup');
    if (!fs.existsSync(backupDir)) return res.json(success([]));
    
    const files = fs.readdirSync(backupDir)
      .filter(f => f.startsWith('litemall_') && f.endsWith('.db'))
      .map(f => {
        const fp = path.join(backupDir, f);
        const stat = fs.statSync(fp);
        return { name: f, size: stat.size, mtime: stat.mtime.toISOString() };
      })
      .sort((a, b) => b.mtime < a.mtime ? -1 : 1);
    
    return res.json(success(files));
  } catch (e) {
    return res.json(fail('获取备份列表失败'));
  }
});

// 恢复备份
router.post('/backup/restore', (req, res) => {
  try {
    const { name } = req.body;
    if (!name) return res.json(fail('请指定备份文件'));
    const fs = require('fs');
    const path = require('path');
    const backupDir = path.join(path.dirname(config.dbPath), 'backup');
    const src = path.join(backupDir, name);
    if (!fs.existsSync(src)) return res.json(fail('备份文件不存在'));
    
    const { close } = require('../utils/db');
    close();
    fs.copyFileSync(src, config.dbPath);
    
    return res.json(success(null, '恢复成功，请重启服务'));
  } catch (e) {
    return res.json(fail('恢复失败: ' + e.message));
  }
});

// ============================
//  6. 运行日志
// ============================
router.get('/logs', (req, res) => {
  try {
    const fs = require('fs');
    const path = require('path');
    const logFile = path.join(__dirname, '..', '..', 'server.log');
    if (!fs.existsSync(logFile)) return res.json(success({ lines: ['暂无日志数据'], total: 0 }));
    
    const maxLines = 200;
    const content = fs.readFileSync(logFile, 'utf-8');
    const lines = content.split('\n').filter(Boolean).slice(-maxLines).reverse();
    
    return res.json(success({ lines, total: lines.length }));
  } catch (e) {
    return res.json(fail('读取日志失败'));
  }
});

// 清除日志
router.delete('/logs', (req, res) => {
  try {
    const fs = require('fs');
    const path = require('path');
    const logFile = path.join(__dirname, '..', '..', 'server.log');
    fs.writeFileSync(logFile, '');
    return res.json(success(null, '日志已清除'));
  } catch (e) {
    return res.json(fail('清除失败'));
  }
});

// ============================
//  7. 运营模式切换
// ============================
router.post('/switch-mode', (req, res) => {
  const { mode } = req.body;
  if (!['test', 'production'].includes(mode)) return res.json(fail('无效模式'));
  run("UPDATE system_config SET value=? WHERE key='operate_mode'", [mode]);
  const label = mode === 'test' ? '测试' : '正式';
  return res.json(success({ mode }, '已切换至' + label + '模式'));
});

// 获取当前模式
router.get('/mode', (req, res) => {
  const mode = get("SELECT value FROM system_config WHERE key='operate_mode'")?.value || 'test';
  return res.json(success({ mode, label: mode === 'test' ? '测试模式' : '正式运营' }));
});


// ============================
//  8. 登录日志
// ============================
router.get('/login-logs', (req, res) => {
  const { page: p = 1, pageSize = 30, phone, result } = req.query;
  const pageNum = Math.max(1, +p);
  const size = Math.min(100, Math.max(1, +pageSize));
  let where = 'WHERE 1=1';
  const params = [];
  if (phone) { where += ' AND phone LIKE ?'; params.push('%' + phone + '%'); }
  if (result) { where += ' AND result=?'; params.push(result); }
  
  const total = get('SELECT COUNT(*) as c FROM login_logs ' + where, params).c;
  const list = all('SELECT * FROM login_logs ' + where + ' ORDER BY id DESC LIMIT ? OFFSET ?',
    [...params, size, (pageNum - 1) * size]);
  return res.json(page(list, total, pageNum, size));
});

// 登录日志统计
router.get('/login-logs/stats', (req, res) => {
  const today = get("SELECT COUNT(*) as total, SUM(CASE WHEN result='success' THEN 1 ELSE 0 END) as success, SUM(CASE WHEN result='fail' THEN 1 ELSE 0 END) as fail FROM login_logs WHERE date(created_at)=date('now','localtime')");
  const total = get('SELECT COUNT(*) as c FROM login_logs').c;
  return res.json(success({ today, total }));
});

// ============================
//  9. 密码强度检查
// ============================
router.post('/check-password', (req, res) => {
  const { password } = req.body;
  const { checkPasswordStrength } = require('../middleware/security');
  const errors = checkPasswordStrength(password);
  return res.json(success({ valid: errors.length === 0, errors }));
});

module.exports = router;

===== server/src/routes/captcha.js =====
const express = require('express');
const router = express.Router();
const svgCaptcha = require('svg-captcha');

// 存储验证码（生产环境建议用redis）
const captchaStore = {};
const CAPTCHA_EXPIRE = 5 * 60 * 1000; // 5分钟

// 生成验证码
router.get('/image', (req, res) => {
  const captcha = svgCaptcha.create({
    size: 4,
    fontSize: 50,
    width: 120,
    height: 40,
    noise: 2,
    color: true,
    background: '#f0f4ff',
  });
  
  const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
  captchaStore[id] = {
    text: captcha.text.toLowerCase(),
    expires: Date.now() + CAPTCHA_EXPIRE
  };
  
  // 清理过期验证码
  for (const key in captchaStore) {
    if (captchaStore[key].expires < Date.now()) delete captchaStore[key];
  }
  
  res.json({
    code: 0,
    data: {
      id,
      svg: captcha.data
    }
  });
});

// 验证验证码
router.post('/verify', (req, res) => {
  const { id, text } = req.body;
  if (!id || !text) return res.json({ code: 1, message: '参数不完整' });
  
  const record = captchaStore[id];
  if (!record) return res.json({ code: 1, message: '验证码已过期' });
  if (record.expires < Date.now()) {
    delete captchaStore[id];
    return res.json({ code: 1, message: '验证码已过期' });
  }
  
  if (record.text !== text.toLowerCase()) {
    return res.json({ code: 1, message: '验证码错误' });
  }
  
  delete captchaStore[id];
  res.json({ code: 0, message: '验证通过' });
});

// 发送短信验证码（mock）
router.post('/sms', (req, res) => {
  const { phone } = req.body;
  if (!phone) return res.json({ code: 1, message: '请输入手机号' });
  
  const code = String(Math.floor(100000 + Math.random() * 900000));
  const id = 'sms_' + Date.now().toString(36);
  captchaStore[id] = {
    text: code,
    expires: Date.now() + CAPTCHA_EXPIRE,
    phone
  };
  
  // 实际开发中这里调用短信服务商API
  console.log('[短信验证码]', phone, '->', code);
  
  res.json({
    code: 0,
    data: { id },
    message: '验证码已发送' + (process.env.NODE_ENV !== 'production' ? ': ' + code : '')
  });
});

module.exports = router;

===== server/src/routes/address.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, fail } = require('../utils/response');
const { authUser } = require('../middleware/auth');

router.use(authUser);

// 地址列表
router.get('/list', (req, res) => {
  try {
    const list = all('SELECT * FROM user_addresses WHERE user_id=? ORDER BY is_default DESC, id DESC', [req.userId]);
    return res.json(success(list));
  } catch (e) {
    return res.json(fail('获取地址失败'));
  }
});

// 保存地址（新增或更新）
router.post('/save', (req, res) => {
  try {
    const { id, name, phone, province, city, district, detail, zip_code, is_default } = req.body;
    if (!name || !phone) return res.json(fail('请填写完整信息'));

    if (id) {
      // 更新
      const addr = get('SELECT id FROM user_addresses WHERE id=? AND user_id=?', [id, req.userId]);
      if (!addr) return res.json(fail('地址不存在'));
      if (is_default) run('UPDATE user_addresses SET is_default=0 WHERE user_id=?', [req.userId]);
      run(`UPDATE user_addresses SET name=?,phone=?,province=?,city=?,district=?,detail=?,zip_code=?,is_default=?
        WHERE id=? AND user_id=?`,
        [name, phone, province||'', city||'', district||'', detail||'', zip_code||'', is_default?1:0, id, req.userId]);
      return res.json(success(null, '更新成功'));
    } else {
      // 新增
      if (is_default) run('UPDATE user_addresses SET is_default=0 WHERE user_id=?', [req.userId]);
      const count = get('SELECT COUNT(*) as c FROM user_addresses WHERE user_id=?', [req.userId]);
      const def = is_default || count.c === 0 ? 1 : 0;
      const r = run(
        'INSERT INTO user_addresses(user_id,name,phone,province,city,district,detail,zip_code,is_default) VALUES(?,?,?,?,?,?,?,?,?)',
        [req.userId, name, phone, province||'', city||'', district||'', detail||'', zip_code||'', def]
      );
      return res.json(success({ id: r.lastInsertRowid }, '新增成功'));
    }
  } catch (e) {
    return res.json(fail('保存失败'));
  }
});

// 设为默认地址
router.post('/:id/default', (req, res) => {
  try {
    const addr = get('SELECT id FROM user_addresses WHERE id=? AND user_id=?', [req.params.id, req.userId]);
    if (!addr) return res.json(fail('地址不存在'));
    run('UPDATE user_addresses SET is_default=0 WHERE user_id=?', [req.userId]);
    run('UPDATE user_addresses SET is_default=1 WHERE id=?', [req.params.id]);
    return res.json(success(null, '设置成功'));
  } catch (e) {
    return res.json(fail('设置失败'));
  }
});

// 删除地址
router.delete('/:id', (req, res) => {
  try {
    run('DELETE FROM user_addresses WHERE id=? AND user_id=?', [req.params.id, req.userId]);
    return res.json(success(null, '删除成功'));
  } catch (e) {
    return res.json(fail('删除失败'));
  }
});

module.exports = router;

===== server/src/routes/review.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, fail } = require('../utils/response');
const { authUser } = require('../middleware/auth');

// 创建评价
router.post('/create', authUser, (req, res) => {
  try {
    const { product_id, order_id, rating, content, images } = req.body;
    if (!product_id || !order_id) return res.json(fail('参数错误'));
    if (!rating || rating < 1 || rating > 5) return res.json(fail('评分需在1-5之间'));

    // 检查订单是否属于该用户且已完成（received状态）
    const order = get('SELECT * FROM orders WHERE id=? AND user_id=? AND status=?', [order_id, req.userId, 'received']);
    if (!order) return res.json(fail('订单不存在或不可评价'));

    // 检查是否已评价
    const exist = get('SELECT id FROM product_reviews WHERE user_id=? AND order_id=? AND product_id=?', [req.userId, order_id, product_id]);
    if (exist) return res.json(fail('已评价过该商品'));

    const orderItem = get('SELECT sku_info FROM order_items WHERE order_id=? AND product_id=? LIMIT 1', [order_id, product_id]);

    run('INSERT INTO product_reviews(product_id,order_id,user_id,sku_info,rating,content,images) VALUES(?,?,?,?,?,?,?)',
      [product_id, order_id, req.userId, orderItem?.sku_info||'', rating, content||'', JSON.stringify(images||[])]);

    return res.json(success(null, '评价成功'));
  } catch (e) {
    console.error('创建评价失败:', e);
    return res.json(fail('评价失败'));
  }
});

module.exports = router;

===== server/src/routes/pagebuilder.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, fail, page } = require('../utils/response');
const { authAdmin } = require('../middleware/auth');

// 获取页面布局
router.get('/layout', (req, res) => {
  const { device = 'mobile', page: p = 'home' } = req.query;
  const layout = get('SELECT * FROM page_layouts WHERE device=? AND page=? AND status=1 ORDER BY id DESC LIMIT 1', [device, p]);
  if (layout) {
    layout.layout = JSON.parse(layout.layout);
    return res.json(success(layout));
  }
  return res.json(success({ layout: [], name: '默认布局' }));
});

// 保存页面布局
router.post('/layout', authAdmin, (req, res) => {
  const { name, page: p = 'home', device = 'mobile', layout: layoutData } = req.body;
  if (!layoutData) return res.json(fail('布局数据不能为空'));
  
  const existing = get('SELECT id FROM page_layouts WHERE device=? AND page=? ORDER BY id DESC LIMIT 1', [device, p]);
  if (existing) {
    run("UPDATE page_layouts SET name=?,layout=?,updated_at=datetime('now','localtime') WHERE id=?", [name||p, JSON.stringify(layoutData), existing.id]);
  } else {
    run('INSERT INTO page_layouts(name,page,device,layout) VALUES(?,?,?,?)', [name||p, p, device, JSON.stringify(layoutData)]);
  }
  return res.json(success(null, '布局保存成功'));
});

// 获取所有布局
router.get('/layouts', authAdmin, (req, res) => {
  const list = all('SELECT * FROM page_layouts ORDER BY id DESC');
  return res.json(success(list));
});

module.exports = router;

===== server/src/routes/collector.js =====
const express = require('express');
const router = express.Router();
const { get, run, all } = require('../utils/db');
const { success, fail } = require('../utils/response');
const { authAdmin } = require('../middleware/auth');
const https = require('https');
const http = require('http');

router.use(authAdmin);

// 获取采集配置
router.get('/config', (req, res) => {
  const configs = all("SELECT key,value FROM system_config WHERE group_name='collector'");
  const map = {};
  configs.forEach(c => map[c.key] = c.value);
  return res.json(success(map));
});

// 保存采集配置
router.post('/config', (req, res) => {
  const { api_url, app_key, secret } = req.body;
  const { run } = require('../utils/db');
  run("INSERT OR REPLACE INTO system_config(group_name,key,value,description) VALUES('collector','collector_api_url',?,'采集API地址')", [api_url||'']);
  run("INSERT OR REPLACE INTO system_config(group_name,key,value,description) VALUES('collector','collector_app_key',?,'采集AppKey')", [app_key||'']);
  run("INSERT OR REPLACE INTO system_config(group_name,key,value,description) VALUES('collector','collector_secret',?,'采集密钥')", [secret||'']);
  return res.json(success(null, '配置保存成功'));
});

// 解析商品链接
router.post('/parse', async (req, res) => {
  try {
    const { url } = req.body;
    if (!url) return res.json(fail('请输入商品链接'));
    
    // 检测平台
    let platform = 'unknown';
    if (url.includes('taobao.com') || url.includes('tmall.com')) platform = 'taobao';
    else if (url.includes('1688.com')) platform = '1688';
    else if (url.includes('pinduoduo.com') || url.includes('yangkeduo.com')) platform = 'pdd';
    else if (url.includes('jd.com')) platform = 'jd';
    else if (url.includes('suning.com')) platform = 'suning';
    
    // 获取已配置的采集服务信息
    const apiUrl = get("SELECT value FROM system_config WHERE key='collector_api_url'")?.value;
    const appKey = get("SELECT value FROM system_config WHERE key='collector_app_key'")?.value;
    
    // 如果有配置采集API，调用第三方服务
    if (apiUrl && appKey) {
      try {
        const result = await callCollectorAPI(apiUrl, appKey, url, platform);
        if (result) return res.json(success(result));
      } catch(e) {
        console.error('采集API调用失败:', e.message);
      }
    }
    
    // 无采集配置时返回模拟数据（方便测试）
    return res.json(success({
      platform,
      title: getMockTitle(platform),
      price: Math.floor(Math.random() * 200) + 10,
      original_price: Math.floor(Math.random() * 400) + 50,
      images: [
        'https://picsum.photos/seed/' + Date.now() + '/400/400',
        'https://picsum.photos/seed/' + (Date.now()+1) + '/400/400'
      ],
      description: '来自' + platformName(platform) + '的商品数据，实际使用时请配置采集API密钥',
      unit: '件',
      stock: Math.floor(Math.random() * 500) + 50
    }));
  } catch(e) {
    return res.json(fail('解析失败: ' + e.message));
  }
});

function platformName(p) {
  return { taobao:'淘宝', '1688':'1688', pdd:'拼多多', jd:'京东', suning:'苏宁', unknown:'其他平台' }[p] || p;
}

function getMockTitle(p) {
  const titles = {
    taobao: ['2024新款简约ins风台灯', '家用智能感应小夜灯', '北欧落地灯客厅卧室'],
    '1688': ['LED灯带工厂直供', '筒灯射灯批发', '智能灯泡ODM定制'],
    pdd: ['超亮LED灯泡5只装', 'USB充电小夜灯', '创意氛围灯带'],
    jd: ['京选智能台灯Pro', '护眼学习台灯', '智能家居灯控套装'],
  };
  const list = titles[p] || titles.taobao;
  return list[Math.floor(Math.random() * list.length)];
}

// 调用采集API（通用HTTP请求）
function callCollectorAPI(apiUrl, appKey, url, platform) {
  return new Promise((resolve, reject) => {
    const params = JSON.stringify({ app_key: appKey, url, platform });
    const isHttps = apiUrl.startsWith('https');
    const client = isHttps ? https : http;
    
    const req = client.request(apiUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(params) }
    }, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        try { resolve(JSON.parse(data)); }
        catch(e) { reject(new Error('响应解析失败')); }
      });
    });
    req.on('error', reject);
    req.write(params);
    req.end();
  });
}

// 测试采集连接
router.post('/test', authAdmin, (req, res) => {
  const apiUrl = get("SELECT value FROM system_config WHERE key='collector_api_url'")?.value;
  const appKey = get("SELECT value FROM system_config WHERE key='collector_app_key'")?.value;
  if (!apiUrl || !appKey) return res.json(fail('请先配置采集API'));
  return res.json(success({ api_url: apiUrl, app_key: appKey }, '配置正常'));
});

module.exports = router;

===== server/src/init-db.js =====
const Database = require('better-sqlite3');
const path = require('path');
const fs = require('fs');
const bcrypt = require('bcryptjs');

const DB_PATH = path.join(__dirname, '..', 'data', 'litemall.db');

function initDatabase() {
  const dir = path.dirname(DB_PATH);
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });

  const db = new Database(DB_PATH);
  db.pragma('journal_mode = WAL');
  db.pragma('foreign_keys = ON');

  // ========== 用户体系 ==========
  db.exec(`
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      nickname TEXT DEFAULT '',
      avatar TEXT DEFAULT '',
      phone TEXT UNIQUE,
      password TEXT,
      openid TEXT,
      unionid TEXT,
      level_id INTEGER DEFAULT 1,
      experience INTEGER DEFAULT 0,
      balance DECIMAL(10,2) DEFAULT 0.00,
      freeze_balance DECIMAL(10,2) DEFAULT 0.00,
      total_consumed DECIMAL(12,2) DEFAULT 0.00,
      order_count INTEGER DEFAULT 0,
      parent_id INTEGER,
      parent_ids TEXT DEFAULT '',
      team_count INTEGER DEFAULT 0,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime')),
      updated_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS user_levels (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      level TINYINT UNIQUE NOT NULL,
      min_experience INTEGER DEFAULT 0,
      discount DECIMAL(3,2) DEFAULT 1.00,
      icon TEXT DEFAULT '',
      description TEXT DEFAULT '',
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS user_addresses (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL REFERENCES users(id),
      name TEXT NOT NULL,
      phone TEXT NOT NULL,
      province TEXT,
      city TEXT,
      district TEXT,
      detail TEXT,
      zip_code TEXT,
      is_default INTEGER DEFAULT 0,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 会员体系 ==========
    CREATE TABLE IF NOT EXISTS membership_plans (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      type TEXT CHECK(type IN ('monthly','quarterly','yearly','permanent')),
      price DECIMAL(10,2) NOT NULL,
      original_price DECIMAL(10,2) DEFAULT 0,
      level_id INTEGER REFERENCES user_levels(id),
      give_experience INTEGER DEFAULT 0,
      give_coupon_ids TEXT DEFAULT '',
      description TEXT DEFAULT '',
      status INTEGER DEFAULT 1,
      sort INTEGER DEFAULT 0,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS user_memberships (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL REFERENCES users(id),
      plan_id INTEGER REFERENCES membership_plans(id),
      start_time DATETIME,
      end_time DATETIME,
      status TEXT CHECK(status IN ('active','expired','cancelled')) DEFAULT 'active',
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 商品体系 ==========
    CREATE TABLE IF NOT EXISTS categories (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      pid INTEGER DEFAULT 0,
      icon TEXT DEFAULT '',
      image TEXT DEFAULT '',
      sort INTEGER DEFAULT 0,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS products (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      subtitle TEXT DEFAULT '',
      category_id INTEGER REFERENCES categories(id),
      brand TEXT DEFAULT '',
      unit TEXT DEFAULT '件',
      image TEXT DEFAULT '',
      images TEXT DEFAULT '[]',
      video TEXT DEFAULT '',
      description TEXT DEFAULT '',
      spec_type INTEGER DEFAULT 0,
      price DECIMAL(10,2) DEFAULT 0.00,
      original_price DECIMAL(10,2) DEFAULT 0.00,
      cost_price DECIMAL(10,2) DEFAULT 0.00,
      stock INTEGER DEFAULT 0,
      sales INTEGER DEFAULT 0,
      min_qty INTEGER DEFAULT 1,
      max_qty INTEGER DEFAULT 999,
      weight DECIMAL(10,2) DEFAULT 0,
      shipping_template_id INTEGER,
      status INTEGER DEFAULT 1,
      is_new INTEGER DEFAULT 0,
      is_hot INTEGER DEFAULT 0,
      is_recommend INTEGER DEFAULT 0,
      sort INTEGER DEFAULT 0,
      seo_keywords TEXT DEFAULT '',
      seo_description TEXT DEFAULT '',
      created_at DATETIME DEFAULT (datetime('now','localtime')),
      updated_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS product_skus (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      product_id INTEGER NOT NULL REFERENCES products(id),
      sku_code TEXT DEFAULT '',
      image TEXT DEFAULT '',
      specs TEXT DEFAULT '[]',
      price DECIMAL(10,2) NOT NULL,
      original_price DECIMAL(10,2) DEFAULT 0.00,
      cost_price DECIMAL(10,2) DEFAULT 0.00,
      stock INTEGER DEFAULT 0,
      sales INTEGER DEFAULT 0,
      weight DECIMAL(10,2) DEFAULT 0,
      bar_code TEXT DEFAULT '',
      status INTEGER DEFAULT 1,
      sort INTEGER DEFAULT 0
    );

    CREATE TABLE IF NOT EXISTS product_images (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      product_id INTEGER NOT NULL REFERENCES products(id),
      url TEXT NOT NULL,
      type INTEGER DEFAULT 0,
      sort INTEGER DEFAULT 0
    );

    CREATE TABLE IF NOT EXISTS product_specs (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      product_id INTEGER NOT NULL REFERENCES products(id),
      name TEXT NOT NULL,
      spec_values TEXT NOT NULL DEFAULT '[]',
      sort INTEGER DEFAULT 0
    );

    -- ========== 购物车与订单 ==========
    CREATE TABLE IF NOT EXISTS carts (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL REFERENCES users(id),
      product_id INTEGER NOT NULL REFERENCES products(id),
      sku_id INTEGER REFERENCES product_skus(id),
      quantity INTEGER DEFAULT 1,
      selected INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS orders (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      order_no TEXT UNIQUE NOT NULL,
      user_id INTEGER NOT NULL REFERENCES users(id),
      total_amount DECIMAL(12,2) NOT NULL,
      discount_amount DECIMAL(12,2) DEFAULT 0.00,
      shipping_fee DECIMAL(10,2) DEFAULT 0.00,
      pay_amount DECIMAL(12,2) NOT NULL,
      paid_amount DECIMAL(12,2) DEFAULT 0.00,
      payment_method TEXT CHECK(payment_method IN ('wechat','alipay','balance','none')) DEFAULT 'none',
      status TEXT CHECK(status IN ('pending_pay','pending_ship','shipped','received','completed','closed','refunding','refunded')) DEFAULT 'pending_pay',
      refund_status TEXT DEFAULT '',
      consignee TEXT DEFAULT '',
      phone TEXT DEFAULT '',
      province TEXT DEFAULT '',
      city TEXT DEFAULT '',
      district TEXT DEFAULT '',
      address TEXT DEFAULT '',
      zip_code TEXT DEFAULT '',
      shipping_company TEXT DEFAULT '',
      shipping_no TEXT DEFAULT '',
      shipping_time DATETIME,
      confirm_time DATETIME,
      close_time DATETIME,
      remark TEXT DEFAULT '',
      close_reason TEXT DEFAULT '',
      use_coupon_ids TEXT DEFAULT '',
      is_distributed INTEGER DEFAULT 0,
      created_at DATETIME DEFAULT (datetime('now','localtime')),
      updated_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS order_items (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      order_id INTEGER NOT NULL REFERENCES orders(id),
      product_id INTEGER NOT NULL,
      sku_id INTEGER,
      product_name TEXT NOT NULL,
      sku_info TEXT DEFAULT '',
      image TEXT DEFAULT '',
      price DECIMAL(10,2) NOT NULL,
      quantity INTEGER NOT NULL,
      subtotal DECIMAL(12,2) NOT NULL,
      after_sale_status INTEGER DEFAULT 0
    );

    CREATE TABLE IF NOT EXISTS order_logs (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      order_id INTEGER NOT NULL REFERENCES orders(id),
      action TEXT NOT NULL,
      operator TEXT DEFAULT 'system',
      content TEXT DEFAULT '',
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS payment_records (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      trade_no TEXT UNIQUE NOT NULL,
      order_id INTEGER REFERENCES orders(id),
      user_id INTEGER NOT NULL,
      amount DECIMAL(12,2) NOT NULL,
      method TEXT CHECK(method IN ('wechat','alipay','balance')),
      status TEXT CHECK(status IN ('pending','success','failed','refunded')) DEFAULT 'pending',
      transaction_id TEXT DEFAULT '',
      pay_time DATETIME,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS refunds (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      refund_no TEXT UNIQUE NOT NULL,
      order_id INTEGER NOT NULL REFERENCES orders(id),
      order_item_id INTEGER,
      user_id INTEGER NOT NULL REFERENCES users(id),
      type TEXT CHECK(type IN ('only_refund','refund_and_return','exchange')),
      reason TEXT NOT NULL,
      explain_text TEXT DEFAULT '',
      images TEXT DEFAULT '[]',
      amount DECIMAL(12,2) NOT NULL,
      status TEXT CHECK(status IN ('pending','approved','rejected','shipped_back','received','completed','cancelled')) DEFAULT 'pending',
      reject_reason TEXT DEFAULT '',
      shipping_company TEXT DEFAULT '',
      shipping_no TEXT DEFAULT '',
      created_at DATETIME DEFAULT (datetime('now','localtime')),
      updated_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 分销体系 ==========
    CREATE TABLE IF NOT EXISTS distribution_config (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      key TEXT UNIQUE NOT NULL,
      value TEXT DEFAULT '',
      description TEXT DEFAULT ''
    );

    CREATE TABLE IF NOT EXISTS distribution_levels (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      level INTEGER UNIQUE NOT NULL,
      min_team_count INTEGER DEFAULT 0,
      min_team_sales DECIMAL(12,2) DEFAULT 0.00,
      commission_rate DECIMAL(5,4) DEFAULT 0.0000,
      commission_rate2 DECIMAL(5,4) DEFAULT 0.0000,
      commission_rate3 DECIMAL(5,4) DEFAULT 0.0000,
      upgrade_type TEXT DEFAULT 'auto',
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS distribution_records (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      order_id INTEGER NOT NULL,
      order_item_id INTEGER,
      buyer_id INTEGER NOT NULL,
      user_id INTEGER NOT NULL,
      level INTEGER NOT NULL,
      product_amount DECIMAL(12,2) NOT NULL,
      rate DECIMAL(5,4) NOT NULL,
      commission DECIMAL(12,2) NOT NULL,
      status TEXT CHECK(status IN ('pending','settled','cancelled')) DEFAULT 'pending',
      settled_at DATETIME,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS withdraw_requests (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL REFERENCES users(id),
      amount DECIMAL(12,2) NOT NULL,
      fee DECIMAL(10,2) DEFAULT 0.00,
      real_amount DECIMAL(12,2) NOT NULL,
      account_type TEXT CHECK(account_type IN ('wechat','alipay','bank')) NOT NULL,
      account_info TEXT DEFAULT '',
      status TEXT CHECK(status IN ('pending','approved','rejected','completed')) DEFAULT 'pending',
      reject_reason TEXT DEFAULT '',
      completed_at DATETIME,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 营销体系 ==========
    CREATE TABLE IF NOT EXISTS coupons (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      type TEXT CHECK(type IN ('full_reduce','discount','cash')) NOT NULL,
      value DECIMAL(10,2) NOT NULL,
      min_amount DECIMAL(10,2) DEFAULT 0.00,
      max_amount DECIMAL(10,2) DEFAULT 0.00,
      total_count INTEGER DEFAULT 0,
      used_count INTEGER DEFAULT 0,
      per_limit INTEGER DEFAULT 1,
      valid_days INTEGER DEFAULT 30,
      start_time DATETIME,
      end_time DATETIME,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS user_coupons (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL REFERENCES users(id),
      coupon_id INTEGER NOT NULL REFERENCES coupons(id),
      status TEXT CHECK(status IN ('unused','used','expired')) DEFAULT 'unused',
      used_time DATETIME,
      expired_time DATETIME,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS seckill_products (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      product_id INTEGER NOT NULL REFERENCES products(id),
      seckill_price DECIMAL(10,2) NOT NULL,
      stock INTEGER DEFAULT 0,
      sales INTEGER DEFAULT 0,
      per_limit INTEGER DEFAULT 1,
      start_time DATETIME NOT NULL,
      end_time DATETIME NOT NULL,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS group_buy_products (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      product_id INTEGER NOT NULL REFERENCES products(id),
      group_price DECIMAL(10,2) NOT NULL,
      min_people INTEGER DEFAULT 2,
      stock INTEGER DEFAULT 0,
      sales INTEGER DEFAULT 0,
      start_time DATETIME NOT NULL,
      end_time DATETIME NOT NULL,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS group_buy_orders (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      group_id TEXT NOT NULL,
      order_id INTEGER NOT NULL REFERENCES orders(id),
      user_id INTEGER NOT NULL,
      status TEXT CHECK(status IN ('pending','success','failed')) DEFAULT 'pending',
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== AI客服知识库 ==========
    CREATE TABLE IF NOT EXISTS ai_knowledge_base (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      category TEXT DEFAULT '',
      question TEXT NOT NULL,
      answer TEXT NOT NULL,
      keywords TEXT DEFAULT '',
      weight INTEGER DEFAULT 0,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime')),
      updated_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS chat_conversations (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER REFERENCES users(id),
      title TEXT DEFAULT '',
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS chat_messages (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      conversation_id INTEGER NOT NULL REFERENCES chat_conversations(id),
      role TEXT CHECK(role IN ('user','assistant','system')) NOT NULL,
      content TEXT NOT NULL,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 系统配置 ==========
    CREATE TABLE IF NOT EXISTS system_config (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      group_name TEXT DEFAULT 'base',
      key TEXT UNIQUE NOT NULL,
      value TEXT DEFAULT '',
      type TEXT DEFAULT 'text',
      description TEXT DEFAULT '',
      sort INTEGER DEFAULT 0
    );

    CREATE TABLE IF NOT EXISTS banners (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      title TEXT DEFAULT '',
      image TEXT NOT NULL,
      url TEXT DEFAULT '',
      sort INTEGER DEFAULT 0,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS pages (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      title TEXT NOT NULL,
      type TEXT CHECK(type IN ('about','policy','service','custom')) DEFAULT 'custom',
      content TEXT DEFAULT '',
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime')),
      updated_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS login_logs (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER,
      phone TEXT,
      ip TEXT DEFAULT '',
      user_agent TEXT DEFAULT '',
      result TEXT CHECK(result IN ('success','fail')),
      reason TEXT DEFAULT '',
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    CREATE TABLE IF NOT EXISTS shipping_templates (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      type TEXT CHECK(type IN ('weight','piece','free')) DEFAULT 'piece',
      free_shipping_amount DECIMAL(10,2) DEFAULT 0.00,
      first_piece INTEGER DEFAULT 1,
      first_fee DECIMAL(10,2) DEFAULT 0.00,
      extra_piece INTEGER DEFAULT 1,
      extra_fee DECIMAL(10,2) DEFAULT 0.00,
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 操作日志 ==========
    CREATE TABLE IF NOT EXISTS operation_logs (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      admin_id INTEGER DEFAULT 0,
      action TEXT NOT NULL,
      module TEXT DEFAULT '',
      target_id INTEGER,
      detail TEXT DEFAULT '',
      ip TEXT DEFAULT '',
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 通知消息 ==========
    CREATE TABLE IF NOT EXISTS notifications (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER DEFAULT 0,
      type TEXT DEFAULT 'system',
      title TEXT NOT NULL,
      content TEXT DEFAULT '',
      is_read INTEGER DEFAULT 0,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 商品评价 ==========
    CREATE TABLE IF NOT EXISTS product_reviews (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      product_id INTEGER NOT NULL REFERENCES products(id),
      order_id INTEGER NOT NULL REFERENCES orders(id),
      user_id INTEGER NOT NULL REFERENCES users(id),
      sku_info TEXT DEFAULT '',
      rating INTEGER CHECK(rating BETWEEN 1 AND 5) DEFAULT 5,
      content TEXT DEFAULT '',
      images TEXT DEFAULT '[]',
      reply TEXT DEFAULT '',
      status INTEGER DEFAULT 1,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );

    -- ========== 收藏 ==========
    CREATE TABLE IF NOT EXISTS user_favorites (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL REFERENCES users(id),
      product_id INTEGER NOT NULL REFERENCES products(id),
      created_at DATETIME DEFAULT (datetime('now','localtime')),
      UNIQUE(user_id, product_id)
    );

    -- ========== 搜索历史 ==========
    CREATE TABLE IF NOT EXISTS search_history (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL REFERENCES users(id),
      keyword TEXT NOT NULL,
      created_at DATETIME DEFAULT (datetime('now','localtime'))
    );
  `);

  // ========== 种子数据 ==========
  // 默认用户等级
  const levelCount = db.prepare('SELECT COUNT(*) as c FROM user_levels').get();
  if (levelCount.c === 0) {
    db.prepare('INSERT INTO user_levels (name, level, min_experience, discount, description) VALUES (?,?,?,?,?)').run('普通用户', 1, 0, 1.00, '注册即享');
    db.prepare('INSERT INTO user_levels (name, level, min_experience, discount, description) VALUES (?,?,?,?,?)').run('白银会员', 2, 500, 0.90, '购物享9折');
    db.prepare('INSERT INTO user_levels (name, level, min_experience, discount, description) VALUES (?,?,?,?,?)').run('黄金会员', 3, 2000, 0.85, '购物享85折');
    db.prepare('INSERT INTO user_levels (name, level, min_experience, discount, description) VALUES (?,?,?,?,?)').run('钻石会员', 4, 8000, 0.80, '购物享8折');
  }

  // 默认管理员账号
  const adminCount = db.prepare("SELECT COUNT(*) as c FROM users WHERE phone='admin'").get();
  if (adminCount.c === 0) {
    const hash = bcrypt.hashSync('admin888', 10);
    db.prepare('INSERT INTO users (nickname, phone, password, level_id) VALUES (?,?,?,?)').run('管理员', 'admin', hash, 4);
  }

  // 默认分销等级
  const distLevelCount = db.prepare('SELECT COUNT(*) as c FROM distribution_levels').get();
  if (distLevelCount.c === 0) {
    db.prepare('INSERT INTO distribution_levels (name, level, min_team_count, commission_rate, commission_rate2, commission_rate3) VALUES (?,?,?,?,?,?)').run('普通分销商', 1, 0, 0.0500, 0.0200, 0.0100);
    db.prepare('INSERT INTO distribution_levels (name, level, min_team_count, min_team_sales, commission_rate, commission_rate2, commission_rate3) VALUES (?,?,?,?,?,?,?)').run('高级分销商', 2, 10, 5000.00, 0.0800, 0.0300, 0.0150);
    db.prepare('INSERT INTO distribution_levels (name, level, min_team_count, min_team_sales, commission_rate, commission_rate2, commission_rate3) VALUES (?,?,?,?,?,?,?)').run('金牌分销商', 3, 50, 50000.00, 0.1200, 0.0500, 0.0200);
  }

  // 默认系统配置
  const configCount = db.prepare('SELECT COUNT(*) as c FROM system_config').get();
  if (configCount.c === 0) {
    const configs = [
      ['base', 'site_name', '龙虾Lite商城', 'text', '站点名称'],
      ['base', 'site_logo', '', 'image', '站点Logo'],
      ['base', 'site_description', '轻量级电商系统', 'text', '站点描述'],
      ['base', 'icp_beian', '', 'text', 'ICP备案号'],
      ['base', 'contact_phone', '', 'text', '客服电话'],
      ['base', 'contact_email', '', 'text', '客服邮箱'],
      ['payment', 'wechat_appid', '', 'text', '微信AppId'],
      ['payment', 'wechat_mchid', '', 'text', '微信商户号'],
      ['payment', 'wechat_key', '', 'password', '微信API密钥'],
      ['payment', 'alipay_appid', '', 'text', '支付宝AppId'],
      ['payment', 'alipay_private_key', '', 'password', '支付宝私钥'],
      ['payment', 'alipay_public_key', '', 'text', '支付宝公钥'],
      ['distribution', 'is_open', '1', 'switch', '是否开启分销'],
      ['distribution', 'auto_settle_days', '7', 'number', '佣金自动结算天数'],
      ['distribution', 'min_withdraw', '10', 'number', '最低提现金额'],
      ['distribution', 'withdraw_fee_rate', '0', 'number', '提现手续费率%'],
      ['share', 'share_title', '快来这个好商城逛逛', 'text', '分享标题'],
      ['share', 'share_desc', '品质好物，一站购齐', 'text', '分享描述'],
      ['share', 'share_image', '', 'image', '分享图片'],
      ['ai', 'ai_enabled', '0', 'switch', '开启AI客服'],
      ['ai', 'ai_welcome', '您好，我是AI客服，有什么可以帮您的吗？', 'text', 'AI欢迎语'],
      ['ai', 'ai_auto_reply', '0', 'switch', '未匹配知识库时自动回复'],
      ['ai', 'ai_fallback', '您好，这个问题我需要转接人工客服，请稍等。', 'text', 'AI兜底回复'],
    ];
    const stmt = db.prepare('INSERT INTO system_config (group_name, key, value, type, description) VALUES (?,?,?,?,?)');
    for (const c of configs) stmt.run(...c);
  }

  // 默认会员套餐
  const planCount = db.prepare('SELECT COUNT(*) as c FROM membership_plans').get();
  if (planCount.c === 0) {
    db.prepare('INSERT INTO membership_plans (name, type, price, original_price, level_id, give_experience, description) VALUES (?,?,?,?,?,?,?)').run('白银月卡', 'monthly', 39.00, 59.00, 2, 500, '开通即升白银会员，享全场9折');
    db.prepare('INSERT INTO membership_plans (name, type, price, original_price, level_id, give_experience, description) VALUES (?,?,?,?,?,?,?)').run('黄金月卡', 'monthly', 69.00, 99.00, 3, 2000, '开通即升黄金会员，享全场85折');
    db.prepare('INSERT INTO membership_plans (name, type, price, original_price, level_id, give_experience, description) VALUES (?,?,?,?,?,?,?)').run('钻石月卡', 'monthly', 119.00, 169.00, 4, 8000, '开通即升钻石会员，享全场8折');
  }

  // 默认分销配置
  const distConfigCount = db.prepare('SELECT COUNT(*) as c FROM distribution_config').get();
  if (distConfigCount.c === 0) {
    const distConfigs = [
      ['is_open', '1', '是否开启分销'],
      ['auto_settle_days', '7', '佣金自动结算天数'],
      ['min_withdraw', '10', '最低提现金额'],
      ['withdraw_fee_rate', '0', '提现手续费率%'],
      ['register_earn_self', '1', '自购返佣'],
    ];
    const stmt = db.prepare('INSERT INTO distribution_config (key, value, description) VALUES (?,?,?)');
    for (const c of distConfigs) stmt.run(...c);
  }

  // 默认通知
  const notifCount = db.prepare('SELECT COUNT(*) as c FROM notifications').get();
  if (notifCount.c === 0) {
    db.prepare('INSERT INTO notifications(user_id,type,title,content) VALUES(?,?,?,?)').run(0, 'system', '欢迎使用龙虾Lite商城', '感谢您的注册！在这里您可以浏览商品、下单购买、享受会员折扣和其他优惠。');
  }

  // 默认页面
  const pageCount = db.prepare('SELECT COUNT(*) as c FROM pages').get();
  if (pageCount.c === 0) {
    db.prepare('INSERT INTO pages (title, type, content) VALUES (?,?,?)').run('关于我们', 'about', '<p>龙虾Lite商城 - 轻量级电商解决方案</p>');
    db.prepare('INSERT INTO pages (title, type, content) VALUES (?,?,?)').run('隐私政策', 'policy', '<p>我们重视您的隐私...</p>');
    db.prepare('INSERT INTO pages (title, type, content) VALUES (?,?,?)').run('服务条款', 'service', '<p>使用本商城即表示同意以下条款...</p>');
  }

  console.log('✅ 数据库初始化完成');
  db.close();
}

if (require.main === module) {
  initDatabase();
}

module.exports = { initDatabase, DB_PATH };

===== server/config/index.js =====
module.exports = {
  port: process.env.PORT || 3001,
  host: process.env.HOST || "0.0.0.0",
  jwtSecret: process.env.JWT_SECRET || 'litemall_jwt_secret_2026',
  jwtExpiresIn: '7d',
  uploadDir: process.env.UPLOAD_DIR || 'uploads',
  dbPath: require('path').join(__dirname, '..', 'data', 'litemall.db'),
};

