05.1 ปรบปรง backend ทงหมด และ frontend/login

This commit is contained in:
admin
2025-10-01 11:14:11 +07:00
parent 5be0f5407b
commit 905afb56f5
43 changed files with 2285 additions and 2834 deletions

View File

@@ -1,17 +1,4 @@
// FILE: src/db/index.js (ESM)
// Database connection and query utility
// - Uses mysql2/promise for connection pooling and async/await
// - Exports a query function for executing SQL with parameters
// - Connection settings are read from environment variables with defaults
// - Uses named placeholders for query parameters
// - Dates are handled as strings in UTC timezone to avoid timezone issues
// - Connection pool is configured to handle multiple concurrent requests
// =============================================================
// Load environment variables from .env file if present
// (uncomment the next line if using dotenv)
// import dotenv from 'dotenv'; dotenv.config();
// (Make sure to install dotenv package if using this line)
// FILE: backend/src/db/index.js (ESM)
import mysql from "mysql2/promise";
const {
@@ -30,21 +17,23 @@ const pool = mysql.createPool({
password: DB_PASSWORD,
database: DB_NAME,
connectionLimit: Number(DB_CONN_LIMIT),
waitForConnections: true, // Recommended for handling connection spikes
waitForConnections: true,
namedPlaceholders: true,
dateStrings: true, // Keep dates as strings
timezone: "Z", // Store and retrieve dates in UTC
dateStrings: true, // คงวันที่เป็น string
timezone: "Z", // ใช้ UTC
});
/**
* Executes a SQL query with parameters.
* @param {string} sql The SQL query string.
* @param {object} [params={}] The parameters to bind to the query.
* @returns {Promise<any[]>} A promise that resolves to an array of rows.
* เรียก Stored Procedure แบบง่าย
* @param {string} procName ชื่อโปรซีเยอร์ เช่น "sp_rfa_create_with_items"
* @param {Array<any>} params ลำดับพารามิเตอร์
* @returns {Promise<any>} rows จาก CALL
*/
export async function query(sql, params = {}) {
const [rows] = await pool.execute(sql, params);
export async function callProc(procName, params = []) {
const placeholders = params.map(() => "?").join(",");
const sql = `CALL ${procName}(${placeholders})`;
const [rows] = await pool.query(sql, params);
return rows;
}
export default pool;
export default pool; // ใช้ sql.query(...) ได้ตามที่ routes เรียกอยู่

View File

@@ -1,10 +1,7 @@
// FILE: src/db/sequelize.js
// Sequelize initialization and model definitions
// - Configured via config.js
// - Defines User, Role, Permission, UserRole, RolePermission models
// - Sets up associations between models
// - Exports sequelize instance and models for use in other modules
// FILE: backend/src/db/sequelize.js
// “lazy-load” ตาม env ปลอดภัยกว่า และยังคง dbReady() ให้เรียกทดสอบได้
// ใช้ได้เมื่อจำเป็น (เช่น งาน admin tool เฉพาะกิจ)
// ตั้ง ENABLE_SEQUELIZE=1 เพื่อเปิดใช้ Model loader; ไม่งั้นจะเป็นโหมดเบา ๆ
import { Sequelize } from "sequelize";
import { config } from "../config.js";
@@ -18,49 +15,57 @@ export const sequelize = new Sequelize(
dialect: "mariadb",
logging: false,
dialectOptions: { timezone: "Z" },
define: {
freezeTableName: true,
underscored: false,
timestamps: false,
},
define: { freezeTableName: true, underscored: false, timestamps: false },
pool: { max: 10, min: 0, idle: 10000 },
}
);
import UserModel from "./models/User.js";
import RoleModel from "./models/Role.js";
import PermissionModel from "./models/Permission.js";
import UserRoleModel from "./models/UserRole.js";
import RolePermissionModel from "./models/RolePermission.js";
export let User = null;
export let Role = null;
export let Permission = null;
export let UserRole = null;
export let RolePermission = null;
export const User = UserModel(sequelize);
export const Role = RoleModel(sequelize);
export const Permission = PermissionModel(sequelize);
export const UserRole = UserRoleModel(sequelize);
export const RolePermission = RolePermissionModel(sequelize);
if (process.env.ENABLE_SEQUELIZE === "1") {
// โหลดโมเดลแบบ on-demand เพื่อลดความเสี่ยง runtime หากไฟล์โมเดลไม่มี
const mdlUser = await import("./models/User.js").catch(() => null);
const mdlRole = await import("./models/Role.js").catch(() => null);
const mdlPerm = await import("./models/Permission.js").catch(() => null);
const mdlUR = await import("./models/UserRole.js").catch(() => null);
const mdlRP = await import("./models/RolePermission.js").catch(() => null);
User.belongsToMany(Role, {
through: UserRole,
foreignKey: "user_id",
otherKey: "role_id",
});
Role.belongsToMany(User, {
through: UserRole,
foreignKey: "role_id",
otherKey: "user_id",
});
if (mdlUser?.default) User = mdlUser.default(sequelize);
if (mdlRole?.default) Role = mdlRole.default(sequelize);
if (mdlPerm?.default) Permission = mdlPerm.default(sequelize);
if (mdlUR?.default) UserRole = mdlUR.default(sequelize);
if (mdlRP?.default) RolePermission = mdlRP.default(sequelize);
Role.belongsToMany(Permission, {
through: RolePermission,
foreignKey: "role_id",
otherKey: "permission_id",
});
Permission.belongsToMany(Role, {
through: RolePermission,
foreignKey: "permission_id",
otherKey: "role_id",
});
if (User && Role && Permission && UserRole && RolePermission) {
User.belongsToMany(Role, {
through: UserRole,
foreignKey: "user_id",
otherKey: "role_id",
});
Role.belongsToMany(User, {
through: UserRole,
foreignKey: "role_id",
otherKey: "user_id",
});
Role.belongsToMany(Permission, {
through: RolePermission,
foreignKey: "role_id",
otherKey: "permission_id",
});
Permission.belongsToMany(Role, {
through: RolePermission,
foreignKey: "permission_id",
otherKey: "role_id",
});
}
}
export async function dbReady() {
// โหมดเบา ๆ: แค่ทดสอบเชื่อมต่อ
await sequelize.authenticate();
}