chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore - 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using 報到系統客戶端.Models;
|
||||
|
||||
namespace 報到系統客戶端.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// API 服務基礎類別
|
||||
/// 處理 HTTP 請求、Session cookie、錯誤處理
|
||||
/// </summary>
|
||||
public class ApiService
|
||||
{
|
||||
private static ApiService _instance;
|
||||
private static readonly object _lockObject = new object();
|
||||
|
||||
private string _baseUrl;
|
||||
private CookieContainer _cookieContainer;
|
||||
|
||||
// 用於儲存 cookie 的檔案路徑
|
||||
private string _cookiePath;
|
||||
|
||||
public static JsonSerializerSettings jsonConvertSettings = new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Local };
|
||||
|
||||
public static object DeserializeObject(string value)
|
||||
{
|
||||
return JsonConvert.DeserializeObject(value, jsonConvertSettings);
|
||||
}
|
||||
public static T DeserializeObject<T>(string value)
|
||||
{
|
||||
return (T)JsonConvert.DeserializeObject(value, typeof(T), jsonConvertSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取得單例實例
|
||||
/// </summary>
|
||||
public static ApiService Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new ApiService();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private ApiService()
|
||||
{
|
||||
// 從設定檔讀取基底 URL
|
||||
_baseUrl = ConfigService.Instance.GetApiBaseUrl();
|
||||
if (string.IsNullOrWhiteSpace(_baseUrl))
|
||||
{
|
||||
_baseUrl = "http://localhost:58792";
|
||||
}
|
||||
|
||||
// 初始化 Cookie 容器
|
||||
_cookieContainer = new CookieContainer();
|
||||
_cookiePath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"報到系統客戶端",
|
||||
"cookies.txt"
|
||||
);
|
||||
|
||||
// 嘗試載入已儲存的 Cookie
|
||||
LoadCookies();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 設定基底 URL
|
||||
/// </summary>
|
||||
public string BaseUrl
|
||||
{
|
||||
set
|
||||
{
|
||||
_baseUrl = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return _baseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 執行 POST 請求
|
||||
/// </summary>
|
||||
public async Task<BaseResponse> PostAsync(string servicePath, string methodName, object parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
string url = $"{_baseUrl}{servicePath}/{methodName}";
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.Method = "POST";
|
||||
request.ContentType = "application/json; charset=utf-8";
|
||||
request.CookieContainer = _cookieContainer;
|
||||
request.KeepAlive = true;
|
||||
|
||||
// 序列化參數
|
||||
string jsonData = JsonConvert.SerializeObject(parameters ?? new { });
|
||||
|
||||
// 寫入請求體
|
||||
byte[] data = Encoding.UTF8.GetBytes(jsonData);
|
||||
request.ContentLength = data.Length;
|
||||
|
||||
using (Stream requestStream = request.GetRequestStream())
|
||||
{
|
||||
await requestStream.WriteAsync(data, 0, data.Length);
|
||||
}
|
||||
|
||||
// 取得回應
|
||||
using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
|
||||
{
|
||||
// 更新 Cookie(用於 Session 管理)
|
||||
_cookieContainer.Add(response.ResponseUri, response.Cookies);
|
||||
SaveCookies();
|
||||
|
||||
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
|
||||
{
|
||||
string responseJson = await reader.ReadToEndAsync();
|
||||
|
||||
// 解析回應
|
||||
dynamic result = DeserializeObject(responseJson);
|
||||
|
||||
// ASP.NET Web Service 會將結果包在 "d" 屬性中
|
||||
if (result.d != null)
|
||||
{
|
||||
string dataJson = JsonConvert.SerializeObject(result.d);
|
||||
return DeserializeObject<BaseResponse>(dataJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DeserializeObject<BaseResponse>(responseJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
return new BaseResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = $"網路錯誤: {ex.Message}"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new BaseResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = $"錯誤: {ex.Message}"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步版本的 POST 請求(用於向後相容)
|
||||
/// </summary>
|
||||
public BaseResponse Post(string servicePath, string methodName, object parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
string url = $"{_baseUrl}{servicePath}/{methodName}";
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.Method = "POST";
|
||||
request.ContentType = "application/json; charset=utf-8";
|
||||
request.CookieContainer = _cookieContainer;
|
||||
request.KeepAlive = true;
|
||||
|
||||
// 序列化參數
|
||||
string jsonData = JsonConvert.SerializeObject(parameters ?? new { });
|
||||
|
||||
// 寫入請求體
|
||||
byte[] data = Encoding.UTF8.GetBytes(jsonData);
|
||||
request.ContentLength = data.Length;
|
||||
|
||||
using (Stream requestStream = request.GetRequestStream())
|
||||
{
|
||||
requestStream.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
// 取得回應
|
||||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
||||
{
|
||||
// 更新 Cookie(用於 Session 管理)
|
||||
_cookieContainer.Add(response.ResponseUri, response.Cookies);
|
||||
SaveCookies();
|
||||
|
||||
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
|
||||
{
|
||||
string responseJson = reader.ReadToEnd();
|
||||
|
||||
// 解析回應
|
||||
dynamic result = DeserializeObject(responseJson);
|
||||
|
||||
// ASP.NET Web Service 會將結果包在 "d" 屬性中
|
||||
if (result.d != null)
|
||||
{
|
||||
string dataJson = JsonConvert.SerializeObject(result.d);
|
||||
return DeserializeObject<BaseResponse>(dataJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DeserializeObject<BaseResponse>(responseJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
return new BaseResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = $"網路錯誤: {ex.Message}"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new BaseResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = $"錯誤: {ex.Message}"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有 Session cookie
|
||||
/// </summary>
|
||||
public void ClearSession()
|
||||
{
|
||||
_cookieContainer = new CookieContainer();
|
||||
DeleteCookies();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 儲存 Cookie 到檔案
|
||||
/// </summary>
|
||||
private void SaveCookies()
|
||||
{
|
||||
try
|
||||
{
|
||||
string directory = Path.GetDirectoryName(_cookiePath);
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
using (StreamWriter sw = new StreamWriter(_cookiePath, false, Encoding.UTF8))
|
||||
{
|
||||
foreach (Cookie cookie in _cookieContainer.GetCookies(new Uri(_baseUrl)))
|
||||
{
|
||||
sw.WriteLine($"{cookie.Name}={cookie.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略儲存錯誤
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 從檔案載入 Cookie
|
||||
/// </summary>
|
||||
private void LoadCookies()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_cookiePath))
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(_cookiePath, Encoding.UTF8))
|
||||
{
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
|
||||
string[] parts = line.Split(new[] { '=' }, 2);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
Cookie cookie = new Cookie(parts[0], parts[1])
|
||||
{
|
||||
Path = "/",
|
||||
HttpOnly = true
|
||||
};
|
||||
_cookieContainer.Add(new Uri(_baseUrl), cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略載入錯誤
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刪除儲存的 Cookie 檔案
|
||||
/// </summary>
|
||||
private void DeleteCookies()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_cookiePath))
|
||||
{
|
||||
File.Delete(_cookiePath);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略刪除錯誤
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using 報到系統客戶端.Models;
|
||||
|
||||
namespace 報到系統客戶端.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 員工資料服務客戶端
|
||||
/// 呼叫後端 Services/BPSNService.asmx
|
||||
/// </summary>
|
||||
public class BPSNService
|
||||
{
|
||||
private const string SERVICE_PATH = "/Services/BPSNService.asmx";
|
||||
|
||||
/// <summary>
|
||||
/// 下載員工資料
|
||||
/// </summary>
|
||||
/// <returns>下載結果,包含員工資料清單</returns>
|
||||
public static BaseResponse Download()
|
||||
{
|
||||
return ApiService.Instance.Post(SERVICE_PATH, "Download", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下載員工資料(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> DownloadAsync()
|
||||
//{
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "Download", null);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using 報到系統客戶端.Models;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip;
|
||||
|
||||
namespace 報到系統客戶端.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 活動服務客戶端
|
||||
/// 呼叫後端 Services/ClassesService.asmx
|
||||
/// </summary>
|
||||
public class ClassesService
|
||||
{
|
||||
private const string SERVICE_PATH = "/Services/ClassesService.asmx";
|
||||
|
||||
/// <summary>
|
||||
/// 搜尋活動清單
|
||||
/// </summary>
|
||||
/// <param name="pageIndex">頁碼(從 1 開始)</param>
|
||||
/// <param name="pageSize">每頁筆數</param>
|
||||
/// <param name="courseCode">活動代碼</param>
|
||||
/// <param name="courseName">活動名稱</param>
|
||||
/// <param name="courseDate1">活動開始日期</param>
|
||||
/// <param name="courseDate2">活動結束日期</param>
|
||||
/// <param name="courseLocation">活動地點</param>
|
||||
/// <returns>搜尋結果</returns>
|
||||
public static BaseResponse SearchClasses()
|
||||
{
|
||||
var parameters = new
|
||||
{
|
||||
pageIndex = 1,
|
||||
pageSize = Int32.MaxValue,
|
||||
courseCode = string.Empty,
|
||||
courseName = string.Empty,
|
||||
courseDate1 = new DateTime?(),
|
||||
courseDate2 = new DateTime?(),
|
||||
courseLocation = string.Empty,
|
||||
projectID = string.Empty,
|
||||
closed = false
|
||||
};
|
||||
|
||||
return ApiService.Instance.Post(SERVICE_PATH, "SearchClasses", parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜尋活動清單(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> SearchClassesAsync()
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// pageIndex = 1,
|
||||
// pageSize = Int32.MaxValue,
|
||||
// courseCode = string.Empty,
|
||||
// courseName = string.Empty,
|
||||
// courseDate1 = new DateTime?(),
|
||||
// courseDate2 = new DateTime?(),
|
||||
// courseLocation = string.Empty,
|
||||
// projectID = string.Empty,
|
||||
// closed = false
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "SearchClasses", parameters);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace 報到系統客戶端.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 系統設定管理服務
|
||||
/// 提供讀取和寫入應用程式設定的功能
|
||||
/// 設定檔存儲在用戶的 AppData 資料夾中,以避免 Program Files 權限問題
|
||||
/// </summary>
|
||||
public class ConfigService
|
||||
{
|
||||
private static ConfigService _instance;
|
||||
private static readonly object _lockObject = new object();
|
||||
|
||||
private string _userConfigPath;
|
||||
private string _defaultConfigPath;
|
||||
|
||||
/// <summary>
|
||||
/// 取得 ConfigService 的單一實例
|
||||
/// </summary>
|
||||
public static ConfigService Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new ConfigService();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigService()
|
||||
{
|
||||
_defaultConfigPath = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
|
||||
|
||||
// 用戶設定檔存儲在 AppData\Roaming\報到系統客戶端 資料夾
|
||||
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
string configDirectory = Path.Combine(appDataPath, "報到系統客戶端");
|
||||
|
||||
// 確保目錄存在
|
||||
if (!Directory.Exists(configDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(configDirectory);
|
||||
}
|
||||
|
||||
_userConfigPath = Path.Combine(configDirectory, "AppSettings.config");
|
||||
|
||||
// 如果用戶設定檔不存在,從預設設定檔複製
|
||||
if (!File.Exists(_userConfigPath))
|
||||
{
|
||||
InitializeUserConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化用戶設定檔
|
||||
/// 從預設設定檔複製所需的設定項目
|
||||
/// </summary>
|
||||
private void InitializeUserConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
XmlDocument defaultDoc = new XmlDocument();
|
||||
defaultDoc.Load(_defaultConfigPath);
|
||||
|
||||
XmlDocument userDoc = new XmlDocument();
|
||||
|
||||
// 建立新的設定檔結構
|
||||
XmlDeclaration declaration = userDoc.CreateXmlDeclaration("1.0", "utf-8", null);
|
||||
userDoc.AppendChild(declaration);
|
||||
|
||||
XmlElement configElement = userDoc.CreateElement("configuration");
|
||||
userDoc.AppendChild(configElement);
|
||||
|
||||
// 建立 applicationSettings 節點
|
||||
XmlElement appSettingsNode = userDoc.CreateElement("applicationSettings");
|
||||
configElement.AppendChild(appSettingsNode);
|
||||
|
||||
// 建立報到系統客戶端.Properties.Settings 節點
|
||||
XmlElement settingsNode = userDoc.CreateElement("報到系統客戶端.Properties.Settings");
|
||||
appSettingsNode.AppendChild(settingsNode);
|
||||
|
||||
// 建立 ApiBaseUrl 設定項目
|
||||
XmlElement settingElement = userDoc.CreateElement("setting");
|
||||
settingElement.SetAttribute("name", "ApiBaseUrl");
|
||||
settingElement.SetAttribute("serializeAs", "String");
|
||||
|
||||
XmlElement valueElement = userDoc.CreateElement("value");
|
||||
valueElement.InnerText = "https://thinkyustaff.com/event";
|
||||
settingElement.AppendChild(valueElement);
|
||||
|
||||
settingsNode.AppendChild(settingElement);
|
||||
|
||||
userDoc.Save(_userConfigPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"初始化用戶設定檔失敗: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 讀取 API 基礎 URL
|
||||
/// </summary>
|
||||
/// <returns>API 基礎 URL</returns>
|
||||
public string GetApiBaseUrl()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_userConfigPath))
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(_userConfigPath);
|
||||
|
||||
XmlNode valueNode = doc.SelectSingleNode(
|
||||
"/configuration/applicationSettings/報到系統客戶端.Properties.Settings/setting[@name='ApiBaseUrl']/value"
|
||||
);
|
||||
|
||||
if (valueNode != null && !string.IsNullOrWhiteSpace(valueNode.InnerText))
|
||||
{
|
||||
return valueNode.InnerText;
|
||||
}
|
||||
}
|
||||
|
||||
// 回退到預設值或 App.config
|
||||
return Properties.Settings.Default.ApiBaseUrl ?? "https://thinkyustaff.com/event";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "https://thinkyustaff.com/event";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 設定 API 基礎 URL
|
||||
/// </summary>
|
||||
/// <param name="baseUrl">新的 API 基礎 URL</param>
|
||||
/// <returns>是否設定成功</returns>
|
||||
public bool SetApiBaseUrl(string baseUrl)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 確保用戶設定檔存在
|
||||
if (!File.Exists(_userConfigPath))
|
||||
{
|
||||
InitializeUserConfig();
|
||||
}
|
||||
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(_userConfigPath);
|
||||
|
||||
// 找到或建立 applicationSettings 節點
|
||||
XmlNode appSettingsNode = doc.SelectSingleNode("//applicationSettings");
|
||||
if (appSettingsNode == null)
|
||||
{
|
||||
XmlNode configNode = doc.SelectSingleNode("//configuration");
|
||||
if (configNode == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
appSettingsNode = doc.CreateElement("applicationSettings");
|
||||
configNode.AppendChild(appSettingsNode);
|
||||
}
|
||||
|
||||
// 找到或建立 報到系統客戶端.Properties.Settings 節點
|
||||
XmlNode settingsNode = appSettingsNode.SelectSingleNode("報到系統客戶端.Properties.Settings");
|
||||
if (settingsNode == null)
|
||||
{
|
||||
settingsNode = doc.CreateElement("報到系統客戶端.Properties.Settings");
|
||||
appSettingsNode.AppendChild(settingsNode);
|
||||
}
|
||||
|
||||
// 找到 ApiBaseUrl 設定項目
|
||||
XmlNode apiBaseUrlNode = settingsNode.SelectSingleNode("setting[@name='ApiBaseUrl']");
|
||||
if (apiBaseUrlNode == null)
|
||||
{
|
||||
apiBaseUrlNode = doc.CreateElement("setting");
|
||||
apiBaseUrlNode.Attributes.Append(doc.CreateAttribute("name"));
|
||||
apiBaseUrlNode.Attributes["name"].Value = "ApiBaseUrl";
|
||||
apiBaseUrlNode.Attributes.Append(doc.CreateAttribute("serializeAs"));
|
||||
apiBaseUrlNode.Attributes["serializeAs"].Value = "String";
|
||||
settingsNode.AppendChild(apiBaseUrlNode);
|
||||
}
|
||||
|
||||
// 更新值
|
||||
XmlNode valueNode = apiBaseUrlNode.SelectSingleNode("value");
|
||||
if (valueNode != null)
|
||||
{
|
||||
valueNode.InnerText = baseUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果沒有 value 節點,則建立一個
|
||||
valueNode = doc.CreateElement("value");
|
||||
valueNode.InnerText = baseUrl;
|
||||
apiBaseUrlNode.AppendChild(valueNode);
|
||||
}
|
||||
|
||||
// 保存設定檔到用戶的 AppData 資料夾
|
||||
doc.Save(_userConfigPath);
|
||||
|
||||
// 刷新設定以更新記憶體中的值
|
||||
RefreshSettings();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"設定 ApiBaseUrl 失敗: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新設定值
|
||||
/// </summary>
|
||||
private void RefreshSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
Properties.Settings.Default.Reload();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 刷新失敗時不執行任何操作
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取得應用程式設定檔路徑
|
||||
/// 返回用戶設定檔的路徑(位於 AppData 中)
|
||||
/// </summary>
|
||||
/// <returns>設定檔路徑</returns>
|
||||
//public string GetConfigFilePath()
|
||||
//{
|
||||
// return _userConfigPath;
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using 報到系統客戶端.Models;
|
||||
|
||||
namespace 報到系統客戶端.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 登入服務客戶端
|
||||
/// 呼叫後端 Services/LoginService.asmx
|
||||
/// </summary>
|
||||
public class LoginService
|
||||
{
|
||||
private const string SERVICE_PATH = "/Services/LoginService.asmx";
|
||||
|
||||
/// <summary>
|
||||
/// 登入
|
||||
/// </summary>
|
||||
/// <param name="username">使用者名稱</param>
|
||||
/// <param name="password">密碼</param>
|
||||
/// <param name="rememberMe">是否記住密碼</param>
|
||||
/// <returns>登入結果</returns>
|
||||
public static BaseResponse Login(string username, string password, bool rememberMe = false)
|
||||
{
|
||||
var parameters = new
|
||||
{
|
||||
username = username,
|
||||
password = password,
|
||||
rememberMe = rememberMe
|
||||
};
|
||||
|
||||
return ApiService.Instance.Post(SERVICE_PATH, "Login", parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登入(非同步版本)
|
||||
/// </summary>
|
||||
public static async Task<BaseResponse> LoginAsync(string username, string password, bool rememberMe = false)
|
||||
{
|
||||
var parameters = new
|
||||
{
|
||||
username = username,
|
||||
password = password,
|
||||
rememberMe = rememberMe
|
||||
};
|
||||
|
||||
return await ApiService.Instance.PostAsync(SERVICE_PATH, "Login", parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登出
|
||||
/// </summary>
|
||||
/// <returns>登出結果</returns>
|
||||
public static BaseResponse Logout()
|
||||
{
|
||||
return ApiService.Instance.Post(SERVICE_PATH, "Logout", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登出(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> LogoutAsync()
|
||||
//{
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "Logout", null);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 檢查 Session(當作心跳使用)
|
||||
/// </summary>
|
||||
/// <returns>檢查結果</returns>
|
||||
public static BaseResponse CheckSession()
|
||||
{
|
||||
return ApiService.Instance.Post(SERVICE_PATH, "CheckSession", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 檢查 Session(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> CheckSessionAsync()
|
||||
//{
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "CheckSession", null);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 清除 Session
|
||||
/// </summary>
|
||||
public static void ClearSession()
|
||||
{
|
||||
ApiService.Instance.ClearSession();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 測試是否能連線
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool Ping()
|
||||
{
|
||||
var pingResult = ApiService.Instance.Post(SERVICE_PATH, "Ping", null);
|
||||
return pingResult != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Media;
|
||||
|
||||
namespace 報到系統客戶端.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知音效服務,密集呼叫時會中斷先前的播放再重新播放。
|
||||
/// </summary>
|
||||
public static class NotificationSoundService
|
||||
{
|
||||
private static readonly string _dingWavePath =
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sound\\ding.wav");
|
||||
private static readonly string _checkinWavePath =
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sound\\CheckinOK.wav");
|
||||
private static readonly string _checkoutWavePath =
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sound\\CheckoutOK.wav");
|
||||
|
||||
private static SoundPlayer _dingPlayer;
|
||||
private static SoundPlayer _checkinPlayer;
|
||||
private static SoundPlayer _checkoutPlayer;
|
||||
|
||||
private static void StopAll()
|
||||
{
|
||||
_dingPlayer?.Stop();
|
||||
_checkinPlayer?.Stop();
|
||||
_checkoutPlayer?.Stop();
|
||||
}
|
||||
|
||||
private static void PlaySound(string path, ref SoundPlayer player)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
if (player == null)
|
||||
player = new SoundPlayer(path);
|
||||
|
||||
StopAll();
|
||||
player.Play();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 播放 ding.wav;若有其他音效正在播放,先全部停止再播放。
|
||||
/// </summary>
|
||||
public static void Ding() => PlaySound(_dingWavePath, ref _dingPlayer);
|
||||
|
||||
/// <summary>
|
||||
/// 播放 CheckinOK.wav;若有其他音效正在播放,先全部停止再播放。
|
||||
/// </summary>
|
||||
public static void CheckinOK() => PlaySound(_checkinWavePath, ref _checkinPlayer);
|
||||
|
||||
/// <summary>
|
||||
/// 播放 CheckoutOK.wav;若有其他音效正在播放,先全部停止再播放。
|
||||
/// </summary>
|
||||
public static void CheckoutOK() => PlaySound(_checkoutWavePath, ref _checkoutPlayer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using 報到系統客戶端.Models;
|
||||
|
||||
namespace 報到系統客戶端.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 報名服務客戶端
|
||||
/// 呼叫後端 Services/SignUpService.asmx
|
||||
/// </summary>
|
||||
public class SignUpService
|
||||
{
|
||||
private const string SERVICE_PATH = "/Services/SignUpService.asmx";
|
||||
|
||||
/// <summary>
|
||||
/// 搜尋活動參加人員清單
|
||||
/// </summary>
|
||||
/// <param name="pageIndex">頁碼(從 1 開始)</param>
|
||||
/// <param name="pageSize">每頁筆數</param>
|
||||
/// <param name="courseID">活動編號</param>
|
||||
/// <param name="name">學員姓名</param>
|
||||
/// <param name="mobile">手機號</param>
|
||||
/// <returns>搜尋結果</returns>
|
||||
public static BaseResponse SearchSignUps(
|
||||
int pageIndex,
|
||||
int pageSize,
|
||||
int courseID,
|
||||
string name = "",
|
||||
string mobile = "")
|
||||
{
|
||||
var parameters = new
|
||||
{
|
||||
pageIndex = pageIndex,
|
||||
pageSize = pageSize,
|
||||
courseID = courseID,
|
||||
name = name,
|
||||
mobile = mobile
|
||||
};
|
||||
|
||||
return ApiService.Instance.Post(SERVICE_PATH, "SearchSignUps", parameters);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 搜尋活動參加人員清單(非同步版本)
|
||||
///// </summary>
|
||||
//public static async Task<BaseResponse> SearchSignUpsAsync(
|
||||
// int pageIndex,
|
||||
// int pageSize,
|
||||
// int courseID,
|
||||
// string name = "",
|
||||
// string mobile = "")
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// pageIndex = pageIndex,
|
||||
// pageSize = pageSize,
|
||||
// courseID = courseID,
|
||||
// name = name,
|
||||
// mobile = mobile
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "SearchSignUps", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 上傳活動參加人員簽到簽退資料
|
||||
/// 由 WinForm 客戶端上傳簽到簽退資料
|
||||
/// </summary>
|
||||
/// <param name="courseID">活動編號</param>
|
||||
/// <param name="items">報名人員列表</param>
|
||||
/// <returns>上傳結果</returns>
|
||||
//public static BaseResponse UploadSignUps(int courseID, List<SignUpItem> items)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// courseID = courseID,
|
||||
// items = items
|
||||
// };
|
||||
|
||||
// return ApiService.Instance.Post(SERVICE_PATH, "UploadSignUps", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 上傳活動參加人員簽到簽退資料(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> UploadSignUpsAsync(int courseID, List<SignUpItem> items)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// courseID = courseID,
|
||||
// items = items
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "UploadSignUps", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 掃碼簽到
|
||||
/// </summary>
|
||||
/// <param name="checkType">簽到類型</param>
|
||||
/// <param name="qrCode">QR Code</param>
|
||||
/// <param name="checkInTime">簽到時間</param>
|
||||
/// <returns>簽到結果</returns>
|
||||
//public static BaseResponse CheckIn(string checkType, string qrCode, DateTime checkInTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// qrCode = qrCode,
|
||||
// checkInTime = checkInTime
|
||||
// };
|
||||
|
||||
// return ApiService.Instance.Post(SERVICE_PATH, "CheckIn", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 掃碼簽到(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> CheckInAsync(string checkType, string qrCode, DateTime checkInTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// qrCode = qrCode,
|
||||
// checkInTime = checkInTime
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "CheckIn", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 掃碼簽退
|
||||
/// </summary>
|
||||
/// <param name="checkType">簽退類型</param>
|
||||
/// <param name="qrCode">QR Code</param>
|
||||
/// <param name="checkOutTime">簽退時間</param>
|
||||
/// <returns>簽退結果</returns>
|
||||
//public static BaseResponse CheckOut(string checkType, string qrCode, DateTime checkOutTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// qrCode = qrCode,
|
||||
// checkOutTime = checkOutTime
|
||||
// };
|
||||
|
||||
// return ApiService.Instance.Post(SERVICE_PATH, "CheckOut", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 掃碼簽退(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> CheckOutAsync(string checkType, string qrCode, DateTime checkOutTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// qrCode = qrCode,
|
||||
// checkOutTime = checkOutTime
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "CheckOut", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 現場簽到(未預先登記的參加人員)
|
||||
/// </summary>
|
||||
/// <param name="checkType">簽到類型</param>
|
||||
/// <param name="courseID">活動編號</param>
|
||||
/// <param name="name">姓名</param>
|
||||
/// <param name="mobile">手機號</param>
|
||||
/// <param name="checkInTime">簽到時間</param>
|
||||
/// <returns>簽到結果</returns>
|
||||
//public static BaseResponse OnSiteCheckIn(
|
||||
// string checkType,
|
||||
// int courseID,
|
||||
// string name,
|
||||
// string mobile,
|
||||
// DateTime checkInTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// courseID = courseID,
|
||||
// name = name,
|
||||
// mobile = mobile,
|
||||
// checkInTime = checkInTime
|
||||
// };
|
||||
|
||||
// return ApiService.Instance.Post(SERVICE_PATH, "OnSiteCheckIn", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 現場簽到(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> OnSiteCheckInAsync(
|
||||
// string checkType,
|
||||
// int courseID,
|
||||
// string name,
|
||||
// string mobile,
|
||||
// DateTime checkInTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// courseID = courseID,
|
||||
// name = name,
|
||||
// mobile = mobile,
|
||||
// checkInTime = checkInTime
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "OnSiteCheckIn", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 現場簽退(未預先登記的參加人員)
|
||||
/// </summary>
|
||||
/// <param name="checkType">簽退類型</param>
|
||||
/// <param name="courseID">活動編號</param>
|
||||
/// <param name="name">姓名</param>
|
||||
/// <param name="mobile">手機號</param>
|
||||
/// <param name="checkOutTime">簽退時間</param>
|
||||
/// <returns>簽退結果</returns>
|
||||
//public static BaseResponse OnSiteCheckOut(
|
||||
// string checkType,
|
||||
// int courseID,
|
||||
// string name,
|
||||
// string mobile,
|
||||
// DateTime checkOutTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// courseID = courseID,
|
||||
// name = name,
|
||||
// mobile = mobile,
|
||||
// checkOutTime = checkOutTime
|
||||
// };
|
||||
|
||||
// return ApiService.Instance.Post(SERVICE_PATH, "OnSiteCheckOut", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 現場簽退(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> OnSiteCheckOutAsync(
|
||||
// string checkType,
|
||||
// int courseID,
|
||||
// string name,
|
||||
// string mobile,
|
||||
// DateTime checkOutTime)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// checkType = checkType,
|
||||
// courseID = courseID,
|
||||
// name = name,
|
||||
// mobile = mobile,
|
||||
// checkOutTime = checkOutTime
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "OnSiteCheckOut", parameters);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 批量上傳簽到簽退資料
|
||||
/// 由 WinForm 客戶端上傳簽到簽退資料
|
||||
/// </summary>
|
||||
/// <param name="courseID">活動編號</param>
|
||||
/// <param name="items">簽到簽退資料列表</param>
|
||||
/// <returns>上傳結果</returns>
|
||||
public static BaseResponse UploadCheckIns(int courseID, List<CheckInItem> items)
|
||||
{
|
||||
var parameters = new
|
||||
{
|
||||
courseID = courseID,
|
||||
items = items
|
||||
};
|
||||
|
||||
return ApiService.Instance.Post(SERVICE_PATH, "UploadCheckIns", parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量上傳簽到簽退資料(非同步版本)
|
||||
/// </summary>
|
||||
//public static async Task<BaseResponse> UploadCheckInsAsync(int courseID, List<CheckInItem> items)
|
||||
//{
|
||||
// var parameters = new
|
||||
// {
|
||||
// courseID = courseID,
|
||||
// items = items
|
||||
// };
|
||||
|
||||
// return await ApiService.Instance.PostAsync(SERVICE_PATH, "UploadCheckIns", parameters);
|
||||
//}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user