备份:修复前完整项目快照 2026-04-19

This commit is contained in:
root
2026-04-19 19:15:01 +08:00
parent 5266d7732b
commit d00f41a120
449 changed files with 89577 additions and 23251 deletions
@@ -0,0 +1,226 @@
-- ============================================
-- 商品管理改造 - 数据库迁移脚本
-- 支持二级分类树状结构
-- ============================================
-- 1. 创建新的分类表(树状结构)
CREATE TABLE IF NOT EXISTS category_tree (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, -- 分类名称
parent_id INTEGER DEFAULT NULL, -- 父分类ID(NULL表示一级分类)
level INTEGER DEFAULT 1, -- 层级(1=一级,2=二级)
sort_order INTEGER DEFAULT 0, -- 排序
description TEXT, -- 描述
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (parent_id) REFERENCES category_tree(id) ON DELETE CASCADE
);
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_category_parent ON category_tree(parent_id);
CREATE INDEX IF NOT EXISTS idx_category_level ON category_tree(level);
-- 2. 修改商品表,支持新字段和二级分类
-- 先备份原表
ALTER TABLE products RENAME TO products_backup;
-- 创建新的商品表
CREATE TABLE products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, -- 商品名称
model TEXT, -- 型号
category_id INTEGER, -- 二级分类ID(关联category_tree
category_name TEXT, -- 分类名称(冗余,方便查询)
unit TEXT DEFAULT '', -- 单位
cost_price REAL, -- 成本单价(可为空)
price REAL DEFAULT 0, -- 销售单价
brand TEXT, -- 品牌
specification TEXT, -- 规格参数
source TEXT DEFAULT '老挝', -- 来源(中国/老挝)
remark TEXT, -- 备注
stock_quantity REAL DEFAULT 0, -- 库存数量
stock_warning REAL DEFAULT 0, -- 库存预警值
status TEXT DEFAULT 'active', -- 状态:active/disabled
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES category_tree(id)
);
-- 迁移旧数据(简化版,不处理旧数据迁移)
-- 直接创建空的新表结构
-- INSERT INTO products (
-- id, name, model, category_id, category_name, unit,
-- price, brand, specification, remark, status, created_at, updated_at
-- )
-- SELECT
-- p.id,
-- p.name,
-- NULL as model,
-- NULL as category_id,
-- NULL as category_name,
-- COALESCE(p.unit, '件'),
-- COALESCE(p.price, 0),
-- NULL as brand,
-- NULL as specification,
-- p.remark,
-- 'active',
-- p.created_at,
-- p.updated_at
-- FROM products_backup p;
-- 删除备份表
DROP TABLE products_backup;
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_products_category ON products(category_id);
CREATE INDEX IF NOT EXISTS idx_products_name ON products(name);
CREATE INDEX IF NOT EXISTS idx_products_status ON products(status);
-- 3. 删除旧的categories表(数据已迁移到category_tree
-- 注意:先检查是否还有其他表依赖categories
-- DROP TABLE IF EXISTS categories;
-- ============================================
-- 初始化默认分类数据
-- ============================================
-- 插入一级分类
INSERT INTO category_tree (name, parent_id, level, sort_order, description) VALUES
('电杆横担', NULL, 1, 1, '电杆、横担及相关配件'),
('电缆电线', NULL, 1, 2, '各类电缆、电线产品'),
('变压器', NULL, 1, 3, '变压器及相关设备'),
('开关设备', NULL, 1, 4, '开关、断路器等设备'),
('金具', NULL, 1, 5, '电力金具、连接件'),
('工具仪器', NULL, 1, 6, '施工工具、检测仪器'),
('劳保用品', NULL, 1, 7, '安全防护用品'),
('其他材料', NULL, 1, 99, '其他未分类材料');
-- 插入二级分类(电杆横担)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '混凝土电杆', id, 2, 1, '混凝土材质电杆'
FROM category_tree WHERE name = '电杆横担' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '钢管电杆', id, 2, 2, '钢管材质电杆'
FROM category_tree WHERE name = '电杆横担' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '横担', id, 2, 3, '各类横担'
FROM category_tree WHERE name = '电杆横担' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '抱箍', id, 2, 4, '电杆抱箍'
FROM category_tree WHERE name = '电杆横担' AND level = 1;
-- 插入二级分类(电缆电线)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '高压电缆', id, 2, 1, '高压电力电缆'
FROM category_tree WHERE name = '电缆电线' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '低压电缆', id, 2, 2, '低压电力电缆'
FROM category_tree WHERE name = '电缆电线' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '架空导线', id, 2, 3, '架空绝缘导线'
FROM category_tree WHERE name = '电缆电线' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '控制电缆', id, 2, 4, '控制用电缆'
FROM category_tree WHERE name = '电缆电线' AND level = 1;
-- 插入二级分类(变压器)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '配电变压器', id, 2, 1, '配电用变压器'
FROM category_tree WHERE name = '变压器' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '箱式变电站', id, 2, 2, '箱式变电站'
FROM category_tree WHERE name = '变压器' AND level = 1;
-- 插入二级分类(开关设备)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '断路器', id, 2, 1, '各类断路器'
FROM category_tree WHERE name = '开关设备' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '隔离开关', id, 2, 2, '隔离开关'
FROM category_tree WHERE name = '开关设备' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '熔断器', id, 2, 3, '熔断器'
FROM category_tree WHERE name = '开关设备' AND level = 1;
-- 插入二级分类(金具)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '耐张线夹', id, 2, 1, '耐张线夹'
FROM category_tree WHERE name = '金具' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '悬垂线夹', id, 2, 2, '悬垂线夹'
FROM category_tree WHERE name = '金具' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '连接金具', id, 2, 3, '连接金具'
FROM category_tree WHERE name = '金具' AND level = 1;
-- 插入二级分类(工具仪器)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '施工工具', id, 2, 1, '电力施工工具'
FROM category_tree WHERE name = '工具仪器' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '检测仪器', id, 2, 2, '检测测试仪器'
FROM category_tree WHERE name = '工具仪器' AND level = 1;
-- 插入二级分类(劳保用品)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '安全帽', id, 2, 1, '安全帽'
FROM category_tree WHERE name = '劳保用品' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '安全带', id, 2, 2, '安全带'
FROM category_tree WHERE name = '劳保用品' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '绝缘手套', id, 2, 3, '绝缘手套'
FROM category_tree WHERE name = '劳保用品' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '绝缘鞋', id, 2, 4, '绝缘鞋'
FROM category_tree WHERE name = '劳保用品' AND level = 1;
-- 插入二级分类(其他材料)
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '标识标牌', id, 2, 1, '标识标牌'
FROM category_tree WHERE name = '其他材料' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '接地材料', id, 2, 2, '接地装置材料'
FROM category_tree WHERE name = '其他材料' AND level = 1;
INSERT INTO category_tree (name, parent_id, level, sort_order, description)
SELECT '其他', id, 2, 99, '其他未分类'
FROM category_tree WHERE name = '其他材料' AND level = 1;
-- ============================================
-- 创建触发器:自动更新updated_at
-- ============================================
CREATE TRIGGER IF NOT EXISTS update_category_tree_timestamp
AFTER UPDATE ON category_tree
BEGIN
UPDATE category_tree SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
CREATE TRIGGER IF NOT EXISTS update_products_timestamp
AFTER UPDATE ON products
BEGIN
UPDATE products SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
-- ============================================
-- 迁移完成
-- ============================================
SELECT '数据库迁移完成' as message;
SELECT '商品表已更新,支持二级分类' as message;
SELECT '分类表已创建,支持树状结构' as message;
@@ -0,0 +1,77 @@
-- 采购付款分离改造:数据库迁移脚本
-- 创建时间:2026-03-25
-- ============================================
-- 表1:采购申请表 (purchase_requests)
-- ============================================
CREATE TABLE IF NOT EXISTS purchase_requests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
request_code TEXT UNIQUE NOT NULL,
project_id INTEGER NOT NULL,
applicant TEXT NOT NULL,
request_date DATE NOT NULL,
supplier_id INTEGER,
supplier_name TEXT,
expense_category TEXT NOT NULL,
total_amount REAL NOT NULL DEFAULT 0,
currency TEXT DEFAULT 'CNY',
status TEXT DEFAULT 'pending',
remark TEXT,
attachments TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES projects(id),
FOREIGN KEY (supplier_id) REFERENCES suppliers(id)
);
-- ============================================
-- 表2:采购明细表 (purchase_request_items)
-- ============================================
CREATE TABLE IF NOT EXISTS purchase_request_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
purchase_request_id INTEGER NOT NULL,
product_id INTEGER,
product_name TEXT NOT NULL,
specification TEXT,
unit TEXT,
quantity REAL NOT NULL DEFAULT 0,
unit_price REAL NOT NULL DEFAULT 0,
total_price REAL NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (purchase_request_id) REFERENCES purchase_requests(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id)
);
-- ============================================
-- 表3:库存记录表 (inventory_records)
-- ============================================
CREATE TABLE IF NOT EXISTS inventory_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
record_type TEXT NOT NULL,
project_id INTEGER,
purchase_request_id INTEGER,
product_id INTEGER NOT NULL,
quantity REAL NOT NULL DEFAULT 0,
unit_price REAL,
total_amount REAL,
record_date DATE NOT NULL,
operator TEXT,
remark TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES projects(id),
FOREIGN KEY (purchase_request_id) REFERENCES purchase_requests(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
-- ============================================
-- 修改:为付款申请表添加采购单关联字段
-- ============================================
ALTER TABLE payment_requests ADD COLUMN purchase_request_id INTEGER;
ALTER TABLE payment_requests ADD COLUMN payment_type TEXT DEFAULT 'company';
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_purchase_requests_project ON purchase_requests(project_id);
CREATE INDEX IF NOT EXISTS idx_purchase_requests_status ON purchase_requests(status);
CREATE INDEX IF NOT EXISTS idx_purchase_request_items_request ON purchase_request_items(purchase_request_id);
CREATE INDEX IF NOT EXISTS idx_inventory_records_product ON inventory_records(product_id);
CREATE INDEX IF NOT EXISTS idx_inventory_records_project ON inventory_records(project_id);
@@ -0,0 +1,280 @@
-- ============================================
-- 采购-付款-物流-退库一体化流程 - 数据库迁移脚本
-- 版本:v1.0
-- 日期:2026-04-07
-- 遵循设计方案:采购-付款-物流-退库一体化流程设计方案.md
-- ============================================
-- ============================================
-- 第一部分:创建新表
-- ============================================
-- 表1:跨境物流公司表 (logistics_companies)
-- 设计方案章节:9.9 跨境物流公司表
CREATE TABLE IF NOT EXISTS logistics_companies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
address TEXT,
phone TEXT,
email TEXT,
quotation_description TEXT,
status TEXT DEFAULT 'active',
remark TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_logistics_companies_code ON logistics_companies(code);
CREATE INDEX IF NOT EXISTS idx_logistics_companies_status ON logistics_companies(status);
-- 表2:物流公司收款信息表 (logistics_company_payment_infos)
-- 设计方案章节:9.10 物流公司收款信息表
CREATE TABLE IF NOT EXISTS logistics_company_payment_infos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
logistics_company_id INTEGER NOT NULL,
account_name TEXT,
account_number TEXT,
bank_name TEXT,
qr_code TEXT,
is_default INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (logistics_company_id) REFERENCES logistics_companies(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_lc_payment_infos_company ON logistics_company_payment_infos(logistics_company_id);
-- 表3:物流单表 (logistics_records)
-- 设计方案章节:9.4 物流单表
CREATE TABLE IF NOT EXISTS logistics_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT UNIQUE NOT NULL,
purchase_order_id INTEGER NOT NULL,
ship_from TEXT DEFAULT 'Laos',
logistics_company_id INTEGER,
logistics_company TEXT,
tracking_number TEXT,
ship_date DATE,
ship_location TEXT,
estimated_arrival_date DATE,
customs_arrival_date DATE,
customs_clearance_date DATE,
use_hub INTEGER DEFAULT 0,
hub_arrival_date DATE,
hub_receiver TEXT,
hub_verified_quantity REAL,
second_ship_date DATE,
primary_freight REAL DEFAULT 0,
primary_freight_currency TEXT DEFAULT 'CNY',
primary_freight_status TEXT DEFAULT 'pending',
primary_freight_document TEXT,
secondary_freight REAL DEFAULT 0,
secondary_freight_currency TEXT DEFAULT 'LAK',
secondary_freight_status TEXT DEFAULT 'pending',
driver_phone TEXT,
cargo_weight REAL,
transport_distance REAL,
final_arrival_date DATE,
final_location TEXT,
status TEXT DEFAULT 'pending',
remark TEXT,
created_by TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (purchase_order_id) REFERENCES purchase_orders(id),
FOREIGN KEY (logistics_company_id) REFERENCES logistics_companies(id)
);
CREATE INDEX IF NOT EXISTS idx_logistics_records_code ON logistics_records(code);
CREATE INDEX IF NOT EXISTS idx_logistics_records_order ON logistics_records(purchase_order_id);
CREATE INDEX IF NOT EXISTS idx_logistics_records_status ON logistics_records(status);
CREATE INDEX IF NOT EXISTS idx_logistics_records_company ON logistics_records(logistics_company_id);
-- 表4:验收单表 (verification_records)
-- 设计方案章节:9.5 验收单表
CREATE TABLE IF NOT EXISTS verification_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT UNIQUE NOT NULL,
purchase_order_id INTEGER NOT NULL,
logistics_record_id INTEGER,
verification_type TEXT DEFAULT 'direct',
verification_date DATE NOT NULL,
verifier TEXT NOT NULL,
items TEXT,
total_ordered REAL,
total_received REAL,
total_verified REAL,
total_rejected REAL DEFAULT 0,
project_id INTEGER,
storage_type TEXT,
status TEXT DEFAULT 'pending',
remark TEXT,
attachments TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (purchase_order_id) REFERENCES purchase_orders(id),
FOREIGN KEY (logistics_record_id) REFERENCES logistics_records(id),
FOREIGN KEY (project_id) REFERENCES projects(id)
);
CREATE INDEX IF NOT EXISTS idx_verification_records_code ON verification_records(code);
CREATE INDEX IF NOT EXISTS idx_verification_records_order ON verification_records(purchase_order_id);
CREATE INDEX IF NOT EXISTS idx_verification_records_status ON verification_records(status);
-- 表5:退库单表 (return_records)
-- 设计方案章节:9.6 退库单表
CREATE TABLE IF NOT EXISTS return_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT UNIQUE NOT NULL,
project_id INTEGER NOT NULL,
return_type TEXT DEFAULT 'warehouse',
return_date DATE NOT NULL,
applicant TEXT NOT NULL,
items TEXT,
total_quantity REAL,
total_amount REAL,
cost_adjustment REAL DEFAULT 0,
refund_amount REAL DEFAULT 0,
status TEXT DEFAULT 'pending',
remark TEXT,
attachments TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES projects(id)
);
CREATE INDEX IF NOT EXISTS idx_return_records_code ON return_records(code);
CREATE INDEX IF NOT EXISTS idx_return_records_project ON return_records(project_id);
CREATE INDEX IF NOT EXISTS idx_return_records_status ON return_records(status);
-- 表6:材料价格历史表 (material_price_history)
-- 设计方案章节:9.7 材料价格历史表
CREATE TABLE IF NOT EXISTS material_price_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id INTEGER NOT NULL,
purchase_order_id INTEGER,
supplier_id INTEGER,
supplier_country TEXT,
unit_price REAL NOT NULL,
currency TEXT DEFAULT 'CNY',
quantity REAL,
purchase_date DATE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(id),
FOREIGN KEY (purchase_order_id) REFERENCES purchase_orders(id),
FOREIGN KEY (supplier_id) REFERENCES suppliers(id)
);
CREATE INDEX IF NOT EXISTS idx_material_price_history_product ON material_price_history(product_id);
CREATE INDEX IF NOT EXISTS idx_material_price_history_supplier ON material_price_history(supplier_id);
CREATE INDEX IF NOT EXISTS idx_material_price_history_date ON material_price_history(purchase_date);
-- 表7:项目材料库存表 (project_material_inventory)
-- 设计方案章节:9.8 项目材料库存表
CREATE TABLE IF NOT EXISTS project_material_inventory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
product_name TEXT,
unit TEXT,
purchased_quantity REAL DEFAULT 0,
received_quantity REAL DEFAULT 0,
used_quantity REAL DEFAULT 0,
returned_quantity REAL DEFAULT 0,
current_quantity REAL DEFAULT 0,
total_amount REAL DEFAULT 0,
average_price REAL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES projects(id),
FOREIGN KEY (product_id) REFERENCES products(id),
UNIQUE(project_id, product_id)
);
CREATE INDEX IF NOT EXISTS idx_project_material_inventory_project ON project_material_inventory(project_id);
CREATE INDEX IF NOT EXISTS idx_project_material_inventory_product ON project_material_inventory(product_id);
-- ============================================
-- 第二部分:扩展现有表字段(SQLite不支持IF NOT EXISTS,需要手动处理)
-- ============================================
-- 扩展 purchase_orders 表
-- 设计方案章节:9.1 采购订单表
ALTER TABLE purchase_orders ADD COLUMN project_id INTEGER;
ALTER TABLE purchase_orders ADD COLUMN supplier_country TEXT DEFAULT 'Laos';
ALTER TABLE purchase_orders ADD COLUMN estimated_amount REAL DEFAULT 0;
ALTER TABLE purchase_orders ADD COLUMN paid_amount REAL DEFAULT 0;
ALTER TABLE purchase_orders ADD COLUMN contract_url TEXT;
ALTER TABLE purchase_orders ADD COLUMN quotation_url TEXT;
ALTER TABLE purchase_orders ADD COLUMN actual_delivery_date DATE;
ALTER TABLE purchase_orders ADD COLUMN remark TEXT;
-- 扩展 purchase_order_items 表
-- 设计方案章节:9.2 采购订单明细表
ALTER TABLE purchase_order_items ADD COLUMN received_quantity REAL DEFAULT 0;
ALTER TABLE purchase_order_items ADD COLUMN verified_quantity REAL DEFAULT 0;
-- 扩展 payment_plans 表
-- 设计方案章节:9.3 付款计划表
ALTER TABLE payment_plans ADD COLUMN stage TEXT;
ALTER TABLE payment_plans ADD COLUMN planned_date DATE;
ALTER TABLE payment_plans ADD COLUMN planned_amount REAL;
ALTER TABLE payment_plans ADD COLUMN planned_percentage REAL;
ALTER TABLE payment_plans ADD COLUMN actual_amount REAL DEFAULT 0;
ALTER TABLE payment_plans ADD COLUMN actual_date DATE;
ALTER TABLE payment_plans ADD COLUMN payment_request_id INTEGER;
ALTER TABLE payment_plans ADD COLUMN reminder_days INTEGER DEFAULT 3;
ALTER TABLE payment_plans ADD COLUMN remark TEXT;
-- 扩展 payment_requests 表
-- 设计方案章节:9.12 付款申请表扩展
ALTER TABLE payment_requests ADD COLUMN payment_type TEXT DEFAULT 'material';
ALTER TABLE payment_requests ADD COLUMN purchase_order_id INTEGER;
ALTER TABLE payment_requests ADD COLUMN logistics_company_id INTEGER;
ALTER TABLE payment_requests ADD COLUMN logistics_document_url TEXT;
ALTER TABLE payment_requests ADD COLUMN driver_phone TEXT;
ALTER TABLE payment_requests ADD COLUMN cargo_weight REAL;
ALTER TABLE payment_requests ADD COLUMN transport_distance REAL;
-- 扩展 suppliers 表
-- 设计方案章节:9.13 供应商表扩展
ALTER TABLE suppliers ADD COLUMN supply_category TEXT;
ALTER TABLE suppliers ADD COLUMN country TEXT;
ALTER TABLE suppliers ADD COLUMN address TEXT;
ALTER TABLE suppliers ADD COLUMN phone TEXT;
ALTER TABLE suppliers ADD COLUMN email TEXT;
ALTER TABLE suppliers ADD COLUMN status TEXT DEFAULT 'active';
-- 扩展 purchase_requests 表
-- 设计方案章节:9.14 采购申请表扩展
ALTER TABLE purchase_requests ADD COLUMN expected_date DATE;
-- 创建新索引
CREATE INDEX IF NOT EXISTS idx_purchase_orders_project ON purchase_orders(project_id);
CREATE INDEX IF NOT EXISTS idx_purchase_orders_supplier_country ON purchase_orders(supplier_country);
CREATE INDEX IF NOT EXISTS idx_payment_requests_type ON payment_requests(payment_type);
CREATE INDEX IF NOT EXISTS idx_payment_requests_order ON payment_requests(purchase_order_id);
CREATE INDEX IF NOT EXISTS idx_suppliers_country ON suppliers(country);
CREATE INDEX IF NOT EXISTS idx_suppliers_status ON suppliers(status);
@@ -0,0 +1,86 @@
/**
* 添加物流公司联系人表迁移脚本
* 修复物流公司详情获取失败的问题
* 日期:2026-04-08
*/
const db = require('../db-sqlite');
async function createLogisticsCompanyContactsTable() {
try {
console.log('开始创建物流公司联系人表...');
// 创建物流公司联系人表
await db.query(`
CREATE TABLE IF NOT EXISTS logistics_company_contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
logistics_company_id INTEGER NOT NULL,
name TEXT NOT NULL,
phone TEXT,
email TEXT,
position TEXT,
is_primary INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (logistics_company_id) REFERENCES logistics_companies(id) ON DELETE CASCADE
)
`);
// 创建索引
await db.query('CREATE INDEX IF NOT EXISTS idx_lc_contacts_company ON logistics_company_contacts(logistics_company_id)');
await db.query('CREATE INDEX IF NOT EXISTS idx_lc_contacts_primary ON logistics_company_contacts(is_primary)');
console.log('物流公司联系人表创建成功!');
// 检查是否有现有的物流公司,为它们添加默认联系人
const companies = await db.query('SELECT id, name FROM logistics_companies');
if (companies.rows.length > 0) {
console.log(`${companies.rows.length} 个物流公司添加默认联系人...`);
for (const company of companies.rows) {
// 检查是否已有联系人
const existingContacts = await db.query(
'SELECT COUNT(*) as count FROM logistics_company_contacts WHERE logistics_company_id = ?',
[company.id]
);
if (existingContacts.rows[0].count === 0) {
// 添加默认联系人
await db.query(`
INSERT INTO logistics_company_contacts
(logistics_company_id, name, phone, email, position, is_primary, created_at)
VALUES (?, ?, ?, ?, ?, 1, datetime('now'))
`, [company.id, '默认联系人', '', '', '联系人']);
console.log(`为物流公司 "${company.name}" 添加了默认联系人`);
}
}
}
console.log('迁移完成!');
return { success: true, message: '物流公司联系人表创建成功' };
} catch (error) {
console.error('创建物流公司联系人表失败:', error);
return { success: false, message: '创建物流公司联系人表失败', error: error.message };
}
}
// 如果直接运行此脚本
if (require.main === module) {
createLogisticsCompanyContactsTable()
.then(result => {
if (result.success) {
console.log('✅ 迁移成功:', result.message);
process.exit(0);
} else {
console.error('❌ 迁移失败:', result.message);
process.exit(1);
}
})
.catch(error => {
console.error('❌ 迁移执行失败:', error);
process.exit(1);
});
}
module.exports = createLogisticsCompanyContactsTable;
@@ -0,0 +1,29 @@
-- 创建分包商收款信息表
CREATE TABLE IF NOT EXISTS subcontractor_payment_infos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
subcontractor_id INTEGER NOT NULL,
account_name TEXT NOT NULL,
bank_account TEXT NOT NULL,
bank_name TEXT NOT NULL,
qr_code TEXT,
is_primary INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (subcontractor_id) REFERENCES subcontractors(id) ON DELETE CASCADE
);
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_subcontractor_payment_infos_subcontractor_id ON subcontractor_payment_infos(subcontractor_id);
CREATE INDEX IF NOT EXISTS idx_subcontractor_payment_infos_is_primary ON subcontractor_payment_infos(is_primary);
-- 添加注释
COMMENT ON TABLE subcontractor_payment_infos IS '分包商收款信息表';
COMMENT ON COLUMN subcontractor_payment_infos.id IS '主键ID';
COMMENT ON COLUMN subcontractor_payment_infos.subcontractor_id IS '分包商ID';
COMMENT ON COLUMN subcontractor_payment_infos.account_name IS '账户名称';
COMMENT ON COLUMN subcontractor_payment_infos.bank_account IS '银行账号';
COMMENT ON COLUMN subcontractor_payment_infos.bank_name IS '银行名称';
COMMENT ON COLUMN subcontractor_payment_infos.qr_code IS '二维码图片路径';
COMMENT ON COLUMN subcontractor_payment_infos.is_primary IS '是否为主账户(0:否,1:是)';
COMMENT ON COLUMN subcontractor_payment_infos.created_at IS '创建时间';
COMMENT ON COLUMN subcontractor_payment_infos.updated_at IS '更新时间';
+66
View File
@@ -0,0 +1,66 @@
// 数据库迁移:添加 password_hash 字段到 users 表
const db = require('../db-sqlite');
const { hashPassword } = require('../utils/auth');
async function migrate() {
try {
console.log('开始迁移:添加 password_hash 字段...');
// 检查 password_hash 字段是否已存在
const result = await db.query("PRAGMA table_info(users)");
const hasPasswordHash = result.rows.some(row => row.name === 'password_hash');
if (hasPasswordHash) {
console.log('✅ password_hash 字段已存在,跳过迁移');
return;
}
// 添加 password_hash 字段
await db.query("ALTER TABLE users ADD COLUMN password_hash TEXT");
console.log('✅ password_hash 字段添加成功');
// 获取所有用户,为现有用户设置默认密码哈希
// 注意:这会使用密码 '123456' 为所有用户生成哈希
// 首次登录后需要提示用户修改密码
const defaultPassword = '123456';
const defaultHash = hashPassword(defaultPassword);
// 更新所有现有用户,将 plaintext password 迁移到 password_hash
const usersResult = await db.query("SELECT id, password FROM users WHERE password_hash IS NULL");
console.log(`找到 ${usersResult.rows.length} 个需要迁移的用户`);
for (const user of usersResult.rows) {
// 如果已有明文密码,使用相同的密码生成哈希
// 如果没有明文密码,使用默认密码
const passwordToHash = user.password || defaultPassword;
const hashedPassword = hashPassword(passwordToHash);
await db.query(
"UPDATE users SET password_hash = ? WHERE id = ?",
[hashedPassword, user.id]
);
console.log(` 用户 ID ${user.id} 密码已迁移`);
}
console.log('✅ 密码迁移完成');
console.log('');
console.log('⚠️ 重要提示:');
console.log(' - 现有用户密码已迁移(或使用默认密码 123456)');
console.log(' - 建议通知所有用户首次登录后修改密码');
console.log(' - 新注册用户的密码将自动使用哈希存储');
} catch (error) {
console.error('❌ 迁移失败:', error.message);
process.exit(1);
}
}
// 如果是直接运行此脚本
if (require.main === module) {
migrate().then(() => {
console.log('\n迁移完成');
process.exit(0);
});
}
module.exports = { migrate };