refactor(docs): 简化README结构,更新技术栈和项目结构描述

This commit is contained in:
2025-09-21 18:30:38 +08:00
parent 198d10f4f9
commit cc2a351f84
21 changed files with 3435 additions and 43 deletions

View File

@@ -0,0 +1,48 @@
/**
* 检查orders表的详细结构
*/
require('dotenv').config();
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize(
process.env.DB_NAME || 'niumall',
process.env.DB_USERNAME || 'jiebanke',
process.env.DB_PASSWORD || 'aiot741$12346',
{
host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
port: process.env.DB_PORT || 20784,
dialect: 'mysql',
logging: false
}
);
async function checkOrdersStructure() {
try {
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
// 获取orders表的详细结构
const [columns] = await sequelize.query("SHOW COLUMNS FROM orders");
console.log('\n📋 orders表详细结构:');
columns.forEach(col => {
console.log(` - ${col.Field}: ${col.Type} ${col.Null === 'YES' ? '(可空)' : '(非空)'} ${col.Default ? `默认值: ${col.Default}` : ''}`);
});
// 检查现有订单数据
const [orders] = await sequelize.query("SELECT orderNo, paymentStatus, orderStatus FROM orders LIMIT 5");
console.log('\n📊 现有订单状态示例:');
orders.forEach(order => {
console.log(` - ${order.orderNo}: 支付状态=${order.paymentStatus}, 订单状态=${order.orderStatus}`);
});
} catch (error) {
console.error('❌ 检查失败:', error.message);
} finally {
await sequelize.close();
}
}
checkOrdersStructure();

View File

@@ -0,0 +1,549 @@
/**
* 兼容现有表结构的数据插入脚本
* 根据实际表结构插入测试数据
*/
require('dotenv').config();
const { Sequelize } = require('sequelize');
const bcrypt = require('bcrypt');
const { v4: uuidv4 } = require('uuid');
// 使用.env文件中的配置
const sequelize = new Sequelize(
process.env.DB_NAME || 'niumall',
process.env.DB_USERNAME || 'jiebanke',
process.env.DB_PASSWORD || 'aiot741$12346',
{
host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
port: process.env.DB_PORT || 20784,
dialect: 'mysql',
logging: (msg) => console.log(`[SQL] ${msg}`),
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
}
);
/**
* 检查现有表结构
*/
async function checkTableStructure() {
console.log('\n🔍 检查现有表结构...');
try {
// 检查suppliers表结构
const [supplierColumns] = await sequelize.query("DESCRIBE suppliers");
console.log('🏭 suppliers表字段:');
const supplierFields = supplierColumns.map(col => col.Field);
supplierFields.forEach(field => console.log(` - ${field}`));
// 检查orders表结构
const [orderColumns] = await sequelize.query("DESCRIBE orders");
console.log('\n📋 orders表字段:');
const orderFields = orderColumns.map(col => col.Field);
orderFields.forEach(field => console.log(` - ${field}`));
return { supplierFields, orderFields };
} catch (error) {
console.error('❌ 检查表结构失败:', error.message);
throw error;
}
}
/**
* 插入兼容的测试数据
*/
async function insertCompatibleData() {
console.log('\n📊 开始插入兼容的测试数据...');
try {
// 1. 插入管理员和测试用户
console.log('👤 插入用户数据...');
// 检查管理员是否存在
const [existingAdmin] = await sequelize.query(
"SELECT id FROM users WHERE username = 'admin'"
);
if (existingAdmin.length === 0) {
const adminPassword = await bcrypt.hash('admin123', 10);
const adminUuid = uuidv4();
await sequelize.query(`
INSERT INTO users (
uuid, username, password_hash, openid, nickname, real_name,
user_type, status, registration_source, login_count, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
adminUuid, 'admin', adminPassword, 'admin_' + adminUuid.substring(0, 8),
'系统管理员', '管理员', 'admin', 'active', 'admin_create', 0
]
});
console.log('✅ 管理员用户创建成功');
} else {
console.log('✅ 管理员用户已存在');
}
// 测试用户数据 - 使用不同的手机号避免冲突
const testUsers = [
{
uuid: uuidv4(),
username: 'buyer001',
password: await bcrypt.hash('123456', 10),
nickname: '采购商张三',
real_name: '张三',
phone: '13900139001',
email: 'buyer001@niumall.com',
user_type: 'buyer',
company_name: '北京牛肉加工厂',
company_address: '北京市朝阳区xxx街道'
},
{
uuid: uuidv4(),
username: 'trader001',
password: await bcrypt.hash('123456', 10),
nickname: '贸易商李四',
real_name: '李四',
phone: '13900139002',
email: 'trader001@niumall.com',
user_type: 'trader',
company_name: '上海牛只贸易有限公司',
company_address: '上海市浦东新区xxx路'
},
{
uuid: uuidv4(),
username: 'supplier001',
password: await bcrypt.hash('123456', 10),
nickname: '供应商王五',
real_name: '王五',
phone: '13900139003',
email: 'supplier001@niumall.com',
user_type: 'supplier',
company_name: '内蒙古草原牧业',
company_address: '内蒙古呼和浩特市'
},
{
uuid: uuidv4(),
username: 'driver001',
password: await bcrypt.hash('123456', 10),
nickname: '司机赵六',
real_name: '赵六',
phone: '13900139004',
email: 'driver001@niumall.com',
user_type: 'driver',
id_card: '110101199001011234'
},
{
uuid: uuidv4(),
username: 'staff001',
password: await bcrypt.hash('123456', 10),
nickname: '员工孙七',
real_name: '孙七',
phone: '13900139005',
email: 'staff001@niumall.com',
user_type: 'staff',
company_name: '牛商城运营中心'
}
];
for (const user of testUsers) {
// 检查用户是否已存在(检查用户名和手机号)
const [existing] = await sequelize.query(
"SELECT id FROM users WHERE username = ? OR phone = ?",
{ replacements: [user.username, user.phone] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO users (
uuid, username, password_hash, openid, nickname, real_name, phone, email,
user_type, company_name, company_address, id_card, status,
registration_source, login_count, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
user.uuid, user.username, user.password, user.username + '_openid',
user.nickname, user.real_name, user.phone, user.email, user.user_type,
user.company_name || null, user.company_address || null, user.id_card || null,
'active', 'admin_create', 0
]
});
console.log(`✅ 用户 ${user.username} 创建成功`);
} else {
console.log(`✅ 用户 ${user.username} 已存在`);
}
}
// 2. 插入供应商数据(使用现有表结构字段)
console.log('🏭 插入供应商数据...');
const suppliers = [
{
name: '内蒙古草原牧业有限公司',
code: 'SUP001',
contact: '赵大牛',
phone: '13900139001',
address: '内蒙古呼和浩特市赛罕区草原路123号',
region: '内蒙古',
qualificationLevel: 'A',
cattleTypes: JSON.stringify(['西门塔尔牛', '安格斯牛', '夏洛莱牛']),
capacity: 500,
rating: 4.8,
cooperationStartDate: '2023-01-01'
},
{
name: '新疆天山畜牧合作社',
code: 'SUP002',
contact: '马小羊',
phone: '13900139002',
address: '新疆乌鲁木齐市天山区畜牧街456号',
region: '新疆',
qualificationLevel: 'A',
cattleTypes: JSON.stringify(['哈萨克牛', '新疆褐牛']),
capacity: 300,
rating: 4.5,
cooperationStartDate: '2023-03-15'
},
{
name: '山东鲁西黄牛养殖场',
code: 'SUP003',
contact: '孙大强',
phone: '13900139003',
address: '山东省济南市历城区养殖园区789号',
region: '山东',
qualificationLevel: 'B',
cattleTypes: JSON.stringify(['鲁西黄牛', '利木赞牛']),
capacity: 200,
rating: 4.2,
cooperationStartDate: '2023-06-01'
},
{
name: '四川成都优质牧场',
code: 'SUP004',
contact: '李小川',
phone: '13900139004',
address: '四川省成都市双流区牧场路101号',
region: '四川',
qualificationLevel: 'B',
cattleTypes: JSON.stringify(['西门塔尔牛', '本地黄牛']),
capacity: 150,
rating: 4.0,
cooperationStartDate: '2023-08-01'
},
{
name: '河北承德绿色牧业',
code: 'SUP005',
contact: '张承德',
phone: '13900139005',
address: '河北省承德市双桥区绿色牧场街202号',
region: '河北',
qualificationLevel: 'C',
cattleTypes: JSON.stringify(['夏洛莱牛', '安格斯牛']),
capacity: 100,
rating: 3.8,
cooperationStartDate: '2023-09-15'
}
];
for (const supplier of suppliers) {
// 检查供应商是否已存在
const [existing] = await sequelize.query(
"SELECT id FROM suppliers WHERE code = ?",
{ replacements: [supplier.code] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO suppliers (
name, code, contact, phone, address, region, qualification_level,
cattle_types, capacity, rating, cooperation_start_date, status, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
supplier.name, supplier.code, supplier.contact, supplier.phone,
supplier.address, supplier.region, supplier.qualificationLevel, supplier.cattleTypes,
supplier.capacity, supplier.rating, supplier.cooperationStartDate, 'active'
]
});
console.log(`✅ 供应商 ${supplier.code} 创建成功`);
} else {
console.log(`✅ 供应商 ${supplier.code} 已存在`);
}
}
// 3. 插入订单数据(使用现有表结构)
console.log('📋 插入订单数据...');
// 获取用户和供应商ID
const [buyers] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'buyer' LIMIT 1");
const [traders] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'trader' LIMIT 1");
const [supplierList] = await sequelize.query("SELECT id, name FROM suppliers WHERE code LIKE 'SUP%' LIMIT 3");
if (buyers.length > 0 && supplierList.length > 0) {
const orders = [
{
orderNo: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '001',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList[0].id,
supplierName: supplierList[0].name,
traderId: traders.length > 0 ? traders[0].id : null,
traderName: traders.length > 0 ? traders[0].nickname : null,
cattleBreed: '西门塔尔牛',
cattleCount: 50,
expectedWeight: 25000.00,
unitPrice: 32.50,
totalAmount: 812500.00,
paidAmount: 200000.00,
remainingAmount: 612500.00,
deliveryAddress: '北京市朝阳区屠宰场',
expectedDeliveryDate: '2024-02-15 08:00:00',
status: 'confirmed',
notes: '要求健康证明齐全质量等级A级重量范围450-550kg'
},
{
orderNo: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '002',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList.length > 1 ? supplierList[1].id : supplierList[0].id,
supplierName: supplierList.length > 1 ? supplierList[1].name : supplierList[0].name,
traderId: null,
traderName: null,
cattleBreed: '安格斯牛',
cattleCount: 30,
expectedWeight: 16500.00,
unitPrice: 35.00,
totalAmount: 577500.00,
paidAmount: 150000.00,
remainingAmount: 427500.00,
deliveryAddress: '上海市浦东新区加工厂',
expectedDeliveryDate: '2024-02-20 10:00:00',
status: 'pending',
notes: '需要冷链运输重量范围500-600kg'
},
{
orderNo: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '003',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList.length > 2 ? supplierList[2].id : supplierList[0].id,
supplierName: supplierList.length > 2 ? supplierList[2].name : supplierList[0].name,
traderId: null,
traderName: null,
cattleBreed: '鲁西黄牛',
cattleCount: 20,
expectedWeight: 9000.00,
unitPrice: 30.00,
totalAmount: 270000.00,
paidAmount: 80000.00,
remainingAmount: 190000.00,
deliveryAddress: '天津市滨海新区肉类加工园',
expectedDeliveryDate: '2024-02-25 14:00:00',
status: 'pending',
notes: '本地优质黄牛肉质鲜美重量范围400-500kg'
}
];
for (const order of orders) {
// 检查订单是否已存在
const [existing] = await sequelize.query(
"SELECT id FROM orders WHERE orderNo = ?",
{ replacements: [order.orderNo] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO orders (
orderNo, buyerId, buyerName, supplierId, supplierName, traderId, traderName,
cattleBreed, cattleCount, expectedWeight, unitPrice, totalAmount, paidAmount,
remainingAmount, deliveryAddress, expectedDeliveryDate, status, notes,
created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
order.orderNo, order.buyerId, order.buyerName, order.supplierId, order.supplierName,
order.traderId, order.traderName, order.cattleBreed, order.cattleCount,
order.expectedWeight, order.unitPrice, order.totalAmount, order.paidAmount,
order.remainingAmount, order.deliveryAddress, order.expectedDeliveryDate,
order.status, order.notes
]
});
console.log(`✅ 订单 ${order.orderNo} 创建成功`);
} else {
console.log(`✅ 订单 ${order.orderNo} 已存在`);
}
}
}
// 4. 插入系统配置
console.log('⚙️ 插入系统配置...');
const configs = [
['system.name', '活牛采购智能数字化系统', 'string', 'system', '系统名称'],
['system.version', '1.0.0', 'string', 'system', '系统版本'],
['system.company', '牛商城科技有限公司', 'string', 'system', '公司名称'],
['order.auto_confirm_hours', '24', 'number', 'order', '订单自动确认时间(小时)'],
['order.max_quantity', '1000', 'number', 'order', '单笔订单最大数量'],
['payment.timeout_minutes', '30', 'number', 'payment', '支付超时时间(分钟)'],
['payment.min_prepaid_ratio', '0.2', 'number', 'payment', '最低预付比例'],
['transport.tracking_interval', '300', 'number', 'transport', '位置跟踪间隔(秒)'],
['transport.max_distance', '2000', 'number', 'transport', '最大运输距离(公里)'],
['quality.min_score', '80', 'number', 'quality', '质量检验最低分数'],
['quality.pass_rate_threshold', '0.95', 'number', 'quality', '合格率阈值'],
['notification.sms_enabled', 'true', 'boolean', 'notification', '是否启用短信通知'],
['notification.email_enabled', 'true', 'boolean', 'notification', '是否启用邮件通知'],
['notification.push_enabled', 'true', 'boolean', 'notification', '是否启用推送通知'],
['security.session_timeout', '7200', 'number', 'security', '会话超时时间(秒)'],
['security.max_login_attempts', '5', 'number', 'security', '最大登录尝试次数']
];
for (const [key, value, type, category, description] of configs) {
// 检查配置是否已存在
const [existing] = await sequelize.query(
"SELECT id FROM system_configs WHERE config_key = ?",
{ replacements: [key] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO system_configs (
config_key, config_value, config_type, category, description,
is_public, is_editable, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [key, value, type, category, description, true, true]
});
console.log(`✅ 配置 ${key} 创建成功`);
} else {
console.log(`✅ 配置 ${key} 已存在`);
}
}
console.log('✅ 兼容数据插入完成');
} catch (error) {
console.error('❌ 插入数据失败:', error.message);
throw error;
}
}
/**
* 验证数据完整性
*/
async function validateData() {
console.log('\n🔍 验证数据完整性...');
try {
const tables = ['users', 'suppliers', 'orders', 'payments', 'system_configs'];
console.log('📊 数据统计:');
for (const table of tables) {
try {
const [result] = await sequelize.query(`SELECT COUNT(*) as count FROM ${table}`);
console.log(` ${table}: ${result[0].count} 条记录`);
} catch (error) {
console.log(` ${table}: 表不存在或查询失败`);
}
}
// 检查关键数据
const [adminUsers] = await sequelize.query(
"SELECT id, username, nickname FROM users WHERE user_type = 'admin'"
);
console.log('\n👤 管理员用户:');
adminUsers.forEach(user => {
console.log(` - ID: ${user.id}, 用户名: ${user.username}, 昵称: ${user.nickname}`);
});
const [supplierStats] = await sequelize.query(`
SELECT qualification_level, COUNT(*) as count
FROM suppliers
WHERE code LIKE 'SUP%'
GROUP BY qualification_level
ORDER BY qualification_level
`);
console.log('\n🏭 新增供应商等级分布:');
supplierStats.forEach(stat => {
console.log(` - 等级${stat.qualification_level}: ${stat.count}`);
});
const [orderStats] = await sequelize.query(`
SELECT status, COUNT(*) as count
FROM orders
WHERE orderNo LIKE 'ORD2024%'
GROUP BY status
ORDER BY status
`);
console.log('\n📋 新增订单状态分布:');
orderStats.forEach(stat => {
console.log(` - ${stat.status}: ${stat.count}`);
});
} catch (error) {
console.error('❌ 数据验证失败:', error.message);
}
}
/**
* 主函数
*/
async function main() {
try {
console.log('\n🚀 ===== 兼容数据插入开始 =====');
// 1. 测试连接
console.log('\n📡 连接远程MySQL数据库...');
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
console.log(`📍 连接信息: ${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`);
// 2. 检查表结构
await checkTableStructure();
// 3. 插入兼容数据
await insertCompatibleData();
// 4. 验证数据
await validateData();
console.log('\n🎉 ===== 数据插入完成 =====');
console.log('\n📋 系统信息:');
console.log('🌐 后端服务: http://localhost:4330');
console.log('🎨 管理后台: http://localhost:3000');
console.log('👤 管理员账户: admin / admin123');
console.log('📚 API文档: http://localhost:4330/api-docs');
console.log('💓 健康检查: http://localhost:4330/health');
console.log('\n🔑 测试账户:');
console.log(' 采购商: buyer001 / 123456');
console.log(' 贸易商: trader001 / 123456');
console.log(' 供应商: supplier001 / 123456');
console.log(' 司机: driver001 / 123456');
console.log(' 员工: staff001 / 123456');
console.log('\n📈 数据概览:');
console.log(' - 5个不同类型的测试用户');
console.log(' - 5家不同等级的供应商');
console.log(' - 3个不同状态的订单');
console.log(' - 16项系统配置参数');
console.log(' - 完全兼容现有表结构');
} catch (error) {
console.error('\n❌ 数据插入失败:', error);
} finally {
await sequelize.close();
console.log('\n🔌 数据库连接已关闭');
}
}
// 运行脚本
if (require.main === module) {
main();
}
module.exports = { main };

View File

@@ -0,0 +1,843 @@
/**
* 完整的数据库设置脚本
* 连接远程MySQL更新表结构插入测试数据
*/
require('dotenv').config();
const { Sequelize, DataTypes } = require('sequelize');
const bcrypt = require('bcrypt');
const { v4: uuidv4 } = require('uuid');
// 创建数据库连接
const sequelize = new Sequelize(
process.env.DB_NAME || 'niumall',
process.env.DB_USERNAME || 'root',
process.env.DB_PASSWORD || 'aiotAiot123!',
{
host: process.env.DB_HOST || '129.211.213.226',
port: process.env.DB_PORT || 9527,
dialect: 'mysql',
logging: (msg) => console.log(`[SQL] ${msg}`),
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
}
);
/**
* 检查并创建/更新表结构
*/
async function updateTableStructures() {
console.log('\n🔧 开始更新表结构...');
try {
// 1. 更新用户表结构
console.log('👤 更新用户表结构...');
await sequelize.query(`
CREATE TABLE IF NOT EXISTS users (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
uuid VARCHAR(36) UNIQUE COMMENT '用户唯一标识符',
username VARCHAR(50) UNIQUE COMMENT '用户名',
password_hash VARCHAR(255) COMMENT '密码哈希值',
openid VARCHAR(64) COMMENT '微信小程序OpenID',
unionid VARCHAR(64) COMMENT '微信UnionID',
nickname VARCHAR(50) NOT NULL COMMENT '用户昵称',
real_name VARCHAR(50) COMMENT '真实姓名',
avatar VARCHAR(255) COMMENT '头像URL',
gender ENUM('male', 'female', 'other') COMMENT '性别',
birthday DATETIME COMMENT '生日',
phone VARCHAR(20) UNIQUE COMMENT '手机号码',
email VARCHAR(100) UNIQUE COMMENT '邮箱地址',
user_type ENUM('buyer', 'trader', 'supplier', 'driver', 'staff', 'admin') DEFAULT 'buyer' COMMENT '用户类型',
company_name VARCHAR(100) COMMENT '公司名称',
company_address VARCHAR(200) COMMENT '公司地址',
business_license VARCHAR(255) COMMENT '营业执照文件路径',
id_card VARCHAR(18) COMMENT '身份证号',
status ENUM('active', 'inactive', 'suspended', 'pending_approval') DEFAULT 'pending_approval' COMMENT '用户状态',
last_login_at DATETIME COMMENT '最后登录时间',
login_count INT DEFAULT 0 COMMENT '登录次数',
registration_source ENUM('miniprogram', 'web', 'admin_create') DEFAULT 'miniprogram' COMMENT '注册来源',
approval_notes TEXT COMMENT '审核备注',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_uuid (uuid),
INDEX idx_username (username),
INDEX idx_phone (phone),
INDEX idx_email (email),
INDEX idx_openid (openid),
INDEX idx_user_type (user_type),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户基础表'
`);
// 2. 更新供应商表结构
console.log('🏭 更新供应商表结构...');
await sequelize.query(`
CREATE TABLE IF NOT EXISTS suppliers (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '供应商ID',
name VARCHAR(100) NOT NULL COMMENT '供应商名称',
code VARCHAR(20) UNIQUE NOT NULL COMMENT '供应商编码',
contact VARCHAR(50) NOT NULL COMMENT '联系人姓名',
phone VARCHAR(20) UNIQUE NOT NULL COMMENT '联系电话',
email VARCHAR(100) COMMENT '邮箱地址',
address VARCHAR(200) NOT NULL COMMENT '详细地址',
region VARCHAR(20) NOT NULL COMMENT '所属区域',
business_license VARCHAR(255) COMMENT '营业执照文件路径',
animal_quarantine_certificate VARCHAR(255) COMMENT '动物防疫条件合格证文件路径',
qualification_level ENUM('A', 'B', 'C', 'D') DEFAULT 'C' COMMENT '资质等级',
certifications JSON COMMENT '其他认证证书信息',
cattle_types JSON COMMENT '可供应的牛只品种',
capacity INT DEFAULT 0 COMMENT '月供应能力(头数)',
rating DECIMAL(3,2) DEFAULT 0.00 COMMENT '综合评分',
cooperation_start_date DATE COMMENT '合作开始日期',
status ENUM('active', 'inactive', 'suspended', 'blacklisted') DEFAULT 'active' COMMENT '供应商状态',
bank_account VARCHAR(50) COMMENT '银行账号',
bank_name VARCHAR(100) COMMENT '开户银行',
tax_number VARCHAR(30) COMMENT '税务登记号',
notes TEXT COMMENT '备注信息',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_code (code),
INDEX idx_phone (phone),
INDEX idx_region (region),
INDEX idx_qualification_level (qualification_level),
INDEX idx_status (status),
INDEX idx_rating (rating)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='供应商表'
`);
// 3. 更新订单表结构
console.log('📋 更新订单表结构...');
await sequelize.query(`
CREATE TABLE IF NOT EXISTS orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '订单ID',
order_no VARCHAR(50) UNIQUE NOT NULL COMMENT '订单号',
client_id BIGINT NOT NULL COMMENT '采购人ID',
trader_id BIGINT COMMENT '贸易商ID',
supplier_id BIGINT COMMENT '供应商ID',
cattle_type VARCHAR(50) NOT NULL COMMENT '牛只品种',
quantity INT NOT NULL COMMENT '数量(头)',
weight_range VARCHAR(50) COMMENT '重量范围',
estimated_weight DECIMAL(8,2) COMMENT '预估总重量kg',
actual_weight DECIMAL(8,2) COMMENT '实际总重量kg',
unit_price DECIMAL(10,2) NOT NULL COMMENT '单价(元/kg或元/头)',
price_type ENUM('per_kg', 'per_head') DEFAULT 'per_kg' COMMENT '计价方式',
total_amount DECIMAL(12,2) NOT NULL COMMENT '订单总金额',
prepaid_amount DECIMAL(12,2) DEFAULT 0 COMMENT '预付金额',
final_amount DECIMAL(12,2) COMMENT '最终结算金额',
pickup_address TEXT COMMENT '取货地址',
delivery_address TEXT NOT NULL COMMENT '交货地址',
pickup_time DATETIME COMMENT '取货时间',
delivery_time DATETIME COMMENT '要求交货时间',
actual_delivery_time DATETIME COMMENT '实际交货时间',
status ENUM('draft', 'pending', 'confirmed', 'preparing', 'loading', 'transporting', 'arrived', 'inspecting', 'accepted', 'completed', 'cancelled') DEFAULT 'draft' COMMENT '订单状态',
cancel_reason TEXT COMMENT '取消原因',
special_requirements TEXT COMMENT '特殊要求',
quality_standards JSON COMMENT '质量标准JSON',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
confirmed_at TIMESTAMP NULL COMMENT '确认时间',
completed_at TIMESTAMP NULL COMMENT '完成时间',
INDEX idx_order_no (order_no),
INDEX idx_client_id (client_id),
INDEX idx_trader_id (trader_id),
INDEX idx_supplier_id (supplier_id),
INDEX idx_status (status),
INDEX idx_created_at (created_at),
INDEX idx_delivery_time (delivery_time),
INDEX idx_cattle_type (cattle_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单主表'
`);
// 4. 创建支付记录表
console.log('💰 创建支付记录表...');
await sequelize.query(`
CREATE TABLE IF NOT EXISTS payments (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '支付ID',
payment_no VARCHAR(50) UNIQUE NOT NULL COMMENT '支付单号',
order_id BIGINT NOT NULL COMMENT '订单ID',
user_id BIGINT NOT NULL COMMENT '付款用户ID',
amount DECIMAL(12,2) NOT NULL COMMENT '支付金额',
paid_amount DECIMAL(12,2) COMMENT '实际支付金额',
currency VARCHAR(10) DEFAULT 'CNY' COMMENT '货币类型',
payment_method ENUM('bank_transfer', 'alipay', 'wechat_pay', 'cash', 'check', 'other') NOT NULL COMMENT '支付方式',
payment_channel VARCHAR(100) COMMENT '支付渠道',
third_party_order_no VARCHAR(100) COMMENT '第三方订单号',
third_party_transaction_id VARCHAR(100) COMMENT '第三方交易ID',
payer_bank_account VARCHAR(50) COMMENT '付款账户',
payer_bank_name VARCHAR(200) COMMENT '付款银行',
payee_bank_account VARCHAR(50) COMMENT '收款账户',
payee_bank_name VARCHAR(200) COMMENT '收款银行',
status ENUM('pending', 'processing', 'success', 'failed', 'cancelled', 'refunded') DEFAULT 'pending' COMMENT '支付状态',
failure_reason TEXT COMMENT '失败原因',
payment_time DATETIME COMMENT '支付时间',
confirmed_time DATETIME COMMENT '确认时间',
notes TEXT COMMENT '支付备注',
receipt_url VARCHAR(500) COMMENT '支付凭证URL',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_payment_no (payment_no),
INDEX idx_order_id (order_id),
INDEX idx_user_id (user_id),
INDEX idx_status (status),
INDEX idx_payment_method (payment_method),
INDEX idx_payment_time (payment_time),
INDEX idx_third_party_order_no (third_party_order_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='支付记录表'
`);
// 5. 创建运输任务表
console.log('🚛 创建运输任务表...');
await sequelize.query(`
CREATE TABLE IF NOT EXISTS transport_tasks (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '任务ID',
task_no VARCHAR(50) UNIQUE NOT NULL COMMENT '任务编号',
order_id BIGINT NOT NULL COMMENT '订单ID',
driver_id BIGINT NOT NULL COMMENT '司机ID',
vehicle_no VARCHAR(20) NOT NULL COMMENT '车牌号',
vehicle_type VARCHAR(50) COMMENT '车辆类型',
vehicle_capacity DECIMAL(8,2) COMMENT '载重量(吨)',
driver_license VARCHAR(50) COMMENT '驾驶证号',
start_location VARCHAR(200) COMMENT '起始地点',
end_location VARCHAR(200) COMMENT '目的地点',
start_latitude DECIMAL(10,6) COMMENT '起始纬度',
start_longitude DECIMAL(10,6) COMMENT '起始经度',
end_latitude DECIMAL(10,6) COMMENT '目的纬度',
end_longitude DECIMAL(10,6) COMMENT '目的经度',
planned_distance DECIMAL(8,2) COMMENT '计划距离(公里)',
actual_distance DECIMAL(8,2) COMMENT '实际距离(公里)',
planned_start_time DATETIME COMMENT '计划开始时间',
actual_start_time DATETIME COMMENT '实际开始时间',
planned_end_time DATETIME COMMENT '计划结束时间',
actual_end_time DATETIME COMMENT '实际结束时间',
estimated_arrival_time DATETIME COMMENT '预计到达时间',
status ENUM('assigned', 'preparing', 'loading', 'started', 'transporting', 'arrived', 'unloading', 'completed', 'cancelled') DEFAULT 'assigned' COMMENT '任务状态',
transport_fee DECIMAL(10,2) COMMENT '运输费用',
fuel_cost DECIMAL(10,2) COMMENT '燃油费用',
toll_cost DECIMAL(10,2) COMMENT '过路费',
other_cost DECIMAL(10,2) COMMENT '其他费用',
notes TEXT COMMENT '备注',
cancel_reason TEXT COMMENT '取消原因',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_task_no (task_no),
INDEX idx_order_id (order_id),
INDEX idx_driver_id (driver_id),
INDEX idx_vehicle_no (vehicle_no),
INDEX idx_status (status),
INDEX idx_planned_start_time (planned_start_time),
INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='运输任务表'
`);
// 6. 创建质量检验表
console.log('🔍 创建质量检验表...');
await sequelize.query(`
CREATE TABLE IF NOT EXISTS quality_inspections (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '检验ID',
inspection_no VARCHAR(50) UNIQUE NOT NULL COMMENT '检验单号',
order_id BIGINT NOT NULL COMMENT '订单ID',
inspector_id BIGINT NOT NULL COMMENT '检验员ID',
inspection_time DATETIME NOT NULL COMMENT '检验时间',
inspection_location VARCHAR(200) COMMENT '检验地点',
cattle_count INT NOT NULL COMMENT '检验牛只数量',
passed_count INT DEFAULT 0 COMMENT '合格数量',
failed_count INT DEFAULT 0 COMMENT '不合格数量',
average_weight DECIMAL(8,2) COMMENT '平均重量',
total_weight DECIMAL(10,2) COMMENT '总重量',
health_status ENUM('excellent', 'good', 'fair', 'poor') DEFAULT 'good' COMMENT '健康状况',
quality_grade ENUM('A+', 'A', 'B+', 'B', 'C', 'D') DEFAULT 'B' COMMENT '质量等级',
inspection_result ENUM('passed', 'failed', 'conditional_pass') DEFAULT 'passed' COMMENT '检验结果',
defect_description TEXT COMMENT '缺陷描述',
improvement_suggestions TEXT COMMENT '改进建议',
inspector_notes TEXT COMMENT '检验员备注',
photos JSON COMMENT '检验照片URLs',
certificates JSON COMMENT '相关证书信息',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_inspection_no (inspection_no),
INDEX idx_order_id (order_id),
INDEX idx_inspector_id (inspector_id),
INDEX idx_inspection_time (inspection_time),
INDEX idx_quality_grade (quality_grade),
INDEX idx_inspection_result (inspection_result)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='质量检验表'
`);
// 7. 创建系统配置表
console.log('⚙️ 创建系统配置表...');
await sequelize.query(`
CREATE TABLE IF NOT EXISTS system_configs (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '配置ID',
config_key VARCHAR(100) UNIQUE NOT NULL COMMENT '配置键',
config_value TEXT NOT NULL COMMENT '配置值',
config_type ENUM('string', 'number', 'boolean', 'json', 'array') DEFAULT 'string' COMMENT '配置类型',
category VARCHAR(50) NOT NULL COMMENT '配置分类',
description TEXT COMMENT '配置描述',
is_public BOOLEAN DEFAULT FALSE COMMENT '是否公开配置',
is_editable BOOLEAN DEFAULT TRUE COMMENT '是否可编辑',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_config_key (config_key),
INDEX idx_category (category),
INDEX idx_is_public (is_public)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统配置表'
`);
console.log('✅ 表结构更新完成');
} catch (error) {
console.error('❌ 表结构更新失败:', error.message);
throw error;
}
}
/**
* 插入完整测试数据
*/
async function insertCompleteTestData() {
console.log('\n📊 开始插入完整测试数据...');
try {
// 1. 插入管理员和测试用户
console.log('👤 插入用户数据...');
// 管理员用户
const adminPassword = await bcrypt.hash('admin123', 10);
const adminUuid = uuidv4();
await sequelize.query(`
INSERT IGNORE INTO users (
uuid, username, password_hash, openid, nickname, real_name,
user_type, status, registration_source, login_count, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
adminUuid, 'admin', adminPassword, 'admin_' + adminUuid.substring(0, 8),
'系统管理员', '管理员', 'admin', 'active', 'admin_create', 0
]
});
// 测试用户数据
const testUsers = [
{
uuid: uuidv4(),
username: 'buyer001',
password: await bcrypt.hash('123456', 10),
nickname: '采购商张三',
real_name: '张三',
phone: '13800138001',
email: 'buyer001@niumall.com',
user_type: 'buyer',
company_name: '北京牛肉加工厂',
company_address: '北京市朝阳区xxx街道'
},
{
uuid: uuidv4(),
username: 'trader001',
password: await bcrypt.hash('123456', 10),
nickname: '贸易商李四',
real_name: '李四',
phone: '13800138002',
email: 'trader001@niumall.com',
user_type: 'trader',
company_name: '上海牛只贸易有限公司',
company_address: '上海市浦东新区xxx路'
},
{
uuid: uuidv4(),
username: 'supplier001',
password: await bcrypt.hash('123456', 10),
nickname: '供应商王五',
real_name: '王五',
phone: '13800138003',
email: 'supplier001@niumall.com',
user_type: 'supplier',
company_name: '内蒙古草原牧业',
company_address: '内蒙古呼和浩特市'
},
{
uuid: uuidv4(),
username: 'driver001',
password: await bcrypt.hash('123456', 10),
nickname: '司机赵六',
real_name: '赵六',
phone: '13800138004',
email: 'driver001@niumall.com',
user_type: 'driver',
id_card: '110101199001011234'
},
{
uuid: uuidv4(),
username: 'staff001',
password: await bcrypt.hash('123456', 10),
nickname: '员工孙七',
real_name: '孙七',
phone: '13800138005',
email: 'staff001@niumall.com',
user_type: 'staff',
company_name: '牛商城运营中心'
}
];
for (const user of testUsers) {
await sequelize.query(`
INSERT IGNORE INTO users (
uuid, username, password_hash, openid, nickname, real_name, phone, email,
user_type, company_name, company_address, id_card, status,
registration_source, login_count, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
user.uuid, user.username, user.password, user.username + '_openid',
user.nickname, user.real_name, user.phone, user.email, user.user_type,
user.company_name || null, user.company_address || null, user.id_card || null,
'active', 'admin_create', 0
]
});
}
// 2. 插入供应商数据
console.log('🏭 插入供应商数据...');
const suppliers = [
{
name: '内蒙古草原牧业有限公司',
code: 'SUP001',
contact: '赵大牛',
phone: '13900139001',
email: 'sup001@niumall.com',
address: '内蒙古呼和浩特市赛罕区草原路123号',
region: '内蒙古',
qualification_level: 'A',
cattle_types: JSON.stringify(['西门塔尔牛', '安格斯牛', '夏洛莱牛']),
capacity: 500,
rating: 4.8,
cooperation_start_date: '2023-01-01',
bank_account: '6228480402564890018',
bank_name: '农业银行呼和浩特分行',
tax_number: '91150100MA0N2XQJ2K'
},
{
name: '新疆天山畜牧合作社',
code: 'SUP002',
contact: '马小羊',
phone: '13900139002',
email: 'sup002@niumall.com',
address: '新疆乌鲁木齐市天山区畜牧街456号',
region: '新疆',
qualification_level: 'A',
cattle_types: JSON.stringify(['哈萨克牛', '新疆褐牛']),
capacity: 300,
rating: 4.5,
cooperation_start_date: '2023-03-15',
bank_account: '6228480402564890019',
bank_name: '建设银行乌鲁木齐分行',
tax_number: '91650100MA0N2XQJ3L'
},
{
name: '山东鲁西黄牛养殖场',
code: 'SUP003',
contact: '孙大强',
phone: '13900139003',
email: 'sup003@niumall.com',
address: '山东省济南市历城区养殖园区789号',
region: '山东',
qualification_level: 'B',
cattle_types: JSON.stringify(['鲁西黄牛', '利木赞牛']),
capacity: 200,
rating: 4.2,
cooperation_start_date: '2023-06-01',
bank_account: '6228480402564890020',
bank_name: '工商银行济南分行',
tax_number: '91370100MA0N2XQJ4M'
},
{
name: '四川成都优质牧场',
code: 'SUP004',
contact: '李小川',
phone: '13900139004',
email: 'sup004@niumall.com',
address: '四川省成都市双流区牧场路101号',
region: '四川',
qualification_level: 'B',
cattle_types: JSON.stringify(['西门塔尔牛', '本地黄牛']),
capacity: 150,
rating: 4.0,
cooperation_start_date: '2023-08-01',
bank_account: '6228480402564890021',
bank_name: '中国银行成都分行',
tax_number: '91510100MA0N2XQJ5N'
},
{
name: '河北承德绿色牧业',
code: 'SUP005',
contact: '张承德',
phone: '13900139005',
email: 'sup005@niumall.com',
address: '河北省承德市双桥区绿色牧场街202号',
region: '河北',
qualification_level: 'C',
cattle_types: JSON.stringify(['夏洛莱牛', '安格斯牛']),
capacity: 100,
rating: 3.8,
cooperation_start_date: '2023-09-15',
bank_account: '6228480402564890022',
bank_name: '交通银行承德分行',
tax_number: '91130800MA0N2XQJ6O'
}
];
for (const supplier of suppliers) {
await sequelize.query(`
INSERT IGNORE INTO suppliers (
name, code, contact, phone, email, address, region, qualification_level,
cattle_types, capacity, rating, cooperation_start_date, status,
bank_account, bank_name, tax_number, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
supplier.name, supplier.code, supplier.contact, supplier.phone, supplier.email,
supplier.address, supplier.region, supplier.qualification_level, supplier.cattle_types,
supplier.capacity, supplier.rating, supplier.cooperation_start_date, 'active',
supplier.bank_account, supplier.bank_name, supplier.tax_number
]
});
}
// 3. 插入订单数据
console.log('📋 插入订单数据...');
// 获取用户和供应商ID
const [buyers] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'buyer' LIMIT 1");
const [traders] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'trader' LIMIT 1");
const [supplierList] = await sequelize.query("SELECT id, name FROM suppliers LIMIT 3");
if (buyers.length > 0 && supplierList.length > 0) {
const orders = [
{
order_no: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '001',
client_id: buyers[0].id,
trader_id: traders.length > 0 ? traders[0].id : null,
supplier_id: supplierList[0].id,
cattle_type: '西门塔尔牛',
quantity: 50,
weight_range: '450-550kg',
estimated_weight: 25000.00,
unit_price: 32.50,
price_type: 'per_kg',
total_amount: 812500.00,
prepaid_amount: 200000.00,
pickup_address: '内蒙古呼和浩特市赛罕区草原路123号',
delivery_address: '北京市朝阳区屠宰场',
delivery_time: '2024-02-15 08:00:00',
status: 'confirmed',
special_requirements: '要求健康证明齐全质量等级A级',
quality_standards: JSON.stringify({
min_weight: 450,
max_weight: 550,
health_grade: 'A',
age_range: '18-24个月'
})
},
{
order_no: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '002',
client_id: buyers[0].id,
supplier_id: supplierList.length > 1 ? supplierList[1].id : supplierList[0].id,
cattle_type: '安格斯牛',
quantity: 30,
weight_range: '500-600kg',
estimated_weight: 16500.00,
unit_price: 35.00,
price_type: 'per_kg',
total_amount: 577500.00,
prepaid_amount: 150000.00,
pickup_address: '新疆乌鲁木齐市天山区畜牧街456号',
delivery_address: '上海市浦东新区加工厂',
delivery_time: '2024-02-20 10:00:00',
status: 'pending',
special_requirements: '需要冷链运输重量范围500-600kg',
quality_standards: JSON.stringify({
min_weight: 500,
max_weight: 600,
health_grade: 'A',
age_range: '20-26个月'
})
},
{
order_no: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '003',
client_id: buyers[0].id,
supplier_id: supplierList.length > 2 ? supplierList[2].id : supplierList[0].id,
cattle_type: '鲁西黄牛',
quantity: 20,
weight_range: '400-500kg',
estimated_weight: 9000.00,
unit_price: 30.00,
price_type: 'per_kg',
total_amount: 270000.00,
prepaid_amount: 80000.00,
pickup_address: '山东省济南市历城区养殖园区789号',
delivery_address: '天津市滨海新区肉类加工园',
delivery_time: '2024-02-25 14:00:00',
status: 'draft',
special_requirements: '本地优质黄牛,肉质鲜美',
quality_standards: JSON.stringify({
min_weight: 400,
max_weight: 500,
health_grade: 'B+',
age_range: '16-22个月'
})
}
];
for (const order of orders) {
await sequelize.query(`
INSERT IGNORE INTO orders (
order_no, client_id, trader_id, supplier_id, cattle_type, quantity,
weight_range, estimated_weight, unit_price, price_type, total_amount, prepaid_amount,
pickup_address, delivery_address, delivery_time, status, special_requirements,
quality_standards, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
order.order_no, order.client_id, order.trader_id, order.supplier_id,
order.cattle_type, order.quantity, order.weight_range, order.estimated_weight,
order.unit_price, order.price_type, order.total_amount, order.prepaid_amount,
order.pickup_address, order.delivery_address, order.delivery_time,
order.status, order.special_requirements, order.quality_standards
]
});
}
}
// 4. 插入支付记录
console.log('💰 插入支付记录...');
const [orderList] = await sequelize.query("SELECT id, order_no, client_id, prepaid_amount FROM orders WHERE prepaid_amount > 0 LIMIT 2");
for (const order of orderList) {
const paymentNo = 'PAY' + Date.now() + Math.floor(Math.random() * 1000);
await sequelize.query(`
INSERT IGNORE INTO payments (
payment_no, order_id, user_id, amount, paid_amount, payment_method,
payment_channel, status, payment_time, confirmed_time, notes, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
paymentNo, order.id, order.client_id, order.prepaid_amount, order.prepaid_amount,
'bank_transfer', '银行转账', 'success', new Date(), new Date(),
`订单${order.order_no}的预付款支付`
]
});
}
// 5. 插入运输任务
console.log('🚛 插入运输任务...');
const [drivers] = await sequelize.query("SELECT id FROM users WHERE user_type = 'driver' LIMIT 1");
const [confirmedOrders] = await sequelize.query("SELECT id, order_no FROM orders WHERE status = 'confirmed' LIMIT 1");
if (drivers.length > 0 && confirmedOrders.length > 0) {
const taskNo = 'TASK' + Date.now();
await sequelize.query(`
INSERT IGNORE INTO transport_tasks (
task_no, order_id, driver_id, vehicle_no, vehicle_type, vehicle_capacity,
start_location, end_location, planned_distance, planned_start_time, planned_end_time,
status, transport_fee, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
taskNo, confirmedOrders[0].id, drivers[0].id, '蒙A12345', '大型货车', 25.0,
'内蒙古呼和浩特市', '北京市朝阳区', 450.5, '2024-02-14 06:00:00', '2024-02-15 08:00:00',
'assigned', 8000.00
]
});
}
// 6. 插入质量检验记录
console.log('🔍 插入质量检验记录...');
const [staff] = await sequelize.query("SELECT id FROM users WHERE user_type = 'staff' LIMIT 1");
if (staff.length > 0 && confirmedOrders.length > 0) {
const inspectionNo = 'INS' + Date.now();
await sequelize.query(`
INSERT IGNORE INTO quality_inspections (
inspection_no, order_id, inspector_id, inspection_time, inspection_location,
cattle_count, passed_count, failed_count, average_weight, total_weight,
health_status, quality_grade, inspection_result, inspector_notes, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
inspectionNo, confirmedOrders[0].id, staff[0].id, new Date(), '北京市朝阳区检验站',
50, 48, 2, 502.5, 25125.0, 'excellent', 'A', 'passed',
'整体质量优秀2头牛只重量略低于标准但健康状况良好'
]
});
}
// 7. 插入系统配置
console.log('⚙️ 插入系统配置...');
const configs = [
['system.name', '活牛采购智能数字化系统', 'string', 'system', '系统名称'],
['system.version', '1.0.0', 'string', 'system', '系统版本'],
['system.company', '牛商城科技有限公司', 'string', 'system', '公司名称'],
['order.auto_confirm_hours', '24', 'number', 'order', '订单自动确认时间(小时)'],
['order.max_quantity', '1000', 'number', 'order', '单笔订单最大数量'],
['payment.timeout_minutes', '30', 'number', 'payment', '支付超时时间(分钟)'],
['payment.min_prepaid_ratio', '0.2', 'number', 'payment', '最低预付比例'],
['transport.tracking_interval', '300', 'number', 'transport', '位置跟踪间隔(秒)'],
['transport.max_distance', '2000', 'number', 'transport', '最大运输距离(公里)'],
['quality.min_score', '80', 'number', 'quality', '质量检验最低分数'],
['quality.pass_rate_threshold', '0.95', 'number', 'quality', '合格率阈值'],
['notification.sms_enabled', 'true', 'boolean', 'notification', '是否启用短信通知'],
['notification.email_enabled', 'true', 'boolean', 'notification', '是否启用邮件通知'],
['notification.push_enabled', 'true', 'boolean', 'notification', '是否启用推送通知'],
['security.session_timeout', '7200', 'number', 'security', '会话超时时间(秒)'],
['security.max_login_attempts', '5', 'number', 'security', '最大登录尝试次数']
];
for (const [key, value, type, category, description] of configs) {
await sequelize.query(`
INSERT IGNORE INTO system_configs (
config_key, config_value, config_type, category, description,
is_public, is_editable, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [key, value, type, category, description, true, true]
});
}
console.log('✅ 测试数据插入完成');
} catch (error) {
console.error('❌ 插入测试数据失败:', error.message);
throw error;
}
}
/**
* 验证数据完整性
*/
async function validateDatabase() {
console.log('\n🔍 验证数据库完整性...');
try {
const tables = [
'users', 'suppliers', 'orders', 'payments',
'transport_tasks', 'quality_inspections', 'system_configs'
];
console.log('📊 数据统计:');
for (const table of tables) {
try {
const [result] = await sequelize.query(`SELECT COUNT(*) as count FROM ${table}`);
console.log(` ${table}: ${result[0].count} 条记录`);
} catch (error) {
console.log(` ${table}: 表不存在或查询失败`);
}
}
// 检查关键数据
const [adminUsers] = await sequelize.query(
"SELECT id, username, nickname FROM users WHERE user_type = 'admin'"
);
console.log('\n👤 管理员用户:');
adminUsers.forEach(user => {
console.log(` - ID: ${user.id}, 用户名: ${user.username}, 昵称: ${user.nickname}`);
});
const [supplierStats] = await sequelize.query(`
SELECT qualification_level, COUNT(*) as count
FROM suppliers
GROUP BY qualification_level
ORDER BY qualification_level
`);
console.log('\n🏭 供应商等级分布:');
supplierStats.forEach(stat => {
console.log(` - 等级${stat.qualification_level}: ${stat.count}`);
});
const [orderStats] = await sequelize.query(`
SELECT status, COUNT(*) as count
FROM orders
GROUP BY status
ORDER BY status
`);
console.log('\n📋 订单状态分布:');
orderStats.forEach(stat => {
console.log(` - ${stat.status}: ${stat.count}`);
});
} catch (error) {
console.error('❌ 数据验证失败:', error.message);
}
}
/**
* 主函数
*/
async function main() {
try {
console.log('\n🚀 ===== 远程MySQL数据库完整设置开始 =====');
// 1. 测试连接
console.log('\n📡 连接远程MySQL数据库...');
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
console.log(`📍 连接信息: ${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`);
// 2. 更新表结构
await updateTableStructures();
// 3. 插入测试数据
await insertCompleteTestData();
// 4. 验证数据
await validateDatabase();
console.log('\n🎉 ===== 数据库设置完成 =====');
console.log('\n📋 系统信息:');
console.log('🌐 后端服务: http://localhost:4330');
console.log('🎨 管理后台: http://localhost:3000');
console.log('👤 管理员账户: admin / admin123');
console.log('📚 API文档: http://localhost:4330/api-docs');
console.log('💓 健康检查: http://localhost:4330/health');
console.log('\n🔑 测试账户:');
console.log(' 采购商: buyer001 / 123456');
console.log(' 贸易商: trader001 / 123456');
console.log(' 供应商: supplier001 / 123456');
console.log(' 司机: driver001 / 123456');
console.log(' 员工: staff001 / 123456');
console.log('\n📈 数据概览:');
console.log(' - 5个不同类型的测试用户');
console.log(' - 5家不同等级的供应商');
console.log(' - 3个不同状态的订单');
console.log(' - 完整的支付、运输、质检记录');
console.log(' - 16项系统配置参数');
} catch (error) {
console.error('\n❌ 数据库设置失败:', error);
} finally {
await sequelize.close();
console.log('\n🔌 数据库连接已关闭');
}
}
// 运行脚本
if (require.main === module) {
main();
}
module.exports = { main };

View File

@@ -0,0 +1,329 @@
/**
* 使用正确枚举值的数据插入脚本
*/
require('dotenv').config();
const { Sequelize } = require('sequelize');
const bcrypt = require('bcrypt');
const { v4: uuidv4 } = require('uuid');
const sequelize = new Sequelize(
process.env.DB_NAME || 'niumall',
process.env.DB_USERNAME || 'jiebanke',
process.env.DB_PASSWORD || 'aiot741$12346',
{
host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
port: process.env.DB_PORT || 20784,
dialect: 'mysql',
logging: (msg) => console.log(`[SQL] ${msg}`),
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
}
);
/**
* 插入正确的测试数据
*/
async function insertCorrectData() {
console.log('\n📊 开始插入正确的测试数据...');
try {
// 1. 插入供应商数据
console.log('🏭 插入供应商数据...');
const suppliers = [
{
name: '内蒙古草原牧业有限公司',
code: 'SUP001',
contact: '赵大牛',
phone: '15900159001',
email: 'sup001@niumall.com',
address: '内蒙古呼和浩特市赛罕区草原路123号',
region: '内蒙古',
qualification_level: 'A',
cattle_types: JSON.stringify(['西门塔尔牛', '安格斯牛', '夏洛莱牛']),
capacity: 500,
rating: 4.8,
cooperation_start_date: '2023-01-01'
},
{
name: '新疆天山畜牧合作社',
code: 'SUP002',
contact: '马小羊',
phone: '15900159002',
email: 'sup002@niumall.com',
address: '新疆乌鲁木齐市天山区畜牧街456号',
region: '新疆',
qualification_level: 'A',
cattle_types: JSON.stringify(['哈萨克牛', '新疆褐牛']),
capacity: 300,
rating: 4.5,
cooperation_start_date: '2023-03-15'
},
{
name: '山东鲁西黄牛养殖场',
code: 'SUP003',
contact: '孙大强',
phone: '15900159003',
email: 'sup003@niumall.com',
address: '山东省济南市历城区养殖园区789号',
region: '山东',
qualification_level: 'B',
cattle_types: JSON.stringify(['鲁西黄牛', '利木赞牛']),
capacity: 200,
rating: 4.2,
cooperation_start_date: '2023-06-01'
}
];
for (const supplier of suppliers) {
const [existing] = await sequelize.query(
"SELECT id FROM suppliers WHERE code = ?",
{ replacements: [supplier.code] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO suppliers (
name, code, contact, phone, email, address, region, qualification_level,
cattle_types, capacity, rating, cooperation_start_date, status, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
supplier.name, supplier.code, supplier.contact, supplier.phone, supplier.email,
supplier.address, supplier.region, supplier.qualification_level, supplier.cattle_types,
supplier.capacity, supplier.rating, supplier.cooperation_start_date, 'active'
]
});
console.log(`✅ 供应商 ${supplier.code} 创建成功`);
} else {
console.log(`✅ 供应商 ${supplier.code} 已存在`);
}
}
// 2. 插入订单数据(使用正确的枚举值)
console.log('📋 插入订单数据...');
// 获取用户和供应商ID
const [buyers] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'buyer' LIMIT 1");
const [traders] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'trader' LIMIT 1");
const [supplierList] = await sequelize.query("SELECT id, name FROM suppliers WHERE code LIKE 'SUP%' LIMIT 3");
if (buyers.length > 0 && supplierList.length > 0) {
const orders = [
{
orderNo: 'ORD202509001',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList[0].id,
supplierName: supplierList[0].name,
traderId: traders.length > 0 ? traders[0].id : null,
traderName: traders.length > 0 ? traders[0].nickname : null,
cattleBreed: '西门塔尔牛',
cattleCount: 50,
expectedWeight: 25000.00,
unitPrice: 32.50,
totalAmount: 812500.00,
deliveryAddress: '北京市朝阳区屠宰场',
deliveryDate: '2024-02-15',
paymentMethod: 'bank_transfer',
paymentStatus: 'partial_paid',
orderStatus: 'confirmed',
notes: '要求健康证明齐全质量等级A级重量范围450-550kg'
},
{
orderNo: 'ORD202509002',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList.length > 1 ? supplierList[1].id : supplierList[0].id,
supplierName: supplierList.length > 1 ? supplierList[1].name : supplierList[0].name,
traderId: null,
traderName: null,
cattleBreed: '安格斯牛',
cattleCount: 30,
expectedWeight: 16500.00,
unitPrice: 35.00,
totalAmount: 577500.00,
deliveryAddress: '上海市浦东新区加工厂',
deliveryDate: '2024-02-20',
paymentMethod: 'online_payment',
paymentStatus: 'unpaid',
orderStatus: 'pending',
notes: '需要冷链运输重量范围500-600kg'
},
{
orderNo: 'ORD202509003',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList.length > 2 ? supplierList[2].id : supplierList[0].id,
supplierName: supplierList.length > 2 ? supplierList[2].name : supplierList[0].name,
traderId: null,
traderName: null,
cattleBreed: '鲁西黄牛',
cattleCount: 20,
expectedWeight: 9000.00,
unitPrice: 30.00,
totalAmount: 270000.00,
deliveryAddress: '天津市滨海新区肉类加工园',
deliveryDate: '2024-02-25',
paymentMethod: 'cash',
paymentStatus: 'paid',
orderStatus: 'in_production',
notes: '本地优质黄牛肉质鲜美重量范围400-500kg'
}
];
for (const order of orders) {
const [existing] = await sequelize.query(
"SELECT id FROM orders WHERE orderNo = ?",
{ replacements: [order.orderNo] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO orders (
orderNo, buyerId, buyerName, supplierId, supplierName, traderId, traderName,
cattleBreed, cattleCount, expectedWeight, unitPrice, totalAmount,
deliveryAddress, deliveryDate, paymentMethod, paymentStatus, orderStatus, notes,
created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
order.orderNo, order.buyerId, order.buyerName, order.supplierId, order.supplierName,
order.traderId, order.traderName, order.cattleBreed, order.cattleCount,
order.expectedWeight, order.unitPrice, order.totalAmount,
order.deliveryAddress, order.deliveryDate, order.paymentMethod,
order.paymentStatus, order.orderStatus, order.notes
]
});
console.log(`✅ 订单 ${order.orderNo} 创建成功`);
} else {
console.log(`✅ 订单 ${order.orderNo} 已存在`);
}
}
}
console.log('✅ 正确数据插入完成');
} catch (error) {
console.error('❌ 插入数据失败:', error.message);
throw error;
}
}
/**
* 验证数据完整性
*/
async function validateCorrectData() {
console.log('\n🔍 验证数据完整性...');
try {
// 统计数据
const [userCount] = await sequelize.query("SELECT COUNT(*) as count FROM users");
const [supplierCount] = await sequelize.query("SELECT COUNT(*) as count FROM suppliers");
const [orderCount] = await sequelize.query("SELECT COUNT(*) as count FROM orders");
console.log('📊 数据统计:');
console.log(` 用户: ${userCount[0].count} 条记录`);
console.log(` 供应商: ${supplierCount[0].count} 条记录`);
console.log(` 订单: ${orderCount[0].count} 条记录`);
// 检查新增供应商
const [newSuppliers] = await sequelize.query(`
SELECT code, name, qualification_level
FROM suppliers
WHERE code LIKE 'SUP%'
ORDER BY code
`);
console.log('\n🏭 新增供应商:');
newSuppliers.forEach(supplier => {
console.log(` - ${supplier.code}: ${supplier.name} (等级${supplier.qualification_level})`);
});
// 检查新增订单
const [newOrders] = await sequelize.query(`
SELECT orderNo, cattleBreed, cattleCount, paymentStatus, orderStatus
FROM orders
WHERE orderNo LIKE 'ORD202509%'
ORDER BY orderNo
`);
console.log('\n📋 新增订单:');
newOrders.forEach(order => {
console.log(` - ${order.orderNo}: ${order.cattleBreed} ${order.cattleCount}头 (支付:${order.paymentStatus}, 状态:${order.orderStatus})`);
});
// 检查管理员用户
const [adminUsers] = await sequelize.query(
"SELECT id, username, nickname FROM users WHERE user_type = 'admin'"
);
console.log('\n👤 管理员用户:');
adminUsers.forEach(user => {
console.log(` - ID: ${user.id}, 用户名: ${user.username}, 昵称: ${user.nickname}`);
});
} catch (error) {
console.error('❌ 数据验证失败:', error.message);
}
}
/**
* 主函数
*/
async function main() {
try {
console.log('\n🚀 ===== 正确数据插入开始 =====');
// 1. 测试连接
console.log('\n📡 连接远程MySQL数据库...');
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
console.log(`📍 连接信息: ${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`);
// 2. 插入正确数据
await insertCorrectData();
// 3. 验证数据
await validateCorrectData();
console.log('\n🎉 ===== 数据插入完成 =====');
console.log('\n📋 系统信息:');
console.log('🌐 后端服务: http://localhost:4330');
console.log('🎨 管理后台: http://localhost:3000');
console.log('👤 管理员账户: admin / admin123');
console.log('📚 API文档: http://localhost:4330/api-docs');
console.log('💓 健康检查: http://localhost:4330/health');
console.log('\n🔑 测试账户:');
console.log(' 采购商: buyer001 / 123456');
console.log(' 贸易商: trader001 / 123456');
console.log(' 供应商: supplier001 / 123456');
console.log(' 司机: driver001 / 123456');
console.log(' 员工: staff001 / 123456');
console.log('\n📈 数据概览:');
console.log(' - 3家不同等级的供应商 (A级2家, B级1家)');
console.log(' - 3个不同状态的订单 (待处理、已确认、生产中)');
console.log(' - 3种支付方式 (银行转账、在线支付、现金)');
console.log(' - 3种支付状态 (未支付、部分支付、已支付)');
console.log(' - 完全符合数据库表结构和约束');
} catch (error) {
console.error('\n❌ 数据插入失败:', error);
} finally {
await sequelize.close();
console.log('\n🔌 数据库连接已关闭');
}
}
// 运行脚本
if (require.main === module) {
main();
}
module.exports = { main };

View File

@@ -0,0 +1,345 @@
/**
* 最终版本 - 完全兼容现有表结构的数据插入脚本
*/
require('dotenv').config();
const { Sequelize } = require('sequelize');
const bcrypt = require('bcrypt');
const { v4: uuidv4 } = require('uuid');
// 使用.env文件中的配置
const sequelize = new Sequelize(
process.env.DB_NAME || 'niumall',
process.env.DB_USERNAME || 'jiebanke',
process.env.DB_PASSWORD || 'aiot741$12346',
{
host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
port: process.env.DB_PORT || 20784,
dialect: 'mysql',
logging: (msg) => console.log(`[SQL] ${msg}`),
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
}
);
/**
* 插入完全兼容的测试数据
*/
async function insertFinalData() {
console.log('\n📊 开始插入最终测试数据...');
try {
// 1. 插入供应商数据(使用正确的字段名)
console.log('🏭 插入供应商数据...');
const suppliers = [
{
name: '内蒙古草原牧业有限公司',
code: 'SUP001',
contact: '赵大牛',
phone: '15900159001',
email: 'sup001@niumall.com',
address: '内蒙古呼和浩特市赛罕区草原路123号',
region: '内蒙古',
qualification_level: 'A',
cattle_types: JSON.stringify(['西门塔尔牛', '安格斯牛', '夏洛莱牛']),
capacity: 500,
rating: 4.8,
cooperation_start_date: '2023-01-01'
},
{
name: '新疆天山畜牧合作社',
code: 'SUP002',
contact: '马小羊',
phone: '15900159002',
email: 'sup002@niumall.com',
address: '新疆乌鲁木齐市天山区畜牧街456号',
region: '新疆',
qualification_level: 'A',
cattle_types: JSON.stringify(['哈萨克牛', '新疆褐牛']),
capacity: 300,
rating: 4.5,
cooperation_start_date: '2023-03-15'
},
{
name: '山东鲁西黄牛养殖场',
code: 'SUP003',
contact: '孙大强',
phone: '15900159003',
email: 'sup003@niumall.com',
address: '山东省济南市历城区养殖园区789号',
region: '山东',
qualification_level: 'B',
cattle_types: JSON.stringify(['鲁西黄牛', '利木赞牛']),
capacity: 200,
rating: 4.2,
cooperation_start_date: '2023-06-01'
}
];
for (const supplier of suppliers) {
const [existing] = await sequelize.query(
"SELECT id FROM suppliers WHERE code = ?",
{ replacements: [supplier.code] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO suppliers (
name, code, contact, phone, email, address, region, qualification_level,
cattle_types, capacity, rating, cooperation_start_date, status, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
supplier.name, supplier.code, supplier.contact, supplier.phone, supplier.email,
supplier.address, supplier.region, supplier.qualification_level, supplier.cattle_types,
supplier.capacity, supplier.rating, supplier.cooperation_start_date, 'active'
]
});
console.log(`✅ 供应商 ${supplier.code} 创建成功`);
} else {
console.log(`✅ 供应商 ${supplier.code} 已存在`);
}
}
// 2. 插入订单数据(使用正确的字段名)
console.log('📋 插入订单数据...');
// 获取用户和供应商ID
const [buyers] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'buyer' LIMIT 1");
const [traders] = await sequelize.query("SELECT id, nickname FROM users WHERE user_type = 'trader' LIMIT 1");
const [supplierList] = await sequelize.query("SELECT id, name FROM suppliers WHERE code LIKE 'SUP%' LIMIT 3");
if (buyers.length > 0 && supplierList.length > 0) {
const orders = [
{
orderNo: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '001',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList[0].id,
supplierName: supplierList[0].name,
traderId: traders.length > 0 ? traders[0].id : null,
traderName: traders.length > 0 ? traders[0].nickname : null,
cattleBreed: '西门塔尔牛',
cattleCount: 50,
expectedWeight: 25000.00,
unitPrice: 32.50,
totalAmount: 812500.00,
deliveryAddress: '北京市朝阳区屠宰场',
deliveryDate: '2024-02-15 08:00:00',
paymentStatus: 'partial',
orderStatus: 'confirmed',
notes: '要求健康证明齐全质量等级A级重量范围450-550kg'
},
{
orderNo: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '002',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList.length > 1 ? supplierList[1].id : supplierList[0].id,
supplierName: supplierList.length > 1 ? supplierList[1].name : supplierList[0].name,
traderId: null,
traderName: null,
cattleBreed: '安格斯牛',
cattleCount: 30,
expectedWeight: 16500.00,
unitPrice: 35.00,
totalAmount: 577500.00,
deliveryAddress: '上海市浦东新区加工厂',
deliveryDate: '2024-02-20 10:00:00',
paymentStatus: 'pending',
orderStatus: 'pending',
notes: '需要冷链运输重量范围500-600kg'
},
{
orderNo: 'ORD' + new Date().getFullYear() + String(new Date().getMonth() + 1).padStart(2, '0') + '003',
buyerId: buyers[0].id,
buyerName: buyers[0].nickname,
supplierId: supplierList.length > 2 ? supplierList[2].id : supplierList[0].id,
supplierName: supplierList.length > 2 ? supplierList[2].name : supplierList[0].name,
traderId: null,
traderName: null,
cattleBreed: '鲁西黄牛',
cattleCount: 20,
expectedWeight: 9000.00,
unitPrice: 30.00,
totalAmount: 270000.00,
deliveryAddress: '天津市滨海新区肉类加工园',
deliveryDate: '2024-02-25 14:00:00',
paymentStatus: 'pending',
orderStatus: 'pending',
notes: '本地优质黄牛肉质鲜美重量范围400-500kg'
}
];
for (const order of orders) {
const [existing] = await sequelize.query(
"SELECT id FROM orders WHERE orderNo = ?",
{ replacements: [order.orderNo] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO orders (
orderNo, buyerId, buyerName, supplierId, supplierName, traderId, traderName,
cattleBreed, cattleCount, expectedWeight, unitPrice, totalAmount,
deliveryAddress, deliveryDate, paymentStatus, orderStatus, notes,
created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [
order.orderNo, order.buyerId, order.buyerName, order.supplierId, order.supplierName,
order.traderId, order.traderName, order.cattleBreed, order.cattleCount,
order.expectedWeight, order.unitPrice, order.totalAmount,
order.deliveryAddress, order.deliveryDate, order.paymentStatus, order.orderStatus, order.notes
]
});
console.log(`✅ 订单 ${order.orderNo} 创建成功`);
} else {
console.log(`✅ 订单 ${order.orderNo} 已存在`);
}
}
}
// 3. 插入系统配置(如果表存在)
console.log('⚙️ 插入系统配置...');
try {
const configs = [
['system.name', '活牛采购智能数字化系统', 'string', 'system', '系统名称'],
['system.version', '1.0.0', 'string', 'system', '系统版本'],
['order.auto_confirm_hours', '24', 'number', 'order', '订单自动确认时间(小时)'],
['payment.timeout_minutes', '30', 'number', 'payment', '支付超时时间(分钟)'],
['transport.tracking_interval', '300', 'number', 'transport', '位置跟踪间隔(秒)']
];
for (const [key, value, type, category, description] of configs) {
const [existing] = await sequelize.query(
"SELECT id FROM system_configs WHERE config_key = ?",
{ replacements: [key] }
);
if (existing.length === 0) {
await sequelize.query(`
INSERT INTO system_configs (
config_key, config_value, config_type, category, description,
is_public, is_editable, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`, {
replacements: [key, value, type, category, description, true, true]
});
console.log(`✅ 配置 ${key} 创建成功`);
} else {
console.log(`✅ 配置 ${key} 已存在`);
}
}
} catch (error) {
console.log('⚠️ 系统配置表不存在,跳过配置插入');
}
console.log('✅ 最终数据插入完成');
} catch (error) {
console.error('❌ 插入数据失败:', error.message);
throw error;
}
}
/**
* 验证数据完整性
*/
async function validateFinalData() {
console.log('\n🔍 验证最终数据完整性...');
try {
const tables = ['users', 'suppliers', 'orders'];
console.log('📊 数据统计:');
for (const table of tables) {
try {
const [result] = await sequelize.query(`SELECT COUNT(*) as count FROM ${table}`);
console.log(` ${table}: ${result[0].count} 条记录`);
} catch (error) {
console.log(` ${table}: 表不存在或查询失败`);
}
}
// 检查新增供应商
const [newSuppliers] = await sequelize.query(`
SELECT code, name, qualification_level
FROM suppliers
WHERE code LIKE 'SUP%'
ORDER BY code
`);
console.log('\n🏭 新增供应商:');
newSuppliers.forEach(supplier => {
console.log(` - ${supplier.code}: ${supplier.name} (等级${supplier.qualification_level})`);
});
// 检查新增订单
const [newOrders] = await sequelize.query(`
SELECT orderNo, cattleBreed, cattleCount, orderStatus
FROM orders
WHERE orderNo LIKE 'ORD2024%'
ORDER BY orderNo
`);
console.log('\n📋 新增订单:');
newOrders.forEach(order => {
console.log(` - ${order.orderNo}: ${order.cattleBreed} ${order.cattleCount}头 (${order.orderStatus})`);
});
} catch (error) {
console.error('❌ 数据验证失败:', error.message);
}
}
/**
* 主函数
*/
async function main() {
try {
console.log('\n🚀 ===== 最终数据插入开始 =====');
// 1. 测试连接
console.log('\n📡 连接远程MySQL数据库...');
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
console.log(`📍 连接信息: ${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`);
// 2. 插入最终数据
await insertFinalData();
// 3. 验证数据
await validateFinalData();
console.log('\n🎉 ===== 数据插入完成 =====');
console.log('\n📋 系统信息:');
console.log('🌐 后端服务: http://localhost:4330');
console.log('🎨 管理后台: http://localhost:3000');
console.log('👤 管理员账户: admin / admin123');
console.log('📚 API文档: http://localhost:4330/api-docs');
console.log('💓 健康检查: http://localhost:4330/health');
console.log('\n📈 数据概览:');
console.log(' - 3家不同等级的供应商');
console.log(' - 3个不同状态的订单');
console.log(' - 5项系统配置参数');
console.log(' - 完全兼容现有表结构');
} catch (error) {
console.error('\n❌ 数据插入失败:', error);
} finally {
await sequelize.close();
console.log('\n🔌 数据库连接已关闭');
}
}
// 运行脚本
if (require.main === module) {
main();
}
module.exports = { main };