ArKTS: DAL,Model,BLL,Interface,Factory using SQLite

HarmonyOS 用@ohos.data.rdb 用DBHelper.ets 共用調用SQLite 庫,進行DAL,Model,BLL,Interface,Factory 框架模式,表為

CREATE TABLE IF NOT EXISTS signInRecord (
id INTEGER PRIMARY KEY AUTOINCREMENT,
employeeId TEXT NOT NULL,
employeeName TEXT NOT NULL,
signInTime TEXT NOT NULL
)

項目結構 :
UtilitieDB
--DBHelper.ets
DAL
--signIn.ets
Model
--signIn.ets
BLL
----signIn.ets
Interface
----IsignIn.ets
Factory
--AbstractFactory.ets

/*
# encoding: utf-8
# 版權所有  2025 ?涂聚文有限公司? ?
# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : DevEco Studio 5.1.1 HarmonyOS
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2025/7/22 19:11
# User      :  geovindu
# Product   : DevEco Studio
# Project   : MyApplication
# File      : signIn.ets
*/export interface SignInRecordDbObject {id?: number;employeeId: string;employeeName: string;signInTime: string;
}export class SignInRecord {id: number | null;employeeId: string;employeeName: string;signInTime: string;constructor(employeeId: string,employeeName: string,signInTime: string,id: number | null = null) {this.id = id;this.employeeId = employeeId;this.employeeName = employeeName;this.signInTime = signInTime;}// 轉換為數據庫存儲的對象格式(類型安全版本)toDbObject(): SignInRecordDbObject {const dbObject: SignInRecordDbObject = {employeeId: this.employeeId,employeeName: this.employeeName,signInTime: this.signInTime};if (this.id !== null) {dbObject.id = this.id;}return dbObject;}// 從數據庫對象創建模型實例(類型安全版本)static fromDbObject(dbObject: SignInRecordDbObject): SignInRecord {return new SignInRecord(dbObject.employeeId,dbObject.employeeName,dbObject.signInTime,dbObject.id !== undefined ? dbObject.id : null);}
}/*
# encoding: utf-8
# 版權所有  2025 ?涂聚文有限公司? ?
# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : DevEco Studio 5.1.1 HarmonyOS
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2025/7/22 19:04
# User      :  geovindu
# Product   : DevEco Studio
# Project   : MyApplication
# File      : DBHelper.ets
*/import relationalStore from '@ohos.data.relationalStore';
import { BusinessError } from '@ohos.base';
import { Context } from '@ohos.abilityAccessCtrl';export class DBHelper {private static readonly DB_NAME: string = 'signInDB.db';private static readonly DB_VERSION: number = 1;private rdbStore: relationalStore.RdbStore | null = null;private static instance: DBHelper | null = null;private context: Context | null = null; // 新增上下文存儲private constructor() {}/**** @returns*/public static getInstance(): DBHelper {if (!DBHelper.instance) {DBHelper.instance = new DBHelper();}if (!DBHelper.instance) {throw new Error('無法創建DBHelper實例,請檢查實現');}return DBHelper.instance;}/*** 初始化數據庫時保存上下文* @param context* @returns*/public async initDB(context: Context): Promise<relationalStore.RdbStore> {if (this.rdbStore) {return this.rdbStore;}/*** 保存上下文供后續使用*/this.context = context;const storeConfig: relationalStore.StoreConfig = {name: DBHelper.DB_NAME,securityLevel: relationalStore.SecurityLevel.S1};try {this.rdbStore = await relationalStore.getRdbStore(context, storeConfig);await this.createTables();return this.rdbStore;} catch (error) {const err = error as BusinessError;console.error(`初始化數據庫失敗: ${err.code} - ${err.message}`);throw new Error(`數據庫初始化失敗: ${err.message}`);}}/**** @returns*/private async createTables(): Promise<void> {if (!this.rdbStore) {throw new Error('數據庫未初始化,請先調用initDB方法');}const createTableSql: string = `CREATE TABLE IF NOT EXISTS signInRecord (id INTEGER PRIMARY KEY AUTOINCREMENT,employeeId TEXT NOT NULL,employeeName TEXT NOT NULL,signInTime TEXT NOT NULL)`;try {await this.rdbStore.executeSql(createTableSql);console.log('簽到記錄表創建成功或已存在');} catch (error) {const err = error as BusinessError;console.error(`創建簽到記錄表失敗: ${err.code} - ${err.message}`);throw new Error(`創建數據表失敗: ${err.message}`);}}/**** @returns*/public getRdbStore(): relationalStore.RdbStore | null {if (!this.rdbStore) {console.warn('數據庫尚未初始化,請先調用initDB方法');}return this.rdbStore;}/*** 修正關閉數據庫的方法* @returns*/public async closeDB(): Promise<void> {if (this.rdbStore && this.context) {try {// 正確調用deleteRdbStore,需要傳入上下文和數據庫名稱await relationalStore.deleteRdbStore(this.context, DBHelper.DB_NAME);this.rdbStore = null;this.context = null; // 清除上下文console.log('數據庫已關閉并刪除');} catch (error) {const err = error as BusinessError;console.error(`關閉數據庫失敗: ${err.code} - ${err.message}`);throw new Error(`關閉數據庫失敗: ${err.message}`);}} else {if (!this.context) {console.warn('上下文不存在,無法關閉數據庫');} else {console.warn('數據庫連接不存在,無需關閉');}}}
}/*
# encoding: utf-8
# 版權所有  2025 ?涂聚文有限公司? ?
# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : DevEco Studio 5.1.1 HarmonyOS
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2025/7/22 19:14
# User      :  geovindu
# Product   : DevEco Studio
# Project   : MyApplication
# File      : IsignIn.ets
*/import { SignInRecord } from '../model/signIn';export interface ISignIn {/*** 添加簽到記錄* @param record* @returns*/addSignInRecord(record: SignInRecord): Promise<number>;/*** 根據ID獲取簽到記錄* @param id* @returns*/getSignInRecordById(id: number): Promise<SignInRecord | null>;/*** 獲取所有簽到記錄* @returns*/getAllSignInRecords(): Promise<SignInRecord[]>;/*** 根據員工ID獲取簽到記錄* @param employeeId* @returns*/getSignInRecordsByEmployeeId(employeeId: string): Promise<SignInRecord[]>;/*** 更新簽到記錄* @param record* @returns*/updateSignInRecord(record: SignInRecord): Promise<number>;/*** 刪除簽到記錄* @param id* @returns*/deleteSignInRecord(id: number): Promise<number>;
}/*
# encoding: utf-8
# 版權所有  2025 ?涂聚文有限公司? ?
# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : DevEco Studio 5.1.1 HarmonyOS
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2025/7/22 19:16
# User      :  geovindu
# Product   : DevEco Studio
# Project   : MyApplication
# File      : AbstractFactory.ets
*/
import { ISignIn } from '../Interface/IsignIn';
import { SignInDAL } from '../DAL/signIn';
import { SignInBLL } from '../BLL/signIn';/*** 抽象工廠類*/
export abstract class AbstractFactory {// 創建數據訪問層實例public abstract createSignInDAL(): ISignIn;// 創建業務邏輯層實例public abstract createSignInBLL(): ISignIn;
}/*** 簽到記錄工廠類*/
export class SignInFactory extends AbstractFactory {// 創建簽到記錄數據訪問層實例public createSignInDAL(): ISignIn {return new SignInDAL();}/*** 創建簽到記錄業務邏輯層實例* @returns*/public createSignInBLL(): ISignIn {// 可以在這里注入不同的DAL實現,方便測試或切換數據源const dal = this.createSignInDAL();return new SignInBLL(dal);}
}/*
# encoding: utf-8
# 版權所有  2025 ?涂聚文有限公司? ?
# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : DevEco Studio 5.1.1 HarmonyOS
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2025/7/22 19:17
# User      :  geovindu
# Product   : DevEco Studio
# Project   : MyApplication
# File      : signIn.ets
*/
import relationalStore from '@ohos.data.relationalStore';
import { DBHelper } from '../UtilitieDB/DBHelper';
import { SignInRecord, SignInRecordDbObject } from '../model/signIn';
import { ISignIn } from '../Interface/IsignIn';
import { BusinessError } from '@ohos.base';// 定義與數據庫字段對應的類型映射
type SignInColumn = 'id' | 'employeeId' | 'employeeName' | 'signInTime';export class SignInDAL implements ISignIn {private getRdbStore() {const rdbStore = DBHelper.getInstance().getRdbStore();if (!rdbStore) {throw new Error('數據庫未初始化,請先調用initDB方法');}return rdbStore;}/*** 添加簽到記錄* @param record* @returns*/async addSignInRecord(record: SignInRecord): Promise<number> {try {const dbObject = record.toDbObject();// 構建符合要求的ValuesBucketconst valuesBucket: relationalStore.ValuesBucket = {'employeeId': dbObject.employeeId,'employeeName': dbObject.employeeName,'signInTime': dbObject.signInTime};const rowId = await this.getRdbStore().insert('signInRecord', valuesBucket);return rowId;} catch (error) {const err = error as BusinessError;console.error(`添加簽到記錄失敗: ${err.code} - ${err.message}`);throw new Error(`添加簽到記錄失敗: ${err.message}`);}}/*** 根據ID獲取簽到記錄* @param id* @returns*/async getSignInRecordById(id: number): Promise<SignInRecord | null> {try {const predicates = new relationalStore.RdbPredicates('signInRecord');predicates.equalTo('id', id);const resultSet = await this.getRdbStore().query(predicates, ['*']);let record: SignInRecord | null = null;if (await resultSet.goToFirstRow()) {const dbObject: SignInRecordDbObject = {id: resultSet.getLong(resultSet.getColumnIndex('id')),employeeId: resultSet.getString(resultSet.getColumnIndex('employeeId')),employeeName: resultSet.getString(resultSet.getColumnIndex('employeeName')),signInTime: resultSet.getString(resultSet.getColumnIndex('signInTime'))};record = SignInRecord.fromDbObject(dbObject);}await resultSet.close();return record;} catch (error) {const err = error as BusinessError;console.error(`查詢簽到記錄失敗: ${err.code} - ${err.message}`);throw new Error(`查詢簽到記錄失敗: ${err.message}`);}}/*** 根據員工ID獲取簽到記錄* @param employeeId* @returns*/async getSignInRecordsByEmployeeId(employeeId: string): Promise<SignInRecord[]> {try {const predicates = new relationalStore.RdbPredicates('signInRecord');predicates.equalTo('employeeId', employeeId).orderByDesc('signInTime');const resultSet = await this.getRdbStore().query(predicates, ['*']);const records: SignInRecord[] = [];while (await resultSet.goToNextRow()) {const dbObject: SignInRecordDbObject = {id: resultSet.getLong(resultSet.getColumnIndex('id')),employeeId: resultSet.getString(resultSet.getColumnIndex('employeeId')),employeeName: resultSet.getString(resultSet.getColumnIndex('employeeName')),signInTime: resultSet.getString(resultSet.getColumnIndex('signInTime'))};records.push(SignInRecord.fromDbObject(dbObject));}await resultSet.close();return records;} catch (error) {const err = error as BusinessError;console.error(`根據員工ID查詢簽到記錄失敗: ${err.code} - ${err.message}`);throw new Error(`根據員工ID查詢簽到記錄失敗: ${err.message}`);}}/*** 獲取所有簽到記錄* @returns*/async getAllSignInRecords(): Promise<SignInRecord[]> {try {const predicates = new relationalStore.RdbPredicates('signInRecord');predicates.orderByDesc('signInTime');const resultSet = await this.getRdbStore().query(predicates, ['*']);const records: SignInRecord[] = [];while (await resultSet.goToNextRow()) {const dbObject: SignInRecordDbObject = {id: resultSet.getLong(resultSet.getColumnIndex('id')),employeeId: resultSet.getString(resultSet.getColumnIndex('employeeId')),employeeName: resultSet.getString(resultSet.getColumnIndex('employeeName')),signInTime: resultSet.getString(resultSet.getColumnIndex('signInTime'))};records.push(SignInRecord.fromDbObject(dbObject));}await resultSet.close();return records;} catch (error) {const err = error as BusinessError;console.error(`獲取所有簽到記錄失敗: ${err.code} - ${err.message}`);throw new Error(`獲取所有簽到記錄失敗: ${err.message}`);}}/*** 更新簽到記錄* @param record* @returns*/async updateSignInRecord(record: SignInRecord): Promise<number> {if (record.id === null) {throw new Error('更新失敗,簽到記錄ID不能為空');}try {const dbObject = record.toDbObject();const predicates = new relationalStore.RdbPredicates('signInRecord');predicates.equalTo('id', record.id); // 這里已經指定了要更新的記錄ID// 構建ValuesBucket,不包含id字段,因為不需要更新主鍵const valuesBucket: relationalStore.ValuesBucket = {'employeeId': dbObject.employeeId,'employeeName': dbObject.employeeName,'signInTime': dbObject.signInTime};// 執行更新操作const rowsUpdated = await this.getRdbStore().update(valuesBucket, predicates);return rowsUpdated;} catch (error) {const err = error as BusinessError;console.error(`更新簽到記錄失敗: ${err.code} - ${err.message}`);throw new Error(`更新簽到記錄失敗: ${err.message}`);}}/*** 刪除簽到記錄* @param id* @returns*/async deleteSignInRecord(id: number): Promise<number> {try {const predicates = new relationalStore.RdbPredicates('signInRecord');predicates.equalTo('id', id);const rowsDeleted = await this.getRdbStore().delete(predicates);return rowsDeleted;} catch (error) {const err = error as BusinessError;console.error(`刪除簽到記錄失敗: ${err.code} - ${err.message}`);throw new Error(`刪除簽到記錄失敗: ${err.message}`);}}/*** 將結果集轉換為簽到記錄數組* @param resultSet* @returns*/private convertResultSetToSignInRecords(resultSet: relationalStore.ResultSet): SignInRecord[] {const records: SignInRecord[] = [];resultSet.goToFirstRow();do {const record = this.convertResultSetToSignInRecord(resultSet);records.push(record);} while (resultSet.goToNextRow());return records;}/*** 結果集轉換為單個簽到記錄* @param resultSet* @returns*/private convertResultSetToSignInRecord(resultSet: relationalStore.ResultSet): SignInRecord {return new SignInRecord(resultSet.getString(resultSet.getColumnIndex('employeeId')),resultSet.getString(resultSet.getColumnIndex('employeeName')),resultSet.getString(resultSet.getColumnIndex('signInTime')),resultSet.getLong(resultSet.getColumnIndex('id')));}}/*
# encoding: utf-8
# 版權所有  2025 ?涂聚文有限公司? ?
# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : DevEco Studio 5.1.1 HarmonyOS
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2025/7/22 18:18
# User      :  geovindu
# Product   : DevEco Studio
# Project   : MyApplication
# File      : signIn.ets
*/
import { ISignIn } from '../Interface/IsignIn';
import { SignInRecord } from '../model/signIn';
import { SignInDAL } from '../DAL/signIn';export class SignInBLL implements ISignIn {private signInDAL: ISignIn;constructor(signInDAL: ISignIn = new SignInDAL()) {this.signInDAL = signInDAL;}/*** 添加簽到記錄,包含業務邏輯驗證* @param record* @returns*/async addSignInRecord(record: SignInRecord): Promise<number> {// 業務邏輯驗證:檢查必要字段if (!record.employeeId || record.employeeId.trim() === '') {throw new Error('員工ID不能為空');}if (!record.employeeName || record.employeeName.trim() === '') {throw new Error('員工姓名不能為空');}// 檢查簽到時間格式是否合法if (!this.isValidDateTime(record.signInTime)) {throw new Error('簽到時間格式不正確');}// 調用數據訪問層添加記錄return this.signInDAL.addSignInRecord(record);}/*** 根據ID獲取簽到記錄* @param id* @returns*/async getSignInRecordById(id: number): Promise<SignInRecord | null> {if (id <= 0) {throw new Error('無效的記錄ID');}return this.signInDAL.getSignInRecordById(id);}/*** 獲取所有簽到記錄* @returns*/async getAllSignInRecords(): Promise<SignInRecord[]> {return this.signInDAL.getAllSignInRecords();}/*** 根據員工ID獲取簽到記錄* @param employeeId* @returns*/async getSignInRecordsByEmployeeId(employeeId: string): Promise<SignInRecord[]> {if (!employeeId || employeeId.trim() === '') {throw new Error('員工ID不能為空');}return this.signInDAL.getSignInRecordsByEmployeeId(employeeId);}/*** 更新簽到記錄* @param record* @returns*/async updateSignInRecord(record: SignInRecord): Promise<number> {if (!record.id) {throw new Error('簽到記錄ID不能為空');}/*** 驗證更新的數據*/if (!record.employeeId || record.employeeId.trim() === '') {throw new Error('員工ID不能為空');}if (!this.isValidDateTime(record.signInTime)) {throw new Error('簽到時間格式不正確');}return this.signInDAL.updateSignInRecord(record);}/*** 刪除簽到記錄* @param id* @returns*/async deleteSignInRecord(id: number): Promise<number> {if (id <= 0) {throw new Error('無效的記錄ID');}return this.signInDAL.deleteSignInRecord(id);}// 驗證日期時間格式 (YYYY-MM-DD HH:MM:SS)private isValidDateTime(dateTime: string): boolean {const regex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;return regex.test(dateTime);}
}/*
# encoding: utf-8
# 版權所有  2025 ?涂聚文有限公司? ?
# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : DevEco Studio 5.1.1 HarmonyOS
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2025/7/22 18:56
# User      :  geovindu
# Product   : DevEco Studio
# Project   : MyApplication
# File      : SignInExample.ets
*/
import { Context } from '@ohos.abilityAccessCtrl';
import { SignInFactory } from '../Factory/AbstractFactory';
import { DBHelper } from '../UtilitieDB/DBHelper';
import { SignInRecord } from '../model/signIn';
import { ISignIn } from '../Interface/IsignIn';export class SignInExample {private signInBLL: ISignIn;constructor(context: Context) {// 初始化數據庫this.initDatabase(context);// 通過工廠獲取BLL實例const factory = new SignInFactory();this.signInBLL = factory.createSignInBLL();}/*** 初始化數據庫* @param context*/private async initDatabase(context: Context) {try {await DBHelper.getInstance().initDB(context);console.log('數據庫初始化成功');} catch (error) {console.error('數據庫初始化失敗:', error);}}/*** 添加簽到記錄示例* @returns*/async addSignInRecordExample() {try {// 創建簽到記錄對象const now = new Date();const signInTime = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')} ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;const record = new SignInRecord('EMP001',       // employeeId'張三',          // employeeNamesignInTime       // signInTime);// 調用BLL層添加記錄const rowId = await this.signInBLL.addSignInRecord(record);console.log(`添加簽到記錄成功,ID: ${rowId}`);return rowId;} catch (error) {console.error('添加簽到記錄失敗:', error);return null;}}/*** 查詢簽到記錄示例*/async querySignInRecordsExample() {try {// 1. 查詢所有簽到記錄const allRecords = await this.signInBLL.getAllSignInRecords();console.log(`所有簽到記錄(${allRecords.length}條):`, allRecords);// 2. 根據ID查詢記錄(假設我們知道一個存在的ID)if (allRecords.length > 0) {const firstRecordId = allRecords[0].id;if (firstRecordId !== null) {const singleRecord = await this.signInBLL.getSignInRecordById(firstRecordId);console.log(`ID為${firstRecordId}的簽到記錄:`, singleRecord);}}// 3. 根據員工ID查詢記錄const empRecords = await this.signInBLL.getSignInRecordsByEmployeeId('EMP001');console.log(`員工EMP001的簽到記錄(${empRecords.length}條):`, empRecords);return allRecords;} catch (error) {console.error('查詢簽到記錄失敗:', error);return null;}}/**** @param id* @returns*/async querySignInRecordsExampleId(id:string) {try {// 1. 查詢所有簽到記錄const allRecords = await this.signInBLL.getSignInRecordsByEmployeeId(id);console.log(`所有簽到記錄(${allRecords.length}條):`, allRecords);// 2. 根據ID查詢記錄(假設我們知道一個存在的ID)if (allRecords.length > 0) {const firstRecordId = allRecords[0].id;if (firstRecordId !== null) {const singleRecord = await this.signInBLL.getSignInRecordById(firstRecordId);console.log(`ID為${firstRecordId}的簽到記錄:`, singleRecord);}}// 3. 根據員工ID查詢記錄const empRecords = await this.signInBLL.getSignInRecordsByEmployeeId('EMP001');console.log(`員工EMP001的簽到記錄(${empRecords.length}條):`, empRecords);return allRecords;} catch (error) {console.error('查詢簽到記錄失敗:', error);return null;}}/*** 更新簽到記錄示例* @param recordId*/async updateSignInRecordExample(recordId: number) {try {// 先查詢要更新的記錄const record = await this.signInBLL.getSignInRecordById(recordId);if (!record) {console.log(`未找到ID為${recordId}的簽到記錄`);return -1;}// 修改記錄內容record.employeeName = '張三(更新)'; // 修改員工姓名// 調用BLL層更新記錄const rowsUpdated = await this.signInBLL.updateSignInRecord(record);console.log(`更新成功,影響行數: ${rowsUpdated}`);// 驗證更新結果const updatedRecord = await this.signInBLL.getSignInRecordById(recordId);console.log('更新后的記錄:', updatedRecord);return 1;} catch (error) {console.error('更新簽到記錄失敗:', error);return -1;}}/*** 刪除簽到記錄示例* @param recordId*/async deleteSignInRecordExample(recordId: number) {try {// 調用BLL層刪除記錄const rowsDeleted = await this.signInBLL.deleteSignInRecord(recordId);console.log(`刪除成功,影響行數: ${rowsDeleted}`);// 驗證刪除結果const deletedRecord = await this.signInBLL.getSignInRecordById(recordId);if (!deletedRecord) {console.log(`ID為${recordId}的簽到記錄已成功刪除`);}return 1;} catch (error) {console.error('刪除簽到記錄失敗:', error);return -1;}}/*** 完整操作流程示例*/async completeOperationFlow() {// 1. 添加一條新記錄const newRecordId = await this.addSignInRecordExample();if (newRecordId) {// 2. 查詢記錄await this.querySignInRecordsExample();// 3. 更新記錄await this.updateSignInRecordExample(newRecordId);// 4. 刪除記錄await this.deleteSignInRecordExample(newRecordId);}// 關閉數據庫(通常在應用退出時調用)// await DBHelper.getInstance().closeDB();}
}// 在Ability中使用示例
// export default class SignInAbility extends Ability {
//   onWindowStageCreate(windowStage: window.WindowStage) {
//     // 初始化示例并執行操作
//     const signInExample = new SignInExample(this.context);
//     signInExample.completeOperationFlow();
//   }
// }

調用:

/**# encoding: utf-8# 版權所有 2024 ?涂聚文有限公司# 許可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎# 描述:# Author    : geovindu,Geovin Du 涂聚文.# IDE       : DevEco Studio 5.1.1# OS        : windows 10# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j# Datetime  : 2025/7/22 19:33# User      : geovindu# Product   : MyApplicatin# Project   : MyApplicatin# File      : Register.ets* */import router from '@ohos.router'
import promptAction from '@ohos.promptAction'
import { SignInExample } from '../Controller/SignInExample';
import { SignInRecord } from '../model/signIn';
import { Context } from '@ohos.abilityAccessCtrl';@Entry
@Component
struct Register {@State message: string = '注冊用戶';// 頁面數據@State allRecords: SignInRecord[] = [];@State employeeId: string = 'EMP001';@State employeeName: string = '張三';@State currentRecordId: number | null = null;// 頁面上下文(用于數據庫初始化)private context: Context = getContext(this) as Context;// 簽到業務實例private signInExample: SignInExample = new SignInExample(this.context);// 頁面加載時初始化數據async aboutToAppear() {await this.loadAllRecords(); // 加載所有簽到記錄}// 加載所有簽到記錄// 修正后的加載所有簽到記錄方法async loadAllRecords() {try {// 調用查詢方法并獲取結果const result = await this.signInExample.querySignInRecordsExample();// 空值判斷:如果結果為null,設置為空數組if (result === null) {this.allRecords = [];promptAction.showToast({ message: '沒有查詢到簽到記錄' });return;}// 類型判斷:確保返回的是數組if (!Array.isArray(result)) {this.allRecords = [];promptAction.showToast({ message: '數據格式錯誤' });console.error('查詢簽到記錄返回非數組類型:', result);return;}// 正常賦值this.allRecords = result;// 空數組提示if (this.allRecords.length === 0) {promptAction.showToast({ message: '當前沒有簽到記錄' });}} catch (error) {// 錯誤處理:統一捕獲并處理所有可能的異常this.allRecords = []; // 出錯時清空列表const errorMsg = error instanceof Error ? error.message : String(error);promptAction.showToast({ message: `加載失敗: ${errorMsg}` });console.error('加載簽到記錄失敗:', error);}}/*** 添加簽到記錄(綁定按鈕點擊事件)*/async handleAdd() {if (!this.employeeId || !this.employeeName) {promptAction.showToast({ message: '請輸入員工ID和姓名' });return;}try {// 生成當前時間(格式:yyyy-MM-dd HH:mm:ss)const now = new Date();const signInTime = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')} ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;// 創建記錄并添加const record = new SignInRecord(this.employeeId, this.employeeName, signInTime);const newId = await this.signInExample.addSignInRecordExample(); //recordpromptAction.showToast({ message: `添加成功,ID: ${newId}` });// 刷新列表await this.loadAllRecords();} catch (error) {promptAction.showToast({ message: `添加失敗: ${error.message}` });}}/*** 更新簽到記錄(綁定按鈕點擊事件)* @param record*/async handleUpdate(record: SignInRecord) {if (!record.id) {promptAction.showToast({ message: '記錄ID不存在' });return;}try {// 修改記錄(示例:在姓名后加"[已更新]")const updatedRecord = new SignInRecord(record.employeeId,`${record.employeeName}[已更新]`,record.signInTime,record.id);// 執行更新const rows = await this.signInExample.updateSignInRecordExample(1) //(updatedRecord);if (rows > 0) {promptAction.showToast({ message: '更新成功' });await this.loadAllRecords(); // 刷新列表}} catch (error) {promptAction.showToast({ message: `更新失敗: ${error.message}` });}}/*** 刪除簽到記錄(綁定按鈕點擊事件)* @param id*/async handleDelete(id: number) {try {const rows = await this.signInExample.deleteSignInRecordExample(id);if (rows > 0) {promptAction.showToast({ message: '刪除成功' });await this.loadAllRecords(); // 刷新列表}} catch (error) {promptAction.showToast({ message: `刪除失敗: ${error.message}` });}}/*** 根據員工ID查詢(綁定按鈕點擊事件)*/async handleQueryByEmpId() {// 驗證員工ID輸入if (!this.employeeId || this.employeeId.trim() === '') {promptAction.showToast({ message: '請輸入有效的員工ID' });return;}try {// 調用BLL層方法查詢(修正方法名和調用方式)const result = await this.signInExample.querySignInRecordsExampleId(this.employeeId.trim());// 空值判斷if (result === null) {this.allRecords = [];promptAction.showToast({ message: '未查詢到相關記錄' });return;}// 類型驗證if (!Array.isArray(result)) {this.allRecords = [];promptAction.showToast({ message: '查詢數據格式錯誤' });console.error('員工簽到記錄查詢返回非數組類型:', result);return;}// 賦值并提示結果this.allRecords = result;// 根據結果數量顯示不同提示if (this.allRecords.length === 0) {promptAction.showToast({ message: `未查詢到員工${this.employeeId}的簽到記錄` });} else {promptAction.showToast({ message: `查詢到${this.allRecords.length}條記錄` });}} catch (error) {// 錯誤處理this.allRecords = [];const errorMsg = error instanceof Error ? error.message : String(error);promptAction.showToast({ message: `查詢失敗: ${errorMsg}` });console.error(`查詢員工${this.employeeId}的簽到記錄失敗:`, error);}}// 界面渲染build() {Column() {// 操作區域Column() {Text('簽到管理').fontSize(20).fontWeight(FontWeight.Bold).margin(10);// 輸入區域Row() {Button('添加簽到').onClick(() => this.handleAdd()).backgroundColor('#007DFF');Button('查詢該員工').onClick(() => this.handleQueryByEmpId()).backgroundColor('#00B42A');Button('查詢所有').onClick(() => this.loadAllRecords()).backgroundColor('#F53F3F');Button('返回').onClick(() => {router.back();}).backgroundColor('#F53F3F');}.margin(10);// 記錄列表Scroll() {List() {ForEach(this.allRecords, (record: SignInRecord) => {ListItem() {Row() {Column() {Text(`ID: ${record.id}`).fontSize(12);Text(`員工: ${record.employeeName}(${record.employeeId})`).fontSize(14);Text(`簽到時間: ${record.signInTime}`).fontSize(12);}.width('70%');Column() {Button('修改').onClick(() => this.handleUpdate(record)).width(80).margin(5).backgroundColor('#FF7D00');Button('刪除').onClick(() => this.handleDelete(record.id!)).width(80).margin(5).backgroundColor('#F53F3F');}}.padding(10);}})}}.width('100%').flexGrow(1);}.width('100%').height('100%');}.width('100%').height('100%');}
}

輸出:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92458.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92458.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92458.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL JSON 數據類型用法及與傳統JSON字符串的對比 JSON數據類型簡介

文章目錄前言1. 基本用法JSON數據類型 vs 傳統JSON字符串1. 存儲方式2. 查詢方式對比3. 索引支持JSON存儲對象和數組的性能考慮1. 存儲對象2. 存儲數組性能對比總結最佳實踐建議前言 MySQL從 5.7 版本開始引入了 JSON 數據類型&#xff0c;專門用于存儲 JSON 格式的數據。與傳…

C++:list(1)list的使用

list的使用一.list基本的結構1.環狀雙向鏈表2.哨兵節點3.迭代器4.節點結構5.鏈表遍歷6.迭代器失效二.list的基本使用1.test01函數&#xff1a;主要測試std::list的初始化方式及遍歷2.test02函數&#xff1a;主要測試std::list的常用成員函數操作3.測試結果如下三.list的其他操作…

ArcGIS地形起伏度計算

地形起伏度計算地形起伏度步驟1&#xff1a;計算最大值。步驟2&#xff1a;計算最小值。步驟3&#xff1a;計算地形起伏度。地形起伏度、地形粗糙度、地表切割深度和高程變異系數均為坡面復雜度因子&#xff0c;是一種宏觀的地形信息因子&#xff0c;反映的是較大的區域內地表坡…

llama factory新手初步運行完整版

1、新建conda環境名稱為llama_factory&#xff0c;并激活 conda create -n llama_factory python3.10 conda activate llama_factory2、激活后可檢查內部包是否純凈&#xff0c;要確保環境內包較純凈&#xff0c;不然后續安裝對應包會出現一系列水土不服的問題&#xff0c;導致…

Tomcat與JDK版本對照全解析:避坑指南與生產環境選型最佳實踐

&#x1f49d;&#x1f49d;&#x1f49d;歡迎蒞臨我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 持續學習&#xff0c;不斷…

短視頻矩陣的未來前景:機遇無限,挑戰并存

在當今數字化信息飛速傳播的時代&#xff0c;短視頻以其獨特的魅力迅速席卷全球&#xff0c;成為人們獲取信息、娛樂消遣的重要方式之一。短視頻矩陣作為一種高效的內容傳播與運營模式&#xff0c;正逐漸展現出其強大的影響力和潛力。本文將深入探討短視頻矩陣的未來前景&#…

【數據結構】哈希——位圖與布隆過濾器

目錄 位圖&#xff1a; 引入 位圖實現&#xff1a; 位圖的結構 插入數據(標記數據) 刪除數據(重置數據) 查找數據 位圖完整代碼&#xff1a; 位圖的優缺點&#xff1a; 布隆過濾器&#xff1a; 引入 布隆過濾器實現&#xff1a; 布隆過濾器的結構&#xff1a; 插入…

本地運行C++版StableDiffusion!開源應用StableVerce發布

本地運行C版StableDiffusion&#xff01;開源應用StableVerce發布 StableVerse是一個用C開發的本地運行的圖形工具。適合初學者快速入門&#xff1b;適用于辦公室工作人員的文本和圖像制作的小規模計算能力場景。 開源地址&#xff1a;https://github.com/kelvin-luo/StableVer…

OpenLayers 快速入門(七)矢量數據

看過的知識不等于學會。唯有用心總結、系統記錄&#xff0c;并通過溫故知新反復實踐&#xff0c;才能真正掌握一二 作為一名摸爬滾打三年的前端開發&#xff0c;開源社區給了我飯碗&#xff0c;我也將所學的知識體系回饋給大家&#xff0c;助你少走彎路&#xff01; OpenLayers…

【PTA數據結構 | C語言版】關于堆的判斷

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 將一系列給定數字順序插入一個初始為空的最小堆。隨后判斷一系列相關命題是否為真。命題分下列幾種&#xff1a; x is the root&#xff1a;x是根結點&#xff1b;x and y are siblings&#xff1a…

[CH582M入門第十步]藍牙從機

前言 學習目標: 1、初步了解BLE協議 2、BLE從機代碼解析 3、使用手機藍牙軟件控制CH582M從機LED亮滅一、藍牙介紹 藍牙(Bluetooth)是一種短距離無線通信技術,主要用于設備之間的數據傳輸和通信。它由愛立信(Ericsson)于1994年提出,現由藍牙技術聯盟(Bluetooth SIG)維…

力扣(LeetCode) ——輪轉數組(C語言)

題目&#xff1a;輪轉數組 給定一個整數數組 nums&#xff0c;將數組中的元素向右輪轉 k 個位置&#xff0c;其中 k 是非負數。 示例1&#xff1a; 輸入&#xff1a; nums [1,2,3,4,5,6,7]&#xff0c;k 3 輸出&#xff1a; [5,6,7,1,2,3,4] 解釋&#xff1a; 向右輪轉 1 步:…

Rocky9部署Zabbix7(小白的“升級打怪”成長之路)

目錄 一、關閉防火墻和SElinux和配置安裝源 二、zabbxi服務器配置 1、安裝Zabbix server&#xff0c;Web前端&#xff0c;agent &#xff0c;mysql-server 2、配置mysql數據庫 3、為Zabbix server配置數據庫 4、啟動對應服務 三、登錄zabbix 四、客戶端部署 五、解決中…

python安裝package和pycharm更改環境變量

安裝numpy包 1、找到對應python版本的numpy包的版本 NumPy - News確認適配python版本的numpy&#xff0c;我安裝 的python是3.11所以安裝的numpy是2.2.0 2、修改pip安裝的鏡像源 1、全局修改&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.c…

Redis中的setnx命令為什么是原子性的

Redis的SETNX命令是一個原子性操作&#xff0c;這得益于其單線程架構的特性。Redis采用單線程模型&#xff0c;所有命令都在主線程中順序執行&#xff0c;確保每個操作都具有原子性。執行SETNX時&#xff0c;Redis會首先檢查指定key是否存在&#xff1a;若不存在則設置值并返回…

深入解析Hadoop中的EditLog與FsImage持久化設計及Checkpoint機制

HDFS元數據管理概述在HDFS&#xff08;Hadoop Distributed File System&#xff09;的架構中&#xff0c;元數據管理是保證系統可靠性和性能的核心環節。NameNode作為HDFS的主節點&#xff0c;負責維護整個文件系統的命名空間和文件到數據塊的映射關系。這些元數據的高效管理直…

MFC類Qt的自動布局框架

由于作者習慣使用Qt&#xff0c;習慣了其框架下的水平和垂直布局。但在使用MFC時&#xff0c;卻發現并沒有十分好用的布局框架&#xff0c;檢索了部分資料&#xff0c;發現要么不提供源碼&#xff0c;要么方案不理想。搜索了很多資料&#xff0c;最終發現一個可用方案&#xff…

認識Transformer架構

一.前言前面我們介紹了RNN相關系列的模型&#xff0c;在當今大模型時代大家認識一下就好了&#xff0c;而本章節我們是要來介紹一下重中之重的Transformer模型&#xff0c;本章節就來介紹一下他的架構&#xff0c;了解Transformer模型的作?以及了解Transformer總體架構圖中各個…

Python學習之存數據

在得到了對應的數據之后可以考慮用文件或者數據庫的方式把內容持久化下來方便之后的分析&#xff0c;此時可以使用pymongo庫&#xff0c;寥寥幾行代碼&#xff0c;數據就已經很好地存儲下來。&#xff08;此處可參考我們之前發的文章)在 Python 中引入&#xff1a;import pymon…

PointLLM - ECCV 2024 Best Paper Candidate

https://github.com/OpenRobotLab/PointLLM PointLLM: Empowering Large Language Models to Understand Point Clouds 核心問題 對比兩種讓大型語言模型&#xff08;LLM&#xff09;“看懂”三維世界的方法 間接方法&#xff1a;通過2D圖像進行猜測。 這是目前比較常見但充…