更新政府端和银行端

This commit is contained in:
2025-09-17 18:04:28 +08:00
parent f35ceef31f
commit e4287b83fe
185 changed files with 78320 additions and 189 deletions

View File

@@ -0,0 +1,71 @@
-- 创建 bank_ 前缀业务表无DROP避免覆盖现有表
CREATE TABLE IF NOT EXISTS bank_roles (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
display_name VARCHAR(100) NOT NULL,
description TEXT NULL,
level INT NOT NULL DEFAULT 1,
is_system TINYINT(1) NOT NULL DEFAULT 0,
status ENUM('active','inactive') NOT NULL DEFAULT 'active',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS bank_users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
phone VARCHAR(20) NULL,
real_name VARCHAR(50) NOT NULL,
id_card VARCHAR(18) NOT NULL UNIQUE,
avatar VARCHAR(255) NULL,
role_id INT NOT NULL,
status ENUM('active','inactive','suspended','locked') NOT NULL DEFAULT 'active',
last_login DATETIME NULL,
login_attempts INT NOT NULL DEFAULT 0,
locked_until DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_bank_users_role_id FOREIGN KEY (role_id) REFERENCES bank_roles(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS bank_accounts (
id INT AUTO_INCREMENT PRIMARY KEY,
account_number VARCHAR(20) NOT NULL UNIQUE,
user_id INT NOT NULL,
account_type ENUM('savings','checking','credit','loan') NOT NULL DEFAULT 'savings',
balance BIGINT NOT NULL DEFAULT 0,
available_balance BIGINT NOT NULL DEFAULT 0,
frozen_amount BIGINT NOT NULL DEFAULT 0,
currency VARCHAR(3) NOT NULL DEFAULT 'CNY',
interest_rate DECIMAL(5,4) NULL,
status ENUM('active','inactive','frozen','closed') NOT NULL DEFAULT 'active',
opened_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
closed_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_bank_accounts_user_id FOREIGN KEY (user_id) REFERENCES bank_users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS bank_transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
transaction_number VARCHAR(32) NOT NULL UNIQUE,
account_id INT NOT NULL,
transaction_type ENUM('deposit','withdrawal','transfer_in','transfer_out','interest','fee','loan','repayment') NOT NULL,
amount BIGINT NOT NULL,
balance_before BIGINT NOT NULL,
balance_after BIGINT NOT NULL,
counterparty_account VARCHAR(20) NULL,
counterparty_name VARCHAR(100) NULL,
description VARCHAR(255) NULL,
reference_number VARCHAR(50) NULL,
status ENUM('pending','completed','failed','cancelled','reversed') NOT NULL DEFAULT 'pending',
processed_at DATETIME NULL,
reversed_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_bank_transactions_account_id FOREIGN KEY (account_id) REFERENCES bank_accounts(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@@ -0,0 +1,152 @@
/**
* 数据库初始化脚本
* @file init-db.js
* @description 初始化银行系统数据库
*/
const { sequelize } = require('../config/database');
const { User, Role, Account, Transaction } = require('../models');
const bcrypt = require('bcryptjs');
async function initDatabase() {
try {
console.log('🔄 开始初始化银行系统数据库...');
// 测试数据库连接
await sequelize.authenticate();
console.log('✅ 数据库连接成功');
// 同步数据库模型
await sequelize.sync({ force: true });
console.log('✅ 数据库表创建成功');
// 创建初始角色
console.log('🔄 创建初始角色...');
const roles = await Role.bulkCreate([
{
name: 'admin',
display_name: '系统管理员',
description: '拥有系统所有权限',
level: 100,
is_system: true
},
{
name: 'manager',
display_name: '银行经理',
description: '拥有银行管理权限',
level: 80,
is_system: false
},
{
name: 'teller',
display_name: '银行柜员',
description: '拥有基本业务操作权限',
level: 60,
is_system: false
},
{
name: 'user',
display_name: '普通用户',
description: '拥有基本用户权限',
level: 20,
is_system: false
}
]);
console.log('✅ 初始角色创建成功');
// 创建初始管理员用户
console.log('🔄 创建初始管理员用户...');
const adminUser = await User.create({
username: 'admin',
email: 'admin@bank.com',
password: 'Admin123456',
phone: '13800138000',
real_name: '系统管理员',
id_card: '110101199001011234',
role_id: roles[0].id, // admin角色
status: 'active'
});
console.log('✅ 初始管理员用户创建成功');
// 创建测试用户
console.log('🔄 创建测试用户...');
const testUser = await User.create({
username: 'testuser',
email: 'test@bank.com',
password: 'Test123456',
phone: '13800138001',
real_name: '测试用户',
id_card: '110101199001011235',
role_id: roles[3].id, // user角色
status: 'active'
});
console.log('✅ 测试用户创建成功');
// 为测试用户创建账户
console.log('🔄 为测试用户创建账户...');
const testAccount = await Account.create({
account_number: '001' + Date.now().toString().slice(-8) + '0001',
user_id: testUser.id,
account_type: 'savings',
balance: 100000, // 1000元
available_balance: 100000,
frozen_amount: 0,
currency: 'CNY',
interest_rate: 0.035, // 3.5%年利率
status: 'active'
});
console.log('✅ 测试账户创建成功');
// 创建一些示例交易记录
console.log('🔄 创建示例交易记录...');
const transactions = await Transaction.bulkCreate([
{
transaction_number: 'TXN' + Date.now() + '0001',
account_id: testAccount.id,
transaction_type: 'deposit',
amount: 100000,
balance_before: 0,
balance_after: 100000,
description: '开户存款',
status: 'completed',
processed_at: new Date()
},
{
transaction_number: 'TXN' + Date.now() + '0002',
account_id: testAccount.id,
transaction_type: 'interest',
amount: 292, // 约1元利息
balance_before: 100000,
balance_after: 100292,
description: '定期利息',
status: 'completed',
processed_at: new Date()
}
]);
console.log('✅ 示例交易记录创建成功');
console.log('\n🎉 银行系统数据库初始化完成!');
console.log('\n📋 初始数据信息:');
console.log(`👤 管理员账户: admin / Admin123456`);
console.log(`👤 测试用户: testuser / Test123456`);
console.log(`🏦 测试账户: ${testAccount.account_number}`);
console.log(`💰 初始余额: ${(testAccount.balance / 100).toFixed(2)}`);
console.log('\n🔗 数据库连接信息:');
console.log(` 主机: ${process.env.DB_HOST || 'localhost'}`);
console.log(` 端口: ${process.env.DB_PORT || 3306}`);
console.log(` 数据库: ${process.env.DB_NAME || 'bank_management'}`);
} catch (error) {
console.error('❌ 数据库初始化失败:', error);
process.exit(1);
} finally {
await sequelize.close();
console.log('📊 数据库连接已关闭');
}
}
// 运行初始化
if (require.main === module) {
initDatabase();
}
module.exports = initDatabase;

View File

@@ -0,0 +1,35 @@
/**
* 查询用户数据以诊断登录问题
*/
const { sequelize } = require('../config/database');
const { User } = require('../models');
(async () => {
try {
console.log('Connecting to DB...', {
dialect: process.env.DB_DIALECT,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
user: process.env.DB_USER
});
await sequelize.authenticate();
console.log('✅ DB connected');
// 查询所有用户
const users = await User.findAll({
attributes: { exclude: ['password'] } // 排除密码字段
});
console.log('📋 Users count:', users.length);
users.forEach(user => {
console.log(`- ID: ${user.id}, Username: ${user.username}, Email: ${user.email}, Status: ${user.status}, Role ID: ${user.role_id}, Last Login: ${user.last_login}`);
});
process.exit(0);
} catch (err) {
console.error('❌ Query failed:', err.message);
process.exit(1);
}
})();

View File

@@ -0,0 +1,27 @@
-- 初始角色(如果不存在则插入)
INSERT INTO bank_roles (name, display_name, level, is_system, status)
SELECT 'admin','系统管理员',100,1,'active'
WHERE NOT EXISTS (SELECT 1 FROM bank_roles WHERE name='admin');
INSERT INTO bank_roles (name, display_name, level, is_system, status)
SELECT 'user','普通用户',20,0,'active'
WHERE NOT EXISTS (SELECT 1 FROM bank_roles WHERE name='user');
-- 管理员账户,密码由脚本动态替换为 bcrypt 哈希REPLACE_ADMIN_BCRYPT
INSERT INTO bank_users (username,email,password,real_name,id_card,role_id,status)
SELECT 'admin','admin@bank.com','REPLACE_ADMIN_BCRYPT','系统管理员','110101199001011234', r.id,'active'
FROM bank_roles r WHERE r.name='admin'
AND NOT EXISTS (SELECT 1 FROM bank_users WHERE username='admin');
-- 测试用户
INSERT INTO bank_users (username,email,password,real_name,id_card,role_id,status)
SELECT 'testuser','test@bank.com','REPLACE_ADMIN_BCRYPT','测试用户','110101199001011235', r.id,'active'
FROM bank_roles r WHERE r.name='user'
AND NOT EXISTS (SELECT 1 FROM bank_users WHERE username='testuser');
-- 测试账户admin名下
INSERT INTO bank_accounts (account_number,user_id,account_type,balance,available_balance,frozen_amount,currency,interest_rate,status)
SELECT '001' || CAST(FLOOR(RAND()*90000000)+10000000 AS CHAR) || '0001', u.id, 'savings', 100000, 100000, 0, 'CNY', 0.035, 'active'
FROM bank_users u WHERE u.username='admin'
AND NOT EXISTS (SELECT 1 FROM bank_accounts a JOIN bank_users u2 ON a.user_id=u2.id WHERE u2.username='admin');

View File

@@ -0,0 +1,47 @@
Param(
[string]$Host = $env:DB_HOST,
[int]$Port = [int]($env:DB_PORT),
[string]$Database = $env:DB_NAME,
[string]$User = $env:DB_USER,
[string]$Password = $env:DB_PASSWORD,
[string]$AdminPlain = 'Admin123456'
)
Write-Host "Using DB: $Host:$Port/$Database"
# 生成管理员 bcrypt 哈希
try {
$nodeScript = @"
const bcrypt = require('bcryptjs');
const pwd = process.argv[2] || 'Admin123456';
bcrypt.hash(pwd, 10).then(h => { console.log(h); }).catch(e => { console.error(e); process.exit(1); });
"@
$hash = node -e $nodeScript $AdminPlain
if (-not $hash) { throw 'bcrypt hash failed' }
} catch {
Write-Error "Failed to generate bcrypt hash: $_"
exit 1
}
# 读取SQL并替换占位符
$schema = Get-Content -Raw -Encoding UTF8 "$PSScriptRoot/create-bank-schema.sql"
$seed = (Get-Content -Raw -Encoding UTF8 "$PSScriptRoot/seed-bank-demo.sql").Replace('REPLACE_ADMIN_BCRYPT', $hash)
$sql = $schema + "`n" + $seed
# 写入临时文件
$tmp = New-TemporaryFile
Set-Content -Path $tmp -Value $sql -Encoding UTF8
# 调用 mysql 客户端
try {
$env:MYSQL_PWD = $Password
& mysql --host=$Host --port=$Port --user=$User --database=$Database --default-character-set=utf8mb4 --protocol=TCP < $tmp
if ($LASTEXITCODE -ne 0) { throw "mysql returned $LASTEXITCODE" }
Write-Host "✅ Schema & seed executed successfully"
} catch {
Write-Error "Failed to execute SQL: $_"
exit 1
} finally {
Remove-Item $tmp -Force -ErrorAction SilentlyContinue
}

View File

@@ -0,0 +1,29 @@
/**
* 远程数据库连接测试与列出表名
*/
const { sequelize } = require('../config/database');
(async () => {
try {
console.log('Connecting to DB...', {
dialect: process.env.DB_DIALECT,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
user: process.env.DB_USER
});
await sequelize.authenticate();
console.log('✅ DB connected');
const [rows] = await sequelize.query('SHOW TABLES');
const tables = rows.map(r => Object.values(r)[0]);
console.log('📋 Tables:', tables);
process.exit(0);
} catch (err) {
console.error('❌ DB connect failed:', err.message);
process.exit(1);
}
})();