KyrosDev commited on
Commit
a6a49d1
·
1 Parent(s): e69ed7b

優化授權時間計算邏輯統一使用台灣時區

Browse files

- 後端授權時間計算改用台灣時間00:00作為起始點(-8hr)
- SQL範例資料同步調整時間計算邏輯
- 更新activity_logs視圖新增license_id欄位並優化創建方式
- 統一前後端時間處理確保一致性

app/services/license_service.py CHANGED
@@ -37,11 +37,11 @@ class LicenseService:
37
 
38
  license_code = self.generate_license_code()
39
 
40
- # 計算到期時間:從當天00:00開始計算指定天數
41
  if license_data.expires_days > 0:
42
- # 取得今天的午夜(00:00:00)作為起始時間
43
  today = datetime.now(timezone.utc).date()
44
- start_date = datetime.combine(today, datetime.min.time(), timezone.utc)
45
  # 加上指定天數,到期日為最後一天的23:59:59
46
  expires_at = start_date + timedelta(days=license_data.expires_days) - timedelta(seconds=1)
47
  else:
@@ -422,18 +422,17 @@ class LicenseService:
422
  license_data = result.data[0]
423
  current_expires_at = datetime.fromisoformat(license_data["expires_at"].replace('Z', '+00:00'))
424
 
425
- # 計算新的到期時間:從原到期日開始加天數
426
- # 確保新的到期時間也是以天為界限(23:59:59)
427
  if current_expires_at < datetime.now(timezone.utc):
428
  # 如果已過期,從今天開始計算
429
  today = datetime.now(timezone.utc).date()
430
- start_date = datetime.combine(today, datetime.min.time(), timezone.utc)
431
  new_expires_at = start_date + timedelta(days=extend_days) - timedelta(seconds=1)
432
  else:
433
  # 如果未過期,從原到期日的下一天開始計算
434
  expire_date = current_expires_at.date()
435
  next_day = expire_date + timedelta(days=1)
436
- start_date = datetime.combine(next_day, datetime.min.time(), timezone.utc)
437
  new_expires_at = start_date + timedelta(days=extend_days) - timedelta(seconds=1)
438
 
439
  # 更新授權
 
37
 
38
  license_code = self.generate_license_code()
39
 
40
+ # 計算到期時間:從當天00:00開始計算指定天數(-8hr對應台灣時間)
41
  if license_data.expires_days > 0:
42
+ # 取得今天的午夜(00:00:00)作為起始時間,減8小時
43
  today = datetime.now(timezone.utc).date()
44
+ start_date = datetime.combine(today, datetime.min.time(), timezone.utc) - timedelta(hours=8)
45
  # 加上指定天數,到期日為最後一天的23:59:59
46
  expires_at = start_date + timedelta(days=license_data.expires_days) - timedelta(seconds=1)
47
  else:
 
422
  license_data = result.data[0]
423
  current_expires_at = datetime.fromisoformat(license_data["expires_at"].replace('Z', '+00:00'))
424
 
425
+ # 計算新的到期時間:從原到期日開始加天數(-8hr對應台灣時間)
 
426
  if current_expires_at < datetime.now(timezone.utc):
427
  # 如果已過期,從今天開始計算
428
  today = datetime.now(timezone.utc).date()
429
+ start_date = datetime.combine(today, datetime.min.time(), timezone.utc) - timedelta(hours=8)
430
  new_expires_at = start_date + timedelta(days=extend_days) - timedelta(seconds=1)
431
  else:
432
  # 如果未過期,從原到期日的下一天開始計算
433
  expire_date = current_expires_at.date()
434
  next_day = expire_date + timedelta(days=1)
435
+ start_date = datetime.combine(next_day, datetime.min.time(), timezone.utc) - timedelta(hours=8)
436
  new_expires_at = start_date + timedelta(days=extend_days) - timedelta(seconds=1)
437
 
438
  # 更新授權
supabase-schema.sql CHANGED
@@ -145,9 +145,13 @@ COMMENT ON VIEW license_details IS '授權詳細資訊視圖 (含統計)';
145
  -- =====================================================
146
  -- 視圖 - 活動記錄 (前端儀表板使用)
147
  -- =====================================================
148
- CREATE OR REPLACE VIEW activity_logs AS
149
- SELECT
 
 
 
150
  ul.id,
 
151
  ul.action,
152
  ul.ip_address,
153
  ul.user_agent,
@@ -157,18 +161,18 @@ SELECT
157
  l.license_code,
158
  l.user_name,
159
  l.user_email,
160
- CASE
161
  -- 管理員操作:直接顯示為成功,不判斷 error_message
162
  WHEN ul.action IN ('create', 'extend', 'activate_license', 'deactivate_license', 'delete') THEN ul.action
163
  -- Plugin 操作:有 error_message 就是錯誤
164
  WHEN ul.action IN ('activate', 'validate') THEN
165
- CASE
166
  WHEN ul.error_message IS NOT NULL THEN 'error'
167
  ELSE ul.action
168
  END
169
  -- 其他操作:保持原邏輯
170
- ELSE
171
- CASE
172
  WHEN ul.error_message IS NOT NULL THEN 'error'
173
  ELSE ul.action
174
  END
@@ -256,30 +260,30 @@ COMMENT ON FUNCTION generate_license_report IS '生成指定日期範圍的授
256
  -- 示例資料 (可選)
257
  -- =====================================================
258
 
259
- -- 插入測試用授權 (啟用來測試系統)
260
  INSERT INTO licenses (license_code, user_name, user_email, expires_at, hardware_id, is_active, activated_at) VALUES
261
- -- 已啟用用戶 (正常使用中) - 從今天00:00開始計算
262
- ('A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6', '王小明', 'ming@company.com.tw', DATE_TRUNC('day', NOW()) + INTERVAL '90 days' - INTERVAL '1 second', 'CPU123ABC456DEF789GHI012JKL345MN', true, NOW() - INTERVAL '5 days'),
263
- ('X7Y8Z9W0Q1R2S3T4U5V6A7B8C9D0E1F2', '李美華', 'li.meihua@design.studio', DATE_TRUNC('day', NOW()) + INTERVAL '365 days' - INTERVAL '1 second', 'CPU789XYZ012ABC345DEF678GHI901JK', true, NOW() - INTERVAL '30 days'),
264
 
265
- -- 試用用戶 (7天試用) - 從今天00:00開始計算7天
266
- ('B9C8D7E6F5G4H3I2J1K0L9M8N7O6P5Q4', '張工程師', 'engineer.zhang@tech.com', DATE_TRUNC('day', NOW()) + INTERVAL '7 days' - INTERVAL '1 second', 'CPUABC123XYZ456QWE789RTY012UIU34', true, NOW() - INTERVAL '2 days'),
267
 
268
- -- 更多正常用戶 - 從今天00:00開始計算
269
- ('M5N6O7P8Q9R0S1T2U3V4W5X6Y7Z8A9B0', '陳建築師', 'chen@architect.firm', DATE_TRUNC('day', NOW()) + INTERVAL '30 days' - INTERVAL '1 second', 'CPUARCH456BUILD789DESIGN012PROJ34', true, NOW() - INTERVAL '1 day'),
270
- ('F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8', '劉設計師', 'liu.designer@studio.tw', DATE_TRUNC('day', NOW()) + INTERVAL '60 days' - INTERVAL '1 second', 'CPUDESIGN123CREATIVE456ART789STUD', true, NOW() - INTERVAL '7 days'),
271
 
272
  -- 過期授權 (已過期15天)
273
- ('Z0Y9X8W7V6U5T4S3R2Q1P0O9N8M7L6K5', '周老闆', 'boss.zhou@construction.co', DATE_TRUNC('day', NOW()) - INTERVAL '15 days' - INTERVAL '1 second', 'CPU456DEF789ABC012GHI345JKL678MN', true, NOW() - INTERVAL '45 days'),
274
 
275
  -- 已停用授權 (管理員手動停用)
276
- ('Q2W3E4R5T6Y7U8I9O0P1A2S3D4F5G6H7', '黃規用戶', 'huang@suspended.user', DATE_TRUNC('day', NOW()) + INTERVAL '20 days' - INTERVAL '1 second', 'CPUXYZ789ABC012DEF345GHI678JKL90', false, NOW() - INTERVAL '10 days'),
277
 
278
  -- 永久授權 (企業用戶) - 50年
279
- ('K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6', 'KSTools管理員', 'admin@kstools.com.tw', DATE_TRUNC('day', NOW()) + INTERVAL '18250 days' - INTERVAL '1 second', 'CPUADMIN123MASTER456CONTROL789AB', true, NOW() - INTERVAL '1 day'),
280
 
281
  -- 即將過期 (今天結束就過期)
282
- ('V8W9X0Y1Z2A3B4C5D6E7F8G9H0I1J2K3', '趙用戶', 'zhao@expires.soon', DATE_TRUNC('day', NOW()) + INTERVAL '1 day' - INTERVAL '1 second', 'CPU999END888SOON777EXPIRE666ABC', true, NOW() - INTERVAL '28 days')
283
  ON CONFLICT (license_code) DO NOTHING;
284
 
285
  -- 插入測試使用記錄
 
145
  -- =====================================================
146
  -- 視圖 - 活動記錄 (前端儀表板使用)
147
  -- =====================================================
148
+ -- 重新創建 activity_logs 視圖
149
+ DROP VIEW IF EXISTS activity_logs;
150
+
151
+ CREATE VIEW activity_logs AS
152
+ SELECT
153
  ul.id,
154
+ ul.license_id,
155
  ul.action,
156
  ul.ip_address,
157
  ul.user_agent,
 
161
  l.license_code,
162
  l.user_name,
163
  l.user_email,
164
+ CASE
165
  -- 管理員操作:直接顯示為成功,不判斷 error_message
166
  WHEN ul.action IN ('create', 'extend', 'activate_license', 'deactivate_license', 'delete') THEN ul.action
167
  -- Plugin 操作:有 error_message 就是錯誤
168
  WHEN ul.action IN ('activate', 'validate') THEN
169
+ CASE
170
  WHEN ul.error_message IS NOT NULL THEN 'error'
171
  ELSE ul.action
172
  END
173
  -- 其他操作:保持原邏輯
174
+ ELSE
175
+ CASE
176
  WHEN ul.error_message IS NOT NULL THEN 'error'
177
  ELSE ul.action
178
  END
 
260
  -- 示例資料 (可選)
261
  -- =====================================================
262
 
263
+ -- 插入測試用授權 (啟用來測試系統) - 統一使用台灣時間00:00計算(-8hr)
264
  INSERT INTO licenses (license_code, user_name, user_email, expires_at, hardware_id, is_active, activated_at) VALUES
265
+ -- 已啟用用戶 (正常使用中)
266
+ ('A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6', '王小明', 'ming@company.com.tw', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '90 days' - INTERVAL '1 second', 'CPU123ABC456DEF789GHI012JKL345MN', true, NOW() - INTERVAL '5 days'),
267
+ ('X7Y8Z9W0Q1R2S3T4U5V6A7B8C9D0E1F2', '李美華', 'li.meihua@design.studio', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '365 days' - INTERVAL '1 second', 'CPU789XYZ012ABC345DEF678GHI901JK', true, NOW() - INTERVAL '30 days'),
268
 
269
+ -- 試用用戶 (7天試用)
270
+ ('B9C8D7E6F5G4H3I2J1K0L9M8N7O6P5Q4', '張工程師', 'engineer.zhang@tech.com', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '7 days' - INTERVAL '1 second', 'CPUABC123XYZ456QWE789RTY012UIU34', true, NOW() - INTERVAL '2 days'),
271
 
272
+ -- 更多正常用戶
273
+ ('M5N6O7P8Q9R0S1T2U3V4W5X6Y7Z8A9B0', '陳建築師', 'chen@architect.firm', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '30 days' - INTERVAL '1 second', 'CPUARCH456BUILD789DESIGN012PROJ34', true, NOW() - INTERVAL '1 day'),
274
+ ('F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8', '劉設計師', 'liu.designer@studio.tw', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '60 days' - INTERVAL '1 second', 'CPUDESIGN123CREATIVE456ART789STUD', true, NOW() - INTERVAL '7 days'),
275
 
276
  -- 過期授權 (已過期15天)
277
+ ('Z0Y9X8W7V6U5T4S3R2Q1P0O9N8M7L6K5', '周老闆', 'boss.zhou@construction.co', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' - INTERVAL '15 days' - INTERVAL '1 second', 'CPU456DEF789ABC012GHI345JKL678MN', true, NOW() - INTERVAL '45 days'),
278
 
279
  -- 已停用授權 (管理員手動停用)
280
+ ('Q2W3E4R5T6Y7U8I9O0P1A2S3D4F5G6H7', '黃��規用戶', 'huang@suspended.user', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '20 days' - INTERVAL '1 second', 'CPUXYZ789ABC012DEF345GHI678JKL90', false, NOW() - INTERVAL '10 days'),
281
 
282
  -- 永久授權 (企業用戶) - 50年
283
+ ('K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6', 'KSTools管理員', 'admin@kstools.com.tw', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '18250 days' - INTERVAL '1 second', 'CPUADMIN123MASTER456CONTROL789AB', true, NOW() - INTERVAL '1 day'),
284
 
285
  -- 即將過期 (今天結束就過期)
286
+ ('V8W9X0Y1Z2A3B4C5D6E7F8G9H0I1J2K3', '趙用戶', 'zhao@expires.soon', DATE_TRUNC('day', NOW()) - INTERVAL '8 hours' + INTERVAL '1 day' - INTERVAL '1 second', 'CPU999END888SOON777EXPIRE666ABC', true, NOW() - INTERVAL '28 days')
287
  ON CONFLICT (license_code) DO NOTHING;
288
 
289
  -- 插入測試使用記錄