feat: redesign uni-app mobile with consolidated 4-tab workspace

Replace 5-tab layout (首页/客户/营销/报价/我的) with 4-tab (首页/客户/业务/我的). Add workspace-customer (客户列表/挖掘新客/智能跟进) and workspace-biz (翻译/产品库/报价单/营销素材) pages. Simplify index to dashboard, update profile nav.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
TradeMate Dev
2026-06-21 23:05:29 +08:00
parent 5e1aa95969
commit b1ffb78629
6 changed files with 2528 additions and 18 deletions
+3 -1
View File
@@ -10,11 +10,13 @@ export const STORAGE_KEYS = {
export const PAGES = { export const PAGES = {
INDEX: '/pages/index/index', INDEX: '/pages/index/index',
WORKSPACE_CUSTOMER: '/pages/workspace-customer/workspace-customer',
WORKSPACE_BIZ: '/pages/workspace-biz/workspace-biz',
PROFILE: '/pages/profile/profile',
TRANSLATE: '/pages/translate/translate', TRANSLATE: '/pages/translate/translate',
CUSTOMERS: '/pages/customers/customers', CUSTOMERS: '/pages/customers/customers',
MARKETING: '/pages/marketing/marketing', MARKETING: '/pages/marketing/marketing',
QUOTATION: '/pages/quotation/quotation', QUOTATION: '/pages/quotation/quotation',
PROFILE: '/pages/profile/profile',
LOGIN: '/pages/login/login', LOGIN: '/pages/login/login',
PRODUCT: '/pages/product/product', PRODUCT: '/pages/product/product',
UPGRADE: '/pages/upgrade/upgrade', UPGRADE: '/pages/upgrade/upgrade',
+17 -7
View File
@@ -18,6 +18,20 @@
"navigationBarTitleText": "客户管理" "navigationBarTitleText": "客户管理"
} }
}, },
{
"path": "pages/workspace-customer/workspace-customer",
"style": {
"navigationBarTitleText": "客户工作台",
"navigationStyle": "custom"
}
},
{
"path": "pages/workspace-biz/workspace-biz",
"style": {
"navigationBarTitleText": "业务工作台",
"navigationStyle": "custom"
}
},
{ {
"path": "pages/marketing/marketing", "path": "pages/marketing/marketing",
"style": { "style": {
@@ -145,16 +159,12 @@
"text": "首页" "text": "首页"
}, },
{ {
"pagePath": "pages/customers/customers", "pagePath": "pages/workspace-customer/workspace-customer",
"text": "客户" "text": "客户"
}, },
{ {
"pagePath": "pages/marketing/marketing", "pagePath": "pages/workspace-biz/workspace-biz",
"text": "营销" "text": "业务"
},
{
"pagePath": "pages/quotation/quotation",
"text": "报价"
}, },
{ {
"pagePath": "pages/profile/profile", "pagePath": "pages/profile/profile",
+15 -7
View File
@@ -130,25 +130,33 @@
</view> </view>
<view class="more-section"> <view class="more-section">
<view class="section-title">功能矩阵</view> <view class="section-title">快捷入口</view>
<view class="more-grid"> <view class="more-grid">
<view class="more-item" @click="goToPage(PAGES.TRANSLATE)"> <view class="more-item" @click="goToPage(PAGES.WORKSPACE_BIZ)">
<text class="more-icon">🔤</text> <text class="more-icon">🔤</text>
<text class="more-text">翻译</text> <text class="more-text">翻译</text>
</view> </view>
<view class="more-item" @click="goToPage(PAGES.DISCOVERY)"> <view class="more-item" @click="goToPage(PAGES.WORKSPACE_CUSTOMER)">
<text class="more-icon">🔍</text> <text class="more-icon">🔍</text>
<text class="more-text">挖掘新</text> <text class="more-text"></text>
</view> </view>
<view class="more-item" @click="hasLogin ? goToPage(PAGES.PRODUCT) : goToLogin()"> <view class="more-item" @click="hasLogin ? goToPage(PAGES.WORKSPACE_BIZ) : goToLogin()">
<text class="more-icon">📦</text> <text class="more-icon">📦</text>
<text class="more-text">产品</text> <text class="more-text">产品</text>
</view> </view>
<view class="more-item" @click="hasLogin ? goToPage(PAGES.FOLLOWUP) : goToLogin()"> <view class="more-item" @click="hasLogin ? goToPage(PAGES.WORKSPACE_CUSTOMER) : goToLogin()">
<text class="more-icon">📋</text> <text class="more-icon">📋</text>
<text class="more-text">跟进</text> <text class="more-text">跟进</text>
<text class="notif-badge" v-if="hasLogin && followupStats.pending > 0">{{ followupStats.pending > 99 ? '99+' : followupStats.pending }}</text> <text class="notif-badge" v-if="hasLogin && followupStats.pending > 0">{{ followupStats.pending > 99 ? '99+' : followupStats.pending }}</text>
</view> </view>
<view class="more-item" @click="hasLogin ? goToPage(PAGES.WORKSPACE_BIZ) : goToLogin()">
<text class="more-icon">💰</text>
<text class="more-text">报价</text>
</view>
<view class="more-item" @click="hasLogin ? goToPage(PAGES.WORKSPACE_BIZ) : goToLogin()">
<text class="more-icon">📝</text>
<text class="more-text">营销</text>
</view>
<view class="more-item" @click="hasLogin ? goToPage(PAGES.NOTIFICATION) : goToLogin()"> <view class="more-item" @click="hasLogin ? goToPage(PAGES.NOTIFICATION) : goToLogin()">
<text class="more-icon">🔔</text> <text class="more-icon">🔔</text>
<text class="more-text">通知</text> <text class="more-text">通知</text>
+45 -3
View File
@@ -19,6 +19,26 @@
</view> </view>
</view> </view>
<view class="section">
<view class="section-title">工作台</view>
<view class="menu-item" @click="goNotification">
<text class="menu-icon">🔔</text>
<text class="menu-text">通知中心</text>
<text class="badge-count" v-if="unreadCount > 0">{{ unreadCount > 99 ? '99+' : unreadCount }}</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="goAnalytics">
<text class="menu-icon">📊</text>
<text class="menu-text">数据分析</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="goTeam">
<text class="menu-icon">👥</text>
<text class="menu-text">团队协作</text>
<text class="menu-arrow"></text>
</view>
</view>
<view class="section"> <view class="section">
<view class="section-title">账号设置</view> <view class="section-title">账号设置</view>
<view class="menu-item" v-if="user.tier !== 'guest'" @click="showProfileEdit = true"> <view class="menu-item" v-if="user.tier !== 'guest'" @click="showProfileEdit = true">
@@ -59,6 +79,16 @@
<text class="menu-text">意见反馈</text> <text class="menu-text">意见反馈</text>
<text class="menu-arrow"></text> <text class="menu-arrow"></text>
</view> </view>
<view class="menu-item" @click="goPage('/pages/upgrade/upgrade')">
<text class="menu-icon">💎</text>
<text class="menu-text">升级会员</text>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @click="showWechatModal = true">
<text class="menu-icon">💁</text>
<text class="menu-text">联系客服</text>
<text class="menu-arrow"></text>
</view>
</view> </view>
<view class="section"> <view class="section">
@@ -138,12 +168,13 @@
<script setup> <script setup>
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app' import { onShow } from '@dcloudio/uni-app'
import { authApi, creditApi } from '@/utils/api.js' import { authApi, creditApi, notificationApi } from '@/utils/api.js'
import AiAssistant from '@/components/ai-assistant.vue' import AiAssistant from '@/components/ai-assistant.vue'
import { STORAGE_KEYS, PAGES, TIER_LABELS } from '@/config.js' import { STORAGE_KEYS, PAGES, TIER_LABELS } from '@/config.js'
const user = ref({}) const user = ref({})
const creditBalance = ref(0) const creditBalance = ref(0)
const unreadCount = ref(0)
const showProfileEdit = ref(false) const showProfileEdit = ref(false)
const showPassword = ref(false) const showPassword = ref(false)
const editForm = ref({ username: '', email: '' }) const editForm = ref({ username: '', email: '' })
@@ -217,6 +248,17 @@ const goFeedback = () => uni.navigateTo({ url: PAGES.FEEDBACK })
const goAgreement = (type) => uni.navigateTo({ url: `/pages/agreement/${type}` }) const goAgreement = (type) => uni.navigateTo({ url: `/pages/agreement/${type}` })
const goCertification = () => uni.navigateTo({ url: PAGES.CERTIFICATION }) const goCertification = () => uni.navigateTo({ url: PAGES.CERTIFICATION })
const goInvoice = () => uni.navigateTo({ url: PAGES.INVOICE }) const goInvoice = () => uni.navigateTo({ url: PAGES.INVOICE })
const goNotification = () => uni.navigateTo({ url: PAGES.NOTIFICATION })
const goAnalytics = () => uni.navigateTo({ url: PAGES.ANALYTICS })
const goTeam = () => uni.navigateTo({ url: PAGES.TEAM })
const goPage = (url) => uni.navigateTo({ url })
const loadUnread = async () => {
try {
const res = await notificationApi.unreadCount()
unreadCount.value = res.count || 0
} catch { unreadCount.value = 0 }
}
const logout = () => { const logout = () => {
uni.showModal({ uni.showModal({
@@ -232,8 +274,8 @@ const logout = () => {
}) })
} }
onMounted(loadUser) onMounted(() => { loadUser(); loadUnread() })
onShow(loadUser) onShow(() => { loadUser(); loadUnread() })
</script> </script>
<style scoped> <style scoped>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff