feat: upgrade custom tabbar with emoji support, redesign quick-actions
- Switch back to custom tabbar (custom: true) with emoji fix (line-height, font-family) - Redesign home quick-actions: product/followup/analytics/notifications replace redundant nav items - Refactor goToPage to auto-detect tabbar vs non-tabbar pages - Update PROGRESS.md
This commit is contained in:
+39
-10
@@ -1,7 +1,7 @@
|
||||
# TradeMate (外贸小助手) - 项目进度文档
|
||||
|
||||
**更新时间**: 2026-05-12 16:30
|
||||
**状态**: ✅ 游客模式已实现 + H5 底部导航已修复 - 所有功能正常
|
||||
**更新时间**: 2026-05-13 12:00
|
||||
**状态**: ✅ CORS/API 500 修复 + 自定义 tabbar 升级(emoji 正常渲染) - 所有功能正常
|
||||
|
||||
---
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
## 二、已完成的工作
|
||||
|
||||
### 1. Bug 修复 (共 10 个)
|
||||
### 1. Bug 修复 (共 13 个)
|
||||
|
||||
| 序号 | 文件 | 问题描述 | 状态 |
|
||||
|------|------|----------|------|
|
||||
@@ -37,6 +37,9 @@
|
||||
| 8 | `app/ai/providers/openai.py` | max_tokens=1000 不足,导致 Sensenova content 为 None | ✅ 已增加到 3000 |
|
||||
| 9 | `app/ai/providers/openai.py` | Sensenova 特殊 reasoning 字段未处理 | ✅ 已增强 fallback 逻辑 |
|
||||
| 10 | `src/App.vue` + 全局样式 | H5 底部导航覆盖内容 — uni-page 高度未扣除 tabbar | ✅ 设置 `height: calc(100% - 50px)` + `overflow-y: auto` |
|
||||
| 11 | `app/api/v1/auth.py` + `deps.py` | **API 500 根因** — 旧 token `sub` 为 `guest_xxx`(非 UUID),DB UUID 列查询抛 500,CORS 头无法返回 → 浏览器误报 CORS 错误 | ✅ 游客 ID 改为合法 UUID;`get_current_user_id` 校验 UUID 格式,旧 token 返回 401 |
|
||||
| 12 | `backend/.env` + `app/main.py` | CORS 配置不当 — `allow_origins` 包含 `*` + FRONTEND_URL 被忽略 | ✅ 去掉通配符,FRONTEND_URL 指向 `http://localhost:5173` |
|
||||
| 13 | `uni-app/src/utils/api.js` | 前端直连后端端口 → 跨域请求 | ✅ BASE_URL 改为 `/api/v1` 走 Vite proxy,同源请求消除 CORS |
|
||||
|
||||
### 2. 游客模式 (Guest Mode) 实现 ✅
|
||||
|
||||
@@ -120,21 +123,44 @@
|
||||
|
||||
前端 uni-app + Vue 3 项目已启动:
|
||||
- 地址: http://localhost:5173
|
||||
- 后端 API 代理配置: `http://localhost:8000`
|
||||
- 后端 API 代理配置: Vite proxy (`/api` → `http://localhost:8000`)
|
||||
|
||||
**前端功能**:
|
||||
- 登录页: 支持 "快速体验" 进入游客模式
|
||||
- 首页: 游客模式显示快速体验区域,支持翻译和信息提取
|
||||
- 登录页: 支持 "快速体验" 进入游客模式,微信登录按钮 H5 隐藏(条件编译)
|
||||
- 首页: 游客模式显示快速体验区域,支持翻译和信息提取;登录用户显示统计卡片、待跟进客户、快捷操作
|
||||
- 游客模式: 使用公开 API 端点,无需登录
|
||||
|
||||
### 7. 底部导航修复 & 自定义 tabbar 升级
|
||||
|
||||
| 阶段 | 改动 | 说明 |
|
||||
|------|------|------|
|
||||
| 切回原生 tabbar | `pages.json` custom: true → false | 解决自定义 tabbar 因 `position: fixed` + 父级 `transform` 定位异常问题 |
|
||||
| 清理 CSS 遗留 | `App.vue` 删除 tabbar 相关 CSS | 删除 `height: calc(100% - 50px)`、`z-index` 等,让框架自动管理原生 tabbar 布局 |
|
||||
| 恢复快捷按钮 | `index.vue` quick-actions 恢复 | 首页快捷操作按钮重新显示 |
|
||||
| 升级自定义 tabbar | `pages.json` custom: false → true | 切回自定义 tabbar 支持 emoji 图标 |
|
||||
| 修复 emoji 渲染 | `custom-tab-bar/index.vue` | `line-height: 1` → `1.5`,追加 emoji 字体族 `Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji` |
|
||||
|
||||
### 8. 首页快捷入口重新设计
|
||||
|
||||
底部导航已有"翻译、客户、营销、报价",首页快捷入口原先完全重复。重新设计为从"更多功能"区提取最高频功能:
|
||||
|
||||
| 原快捷入口 | 新快捷入口 | 说明 |
|
||||
|-----------|-----------|------|
|
||||
| 智能翻译 → 底部导航已有 | **产品库** | 外贸人每天查产品 |
|
||||
| 客户管理 → 底部导航已有 | **跟进** | 写跟进是日常高频动作,带待办角标 |
|
||||
| 营销文案 → 底部导航已有 | **数据** | 一键看业务概览 |
|
||||
| 报价单 → 底部导航已有 | **通知** | 及时看消息提醒,带未读角标 |
|
||||
|
||||
同时 `goToPage` 函数重构为按 tabbar 页面列表自动判断 `switchTab`/`navigateTo`,不再硬编码。
|
||||
|
||||
---
|
||||
|
||||
## 三、待办事项
|
||||
|
||||
### 中优先级
|
||||
1. 浏览器端手动测试(建议用户在浏览器中访问 http://localhost:5173)
|
||||
2. 测试 WhatsApp 集成
|
||||
3. 性能优化测试
|
||||
### 低优先级
|
||||
1. 测试 WhatsApp 集成
|
||||
2. 性能优化测试
|
||||
3. 自定义 tabbar emoji 渲染效果验证(若仍有问题,改用 `iconPath`/`selectedIconPath` 图片图标)
|
||||
|
||||
---
|
||||
|
||||
@@ -156,6 +182,9 @@
|
||||
| 2026-05-12 | 修复 9 个 Bug,启动后端+前端服务,完成所有 API 测试,AI 功能全部正常 |
|
||||
| 2026-05-12 | 实现游客模式:新增 `/api/v1/auth/login/guest`、`/api/v1/translate/public/*` 端点,前端支持游客体验 |
|
||||
| 2026-05-12 | 修复 H5 底部导航覆盖问题:精简 App.vue,uni-page 设置 `calc(100% - 50px)` + 独立滚动 |
|
||||
| 2026-05-13 | 修复 CORS + API 500 根因:游客 UUID 格式、Vite proxy 替代直连、CORS 配置修正 |
|
||||
| 2026-05-13 | 自定义 tabbar 升级:切回 `custom: true`,修复 emoji `line-height` 和字体族 |
|
||||
| 2026-05-13 | 首页快捷入口重新设计:产品库/跟进/数据/通知,替换原有重复项 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -82,7 +82,8 @@ onUnmounted(() => {
|
||||
|
||||
.tab-bar-icon {
|
||||
font-size: 28px !important;
|
||||
line-height: 1 !important;
|
||||
line-height: 1.5 !important;
|
||||
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif !important;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
"backgroundColor": "#f5f5f5"
|
||||
},
|
||||
"tabBar": {
|
||||
"custom": false,
|
||||
"custom": true,
|
||||
"color": "#666666",
|
||||
"selectedColor": "#1890ff",
|
||||
"backgroundColor": "#ffffff",
|
||||
|
||||
@@ -93,29 +93,35 @@
|
||||
</view>
|
||||
|
||||
<view class="quick-actions">
|
||||
<view class="action-item" @click="goToPage('/pages/translate/translate')">
|
||||
<view class="action-item" @click="hasLogin ? goToPage('/pages/product/product') : goToLogin()">
|
||||
<view class="action-icon-wrap" style="background:#e6f7ff">
|
||||
<text class="action-icon-text" style="color:#1890ff">译</text>
|
||||
<text class="action-icon-text" style="color:#1890ff">品</text>
|
||||
</view>
|
||||
<text class="action-label">智能翻译</text>
|
||||
<text class="action-label">产品库</text>
|
||||
</view>
|
||||
<view class="action-item" @click="hasLogin ? goToPage('/pages/customers/customers') : goToLogin()">
|
||||
<view class="action-icon-wrap" style="background:#fff7e6">
|
||||
<text class="action-icon-text" style="color:#fa8c16">客</text>
|
||||
<view class="action-item" @click="hasLogin ? goToPage('/pages/followup/followup') : goToLogin()">
|
||||
<view class="action-icon-wrap" style="background:#f0f0ff">
|
||||
<text class="action-icon-text" style="color:#667eea">跟</text>
|
||||
</view>
|
||||
<text class="action-label">客户管理</text>
|
||||
<text class="action-label">
|
||||
<text>跟进</text>
|
||||
<text class="action-badge" v-if="hasLogin && followupStats.pending > 0">{{ followupStats.pending > 99 ? '99+' : followupStats.pending }}</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="action-item" @click="hasLogin ? goToPage('/pages/marketing/marketing') : goToLogin()">
|
||||
<view class="action-item" @click="hasLogin ? goToPage('/pages/analytics/analytics') : goToLogin()">
|
||||
<view class="action-icon-wrap" style="background:#f6ffed">
|
||||
<text class="action-icon-text" style="color:#52c41a">营</text>
|
||||
<text class="action-icon-text" style="color:#52c41a">数</text>
|
||||
</view>
|
||||
<text class="action-label">营销文案</text>
|
||||
<text class="action-label">数据</text>
|
||||
</view>
|
||||
<view class="action-item" @click="hasLogin ? goToPage('/pages/quotation/quotation') : goToLogin()">
|
||||
<view class="action-icon-wrap" style="background:#fff0f6">
|
||||
<text class="action-icon-text" style="color:#eb2f96">价</text>
|
||||
<view class="action-item" @click="hasLogin ? goToPage('/pages/notification/notification') : goToLogin()">
|
||||
<view class="action-icon-wrap" style="background:#fff7e6">
|
||||
<text class="action-icon-text" style="color:#fa8c16">知</text>
|
||||
</view>
|
||||
<text class="action-label">报价单</text>
|
||||
<text class="action-label">
|
||||
<text>通知</text>
|
||||
<text class="action-badge" v-if="hasLogin && unreadCount > 0">{{ unreadCount > 99 ? '99+' : unreadCount }}</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -343,11 +349,13 @@ const loadData = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const tabbarPages = ['/pages/index/index', '/pages/translate/translate', '/pages/customers/customers', '/pages/marketing/marketing', '/pages/quotation/quotation']
|
||||
|
||||
const goToPage = (url) => {
|
||||
if (url === '/pages/followup/followup') {
|
||||
uni.navigateTo({ url })
|
||||
} else {
|
||||
if (tabbarPages.includes(url)) {
|
||||
uni.switchTab({ url })
|
||||
} else {
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -785,6 +793,21 @@ const copyTryResult = () => {
|
||||
.action-label {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4rpx;
|
||||
}
|
||||
|
||||
.action-badge {
|
||||
background: #ff4d4f;
|
||||
color: #fff;
|
||||
font-size: 18rpx;
|
||||
min-width: 28rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 14rpx;
|
||||
text-align: center;
|
||||
line-height: 28rpx;
|
||||
padding: 0 6rpx;
|
||||
}
|
||||
|
||||
.more-section {
|
||||
|
||||
Reference in New Issue
Block a user