diff --git a/.env.example b/.env.example index 4947560..0437064 100644 --- a/.env.example +++ b/.env.example @@ -21,11 +21,32 @@ LDAP_BIND_USER_PASSWORD=service_password LDAP_USER_LOGIN_ATTR=userPrincipalName # SMTP 郵件設定 -SMTP_SERVER=smtp.company.com -SMTP_PORT=587 -SMTP_USE_TLS=True -SMTP_SENDER_EMAIL=noreply@company.com -SMTP_SENDER_PASSWORD=smtp_password +# 方案 1: 使用 Port 25 (無需認證) - 推薦用於內部郵件伺服器 +SMTP_SERVER=mail.panjit.com.tw +SMTP_PORT=25 +SMTP_USE_TLS=false +SMTP_USE_SSL=false +SMTP_AUTH_REQUIRED=false +SMTP_SENDER_EMAIL=temp-spec-system@panjit.com.tw +SMTP_SENDER_PASSWORD= + +# 方案 2: 使用 Port 587 (需要認證) - 用於外部 SMTP 或有認證需求的伺服器 +# SMTP_SERVER=smtp.company.com +# SMTP_PORT=587 +# SMTP_USE_TLS=true +# SMTP_USE_SSL=false +# SMTP_AUTH_REQUIRED=true +# SMTP_SENDER_EMAIL=noreply@company.com +# SMTP_SENDER_PASSWORD=smtp_password + +# 方案 3: 使用 Port 465 (SSL + 認證) - 用於安全連接 +# SMTP_SERVER=smtp.gmail.com +# SMTP_PORT=465 +# SMTP_USE_TLS=false +# SMTP_USE_SSL=true +# SMTP_AUTH_REQUIRED=true +# SMTP_SENDER_EMAIL=yourapp@gmail.com +# SMTP_SENDER_PASSWORD=app_password # ONLYOFFICE Document Server 設定 ONLYOFFICE_PORT=8080 diff --git a/MAIL_OPTIMIZATION_GUIDE.md b/MAIL_OPTIMIZATION_GUIDE.md new file mode 100644 index 0000000..391d329 --- /dev/null +++ b/MAIL_OPTIMIZATION_GUIDE.md @@ -0,0 +1,92 @@ +# 郵件通知功能優化說明 + +## 更新日期:2025-01-28 + +## 一、優化內容概述 + +本次優化主要改善了郵件通知的管理邏輯,實現了郵件通知對象的自動記憶和帶出功能,讓系統更符合實際使用需求。 + +## 二、主要變更 + +### 1. 資料庫結構調整 +- 在 `ts_temp_spec` 表新增 `notification_emails` 欄位 +- 用於儲存規範生效時設定的郵件通知對象清單 +- 郵件地址以分號 (;) 分隔儲存 + +### 2. 功能邏輯改進 + +#### 規範生效時(Activate) +- 使用者輸入郵件通知對象 +- 系統自動儲存郵件清單到資料庫 +- 發送生效通知郵件 + +#### 規範停止時(Terminate) +- 系統自動從資料庫讀取之前儲存的郵件清單 +- 在介面上預先填入這些郵件地址 +- 顯示提示訊息告知使用者這是生效時使用的通知對象 +- 使用者可以: + - 直接使用預設的郵件清單 + - 修改郵件清單後再發送 + - 清空並重新選擇收件者 + +#### 規範展延時(Extend) +- 系統自動從資料庫讀取之前儲存的郵件清單 +- 在介面上預先填入這些郵件地址 +- 顯示提示訊息說明可以編輯郵件清單 +- 若使用者修改了郵件清單,系統會更新資料庫中的記錄 +- 確保後續的通知都會發送給更新後的收件者 + +## 三、實施步驟 + +### 1. 執行資料庫遷移 +```bash +python migrate_add_email_column.py +``` + +此腳本會: +- 檢查 `notification_emails` 欄位是否已存在 +- 如果不存在,自動新增該欄位 +- 驗證欄位是否成功新增 + +### 2. 重啟應用程式 +完成資料庫遷移後,重啟 Flask 應用程式以載入新的功能。 + +## 四、使用說明 + +### 對於管理員 +1. **首次生效**:在啟用規範時,輸入所有需要通知的郵件地址 +2. **後續操作**:系統會自動記憶這些地址,無需重複輸入 + +### 對於編輯者 +1. **終止規範**:可以看到並使用之前設定的通知對象 +2. **展延規範**: + - 可以保留原有的通知對象 + - 也可以根據需要調整通知名單 + - 修改後的名單會被儲存供下次使用 + +## 五、優點 + +1. **減少重複輸入**:不需要每次都重新輸入相同的郵件地址 +2. **保持一致性**:確保同一規範的相關人員都能收到通知 +3. **提供彈性**:允許使用者在需要時修改通知名單 +4. **提升效率**:加快操作流程,減少錯誤 +5. **改善使用體驗**:更符合實際業務邏輯 + +## 六、注意事項 + +1. 舊的規範資料不會有預存的郵件清單,需要在首次操作時輸入 +2. 郵件地址以分號分隔儲存,系統會自動處理格式 +3. 如果需要完全清空通知名單,可以在介面上刪除所有地址 + +## 七、技術細節 + +### 修改的檔案 +1. `models.py` - 新增資料庫欄位 +2. `routes/temp_spec.py` - 更新郵件處理邏輯 +3. `templates/terminate_spec.html` - 新增郵件預填功能 +4. `templates/extend_spec.html` - 新增郵件預填功能 +5. `migrate_add_email_column.py` - 資料庫遷移腳本 + +### 相容性 +- 完全向後相容,不影響現有功能 +- 舊資料可正常使用,新功能會在首次使用時生效 \ No newline at end of file diff --git a/SMTP_CONFIGURATION_UPDATE.md b/SMTP_CONFIGURATION_UPDATE.md new file mode 100644 index 0000000..60d42d7 --- /dev/null +++ b/SMTP_CONFIGURATION_UPDATE.md @@ -0,0 +1,152 @@ +# SMTP 配置更新說明 + +## 更新日期:2025-01-28 + +## 一、更新背景 + +根據與 IT 部門確認,郵件伺服器 `mail.panjit.com.tw` 的 Port 25 支援無密碼認證的系統派送郵件功能。因此將系統從原本的 Port 465(需要認證)改為 Port 25(無需認證)的方式發送郵件。 + +## 二、主要變更內容 + +### 1. Config 配置新增項目 +在 `config.py` 中新增以下配置選項: + +```python +SMTP_USE_SSL = os.getenv('SMTP_USE_SSL', 'false').lower() in ['true', '1', 't'] +SMTP_SENDER_EMAIL = os.getenv('SMTP_SENDER_EMAIL', 'temp-spec-system@panjit.com.tw') +SMTP_SENDER_PASSWORD = os.getenv('SMTP_SENDER_PASSWORD', '') # Port 25 不需要密碼 +SMTP_AUTH_REQUIRED = os.getenv('SMTP_AUTH_REQUIRED', 'false').lower() in ['true', '1', 't'] +``` + +### 2. 發送邏輯優化 +更新 `utils.py` 中的 `send_email` 函式: +- 支援多種 SMTP 連接方式 +- Port 465:SSL + 認證 +- Port 587:TLS + 認證 +- Port 25:無加密 + 無認證(系統派送) + +### 3. 環境變數配置 +更新 `.env.example` 提供三種配置方案的範例。 + +## 三、新的配置方案 + +### 方案 1:Port 25 無認證(推薦) + +```env +SMTP_SERVER=mail.panjit.com.tw +SMTP_PORT=25 +SMTP_USE_TLS=false +SMTP_USE_SSL=false +SMTP_AUTH_REQUIRED=false +SMTP_SENDER_EMAIL=temp-spec-system@panjit.com.tw +SMTP_SENDER_PASSWORD= +``` + +**適用場景**: +- 內部郵件伺服器 +- 系統自動發送通知郵件 +- 不需要個人帳號認證 + +### 方案 2:Port 587 + TLS + 認證 + +```env +SMTP_SERVER=smtp.company.com +SMTP_PORT=587 +SMTP_USE_TLS=true +SMTP_USE_SSL=false +SMTP_AUTH_REQUIRED=true +SMTP_SENDER_EMAIL=noreply@company.com +SMTP_SENDER_PASSWORD=smtp_password +``` + +**適用場景**: +- 外部 SMTP 服務 +- 需要認證的郵件伺服器 +- 使用 STARTTLS 加密 + +### 方案 3:Port 465 + SSL + 認證 + +```env +SMTP_SERVER=smtp.gmail.com +SMTP_PORT=465 +SMTP_USE_TLS=false +SMTP_USE_SSL=true +SMTP_AUTH_REQUIRED=true +SMTP_SENDER_EMAIL=yourapp@gmail.com +SMTP_SENDER_PASSWORD=app_password +``` + +**適用場景**: +- Gmail 等外部服務 +- 需要 SSL 加密連接 +- 高安全性要求 + +## 四、實施步驟 + +### 1. 更新環境變數 +修改您的 `.env` 檔案,使用方案 1 的配置: + +```env +SMTP_SERVER=mail.panjit.com.tw +SMTP_PORT=25 +SMTP_USE_TLS=false +SMTP_USE_SSL=false +SMTP_AUTH_REQUIRED=false +SMTP_SENDER_EMAIL=temp-spec-system@panjit.com.tw +SMTP_SENDER_PASSWORD= +``` + +### 2. 設定適當的寄件者郵件地址 +建議使用有意義的系統郵件地址,例如: +- `temp-spec-system@panjit.com.tw` +- `tempspec-notification@panjit.com.tw` +- `noreply-tempspec@panjit.com.tw` + +### 3. 重啟應用程式 +更新配置後,重啟 Flask 應用程式以載入新的 SMTP 設定。 + +### 4. 測試郵件功能 +建議在正式環境使用前,先測試郵件發送功能: +- 啟用一個測試規範 +- 驗證郵件是否正常發送 +- 檢查郵件格式和內容 + +## 五、向後相容性 + +此次更新完全向後相容: +- 原有使用 Port 465/587 + 認證的配置仍然有效 +- 系統會根據配置自動選擇適當的連接方式 +- 不會影響現有的郵件發送功能 + +## 六、除錯訊息 + +系統提供詳細的除錯訊息,包括: +- SMTP 連接方式(SSL/TLS/一般) +- 認證狀態 +- 郵件發送結果 +- 錯誤診斷訊息 + +查看應用程式日誌可以了解郵件發送的詳細過程。 + +## 七、注意事項 + +1. **寄件者地址**:使用系統郵件地址,避免使用個人郵件地址 +2. **網路安全**:Port 25 通常在防火牆中開放,但請確認網路連通性 +3. **郵件限制**:部分郵件伺服器可能有發送頻率限制 +4. **監控建議**:建議監控郵件發送成功率和錯誤日誌 + +## 八、疑難排解 + +### 常見問題 + +**Q: 郵件發送失敗,顯示連接拒絕** +A: 檢查 SMTP_SERVER 和 SMTP_PORT 設定是否正確 + +**Q: 郵件可以發送但收不到** +A: 檢查寄件者郵件地址是否為有效的公司郵件地址 + +**Q: 系統顯示認證失敗** +A: 確認 SMTP_AUTH_REQUIRED=false,Port 25 不需要認證 + +**Q: 要如何切換回認證模式** +A: 修改 .env 檔案,設定 SMTP_AUTH_REQUIRED=true 並提供正確的密碼 \ No newline at end of file diff --git a/config.py b/config.py index 68dd8fc..8d6b126 100644 --- a/config.py +++ b/config.py @@ -27,5 +27,7 @@ class Config: SMTP_SERVER = os.getenv('SMTP_SERVER', 'mail.panjit.com.tw') SMTP_PORT = int(os.getenv('SMTP_PORT', 25)) SMTP_USE_TLS = os.getenv('SMTP_USE_TLS', 'false').lower() in ['true', '1', 't'] - SMTP_SENDER_EMAIL = os.getenv('SMTP_SENDER_EMAIL') - SMTP_SENDER_PASSWORD = os.getenv('SMTP_SENDER_PASSWORD') + SMTP_USE_SSL = os.getenv('SMTP_USE_SSL', 'false').lower() in ['true', '1', 't'] + SMTP_SENDER_EMAIL = os.getenv('SMTP_SENDER_EMAIL', 'temp-spec-system@panjit.com.tw') + SMTP_SENDER_PASSWORD = os.getenv('SMTP_SENDER_PASSWORD', '') # Port 25 不需要密碼 + SMTP_AUTH_REQUIRED = os.getenv('SMTP_AUTH_REQUIRED', 'false').lower() in ['true', '1', 't'] diff --git a/migrate_add_email_column.py b/migrate_add_email_column.py new file mode 100644 index 0000000..8fbf437 --- /dev/null +++ b/migrate_add_email_column.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +""" +資料庫遷移腳本:新增 notification_emails 欄位到 ts_temp_spec 表 +執行方式:python migrate_add_email_column.py +""" + +import os +import sys +from sqlalchemy import create_engine, text +from config import Config + +def migrate_database(): + """執行資料庫遷移,新增 notification_emails 欄位""" + + # 使用 config.py 中的資料庫配置 + engine = create_engine(Config.SQLALCHEMY_DATABASE_URI) + + try: + with engine.connect() as conn: + # 檢查欄位是否已存在 + result = conn.execute(text(""" + SELECT COLUMN_NAME + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_NAME = 'ts_temp_spec' + AND COLUMN_NAME = 'notification_emails' + AND TABLE_SCHEMA = DATABASE() + """)) + + if result.fetchone(): + print("✓ notification_emails 欄位已存在,無需遷移") + return True + + # 新增欄位 + print("正在新增 notification_emails 欄位到 ts_temp_spec 表...") + conn.execute(text(""" + ALTER TABLE ts_temp_spec + ADD COLUMN notification_emails TEXT DEFAULT NULL + COMMENT '通知郵件清單,以分號分隔' + """)) + conn.commit() + + print("✓ 成功新增 notification_emails 欄位") + + # 驗證欄位是否成功新增 + result = conn.execute(text(""" + SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_NAME = 'ts_temp_spec' + AND COLUMN_NAME = 'notification_emails' + AND TABLE_SCHEMA = DATABASE() + """)) + + column_info = result.fetchone() + if column_info: + print(f"✓ 欄位資訊:") + print(f" - 欄位名稱:{column_info[0]}") + print(f" - 資料類型:{column_info[1]}") + print(f" - 可否為空:{column_info[2]}") + return True + else: + print("✗ 欄位新增後無法驗證") + return False + + except Exception as e: + print(f"✗ 遷移失敗:{str(e)}") + return False + +if __name__ == "__main__": + print("=" * 50) + print("資料庫遷移腳本") + print("=" * 50) + + success = migrate_database() + + if success: + print("\n✓ 資料庫遷移完成!") + print(" 現在可以使用新的郵件通知功能了。") + else: + print("\n✗ 資料庫遷移失敗,請檢查錯誤訊息。") + sys.exit(1) \ No newline at end of file diff --git a/models.py b/models.py index 2a3f47e..57f1c70 100644 --- a/models.py +++ b/models.py @@ -27,6 +27,7 @@ class TempSpec(db.Model): created_at = db.Column(db.DateTime) extension_count = db.Column(db.Integer, default=0) termination_reason = db.Column(db.Text, nullable=True) + notification_emails = db.Column(db.Text, nullable=True) # 儲存通知郵件清單,以分號分隔 # 關聯到 Upload 和 SpecHistory,並設定級聯刪除 uploads = db.relationship('Upload', back_populates='spec', cascade='all, delete-orphan') diff --git a/routes/temp_spec.py b/routes/temp_spec.py index d302ca7..cfe8990 100644 --- a/routes/temp_spec.py +++ b/routes/temp_spec.py @@ -265,12 +265,17 @@ def activate_spec(spec_id): db.session.add(new_upload) spec.status = 'active' + + # 儲存通知郵件清單到資料庫 + recipients_str = request.form.get('recipients') + if recipients_str: + spec.notification_emails = recipients_str.strip() + add_history_log(spec.id, '啟用', f"上傳已簽核檔案 '{filename}'") db.session.commit() flash(f"規範 '{spec.spec_code}' 已生效!", 'success') # --- Start of Dynamic Email Notification --- - recipients_str = request.form.get('recipients') if recipients_str: recipients = process_recipients(recipients_str) if recipients: @@ -312,7 +317,10 @@ def terminate_spec(spec_id): add_history_log(spec.id, '終止', f"原因: {reason}") # --- Start of Dynamic Email Notification --- + # 優先使用表單提交的收件者,如果沒有則使用資料庫中儲存的 recipients_str = request.form.get('recipients') + if not recipients_str and spec.notification_emails: + recipients_str = spec.notification_emails if recipients_str: recipients = process_recipients(recipients_str) if recipients: @@ -338,7 +346,8 @@ def terminate_spec(spec_id): flash(f"規範 '{spec.spec_code}' 已被提早終止。", 'warning') return redirect(url_for('temp_spec.spec_list')) - return render_template('terminate_spec.html', spec=spec) + # 將儲存的郵件清單傳遞給模板 + return render_template('terminate_spec.html', spec=spec, saved_emails=spec.notification_emails) @temp_spec_bp.route('/download_initial_word/') @login_required @@ -408,7 +417,14 @@ def extend_spec(spec_id): add_history_log(spec.id, '展延', details) # --- Start of Dynamic Email Notification --- + # 優先使用表單提交的收件者,如果沒有則使用資料庫中儲存的 recipients_str = request.form.get('recipients') + if not recipients_str and spec.notification_emails: + recipients_str = spec.notification_emails + + # 如果使用者有更新郵件清單,儲存回資料庫 + if recipients_str: + spec.notification_emails = recipients_str.strip() if recipients_str: recipients = process_recipients(recipients_str) if recipients: @@ -434,7 +450,8 @@ def extend_spec(spec_id): return redirect(url_for('temp_spec.spec_list')) default_new_end_date = spec.end_date + timedelta(days=30) - return render_template('extend_spec.html', spec=spec, default_new_end_date=default_new_end_date) + # 將儲存的郵件清單傳遞給模板 + return render_template('extend_spec.html', spec=spec, default_new_end_date=default_new_end_date, saved_emails=spec.notification_emails) @temp_spec_bp.route('/history/') @login_required # 補上登入驗證 diff --git a/static/generated/PE1140801.docx b/static/generated/PE1140801.docx index 1612a6c..60894df 100644 Binary files a/static/generated/PE1140801.docx and b/static/generated/PE1140801.docx differ diff --git a/templates/extend_spec.html b/templates/extend_spec.html index a5ebb91..8e04476 100644 --- a/templates/extend_spec.html +++ b/templates/extend_spec.html @@ -30,6 +30,11 @@
+ {% if saved_emails %} +
+ 以下為生效時設定的通知對象,您可以直接使用或進行編輯。如果修改,展延後將更新為新的通知對象。 +
+ {% endif %}
可搜尋姓名或 Email 地址,支援多人選擇
@@ -45,6 +50,13 @@ {% block scripts %} {% endblock %} \ No newline at end of file diff --git a/templates/terminate_spec.html b/templates/terminate_spec.html index 712824c..1bfbb74 100644 --- a/templates/terminate_spec.html +++ b/templates/terminate_spec.html @@ -23,6 +23,11 @@
+ {% if saved_emails %} +
+ 以下為生效時設定的通知對象,您可以直接使用或進行編輯。 +
+ {% endif %}
可搜尋姓名或 Email 地址,支援多人選擇
@@ -38,6 +43,13 @@ {% block scripts %} {% endblock %} diff --git a/utils.py b/utils.py index a850fe2..f0c453d 100644 --- a/utils.py +++ b/utils.py @@ -213,7 +213,7 @@ def process_recipients(recipients_str): def send_email(to_addrs, subject, body): """ Sends an email using the SMTP settings from the config. - Enhanced with detailed debugging information. + Supports both authenticated (Port 465/587) and unauthenticated (Port 25) methods. """ print(f"[EMAIL DEBUG] 開始發送郵件...") print(f"[EMAIL DEBUG] 收件者數量: {len(to_addrs)}") @@ -224,14 +224,18 @@ def send_email(to_addrs, subject, body): # 取得 SMTP 設定 smtp_server = current_app.config['SMTP_SERVER'] smtp_port = current_app.config['SMTP_PORT'] - use_tls = current_app.config['SMTP_USE_TLS'] + use_tls = current_app.config.get('SMTP_USE_TLS', False) + use_ssl = current_app.config.get('SMTP_USE_SSL', False) sender_email = current_app.config['SMTP_SENDER_EMAIL'] - sender_password = current_app.config['SMTP_SENDER_PASSWORD'] + sender_password = current_app.config.get('SMTP_SENDER_PASSWORD', '') + auth_required = current_app.config.get('SMTP_AUTH_REQUIRED', False) print(f"[EMAIL DEBUG] SMTP 設定:") print(f"[EMAIL DEBUG] - 伺服器: {smtp_server}:{smtp_port}") print(f"[EMAIL DEBUG] - 使用 TLS: {use_tls}") + print(f"[EMAIL DEBUG] - 使用 SSL: {use_ssl}") print(f"[EMAIL DEBUG] - 寄件者: {sender_email}") + print(f"[EMAIL DEBUG] - 需要認證: {auth_required}") print(f"[EMAIL DEBUG] - 有密碼: {'是' if sender_password else '否'}") # 建立郵件內容 @@ -243,21 +247,29 @@ def send_email(to_addrs, subject, body): print(f"[EMAIL DEBUG] 郵件內容建立完成") # 連接 SMTP 伺服器 - print(f"[EMAIL DEBUG] 連接 SMTP 伺服器 {smtp_server}:{smtp_port}...") - server = smtplib.SMTP(smtp_server, smtp_port) + if use_ssl and smtp_port == 465: + # Port 465 使用 SSL + print(f"[EMAIL DEBUG] 使用 SSL 連接 SMTP 伺服器 {smtp_server}:{smtp_port}...") + server = smtplib.SMTP_SSL(smtp_server, smtp_port) + else: + # Port 25 或 587 使用一般連接 + print(f"[EMAIL DEBUG] 連接 SMTP 伺服器 {smtp_server}:{smtp_port}...") + server = smtplib.SMTP(smtp_server, smtp_port) + print(f"[EMAIL DEBUG] SMTP 伺服器連接成功") - if use_tls: + if use_tls and smtp_port == 587: print(f"[EMAIL DEBUG] 啟用 TLS...") server.starttls() print(f"[EMAIL DEBUG] TLS 啟用成功") - if sender_password: + # 只在需要認證時才登入 + if auth_required and sender_password: print(f"[EMAIL DEBUG] 登入 SMTP 伺服器...") server.login(sender_email, sender_password) print(f"[EMAIL DEBUG] SMTP 登入成功") else: - print(f"[EMAIL DEBUG] 無需密碼認證") + print(f"[EMAIL DEBUG] 使用匿名發送(Port 25 無需認證)") # 發送郵件 print(f"[EMAIL DEBUG] 發送郵件...") diff --git a/功能升級規劃.txt b/功能升級規劃.txt deleted file mode 100644 index 9b5998b..0000000 --- a/功能升級規劃.txt +++ /dev/null @@ -1,204 +0,0 @@ -功能升級計畫:智慧通知模組 -1. 專案願景 -本次升級旨在將系統的郵件通知功能從一個靜態的範例,全面進化為一個智慧化、高彈性、自動化的通知中樞。完成後,系統將具備以下三大核心能力: - -互動式通知:在所有關鍵操作(啟用、展延、終止)中,提供類似 Outlook 的動態收件人搜尋介面。 - -全流程覆蓋:確保暫規生命週期中的每一個重要節點,都能觸發對應的事件通知。 - -前瞻性提醒:從被動通知轉向主動預警,自動發送即將到期的提醒郵件,防止暫規失效。 - -2. 專案藍圖 (Roadmap) -本計畫將分為三個獨立但環環相扣的模組進行開發,建議依序實施。 - -模組 核心功能 開發重點 狀態 -模組 A 動態收件人介面 建置 LDAP 搜尋 API、前端 UI 元件整合 全新開發 -模組 B 全流程事件通知 將模組 A 的成果應用於「展延」與「終止」流程 功能擴展 -模組 C 自動化排程提醒 引入排程器、建立每日檢查任務、定義提醒規則 全新開發 - -匯出到試算表 -3. 模組 A:動態收件人介面 (互動式通知) -此模組是整個計畫的基石,目標是打造一個可複用的收件人選擇器。 - -A.1. 後端:建置 LDAP 搜尋 API -強化 ldap_utils.py:新增 search_ldap_principals 函式,使用服務帳號安全地查詢 AD 中符合條件的使用者,並回傳其姓名與 Email。 - -建立 API 路由 routes/api.py:建立一個新的 Blueprint,提供 /api/ldap-search 端點,並使用 @login_required 保護,僅供登入者呼叫。 - -註冊 API 路由:在 app.py 中註冊 api_bp,使 API 生效。 - -(詳細程式碼請參考前次對話中的計畫,此處不再贅述) - -A.2. 前端:整合 Tom Select 動態搜尋元件 -修改 templates/base.html:透過 CDN 引入 Tom Select 的 CSS 與 JavaScript 函式庫。 - -修改 templates/activate_spec.html: - -新增一個