chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore - 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
@@ -0,0 +1,7 @@
|
||||
三竹官網:https://sms.mitake.com.tw/
|
||||
帳號:27968860
|
||||
密碼:TY27968860
|
||||
|
||||
MMS API:https://message.mitake.com.tw
|
||||
clientID:235vx4hnn2ga248cq12w
|
||||
clientSecret:hINE8vzjsBLKSNNthzdRiS5G
|
||||
@@ -0,0 +1,309 @@
|
||||
# 多簡訊平台架構設計
|
||||
|
||||
> 建立日期:2026-06-02
|
||||
> 目的:支援 EVERY8D 與三竹(MITAKE)兩個簡訊發送平台
|
||||
|
||||
---
|
||||
|
||||
## 需求說明
|
||||
|
||||
- 加入三竹(MITAKE)簡訊發送平台
|
||||
- 整個系統統一切換發送平台(由系統設定決定)
|
||||
- 存放帳號參數的 `ProjectMMSAccount` 資料表加入平台代碼欄位
|
||||
- 新增 `MMSPlatform` 資料表,存放平台代碼、主帳號密碼等資料(API 端點硬寫於各 Provider 靜態變數)
|
||||
- 於 `BWEX` 資料表加入設定 `CurrentMMSPlatform`,記錄目前使用哪一個簡訊平台
|
||||
- 簡訊帳號設定畫面需支援:
|
||||
- 選擇平台
|
||||
- 顯示目前的預設平台
|
||||
- 設定各簡訊平台的主帳號密碼
|
||||
- 管理各計畫的分帳號密碼
|
||||
|
||||
---
|
||||
|
||||
## 架構概覽
|
||||
|
||||
```
|
||||
SMSSendingService.SendMessage()
|
||||
└─ switch (message.PlatformCode)
|
||||
├─ "EVERY8D" → EVERY8DSMSProvider.SendMMS(...)
|
||||
└─ "MITAKE" → MITAKESMSProvider.SendMMS(...)
|
||||
```
|
||||
|
||||
**設計原則:兩個 Provider 均為純靜態類別,不使用介面或工廠,直接 switch 呼叫。**
|
||||
|
||||
平台代碼優先順序:
|
||||
1. `MessageQueueItem.PlatformCode`(由計畫的 `ProjectMMSAccount.PlatformCode` 填入)
|
||||
2. 若計畫無設定,使用 `PublicVariable.CurrentMMSPlatform`(由 `BWEX.CurrentMMSPlatform` 載入)
|
||||
|
||||
---
|
||||
|
||||
## 資料庫異動
|
||||
|
||||
### 新增資料表 `MMSPlatform`(簡訊平台設定)
|
||||
|
||||
| No | Field Name | Data Type | Length | Not Null | PK | Identity | Description |
|
||||
| --- | ------------ | --------- | ------ | -------- | --- | -------- | ---------------------- |
|
||||
| 1 | ID | INT | | V | V | V | 流水號 |
|
||||
| 2 | PlatformCode | NVARCHAR | 20 | V | | | 平台代碼(EVERY8D / MITAKE) |
|
||||
| 3 | PlatformName | NVARCHAR | 50 | V | | | 平台名稱(EVERY8D / 三竹) |
|
||||
| 4 | Account | NVARCHAR | 100 | | | | 主帳號 |
|
||||
| 5 | Password | NVARCHAR | 100 | | | | 主密碼 |
|
||||
| 6 | Remark | NVARCHAR | 200 | | | | 備註 |
|
||||
| 7 | DB_APPNO | INT | | V | | | 樂觀鎖定版本號 |
|
||||
| 8 | DB_CRDAT | DATETIME | | V | | | 建立日期 |
|
||||
| 9 | DB_CRUSR | NVARCHAR | 20 | V | | | 建立人員 |
|
||||
| 10 | DB_TRDAT | DATETIME | | V | | | 修改日期 |
|
||||
| 11 | DB_TRUSR | NVARCHAR | 20 | V | | | 修改人員 |
|
||||
|
||||
> API 端點網址硬寫於各 Provider 靜態變數,不存入資料庫。
|
||||
|
||||
預設插入兩筆:
|
||||
|
||||
| PlatformCode | PlatformName |
|
||||
| ------------ | ------------ |
|
||||
| EVERY8D | EVERY8D |
|
||||
| MITAKE | 三竹 |
|
||||
|
||||
### 修改資料表 `ProjectMMSAccount`
|
||||
|
||||
新增欄位:
|
||||
|
||||
| No | Field Name | Data Type | Length | Not Null | Description |
|
||||
| --- | ------------ | --------- | ------ | -------- | ----------- |
|
||||
| 5 | PlatformCode | NVARCHAR | 20 | V | 平台代碼 |
|
||||
|
||||
### 修改資料表 `BWEX`(系統設定)
|
||||
|
||||
新增一筆設定資料:
|
||||
|
||||
| KeyName | KeyValue | Description |
|
||||
| ------------------ | -------- | ----------- |
|
||||
| CurrentMMSPlatform | EVERY8D | 目前使用的簡訊平台代碼 |
|
||||
|
||||
---
|
||||
|
||||
## 新增檔案
|
||||
|
||||
### `Services/MITAKESMSProvider.cs`(三竹靜態類別)
|
||||
|
||||
- 純靜態類別(`public static class MITAKESMSProvider`)
|
||||
- API 端點以靜態變數定義:
|
||||
```csharp
|
||||
private const string ApiBaseUrl = "https://message.mitake.com.tw";
|
||||
```
|
||||
- 依 `message.MMSAccount` / `message.MMSPassword` 呼叫三竹 API
|
||||
- 三竹 API 端點格式:
|
||||
`{ApiBaseUrl}/SmSendGet.asp?username={帳號}&password={密碼}&dstaddr={手機}&smbody={內容}`
|
||||
- 回傳格式為純文字:`[1]` 開頭表示成功,`statuscode=` 欄位為狀態碼
|
||||
- 三竹狀態碼說明:
|
||||
|
||||
| statuscode | 說明 |
|
||||
| ---------- | ------ |
|
||||
| 0 | 已送達手機 |
|
||||
| 1 | 已送達三竹 |
|
||||
| 2 | 已送達業者 |
|
||||
| 1000 | 預約傳送中 |
|
||||
| 1001 | 預約已取消 |
|
||||
| 2000 | 內容有錯誤 |
|
||||
| 2001 | 門號有錯誤 |
|
||||
| 2002 | 訊息已停用 |
|
||||
| 2003 | 逾時無法送達 |
|
||||
| 2005 | 內容有關鍵字 |
|
||||
| 2999 | 業者系統錯誤 |
|
||||
| 9998 | 傳送錯誤 |
|
||||
| 9999 | 三竹系統錯誤 |
|
||||
|
||||
|
||||
- `CheckBalance`:呼叫 `{ApiBaseUrl}/SmQueryGet.asp?username={帳號}&password={密碼}&CharsetURL=UTF-8`
|
||||
|
||||
### `Models/MMSPlatformItem.cs`(資料紀錄類別)
|
||||
|
||||
對應 `MMSPlatform` 資料表的單筆資料,屬性包含:
|
||||
`ID`、`PlatformCode`、`PlatformName`、`Account`、`Password`、`Remark`,以及標準 DB 欄位。
|
||||
|
||||
### `Models/MMSPlatformList.cs`(資料集合類別)
|
||||
|
||||
`List<MMSPlatformItem>` 的集合類別。
|
||||
|
||||
### `DAC/DAC_MMSPlatform.cs`(資料存取類別)
|
||||
|
||||
- `MMSPlatformList SelectAll()` — 查詢所有平台
|
||||
- `MMSPlatformItem SelectByCode(string platformCode)` — 依代碼查一筆
|
||||
- `MMSPlatformItem InsertOne(MMSPlatformItem item)` — 新增
|
||||
- `MMSPlatformItem UpdateOne(MMSPlatformItem item)` — 修改(含 `DB_APPNO` 樂觀鎖定)
|
||||
|
||||
---
|
||||
|
||||
## 修改現有檔案
|
||||
|
||||
### `Services/EVERY8DSMSProvider.cs`
|
||||
|
||||
- 維持純靜態類別,不需異動介面或繼承關係
|
||||
- `SendMMS`、`CheckBalance` 保持 static 方法不變
|
||||
- API 端點以靜態常數定義(已存在或補充確認):
|
||||
```csharp
|
||||
private const string ApiBaseUrl = "https://new.e8d.tw/API21/HTTP";
|
||||
```
|
||||
|
||||
### `Models/ProjectMMSAccountItem.cs`(或所在類別檔)
|
||||
|
||||
新增屬性:
|
||||
```csharp
|
||||
public string PlatformCode { get; set; }
|
||||
```
|
||||
|
||||
### `Models/MessageQueueItem.cs`(或所在類別檔)
|
||||
|
||||
新增屬性:
|
||||
```csharp
|
||||
public string PlatformCode { get; set; }
|
||||
```
|
||||
|
||||
### `DAC/DAC_ProjectMMSAccount.cs`
|
||||
|
||||
- `SelectPage`、`Select`、`InsertOne`、`UpdateOne` 均加入 `PlatformCode` 欄位處理
|
||||
|
||||
### `Common/PublicVariable.cs`
|
||||
|
||||
新增靜態變數:
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 目前使用的簡訊平台代碼(由 BWEX.CurrentMMSPlatform 載入)
|
||||
/// </summary>
|
||||
public static string CurrentMMSPlatform = "EVERY8D";
|
||||
```
|
||||
|
||||
### `Global.asax.cs`
|
||||
|
||||
`Application_Start` 新增從 DB 讀取 `BWEX` 的 `CurrentMMSPlatform`,設定至 `PublicVariable.CurrentMMSPlatform`。
|
||||
EVERY8D 相關的 AppSettings 讀取保留作為向後相容 fallback。
|
||||
|
||||
### `Services/SMSSendingService.cs`
|
||||
|
||||
- `Start()` 的帳號填入迴圈,同時填入 `message.PlatformCode`:
|
||||
- 計畫有設定 `PlatformCode` → 使用計畫的 `PlatformCode`
|
||||
- 否則使用 `PublicVariable.CurrentMMSPlatform`
|
||||
- `SendMessage()` 改用 `switch (message.PlatformCode)` 直接呼叫對應靜態 Provider,移除 `SendSMSToEVERY8D()` 方法:
|
||||
|
||||
```csharp
|
||||
switch (message.PlatformCode)
|
||||
{
|
||||
case "MITAKE":
|
||||
result = MITAKESMSProvider.SendMMS(message, out failMessage);
|
||||
break;
|
||||
default: // EVERY8D
|
||||
result = EVERY8DSMSProvider.SendMMS(message, out failMessage);
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
### `Services/MessageAccountManage.asmx.cs`
|
||||
|
||||
新增 WebMethod:
|
||||
|
||||
| Method | 說明 |
|
||||
| ----------------------------------------- | ------------------------------------------------- |
|
||||
| `GetPlatforms()` | 回傳所有平台清單(BaseResponse, Data: MMSPlatformList) |
|
||||
| `GetCurrentPlatform()` | 回傳目前系統預設平台代碼(BaseResponse, Data: MMSPlatformItem) |
|
||||
| `SavePlatform(MMSPlatformItem item)` | 儲存平台設定(帳號 / 密碼) |
|
||||
| `SetCurrentPlatform(string platformCode)` | 更新 BWEX 的 CurrentMMSPlatform,同時更新 PublicVariable |
|
||||
|
||||
修改 `Save()`:加入 `PlatformCode` 欄位的驗證與儲存。
|
||||
|
||||
### `Forms/MessageAccountManage.aspx`
|
||||
|
||||
畫面新增區塊:
|
||||
|
||||
1. **目前預設平台區塊**(搜尋面板上方):
|
||||
- 顯示目前使用的平台名稱與代碼
|
||||
- 提供「切換平台」按鈕開啟平台切換彈窗
|
||||
|
||||
2. **平台設定區塊**(可展開/收合):
|
||||
- 列出所有平台(EVERY8D、三竹)
|
||||
- 每平台顯示:主帳號、主密碼、操作按鈕(儲存)(API 端點固定於程式碼,不顯示於畫面)
|
||||
|
||||
3. **列表欄位**:
|
||||
- 新增「平台」欄(顯示 `PlatformCode`,NULL 時顯示「系統預設」)
|
||||
|
||||
4. **新增/編輯彈窗**:
|
||||
- 新增「使用平台」下拉選單(選項:`使用系統預設`、`EVERY8D`、`三竹`)
|
||||
|
||||
### `Scripts/MessageAccountManage.js`
|
||||
|
||||
新增 `data`:
|
||||
- `platforms: []` — 平台清單
|
||||
- `currentPlatform: null` — 目前預設平台物件
|
||||
- `showPlatformSettings: false` — 控制平台設定展開
|
||||
- `showSwitchModal: false` — 切換平台彈窗
|
||||
|
||||
新增 `methods`:
|
||||
- `loadPlatforms()` — 呼叫 `GetPlatforms()`
|
||||
- `loadCurrentPlatform()` — 呼叫 `GetCurrentPlatform()`
|
||||
- `savePlatformSetting(platform)` — 呼叫 `SavePlatform()`
|
||||
- `setCurrentPlatform(platformCode)` — 呼叫 `SetCurrentPlatform()`
|
||||
|
||||
修改 `editItem`:
|
||||
- 新增 `PlatformCode: ''`(空字串 = 使用系統預設)
|
||||
|
||||
---
|
||||
|
||||
## 三竹 API 說明
|
||||
|
||||
### 發送 API
|
||||
|
||||
```
|
||||
ApiBaseUrl = https://message.mitake.com.tw (硬寫於 MITAKESMSProvider)
|
||||
|
||||
GET/POST {ApiBaseUrl}/SmSendGet.asp
|
||||
參數:
|
||||
username = 帳號
|
||||
password = 密碼
|
||||
dstaddr = 手機號碼(多筆以 $ 分隔)
|
||||
smbody = 簡訊內容(URL Encode, UTF-8)
|
||||
CharsetURL = UTF-8
|
||||
```
|
||||
|
||||
回傳格式(純文字,每筆一行):
|
||||
```
|
||||
[序號]
|
||||
statuscode=1
|
||||
destaddr=0912345678
|
||||
msgid=訊息ID
|
||||
```
|
||||
|
||||
### 查詢餘額 API
|
||||
|
||||
```
|
||||
GET {ApiBaseUrl}/SmQueryGet.asp
|
||||
參數:
|
||||
username = 帳號
|
||||
password = 密碼
|
||||
CharsetURL = UTF-8
|
||||
```
|
||||
|
||||
回傳格式:
|
||||
```
|
||||
AccountPoint=100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 檔案清單
|
||||
|
||||
| 異動類型 | 路徑 |
|
||||
| ---- | --------------------------------------- |
|
||||
| 新增 | `DOC/多簡訊平台架構設計.md` |
|
||||
| 新增 | `Services/MITAKESMSProvider.cs` |
|
||||
| 新增 | `Models/MMSPlatformItem.cs` |
|
||||
| 新增 | `Models/MMSPlatformList.cs` |
|
||||
| 新增 | `DAC/DAC_MMSPlatform.cs` |
|
||||
| 修改 | `Services/EVERY8DSMSProvider.cs` |
|
||||
| 修改 | `Models/ProjectMMSAccountItem.cs` |
|
||||
| 修改 | `Models/MessageQueueItem.cs` |
|
||||
| 修改 | `DAC/DAC_ProjectMMSAccount.cs` |
|
||||
| 修改 | `Common/PublicVariable.cs` |
|
||||
| 修改 | `Global.asax.cs` |
|
||||
| 修改 | `Services/SMSSendingService.cs` |
|
||||
| 修改 | `Services/MessageAccountManage.asmx.cs` |
|
||||
| 修改 | `Forms/MessageAccountManage.aspx` |
|
||||
| 修改 | `Scripts/MessageAccountManage.js` |
|
||||
Binary file not shown.
@@ -0,0 +1,65 @@
|
||||
# 活動人員管理
|
||||
|
||||
## 資料關聯
|
||||
Classes.ID (1) <-> (*) SignUp.CourseID
|
||||
|
||||
## 資料類別
|
||||
* 各資料存取類別、資料集合類別、資料類別已有程式碼
|
||||
* 如需擴充加在 DAC_XXXX2.cs 裡面
|
||||
* DAC_Classes:活動資料處理類別
|
||||
* ClassesList:活動資料集類別
|
||||
* ClassesItem:活動資料項目類別
|
||||
* DAC_SignUp:活動參加人員資料處理類別
|
||||
* SignUpList:活動參加人員資料集類別
|
||||
* SignUpItem:活動參加人員資料項目類別
|
||||
- 主要欄位:ID, CourseID, SeqNo, Name, Mobile, IDNumber, QRCode, SignUpType, CheckInTime, CheckOutTime, IDType, MealType, Email, Gender, LossJobTimes, AgreementStatus
|
||||
|
||||
## 畫面檔
|
||||
|
||||
### 活動參加人員
|
||||
* Forms/SignUpList.aspx
|
||||
* 畫面上方查詢活動,用下拉選擇活動
|
||||
* 畫面下方列出活動參加人員
|
||||
* 分頁顯示,每頁預設 20 筆,可選 10, 20, 50, 100 筆
|
||||
* 分頁列 [第一頁][上一頁] 第[頁數下拉]頁 [下一頁][最後頁] | 每頁[筆數下拉]筆共[筆數]筆
|
||||
|
||||
### 匯入參加人員
|
||||
* Forms/SignUpImport.aspx
|
||||
* 畫面上方查詢活動,用下拉選擇活動
|
||||
* 選擇 .xlsx 檔案,上傳
|
||||
* 列出預覽及驗證錯誤處
|
||||
* 執行匯入,匯入選擇到的活動
|
||||
* 匯入格式與必要欄位是 Name 學員姓名、Mobile 手機號
|
||||
* 要能偵測並跳過表頭
|
||||
|
||||
### 匯出參加人員
|
||||
* Forms/SignUpExport.aspx
|
||||
* 畫面上方查詢活動,用下拉選擇活動
|
||||
* 執行匯出 .xlsx 檔
|
||||
* 匯出格式是
|
||||
* 表頭:活動名稱、日期、地點(空行)
|
||||
* 表身:序號、學員姓名、手機號、簽到時間、簽退時間、身分別、身分證字號、餐點、電子郵件、失業給付認定次數、性別、報名方式
|
||||
|
||||
## 後端服務
|
||||
* Services/ClassesService.asmx
|
||||
* 活動的後端服務
|
||||
* SearchClasses:查詢活動清單
|
||||
* SearchProjects:搜尋計畫(用於自動完成)
|
||||
* Services/SignUpService.asmx
|
||||
* 活動參加人員的後端服務
|
||||
* SearchSignUps:以活動編號(CourseID)查詢參加人員(基本查詢)
|
||||
* SearchSignUpsAdvanced:進階查詢(支援序號、身分別、身分證字號、餐點、Email 等條件)
|
||||
* SaveSignUp:儲存活動參加人員(新增或更新)
|
||||
* DeleteSignUp(int id, int dbAppNo):刪除活動參加人員
|
||||
* ConfirmImport(int courseID, List<SignUpItem> items, bool clearBefore):執行活動參加人員匯入
|
||||
* ExportSignUps(int courseID, string timeFormat):匯出活動參加人員
|
||||
* SendSmsBatch(int courseID, List<int> signupIds):批量發送簡訊
|
||||
* GetSignUpById(int signupId):查詢單筆參加人員
|
||||
* CheckBalance:查詢簡訊點數餘額
|
||||
* Services/FileUploadHandler.ashx
|
||||
* 檔案上傳處理器
|
||||
* action=ProcessImportFile:上傳並解析匯入 Excel 檔案(含驗證),參數 courseID 由 QueryString 傳入
|
||||
|
||||
## 技術規格
|
||||
* 前端使用 Vue.js 實作,不使用 Server Control
|
||||
* 後端使用 WebService,要 EnableSession
|
||||
@@ -0,0 +1,46 @@
|
||||
# 活動人員簽到簽退
|
||||
|
||||
## 資料關聯
|
||||
Classes.ID (1) <-> (*) SignUp.CourseID
|
||||
|
||||
## 資料類別
|
||||
* 各資料存取類別、資料集合類別、資料類別已有程式碼
|
||||
* 如需擴充加在 DAC_XXXX2.cs 裡面
|
||||
* DAC_Classes:活動資料處理類別
|
||||
* ClassesList:活動資料集類別
|
||||
* ClassesItem:活動資料項目類別
|
||||
* DAC_SignUp:活動參加人員資料處理類別
|
||||
* SignUpList:活動參加人員資料集類別
|
||||
* SignUpItem:活動參加人員資料項目類別
|
||||
* CheckInItem:簽到資料項目類別(用於 UploadCheckIns)
|
||||
|
||||
## 畫面檔
|
||||
* 沒有,這是寫給 WinForm 客戶端使用的後端服務
|
||||
|
||||
## 後端服務
|
||||
* Services/ClassesService.asmx
|
||||
* 活動的後端服務
|
||||
* SearchClasses:查詢活動清單
|
||||
* Services/SignUpService.asmx
|
||||
* 活動參加人員的後端服務
|
||||
* SearchSignUps:以活動編號(CourseID)查詢參加人員
|
||||
* UploadCheckIns(int courseID, List<CheckInItem> items):批量上傳簽到簽退資料
|
||||
* 上傳資料欄位(CheckInItem):CourseID, Name, Mobile, IDNumber, IDType, MealType, Email, SignUpType, CheckInType, CheckInTime
|
||||
* 驗證規則
|
||||
* CourseID: 必填、必須存在於課程表 Classes.ID
|
||||
* Name, Mobile: 必填
|
||||
* SignUpType: 必填,允許值 (預約 / 現場)
|
||||
* CheckInType: 必填,允許值 (CHECKIN / CHECKOUT)
|
||||
* CheckInTime: 必填,格式 yyyy-MM-dd HH:mm:ss
|
||||
* 處理邏輯
|
||||
* 按 (CourseID, Name, Mobile) 查詢 SignUp 表
|
||||
* 若找到則依照 CheckInType 更新 CheckInTime/CheckOutTime,計入成功筆數
|
||||
* 若沒找到則新增 (SignUpType="現場"),並依 CheckInType 設定時間欄位,計入成功筆數
|
||||
* 不使用 transaction
|
||||
* 回應格式
|
||||
* 成功: { Success: true, Message: "...", Data: { CreatedCount, UpdatedCount, FailedCount, SkippedCount, SuccessIDs, Errors } }
|
||||
* 失敗: { Success: false, Message: "...", Data: {...} }
|
||||
|
||||
## 技術規格
|
||||
* 前端使用 Vue.js 實作,不使用 Server Control
|
||||
* 後端使用 WebService,要 EnableSession
|
||||
@@ -0,0 +1,95 @@
|
||||
# 活動管理
|
||||
|
||||
## 畫面檔:
|
||||
~/Forms/ClassesList.aspx
|
||||
|
||||
## 資料存取類別
|
||||
~/Models/DAC_Classes1.cs(自動產生,勿修改)
|
||||
~/Models/DAC_Classes2.cs(自訂擴充)
|
||||
- DAC_Classes:資料處理類別
|
||||
- ClassesList:資料集類別
|
||||
- ClassesItem:資料項目類別
|
||||
|
||||
## 畫面排列:
|
||||
上方:搜尋列
|
||||
- 使用 CourseCode、CourseName、CourseDate_1(CourseDate 起)、CourseDate_2(CourseDate 迄)、CourseLocation 為查詢條件
|
||||
下方:搜尋結果列表
|
||||
- 顯示欄位為 CourseCode、CourseName、CourseDate、CourseLocation、操作
|
||||
- 新增按鈕放置在表頭的操作欄
|
||||
- 更正、刪除按鈕放置在操作欄
|
||||
- CourseCode、CourseDate 向中對齊,其餘向左對齊
|
||||
|
||||
## UI 規範:
|
||||
- 小窗尺寸:700x500px
|
||||
- 搜尋結果每頁顯示 20 筆
|
||||
- 操作按鈕使用 Bootstrap 樣式
|
||||
|
||||
## 錯誤處理:
|
||||
- 使用系統共用的 $message 來顯示
|
||||
|
||||
## 新增更正:
|
||||
- 新增更正時彈出小窗
|
||||
- 新增有兩個存檔按鈕
|
||||
存檔:存檔後關閉小窗
|
||||
存檔後繼續新增:存檔後清除輸入內容重新進入新增模式
|
||||
- 更正存檔後關閉小窗
|
||||
|
||||
## 刪除:
|
||||
- 彈 confirm 確認後刪除
|
||||
|
||||
## 資料輸入:
|
||||
- CourseCode 不可輸入,不可修改,自動編號(BeforeInsertOne 處理)
|
||||
- CourseName 必填,可輸入,可修改,單行文字框,最長 100 Unicode 字元
|
||||
- CourseDate 必填,可輸入,可修改,日期輸入框,YYYY-MM-DD 格式,不必驗證是否晚於今天
|
||||
- CourseLocation 非必填,可輸入,可修改,單行文字框
|
||||
- NotificationTitle 非必填,可輸入,可修改,單行文字框,最長 100 Unicode 字元
|
||||
- NotificationTemplate 非必填,可輸入,可修改,多行文字框,最長 500 Unicode 字元
|
||||
NotificationTemplate 插入規則:
|
||||
- 插入格式:{活動日期}、{活動名稱}、{活動地點}
|
||||
- 插入位置:游標當前位置
|
||||
- 範例:「提醒您,{活動名稱}將於{活動日期}在{活動地點}舉行」
|
||||
- AgreedTerms 非必填
|
||||
|
||||
## 前端程式碼:
|
||||
- 使用 Vue.js 實現動態資料綁定與操作。
|
||||
- 不使用 Server control
|
||||
|
||||
## 後端程式碼:
|
||||
- 使用 WebService 實現非同步資料交換。
|
||||
|
||||
## WebService 端點:
|
||||
Services/ClassesService.asmx
|
||||
- EnableSession(True)
|
||||
|
||||
- SearchClasses(int pageIndex, int pageSize, string courseCode, string courseName, DateTime? courseDate1, DateTime? courseDate2, string courseLocation, bool? closed, string projectID):搜尋活動
|
||||
- pageIndex 從 1 開始
|
||||
- 查詢 function 用 DAC_Classes.SelectPage(bool noInputReturnAll, int startRowIndex, int maximumRows, string CourseCode, string CourseName, DateTime? CourseDate_1, DateTime? CourseDate_2, string CourseLocation, bool? Closed, string ProjectID, string orderBy = "")
|
||||
- 筆數 function 用 DAC_Classes.SelectCount(bool noInputReturnAll, string CourseCode, string CourseName, DateTime? CourseDate_1, DateTime? CourseDate_2, string CourseLocation, bool? Closed, string ProjectID, string orderBy = "")
|
||||
- 查詢條件為 AND 關係
|
||||
- 空白條件視為不限制(noInputReturnAll = true)
|
||||
- CourseDate 為範圍查詢
|
||||
- 每筆結果補填 ProjectName(由 DAC_BPAA.SelectProjectName 查詢)
|
||||
- 回傳:BaseResponse(Success, Message, Data: ClassesList.ToDict(), TotalCount: 總筆數)
|
||||
|
||||
- SaveClasses(bool isNew, ClassesItem item):存檔
|
||||
- isNew:是否為新增
|
||||
- item:新增或更正的活動資料(型別 ClassesItem)
|
||||
- 回傳:BaseResponse(Success, Message, Data: 儲存後的 ClassesItem)
|
||||
|
||||
- DeleteClasses(int id, int dbAppNo):刪除活動
|
||||
- 呼叫 DAC_Classes.DeleteOne(int ID, int DB_APPNO)
|
||||
- 回傳:BaseResponse(Success, Message)
|
||||
|
||||
- SearchProjects(string keyword):搜尋計畫(用於自動完成)
|
||||
- 呼叫 DAC_BPAA.Select(keyword)
|
||||
- 回傳:BaseResponse(Success, Message, Data: NameValueList)
|
||||
|
||||
- ExportClassesReport(int classesID, string timeFormat = "datetime"):匯出學員簽到表
|
||||
- 輸入參數:classesID(課程 ID)、timeFormat(時間格式,"datetime" 或 "time")
|
||||
- 查詢課程及參加人員資料,使用 NPOI 產生 Excel
|
||||
- 回傳:BaseResponse(Success, Message, Data: { FileName, FileBase64, FileSize, DataCount })
|
||||
|
||||
- ExportClassesList(DateTime? courseDate1, DateTime? courseDate2, string projectID):匯出課程清單
|
||||
- 輸入參數:courseDate1(課程日期起)、courseDate2(課程日期迄)、projectID(計畫代號)
|
||||
- 查詢課程清單及各課程的參加人員統計,使用 NPOI 產生 Excel
|
||||
- 回傳:BaseResponse(Success, Message, Data: { FileName, FileBase64, FileSize })
|
||||
@@ -0,0 +1,44 @@
|
||||
# 簡訊帳號管理
|
||||
|
||||
用來管理計畫的簡訊發送帳號密碼
|
||||
|
||||
## 資料表
|
||||
- 計畫資料表 BPAA:只用來做輸入的自動完成
|
||||
- 資料存取類別 DAC_BPAA
|
||||
- 計畫簡訊帳號密碼 ProjectMMSAccount
|
||||
- 資料存取類別 DAC_ProjectMMSAccount
|
||||
- 資料集合類別 ProjectMMSAccountList
|
||||
- 資料紀錄類別 ProjectMMSAccountItem
|
||||
- 類別已存在,不需撰寫
|
||||
- 資料表結構
|
||||
|No |Field Name |Data Type|Length|Not Null|PK |Identity|Description |
|
||||
|---|-----------|---------|------|--------|---|--------|---------------|
|
||||
|1 |ID |INT | |V |V |V |流水號 |
|
||||
|2 |ProjectID |NVARCHAR |20 |V | | |計畫代號 |
|
||||
|3 |MMSAccount |NVARCHAR |50 |V | | |簡訊帳號 |
|
||||
|4 |MMSPassword|NVARCHAR |50 |V | | |簡訊密碼 |
|
||||
|
||||
## 前端畫面檔
|
||||
- ~/Forms/MessageAccountManage.aspx
|
||||
- ~/Scripts/MessageAccountManage.js
|
||||
- 使用 Vue.js,不使用 Server control
|
||||
- 參照專案其他畫面的做法,分為查詢區域、列表區域、新增修改彈窗
|
||||
- 刪除前需要確認
|
||||
|
||||
## 後端服務
|
||||
|
||||
### 計畫輸入自動完成
|
||||
- ~/Services/MessageAccountManage.asmx/SearchProjects(string keyword)
|
||||
- 呼叫 DAC_BPAA.Select(keyword)
|
||||
- 回傳:BaseResponse(Success, Message, Data: NameValueList)
|
||||
|
||||
### 計畫簡訊帳號密碼 CRUD
|
||||
- ~/Services/MessageAccountManage.asmx
|
||||
- 查詢方法 Search(int pageNo, int pageSize, string projectID)
|
||||
- 每筆結果補填 ProjectName(由 DAC_BPAA.SelectProjectName 查詢)
|
||||
- 回傳:BaseResponse(Success, Message, Data: ProjectMMSAccountList, TotalCount)
|
||||
- 存檔方法 Save(bool isNew, ProjectMMSAccountItem item)
|
||||
- 新增、修改時都需檢查 ProjectID 必填且唯一
|
||||
- 回傳:BaseResponse(Success, Message, Data: 儲存後的 ProjectMMSAccountItem)
|
||||
- 刪除方法 Delete(int id, int dbAppNo)
|
||||
- 回傳:BaseResponse(Success, Message)
|
||||
@@ -0,0 +1,72 @@
|
||||
# 發送簡訊
|
||||
|
||||
## 架構
|
||||
* 從 Global.asax 的 Application_Start 事件啟動一個 Timer(預設每 1 分鐘觸發),定時啟動 SMSSendingService
|
||||
* 發送服務(Services/SMSSendingService.cs)
|
||||
* 是單例類(Singleton),有 IsBusy 狀態可以顯示是否正在忙碌
|
||||
* 每次啟動就把待發送簡訊全部發完
|
||||
* 啟動時(Start 方法)
|
||||
* 若 _busy == true 則直接返回,避免重複執行
|
||||
* 設定 _busy = true
|
||||
* 查詢 MessageQueue 表 Status 是 PENDING 或 SENDING 的
|
||||
* 依課程 ProjectID 查詢對應的簡訊帳號密碼(DAC_ProjectMMSAccount),若無設定則使用系統預設帳號密碼
|
||||
* 逐一發送(SendMessage 方法)
|
||||
* 每一個發送開始時改狀態為 SENDING
|
||||
* 呼叫 EVERY8DSMSProvider.SendMMS 發送
|
||||
* 成功或失敗結果寫入 MessageLog 表
|
||||
* 刪除 MessageQueue 紀錄
|
||||
* 每一個發送做一個 DB transaction
|
||||
* 最後重置 _busy = false(在 finally 確保執行)
|
||||
* 錯誤寫入 ~/Log/SMSError_yyyyMMdd.txt
|
||||
|
||||
## 預約發送(加入佇列)
|
||||
* Services/SignUpService.asmx
|
||||
* METHOD SendSmsBatch(int courseID, List<int> signupIds)
|
||||
* 驗證課程的 NotificationTitle 和 NotificationTemplate 已設定
|
||||
* 對每位參加人員
|
||||
* 若無 QRCode 則自動產生(DAC_SignUp.GenQRCodeText)並更新回資料表
|
||||
* 以 ZXing 產生 QRCode 圖片,轉成 Base64
|
||||
* 將訊息寫入 MessageQueue 表,Status = "PENDING"
|
||||
* NotificationTemplate 支援替換字串:{課程日期}/{活動日期}、{課程名稱}/{活動名稱}、{課程地點}/{活動地點}、{學員姓名}、{開始時間}、{結束時間}、{講師}
|
||||
* 回傳:BaseResponse(Success, Message, Data: { SuccessCount, FailedCount, SuccessRecords, Errors, TotalRequested })
|
||||
|
||||
## 資料表
|
||||
|
||||
### 待發送簡訊 MessageQueue
|
||||
* 資料存取類別 DAC_MessageQueue
|
||||
* 資料表結構
|
||||
| No | Field Name | Data Type | Length | Not Null | PK | Identity | Description |
|
||||
|----|-------------|-----------|--------|----------|----|----------|-----------------------------|
|
||||
| 1 | ID | INT | | V | V | V | 流水號 |
|
||||
| 2 | CourseID | INT | | V | | | 課程ID |
|
||||
| 3 | Status | NVARCHAR | 10 | | | | 發送狀態 PENDING = 等候發送 |
|
||||
| | | | | | | | SENDING = 發送中 |
|
||||
| | | | | | | | SENT = 已發送 |
|
||||
| | | | | | | | FAILED = 發送失敗 |
|
||||
| 4 | Mobile | NVARCHAR | 20 | | | | 手機號 |
|
||||
| 5 | Subject | NVARCHAR | 100 | | | | 簡訊標題 |
|
||||
| 6 | Content | NVARCHAR | 500 | | | | 發送內容 |
|
||||
| 7 | QRCode | TEXT | | | | | QRCode 圖片的 BASE64 |
|
||||
| 8 | Name | NVARCHAR | 100 | | | | 學員姓名 |
|
||||
| 9 | FailMessage | NVARCHAR | 200 | | | | 發送失敗訊息 |
|
||||
|
||||
|
||||
### 發送紀錄 MessageLog
|
||||
* 資料存取類別 DAC_MessageLog
|
||||
* 資料表結構
|
||||
| No | Field Name | Data Type | Length | Not Null | PK | Identity | Description |
|
||||
|----|-------------|-----------|--------|----------|----|----------|------------------------|
|
||||
| 1 | ID | INT | | V | V | V | 流水號 |
|
||||
| 2 | CourseID | INT | | V | | | 課程ID |
|
||||
| 3 | Status | NVARCHAR | 10 | | | | 發送狀態 SENT = 已發送 |
|
||||
| | | | | | | | FAILED = 發送失敗 |
|
||||
| 4 | Mobile | NVARCHAR | 20 | | | | 手機號 |
|
||||
| 5 | Subject | NVARCHAR | 100 | | | | 簡訊標題 |
|
||||
| 6 | Content | NVARCHAR | 500 | | | | 發送內容 |
|
||||
| 7 | Name | NVARCHAR | 100 | | | | 學員姓名 |
|
||||
| 8 | FailMessage | NVARCHAR | 200 | | | | 發送失敗訊息 |
|
||||
|
||||
## 簡訊服務商
|
||||
服務商:EVERY8D
|
||||
具體的簡訊發送實作在 Services/EVERY8DSMSProvider.cs
|
||||
帳號密碼設定在 PublicVariable(系統預設)或各計畫的 ProjectMMSAccount 資料表(計畫特定)
|
||||
@@ -0,0 +1,50 @@
|
||||
# 群組人員管理
|
||||
|
||||
## 畫面檔:
|
||||
~/Forms/RoleManage.aspx
|
||||
|
||||
## 畫面排列:
|
||||
左側 1/3:群組清單區域
|
||||
- 顯示所有系統群組以及說明的列表。
|
||||
右側 2/3:人員清單區域
|
||||
- 左半部:該群組下所有成員列表(群組成員)
|
||||
- 右半部:人員查詢區域
|
||||
* 查詢條件:員工編號或姓名
|
||||
* 查詢結果:符合條件的員工列表(可加入群組)
|
||||
功能說明:
|
||||
- 從右側人員查詢結果中選擇成員,點擊「加入群組」按鈕,將該成員加入左側所選群組中。
|
||||
- 從左側群組成員列表中選擇成員,點擊「移除群組」按鈕,將該成員從群組中移除。
|
||||
- 支援多選成員進行批次加入或移除操作。
|
||||
|
||||
## 資料來源:
|
||||
- 群組清單及說明:程式內定義的 GroupList 常數陣列(位置:RoleManage.aspx 裡 Vue data 的 GroupList,內容我會補充上去)
|
||||
GroupList 結構:[{ id: '群組代碼', name: '群組名稱', description: '群組說明' }, ...]
|
||||
- 群組成員列表:來自 DAC_BWEH.SelectByGroupId,DAC_BWEH 為群組與員工對應表,儲存哪些員工屬於哪些群組,查詢結果的 Name 是員工姓名,Value 是員工編號。
|
||||
- 人員查詢,來自 Models.DAC_BPSN.Select,查詢結果的 Name 是員工姓名,Value 是員工編號。
|
||||
|
||||
## 前端程式碼:
|
||||
- 使用 Vue.js 實現動態資料綁定與操作。
|
||||
- 不使用 Server control
|
||||
|
||||
## 後端程式碼:
|
||||
- 使用 WebService 實現非同步資料交換。
|
||||
- 提供 API 端點處理成員搜尋、成員加入與移除群組的請求。
|
||||
|
||||
## WebService 端點:Services/RoleManageService.asmx
|
||||
- SearchEmployees(string keyword):搜尋員工,關鍵字可為員工編號或姓名
|
||||
回傳:BaseResponse(Success, Message, Data: NameValueList, TotalCount)
|
||||
|
||||
- GetGroupMembers(string groupID):取得群組成員列表
|
||||
回傳:BaseResponse(Success, Message, Data: NameValueList, TotalCount)
|
||||
|
||||
- AddMemberToGroup(string groupID, string[] employeeIDs):將成員加入群組
|
||||
回傳:BaseResponse(Success, Message, TotalCount: 成功加入筆數)
|
||||
|
||||
- RemoveMemberFromGroup(string groupID, string[] employeeIDs):將成員從群組移除
|
||||
回傳:BaseResponse(Success, Message, TotalCount: 成功移除筆數)
|
||||
|
||||
## 操作流程:
|
||||
1. 從左側群組清單中選擇一個群組
|
||||
2. 右側自動載入該群組的現有成員
|
||||
3. 使用右側查詢區域搜尋要加入的人員
|
||||
4. 選擇人員後點擊「加入群組」或從成員列表中「移除群組」
|
||||
@@ -0,0 +1,37 @@
|
||||
# 課程報表
|
||||
|
||||
## 畫面檔:
|
||||
~/Forms/ClassesReport.aspx
|
||||
|
||||
## 資料存取類別
|
||||
~/Models/DAC_Classes1.cs / DAC_Classes2.cs
|
||||
- DAC_Classes:資料處理類別
|
||||
- ClassesList:資料集類別
|
||||
- ClassesItem:資料項目類別
|
||||
~/Models/DAC_SignUp1.cs / DAC_SignUp2.cs
|
||||
- DAC_SignUp:資料處理類別
|
||||
- SignUpList:資料集類別
|
||||
- SignUpItem:資料項目類別
|
||||
|
||||
## 畫面排列:
|
||||
上方:搜尋列
|
||||
- 比照 ~/Forms/ClassesList.aspx
|
||||
下方:搜尋結果列表
|
||||
- 除了操作欄位之外的資料顯示欄位比照 ~/Forms/ClassesList.aspx
|
||||
- 報表匯出按鈕放置在操作欄,按下後呼叫後端的 ExportClassesReport
|
||||
|
||||
## 後端處理
|
||||
- ~/Services/ClassesService.asmx
|
||||
|
||||
- ExportClassesReport(int classesID, string timeFormat = "datetime"):匯出學員簽到表
|
||||
- 輸入參數:classesID(課程 ID)、timeFormat(時間格式,"datetime" 顯示完整日期時間,"time" 只顯示時間)
|
||||
- 查詢課程資訊(含 ProjectName)及該課程所有參加人員
|
||||
- 統計:實到人數、應到人數、缺席人數、現場報名、異常人數
|
||||
- 使用 NPOI 產生 Excel,欄位:序號、學員姓名、手機號碼、身分證字號、性別、認定次數、用餐別、報名方式、簽到時間、簽退時間、出席狀況
|
||||
- 回傳:BaseResponse(Success, Message, Data: { FileName, FileBase64, FileSize, DataCount })
|
||||
|
||||
- ExportClassesList(DateTime? courseDate1, DateTime? courseDate2, string projectID):匯出課程清單
|
||||
- 輸入參數:courseDate1(課程日期起)、courseDate2(課程日期迄)、projectID(計畫代號)
|
||||
- 查詢符合條件的課程,並逐一統計各課程的實到/應到/缺席/現場報名人數
|
||||
- 使用 NPOI 產生 Excel,欄位:課程名稱、課程地點、授課講師、實到人數、應到人數、缺席人數、現場報名
|
||||
- 回傳:BaseResponse(Success, Message, Data: { FileName, FileBase64, FileSize })
|
||||
@@ -0,0 +1,45 @@
|
||||
# 資料同步
|
||||
|
||||
## 員工資料下載
|
||||
* Services/BPSNService.asmx
|
||||
* METHOD Download:下載員工資料
|
||||
* 資料存取類別:DAC_BPSN
|
||||
* 資料讀取方法:SelectForClient()
|
||||
|
||||
## 報到資料上傳
|
||||
* Services/SignUpService.asmx
|
||||
* METHOD UploadCheckIns(int courseID, List<CheckInItem> items):上傳簽到簽退資料清單
|
||||
* 資料表
|
||||
* SignUp 參加人員
|
||||
* Classes 課程
|
||||
* 資料存取類別
|
||||
* DAC_SignUp 參加人員
|
||||
* DAC_Classes 課程
|
||||
* 上傳資料欄位(CheckInItem)
|
||||
* CourseID (INTEGER NOT NULL) - 課程ID
|
||||
* Name (TEXT NOT NULL) - 學員姓名
|
||||
* Mobile (TEXT NOT NULL) - 手機號
|
||||
* IDNumber (TEXT) - 身分證字號
|
||||
* IDType (TEXT) - 身分別
|
||||
* MealType (TEXT) - 餐點
|
||||
* Email (TEXT) - 電子郵件
|
||||
* SignUpType (TEXT) - 報名方式(預約 / 現場)
|
||||
* CheckInType (TEXT) - 簽到類別(CHECKIN / CHECKOUT)
|
||||
* CheckInTime (DATETIME) - 簽到/簽退時間
|
||||
* 驗證規則
|
||||
* CourseID: 必填、必須存在於課程表 Classes.ID
|
||||
* Name: 必填
|
||||
* Mobile: 必填
|
||||
* SignUpType: 必填,允許值 (預約 / 現場)
|
||||
* CheckInType: 必填,允許值(CHECKIN / CHECKOUT)
|
||||
* CheckInTime: 必填,格式 yyyy-MM-dd HH:mm:ss
|
||||
* 處理邏輯
|
||||
* 用 CourseID 查詢 Classes.ID,若不存在則拒絕整批資料
|
||||
* 按 (CourseID, Name, Mobile) 作為複合主鍵查詢 SignUp 表
|
||||
* 若找到則依照 CheckInType 使用傳入的 CheckInTime 更新 CheckInTime/CheckOutTime,計入成功筆數
|
||||
* 若沒找到則新增 (SignUpType="現場"),並依 CheckInType 設定時間欄位,計入成功筆數
|
||||
* 不使用 transaction
|
||||
* 回應格式
|
||||
* 成功: { Success: true, Message: "...", Data: { CreatedCount, UpdatedCount, FailedCount, SkippedCount, SuccessIDs, Errors } }
|
||||
* 失敗: { Success: false, Message: "..." }
|
||||
|
||||
Reference in New Issue
Block a user