diff --git a/client/lib/screens/about/about_screen.dart b/client/lib/screens/about/about_screen.dart index a9aa60b..8058460 100644 --- a/client/lib/screens/about/about_screen.dart +++ b/client/lib/screens/about/about_screen.dart @@ -60,9 +60,21 @@ class _AboutScreenState extends ConsumerState { // 页脚 Padding( padding: const EdgeInsets.only(top: 4, bottom: 12), - child: Text('© 2026 岩美科技 · 保留所有权利 · 京ICP备2026039814号', - textAlign: TextAlign.center, - style: TextStyle(fontSize: AppDims.fsXs, color: t.faint)), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('© 2026 岩美科技 · 保留所有权利 · ', + style: TextStyle( + fontSize: AppDims.fsXs, color: t.faint)), + InkWell( + onTap: () => + launchUrl(Uri.parse('https://beian.miit.gov.cn')), + child: Text('京ICP备2026039814号', + style: TextStyle( + fontSize: AppDims.fsXs, color: t.faint)), + ), + ], + ), ), ], ), diff --git a/client/lib/screens/settings/purchase_card.dart b/client/lib/screens/settings/purchase_card.dart index 00fc357..368f2d0 100644 --- a/client/lib/screens/settings/purchase_card.dart +++ b/client/lib/screens/settings/purchase_card.dart @@ -32,7 +32,7 @@ class PurchaseCard extends ConsumerStatefulWidget { class _PurchaseCardState extends ConsumerState { _Phase _phase = _Phase.pick; - int _tabIdx = 0; // 0=标准版 1=首月特惠 2=高级版 + int _tabIdx = 0; // 0=首月特惠 1=标准版 2=高级版 int _cycleIdx = 0; // 0=年付 1=月付 bool _submitting = false; bool _checking = false; @@ -42,9 +42,9 @@ class _PurchaseCardState extends ConsumerState { DateTime? _newExpiresAt; Timer? _pollTimer; - bool get _isPromo => _tabIdx == 1; + bool get _isPromo => _tabIdx == 0; LicensePlanGroup get _group => - _tabIdx == 0 ? LicensePlans.standard : LicensePlans.pro; + _tabIdx == 1 ? LicensePlans.standard : LicensePlans.pro; LicensePlan get _plan => _isPromo ? LicensePlans.promo : (_cycleIdx == 0 ? _group.annual : _group.monthly); @@ -54,7 +54,16 @@ class _PurchaseCardState extends ConsumerState { void initState() { super.initState(); ref.read(licenseRepositoryProvider).promoUsed().then((used) { - if (mounted && used) setState(() => _promoUsed = true); + // 已享受过特惠:置灰并把默认选中切到「高级版 · 年付」 + if (mounted && used) { + setState(() { + _promoUsed = true; + if (_phase == _Phase.pick && _isPromo) { + _tabIdx = 2; + _cycleIdx = 0; + } + }); + } }); } @@ -149,8 +158,8 @@ class _PurchaseCardState extends ConsumerState { Wrap(spacing: 10, runSpacing: 8, children: [ DsSeg( items: [ - '标准版', _promoUsed ? '首月特惠(已享受)' : '🔥 首月特惠 ¥1', + '标准版', '高级版', ], index: _tabIdx, diff --git a/client/lib/screens/settings/settings_screen.dart b/client/lib/screens/settings/settings_screen.dart index c863beb..243e8fd 100644 --- a/client/lib/screens/settings/settings_screen.dart +++ b/client/lib/screens/settings/settings_screen.dart @@ -699,127 +699,114 @@ class _LicensePanelState extends ConsumerState<_LicensePanel> { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + // ── 卡1:授权到期时间(原型 .lic 统计条:bg 底 / border / r-md)── _SettingsCard( - title: '授权管理', - desc: '使用兑换券续期,时长在现有到期时间上叠加', - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 原型 .lic 统计条:bg 底 / border / r-md / pad 18 20 + title: '授权到期时间', + desc: '当前门店的授权有效期,续期时长在现有到期时间上叠加', + child: Container( + padding: const EdgeInsets.fromLTRB(20, 18, 20, 18), + decoration: BoxDecoration( + color: t.bg, + border: Border.all(color: t.border), + borderRadius: BorderRadius.circular(AppDims.rMd), + ), + child: Row(children: [ + _stat(t, '授权到期日', expires), + const SizedBox(width: 24), + _stat(t, '剩余天数', days != null ? '剩余 $days 天' : '—', warn: true), + const Spacer(), Container( - padding: const EdgeInsets.fromLTRB(20, 18, 20, 18), + width: 46, + height: 46, decoration: BoxDecoration( - color: t.bg, - border: Border.all(color: t.border), + color: t.okSoft, borderRadius: BorderRadius.circular(AppDims.rMd), ), - child: Row(children: [ - _stat(t, '授权到期日', expires), - const SizedBox(width: 24), - _stat(t, '剩余天数', days != null ? '剩余 $days 天' : '—', - warn: true), - const Spacer(), - Container( - width: 46, - height: 46, - decoration: BoxDecoration( - color: t.okSoft, - borderRadius: BorderRadius.circular(AppDims.rMd), - ), - child: Icon(LucideIcons.shieldCheck, - size: 22, color: t.success), - ), - ]), + child: + Icon(LucideIcons.shieldCheck, size: 22, color: t.success), ), - const SizedBox(height: 16), - // 兑换(原型 .redeem:input + 按钮,max 520) - ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 520), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('兑换券短码', - style: TextStyle( - fontSize: AppDims.fsSm, color: t.muted)), - const SizedBox(height: 6), - DsInput( - controller: _voucherCtrl, - hintText: '输入兑换券短码', - ), - ], - ), - ), - const SizedBox(width: 10), - WriteGuard( - child: DsButton(_redeeming ? '兑换中…' : '兑换续期', - variant: DsBtnVariant.primary, - onPressed: _redeeming ? null : _redeem), - ), - ], - ), - ), - // 在线购买仅管理员(后端 purchase 接口 admin only,主 CTA 已上移到统计条); - // 其他角色引导看官网价格页 - if (!isAdmin) ...[ - const SizedBox(height: 14), - Row(children: [ - Text('在线购买请联系门店管理员 · ', - style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)), - InkWell( - onTap: () => - launchUrl(Uri.parse('${AppInfo.website}/#pricing')), - child: Text('查看套餐价格 →', - style: TextStyle( - fontSize: AppDims.fsSm, - fontWeight: FontWeight.w600, - color: t.primary)), - ), - ]), - ], - const SizedBox(height: 16), - // 过期降级说明(现有能力保留) - Container( - padding: const EdgeInsets.all(14), - decoration: BoxDecoration( - color: t.bg, - border: Border.all(color: t.borderSubtle), - borderRadius: BorderRadius.circular(AppDims.rMd), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('到期后的降级规则', - style: TextStyle( - fontSize: AppDims.fsSm, - fontWeight: FontWeight.w600, - color: t.heading)), - const SizedBox(height: 6), - for (final note in LicenseCopy.degradationNotes()) - Padding( - padding: const EdgeInsets.only(top: 3), - child: Text('· $note', - style: TextStyle( - fontSize: AppDims.fsSm, color: t.muted)), - ), - ], - ), - ), - ], + ]), ), ), - // 在线购买仅管理员(后端 purchase 接口 admin only),单独一张卡内联展示 - if (isAdmin) ...[ - const SizedBox(height: 16), + const SizedBox(height: 16), + // ── 卡2:在线购买 / 续费(后端 purchase 接口 admin only, + // 非管理员引导看官网价格页)── + if (isAdmin) const _SettingsCard( title: '在线购买 / 续费', desc: '选择套餐支付宝支付,到账后授权自动续期', child: PurchaseCard(), + ) + else + _SettingsCard( + title: '在线购买 / 续费', + desc: '在线购买仅门店管理员可操作', + child: Row(children: [ + Text('在线购买请联系门店管理员 · ', + style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)), + InkWell( + onTap: () => + launchUrl(Uri.parse('${AppInfo.website}/#pricing')), + child: Text('查看套餐价格 →', + style: TextStyle( + fontSize: AppDims.fsSm, + fontWeight: FontWeight.w600, + color: t.primary)), + ), + ]), ), - ], + const SizedBox(height: 16), + // ── 卡3:兑换券(原型 .redeem:input + 按钮,max 520)── + _SettingsCard( + title: '兑换券', + desc: '输入兑换券短码续期', + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 520), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('兑换券短码', + style: TextStyle( + fontSize: AppDims.fsSm, color: t.muted)), + const SizedBox(height: 6), + DsInput( + controller: _voucherCtrl, + hintText: '输入兑换券短码', + ), + ], + ), + ), + const SizedBox(width: 10), + WriteGuard( + child: DsButton(_redeeming ? '兑换中…' : '兑换续期', + variant: DsBtnVariant.primary, + onPressed: _redeeming ? null : _redeem), + ), + ], + ), + ), + ), + const SizedBox(height: 16), + // ── 卡4:到期后的降级规则(现有能力保留)── + _SettingsCard( + title: '到期后的降级规则', + desc: '授权到期后系统各功能的可用性说明', + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + for (final note in LicenseCopy.degradationNotes()) + Padding( + padding: const EdgeInsets.only(top: 3), + child: Text('· $note', + style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)), + ), + ], + ), + ), ], ); }