diff --git a/mariadb-v2-260106.zip b/mariadb-v2-260106.zip deleted file mode 100644 index e5587ec..0000000 Binary files a/mariadb-v2-260106.zip and /dev/null differ diff --git a/package-lock.json b/package-lock.json index f4724f3..b69645a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "cors": "^2.8.5", + "crypto": "^1.0.1", "dotenv": "^17.2.3", "express": "^5.2.1", "helmet": "^8.1.0", @@ -408,6 +409,13 @@ "node": ">=12.0.0" } }, + "node_modules/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.", + "license": "ISC" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", diff --git a/package.json b/package.json index f79d1ef..d91af5d 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node server.js", - "dev": "nodemon server.js" + "dev": "nodemon server.js" }, "keywords": [], "author": "", @@ -14,6 +14,7 @@ "type": "commonjs", "dependencies": { "cors": "^2.8.5", + "crypto": "^1.0.1", "dotenv": "^17.2.3", "express": "^5.2.1", "helmet": "^8.1.0", diff --git a/readme.txt b/readme.txt index 303620c..8202ae0 100644 --- a/readme.txt +++ b/readme.txt @@ -1,38 +1,41 @@ /my-api-v2 - ├── .env # 環境變數 (DB 帳密, Mail 帳密) - ├── server.js # 主程式 (Entry Point) - ├── src/ - │ ├── config/ - │ │ └── db.js # MariaDB 連線池設定 - │ ├── services/ - │ │ ├── ormService.js # 核心 ORM 與 SP 邏輯 - │ │ ├── uploadService.js # 檔案上傳邏輯 - │ │ └── mailService.js # 郵件與排程邏輯 - │ └── utils/ - │ └── helper.js # 通用工具函式 (quotstr, date format) - └── public/upload # 檔案上傳目錄 + .env # h׃ (DB , Mail ) + server.js # ʽ (Entry Point) + src/ + config/ + db.js # MariaDB BO + services/ + ormService.js # ORM c SP ߉݋ + uploadService.js # nς߉݋ + mailService.js # ]cų߉݋ + utils/ + helper.js # ͨùߺʽ (quotstr, date format) + public/upload # nςĿ >> https://gemini.google.com/app/57091040afbd48e1 -# 1. 初始化 npm 專案 (若尚未執行) +# 1. ʼ npm (δ) npm init -y -# 2. 安裝核心 Web 框架與安全套件 +# 2. b Web cȫ׼ npm install express cors helmet dotenv -# 3. 安裝資料庫驅動 (MariaDB/MySQL) +# 3. bYώ (MariaDB/MySQL) npm install mysql2 -# 4. 安裝檔案處理與上傳套件 +# 4. bn̎cς׼ npm install multer -# 5. 安裝郵件與排程套件 +# 5. b]cų׼ npm install nodemailer node-schedule -# 6. 安裝進階 Log 管理系統 +# 6. bMA Log ϵy npm install morgan winston winston-daily-rotate-file -# 7. (選用) 安裝開發環境自動重啟工具 +# 7. (x) b_lhԄ؆ npm install --save-dev nodemon + + + diff --git a/server.js b/server.js index 2ead2a9..df27f6e 100644 --- a/server.js +++ b/server.js @@ -64,7 +64,12 @@ app.post(ormRoutes, async (req, res, next) => { app.post('/upload/:dbname/:typeid', upload.single('file'), (req, res) => { if (!req.file) return res.status(400).json({ status: 400, msg: 'No file' }); - const fileUrl = `/static/upload/${req.params.dbname}/${req.params.typeid}/${req.file.filename}`; + //const fileUrl = `/static/upload/${req.params.dbname}/${req.params.typeid}/${req.file.filename}`; + + // אּ㪺 Server IP + const serverRoot = 'https://api.gex.com.tw:8033/upload'; + const fileUrl = `${serverRoot}/${req.params.dbname}/${req.params.typeid}/${req.file.filename}`; + res.json({ status: 0, data: { value: fileUrl, url: fileUrl }, msg: 'success' }); }); diff --git a/src/config/db.js b/src/config/db.js index 24a8729..021104b 100644 --- a/src/config/db.js +++ b/src/config/db.js @@ -11,7 +11,8 @@ const pool = mysql.createPool({ connectionLimit: 15, // 增加併發處理能力 queueLimit: 0, multipleStatements: true, - timezone: '+08:00' // 強制時區一致 + charset: 'utf8mb4', // 確保這一行存在 + timezone: '+08:00' // 強制時區一致 }); // 啟動測試 diff --git a/src/services/ormService.js b/src/services/ormService.js index 02c4c6e..4799c42 100644 --- a/src/services/ormService.js +++ b/src/services/ormService.js @@ -246,10 +246,14 @@ class OrmService { if (spName === 'get_treedata' || spName === 'get_assignData') { finalParams = [...orderedParas, "''"]; } - // get_treedata 應傳入3個參數 - //if (spName === 'zen_showsource') { - // finalParams = [...orderedParas, "''"]; - //} + // get_treedata 應傳入3個參數(會傳入 [_flow_level, _tag, para01, para02, para03]) + if (spName === 'zen_showsource' || spName === 'zen_updatesource') { + finalParams = [body.para01, body.para02, body.para03]; + } + // + if (spName === 'zen_create_json_v2') { + finalParams = [body.para01, body.para02]; + } return finalParams; } diff --git a/src/services/uploadService.js b/src/services/uploadService.js index 85595e3..210e344 100644 --- a/src/services/uploadService.js +++ b/src/services/uploadService.js @@ -1,6 +1,7 @@ const multer = require('multer'); const fs = require('fs'); const path = require('path'); +const crypto = require('crypto'); // 用於生成隨機字串 const storage = multer.diskStorage({ destination: (req, file, cb) => { @@ -10,8 +11,45 @@ const storage = multer.diskStorage({ cb(null, uploadPath); }, filename: (req, file, cb) => { - const dateStr = new Date().toISOString().replace(/[:.]/g, '-'); - cb(null, `${dateStr}-${file.originalname}`); + //下行程式會自動加入日期 tag 在檔名前, 目前先取消 2026/01/10 + //const dateStr = new Date().toISOString().replace(/[:.]/g, '-'); + //cb(null, `${dateStr}-${file.originalname}`); + + // 解決中文亂碼問題:將 latin1 轉回 utf-8 + //const originalName = Buffer.from(file.originalname, 'latin1').toString('utf8'); + //cb(null, `${file.originalname}`); + + + // 1. 取得原始檔名與副檔名 + const ext = path.extname(file.originalname); // 包含點,例如 .jpg + const baseName = path.basename(file.originalname, ext); // 只有主檔名 + + // 2. 正則表達式:判斷是否為純英數、底線、橫線 + // ^[a-zA-Z0-9_-]+$ 表示從頭到尾都是英數或底線橫線 + const isAlphaNumeric = /^[a-zA-Z0-9_-]+$/.test(baseName); + + let finalFileName = ''; + //const dateStr = new Date().toISOString().replace(/[:.]/g, '-'); + const dateStr = new Date().toISOString().replace(/\D/g, ''); + + if (isAlphaNumeric) { + // A. 如果是純英數,保持原樣,~~加上時間戳防止重複~~ + //finalFileName = `${dateStr}-${file.originalname}`; + finalFileName = `${file.originalname}`; + } else { + // B. 如果包含中文或其他字元 + // 先修復 Multer 的編碼錯誤 (latin1 -> utf8) + const decodedName = Buffer.from(file.originalname, 'latin1').toString('utf8'); + + // 為了系統穩定,硬碟端存儲建議改用「隨機英數」防止 URL 編碼問題 + const uniqueSuffix = crypto.randomBytes(4).toString('hex'); + finalFileName = `${dateStr}-${uniqueSuffix}${ext}`; + + // 將正確的中文名稱掛載,供 Controller 存入資料庫使用 + file.decodedOriginalName = decodedName; + } + + cb(null, finalFileName); } });