更新政府端和银行端
This commit is contained in:
71
bank-backend/scripts/create-bank-schema.sql
Normal file
71
bank-backend/scripts/create-bank-schema.sql
Normal 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;
|
||||
|
||||
152
bank-backend/scripts/init-db.js
Normal file
152
bank-backend/scripts/init-db.js
Normal 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;
|
||||
35
bank-backend/scripts/query-users.js
Normal file
35
bank-backend/scripts/query-users.js
Normal 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);
|
||||
}
|
||||
})();
|
||||
27
bank-backend/scripts/seed-bank-demo.sql
Normal file
27
bank-backend/scripts/seed-bank-demo.sql
Normal 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');
|
||||
|
||||
47
bank-backend/scripts/setup-bank-db.ps1
Normal file
47
bank-backend/scripts/setup-bank-db.ps1
Normal 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
|
||||
}
|
||||
|
||||
29
bank-backend/scripts/test-connection.js
Normal file
29
bank-backend/scripts/test-connection.js
Normal 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);
|
||||
}
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user