refactor: 产品大图迁移OSS,小图标本地打包,资源基址改为.env配置

This commit is contained in:
2026-08-06 23:52:48 +08:00
parent 8de00e6614
commit 0f3132b08e
77 changed files with 83 additions and 70 deletions
+6 -5
View File
@@ -4,14 +4,15 @@ import { useEffect, useState } from 'react'
import { getTheme, resolveTheme } from '../utils/store'
import { THEME_CHANGE_EVENT } from '../context/ThemeContext'
import { applyPageBackground } from '../utils/themeBackground'
import { assetUrl } from '../utils/asset'
import './index.scss'
const TABS = [
{ pagePath: '/pages/index/index', label: '首页', icon: '/icon/首页.svg', iconActive: '/icon/首页-fill.svg' },
{ pagePath: '/pages/shop/index', label: '商品', icon: '/icon/商品.svg', iconActive: '/icon/商品-fill.svg' },
{ pagePath: '/pages/designList/index', label: '设计清单', icon: '/icon/调色盘.svg', iconActive: '/icon/调色盘-fill.svg' },
{ pagePath: '/pages/orders/index', label: '订单', icon: '/icon/包裹.svg', iconActive: '/icon/包裹-fill.svg' },
{ pagePath: '/pages/profile/index', label: '我的', icon: '/icon/个人.svg', iconActive: '/icon/个人-fill.svg' }
{ pagePath: '/pages/index/index', label: '首页', icon: assetUrl('/icon/首页.svg'), iconActive: assetUrl('/icon/首页-fill.svg') },
{ pagePath: '/pages/shop/index', label: '商品', icon: assetUrl('/icon/商品.svg'), iconActive: assetUrl('/icon/商品-fill.svg') },
{ pagePath: '/pages/designList/index', label: '设计清单', icon: assetUrl('/icon/调色盘.svg'), iconActive: assetUrl('/icon/调色盘-fill.svg') },
{ pagePath: '/pages/orders/index', label: '订单', icon: assetUrl('/icon/包裹.svg'), iconActive: assetUrl('/icon/包裹-fill.svg') },
{ pagePath: '/pages/profile/index', label: '我的', icon: assetUrl('/icon/个人.svg'), iconActive: assetUrl('/icon/个人-fill.svg') }
]
function matchTab(path: string): string {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

+2 -1
View File
@@ -8,6 +8,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import { assetUrl } from '../../utils/asset'
export default function AddressPage() {
const { theme, resolvedTheme } = useThemeContext()
@@ -132,7 +133,7 @@ export default function AddressPage() {
{list.length === 0 && (
<View className='empty-state'>
<Image className='empty-icon-img' src='/icon/地址.png' mode='aspectFit' />
<Image className='empty-icon-img' src={assetUrl('/icon/地址.png')} mode='aspectFit' />
<Text className='empty-text'></Text>
<Text className='empty-sub'></Text>
</View>
+1 -1
View File
@@ -210,7 +210,7 @@ export default function DesignListPage() {
{filtered.length === 0 && (
<View className='empty-state'>
<Image className='empty-icon-img' src='/icon/调色盘.png' mode='aspectFit' />
<Image className='empty-icon-img' src={assetUrl('/icon/调色盘.png')} mode='aspectFit' />
<Text className='empty-text'></Text>
<Text className='empty-sub'></Text>
<View className='btn-gradient' onTap={() => Taro.switchTab({ url: '/pages/index/index' })}>
+3 -3
View File
@@ -62,7 +62,7 @@ export default function Index() {
<View className='search-card dashed-card'>
<View className='star-badge' />
<View className='search-inner'>
<Image className='search-icon-img' src='/icon/搜索.png' mode='aspectFit' />
<Image className='search-icon-img' src={assetUrl('/icon/搜索.png')} mode='aspectFit' />
<Input
className='search-input'
type='text'
@@ -132,7 +132,7 @@ export default function Index() {
<View className='category-img-wrapper'>
<Image
className='category-img-real'
src={PRODUCT_IMG_MAP[cat.id] || '/icon/四角星.png'}
src={PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.png')}
mode='aspectFill'
/>
</View>
@@ -144,7 +144,7 @@ export default function Index() {
</View>
{filteredCategories.length === 0 && (
<View className='empty-category dashed-card'>
<Image className='empty-icon-img' src='/icon/搜索.png' mode='aspectFit' />
<Image className='empty-icon-img' src={assetUrl('/icon/搜索.png')} mode='aspectFit' />
<Text className='empty-text'></Text>
<Text className='empty-sub'></Text>
</View>
+2 -2
View File
@@ -100,7 +100,7 @@ export default function OrderDetailPage() {
<View className='star-badge' />
<View className='logistics-header'>
<View className='flex-center'>
<Image className='card-icon-img' src='/icon/包裹.png' mode='aspectFit' />
<Image className='card-icon-img' src={assetUrl('/icon/包裹.png')} mode='aspectFit' />
<Text className='logistics-title'></Text>
</View>
<Text className='logistics-num'>单号: SF1234567890</Text>
@@ -161,7 +161,7 @@ export default function OrderDetailPage() {
<View className='star-badge' />
<View className='address-header'>
<View className='flex-center'>
<Image className='card-icon-img' src='/icon/地址.png' mode='aspectFit' />
<Image className='card-icon-img' src={assetUrl('/icon/地址.png')} mode='aspectFit' />
<Text className='address-title'></Text>
</View>
<View className='address-change' onTap={() => setShowAddrPicker(true)}>
+1 -1
View File
@@ -174,7 +174,7 @@ export default function OrdersPage() {
{filteredOrders.length === 0 && (
<View className='empty-state'>
<Image className='empty-icon-img' src='/icon/包裹.png' mode='aspectFit' />
<Image className='empty-icon-img' src={assetUrl('/icon/包裹.png')} mode='aspectFit' />
<Text className='empty-text'></Text>
<Text className='empty-sub'></Text>
<View className='btn-gradient' onTap={() => Taro.switchTab({ url: '/pages/index/index' })}>
+15 -14
View File
@@ -9,22 +9,23 @@ import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import { login, getMe, updateProfile, getToken } from '../../utils/api'
import { safeHideLoading } from '../../utils/request'
import { assetUrl } from '../../utils/asset'
const ICON_MAP: Record<string, string> = {
'我的设计': '/icon/调色盘.png',
'词云生成': '/icon/词云生成.png',
'收货地址': '/icon/地址.png',
'联系客服': '/icon/电话.png',
'使用帮助': '/icon/使用帮助.png',
'设置': '/icon/设置.png'
'我的设计': assetUrl('/icon/调色盘.png'),
'词云生成': assetUrl('/icon/词云生成.png'),
'收货地址': assetUrl('/icon/地址.png'),
'联系客服': assetUrl('/icon/电话.png'),
'使用帮助': assetUrl('/icon/使用帮助.png'),
'设置': assetUrl('/icon/设置.png')
}
const STATUS_MAP = [
{ key: 'toDesign', label: '待设计', icon: '/icon/三角尺.png' },
{ key: 'pending', label: '待付款', icon: '/icon/四角星.png' },
{ key: 'paid', label: '待发货', icon: '/icon/包裹.png' },
{ key: 'shipping', label: '待收货', icon: '/icon/杯子.png' },
{ key: 'done', label: '已完成', icon: '/icon/书本.png' }
{ key: 'toDesign', label: '待设计', icon: assetUrl('/icon/三角尺.png') },
{ key: 'pending', label: '待付款', icon: assetUrl('/icon/四角星.png') },
{ key: 'paid', label: '待发货', icon: assetUrl('/icon/包裹.png') },
{ key: 'shipping', label: '待收货', icon: assetUrl('/icon/杯子.png') },
{ key: 'done', label: '已完成', icon: assetUrl('/icon/书本.png') }
]
const MENU_ITEMS = [
@@ -288,7 +289,7 @@ export default function ProfilePage() {
<Image className='avatar' src={userInfo.avatarUrl} mode='aspectFill' />
) : (
<View className='avatar-placeholder' onTap={handleOpenLogin}>
<Image className='avatar-icon-img' src='/icon/个人.png' mode='aspectFit' />
<Image className='avatar-icon-img' src={assetUrl('/icon/个人.png')} mode='aspectFit' />
</View>
)}
<View className='user-meta'>
@@ -351,7 +352,7 @@ export default function ProfilePage() {
<View className='flex-between'>
<View className='flex-column'>
<View className='flex-center'>
<Image className='enterprise-icon' src='/icon/企业批量定制.png' mode='aspectFit' />
<Image className='enterprise-icon' src={assetUrl('/icon/企业批量定制.png')} mode='aspectFit' />
<Text className='enterprise-title'></Text>
</View>
<Text className='enterprise-desc'></Text>
@@ -394,7 +395,7 @@ export default function ProfilePage() {
{loginAvatarUrl ? (
<Image className='avatar-img' src={loginAvatarUrl} mode='aspectFill' />
) : (
<Image className='avatar-placeholder-img' src='/icon/个人.png' mode='aspectFit' />
<Image className='avatar-placeholder-img' src={assetUrl('/icon/个人.png')} mode='aspectFit' />
)}
</Button>
<Input
+6 -5
View File
@@ -5,6 +5,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import { assetUrl } from '../../utils/asset'
const FAQ_ITEMS = [
{ q: '定制周期需要多久?', a: '通常下单后3-5个工作日内发货,批量订单(50件以上)可能需要7-10个工作日。' },
@@ -30,7 +31,7 @@ export default function ServicePage() {
{/* 客服入口 */}
<View className='service-hero dashed-card mt-20'>
<View className='star-badge' />
<Image className='service-hero-icon' src='/icon/电话.png' mode='aspectFit' />
<Image className='service-hero-icon' src={assetUrl('/icon/电话.png')} mode='aspectFit' />
<Text className='service-title'></Text>
<Text className='service-desc'> 09:00 - 18:00 线</Text>
<View className='btn-gradient service-btn' onTap={() => Taro.showToast({ title: '跳转客服会话', icon: 'none' })}>
@@ -44,7 +45,7 @@ export default function ServicePage() {
<View className='contact-list'>
<View className='contact-item dashed-card'>
<View className='star-badge' />
<Image className='contact-icon-img' src='/icon/电话.png' mode='aspectFit' />
<Image className='contact-icon-img' src={assetUrl('/icon/电话.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
<Text className='contact-value'>400-XXX-XXXX</Text>
@@ -52,7 +53,7 @@ export default function ServicePage() {
</View>
<View className='contact-item dashed-card' onTap={() => Taro.setClipboardData({ data: 'smart_engraving' })}>
<View className='star-badge' />
<Image className='contact-icon-img' src='/icon/词云生成.png' mode='aspectFit' />
<Image className='contact-icon-img' src={assetUrl('/icon/词云生成.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
<Text className='contact-value'>smart_engraving</Text>
@@ -60,7 +61,7 @@ export default function ServicePage() {
</View>
<View className='contact-item dashed-card'>
<View className='star-badge' />
<Image className='contact-icon-img' src='/icon/使用帮助.png' mode='aspectFit' />
<Image className='contact-icon-img' src={assetUrl('/icon/使用帮助.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
<Text className='contact-value'>biz@smart-engraving.com</Text>
@@ -85,7 +86,7 @@ export default function ServicePage() {
<View className='enterprise-service dashed-card mt-20 mb-20'>
<View className='star-badge' />
<View className='flex-center'>
<Image className='enterprise-icon' src='/icon/企业批量定制.png' mode='aspectFit' />
<Image className='enterprise-icon' src={assetUrl('/icon/企业批量定制.png')} mode='aspectFit' />
<Text className='enterprise-title'></Text>
</View>
<Text className='enterprise-desc'>50</Text>
+7 -6
View File
@@ -7,6 +7,7 @@ import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import { getUserInfo, setUserInfo, clearUserInfo, getAddressList, getDefaultAddress, type AddressItem } from '../../utils/store'
import { assetUrl } from '../../utils/asset'
const THEME_OPTIONS: { label: string; value: 'light' | 'dark' | 'auto' }[] = [
{ label: '浅色模式', value: 'light' },
@@ -15,10 +16,10 @@ const THEME_OPTIONS: { label: string; value: 'light' | 'dark' | 'auto' }[] = [
]
const MENU = [
{ label: '个人信息', icon: '/icon/个人.png', action: (s: any) => s.setShowEdit(true) },
{ label: '账号管理', icon: '/icon/账号管理.png', action: () => Taro.navigateTo({ url: '/pages/userDatabase/index' }) },
{ label: '定制协议', icon: '/icon/定制协议.png', action: () => Taro.navigateTo({ url: '/pages/agreement/index' }) },
{ label: '关于我们', icon: '/icon/关于我们.png', action: () => Taro.showToast({ title: '智绘微刻 v1.0', icon: 'none' }) }
{ label: '个人信息', icon: assetUrl('/icon/个人.png'), action: (s: any) => s.setShowEdit(true) },
{ label: '账号管理', icon: assetUrl('/icon/账号管理.png'), action: () => Taro.navigateTo({ url: '/pages/userDatabase/index' }) },
{ label: '定制协议', icon: assetUrl('/icon/定制协议.png'), action: () => Taro.navigateTo({ url: '/pages/agreement/index' }) },
{ label: '关于我们', icon: assetUrl('/icon/关于我们.png'), action: () => Taro.showToast({ title: '智绘微刻 v1.0', icon: 'none' }) }
]
export default function SettingsPage() {
@@ -87,7 +88,7 @@ export default function SettingsPage() {
<Image className='settings-avatar' src={user.avatarUrl} mode='aspectFill' />
) : (
<View className='settings-avatar-placeholder'>
<Image className='settings-avatar-icon' src='/icon/个人.png' mode='aspectFit' />
<Image className='settings-avatar-icon' src={assetUrl('/icon/个人.png')} mode='aspectFit' />
</View>
)}
<View style={{ marginLeft: '20px' }}>
@@ -150,7 +151,7 @@ export default function SettingsPage() {
{editAvatar ? (
<Image className='avatar-img' src={editAvatar} mode='aspectFill' />
) : (
<Image className='avatar-placeholder-img' src='/icon/个人.png' mode='aspectFit' />
<Image className='avatar-placeholder-img' src={assetUrl('/icon/个人.png')} mode='aspectFit' />
)}
</Button>
<Input
+5 -1
View File
@@ -4,7 +4,9 @@
* 留空表示继续使用小程序包内本地资源(/icon、/img);
* 配置阿里云 OSS / CDN 后,所有经 assetUrl 处理的资源会自动拼接远程地址。
*/
export const ASSET_BASE_URL = 'https://wordcloudwechat.oss-cn-hangzhou.aliyuncs.com'
declare const __OSS_BASE_URL__: string | undefined
export const ASSET_BASE_URL = typeof __OSS_BASE_URL__ !== 'undefined' ? __OSS_BASE_URL__ : ''
/** 把本地资源路径转成远程 URL;已经是 http(s) 或 wxfile/data 的保持不变 */
export function assetUrl(path?: string | null): string {
@@ -12,6 +14,8 @@ export function assetUrl(path?: string | null): string {
if (/^(https?:|wxfile:|data:)/i.test(path)) return path
if (!ASSET_BASE_URL) return path
const base = ASSET_BASE_URL.replace(/\/+$/, '')
// 小图标(/icon/*)保持本地打包,只有 /img/* 大图走 OSS
if (!path.startsWith('/img/')) return path
const normalized = path.startsWith('/') ? path : `/${path}`
return `${base}${normalized}`
}