import fs from 'fs'; import { BasedbService } from './basedb'; interface ActivateRecordItem { applicant: string; macAddress: string; applicationCode: string; module: string; activationCode: string; createTime: string; remark: string; } /** * sqlite data storage */ class ActivateRecordService extends BasedbService { tableName: string; constructor() { const options = { dbname: 'pqs9100-tool.db', }; super(options); this.tableName = 'activate_record'; } /** * Initialize table and perform lightweight schema migration. */ init(): void { this._init(); const masterStmt = this.db.prepare('SELECT * FROM sqlite_master WHERE type=? AND name = ?'); const tableExists = masterStmt.get('table', this.tableName); if (!tableExists) { const createTableSql = `CREATE TABLE ${this.tableName} ( id INTEGER PRIMARY KEY AUTOINCREMENT, applicant CHAR(100) NULL, macAddress CHAR(50) NOT NULL, applicationCode CHAR(2000) NOT NULL, module CHAR(200) NOT NULL, activationCode CHAR(2000) NOT NULL, createTime CHAR(32) NOT NULL, remark CHAR(120) NULL );`; this.db.exec(createTableSql); return; } const columns = this.db.prepare(`PRAGMA table_info(${this.tableName})`).all() as Array<{ name: string }>; const hasApplicant = columns.some((column) => column.name === 'applicant'); if (!hasApplicant) { this.db.exec(`ALTER TABLE ${this.tableName} ADD COLUMN applicant CHAR(100) NULL`); } } /** * Insert one record. */ async save(data: ActivateRecordItem) { const insert = this.db.prepare( `INSERT INTO ${this.tableName} (applicant, macAddress, applicationCode, module, activationCode, createTime, remark) VALUES (@applicant, @macAddress, @applicationCode, @module, @activationCode, @createTime, @remark)` ); insert.run({ ...data, applicant: data.applicant || '', remark: data.remark || '' }); return true; } /** * Delete one record by id. */ async removeById(id: number): Promise { const remove = this.db.prepare(`DELETE FROM ${this.tableName} WHERE id = ?`); remove.run(id); return true; } /** * Clear all records. */ async clear(): Promise { const clearStmt = this.db.prepare(`DELETE FROM ${this.tableName}`); clearStmt.run(); return true; } /** * Query record list. */ async list(macAddress: string = '', modules: string[] = []): Promise { let condition = ''; if (macAddress) { condition += ` AND macAddress = '${macAddress}'`; } if (modules.length > 0) { const moduleConditions = modules.map((module) => `module LIKE '%${module}%'`).join(' OR '); condition += ` AND (${moduleConditions})`; } const select = this.db.prepare(`SELECT * FROM ${this.tableName} WHERE 1 = 1 ${condition} order by id desc`); return select.all(); } /** * Export all records to a JSON backup file. */ async backup(filePath: string): Promise { const records = await this.getAllTestDataSqlite(); const payload = { version: 1, tableName: this.tableName, exportedAt: new Date().toISOString(), records }; fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8'); return records.length; } /** * Import backup and replace current records. */ async importBackup(filePath: string): Promise { const raw = fs.readFileSync(filePath, 'utf8'); const parsed = JSON.parse(raw); const inputRecords = Array.isArray(parsed) ? parsed : parsed.records; if (!Array.isArray(inputRecords)) { throw new Error('Invalid backup file'); } const records = inputRecords.map((item: any) => this.normalizeRecord(item)); const clearStmt = this.db.prepare(`DELETE FROM ${this.tableName}`); const insertStmt = this.db.prepare( `INSERT INTO ${this.tableName} (applicant, macAddress, applicationCode, module, activationCode, createTime, remark) VALUES (@applicant, @macAddress, @applicationCode, @module, @activationCode, @createTime, @remark)` ); const transaction = this.db.transaction((rows: ActivateRecordItem[]) => { clearStmt.run(); for (const row of rows) { insertStmt.run(row); } }); transaction(records); return records.length; } /** * Read all records. */ async getAllTestDataSqlite(): Promise { const selectAllUser = this.db.prepare(`SELECT * FROM ${this.tableName} ORDER BY id DESC`); return selectAllUser.all(); } /** * Get data directory. */ async getDataDir(): Promise { return this.storage.getDbDir(); } /** * Set custom data directory. */ async setCustomDataDir(dir: string): Promise { if (dir.length === 0) { return; } this.changeDataDir(dir); this.init(); } private normalizeRecord(item: any): ActivateRecordItem { return { applicant: typeof item?.applicant === 'string' ? item.applicant : '', macAddress: typeof item?.macAddress === 'string' ? item.macAddress : '', applicationCode: typeof item?.applicationCode === 'string' ? item.applicationCode : '', module: typeof item?.module === 'string' ? item.module : Array.isArray(item?.modules) ? item.modules.join(',') : '', activationCode: typeof item?.activationCode === 'string' ? item.activationCode : '', createTime: typeof item?.createTime === 'string' ? item.createTime : '', remark: typeof item?.remark === 'string' ? item.remark : '', }; } } ActivateRecordService.toString = () => '[class ActivateRecordService]'; const activateRecordService = new ActivateRecordService(); export { ActivateRecordService, activateRecordService };