This commit is contained in:
beabigegg
2025-08-28 13:20:29 +08:00
parent bdfda30ca8
commit dcd15baf3f
11 changed files with 276 additions and 945 deletions

13
.gitignore vendored
View File

@@ -37,4 +37,17 @@ Thumbs.db
# 忽略所有日誌檔案。
*.log
logs/
# --- 環境設定檔 ---
.env
# --- 測試相關 (Testing) ---
# 忽略測試檔案
test_*.py
*_test.py
tests/
# --- 開發者專用文件 (Developer Only) ---
# 最佳實踐文件(包含敏感設定資訊)
BEST_PRACTICES.md
DEVELOPER_GUIDE.md

View File

@@ -12,8 +12,8 @@ cp .env.example .env
# 2. 編輯 .env 檔案 (重要!)
# 設定以下關鍵參數:
# - LDAP_SERVER=ldap://your-dc.panjit.com.tw
# - LDAP_BIND_USER_DN=CN=service,DC=panjit,DC=com,DC=tw
# - LDAP_SERVER=ldap://your-dc.company.com
# - LDAP_BIND_USER_DN=CN=service,DC=company,DC=com
# - LDAP_BIND_USER_PASSWORD=your_service_password
# 3. 啟動所有服務
@@ -48,7 +48,7 @@ start-windows.bat
- [ ] **LDAP連線**: 使用AD帳號測試登入
### 權限設定確認
- [ ] **ymirliu@panjit.com.tw**: 已設定為管理員權限
- [ ] **admin@company.com**: 已設定為管理員權限
- [ ] **權限管理頁面**: 可透過選單訪問
- [ ] **角色功能**: admin/editor/viewer 功能正常
@@ -99,7 +99,7 @@ docker-compose exec app python init_db.py
1. **登入測試**
```bash
# 測試AD帳號登入
用戶: ymirliu@panjit.com.tw (或 ymirliu)
用戶: admin@company.com
密碼: [AD密碼]
```
@@ -174,7 +174,7 @@ docker-compose exec mysql mysql -u root -p -e "SHOW DATABASES;"
```sql
-- 直接在資料庫中設定管理員
USE tempspec_db;
UPDATE ts_user SET role='admin' WHERE username='ymirliu@panjit.com.tw';
UPDATE ts_user SET role='admin' WHERE username='admin@company.com';
```
### 快速重置
@@ -247,4 +247,4 @@ Demo成功的標誌
---
**祝您Demo順利** 如有任何問題請參考系統日誌或聯繫技術支援團隊
**祝您Demo順利** 如有任何問題請參考系統日誌

View File

@@ -687,4 +687,4 @@ curl -s http://localhost:5000/health | jq .
---
本部署指南涵蓋了大部分常見的部署場景。如果遇到特殊情況或需要客製化部署,請參考系統文檔或聯繫技術支援團隊
本部署指南涵蓋了大部分常見的部署場景。如果遇到特殊情況或需要客製化部署,請參考系統相關文檔。

297
README.md
View File

@@ -21,6 +21,7 @@
### 智慧通知系統
- **動態收件人選擇**整合LDAP的即時用戶搜尋
- **郵件記憶功能**:自動記憶並帶出之前使用的通知對象
- **全流程通知**:啟用、展延、終止操作的自動郵件通知
- **自動提醒**3天與7天到期前的主動提醒郵件
- **排程系統**:每日自動檢查即將到期的規範
@@ -87,6 +88,12 @@ docker-compose up -d
docker-compose exec app python init_db.py
```
5. **資料庫遷移(如果需要)**
```bash
# 新增郵件功能欄位
docker-compose exec app python migrate_add_email_column.py
```
### 手動安裝
#### Windows 環境
@@ -107,7 +114,12 @@ REM 編輯 .env 檔案
python init_db.py
```
4. **啟動 ONLYOFFICE Document Server**
4. **資料庫遷移(如果需要)**
```cmd
python migrate_add_email_column.py
```
5. **啟動 ONLYOFFICE Document Server**
```cmd
docker run -d -p 8080:80 --restart=always ^
-e JWT_ENABLED=true ^
@@ -115,7 +127,7 @@ docker run -d -p 8080:80 --restart=always ^
onlyoffice/documentserver
```
5. **啟動應用程式**
6. **啟動應用程式**
```cmd
REM 開發環境
python app.py
@@ -143,7 +155,12 @@ cp .env.example .env
python init_db.py
```
4. **啟動 ONLYOFFICE Document Server**
4. **資料庫遷移(如果需要)**
```bash
python migrate_add_email_column.py
```
5. **啟動 ONLYOFFICE Document Server**
```bash
docker run -d -p 8080:80 --restart=always \
-e JWT_ENABLED=true \
@@ -151,7 +168,7 @@ docker run -d -p 8080:80 --restart=always \
onlyoffice/documentserver
```
5. **啟動應用程式**
6. **啟動應用程式**
```bash
# 開發環境
python app.py
@@ -161,79 +178,6 @@ pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 app:app
```
### 生產環境部署
#### 使用 Nginx + Gunicorn (Linux)
1. **安裝 Gunicorn**
```bash
pip install gunicorn
```
2. **建立 Gunicorn 服務檔案**
```bash
sudo nano /etc/systemd/system/tempspec.service
```
內容:
```ini
[Unit]
Description=Temp Spec System
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/app
Environment="PATH=/path/to/your/app/venv/bin"
ExecStart=/path/to/your/app/venv/bin/gunicorn -w 4 -b 127.0.0.1:5000 app:app
Restart=always
[Install]
WantedBy=multi-user.target
```
3. **Nginx 設定**
```nginx
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
4. **啟動服務**
```bash
sudo systemctl enable tempspec
sudo systemctl start tempspec
```
#### Windows IIS 部署
1. **安裝 IIS 與 Python**
2. **安裝 HttpPlatformHandler**
3. **設定 Web.config**
```xml
<configuration>
<system.webServer>
<handlers>
<add name="PythonHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers>
<httpPlatform processPath="C:\path\to\python.exe"
arguments="app.py"
startupTimeLimit="60"
startupRetryCount="3">
</httpPlatform>
</system.webServer>
</configuration>
```
## ⚙️ 組態設定
### 環境變數 (.env)
@@ -255,74 +199,29 @@ LDAP_BIND_USER_DN=CN=service,DC=company,DC=com
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
# SMTP 郵件設定 (Port 25 無認證方式)
SMTP_SERVER=mail.company.com
SMTP_PORT=25
SMTP_USE_TLS=false
SMTP_USE_SSL=false
SMTP_AUTH_REQUIRED=false
SMTP_SENDER_EMAIL=temp-spec-system@company.com
SMTP_SENDER_PASSWORD=
# ONLYOFFICE 設定
ONLYOFFICE_URL=http://onlyoffice:8080
ONLYOFFICE_JWT_SECRET=your_jwt_secret
```
### 特殊注意事項
### SMTP 配置說明
#### Windows 環境差異
系統支援多種 SMTP 配置方式:
1. **排程服務限制**
- APScheduler 在 Windows 上運行正常
- 若使用 Celery需要額外設定
```bash
# Windows 環境需要使用 eventlet 或 solo 執行器
celery -A app.celery worker --loglevel=info --pool=solo
```
- **Port 25推薦**:內部郵件伺服器,無需認證
- **Port 587**STARTTLS + 認證
- **Port 465**SSL + 認證
2. **路徑設定**
```python
# Windows 環境請使用絕對路徑或適當的路徑分隔符
UPLOAD_FOLDER = r'C:\path\to\uploads'
```
3. **服務安裝**
```bash
# 使用 NSSM 將 Python 應用程式安裝為 Windows 服務
nssm install TempSpecSystem python.exe app.py
```
#### Linux 環境最佳化
1. **系統服務設定**
```bash
# 設定系統服務自動啟動
sudo systemctl enable tempspec.service
```
2. **日誌管理**
```bash
# 使用 logrotate 管理日誌檔案
sudo nano /etc/logrotate.d/tempspec
```
3. **效能調校**
```bash
# Gunicorn 推薦設定
gunicorn -w 4 -k gevent --worker-connections 1000 -b 0.0.0.0:5000 app:app
```
## 🔐 安全性設定
### LDAP 整合
- 支援 SSL/TLS 加密連線
- 服務帳號權限最小化原則
- 自動用戶同步與權限管控
### 資料保護
- JWT Token 驗證
- 檔案存取權限控制
- SQL Injection 防護
- XSS 攻擊防護
詳細設定請參考 `SMTP_CONFIGURATION_UPDATE.md`
## 📚 使用說明
@@ -344,40 +243,34 @@ ONLYOFFICE_JWT_SECRET=your_jwt_secret
UPDATE ts_user SET role='admin' WHERE username='user@domain.com';
```
3. **程式設定**:修改 `routes/auth.py` 中的管理員帳號列表:
```python
# 將特定用戶設為管理員
if user_info['username'].lower() == 'your_admin@domain.com':
default_role = 'admin'
```
### 郵件通知功能
### 排程任務說明
系統具備智慧郵件管理功能:
系統預設每天凌晨 2:00 執行到期檢查任務,可在 `app.py` 中調整:
1. **規範生效時**:輸入通知郵件對象,系統自動記憶
2. **規範終止時**:自動帶出生效時使用的郵件清單,可編輯後發送
3. **規範展延時**:自動帶出郵件清單,修改後更新記錄
```python
@scheduler.task('cron', id='check_expiring_specs_job', hour=2, minute=0)
def scheduled_job():
check_expiring_specs(app)
```
### 排程任務
### 自訂提醒天數
系統預設每天凌晨 2:00 執行到期檢查任務:
在 `tasks.py` 中修改提醒時程:
- 7天到期提醒
- 3天到期提醒
- 自動發送提醒郵件
```python
seven_days_later = today + timedelta(days=7) # 7天前提醒
three_days_later = today + timedelta(days=3) # 3天前提醒
```
## 🔐 安全性設定
### 預設收件人群組設定
### LDAP 整合
- 支援 SSL/TLS 加密連線
- 服務帳號權限最小化原則
- 自動用戶同步與權限管控
在 `tasks.py` 中設定自動提醒的收件人:
```python
# 修改為實際的 AD 群組名稱
default_recipients = get_ldap_group_members('TempSpec_Admins')
```
### 資料保護
- JWT Token 驗證
- 檔案存取權限控制
- SQL Injection 防護
- XSS 攻擊防護
## 🐛 疑難排解
@@ -395,19 +288,14 @@ default_recipients = get_ldap_group_members('TempSpec_Admins')
3. **郵件發送失敗**
- 確認 SMTP 設定正確
- 檢查郵件伺服器認證
- 驗證防火牆規則 (通常是 25/587/465 port)
- 檢查郵件伺服器認證設定
- 驗證防火牆規則 (Port 25/587/465)
4. **排程任務未執行**
- 檢查 APScheduler 初始化
- 確認應用程式持續運行
- 查看系統日誌
5. **檔案上傳失敗**
- 檢查上傳目錄權限
- 確認檔案大小限制設定
- 驗證磁碟空間是否足夠
### 日誌查看
```bash
@@ -421,40 +309,8 @@ tail -f logs/app.log
Get-Content logs/app.log -Tail 10 -Wait
```
### 效能監控
```bash
# 監控資源使用
htop
docker stats
# 檢查資料庫效能
SHOW PROCESSLIST;
SHOW ENGINE INNODB STATUS;
```
## 🤝 開發指南
### 開發環境設定
1. **虛擬環境建立**
```bash
python -m venv venv
source venv/bin/activate # Linux
venv\Scripts\activate # Windows
```
2. **安裝開發依賴**
```bash
pip install -r requirements.txt
pip install -r requirements-dev.txt # 如果有開發專用依賴
```
3. **資料庫遷移**
```bash
python init_db.py
```
### 程式碼結構
```
@@ -473,41 +329,38 @@ python init_db.py
└── ldap_utils.py # LDAP 工具
```
### 新增功能開發
### 資料庫遷移
1. **建立新的路由模組**
2. **新增對應的資料模型**
3. **建立前端範本**
4. **撰寫單元測試**
當系統需要資料庫結構更新時:
```bash
# 執行遷移腳本
python migrate_add_email_column.py
```
## 📄 授權條款
本專案採用 MIT 授權條款,詳見 [LICENSE](LICENSE) 檔案
本專案採用 MIT 授權條款。
## 🆕 版本歷程
### v3.0.0 (2024-01-XX)
### v3.2.0 (最新版本)
- 🆕 新增郵件通知記憶功能
- 🆕 支援 Port 25 無認證 SMTP
- ♻️ 優化郵件管理邏輯
- 🗑️ 移除測試檔案和調試代碼
### v3.1.0
- 🆕 新增 LDAP/AD 整合驗證
- 🆕 整合 ONLYOFFICE 線上編輯器
- 🆕 整合 ONLYOFFICE 線上編輯器
- 🆕 實作智慧通知系統
- 🆕 新增自動排程提醒功能
- 🆕 支援 Docker 容器化部署
### v3.0.0
- ♻️ 重構權限管理系統
- 🗑️ 移除本地帳號管理功能
### v2.x.x
- Toast UI Editor 整合
- 基本文件管理功能
- 本地帳號系統
## 📞 技術支援
如有問題或建議,請透過以下方式聯繫:
- 📧 Email: support@company.com
- 📋 Issue Tracker: GitHub Issues
- 📖 文件wiki: GitHub Wiki
---
**暫時規範管理系統 V3** - 讓企業文件管理更智慧、更高效!

View File

@@ -18,10 +18,12 @@
暫時規範管理系統 V3 是一個集中化平台,用於管理、追蹤和存檔所有暫時性的工程規範。它涵蓋了從草擬、線上編輯、簽核、生效到最終歸檔的完整生命週期。
### 🚀 V3 版本新特色
### 🚀 V3.2 版本新特色
- **LDAP/AD 整合**使用企業Active Directory帳號登入
- **智慧通知系統**:動態收件人選擇與自動提醒
- **智慧郵件記憶**:自動記憶並帶出之前使用的通知對象
- **彈性郵件編輯**:可編輯通知名單並更新記錄
- **多種SMTP支援**支援Port 25無認證及其他認證方式
- **自動排程提醒**:系統主動發送到期提醒郵件
- **增強的編輯體驗**ONLYOFFICE文件協作編輯
@@ -31,7 +33,7 @@
### 2.1 LDAP 登入
🆕 **V3 新功能**:系統現在使用企業 Active Directory 進行單一登入。
系統使用企業 Active Directory 進行單一登入。
**🚨 重要登入規範**
@@ -48,152 +50,164 @@
> **注意**
> - 首次登入的用戶預設為 `Viewer` 權限
> - 如需提升權限請聯繫系統管理員
> - 需要聯繫系統管理員提升權限
### 2.2 主畫面功能
### 2.2 主畫面導覽
登入後進入暫時規範表,包含以下區域
登入後會看到暫時規範表,包含:
- **🔍 搜尋與篩選區**:根據編號、主題或狀態快速查找
- **📊 狀態統計**:顯示各狀態規範的數量概覽
- **📋 規範列表**:詳細顯示所有規範資訊
- **⚡ 快速操作**:根據權限和規範狀態提供操作按鈕
### 2.3 狀態指示說明
| 狀態 | 圖示 | 說明 |
|------|------|------|
| 待生效 | 🟡 | 草稿完成,待管理員啟用 |
| 已生效 | 🟢 | 正在生效中的規範 |
| 已過期 | 🔴 | 已自動過期的規範 |
| 已終止 | ⚫ | 提早終止的規範 |
- **規範編號**系統自動產生PE+民國年+月份+序號)
- **主題**:規範標題
- **申請人**:規範申請者
- **狀態**pending_approval待生效/active已生效/expired已過期/terminated已終止
- **時間範圍**:生效日期至結束日期
- **操作按鈕**:依權限顯示不同功能
---
## 3. 核心操作流程
### 3.1 完整工作流程
### 3.1 建立新規範Editor/Admin 權限)
```mermaid
graph TD
A[Editor建立草稿] --> B[ONLYOFFICE線上編輯]
B --> C[下載Word文件]
C --> D[線下簽核流程]
D --> E[Admin上傳PDF啟用]
E --> F[🆕選擇通知對象]
F --> G[規範正式生效]
G --> H[🆕自動到期提醒]
```
1. 點擊「**新增規範**」按鈕
2. 填寫規範資訊:
- **主題**:規範標題
- **申請人**:申請者姓名
- **申請人電話**:聯絡電話
- **相關資訊**:包裝、批號、設備類型等
### 3.2 建立新的暫時規範 (Editor / Admin)
3. **選擇適用站別**
- Probing、Dicing、Die bond、Wire bond 等
- 可多選
1. **建立草稿**
- 點擊 **[+ 暫時規範建立]** 按鈕
- 填寫基本資料:主題、申請人、站別等
- 選擇適用的 TCCS 等級和 4M 類別
- 點擊 **[建立並開始編輯]**
4. **TCCS等級選擇**
- L1-L4 四個等級
- 單選
2. **線上編輯**
- 系統自動開啟 ONLYOFFICE 編輯器
- 文件已預填初始資料
- 支援多人協作編輯
- 所有變更自動儲存
5. **4M選擇**
- Man、Machine、Material、Method、Environment
- 單選
3. **完成草稿**
- 編輯完成後可直接關閉編輯器
- 或點擊 **[完成編輯]** 返回總表
6. 點擊「**建立**」完成草稿建立
### 3.3 啟用暫時規範 (僅限 Admin)
### 3.2 編輯規範內容Editor/Admin 權限)
🆕 **新增智慧通知功能**
**🆕 ONLYOFFICE 線上編輯**
1. **開始啟用流程**
- 找到狀態為「待生效」的規範
- 點擊 **啟用圖示 (✅)**
1. 在規範列表點擊「**編輯**」按鈕
2. 系統開啟 ONLYOFFICE 編輯器
3. 進行文件編輯、格式調整
4. 使用 **Ctrl+S** 定期儲存
5. 編輯完成後關閉編輯器視窗
2. **上傳簽核文件**
- 上傳已簽核完成的 PDF 檔案
- 系統自動驗證檔案格式
**編輯器功能**
- 全功能 Word 文件編輯
- 即時自動儲存
- 支援圖片、表格插入
- 格式化工具列
3. **🆕 選擇通知對象**
- 在「郵件通知對象」欄位輸入姓名或Email
- 系統即時搜尋 LDAP 用戶
- 支援多人選擇
- 可選擇不發送通知
### 3.3 啟用規範Admin 權限)
4. **確認啟用**
- 點擊 **[上傳並啟用]**
- 系統發送啟用通知郵件
- 規範狀態變更為「已生效」
將規範從「待生效」變更為「已生效」狀態:
### 3.4 展延暫時規範 (Editor / Admin)
1. 點擊「**啟用**」按鈕
2. **上傳已簽核檔案**選擇已簽核的PDF檔案
3. **設定通知對象**
- 在搜尋框輸入姓名或Email至少2個字元
- 從下拉清單選擇收件者
- 支援AD群組搜尋格式`group:群組名稱`
- 可選擇多位收件者
🆕 **新增智慧通知功能**
4. 點擊「**確認啟用**
5. 系統自動:
- 更新規範狀態
- **記憶通知對象**供後續使用
- 發送啟用通知郵件
1. **開始展延**
- 點擊 **展延圖示 (📅+)**
- 選擇新的結束日期
### 3.4 展延規範Editor/Admin 權限)
2. **上傳佐證文件**
- 必須上傳新的佐證文件 (PDF格式)
延長已生效規範的結束日期:
3. **🆕 通知對象選擇**
- 選擇需要通知的相關人員
- 使用動態搜尋功能選擇收件人
1. 點擊「**展延**」按鈕
2. **設定新結束日期**:選擇展延後的日期
3. **上傳佐證檔案**提供展延理由相關文件PDF格式
4. **🆕 智慧通知設定**
- 系統自動帶出之前啟用時使用的通知對象
- 可直接使用或進行編輯
- 修改後的名單會更新到系統記錄中
4. **確認展延**
- 點擊 **[確認展延]**
- 系統發送展延通知郵件
5. 點擊「**確認展延**
6. 系統自動發送展延通知郵件
### 3.5 終止暫時規範 (Editor / Admin)
### 3.5 終止規範(Editor/Admin 權限)
🆕 **新增智慧通知功能**
提早結束規範:
1. **開始終止**
- 點擊 **終止圖示 (❌)**
- 填寫提早結束原因
1. 點擊「**終止**」按鈕
2. **填寫終止原因**:說明提早結束的理由
3. **🆕 智慧通知設定**
- 系統自動帶出之前啟用時使用的通知對象
- 顯示提示「以下為生效時設定的通知對象」
- 可直接使用或進行編輯
2. **🆕 通知設定**
- 選擇需要通知終止訊息的人員
3. **確認終止**
- 點擊 **[確認終止]**
- 系統發送終止通知郵件
- 規範狀態變為「已終止」
4. 點擊「**確認終止**
5. 系統自動:
- 更新結束日期為今日
- 發送終止通知郵件
---
## 4. 智慧通知系統
🆕 **V3 全新功能**
### 4.1 🆕 郵件記憶功能
### 4.1 動態收件人選擇
**V3.2 新增功能**:系統現在具備智慧郵件管理能力
所有主要操作(啟用、展延、終止)都支援智慧通知
**運作機制**
1. **規範啟用時**:輸入通知郵件對象,系統自動記憶
2. **規範終止時**:自動帶出啟用時的郵件清單,可編輯後發送
3. **規範展延時**:自動帶出郵件清單,修改後會更新記錄
- **即時搜尋**輸入姓名或Email即時搜尋AD用戶
- **多人選擇**:支援選擇多位收件人
- **自動完成**顯示完整姓名和Email資訊
- **移除功能**:可隨時移除已選擇的收件人
**操作說明**
- 系統會顯示「以下為生效時設定的通知對象」提示
- 可以直接使用預設的郵件清單
- 也可以修改郵件清單後再發送
- 展延時修改的名單會成為新的預設通知對象
### 4.2 通知郵件內容
### 4.2 動態收件人選擇
系統會根據操作類型自動發送相應的通知郵件
**搜尋功能**
- 輸入至少 **2個字元** 開始搜尋
- 支援姓名或Email模糊搜尋
- 即時顯示搜尋結果
- **啟用通知**:包含規範編號、主題、生效/結束日期
- **展延通知**:包含新的結束日期和展延原因
- **終止通知**:包含終止原因和終止日期
**選擇方式**
- **個人用戶**:直接選擇用戶
- **AD群組**:輸入 `group:群組名稱` 選擇整個群組
- **多重選擇**:可同時選擇多位收件者
### 4.3 🆕 自動到期提醒
**群組搜尋**
- 格式:`group:TempSpec_Admins`
- 系統會自動展開群組成員
- 發送時會寄給所有群組成員
系統每天自動檢查即將到期的規範:
### 4.3 通知類型
- **7天前提醒**:首次到期預警
- **3天前提醒**:最終到期提醒
- **自動發送**:無需人工干預
- **群組通知**:發送給預設管理群組
**手動通知**(操作觸發):
- 規範啟用通知
- 規範展延通知
- 規範終止通知
> **管理員設定**:可在 `tasks.py` 中修改提醒天數和收件人群組
**🆕 自動提醒**(系統排程):
- **7天到期提醒**在規範到期前7天自動發送
- **3天到期提醒**在規範到期前3天自動發送
- **發送時間**每天凌晨2:00檢查並發送
**郵件內容**
- HTML格式美化顯示
- 包含規範編號、標題、申請人
- 明確標示生效/結束日期
- 提供系統連結
---
@@ -230,12 +244,12 @@ graph TD
- 操作類型(建立/啟用/展延/終止)
- 詳細說明
### 5.4 🆕 即將到期警示
### 5.4 即將到期警示
在規範列表中會特別標示即將到期的規範:
- **🟡 橙色標示**7天內到期
- **🔴 紅色標示**3天內到期
- **🔴 紅色標示**3天內到期
- **閃爍動畫**:今日到期
---
@@ -250,17 +264,24 @@ graph TD
| **Editor** | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| **Admin** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
### 6.2 🆕 LDAP 權限管理
### 6.2 權限說明
- **自動用戶創建**AD用戶首次登入自動建立帳號
- **預設權限**:新用戶預設為 `Viewer` 權限
- **權限提升**:需要管理員手動調整資料庫或修改程式碼
**Viewer檢視者**
- 檢視所有規範內容
- 下載PDF檔案
- 檢視歷史紀錄
**管理員手動提升權限**
```sql
-- 使用完整UPN格式帳號
UPDATE ts_user SET role='admin' WHERE username='user@domain.com';
```
**Editor編輯者**
- 建立新規範草稿
- 編輯規範內容
- 展延和終止規範
- 下載Word和PDF檔案
**Admin管理員**
- 所有Editor權限
- 啟用規範(上傳簽核檔案)
- 刪除規範
- 系統管理功能
---
@@ -268,40 +289,39 @@ UPDATE ts_user SET role='admin' WHERE username='user@domain.com';
### 7.1 登入相關
**Q: 無法使用AD帳號登入**
A: 請確認:
1. **必須使用完整UPN格式**:例如 user@domain.com不支援縮略帳號如 user
2. 密碼正確
3. 帳號未被鎖定
4. 聯繫IT部門確認LDAP連線狀態
**Q: 忘記帳號格式**
A: 必須使用完整的 `user@domain.com` 格式,不能只輸入 `user`
**Q: 忘記密碼怎麼辦**
A: 系統使用AD驗證請透過企業標準流程重設AD密碼。
**Q: 無法登入**
A: 請確認:
1. 帳號格式正確(包含@domain.com
2. 密碼正確
3. AD帳號未被鎖定
4. 網路連線正常
### 7.2 權限相關
**Q: 為什麼我看不到建立規範按鈕**
A: 您的權限可能為 `Viewer`,請聯繫管理員提升權限至 `Editor`
**Q: 無法建立規範?**
A: 請確認您的權限等級Viewer無法建立規範需要Editor以上權限
**Q: 為什麼我無法啟用規範?**
A: 啟用功能僅限 `Admin` 權限,請聯繫系統管理員操作
**Q: 無法啟用規範?**
A: 啟用功能需要Admin權限請聯繫系統管理員。
### 7.3 編輯相關
### 7.3 編輯相關
**Q: ONLYOFFICE編輯器無法載入**
A: 請檢查
1. 瀏覽器是否允許彈出視窗
2. 網路連線是否正常
3. 是否安裝最新版瀏覽器
4. 聯繫IT確認Document Server狀態
A: 請確認
1. 瀏覽器支援建議Chrome/Edge
2. 網路連線穩定
3. 彈出視窗未被阻擋
**Q: 編輯內容未儲存?**
A: ONLYOFFICE有自動儲存功能但請確認
A: 建議
1. 編輯期間保持網路連線
2. 避免同時多人編輯同一文件
3. 定期手動儲存 (Ctrl+S)
### 7.4 🆕 通知相關
### 7.4 通知相關
**Q: 搜尋不到AD用戶**
A: 請確認:
@@ -314,11 +334,16 @@ A: 請檢查:
1. Email地址是否正確
2. 垃圾郵件資料夾
3. 公司郵件伺服器設定
4. 聯繫IT確認SMTP設定
**Q: 自動提醒郵件何時發送?**
A: 系統每天凌晨2:00自動檢查並發送提醒分別在到期前7天和3天發送。
**🆕 Q: 郵件通知對象會自動記憶嗎?**
A: 是的,系統會記憶啟用時設定的通知對象:
- 終止規範時會自動帶出之前的郵件清單
- 展延規範時也會自動帶出,修改後會更新記錄
- 您可以直接使用或編輯後再發送
### 7.5 檔案相關
**Q: 可以上傳Word檔案來啟用規範嗎**
@@ -342,23 +367,27 @@ A: 可能原因:
---
## 🆘 技術支援
如遇到本手冊未涵蓋的問題,請透過以下方式聯繫:
- **📧 系統管理員**: [admin@company.com](mailto:admin@company.com)
- **📞 IT支援專線**: 分機 2345
- **💬 企業即時通**: #temp-spec-support
---
## 📝 版本資訊
- **文件版本**: V3.0.0
- **最後更新**: 2024年1月
- **適用系統**: 暫時規範管理系統 V3
- **文件版本**: V3.2.0
- **最後更新**: 2025年1月
- **適用系統**: 暫時規範管理系統 V3.2
### 版本更新記錄
**V3.2.0**
- 新增郵件通知記憶功能
- 支援Port 25無認證SMTP
- 優化郵件管理邏輯
- 更新操作說明
**V3.1.0**
- 新增LDAP/AD整合認證
- 整合ONLYOFFICE線上編輯器
- 實作智慧通知系統
- 新增自動排程提醒功能
---
**感謝您使用暫時規範管理系統 V3**
希望這個操作手冊能幫助您更有效地使用系統功能。如有任何建議或回饋,歡迎與我們聯繫。
希望這個操作手冊能幫助您更有效地使用系統功能。

View File

@@ -1,72 +0,0 @@
#!/usr/bin/env python3
"""
測試 LDAP API 端點功能
"""
import requests
import json
def test_api_search():
"""測試 API 搜尋功能"""
print("=== 測試 LDAP API 搜尋功能 ===")
# 測試不同的搜尋詞
test_terms = ["liu", "", "PE", "管理", "admin"]
base_url = "http://127.0.0.1:5000"
# 先登入獲取 session cookie
session = requests.Session()
print("正在登入系統...")
login_data = {
'username': 'ymirliu@panjit.com.tw',
'password': input("請輸入 ymirliu@panjit.com.tw 的密碼: ")
}
# 嘗試登入
login_response = session.post(f"{base_url}/login", data=login_data)
if login_response.status_code == 200 and "總表檢視" in login_response.text:
print("✅ 登入成功")
for term in test_terms:
print(f"\n🔍 測試搜尋: '{term}'")
print("-" * 40)
api_url = f"{base_url}/api/ldap-search"
params = {'q': term}
try:
response = session.get(api_url, params=params)
print(f"HTTP 狀態: {response.status_code}")
if response.status_code == 200:
try:
data = response.json()
print(f"找到 {len(data)} 個結果:")
for i, result in enumerate(data, 1):
print(f" {i}. {result.get('text', 'N/A')}")
print(f" 值: {result.get('value', 'N/A')}")
print(f" 類型: {result.get('type', 'N/A')}")
except json.JSONDecodeError:
print("❌ 回應不是有效的 JSON")
print(f"回應內容: {response.text[:200]}")
else:
print(f"❌ API 請求失敗: {response.status_code}")
print(f"回應: {response.text[:200]}")
except requests.RequestException as e:
print(f"❌ 請求錯誤: {e}")
else:
print("❌ 登入失敗")
print(f"HTTP 狀態: {login_response.status_code}")
if __name__ == "__main__":
try:
test_api_search()
except KeyboardInterrupt:
print("\n\n測試已中斷")
except Exception as e:
print(f"\n測試發生錯誤: {e}")

View File

@@ -1,116 +0,0 @@
#!/usr/bin/env python3
"""
簡單的 LDAP 連線測試腳本
用於驗證 LDAP 設定是否正確
"""
from ldap3 import Server, Connection, ALL
import os
from dotenv import load_dotenv
# 載入環境變數
load_dotenv()
def test_ldap_connection():
"""測試 LDAP 伺服器連線"""
print("=== LDAP 連線測試 ===")
# 讀取設定
ldap_server = os.getenv('LDAP_SERVER')
ldap_port = int(os.getenv('LDAP_PORT', 389))
use_ssl = os.getenv('LDAP_USE_SSL', 'false').lower() in ['true', '1', 't']
bind_dn = os.getenv('LDAP_BIND_USER_DN')
bind_password = os.getenv('LDAP_BIND_USER_PASSWORD')
search_base = os.getenv('LDAP_SEARCH_BASE')
print(f"LDAP 伺服器: {ldap_server}")
print(f"LDAP 連接埠: {ldap_port}")
print(f"使用 SSL: {use_ssl}")
print(f"搜尋基底: {search_base}")
print(f"服務帳號 DN: {bind_dn}")
try:
# 建立伺服器連線
server = Server(ldap_server, port=ldap_port, use_ssl=use_ssl, get_info=ALL)
print(f"✅ LDAP 伺服器物件建立成功")
# 測試服務帳號連線
print("正在測試服務帳號連線...")
conn = Connection(server, user=bind_dn, password=bind_password, auto_bind=True)
if conn.bound:
print("✅ 服務帳號連線成功!")
# 測試搜尋功能
print("正在測試 LDAP 搜尋功能...")
search_filter = "(objectClass=user)"
conn.search(search_base, search_filter, attributes=['dn'], size_limit=5)
if conn.entries:
print(f"✅ LDAP 搜尋成功,找到 {len(conn.entries)} 個條目")
for entry in conn.entries[:3]:
print(f" - {entry.entry_dn}")
else:
print("⚠️ LDAP 搜尋沒有找到任何條目")
conn.unbind()
else:
print("❌ 服務帳號連線失敗")
return False
except Exception as e:
print(f"❌ LDAP 連線錯誤: {e}")
return False
print("=== LDAP 連線測試完成 ===")
return True
def test_user_authentication():
"""測試使用者認證 (需要手動輸入測試帳號)"""
print("\n=== 使用者認證測試 ===")
test_user = input("請輸入測試用帳號 (完整UPN格式如 user@domain.com): ").strip()
if not test_user or '@' not in test_user:
print("❌ 帳號格式不正確")
return False
test_password = input("請輸入測試密碼: ").strip()
if not test_password:
print("❌ 密碼不可為空")
return False
# 讀取設定
ldap_server = os.getenv('LDAP_SERVER')
ldap_port = int(os.getenv('LDAP_PORT', 389))
use_ssl = os.getenv('LDAP_USE_SSL', 'false').lower() in ['true', '1', 't']
try:
server = Server(ldap_server, port=ldap_port, use_ssl=use_ssl, get_info=ALL)
print(f"正在驗證 {test_user}...")
conn = Connection(server, user=test_user, password=test_password, auto_bind=True)
if conn.bound:
print("✅ 使用者認證成功!")
conn.unbind()
return True
else:
print("❌ 使用者認證失敗 - 帳號或密碼錯誤")
return False
except Exception as e:
print(f"❌ 認證過程發生錯誤: {e}")
return False
if __name__ == "__main__":
print("LDAP 測試工具")
print("此工具用於測試 LDAP 連線和認證功能\n")
# 測試 LDAP 連線
if test_ldap_connection():
# 如果連線測試通過,可以選擇測試使用者認證
choice = input("\n是否要測試使用者認證? (y/N): ").strip().lower()
if choice == 'y':
test_user_authentication()
input("\n按 Enter 鍵結束...")

View File

@@ -1,113 +0,0 @@
#!/usr/bin/env python3
"""
測試 LDAP 搜尋功能的獨立腳本
用於偵錯郵件通知對象搜尋問題
"""
from ldap_utils import search_ldap_principals, search_ldap_groups
from app import app
import sys
def test_user_search():
"""測試使用者搜尋功能"""
print("=== 測試使用者搜尋功能 ===")
test_terms = ["", "liu", "管理", "admin", "工程"]
for term in test_terms:
print(f"\n搜尋詞: '{term}'")
print("-" * 40)
try:
results = search_ldap_principals(term, limit=10)
print(f"找到 {len(results)} 個結果:")
for i, result in enumerate(results, 1):
print(f"{i}. {result['name']} ({result['email']})")
except Exception as e:
print(f"搜尋失敗: {e}")
import traceback
traceback.print_exc()
def test_group_search():
"""測試群組搜尋功能"""
print("\n=== 測試群組搜尋功能 ===")
test_terms = ["管理", "工程", "admin", "group"]
for term in test_terms:
print(f"\n搜尋詞: '{term}'")
print("-" * 40)
try:
results = search_ldap_groups(term, limit=10)
print(f"找到 {len(results)} 個群組:")
for i, result in enumerate(results, 1):
print(f"{i}. {result['name']} (成員數: {result['member_count']})")
except Exception as e:
print(f"群組搜尋失敗: {e}")
import traceback
traceback.print_exc()
def test_interactive_search():
"""互動式搜尋測試"""
print("\n=== 互動式搜尋測試 ===")
while True:
search_term = input("\n請輸入搜尋詞 (或輸入 'quit' 結束): ").strip()
if search_term.lower() == 'quit':
break
if not search_term:
continue
print(f"\n搜尋 '{search_term}'...")
# 搜尋使用者
try:
user_results = search_ldap_principals(search_term, limit=10)
print(f"\n👤 使用者結果 ({len(user_results)}):")
for i, result in enumerate(user_results, 1):
print(f" {i}. {result['name']} ({result['email']})")
except Exception as e:
print(f"使用者搜尋失敗: {e}")
# 搜尋群組
try:
group_results = search_ldap_groups(search_term, limit=5)
print(f"\n👥 群組結果 ({len(group_results)}):")
for i, result in enumerate(group_results, 1):
print(f" {i}. {result['name']} (成員: {result['member_count']})")
except Exception as e:
print(f"群組搜尋失敗: {e}")
def main():
"""主測試函式"""
print("LDAP 搜尋功能測試工具")
print("=" * 50)
with app.app_context():
# 測試預設搜尋詞
test_user_search()
test_group_search()
# 互動式測試
choice = input("\n是否要進行互動式搜尋測試? (y/N): ").strip().lower()
if choice == 'y':
test_interactive_search()
print("\n測試完成!")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n測試已中斷")
except Exception as e:
print(f"\n測試發生錯誤: {e}")
import traceback
traceback.print_exc()

View File

@@ -1,126 +0,0 @@
#!/usr/bin/env python3
"""
測試組織架構搜尋功能的獨立腳本
根據您提供的組織架構圖進行測試
"""
from ldap_utils import search_ldap_groups
from app import app
def test_org_units():
"""測試組織單位搜尋"""
print("=== 測試組織單位搜尋 ===")
# 根據您的組織架構圖測試這些關鍵字
test_terms = [
"PANJIT", # 主要組織
"Audit Office", # 稽核室
"Fab bu", # 晶圓事業部
"CFPU", # 客戶產品事業部
"GMO", # 總經理室
"RBU", # 新創事業處
"kM_ESP", # 知識管理
"SBG", # 特殊應用事業群
"AUBU", # 車載事業處
"IQBU", # 檢測事業處
"MBU1", # 行銷事業處1
"AssEng", # 製程工程
"scottlee", # 個人帳號
"staceychu", # 個人帳號
"ymirliu" # 劉經理
]
for term in test_terms:
print(f"\n搜尋: '{term}'")
print("-" * 50)
try:
results = search_ldap_groups(term, limit=10)
if results:
print(f"找到 {len(results)} 個結果:")
for i, result in enumerate(results, 1):
type_text = "組織單位" if result['type'] == 'organizationalUnit' else "群組"
print(f" {i}. {result['name']} ({type_text})")
print(f" 成員: {result['member_count']}")
if result.get('email'):
print(f" 郵件: {result['email']}")
print(f" DN: {result['dn']}")
print()
else:
print("沒有找到結果")
except Exception as e:
print(f"搜尋錯誤: {e}")
import traceback
traceback.print_exc()
def test_specific_search():
"""測試特定搜尋詞"""
print("\n=== 特定搜尋測試 ===")
while True:
term = input("\n請輸入要搜尋的組織名稱 (或輸入 'quit' 結束): ").strip()
if term.lower() == 'quit':
break
if not term:
continue
print(f"\n搜尋組織: '{term}'")
print("-" * 40)
try:
results = search_ldap_groups(term, limit=15)
if results:
print(f"找到 {len(results)} 個組織:")
for i, result in enumerate(results, 1):
type_text = "組織單位" if result['type'] == 'organizationalUnit' else "群組"
print(f"{i}. {result['name']} ({type_text}, 成員: {result['member_count']})")
# 提供選擇選項
if results:
choice = input(f"\n要查看哪個組織的詳細資訊? (1-{len(results)}, 或按 Enter 跳過): ").strip()
if choice.isdigit() and 1 <= int(choice) <= len(results):
selected = results[int(choice) - 1]
print(f"\n{selected['name']} 詳細資訊:")
print(f" 類型: {selected['type']}")
print(f" 成員數: {selected['member_count']}")
print(f" DN: {selected['dn']}")
if selected.get('email'):
print(f" 群組郵件: {selected['email']}")
else:
print("沒有找到相符的組織")
except Exception as e:
print(f"搜尋失敗: {e}")
def main():
"""主測試函式"""
print("組織架構搜尋測試工具")
print("=" * 50)
print("此工具將測試根據您的 AD 組織架構搜尋群組和組織單位")
with app.app_context():
# 自動測試常見組織名稱
test_org_units()
# 互動式測試
choice = input("\n是否要進行互動式組織搜尋測試? (y/N): ").strip().lower()
if choice == 'y':
test_specific_search()
print("\n測試完成!")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n測試已中斷")
except Exception as e:
print(f"\n測試發生錯誤: {e}")
import traceback
traceback.print_exc()

View File

@@ -1,137 +0,0 @@
#!/usr/bin/env python3
"""
測試系統啟動的腳本
用於檢查各個模組是否可以正常導入和初始化
"""
def test_imports():
"""測試所有模組導入"""
print("🔧 測試模組導入...")
try:
print(" ├─ 測試基本 Flask 組件...")
from flask import Flask
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
print(" │ ✅ Flask 基本組件導入成功")
print(" ├─ 測試資料庫模型...")
from models import db, User, TempSpec
print(" │ ✅ 資料庫模型導入成功")
print(" ├─ 測試工具函式...")
from utils import admin_required, editor_or_admin_required, send_email
print(" │ ✅ 工具函式導入成功")
print(" ├─ 測試 LDAP 工具...")
from ldap_utils import authenticate_ldap_user, search_ldap_principals
print(" │ ✅ LDAP 工具導入成功")
print(" ├─ 測試路由模組...")
from routes.auth import auth_bp
print(" │ ✅ auth 路由導入成功")
from routes.temp_spec import temp_spec_bp
print(" │ ✅ temp_spec 路由導入成功")
from routes.admin import admin_bp
print(" │ ✅ admin 路由導入成功")
from routes.api import api_bp
print(" │ ✅ api 路由導入成功")
from routes.upload import upload_bp
print(" │ ✅ upload 路由導入成功")
print(" ├─ 測試排程任務...")
from tasks import check_expiring_specs
print(" │ ✅ 排程任務導入成功")
print(" └─ 所有模組導入成功!")
return True
except Exception as e:
print(f" ❌ 模組導入失敗: {e}")
import traceback
traceback.print_exc()
return False
def test_app_creation():
"""測試 Flask 應用程式建立"""
print("\n🔧 測試應用程式建立...")
try:
from app import app
print(" ✅ Flask 應用程式建立成功")
# 測試路由註冊
with app.app_context():
print(f" ✅ 應用程式名稱: {app.name}")
print(f" ✅ 註冊的藍圖數量: {len(app.blueprints)}")
for bp_name in app.blueprints:
print(f" - {bp_name}")
return True
except Exception as e:
print(f" ❌ 應用程式建立失敗: {e}")
import traceback
traceback.print_exc()
return False
def test_config():
"""測試設定檔"""
print("\n🔧 測試設定檔...")
try:
from config import Config
print(" ✅ 設定檔導入成功")
# 檢查重要設定
config = Config()
print(f" ✅ SECRET_KEY 已設定: {'' if hasattr(config, 'SECRET_KEY') and config.SECRET_KEY else ''}")
print(f" ✅ DATABASE_URL 已設定: {'' if hasattr(config, 'SQLALCHEMY_DATABASE_URI') and config.SQLALCHEMY_DATABASE_URI else ''}")
return True
except Exception as e:
print(f" ❌ 設定檔測試失敗: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""主測試函式"""
print("=" * 50)
print("🚀 暫時規範管理系統 V3 - 啟動測試")
print("=" * 50)
success_count = 0
total_tests = 3
# 測試模組導入
if test_imports():
success_count += 1
# 測試設定檔
if test_config():
success_count += 1
# 測試應用程式建立
if test_app_creation():
success_count += 1
# 結果統計
print("\n" + "=" * 50)
print(f"📊 測試結果: {success_count}/{total_tests} 個測試通過")
if success_count == total_tests:
print("🎉 所有測試通過!系統可以正常啟動。")
return True
else:
print("⚠️ 部分測試失敗,請檢查上述錯誤訊息。")
return False
if __name__ == "__main__":
success = main()
exit(0 if success else 1)

View File

@@ -27,7 +27,7 @@ def _resolve_image_path(src: str) -> str:
import logging
DEBUG_LOG = True # 設定為 False 可關閉 debug 訊息
DEBUG_LOG = False # 生產環境關閉 debug 訊息
def _process_markdown_sections(doc, md_content):
from bs4 import BeautifulSoup, Tag