93cb5dae25
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
159 lines
6.4 KiB
Dart
159 lines
6.4 KiB
Dart
import 'package:flutter/material.dart';
|
||
|
||
import '../../models/license.dart';
|
||
|
||
/// 授权阶段文案 + 阈值的集中配置。
|
||
///
|
||
/// 所有授权相关提示(顶部横幅、到期弹窗、设置页状态、底部状态栏、过期说明)
|
||
/// 统一在此维护,组件层不再硬编码文案与天数阈值。
|
||
///
|
||
/// 阈值须与后端 `backend/internal/middleware/license_guard.go` 保持一致:
|
||
/// 宽限期 0–[graceDays] 天(仍可写)→ 只读 [graceDays]–[readonlyDays] 天 → 锁定 [readonlyDays] 天+。
|
||
class LicenseCopy {
|
||
LicenseCopy._();
|
||
|
||
/// 宽限期上限(天):过期 ≤ 此值仍可正常写入。
|
||
static const int graceDays = 7;
|
||
|
||
/// 只读期上限(天):过期 ≤ 此值进入只读;超过则锁定登录。
|
||
static const int readonlyDays = 15;
|
||
|
||
/// 顶部横幅文案(仅 grace/readonly/locked 显示;normal 返回空串)。
|
||
static String banner(LicenseInfo lic) {
|
||
final d = lic.daysExpired;
|
||
switch (lic.phase) {
|
||
case 'grace':
|
||
return '授权已过期 $d 天,请及时续费,否则将影响您的正常使用';
|
||
case 'readonly':
|
||
return '授权已过期 $d 天,已进入只读模式,暂时无法新增或修改数据;'
|
||
'过期满 $readonlyDays 天后将彻底锁定,请尽快续费';
|
||
case 'locked':
|
||
return '授权已过期 $d 天并已锁定,所有功能已停用,请立即续费或激活新授权码';
|
||
default:
|
||
return '';
|
||
}
|
||
}
|
||
|
||
/// 设置页「授权状态」行文案。
|
||
static String statusText(LicenseInfo lic) {
|
||
switch (lic.phase) {
|
||
case 'grace':
|
||
return '宽限期 · 已过期 ${lic.daysExpired} 天';
|
||
case 'readonly':
|
||
return '只读模式 · 已过期 ${lic.daysExpired} 天';
|
||
case 'locked':
|
||
return '已锁定 · 已过期 ${lic.daysExpired} 天';
|
||
default:
|
||
return lic.expiresAt == null
|
||
? '正常(永久授权)'
|
||
: '正常(剩余 ${lic.daysRemaining ?? 0} 天)';
|
||
}
|
||
}
|
||
|
||
/// 底部状态栏紧凑文案。[expiryDate] 为已格式化的到期日(yyyy-MM-dd)。
|
||
static String statusBar(LicenseInfo lic, String expiryDate) {
|
||
switch (lic.phase) {
|
||
case 'grace':
|
||
return '授权宽限期 · 已过期 ${lic.daysExpired} 天';
|
||
case 'readonly':
|
||
return '只读模式 · 已过期 ${lic.daysExpired} 天';
|
||
case 'locked':
|
||
return '已锁定 · 已过期 ${lic.daysExpired} 天';
|
||
default:
|
||
return lic.expiresAt == null ? '永久授权' : '授权正常 · 到期 $expiryDate';
|
||
}
|
||
}
|
||
|
||
/// 到期提醒弹窗的(标题, 正文)。
|
||
static (String title, String body) dialog(LicenseInfo lic) {
|
||
final d = lic.daysExpired;
|
||
switch (lic.phase) {
|
||
case 'locked':
|
||
return (
|
||
'授权已锁定',
|
||
'您的授权已过期 $d 天(超过 $readonlyDays 天),所有功能已停用。\n'
|
||
'请前往「设置 → 授权」激活新的授权码,或联系客服续费。',
|
||
);
|
||
case 'readonly':
|
||
return (
|
||
'授权已过期 · 只读模式',
|
||
'您的授权已过期 $d 天,系统进入只读模式,无法执行任何写操作。\n'
|
||
'过期满 $readonlyDays 天后将彻底锁定登录,请尽快续费。',
|
||
);
|
||
default: // grace
|
||
return (
|
||
'授权已过期',
|
||
'您的授权已过期 $d 天,目前仍可正常使用(宽限期 $graceDays 天)。\n'
|
||
'过期超过 $graceDays 天将进入只读模式,请尽快续费以免影响使用。',
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 只读账号尝试写操作被后端拒绝(403 code=READONLY_USER)时的提示。
|
||
static const String readonlyUserToast = '当前为只读账号,仅可查看数据,无法新增或修改';
|
||
|
||
/// 写按钮被授权过期禁用时,点击弹出的提示文案。
|
||
static String writeBlockedToast(LicenseInfo lic) {
|
||
switch (lic.phase) {
|
||
case 'locked':
|
||
return '授权已过期 ${lic.daysExpired} 天并已锁定,无法操作,请前往「设置 → 授权」续费或激活';
|
||
default: // readonly
|
||
return '授权已过期 ${lic.daysExpired} 天,已进入只读模式,续费后可继续操作(设置 → 授权)';
|
||
}
|
||
}
|
||
|
||
// ---- 阶段视觉(颜色 / 图标)集中映射 ----
|
||
// 顶部横幅、底部状态条、设置页状态三处此前各自硬编码 phase→色,readonly 取色还分叉
|
||
// (横幅 0xFFB71C1C vs 状态条 0xFFEF5350)。这里按「角色」给出单一来源:
|
||
// - [bannerColor]:顶部横幅**实底背景**(白字承其上),仅 grace/readonly/locked 显示。
|
||
// - [phaseColor] :前景强调色(底部状态条图标+文字、设置页状态文字共用一套)。
|
||
// - [phaseIcon] :状态图标(状态条用)。
|
||
|
||
/// 顶部横幅实底背景色(深色调,承载白字)。normal 不显示横幅,返回透明。
|
||
static Color bannerColor(String phase) {
|
||
switch (phase) {
|
||
case 'locked':
|
||
return const Color(0xFFD14343);
|
||
case 'readonly':
|
||
return const Color(0xFFB71C1C); // 深红,强调即将彻底锁定
|
||
case 'grace':
|
||
return const Color(0xFFE65100); // 深橙
|
||
default:
|
||
return Colors.transparent;
|
||
}
|
||
}
|
||
|
||
/// 前景强调色:normal=正常绿,grace=警告橙,readonly/locked=危险红。
|
||
static Color phaseColor(String phase) {
|
||
switch (phase) {
|
||
case 'grace':
|
||
return const Color(0xFFE08E00);
|
||
case 'readonly':
|
||
case 'locked':
|
||
return const Color(0xFFD14343);
|
||
default:
|
||
return const Color(0xFF2E8B57);
|
||
}
|
||
}
|
||
|
||
/// 状态图标:normal=已验证,grace=警告,readonly/locked=错误。
|
||
static IconData phaseIcon(String phase) {
|
||
switch (phase) {
|
||
case 'grace':
|
||
return Icons.warning_amber_rounded;
|
||
case 'readonly':
|
||
case 'locked':
|
||
return Icons.error_outline;
|
||
default:
|
||
return Icons.verified_user_outlined;
|
||
}
|
||
}
|
||
|
||
/// 过期降级说明(设置页固定展示),随阈值自动联动。
|
||
static List<String> degradationNotes() => [
|
||
'过期 $graceDays 天内(宽限期):仍可正常使用,请尽快续费',
|
||
'过期 $graceDays–$readonlyDays 天(只读期):仅能查看数据,无法新增或修改',
|
||
'过期满 $readonlyDays 天:系统锁定,无法登录,需续费或激活新授权码后恢复',
|
||
];
|
||
}
|