From c2a3c0e5bfeca43bdfcaa1b15ac512613f2eac5d Mon Sep 17 00:00:00 2001 From: yiming Date: Fri, 26 Dec 2025 01:46:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=9C=E5=B0=8B=E8=BA=AB=E4=BB=BD=E8=AD=89?= =?UTF-8?q?=E8=99=9F,=20=E9=9B=BB=E8=A9=B1=E5=8A=9F=E8=83=BD=E9=81=B8?= =?UTF-8?q?=E9=A0=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/search_keyword.md | 209 +++++++++++++++ web/App_Code/GlobalVariables.cs | 16 ++ web/App_Code/Model/Model.Context.cs | 2 +- web/App_Code/Model/Model.Designer.cs | 2 +- web/App_Code/Model/Model.cs | 19 +- web/App_Code/Model/Model.edmx | 261 ++++++++++--------- web/App_Code/Model/Model.edmx.diagram | 18 +- web/App_Code/Model/Partial/follower.cs | 28 ++ web/App_Code/Model/ViewModel/follower.cs | 1 + web/App_Code/api/FollowerController.cs | 11 + web/App_Code/appapi/appFollowerController.cs | 11 + web/App_Code/encrypt.cs | 61 +++++ web/admin/follower/index.aspx | 5 + web/admin/follower/index.aspx.cs | 13 + web/admin/follower/reg.aspx.cs | 14 + web/web.config | 11 +- 16 files changed, 528 insertions(+), 154 deletions(-) create mode 100644 data/search_keyword.md diff --git a/data/search_keyword.md b/data/search_keyword.md new file mode 100644 index 0000000..e4a8e29 --- /dev/null +++ b/data/search_keyword.md @@ -0,0 +1,209 @@ +# 新增 followers 欄位 search_keywords +- 參考程式 : D:\dev\ez\17168erp\git_17888\web\admin\follower\follower_code.aspx + + ``` + string joinedString = string.Join("|", new string[] { + phone_decrypted, // 解密後的 phone 電話號碼 + cellphone_decrypted, // 解密後的 cellphone 手機號碼 + id_code_decrypted, // 解密後的 id_code 身份證號 + passport_decrypted // 解密後的 passport 護照號碼 + }); + // 將連接字串轉換為 HEX + string hexString = ""; + try { + byte[] bytes = Encoding.UTF8.GetBytes(joinedString); + hexString = BitConverter.ToString(bytes).Replace("-", "").ToLower(); + } catch { + hexString = ""; + } + ``` + +- 原本table: followers 有4個欄位 phone, cellphone, id_code, passport +- 是加密儲存, 但因部份用戶認為方便比加密重要, 所以折衷加上欄位: search_keywords, 如上方式"編碼", 而非加密。 +- 為保持原程式安全性, 本功能應為: 輔助, 選用, 不使用此機制, 就保持安全性優先。使用了, 就放棄加密。 +- 為保彈性, 在web.config加一個參數: use search keywords, 為true/false, 目前設true, 並讀入為static class property。 +- 相關機制運作, 都只有在該值為true時作用。 + +## 應作用機制: + +針對以下程式, 若web.config use search keywords為true: +``` +D:\dev\ez\17168erp\git_17888\web\App_Code\api\FollowerController.cs +D:\dev\ez\17168erp\git_17888\web\admin\follower\index.aspx +D:\dev\ez\17168erp\git_17888\web\admin\follower\index.aspx.cs +D:\dev\ez\17168erp\git_17888\web\admin\follower\reg.aspx +D:\dev\ez\17168erp\git_17888\web\admin\follower\reg.aspx.cs +D:\dev\ez\17168erp\git_17888\web\App_Code\Model\Partial\follower.cs +D:\dev\ez\17168erp\git_17888\web\App_Code\api\FollowerController.cs +D:\dev\ez\17168erp\git_17888\web\App_Code\appapi\appFollowerController.cs +``` + +- 搜尋時, 加上一個: 電話/證號 搜尋欄位, 將輸入的字串轉為HEX做 search_keywords like '%...%' 搜尋 +- 儲存時, 除了原來欄位加密照原方式運行, 另外將4個欄位解密/組合/轉為HEX字串, 存入search_keywords + +# 現有程式檢查 + +## 1. 資料庫檢查 +- **followers 資料表** + - ✅ 已有加密欄位: `phone`, `cellphone`, `id_code`, `passport` + - ⚠️ **需新增**: `search_keywords` VARCHAR(MAX) 欄位 (用於存放 HEX 編碼字串) + +## 2. 加密解密機制檢查 +- **MyWeb.encrypt 類別** (App_Code/encrypt.cs) + - ✅ 已有加密方法: `EncryptAutoKey()` + - ✅ 已有解密方法: `DecryptAutoKey()` + - ✅ 已有 `followerHash()` 方法 (可參考其 HEX 轉換邏輯) + +## 3. 現有程式搜尋功能 +### 3.1 API 控制器 - FollowerController.cs +- **路徑**: D:\dev\ez\17168erp\git_17888\web\App_Code\api\FollowerController.cs +- **現況**: + - `GetList()` 方法有搜尋功能 + - 使用 `Contains()` 搜尋 `f_number`, `u_name`, `address` 等欄位 + - ⚠️ **無加密欄位搜尋**: phone, cellphone, id_code, passport 欄位無法直接搜尋 + +### 3.2 API 控制器 - appFollowerController.cs +- **路徑**: D:\dev\ez\17168erp\git_17888\web\App_Code\appapi\appFollowerController.cs +- **現況**: 與 FollowerController.cs 類似 + - ⚠️ 同樣無加密欄位搜尋功能 + +### 3.3 前端頁面 - index.aspx +- **路徑**: D:\dev\ez\17168erp\git_17888\web\admin\follower\index.aspx +- **現況**: + - 搜尋欄位: 信眾編號、信眾姓名、地址、生日、國籍 + - ⚠️ **缺少**: 電話/證號 搜尋欄位 + +### 3.4 後端頁面 - index.aspx.cs +- **路徑**: D:\dev\ez\17168erp\git_17888\web\admin\follower\index.aspx.cs +- **現況**: + - `searchData()` 方法處理搜尋條件 + - ⚠️ 無加密欄位搜尋邏輯 + +## 4. 儲存功能檢查 +### 4.1 註冊頁面 - reg.aspx.cs +- **路徑**: D:\dev\ez\17168erp\git_17888\web\admin\follower\reg.aspx.cs +- **現況**: + - ✅ `add_Click()` 新增方法: 有使用 `EncryptAutoKey()` 加密 + - ✅ `edit_Click()` 修改方法: 有使用 `EncryptAutoKey()` 加密 + - ⚠️ **缺少**: 儲存時需要生成 search_keywords + +### 4.2 Model Partial 類別 - follower.cs +- **路徑**: D:\dev\ez\17168erp\git_17888\web\App_Code\Model\Partial\follower.cs +- **現況**: + - ✅ 有各種輔助方法 + - ⚠️ **建議新增**: 生成 search_keywords 的輔助方法 + +## 5. Web.config 檢查 +- **路徑**: D:\dev\ez\17168erp\git_17888\web\web.config +- **現況**: + - ⚠️ **需新增**: `` 參數 + +# 程式工作規劃 + +## 階段一:資料庫與配置 (優先) +1. **資料庫結構調整** + - [ ] 在 `followers` 資料表新增 `search_keywords` VARCHAR(MAX) 欄位 + - [ ] 執行 SQL Script 更新結構 + - [ ] 備份現有資料 + +2. **Web.config 配置** + - [ ] 新增 `UseSearchKeywords` 參數 (預設值: true) + - [ ] 建立靜態類別讀取此設定值 + +## 階段二:核心功能實作 +3. **encrypt.cs 擴充** (D:\dev\ez\17168erp\git_17888\web\App_Code\encrypt.cs) + - [ ] 新增 `GenerateSearchKeywords()` 方法 + ```csharp + // 輸入: phone, cellphone, id_code, passport (加密字串) + // 輸出: HEX 編碼的搜尋關鍵字 + public string GenerateSearchKeywords(string phone, string cellphone, + string id_code, string passport) + ``` + - [ ] 參考現有 follower_code.aspx 的轉換邏輯 + +4. **follower.cs Partial 擴充** (D:\dev\ez\17168erp\git_17888\web\App_Code\Model\Partial\follower.cs) + - [ ] 新增屬性 `public string search_keywords { get; set; }` + - [ ] 新增靜態方法 `UpdateSearchKeywords()` + +## 階段三:儲存功能調整 +5. **reg.aspx.cs 修改** (D:\dev\ez\17168erp\git_17888\web\admin\follower\reg.aspx.cs) + - [ ] 修改 `add_Click()` 方法 + - 新增資料後,如果 UseSearchKeywords = true + - 將 phone, cellphone, id_code, passport 解密 + - 調用 GenerateSearchKeywords() 生成 HEX + - 更新 search_keywords 欄位 + + - [ ] 修改 `edit_Click()` 方法 + - 同上述邏輯更新 search_keywords + +6. **API 控制器調整** + - [ ] FollowerController.cs: 調整 POST/PUT 方法 + - [ ] appFollowerController.cs: 同步調整 + +## 階段四:搜尋功能實作 +7. **前端頁面 - index.aspx** + - [ ] 在搜尋區塊新增「電話/證號」搜尋欄位 + - [ ] 修改 Vue.js data 區塊,新增 `search.phone_idcode` 欄位 + - [ ] 修改 `btn_search()` 方法傳送新參數 + +8. **後端頁面 - index.aspx.cs** + - [ ] 修改 `searchData()` 方法 + - [ ] 新增電話/證號搜尋邏輯 + ```csharp + if (!isStrNull(s_phone_idcode.Value) && UseSearchKeywords) + { + string hexSearch = ConvertToHex(s_phone_idcode.Value.Trim()); + qry = qry.Where(o => o.search_keywords.Contains(hexSearch)); + } + ``` + +9. **API 控制器搜尋功能** + - [ ] FollowerController.cs - `GetList()` 方法 + - 新增 phone_idcode 參數處理 + - 如果 UseSearchKeywords = true,使用 HEX 搜尋 + - 如果 UseSearchKeywords = false,返回錯誤或略過 + + - [ ] appFollowerController.cs - 同步修改 + +## 階段五:資料遷移與測試 +10. **現有資料更新** + - [ ] 撰寫 SQL Script 或後台工具 + - [ ] 批次更新現有 followers 的 search_keywords 欄位 + - [ ] 驗證資料完整性 + +11. **測試計畫** + - [ ] 單元測試: HEX 轉換正確性 + - [ ] 整合測試: 新增/修改資料後 search_keywords 正確生成 + - [ ] 功能測試: 搜尋功能正常運作 + +## 階段六:文件與部署 +12. **文件撰寫** + - [ ] 更新 API 文件 + - [ ] 撰寫使用者手冊 + - [ ] 記錄資料庫變更 + +13. **部署準備** + - [ ] 準備 SQL 更新腳本 + - [ ] 準備回滾計畫 + - [ ] 通知相關人員 + +# 程式問題 + +## 技術實作問題 + +### 8. 欄位為 NULL 的處理 +- **6題**: phone, cellphone, id_code, passport 可能為 NULL +- **風險**: 轉 HEX 時可能發生錯誤 +- **建議**: + - 在 GenerateSearchKeywords() 方法中妥善處理 NULL 值 + - 使用 `string.Join("|", new string[] { ... }.Where(s => !string.IsNullOrEmpty(s)))` + + +## 建議的緩解措施優先順序 +實作優先順序建議 + +### 高優先級 (必須處理) +1. **NULL 值處理**: 確保程式不會因為 NULL 值崩潰 +2. **現有資料遷移**: 確保資料完整性 +3. **錯誤處理**: 完善的例外處理機制 + diff --git a/web/App_Code/GlobalVariables.cs b/web/App_Code/GlobalVariables.cs index 8dd99f3..5f56cbc 100644 --- a/web/App_Code/GlobalVariables.cs +++ b/web/App_Code/GlobalVariables.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Configuration; using System.Linq; using System.Web; @@ -9,4 +10,19 @@ using System.Web; public static class GlobalVariables { // FNumberLock 已移除,因為改用資料庫直接取號,不再需要 Application 狀態鎖定 + + /// + /// 是否啟用 search_keywords 搜尋功能 + /// + public static bool UseSearchKeywords + { + get + { + string configValue = ConfigurationManager.AppSettings["UseSearchKeywords"]; + if (string.IsNullOrEmpty(configValue)) + return false; + + return configValue.Equals("true", StringComparison.OrdinalIgnoreCase); + } + } } \ No newline at end of file diff --git a/web/App_Code/Model/Model.Context.cs b/web/App_Code/Model/Model.Context.cs index 55693ea..d4d20be 100644 --- a/web/App_Code/Model/Model.Context.cs +++ b/web/App_Code/Model/Model.Context.cs @@ -81,7 +81,6 @@ namespace Model public virtual DbSet ShuWen { get; set; } public virtual DbSet transfer_register { get; set; } public virtual DbSet GuaDanOrder { get; set; } - public virtual DbSet GuaDanOrderGuest { get; set; } public virtual DbSet GuadanTimeSetting { get; set; } public virtual DbSet Region { get; set; } public virtual DbSet RegionAndRoomAndBedSchedule { get; set; } @@ -94,6 +93,7 @@ namespace Model public virtual DbSet AncestralTabletPositionRecord { get; set; } public virtual DbSet AncestralTabletRegistrant { get; set; } public virtual DbSet AncestralTabletStatus { get; set; } + public virtual DbSet GuaDanOrderGuest { get; set; } public virtual int pager_eztrust(Nullable startRowIndex, Nullable pageSize, string tableName, string columnName, string sqlWhere, string orderBy, ObjectParameter rowCount) { diff --git a/web/App_Code/Model/Model.Designer.cs b/web/App_Code/Model/Model.Designer.cs index 1c2d095..c69a080 100644 --- a/web/App_Code/Model/Model.Designer.cs +++ b/web/App_Code/Model/Model.Designer.cs @@ -1,4 +1,4 @@ -// 已啟用模型 'D:\17168erp_new_git\17168ERP\web\App_Code\Model\Model.edmx' 的 T4 程式碼產生。 +// 已啟用模型 'D:\dev\ez\17168erp\git_17888\web\App_Code\Model\Model.edmx' 的 T4 程式碼產生。 // 若要啟用舊版程式碼產生,請將 [程式碼產生策略] 設計工具屬性的值 //變更為 [舊版 ObjectContext]。當模型在設計工具中開啟時,這個屬性便可 //以在 [屬性] 視窗中使用。 diff --git a/web/App_Code/Model/Model.cs b/web/App_Code/Model/Model.cs index 450d467..1ca239e 100644 --- a/web/App_Code/Model/Model.cs +++ b/web/App_Code/Model/Model.cs @@ -936,6 +936,7 @@ namespace Model public string country { get; set; } public Nullable appellation_id { get; set; } public string follower_hash { get; set; } + public string search_keywords { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection activity_check { get; set; } @@ -1042,12 +1043,12 @@ namespace Model public Nullable OrderUuid { get; set; } public virtual follower followers { get; set; } + public virtual GuaDanOrder GuaDanOrder { get; set; } public virtual RegionRoomBed RegionRoomBed { get; set; } public virtual Room Room { get; set; } public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection RegionAndRoomAndBedSchedule { get; set; } - public virtual GuaDanOrder GuaDanOrder { get; set; } } } namespace Model @@ -1573,10 +1574,10 @@ namespace Model public System.Guid RoomUuid { get; set; } public string StatusCode { get; set; } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] - public virtual ICollection GuaDanOrderGuest { get; set; } public virtual Room Room { get; set; } public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection GuaDanOrderGuest { get; set; } } } namespace Model @@ -1589,8 +1590,8 @@ namespace Model [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public RegionRoomBedStatus() { - this.GuaDanOrderGuest = new HashSet(); this.RegionRoomBed = new HashSet(); + this.GuaDanOrderGuest = new HashSet(); } public string Code { get; set; } @@ -1599,10 +1600,10 @@ namespace Model public Nullable Category { get; set; } public bool IsDeleted { get; set; } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] - public virtual ICollection GuaDanOrderGuest { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection RegionRoomBed { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection GuaDanOrderGuest { get; set; } } } namespace Model @@ -1639,8 +1640,8 @@ namespace Model [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public Room() { - this.GuaDanOrderGuest = new HashSet(); this.RegionRoomBed = new HashSet(); + this.GuaDanOrderGuest = new HashSet(); } public string Name { get; set; } @@ -1653,11 +1654,11 @@ namespace Model public System.Guid Uuid { get; set; } public System.Guid RegionUuid { get; set; } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] - public virtual ICollection GuaDanOrderGuest { get; set; } public virtual Region Region { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection RegionRoomBed { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection GuaDanOrderGuest { get; set; } } } namespace Model diff --git a/web/App_Code/Model/Model.edmx b/web/App_Code/Model/Model.edmx index e887b85..9bd2192 100644 --- a/web/App_Code/Model/Model.edmx +++ b/web/App_Code/Model/Model.edmx @@ -480,6 +480,7 @@ + @@ -979,7 +980,7 @@ - + @@ -2156,7 +2157,7 @@ - + @@ -2971,6 +2972,7 @@ + @@ -4462,7 +4464,6 @@ - @@ -4478,26 +4479,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -4539,14 +4520,35 @@ - + + + + + + + + + + + + + + + + + + + + + + @@ -4841,28 +4843,7 @@ - - - - - - - - - - - - - - - - - - - - - - + @@ -4925,9 +4906,9 @@ - + @@ -4938,8 +4919,8 @@ - + @@ -4966,9 +4947,9 @@ - + @@ -4994,66 +4975,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5160,7 +5081,7 @@ - + @@ -5181,7 +5102,7 @@ - + @@ -5240,7 +5161,7 @@ - + @@ -5252,6 +5173,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5264,6 +5218,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5636,6 +5638,7 @@ + @@ -6122,22 +6125,6 @@ - - - - - - - - - - - - - - - - @@ -6311,7 +6298,23 @@ - + + + + + + + + + + + + + + + + + diff --git a/web/App_Code/Model/Model.edmx.diagram b/web/App_Code/Model/Model.edmx.diagram index 4de4ec0..4147bfb 100644 --- a/web/App_Code/Model/Model.edmx.diagram +++ b/web/App_Code/Model/Model.edmx.diagram @@ -4,7 +4,7 @@ - + @@ -131,21 +131,15 @@ - - + - - - - - @@ -160,8 +154,14 @@ - + + + + + + + diff --git a/web/App_Code/Model/Partial/follower.cs b/web/App_Code/Model/Partial/follower.cs index cacba58..cc1ece0 100644 --- a/web/App_Code/Model/Partial/follower.cs +++ b/web/App_Code/Model/Partial/follower.cs @@ -298,6 +298,34 @@ namespace Model var timestamp = DateTime.Now.ToString("HHmmss"); return prefix + datePart + timestamp; } + + /// + /// 更新指定 follower 的 search_keywords 欄位 + /// + /// follower 的 ID + /// 是否成功更新 + public static bool UpdateSearchKeywords(int followerId) + { + try + { + using (var db = new Model.ezEntities()) + { + var follower = db.followers.Find(followerId); + if (follower == null) + return false; + + MyWeb.encrypt enc = new MyWeb.encrypt(); + follower.search_keywords = enc.GenerateSearchKeywords(follower); + + db.SaveChanges(); + return true; + } + } + catch + { + return false; + } + } } } diff --git a/web/App_Code/Model/ViewModel/follower.cs b/web/App_Code/Model/ViewModel/follower.cs index aa36ac5..7dc70c3 100644 --- a/web/App_Code/Model/ViewModel/follower.cs +++ b/web/App_Code/Model/ViewModel/follower.cs @@ -42,6 +42,7 @@ namespace Model.ViewModel public string country { get; set; } public string country2 { get; set; } + public string phone_idcode { get; set; } // 電話/證號搜尋欄位 } public class followers_tablet { diff --git a/web/App_Code/api/FollowerController.cs b/web/App_Code/api/FollowerController.cs index eb8bede..eb581d9 100644 --- a/web/App_Code/api/FollowerController.cs +++ b/web/App_Code/api/FollowerController.cs @@ -173,6 +173,17 @@ public class FollowerController : ApiController } } + + // 電話/證號搜尋 (使用 search_keywords HEX 編碼) + if (!string.IsNullOrEmpty(q.phone_idcode) && GlobalVariables.UseSearchKeywords) + { + MyWeb.encrypt enc = new MyWeb.encrypt(); + string hexSearch = enc.ConvertToHex(q.phone_idcode.Trim()); + if (!string.IsNullOrEmpty(hexSearch)) + { + qry = qry.Where(o => o.search_keywords != null && o.search_keywords.Contains(hexSearch)); + } + } if (sortBy.Equals("f_number")) diff --git a/web/App_Code/appapi/appFollowerController.cs b/web/App_Code/appapi/appFollowerController.cs index 967ea6f..8c19a5d 100644 --- a/web/App_Code/appapi/appFollowerController.cs +++ b/web/App_Code/appapi/appFollowerController.cs @@ -158,6 +158,17 @@ public class appFollowerController : ApiController } } + + // 電話/證號搜尋 (使用 search_keywords HEX 編碼) + if (!string.IsNullOrEmpty(q.phone_idcode) && GlobalVariables.UseSearchKeywords) + { + MyWeb.encrypt enc = new MyWeb.encrypt(); + string hexSearch = enc.ConvertToHex(q.phone_idcode.Trim()); + if (!string.IsNullOrEmpty(hexSearch)) + { + qry = qry.Where(o => o.search_keywords != null && o.search_keywords.Contains(hexSearch)); + } + } if (sortBy.Equals("f_number")) diff --git a/web/App_Code/encrypt.cs b/web/App_Code/encrypt.cs index 1bc9138..5a53a43 100644 --- a/web/App_Code/encrypt.cs +++ b/web/App_Code/encrypt.cs @@ -127,6 +127,67 @@ namespace MyWeb char.IsLetterOrDigit(c)).ToArray()).ToUpper(); return SHA256(input); } + + /// + /// 生成 search_keywords 的 HEX 編碼字串 + /// + /// follower 物件 + /// HEX 編碼字串 + public string GenerateSearchKeywords(Model.follower follower) + { + try + { + // 解密各欄位 + string phone_decrypted = string.IsNullOrEmpty(follower.phone) ? "" : DecryptAutoKey(follower.phone); + string cellphone_decrypted = string.IsNullOrEmpty(follower.cellphone) ? "" : DecryptAutoKey(follower.cellphone); + string id_code_decrypted = string.IsNullOrEmpty(follower.id_code) ? "" : DecryptAutoKey(follower.id_code); + string passport_decrypted = string.IsNullOrEmpty(follower.passport) ? "" : DecryptAutoKey(follower.passport); + + // 組合字串 (使用 | 分隔) + string joinedString = string.Join("|", new string[] { + phone_decrypted, + cellphone_decrypted, + id_code_decrypted, + passport_decrypted + }); + + // 轉換為 HEX 編碼 + if (string.IsNullOrEmpty(joinedString.Replace("|", ""))) + { + return ""; // 如果所有欄位都是空的,返回空字串 + } + + byte[] bytes = Encoding.UTF8.GetBytes(joinedString); + string hexString = BitConverter.ToString(bytes).Replace("-", "").ToLower(); + return hexString; + } + catch + { + return ""; // 發生錯誤時返回空字串 + } + } + + /// + /// 將搜尋字串轉換為 HEX 編碼 (用於搜尋功能) + /// + /// 要搜尋的文字 + /// HEX 編碼字串 + public string ConvertToHex(string searchText) + { + try + { + if (string.IsNullOrEmpty(searchText)) + return ""; + + byte[] bytes = Encoding.UTF8.GetBytes(searchText); + string hexString = BitConverter.ToString(bytes).Replace("-", "").ToLower(); + return hexString; + } + catch + { + return ""; + } + } } } diff --git a/web/admin/follower/index.aspx b/web/admin/follower/index.aspx index 2379834..6b2ea3f 100644 --- a/web/admin/follower/index.aspx +++ b/web/admin/follower/index.aspx @@ -65,6 +65,7 @@ address: '', country: '', country2: '', + phone_idcode: '', // 電話/證號搜尋 /*注意這邊的參數不能跟下方print_search重複*/ }, //列印管理報表 @@ -561,6 +562,10 @@ +
+ + +
diff --git a/web/admin/follower/index.aspx.cs b/web/admin/follower/index.aspx.cs index 118d960..304ed49 100644 --- a/web/admin/follower/index.aspx.cs +++ b/web/admin/follower/index.aspx.cs @@ -245,6 +245,19 @@ public partial class admin_follower_index : MyWeb.config qry = qry.Where(o => o.address.Contains(s_address.Value.Trim())); _query += "地址:" + s_u_name.Value.Trim() + "\n"; } + + // 電話/證號搜尋 (使用 search_keywords HEX 編碼) + if (!isStrNull(s_phone_idcode.Value) && GlobalVariables.UseSearchKeywords) + { + MyWeb.encrypt encrypt = new MyWeb.encrypt(); + string hexSearch = encrypt.ConvertToHex(s_phone_idcode.Value.Trim()); + if (!string.IsNullOrEmpty(hexSearch)) + { + qry = qry.Where(o => o.search_keywords != null && o.search_keywords.Contains(hexSearch)); + _query += "電話/證號:" + s_phone_idcode.Value.Trim() + "\n"; + } + } + if (!isStrNull(s_birthday.Value) && isDate(s_birthday.Value)) { qry = qry.Where(o => o.birthday >= ValDate(s_birthday.Value)); diff --git a/web/admin/follower/reg.aspx.cs b/web/admin/follower/reg.aspx.cs index d724d6a..a3be434 100644 --- a/web/admin/follower/reg.aspx.cs +++ b/web/admin/follower/reg.aspx.cs @@ -230,6 +230,13 @@ public partial class admin_follower_reg : MyWeb.config if (_id > 0) { + // 如果啟用 search_keywords 功能,生成並更新 search_keywords + if (GlobalVariables.UseSearchKeywords) + { + followers.search_keywords = encrypt.GenerateSearchKeywords(followers); + _db.SaveChanges(); + } + Model.admin_log admin_log = new Model.admin_log(); admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Follower, (int)Model.admin_log.Status.Insert, f_number.Text + u_name.Text); @@ -305,6 +312,13 @@ public partial class admin_follower_reg : MyWeb.config followers.tab = tab.Value.Trim(','); followers.admin_log = admin.info.u_id + " " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); followers.follower_hash = encrypt.followerHash(followers.phone, followers.id_code); + + // 如果啟用 search_keywords 功能,生成並更新 search_keywords + if (GlobalVariables.UseSearchKeywords) + { + followers.search_keywords = encrypt.GenerateSearchKeywords(followers); + } + _db.SaveChanges(); Model.admin_log admin_log = new Model.admin_log(); diff --git a/web/web.config b/web/web.config index ce0bb37..eb77cc8 100644 --- a/web/web.config +++ b/web/web.config @@ -38,16 +38,17 @@ + + - - - + + +