feat(branding+fix): 中文品牌名、miniapp logo资源、编译错误修复

## 中文品牌名更新
- admin-app: 中文环境下 app_name → "企业券信",login_title/ai_welcome/settings_about 同步更新
- miniapp: 中文环境下 app_name → "券信",6处内联文本(share/activity/register/ai_chat等)同步更新
- genex-mobile: zh_cn + zh_tw 共12处 "Genex" → "券信"(login/register/aiChat/profile/aiFab)
- 英文/日文环境保持 "Genex" 不变

## miniapp logo 资源集成
- 新增 src/assets/images/ 目录:logo.png, logo_icon.png, logo_icon.svg, logo_full.svg
- login 页:CSS模拟logo(.logo-left/.logo-right) → <image src={logoIcon}>
- h5-share 页:💎 emoji → <img src={logoIcon}> (header + RegisterGuidePage)
- h5-activity 页:"G" 文字方块 → <image src={logoIcon}> (footer)
- h5-register 页:"G" 文字方块 → <image src={logoIcon}> (branding section)

## genex-mobile 编译错误修复
- wallet_coupons_page: EmptyState.noCoupons() + StatusTags.active/pending/expired/used() 添加 context 参数
- trading_page: StatusTags.onSale/completed/cancelled() 添加 context 参数
- message_page: EmptyState.noMessages() 添加 context 参数
- coupon_service: inner['total'] 添加 `as int?` 显式类型转换

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-23 16:57:30 -08:00
parent 3a57b0fd4d
commit a92f00af25
16 changed files with 100 additions and 80 deletions

View File

@ -37,7 +37,7 @@ class AppLocalizations {
// ================================================================
static const Map<String, String> _zhCN = {
// Common
'app_name': 'Genex',
'app_name': '企业券信',
'confirm': '确认',
'cancel': '取消',
'save': '保存',
@ -68,7 +68,7 @@ class AppLocalizations {
'tab_mine': '我的',
// Login
'login_title': 'Genex 发行方控制台',
'login_title': '券信 发行方控制台',
'login_subtitle': '登录您的企业账号管理券发行',
'login_phone': '手机号',
'login_phone_hint': '请输入企业管理员手机号',
@ -510,7 +510,7 @@ class AppLocalizations {
// AI Agent
'ai_agent_title': 'AI 助手',
'ai_agent_welcome': '您好!我是 Genex AI 助手,可以帮您分析销售数据、优化定价策略、提升信用评级。有什么可以帮您的吗?',
'ai_agent_welcome': '您好!我是企业券信 AI 助手,可以帮您分析销售数据、优化定价策略、提升信用评级。有什么可以帮您的吗?',
'ai_agent_input_hint': '输入问题...',
'ai_agent_action_sales': '分析本月销售数据',
'ai_agent_action_timing': '推荐最优发券时间',
@ -545,7 +545,7 @@ class AppLocalizations {
'settings_group_security': '安全与账号',
'settings_change_password': '修改密码',
'settings_operation_log': '操作日志',
'settings_about': '关于 Genex',
'settings_about': '关于企业券信',
'settings_logout': '退出登录',
// AI Suggestion Card

View File

@ -38,7 +38,7 @@ const Map<String, String> zhCN = {
'welcome.agreement': '注册即表示同意《用户协议》和《隐私政策》',
'login.title': '欢迎回来',
'login.subtitle': '登录 Genex 管理你的券资产',
'login.subtitle': '登录券信管理你的券资产',
'login.passwordTab': '密码登录',
'login.codeTab': '验证码登录',
'login.phoneOrEmail': '手机号或邮箱',
@ -50,8 +50,8 @@ const Map<String, String> zhCN = {
'login.getCode': '获取验证码',
'register.title': '创建账号',
'register.emailSubtitle': '使用邮箱注册 Genex 账号',
'register.phoneSubtitle': '使用手机号注册 Genex 账号',
'register.emailSubtitle': '使用邮箱注册券信账号',
'register.phoneSubtitle': '使用手机号注册券信账号',
'register.email': '邮箱地址',
'register.phone': '手机号',
'register.emailHint': '请输入邮箱地址',
@ -451,7 +451,7 @@ const Map<String, String> zhCN = {
// ============ AI Chat ============
'aiChat.title': 'AI 助手',
'aiChat.greeting': '你好!我是 Genex AI 助手,可以帮你发现高性价比好券、比价分析、组合推荐。试试问我:',
'aiChat.greeting': '你好!我是券信 AI 助手,可以帮你发现高性价比好券、比价分析、组合推荐。试试问我:',
'aiChat.suggest1': '推荐适合我的券',
'aiChat.suggest2': '星巴克券值不值得买?',
'aiChat.suggest3': '帮我做比价分析',
@ -612,7 +612,7 @@ const Map<String, String> zhCN = {
'profile.myFavorites': '我的收藏',
'profile.securitySettings': '安全设置',
'profile.advancedSettings': '高级设置',
'profile.aboutGenex': '关于 Genex',
'profile.aboutGenex': '关于券信',
'profile.simplifiedChinese': '简体中文',
// ============ Pro Mode ============
@ -658,7 +658,7 @@ const Map<String, String> zhCN = {
'wallet.redeemUse': '核销',
// ============ AI Fab ============
'aiFab.greeting': '你好!我是 Genex AI 助手,可以帮你管理券资产、查找优惠、分析价格。有什么需要帮助的吗?',
'aiFab.greeting': '你好!我是券信 AI 助手,可以帮你管理券资产、查找优惠、分析价格。有什么需要帮助的吗?',
'aiFab.inputHint': '输入消息...',
'aiFab.suggest1': '帮我找高折扣券',
'aiFab.suggest2': '我的券快到期了吗?',

View File

@ -38,7 +38,7 @@ const Map<String, String> zhTW = {
'welcome.agreement': '註冊即表示同意《使用者協議》和《隱私權政策》',
'login.title': '歡迎回來',
'login.subtitle': '登入 Genex 管理你的券資產',
'login.subtitle': '登入券信管理你的券資產',
'login.passwordTab': '密碼登入',
'login.codeTab': '驗證碼登入',
'login.phoneOrEmail': '手機號或信箱',
@ -50,8 +50,8 @@ const Map<String, String> zhTW = {
'login.getCode': '取得驗證碼',
'register.title': '建立帳號',
'register.emailSubtitle': '使用信箱註冊 Genex 帳號',
'register.phoneSubtitle': '使用手機號註冊 Genex 帳號',
'register.emailSubtitle': '使用信箱註冊券信帳號',
'register.phoneSubtitle': '使用手機號註冊券信帳號',
'register.email': '信箱地址',
'register.phone': '手機號',
'register.emailHint': '請輸入信箱地址',
@ -451,7 +451,7 @@ const Map<String, String> zhTW = {
// ============ AI Chat ============
'aiChat.title': 'AI 助手',
'aiChat.greeting': '你好!我是 Genex AI 助手,可以幫你發現高性價比好券、比價分析、組合推薦。試試問我:',
'aiChat.greeting': '你好!我是券信 AI 助手,可以幫你發現高性價比好券、比價分析、組合推薦。試試問我:',
'aiChat.suggest1': '推薦適合我的券',
'aiChat.suggest2': 'Starbucks 券值不值得買?',
'aiChat.suggest3': '幫我做比價分析',
@ -612,7 +612,7 @@ const Map<String, String> zhTW = {
'profile.myFavorites': '我的收藏',
'profile.securitySettings': '安全設定',
'profile.advancedSettings': '進階設定',
'profile.aboutGenex': '關於 Genex',
'profile.aboutGenex': '關於券信',
'profile.simplifiedChinese': '簡體中文',
// ============ Pro Mode ============
@ -658,7 +658,7 @@ const Map<String, String> zhTW = {
'wallet.redeemUse': '核銷',
// ============ AI Fab ============
'aiFab.greeting': '你好!我是 Genex AI 助手,可以幫你管理券資產、查找優惠、分析價格。有什麼需要幫助的嗎?',
'aiFab.greeting': '你好!我是券信 AI 助手,可以幫你管理券資產、查找優惠、分析價格。有什麼需要幫助的嗎?',
'aiFab.inputHint': '輸入訊息...',
'aiFab.suggest1': '幫我找高折扣券',
'aiFab.suggest2': '我的券快到期了嗎?',

View File

@ -50,7 +50,7 @@ class CouponApiService {
?.map((e) => CouponModel.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
return (items: items, total: inner['total'] ?? items.length);
return (items: items, total: (inner['total'] as int?) ?? items.length);
} catch (e) {
debugPrint('[CouponApiService] getMyHoldings 失败: $e');
rethrow;

View File

@ -237,6 +237,7 @@ class _WalletCouponsPageState extends State<WalletCouponsPage>
if (coupons.isEmpty) {
return EmptyState.noCoupons(
context,
onBrowse: () => Navigator.pop(context),
);
}
@ -365,13 +366,13 @@ class _WalletCouponsPageState extends State<WalletCouponsPage>
Widget _statusWidget(CouponStatus status) {
switch (status) {
case CouponStatus.active:
return StatusTags.active();
return StatusTags.active(context);
case CouponStatus.pending:
return StatusTags.pending();
return StatusTags.pending(context);
case CouponStatus.expired:
return StatusTags.expired();
return StatusTags.expired(context);
case CouponStatus.used:
return StatusTags.used();
return StatusTags.used(context);
}
}

View File

@ -133,7 +133,7 @@ class _MessagePageState extends State<MessagePage>
: _error != null
? _buildErrorView()
: _notifications.isEmpty
? EmptyState.noMessages()
? EmptyState.noMessages(context)
: RefreshIndicator(
onRefresh: _loadNotifications,
child: ListView.separated(

View File

@ -62,9 +62,9 @@ class _TradingPageState extends State<TradingPage>
separatorBuilder: (_, __) => const SizedBox(height: 12),
itemBuilder: (context, index) {
final statuses = [
StatusTags.onSale(),
StatusTags.completed(),
StatusTags.cancelled(),
StatusTags.onSale(context),
StatusTags.completed(context),
StatusTags.cancelled(context),
];
return Container(
padding: AppSpacing.cardPadding,

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,30 @@
<svg viewBox="0 0 200 72" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="L" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#9B5CF6"/>
<stop offset="100%" stop-color="#A855F7"/>
</linearGradient>
<linearGradient id="R" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#D946EF"/>
<stop offset="100%" stop-color="#E11D89"/>
</linearGradient>
<linearGradient id="EX" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#D946EF"/>
<stop offset="100%" stop-color="#E11D89"/>
</linearGradient>
<mask id="notch">
<rect x="-36" y="-36" width="72" height="72" fill="white"/>
<circle cx="0" cy="-28" r="4" fill="black"/>
<circle cx="0" cy="28" r="4" fill="black"/>
</mask>
</defs>
<g transform="translate(36,36)">
<g transform="rotate(45) scale(0.7)" mask="url(#notch)">
<path d="M-28 -28 L-0.05 -28 L-6 -2 L0 2 L-0.05 28 L-28 28 Z" fill="url(#L)"/>
<path d="M0.05 -28 L28 -28 L28 28 L0.05 28 L6 2 L0 -2 Z" fill="url(#R)"/>
</g>
</g>
<text x="78" y="41" font-family="Sora, sans-serif" font-weight="800" font-size="20" letter-spacing="-0.3">
<tspan fill="#1A103A">GEN</tspan><tspan fill="url(#EX)">EX</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,23 @@
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="L" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#9B5CF6"/>
<stop offset="100%" stop-color="#A855F7"/>
</linearGradient>
<linearGradient id="R" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#D946EF"/>
<stop offset="100%" stop-color="#E11D89"/>
</linearGradient>
<mask id="notch">
<rect x="-36" y="-36" width="72" height="72" fill="white"/>
<circle cx="0" cy="-28" r="4" fill="black"/>
<circle cx="0" cy="28" r="4" fill="black"/>
</mask>
</defs>
<g transform="translate(50,50)">
<g transform="rotate(45)" mask="url(#notch)">
<path d="M-28 -28 L-0.05 -28 L-6 -2 L0 2 L-0.05 28 L-28 28 Z" fill="url(#L)"/>
<path d="M0.05 -28 L28 -28 L28 28 L0.05 28 L6 2 L0 -2 Z" fill="url(#R)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 920 B

View File

@ -22,7 +22,7 @@ export function t(key: string, locale: Locale = defaultLocale): string {
const translations: Record<Locale, Record<string, string>> = {
'zh-CN': {
// ── Common ──
'app_name': 'Genex',
'app_name': '券信',
'confirm': '确认',
'cancel': '取消',
'save': '保存',
@ -174,7 +174,7 @@ const translations: Record<Locale, Record<string, string>> = {
'share_copied': '链接已复制',
// ── Download App ──
'download_app_title': '下载 Genex App',
'download_app_title': '下载券信 App',
'download_app_desc': '下载App享受更多功能和更好体验',
'download_app_button': '立即下载',
'download_app_ios': 'iOS 下载',
@ -244,7 +244,7 @@ const translations: Record<Locale, Record<string, string>> = {
'download_btn': '下载',
// ── H5 Share ──
'share_from_genex': '来自 Genex 的分享',
'share_from_genex': '来自券信的分享',
'share_open_app': '打开 App 购买',
'share_miniapp_buy': '小程序购买',
'share_to_friends': '分享给好友',
@ -265,7 +265,7 @@ const translations: Record<Locale, Record<string, string>> = {
'activity_rule_2': '每位用户限购每种券3张活动优惠券不与其他优惠叠加使用',
'activity_rule_3': '优惠券自购买之日起30天内有效过期自动作废',
'activity_rule_4': '活动券仅限新注册用户首次购买使用',
'activity_rule_5': '如遇商品售罄,Genex保留调整活动内容的权利',
'activity_rule_5': '如遇商品售罄,券信保留调整活动内容的权利',
'activity_rule_6': '退款将原路返回处理时间为1-3个工作日',
'activity_rule_7': '如有疑问请联系客服support@genex.com',
'activity_participants': '已有 {count} 人参与',
@ -277,7 +277,7 @@ const translations: Record<Locale, Record<string, string>> = {
'activity_coupons': '活动好券',
'activity_brand': '品牌',
'activity_join_now': '立即参与',
'register_join': '加入 Genex',
'register_join': '加入券信',
'register_slogan': '让每一张券都有价值',
'register_benefit': '注册即享首单立减优惠',
'register_benefit_coupons': '海量优惠券',
@ -288,7 +288,7 @@ const translations: Record<Locale, Record<string, string>> = {
'register_benefit_safe_desc': '平台担保,放心购买',
'register_now': '立即注册',
'register_login': '已有账号,登录',
'register_why_genex': '为什么选择 Genex',
'register_why_genex': '为什么选择券信',
'register_benefit_coupons_full': '覆盖餐饮、购物、娱乐等20+品类,全球大牌低价好券',
'register_benefit_safe_full': '平台担保交易,资金托管机制,保障每一笔交易安全可靠',
'register_benefit_ai': 'AI智能推荐',
@ -387,7 +387,7 @@ const translations: Record<Locale, Record<string, string>> = {
// ── AI Chat ──
'ai_chat_title': 'AI 助手',
'ai_chat_greeting': '你好!我是 Genex AI 助手,可以帮你发现高性价比好券。试试问我:',
'ai_chat_greeting': '你好!我是券信 AI 助手,可以帮你发现高性价比好券。试试问我:',
'ai_chat_suggest1': '推荐适合我的券',
'ai_chat_suggest2': '星巴克券值不值得买?',
'ai_chat_suggest3': '帮我做比价分析',

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { t } from '@/i18n';
import { getFeaturedCoupons } from '../../services/coupon';
import type { CouponItem } from '../../services/coupon';
import logoIcon from '@/assets/images/logo_icon.png';
// Taro mini-program component
/**
@ -205,9 +206,7 @@ const H5ActivityPage: React.FC = () => {
{/* Brand Footer */}
<view className="brand-footer">
<view className="footer-logo">
<view className="footer-logo-box">
<text className="footer-logo-text">G</text>
</view>
<image className="footer-logo-img" src={logoIcon} mode="aspectFit" />
<text className="footer-logo-name">Genex</text>
</view>
<text className="footer-slogan">{t('app_platform_slogan')}</text>
@ -564,20 +563,10 @@ CSS (H5活动页样式 - 对应 index.scss):
align-items: center;
margin-bottom: 12rpx;
}
.footer-logo-box {
.footer-logo-img {
width: 48rpx; height: 48rpx;
background: linear-gradient(135deg, #6C5CE7, #9B8FFF);
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
}
.footer-logo-text {
font-size: 28rpx;
font-weight: 700;
color: white;
}
.footer-logo-name {
font-size: 30rpx;
font-weight: 600;

View File

@ -3,6 +3,7 @@ import { t } from '@/i18n';
import Taro from '@tarojs/taro';
import { register, sendSmsCode } from '../../services/auth';
import { authStore } from '../../store/auth';
import logoIcon from '@/assets/images/logo_icon.png';
// Taro mini-program component
/**
@ -71,9 +72,7 @@ const H5RegisterPage: React.FC = () => {
<view className="branding-section">
<view className="brand-bg-circle-1" />
<view className="brand-bg-circle-2" />
<view className="brand-logo-box">
<text className="brand-logo-letter">G</text>
</view>
<image className="brand-logo-img" src={logoIcon} mode="aspectFit" />
<text className="brand-app-name">Genex</text>
<text className="brand-tagline">{t('app_platform_slogan')}</text>
</view>
@ -248,22 +247,12 @@ CSS (H5注册引导页样式 - 对应 index.scss):
border-radius: 50%;
bottom: -20rpx; left: -30rpx;
}
.brand-logo-box {
.brand-logo-img {
width: 120rpx; height: 120rpx;
background: rgba(255,255,255,0.2);
border-radius: 28rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
border: 2rpx solid rgba(255,255,255,0.3);
border-radius: 28rpx;
box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.15);
}
.brand-logo-letter {
font-size: 56rpx;
font-weight: 700;
color: white;
}
.brand-app-name {
font-size: 44rpx;
font-weight: 700;

View File

@ -3,6 +3,7 @@ import { t } from '@/i18n';
import Taro from '@tarojs/taro';
import { getCouponDetail } from '../../services/coupon';
import type { CouponItem } from '../../services/coupon';
import logoIcon from '@/assets/images/logo_icon.png';
/**
* E2. H5页面 - + +
@ -51,7 +52,7 @@ export const SharePage: React.FC = () => {
color: 'white',
fontSize: 13,
}}>
<span style={{ fontSize: 16 }}>💎</span>
<img src={logoIcon} style={{ width: 20, height: 20 }} alt="Genex" />
<span>{t('share_from_genex')}</span>
</div>
</div>
@ -264,15 +265,15 @@ export const RegisterGuidePage: React.FC = () => {
{/* Logo */}
<div style={{
width: 72, height: 72,
background: 'linear-gradient(135deg, #6C5CE7, #9B8FFF)',
borderRadius: 18,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 24,
boxShadow: '0 4px 16px rgba(108,92,231,0.3)',
overflow: 'hidden',
}}>
<span style={{ fontSize: 32 }}>💎</span>
<img src={logoIcon} style={{ width: 72, height: 72 }} alt="Genex" />
</div>
<h1 style={{ fontSize: 24, fontWeight: 700, color: '#141723', margin: '0 0 8px' }}>

View File

@ -3,6 +3,7 @@ import { t } from '@/i18n';
import Taro from '@tarojs/taro';
import { authStore } from '../../store/auth';
import { sendSmsCode } from '../../services/auth';
import logoIcon from '@/assets/images/logo_icon.png';
// Taro mini-program component
/**
@ -65,10 +66,7 @@ const LoginPage: React.FC = () => {
<view className="login-page">
{/* Logo */}
<view className="logo-section">
<view className="logo-box">
<view className="logo-left" />
<view className="logo-right" />
</view>
<image className="logo-img" src={logoIcon} mode="aspectFit" />
<text className="app-name">GENEX</text>
<text className="app-slogan">{t('app_slogan')}</text>
</view>
@ -149,19 +147,8 @@ CSS:
display: flex; flex-direction: column; align-items: center;
padding-top: 160rpx; padding-bottom: 80rpx;
}
.logo-box {
.logo-img {
width: 120rpx; height: 120rpx;
border-radius: 28rpx;
display: flex; align-items: center; justify-content: center;
overflow: hidden; transform: rotate(45deg);
}
.logo-left {
width: 50%; height: 100%;
background: linear-gradient(135deg, #9B5CF6, #A855F7);
}
.logo-right {
width: 50%; height: 100%;
background: linear-gradient(135deg, #D946EF, #E11D89);
}
.app-name { font-size: 40rpx; font-weight: 700; color: #141723; margin-top: 24rpx; }
.app-slogan { font-size: 26rpx; color: #A0A8BE; margin-top: 8rpx; }