chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore - 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using 報到系統客戶端.Data.Models;
|
||||
using 報到系統客戶端.Data.Repositories;
|
||||
using 報到系統客戶端.Models;
|
||||
using 報到系統客戶端.Services;
|
||||
|
||||
namespace 報到系統客戶端.Data.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 資料同步服務
|
||||
/// 協調後端 API 和本地 SQLite 資料庫的資料同步
|
||||
/// </summary>
|
||||
public class DataSyncService
|
||||
{
|
||||
private readonly ClassesRepository _classesRepo;
|
||||
private readonly SignUpsRepository _signUpsRepo;
|
||||
|
||||
public DataSyncService()
|
||||
{
|
||||
_classesRepo = new ClassesRepository();
|
||||
_signUpsRepo = new SignUpsRepository();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步 Classes 資料(從 API 到本地)
|
||||
/// </summary>
|
||||
public async Task<bool> SyncClassesFromApiAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 從 API 查詢資料
|
||||
var response = await ClassesService.SearchClassesAsync();
|
||||
|
||||
if (!response.Success)
|
||||
return false;
|
||||
|
||||
// 轉換資料
|
||||
dynamic dataObj = response.Data;
|
||||
if (dataObj == null)
|
||||
return false;
|
||||
|
||||
_classesRepo.DeleteAll();
|
||||
|
||||
// 插入資料
|
||||
foreach (var item in dataObj)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 轉換為本地模型
|
||||
var apiModel = (ClassesItem)item;
|
||||
var localItem = LocalClassesItem.ConvertFromApiModel(apiModel);
|
||||
|
||||
// 檢查是否已存在
|
||||
var existing = _classesRepo.GetById(localItem.ID);
|
||||
if (existing != null)
|
||||
{
|
||||
_classesRepo.Update(localItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_classesRepo.Insert(localItem);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略單筆資料錯誤,繼續同步其他資料
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"同步 Classes 資料失敗:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步 Classes 資料(同步版本)
|
||||
/// </summary>
|
||||
public bool SyncClassesFromApi()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 從 API 查詢資料
|
||||
var response = ClassesService.SearchClasses();
|
||||
|
||||
if (!response.Success)
|
||||
return false;
|
||||
|
||||
// 轉換資料
|
||||
dynamic dataObj = response.Data;
|
||||
if (dataObj == null)
|
||||
return false;
|
||||
|
||||
_classesRepo.DeleteAll();
|
||||
|
||||
// 插入資料
|
||||
foreach (var item in dataObj)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 轉換為本地模型
|
||||
var apiModel = (ClassesItem)item;
|
||||
var localItem = LocalClassesItem.ConvertFromApiModel(apiModel);
|
||||
|
||||
// 檢查是否已存在
|
||||
var existing = _classesRepo.GetById(localItem.ID);
|
||||
if (existing != null)
|
||||
{
|
||||
_classesRepo.Update(localItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_classesRepo.Insert(localItem);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略單筆資料錯誤,繼續同步其他資料
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"同步 Classes 資料失敗:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步 SignUps 資料(從 API 到本地)
|
||||
/// </summary>
|
||||
public async Task<bool> SyncSignUpsFromApiAsync(int courseID, int pageIndex, int pageSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 從 API 查詢資料
|
||||
var response = await SignUpService.SearchSignUpsAsync(pageIndex, pageSize, courseID);
|
||||
|
||||
if (!response.Success)
|
||||
return false;
|
||||
|
||||
// 轉換資料
|
||||
dynamic dataObj = response.Data;
|
||||
if (dataObj == null)
|
||||
return false;
|
||||
|
||||
// 如果第一頁,先清除該課程的本地資料
|
||||
if (pageIndex == 1)
|
||||
{
|
||||
var existingList = _signUpsRepo.GetByCourseID(courseID);
|
||||
foreach (var item in existingList)
|
||||
{
|
||||
_signUpsRepo.Delete(item.ID);
|
||||
}
|
||||
}
|
||||
|
||||
// 插入資料
|
||||
foreach (var item in dataObj)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 轉換為本地模型
|
||||
var apiModel = (SignUpItem)item;
|
||||
var localItem = LocalSignUpItem.ConvertFromApiModel(apiModel);
|
||||
|
||||
// 檢查是否已存在
|
||||
var existing = _signUpsRepo.GetById(localItem.ID);
|
||||
if (existing != null)
|
||||
{
|
||||
_signUpsRepo.Update(localItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_signUpsRepo.Insert(localItem);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略單筆資料錯誤,繼續同步其他資料
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"同步 SignUps 資料失敗:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步 SignUps 資料(同步版本)
|
||||
/// </summary>
|
||||
public bool SyncSignUpsFromApi(int courseID, int pageIndex, int pageSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 從 API 查詢資料
|
||||
var response = SignUpService.SearchSignUps(pageIndex, pageSize, courseID);
|
||||
|
||||
if (!response.Success)
|
||||
return false;
|
||||
|
||||
// 轉換資料
|
||||
dynamic dataObj = response.Data;
|
||||
if (dataObj == null)
|
||||
return false;
|
||||
|
||||
// 如果第一頁,先清除該課程的本地資料
|
||||
if (pageIndex == 1)
|
||||
{
|
||||
var existingList = _signUpsRepo.GetByCourseID(courseID);
|
||||
foreach (var item in existingList)
|
||||
{
|
||||
_signUpsRepo.Delete(item.ID);
|
||||
}
|
||||
}
|
||||
|
||||
// 插入資料
|
||||
foreach (var item in dataObj)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 轉換為本地模型
|
||||
var apiModel = (SignUpItem)item;
|
||||
var localItem = LocalSignUpItem.ConvertFromApiModel(apiModel);
|
||||
|
||||
// 檢查是否已存在
|
||||
var existing = _signUpsRepo.GetById(localItem.ID);
|
||||
if (existing != null)
|
||||
{
|
||||
_signUpsRepo.Update(localItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_signUpsRepo.Insert(localItem);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略單筆資料錯誤,繼續同步其他資料
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"同步 SignUps 資料失敗:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上傳本地 SignUps 簽到簽退資料到 API
|
||||
/// </summary>
|
||||
public async Task<bool> UploadSignUpsToApiAsync(int courseID)
|
||||
{
|
||||
try
|
||||
{
|
||||
var localItems = _signUpsRepo.GetByCourseID(courseID);
|
||||
if (localItems.Count == 0)
|
||||
return true;
|
||||
|
||||
// 轉換為 API 模型
|
||||
var apiItems = new List<SignUpItem>();
|
||||
foreach (var item in localItems)
|
||||
{
|
||||
apiItems.Add(LocalSignUpItem.ConvertToApiModel(item));
|
||||
}
|
||||
|
||||
// 上傳到 API
|
||||
var response = await SignUpService.UploadSignUpsAsync(courseID, apiItems);
|
||||
return response.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"上傳 SignUps 資料失敗:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上傳本地 SignUps 簽到簽退資料到 API(同步版本)
|
||||
/// </summary>
|
||||
public bool UploadSignUpsToApi(int courseID)
|
||||
{
|
||||
try
|
||||
{
|
||||
var localItems = _signUpsRepo.GetByCourseID(courseID);
|
||||
if (localItems.Count == 0)
|
||||
return true;
|
||||
|
||||
// 轉換為 API 模型
|
||||
var apiItems = new List<SignUpItem>();
|
||||
foreach (var item in localItems)
|
||||
{
|
||||
apiItems.Add(LocalSignUpItem.ConvertToApiModel(item));
|
||||
}
|
||||
|
||||
// 上傳到 API
|
||||
var response = SignUpService.UploadSignUps(courseID, apiItems);
|
||||
return response.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"上傳 SignUps 資料失敗:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有本地資料
|
||||
/// </summary>
|
||||
public void ClearAllLocalData()
|
||||
{
|
||||
try
|
||||
{
|
||||
DatabaseService.Instance.ClearAllTables();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"清除本地資料失敗:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取得 Classes Repository
|
||||
/// </summary>
|
||||
public ClassesRepository GetClassesRepository()
|
||||
{
|
||||
return _classesRepo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取得 SignUps Repository
|
||||
/// </summary>
|
||||
public SignUpsRepository GetSignUpsRepository()
|
||||
{
|
||||
return _signUpsRepo;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user