update delete log, authentication, add export device #4
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -1 +1,2 @@
 | 
			
		|||
BASE_URL=http://localhost:4000
 | 
			
		||||
JWT_SECRET=secret
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,8 @@
 | 
			
		|||
        "multer": "^1.4.5-lts.1",
 | 
			
		||||
        "mysql2": "^3.14.2",
 | 
			
		||||
        "sqlite3": "^5.1.6",
 | 
			
		||||
        "string-similarity": "^4.0.4"
 | 
			
		||||
        "string-similarity": "^4.0.4",
 | 
			
		||||
        "xlsx-js-style": "^1.2.0"
 | 
			
		||||
      },
 | 
			
		||||
      "devDependencies": {
 | 
			
		||||
        "nodemon": "^3.1.10"
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +97,22 @@
 | 
			
		|||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/adler-32": {
 | 
			
		||||
      "version": "1.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "exit-on-epipe": "~1.0.1",
 | 
			
		||||
        "printj": "~1.1.0"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "adler32": "bin/adler32.njs"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/agent-base": {
 | 
			
		||||
      "version": "6.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -519,6 +536,28 @@
 | 
			
		|||
        "url": "https://github.com/sponsors/ljharb"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/cfb": {
 | 
			
		||||
      "version": "1.2.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
 | 
			
		||||
      "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "adler-32": "~1.3.0",
 | 
			
		||||
        "crc-32": "~1.2.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/cfb/node_modules/adler-32": {
 | 
			
		||||
      "version": "1.3.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
 | 
			
		||||
      "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/cheerio": {
 | 
			
		||||
      "version": "1.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -611,6 +650,28 @@
 | 
			
		|||
        "node": ">=4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/codepage": {
 | 
			
		||||
      "version": "1.14.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
 | 
			
		||||
      "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "commander": "~2.14.1",
 | 
			
		||||
        "exit-on-epipe": "~1.0.1"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "codepage": "bin/codepage.njs"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/codepage/node_modules/commander": {
 | 
			
		||||
      "version": "2.14.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
 | 
			
		||||
      "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/color-support": {
 | 
			
		||||
      "version": "1.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -631,6 +692,12 @@
 | 
			
		|||
        "node": ">= 0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/commander": {
 | 
			
		||||
      "version": "2.17.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
 | 
			
		||||
      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/concat-map": {
 | 
			
		||||
      "version": "0.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -706,6 +773,18 @@
 | 
			
		|||
        "node": ">= 0.10"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/crc-32": {
 | 
			
		||||
      "version": "1.2.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
 | 
			
		||||
      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "crc32": "bin/crc32.njs"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/css-select": {
 | 
			
		||||
      "version": "5.2.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,6 +1122,15 @@
 | 
			
		|||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/exit-on-epipe": {
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/expand-template": {
 | 
			
		||||
      "version": "2.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -1096,6 +1184,12 @@
 | 
			
		|||
        "url": "https://opencollective.com/express"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/fflate": {
 | 
			
		||||
      "version": "0.3.11",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.3.11.tgz",
 | 
			
		||||
      "integrity": "sha512-Rr5QlUeGN1mbOHlaqcSYMKVpPbgLy0AWT/W0EHxA6NGI12yO1jpoui2zBBvU2G824ltM6Ut8BFgfHSBGfkmS0A==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/file-uri-to-path": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -1172,6 +1266,15 @@
 | 
			
		|||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/frac": {
 | 
			
		||||
      "version": "1.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
 | 
			
		||||
      "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/fresh": {
 | 
			
		||||
      "version": "0.5.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -2446,6 +2549,18 @@
 | 
			
		|||
        "node": ">=10"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/printj": {
 | 
			
		||||
      "version": "1.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
 | 
			
		||||
      "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "printj": "bin/printj.njs"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/process-nextick-args": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -2936,6 +3051,18 @@
 | 
			
		|||
        "node": ">= 0.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ssf": {
 | 
			
		||||
      "version": "0.11.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
 | 
			
		||||
      "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "frac": "~1.1.2"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ssri": {
 | 
			
		||||
      "version": "8.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -3278,11 +3405,53 @@
 | 
			
		|||
        "string-width": "^1.0.2 || 2 || 3 || 4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/wmf": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/word": {
 | 
			
		||||
      "version": "0.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/wrappy": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/xlsx-js-style": {
 | 
			
		||||
      "version": "1.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xlsx-js-style/-/xlsx-js-style-1.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-DDT4FXFSWfT4DXMSok/m3TvmP1gvO3dn0Eu/c+eXHW5Kzmp7IczNkxg/iEPnImbG9X0Vb8QhROda5eatSR/97Q==",
 | 
			
		||||
      "license": "Apache-2.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "adler-32": "~1.2.0",
 | 
			
		||||
        "cfb": "^1.1.4",
 | 
			
		||||
        "codepage": "~1.14.0",
 | 
			
		||||
        "commander": "~2.17.1",
 | 
			
		||||
        "crc-32": "~1.2.0",
 | 
			
		||||
        "exit-on-epipe": "~1.0.1",
 | 
			
		||||
        "fflate": "^0.3.8",
 | 
			
		||||
        "ssf": "~0.11.2",
 | 
			
		||||
        "wmf": "~1.0.1",
 | 
			
		||||
        "word": "~0.3.0"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "xlsx": "bin/xlsx.njs"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/xtend": {
 | 
			
		||||
      "version": "4.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,8 @@
 | 
			
		|||
    "multer": "^1.4.5-lts.1",
 | 
			
		||||
    "mysql2": "^3.14.2",
 | 
			
		||||
    "sqlite3": "^5.1.6",
 | 
			
		||||
    "string-similarity": "^4.0.4"
 | 
			
		||||
    "string-similarity": "^4.0.4",
 | 
			
		||||
    "xlsx-js-style": "^1.2.0"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "nodemon": "^3.1.10"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										109
									
								
								server.js
								
								
								
								
							
							
						
						
									
										109
									
								
								server.js
								
								
								
								
							| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
const express = require("express");
 | 
			
		||||
const mysql = require("mysql2/promise");
 | 
			
		||||
const bodyParser = require("body-parser");
 | 
			
		||||
const XLSX = require("xlsx-js-style");
 | 
			
		||||
const dotenv = require("dotenv");
 | 
			
		||||
dotenv.config();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,17 +36,10 @@ app.use(bodyParser.json());
 | 
			
		|||
app.use(express.static("public"));
 | 
			
		||||
app.use(express.urlencoded({ extended: true }));
 | 
			
		||||
 | 
			
		||||
// const db = mysql.createPool({
 | 
			
		||||
// 	host: "localhost",
 | 
			
		||||
// 	user: "admin",
 | 
			
		||||
// 	password: "Work1234",
 | 
			
		||||
// 	database: "log_analysis",
 | 
			
		||||
// });
 | 
			
		||||
 | 
			
		||||
const db = mysql.createPool({
 | 
			
		||||
	host: "localhost",
 | 
			
		||||
	user: "root",
 | 
			
		||||
	password: "",
 | 
			
		||||
	user: "admin",
 | 
			
		||||
	password: "Work1234",
 | 
			
		||||
	database: "log_analysis",
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -318,6 +312,103 @@ app.post("/api/confirm-count", async (req, res) => {
 | 
			
		|||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
app.get("/api/device-export-excel", async (req, res) => {
 | 
			
		||||
	const [rows] = await db.query(
 | 
			
		||||
		"SELECT pid, version, update_name, update_email, updated_at FROM devices",
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	const worksheetData = [
 | 
			
		||||
		["No", "PID", "Verion", "Url", "Name", "Email", "Updated At"],
 | 
			
		||||
		...rows.map((deviceItem, deviceIndex) => {
 | 
			
		||||
			const url = `${process.env.BASE_URL}?pid=${deviceItem.pid}&version=${deviceItem.version}`;
 | 
			
		||||
			return [
 | 
			
		||||
				deviceIndex + 1,
 | 
			
		||||
				deviceItem.pid,
 | 
			
		||||
				deviceItem.version,
 | 
			
		||||
				{ v: url, l: { Target: url } },
 | 
			
		||||
				deviceItem.update_name,
 | 
			
		||||
				deviceItem.update_email,
 | 
			
		||||
				deviceItem.updated_at,
 | 
			
		||||
			];
 | 
			
		||||
		}),
 | 
			
		||||
	];
 | 
			
		||||
 | 
			
		||||
	// Create worksheet
 | 
			
		||||
	const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);
 | 
			
		||||
 | 
			
		||||
	// Add styles to header row
 | 
			
		||||
	const headerStyle = {
 | 
			
		||||
		font: { bold: true, color: { rgb: "FFFFFF" } },
 | 
			
		||||
		fill: { fgColor: { rgb: "4F81BD" } },
 | 
			
		||||
		alignment: { horizontal: "center" },
 | 
			
		||||
		border: {
 | 
			
		||||
			top: { style: "thin", color: { rgb: "000000" } },
 | 
			
		||||
			bottom: { style: "thin", color: { rgb: "000000" } },
 | 
			
		||||
			left: { style: "thin", color: { rgb: "000000" } },
 | 
			
		||||
			right: { style: "thin", color: { rgb: "000000" } },
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const commonCellStyle = {
 | 
			
		||||
		alignment: { horizontal: "center", vertical: "center" },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const wrapTextStyle = {
 | 
			
		||||
		alignment: { horizontal: "left", wrapText: true, vertical: "center" },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const dateCellStyle = {
 | 
			
		||||
		alignment: { horizontal: "center", vertical: "center" },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Set column widths
 | 
			
		||||
	worksheet["!cols"] = [
 | 
			
		||||
		{ wch: 6 }, // No
 | 
			
		||||
		{ wch: 20 }, // PID
 | 
			
		||||
		{ wch: 10 }, // Verion
 | 
			
		||||
		{ wch: 60 }, // Url
 | 
			
		||||
		{ wch: 20 }, // Name
 | 
			
		||||
		{ wch: 30 }, // Email
 | 
			
		||||
		{ wch: 10 }, // Updated At
 | 
			
		||||
	];
 | 
			
		||||
 | 
			
		||||
	["A1", "B1", "C1", "D1", "E1", "F1", "G1"].forEach((cell) => {
 | 
			
		||||
		worksheet[cell].s = headerStyle;
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const totalRows = worksheetData.length;
 | 
			
		||||
	for (let row = 2; row <= totalRows; row++) {
 | 
			
		||||
		const noCell = worksheet[`A${row}`];
 | 
			
		||||
		if (noCell) noCell.s = commonCellStyle;
 | 
			
		||||
 | 
			
		||||
		const dateCell = worksheet[`G${row}`];
 | 
			
		||||
		if (dateCell) {
 | 
			
		||||
			dateCell.s = dateCellStyle;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		["B", "C", "D", "E", "F"].forEach((col) => {
 | 
			
		||||
			const cell = worksheet[`${col}${row}`];
 | 
			
		||||
			if (cell) cell.s = wrapTextStyle;
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const workbook = XLSX.utils.book_new();
 | 
			
		||||
	XLSX.utils.book_append_sheet(workbook, worksheet, "Devices");
 | 
			
		||||
 | 
			
		||||
	const buffer = XLSX.write(workbook, {
 | 
			
		||||
		type: "buffer",
 | 
			
		||||
		bookType: "xlsx",
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	res.setHeader("Content-Disposition", "attachment; filename=devices.xlsx");
 | 
			
		||||
	res.setHeader(
 | 
			
		||||
		"Content-Type",
 | 
			
		||||
		"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	res.send(buffer);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Danh sách regex lọc lỗi
 | 
			
		||||
const errorPatterns = [
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue