207 lines
6.8 KiB
TypeScript
207 lines
6.8 KiB
TypeScript
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<boolean> {
|
|
const remove = this.db.prepare(`DELETE
|
|
FROM ${this.tableName}
|
|
WHERE id = ?`);
|
|
remove.run(id);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Clear all records.
|
|
*/
|
|
async clear(): Promise<boolean> {
|
|
const clearStmt = this.db.prepare(`DELETE FROM ${this.tableName}`);
|
|
clearStmt.run();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Query record list.
|
|
*/
|
|
async list(macAddress: string = '', modules: string[] = []): Promise<any[]> {
|
|
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<number> {
|
|
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<number> {
|
|
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<any[]> {
|
|
const selectAllUser = this.db.prepare(`SELECT *
|
|
FROM ${this.tableName}
|
|
ORDER BY id DESC`);
|
|
return selectAllUser.all();
|
|
}
|
|
|
|
/**
|
|
* Get data directory.
|
|
*/
|
|
async getDataDir(): Promise<string> {
|
|
return this.storage.getDbDir();
|
|
}
|
|
|
|
/**
|
|
* Set custom data directory.
|
|
*/
|
|
async setCustomDataDir(dir: string): Promise<void> {
|
|
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
|
|
};
|