开山网商品详情页前端性能优化实战

简介: 开山网商品详情页前端性能优化实战:针对鞋类B2B批发场景,聚焦图片智能加载(AVIF/WebP自适应、模糊占位、按需预载)、高性能尺码选择器(虚拟网格、实时库存融合)、批发价实时计算及移动端批采体验优化,LCP降低67%,图片加载提速74%,转化率提升162%。

开山网商品详情页前端性能优化实战

一、开山网业务场景分析

1.1 开山网平台特征

开山网作为国内领先的鞋类B2B批发平台,其商品详情页具有独特的业务特点:
// 开山网商品详情页特性
interface KaiShanWangProductFeatures {
// 鞋类行业特征
footwearFeatures: {
multipleAngles: number; // 多角度展示(正侧背底内)
sizeChartRequired: boolean; // 必须显示尺码表
colorVariants: ColorVariant[]; // 颜色变体
materialShowcase: Material[]; // 材质展示
sizeGrid: SizeGrid; // 尺码网格
};

// B2B批发特征
wholesaleFeatures: {
bulkPricing: BulkPricing[]; // 阶梯批发价
minOrderQuantity: number; // 最小起订量
inventoryBySize: SizeInventory[]; // 各尺码库存
supplierInfo: SupplierProfile; // 供应商信息
tradeAssurance: boolean; // 交易保障
};

// 移动端批采特征
mobileWholesale: {
quickBulkSelect: boolean; // 快速批量选码
oneClickInquiry: boolean; // 一键询价
shareToWechat: boolean; // 微信分享
saveToFavorites: boolean; // 收藏商品
};

// 内容展示特征
contentFeatures: {
richDescriptions: Description[]; // 富文本描述
detailImages: DetailImage[]; // 详情图
videoShowcase: Video[]; // 视频展示
modelShows: ModelShow[]; // 模特展示
};
}

1.2 开山网性能痛点

// 开山网性能痛点分析
const kaiShanWangPainPoints = {
// 图片资源极其丰富
imageHeavy: {
mainImages: 12-20, // 主图(正、侧、背、底、内、细节)
sizeCharts: 3-5, // 尺码表(男女童、不同标准)
colorSwatches: 8-15, // 颜色色卡
materialTextures: 5-10, // 材质纹理特写
detailShots: 20-40, // 工艺细节图
modelShots: 10-20, // 模特展示图
totalImages: 60-100+ // 总计图片数量
},

// 尺码选择复杂
complexSizeSelection: {
sizeStandards: ['EUR', 'US', 'UK', 'CM'], // 多尺码标准
sizeGrid: '6x10+', // 6行10列以上的尺码网格
inventoryCheck: 'per-size', // 每个尺码独立库存
realtimeStock: true, // 实时库存
sizeChartImages: true // 尺码表为图片格式
},

// 批发价格计算复杂
complexPricing: {
bulkPricingTiers: 5-10, // 5-10个批发阶梯
priceRules: 'complex', // 复杂价格规则
memberDiscounts: true, // 会员折扣
promotionOverlays: true, // 促销叠加
realtimeCalculation: true // 实时计算
},

// 移动端批采场景
mobileBulkPurchase: {
quickSelectMode: true, // 快速选码模式
largeSizeGrid: true, // 大尺码表格
touchOptimized: true, // 触控优化
oneHandOperation: true, // 单手操作
shareAndInquire: true // 分享询价
}
};

二、开山网图片资源优化

2.1 鞋类商品图片智能加载

// 开山网智能图片加载系统
import { memo, useState, useCallback, useEffect, useRef, useMemo } from 'react';
import { useIntersectionObserver } from 'react-intersection-observer';

// 开山网图片分类
type ShoeImageType =
| 'main-front' // 正面主图
| 'main-side' // 侧面主图
| 'main-back' // 背面主图
| 'main-sole' // 鞋底主图
| 'main-inner' // 内里主图
| 'main-detail' // 细节主图
| 'size-chart' // 尺码表
| 'color-swatch' // 颜色色卡
| 'material-texture' // 材质纹理
| 'detail-shot' // 工艺细节
| 'model-show' // 模特展示
| 'video-cover'; // 视频封面

interface ShoeImage {
id: string;
type: ShoeImageType;
url: string;
thumbnail: string;
webpUrl?: string;
avifUrl?: string;
width: number;
height: number;
size: number;
colorVariant?: string;
angle?: string;
priority: 'critical' | 'high' | 'medium' | 'low';
preloadGroup: 'above-fold' | 'below-fold' | 'on-demand';
}

interface ShoeImageLoaderProps {
images: ShoeImage[];
productId: string;
enableSmartLoading: boolean;
onImageLoad: (imageId: string, loadTime: number, type: ShoeImageType) => void;
onImageError: (imageId: string, type: ShoeImageType) => void;
}

const ShoeImageLoader = memo(({
images,
productId,
enableSmartLoading,
onImageLoad,
onImageError
}: ShoeImageLoaderProps) => {
const [loadedImages, setLoadedImages] = useState>(new Map());
const [currentMainIndex, setCurrentMainIndex] = useState(0);
const [isFullscreen, setIsFullscreen] = useState(false);
const [showSizeChart, setShowSizeChart] = useState(false);
const [showColorSwatches, setShowColorSwatches] = useState(false);
const [devicePixelRatio, setDevicePixelRatio] = useState(1);
const [viewportWidth, setViewportWidth] = useState(window.innerWidth);
const [connectionType, setConnectionType] = useState('unknown');
const [userPreference, setUserPreference] = useState({
preferredFormat: 'auto',
qualityLevel: 'high',
showWatermark: false
});

// 设备信息检测
useEffect(() => {
const updateDeviceInfo = () => {
setDevicePixelRatio(window.devicePixelRatio || 1);
setViewportWidth(window.innerWidth);

  if (navigator.connection) {
    setConnectionType(navigator.connection.effectiveType || 'unknown');
  }
};

updateDeviceInfo();
window.addEventListener('resize', updateDeviceInfo);

if (navigator.connection) {
  navigator.connection.addEventListener('change', updateDeviceInfo);
}

// 读取用户偏好设置
const savedPreference = localStorage.getItem('ksw_image_preference');
if (savedPreference) {
  try {
    setUserPreference(JSON.parse(savedPreference));
  } catch (e) {
    console.warn('Failed to parse image preference:', e);
  }
}

return () => {
  window.removeEventListener('resize', updateDeviceInfo);
  if (navigator.connection) {
    navigator.connection.removeEventListener('change', updateDeviceInfo);
  }
};

}, []);

// 根据用户偏好和网络状况确定图片格式
const getOptimalImageUrl = useCallback((image: ShoeImage): string => {
// 如果用户手动选择了格式
if (userPreference.preferredFormat !== 'auto') {
switch (userPreference.preferredFormat) {
case 'avif':
if (image.avifUrl) return image.avifUrl;
break;
case 'webp':
if (image.webpUrl) return image.webpUrl;
break;
}
}

// 自动选择最佳格式
if (image.avifUrl && supportsAvif()) {
  return image.avifUrl;
}

if (image.webpUrl && supportsWebp()) {
  return image.webpUrl;
}

return image.url;

}, [userPreference.preferredFormat]);

// 根据网络状况调整质量等级
const getQualityLevel = useCallback((): QualityLevel => {
switch (connectionType) {
case '4g':
case 'wifi':
return userPreference.qualityLevel === 'high' ? 'high' : 'medium';
case '3g':
return 'medium';
case '2g':
case 'slow-2g':
default:
return 'low';
}
}, [connectionType, userPreference.qualityLevel]);

// 计算鞋子图片的最佳尺寸
const getOptimalSize = useCallback((originalWidth: number, originalHeight: number, type: ShoeImageType) => {
const maxWidth = viewportWidth;

// 不同类型图片的尺寸策略
let ratio = originalWidth / originalHeight;

switch (type) {
  case 'main-front':
  case 'main-side':
  case 'main-back':
    // 主图占满屏幕宽度
    ratio = 4 / 5;
    break;
  case 'main-sole':
  case 'main-inner':
    // 底部和内里稍窄
    ratio = 3 / 4;
    break;
  case 'size-chart':
    // 尺码表需要足够宽度显示
    ratio = 2 / 3;
    break;
  case 'color-swatch':
    // 色卡小图
    ratio = 1;
    break;
  case 'material-texture':
    // 材质特写
    ratio = 1;
    break;
  case 'detail-shot':
    // 细节图
    ratio = 3 / 4;
    break;
  case 'model-show':
    // 模特图
    ratio = 3 / 4;
    break;
  case 'video-cover':
    // 视频封面
    ratio = 16 / 9;
    break;
}

const optimalWidth = Math.min(originalWidth, maxWidth);
const optimalHeight = optimalWidth / ratio;

return {
  width: Math.round(optimalWidth * devicePixelRatio),
  height: Math.round(optimalHeight * devicePixelRatio)
};

}, [viewportWidth, devicePixelRatio]);

// 按类型分组图片
const groupedImages = useMemo(() => {
const groups: Record = {
'main-front': [],
'main-side': [],
'main-back': [],
'main-sole': [],
'main-inner': [],
'main-detail': [],
'size-chart': [],
'color-swatch': [],
'material-texture': [],
'detail-shot': [],
'model-show': [],
'video-cover': []
};

images.forEach(image => {
  if (groups[image.type]) {
    groups[image.type].push(image);
  }
});

return groups;

}, [images]);

// 获取关键图片(首屏必需)
const criticalImages = useMemo(() => {
const critical: ShoeImage[] = [];

// 正面主图是关键
if (groupedImages['main-front'].length > 0) {
  critical.push(groupedImages['main-front'][0]);
}

// 第一个颜色的所有主图
Object.values(groupedImages).forEach(group => {
  group.forEach(image => {
    if (image.priority === 'critical') {
      critical.push(image);
    }
  });
});

return critical;

}, [groupedImages]);

// 渐进式图片组件
const ProgressiveShoeImage = memo(({
image,
index,
isActive,
showWatermark
}: {
image: ShoeImage;
index: number;
isActive: boolean;
showWatermark: boolean;
}) => {
const [loadState, setLoadState] = useState<'loading' | 'loaded' | 'error'>('loading');
const [blurUrl, setBlurUrl] = useState('');
const [fullUrl, setFullUrl] = useState('');
const [watermarkUrl, setWatermarkUrl] = useState('');
const imageRef = useRef(null);
const { ref: intersectionRef, inView } = useIntersectionObserver({
threshold: 0.1,
triggerOnce: false
});

// 生成模糊占位图
useEffect(() => {
  if (enableSmartLoading && image.thumbnail) {
    generateBlurPlaceholder(image.thumbnail).then(url => {
      setBlurUrl(url);
    });
  }
}, [image.thumbnail, enableSmartLoading]);

// 加载完整图片
useEffect(() => {
  if (!inView && !isActive && image.preloadGroup !== 'above-fold') return;

  const startTime = performance.now();
  const optimalUrl = getOptimalImageUrl(image);
  const size = getOptimalSize(image.width, image.height, image.type);

  // 构建带尺寸的URL(CDN参数)
  const sizedUrl = optimalUrl.replace(/(\.\w+)(?=[?#]|$)/, `_${size.width}x${size.height}$1`);

  const img = new Image();
  img.onload = () => {
    const loadTime = performance.now() - startTime;
    setFullUrl(sizedUrl);
    setLoadState('loaded');
    onImageLoad(image.id, loadTime, image.type);

    // 预加载同组其他图片
    preloadGroupImages(image.type, images);
  };
  img.onerror = () => {
    setLoadState('error');
    onImageError(image.id, image.type);
  };
  img.src = sizedUrl;
}, [inView, isActive, image, getOptimalImageUrl, getOptimalSize, onImageLoad, onImageError, images]);

// 水印处理
useEffect(() => {
  if (showWatermark && loadState === 'loaded' && image.type === 'main-front') {
    // 为批发商保护图片,添加水印
    addWatermark(fullUrl).then(url => {
      setWatermarkUrl(url);
    });
  }
}, [showWatermark, loadState, fullUrl, image.type]);

return (
  <div 
    ref={intersectionRef}
    className={`shoe-image-container ${isActive ? 'active' : ''} ${loadState} ${image.type}`}
    data-image-type={image.type}
  >
    {/* 加载中显示模糊占位 */}
    {loadState === 'loading' && blurUrl && (
      <div 
        className="blur-placeholder shoe-blur"
        style={
  { backgroundImage: `url(${blurUrl})` }}
      >
        <div className="loading-spinner">
          <div className="spinner-ring"></div>
          <span>加载中...</span>
        </div>
      </div>
    )}

    {/* 加载完成的图片 */}
    {(fullUrl || watermarkUrl) && (
      <img
        ref={imageRef}
        src={watermarkUrl || fullUrl}
        alt={`${image.type} - ${index + 1}`}
        className={`shoe-image ${loadState === 'loaded' ? 'loaded' : ''}`}
        loading={image.priority === 'critical' ? 'eager' : 'lazy'}
        decoding="async"
        style={
  {
          aspectRatio: `${image.width}/${image.height}`
        }}
      />
    )}

    {/* 错误状态 */}
    {loadState === 'error' && (
      <div className="image-error shoe-error">
        <span className="error-icon">👟</span>
        <span>图片加载失败</span>
        <button onClick={() => setLoadState('loading')}>重试</button>
      </div>
    )}

    {/* 图片类型标签 */}
    {isActive && (
      <div className="image-type-label">
        {getImageTypeLabel(image.type)}
      </div>
    )}

    {/* 图片计数器 */}
    {isActive && (
      <div className="image-counter">
        {currentMainIndex + 1} / {groupedImages['main-front'].length}
      </div>
    )}
  </div>
);

});

// 预加载同组图片
const preloadGroupImages = useCallback((type: ShoeImageType, allImages: ShoeImage[]) => {
const groupImages = allImages.filter(img => img.type === type && img.id !== allImages[currentMainIndex]?.id);
const preloadIndexes = [0, 1, 2]; // 预加载前3张

preloadIndexes.forEach(i => {
  const image = groupImages[i];
  if (image && !loadedImages.has(image.id)) {
    const url = getOptimalImageUrl(image);
    const img = new Image();
    img.src = url;
    setLoadedImages(prev => new Map(prev).set(image.id, true));
  }
});

}, [getOptimalImageUrl, loadedImages, currentMainIndex]);

// 获取图片类型中文标签
const getImageTypeLabel = (type: ShoeImageType): string => {
const labels: Record = {
'main-front': '正面',
'main-side': '侧面',
'main-back': '背面',
'main-sole': '鞋底',
'main-inner': '内里',
'main-detail': '细节',
'size-chart': '尺码表',
'color-swatch': '色卡',
'material-texture': '材质',
'detail-shot': '工艺',
'model-show': '模特',
'video-cover': '视频'
};
return labels[type] || type;
};

// 主图切换
const handleMainImageChange = useCallback((direction: 'prev' | 'next') => {
const mainImages = groupedImages['main-front'];
if (mainImages.length === 0) return;

setCurrentMainIndex(prev => {
  if (direction === 'prev') {
    return prev > 0 ? prev - 1 : mainImages.length - 1;
  }
  return prev < mainImages.length - 1 ? prev + 1 : 0;
});

}, [groupedImages]);

// 键盘导航
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (!isFullscreen) return;

  switch (e.key) {
    case 'ArrowLeft':
      handleMainImageChange('prev');
      break;
    case 'ArrowRight':
      handleMainImageChange('next');
      break;
    case 'Escape':
      setIsFullscreen(false);
      break;
    case 's':
    case 'S':
      if (e.ctrlKey) {
        e.preventDefault();
        setShowSizeChart(prev => !prev);
      }
      break;
  }
};

window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);

}, [isFullscreen, handleMainImageChange]);

// 触摸滑动支持
const handleTouchStart = useCallback((e: React.TouchEvent) => {
// 实现滑动切换
}, []);

const handleTouchEnd = useCallback((e: React.TouchEvent) => {
// 实现滑动切换
}, []);

const mainImages = groupedImages['main-front'];
const currentMainImage = mainImages[currentMainIndex];

return (


{/ 主图展示区 /}

{currentMainImage && (

)}
    {/* 导航按钮 */}
    {mainImages.length > 1 && (
      <>
        <button 
          className="nav-btn prev"
          onClick={() => handleMainImageChange('prev')}
          aria-label="上一张"
        >
          ‹
        </button>
        <button 
          className="nav-btn next"
          onClick={() => handleMainImageChange('next')}
          aria-label="下一张"
        >
          ›
        </button>
      </>
    )}

    {/* 快捷操作按钮 */}
    <div className="quick-actions">
      <button 
        className={`action-btn ${showSizeChart ? 'active' : ''}`}
        onClick={() => setShowSizeChart(!showSizeChart)}
        title="查看尺码表 (Ctrl+S)"
      >
        📏 尺码表
      </button>
      <button 
        className={`action-btn ${showColorSwatches ? 'active' : ''}`}
        onClick={() => setShowColorSwatches(!showColorSwatches)}
        title="查看颜色"
      >
        🎨 颜色
      </button>
      <button 
        className="action-btn"
        onClick={() => setIsFullscreen(true)}
        title="全屏查看"
      >
        ⛶ 全屏
      </button>
    </div>
  </div>

  {/* 缩略图列表 */}
  <div className="thumbnail-strip">
    {mainImages.map((image, index) => (
      <button
        key={image.id}
        className={`thumbnail ${index === currentMainIndex ? 'active' : ''} ${image.type}`}
        onClick={() => setCurrentMainIndex(index)}
        aria-label={`查看${getImageTypeLabel(image.type)}`}
      >
        <img
          src={image.thumbnail}
          alt={`缩略图 ${index + 1}`}
          loading="lazy"
        />
        <span className="thumbnail-label">{getImageTypeLabel(image.type)}</span>
      </button>
    ))}
  </div>

  {/* 尺码表弹窗 */}
  {showSizeChart && (
    <SizeChartModal
      images={groupedImages['size-chart']}
      onClose={() => setShowSizeChart(false)}
      getOptimalUrl={getOptimalImageUrl}
    />
  )}

  {/* 颜色色卡 */}
  {showColorSwatches && (
    <ColorSwatchesPanel
      images={groupedImages['color-swatch']}
      onClose={() => setShowColorSwatches(false)}
      onSelect={(color) => {
        // 切换到对应颜色的图片
      }}
    />
  )}

  {/* 全屏灯箱 */}
  {isFullscreen && currentMainImage && (
    <FullscreenLightbox
      images={mainImages}
      currentIndex={currentMainIndex}
      onClose={() => setIsFullscreen(false)}
      onNavigate={handleMainImageChange}
      getOptimalUrl={getOptimalImageUrl}
      imageType="shoe-main"
    />
  )}

  {/* 图片设置面板 */}
  <ImageSettingsPanel
    preference={userPreference}
    onPreferenceChange={setUserPreference}
  />
</div>

);
});

// 尺码表模态框
const SizeChartModal = memo(({
images,
onClose,
getOptimalUrl
}: {
images: ShoeImage[];
onClose: () => void;
getOptimalUrl: (img: ShoeImage) => string;
}) => {
const [currentIndex, setCurrentIndex] = useState(0);

return (



e.stopPropagation()}>
    <div className="modal-header">
      <h3>📏 尺码对照表</h3>
      <div className="size-standard-tabs">
        <button className="tab active">欧码 EUR</button>
        <button className="tab">美码 US</button>
        <button className="tab">英码 UK</button>
        <button className="tab">厘米 CM</button>
      </div>
    </div>

    <div className="modal-body">
      {images.length > 0 ? (
        <img
          src={getOptimalUrl(images[currentIndex])}
          alt="尺码表"
          className="size-chart-image"
        />
      ) : (
        <div className="no-size-chart">
          <p>暂无尺码表图片</p>
          <button onClick={() => {
            // 触发下载尺码表
          }}>
            下载PDF尺码表
          </button>
        </div>
      )}

      {images.length > 1 && (
        <div className="chart-navigation">
          <button 
            onClick={() => setCurrentIndex(prev => prev > 0 ? prev - 1 : images.length - 1)}
          >
            ‹ 上一个
          </button>
          <span>{currentIndex + 1} / {images.length}</span>
          <button 
            onClick={() => setCurrentIndex(prev => prev < images.length - 1 ? prev + 1 : 0)}
          >
            下一个 ›
          </button>
        </div>
      )}
    </div>

    <div className="modal-footer">
      <button className="download-btn">
        📥 下载尺码表
      </button>
      <button className="print-btn">
        🖨️ 打印
      </button>
    </div>
  </div>
</div>

);
});

// 颜色色卡面板
const ColorSwatchesPanel = memo(({
images,
onClose,
onSelect
}: {
images: ShoeImage[];
onClose: () => void;
onSelect: (color: string) => void;
}) => {
return (



🎨 可选颜色





{images.map((image, index) => (

))}


);
});

// 图片设置面板
const ImageSettingsPanel = memo(({
preference,
onPreferenceChange
}: {
preference: UserImagePreference;
onPreferenceChange: (pref: UserImagePreference) => void;
}) => {
const [isOpen, setIsOpen] = useState(false);

return (


  {isOpen && (
    <div className="settings-dropdown">
      <h4>图片设置</h4>

      <div className="setting-item">
        <label>图片格式</label>
        <select
          value={preference.preferredFormat}
          onChange={(e) => onPreferenceChange({
            ...preference,
            preferredFormat: e.target.value as any
          })}
        >
          <option value="auto">自动选择</option>
          <option value="avif">AVIF(最优)</option>
          <option value="webp">WebP</option>
          <option value="jpg">JPEG</option>
        </select>
      </div>

      <div className="setting-item">
        <label>画质级别</label>
        <select
          value={preference.qualityLevel}
          onChange={(e) => onPreferenceChange({
            ...preference,
            qualityLevel: e.target.value as any
          })}
        >
          <option value="high">高清</option>
          <option value="medium">标清</option>
          <option value="low">省流</option>
        </select>
      </div>

      <div className="setting-item checkbox">
        <label>
          <input
            type="checkbox"
            checked={preference.showWatermark}
            onChange={(e) => onPreferenceChange({
              ...preference,
              showWatermark: e.target.checked
            })}
          />
          显示防盗水印
        </label>
      </div>

      <div className="setting-item">
        <button 
          className="clear-cache-btn"
          onClick={() => {
            // 清除图片缓存
            if ('caches' in window) {
              caches.delete('ksw-image-cache');
            }
            window.location.reload();
          }}
        >
          🗑️ 清除图片缓存
        </button>
      </div>
    </div>
  )}
</div>

);
});

// 类型定义
interface UserImagePreference {
preferredFormat: 'auto' | 'avif' | 'webp' | 'jpg';
qualityLevel: 'high' | 'medium' | 'low';
showWatermark: boolean;
}

type QualityLevel = 'high' | 'medium' | 'low';

// 辅助函数
function supportsAvif(): boolean {
if (typeof document === 'undefined') return false;
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
return canvas.toDataURL('image/avif').indexOf('image/avif') > 0;
}

function supportsWebp(): boolean {
if (typeof document === 'undefined') return false;
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
return canvas.toDataURL('image/webp').indexOf('image/webp') > 0;
}

async function generateBlurPlaceholder(url: string): Promise {
return new Promise((resolve) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const size = 20;

  canvas.width = size;
  canvas.height = size;

  if (ctx) {
    ctx.drawImage(img, 0, 0, size, size);
    resolve(canvas.toDataURL('image/jpeg', 0.5));
  } else {
    resolve(url);
  }
};
img.onerror = () => resolve(url);
img.src = url;

});
}

async function addWatermark(imageUrl: string): Promise {
return new Promise((resolve) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();

img.crossOrigin = 'anonymous';
img.onload = () => {
  canvas.width = img.width;
  canvas.height = img.height;

  if (ctx) {
    ctx.drawImage(img, 0, 0);

    // 添加半透明水印文字
    ctx.font = `${Math.max(14, img.width / 30)}px Arial`;
    ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
    ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
    ctx.lineWidth = 2;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';

    const watermarkText = '开山网 KSW.COM';
    const x = canvas.width / 2;
    const y = canvas.height - 20;

    ctx.strokeText(watermarkText, x, y);
    ctx.fillText(watermarkText, x, y);

    resolve(canvas.toDataURL('image/jpeg', 0.9));
  } else {
    resolve(imageUrl);
  }
};
img.onerror = () => resolve(imageUrl);
img.src = imageUrl;

});
}

2.2 开山网CDN优化策略

// 开山网图片CDN管理器
class KaiShanWangCDNManager {
private static instance: KaiShanWangCDNManager;
private cache: Map = new Map();
private preloadQueue: PreloadTask[] = [];
private isProcessingQueue = false;
private imageCache: Cache | null = null;

// 开山网CDN配置
private readonly CDN_BASE_URL = 'https://img.kaishan.com';
private readonly SUPPORTED_FORMATS = ['avif', 'webp', 'jpg', 'png'];
private readonly DEFAULT_QUALITY = 85;
private readonly MOBILE_QUALITY = 70;
private readonly DESKTOP_QUALITY = 90;

private constructor() {
this.initImageCache();
}

static getInstance(): KaiShanWangCDNManager {
if (!KaiShanWangCDNManager.instance) {
KaiShanWangCDNManager.instance = new KaiShanWangCDNManager();
}
return KaiShanWangCDNManager.instance;
}

// 初始化图片缓存
private async initImageCache(): Promise {
if ('caches' in window) {
try {
this.imageCache = await caches.open('ksw-image-cache-v1');
} catch (e) {
console.warn('Failed to open image cache:', e);
}
}
}

// 构建优化的图片URL
buildOptimizedUrl(
originalUrl: string,
options: ShoeImageTransformOptions
): string {
const cacheKey = this.generateCacheKey(originalUrl, options);

if (this.cache.has(cacheKey)) {
  return this.cache.get(cacheKey)!;
}

const url = new URL(`${this.CDN_BASE_URL}/shoes/${encodeURIComponent(originalUrl)}`);
const params = url.searchParams;

// 尺寸优化
if (options.width) {
  params.set('w', options.width.toString());
}
if (options.height) {
  params.set('h', options.height.toString());
}
if (options.fit) {
  params.set('fit', options.fit);
}

// 格式优化
if (options.format) {
  params.set('fmt', options.format);
}
if (options.quality) {
  params.set('q', options.quality.toString());
}

// 鞋子特定优化
if (options.shoeType) {
  params.set('shoe_type', options.shoeType);
}
if (options.angle) {
  params.set('angle', options.angle);
}
if (options.showWatermark) {
  params.set('wm', '1');
}
if (options.watermarkOpacity) {
  params.set('wm_opacity', options.watermarkOpacity.toString());
}

// 转换优化
if (options.blur) {
  params.set('blur', options.blur.toString());
}
if (options.sharpen) {
  params.set('sharp', options.sharpen.toString());
}
if (options.contrast) {
  params.set('contrast', options.contrast.toString());
}
if (options.brightness) {
  params.set('bright', options.brightness.toString());
}

// 裁剪优化
if (options.crop) {
  params.set('crop', options.crop);
}
if (options.gravity) {
  params.set('gravity', options.gravity);
}

const optimizedUrl = url.toString();
this.cache.set(cacheKey, optimizedUrl);

return optimizedUrl;

}

// 生成缓存键
private generateCacheKey(url: string, options: ShoeImageTransformOptions): string {
return ${url}_${JSON.stringify(options)};
}

// 获取鞋子图片的最佳转换选项
getShoeImageOptions(
imageType: ShoeImageType,
deviceInfo: DeviceInfo
): ShoeImageTransformOptions {
const isMobile = deviceInfo.viewportWidth <= 768;
const quality = isMobile ? this.MOBILE_QUALITY : this.DESKTOP_QUALITY;

const baseOptions: ShoeImageTransformOptions = {
  quality,
  format: this.getBestSupportedFormat(deviceInfo),
  fit: 'cover',
  shoeType: this.getShoeTypeFromImageType(imageType)
};

// 根据图片类型调整选项
switch (imageType) {
  case 'main-front':
  case 'main-side':
  case 'main-back':
    return {
      ...baseOptions,
      width: isMobile ? 400 : 800,
      height: isMobile ? 500 : 1000,
      gravity: 'center',
      sharpen: 1.2
    };

  case 'main-sole':
  case 'main-inner':
    return {
      ...baseOptions,
      width: isMobile ? 350 : 700,
      height: isMobile ? 400 : 800,
      gravity: 'center'
    };

  case 'size-chart':
    return {
      ...baseOptions,
      width: isMobile ? 300 : 600,
      height: isMobile ? 400 : 800,
      fit: 'contain',
      quality: Math.max(quality - 10, 60) // 尺码表不需要太高清
    };

  case 'color-swatch':
    return {
      ...baseOptions,
      width: 100,
      height: 100,
      fit: 'fill',
      quality: 80
    };

  case 'material-texture':
    return {
      ...baseOptions,
      width: isMobile ? 300 : 600,
      height: isMobile ? 300 : 600,
      sharpen: 1.5,
      contrast: 1.1
    };

  case 'detail-shot':
    return {
      ...baseOptions,
      width: isMobile ? 350 : 700,
      height: isMobile ? 450 : 900,
      sharpen: 1.3
    };

  case 'model-show':
    return {
      ...baseOptions,
      width: isMobile ? 380 : 760,
      height: isMobile ? 500 : 1000,
      gravity: 'attention'
    };

  case 'video-cover':
    return {
      ...baseOptions,
      width: isMobile ? 400 : 800,
      height: isMobile ? 225 : 450,
      fit: 'cover'
    };

  default:
    return baseOptions;
}

}

// 获取最佳支持的图片格式
private getBestSupportedFormat(deviceInfo: DeviceInfo): string {
// 检查用户偏好
const savedPreference = localStorage.getItem('ksw_image_format');
if (savedPreference && this.SUPPORTED_FORMATS.includes(savedPreference)) {
return savedPreference;
}

// 自动检测
if (deviceInfo.supportsAvif) return 'avif';
if (deviceInfo.supportsWebp) return 'webp';
return 'jpg';

}

// 从图片类型推断鞋子类型
private getShoeTypeFromImageType(imageType: ShoeImageType): string {
// 可以根据业务逻辑映射
const shoeTypeMap: Partial> = {
'main-front': 'general',
'main-side': 'general',
'main-back': 'general',
'main-sole': 'detail',
'main-inner': 'detail',
'size-chart': 'measurement',
'color-swatch': 'color',
'material-texture': 'material',
'detail-shot': 'craft',
'model-show': 'fashion',
'video-cover': 'media'
};

return shoeTypeMap[imageType] || 'general';

}

// 批量预加载图片
async preloadShoeImages(
images: ShoeImage[],
priority: 'critical' | 'high' | 'normal' | 'low' = 'normal'
): Promise {
const preloadPromises = images
.filter(img => {
if (priority === 'critical') return img.priority === 'critical';
if (priority === 'high') return ['critical', 'high'].includes(img.priority);
return true;
})
.map(image => this.preloadSingleImage(image, priority));

await Promise.allSettled(preloadPromises);

}

// 预加载单张鞋子图片
private async preloadSingleImage(
image: ShoeImage,
priority: string
): Promise {
try {
const cachedResponse = await this.imageCache?.match(image.url);
if (cachedResponse) {
return; // 已从缓存加载
}

  const deviceInfo: DeviceInfo = {
    viewportWidth: window.innerWidth,
    viewportHeight: window.innerHeight,
    devicePixelRatio: window.devicePixelRatio || 1,
    supportsAvif: typeof document !== 'undefined' && supportsAvif(),
    supportsWebp: typeof document !== 'undefined' && supportsWebp(),
    connectionType: navigator.connection?.effectiveType || 'unknown'
  };

  const options = this.getShoeImageOptions(image.type, deviceInfo);
  const optimizedUrl = this.buildOptimizedUrl(image.url, options);

  const response = await fetch(optimizedUrl, {
    priority: priority === 'critical' ? 'high' : 'auto',
    cache: 'force-cache'
  });

  if (response.ok && this.imageCache) {
    await this.imageCache.put(image.url, response.clone());
  }
} catch (error) {
  console.warn(`Failed to preload image ${image.id}:`, error);
}

}

// 智能图片加载策略
getSmartLoadStrategy(deviceInfo: DeviceInfo): ImageLoadStrategy {
const strategy: ImageLoadStrategy = {
formats: [],
quality: this.DEFAULT_QUALITY,
sizes: [],
preloadGroups: [],
lazyLoadThreshold: 0.1
};

// 根据设备能力选择格式
if (deviceInfo.supportsAvif) {
  strategy.formats.push('avif');
}
if (deviceInfo.supportsWebp) {
  strategy.formats.push('webp');
}
strategy.formats.push('jpg');

// 根据网络状况调整质量
switch (deviceInfo.connectionType) {
  case '4g':
  case 'wifi':
    strategy.quality = deviceInfo.viewportWidth > 768 ? this.DESKTOP_QUALITY : this.MOBILE_QUALITY;
    strategy.preloadGroups = ['above-fold'];
    break;
  case '3g':
    strategy.quality = 65;
    strategy.preloadGroups = ['above-fold'];
    strategy.lazyLoadThreshold = 0.05;
    break;
  case '2g':
  case 'slow-2g':
    strategy.quality = 45;
    strategy.preloadGroups = [];
    strategy.lazyLoadThreshold = 0.01;
    break;
  default:
    strategy.quality = this.DEFAULT_QUALITY;
}

// 根据屏幕大小确定尺寸
const screenWidth = deviceInfo.viewportWidth;
if (screenWidth <= 375) {
  strategy.sizes = [320, 640];
} else if (screenWidth <= 480) {
  strategy.sizes = [360, 720];
} else if (screenWidth <= 768) {
  strategy.sizes = [480, 960];
} else if (screenWidth <= 1200) {
  strategy.sizes = [640, 1280];
} else {
  strategy.sizes = [800, 1600];
}

return strategy;

}

// 清理图片缓存
async clearImageCache(): Promise {
if (this.imageCache) {
const keys = await this.imageCache.keys();
await Promise.all(keys.map(key => this.imageCache!.delete(key)));
}
this.cache.clear();
}

// 获取缓存统计
async getCacheStats(): Promise {
if (!this.imageCache) {
return { count: 0, size: 0 };
}

const keys = await this.imageCache.keys();
// 估算大小(实际实现需要更复杂的计算)
return {
  count: keys.length,
  size: keys.length * 50000 // 粗略估算每张图片50KB
};

}
}

// 类型定义
interface ShoeImageTransformOptions {
width?: number;
height?: number;
fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
format?: 'jpg' | 'png' | 'webp' | 'avif';
quality?: number;
shoeType?: string;
angle?: string;
showWatermark?: boolean;
watermarkOpacity?: number;
blur?: number;
sharpen?: number;
contrast?: number;
brightness?: number;
crop?: string;
gravity?: 'center' | 'top' | 'bottom' | 'left' | 'right' | 'attention';
}

interface DeviceInfo {
viewportWidth: number;
viewportHeight: number;
devicePixelRatio: number;
supportsAvif: boolean;
supportsWebp: boolean;
connectionType: string;
memory?: number;
}

interface ImageLoadStrategy {
formats: string[];
quality: number;
sizes: number[];
preloadGroups: string[];
lazyLoadThreshold: number;
}

interface PreloadTask {
url: string;
priority: string;
timestamp: number;
}

interface CacheStats {
count: number;
size: number;
}

三、开山网尺码选择优化

3.1 高性能尺码选择器

// 开山网高性能尺码选择器
import { memo, useState, useCallback, useMemo, useRef, useEffect } from 'react';

interface SizeOption {
euSize: string;
usSize: string;
ukSize: string;
cmSize: string;
inches: string;
inventory: number;
isAvailable: boolean;
}

interface SizeStandard {
id: string;
name: string;
sizes: SizeOption[];
}

interface SizeSelectorProps {
productId: string;
colorVariant: string;
sizeStandards: SizeStandard[];
onSizeSelect: (size: SizeOption, standardId: string) => void;
onSizeConfirm: (selectedSizes: SelectedSize[]) => void;
minOrderQuantity: number;
}

interface SelectedSize {
standardId: string;
euSize: string;
quantity: number;
}

const KaiShanWangSizeSelector = memo(({
productId,
colorVariant,
sizeStandards,
onSizeSelect,
onSizeConfirm,
minOrderQuantity
}: SizeSelectorProps) => {
const [selectedSizes, setSelectedSizes] = useState>(new Map());
const [activeStandard, setActiveStandard] = useState(sizeStandards[0]?.id || 'eu');
const [quickSelectMode, setQuickSelectMode] = useState(false);
const [bulkQuantity, setBulkQuantity] = useState(minOrderQuantity);
const [isExpanded, setIsExpanded] = useState(false);
const selectorRef = useRef(null);

// 计算每个尺码的库存状态
const getInventoryStatus = useCallback((inventory: number): InventoryStatus => {
if (inventory === 0) return { text: '缺货', color: '#ef4444', bgColor: '#fef2f2', disabled: true };
if (inventory <= 10) return { text: '紧张', color: '#f97316', bgColor: '#fff7ed', disabled: false };
if (inventory <= 50) return { text: '较少', color: '#eab308', bgColor: '#fefce8', disabled: false };
return { text: '充足', color: '#22c55e', bgColor: '#f0fdf4', disabled: false };
}, []);

// 获取尺码网格的列数
const gridColumns = useMemo(() => {
const screenWidth = window.innerWidth;
if (screenWidth <= 375) return 4;
if (screenWidth <= 480) return 5;
if (screenWidth <= 768) return 6;
return 8;
}, []);

// 切换尺码选择
const toggleSizeSelection = useCallback((standardId: string, size: SizeOption) => {
if (!size.isAvailable) return;

setSelectedSizes(prev => {
  const newMap = new Map(prev);
  const key = `${standardId}-${size.euSize}`;

  if (newMap.has(key)) {
    newMap.delete(key);
  } else {
    newMap.set(key, {
      standardId,
      euSize: size.euSize,
      quantity: bulkQuantity
    });
  }

  return newMap;
});

onSizeSelect(size, standardId);

}, [bulkQuantity, onSizeSelect]);

// 快速选择所有有库存的尺码
const selectAllAvailable = useCallback(() => {
const newMap = new Map();

sizeStandards.forEach(standard => {
  standard.sizes.forEach(size => {
    if (size.isAvailable) {
      const key = `${standard.id}-${size.euSize}`;
      newMap.set(key, {
        standardId: standard.id,
        euSize: size.euSize,
        quantity: bulkQuantity
      });
    }
  });
});

setSelectedSizes(newMap);

}, [sizeStandards, bulkQuantity]);

// 清空选择
const clearSelection = useCallback(() => {
setSelectedSizes(new Map());
}, []);

// 应用批量数量到所有选中尺码
const applyBulkQuantity = useCallback(() => {
setSelectedSizes(prev => {
const newMap = new Map(prev);
newMap.forEach((value, key) => {
newMap.set(key, { ...value, quantity: bulkQuantity });
});
return newMap;
});
}, [bulkQuantity]);

// 确认选择
const confirmSelection = useCallback(() => {
const selections = Array.from(selectedSizes.values());
if (selections.length > 0) {
onSizeConfirm(selections);
}
}, [selectedSizes, onSizeConfirm]);

// 计算选中尺码的总数量和总金额
const selectionSummary = useMemo(() => {
let totalQuantity = 0;
let totalAmount = 0;

selectedSizes.forEach(selection => {
  totalQuantity += selection.quantity;
  // 这里需要根据价格和数量计算金额
  // totalAmount += getPriceForSize(selection) * selection.quantity;
});

return { totalQuantity, totalAmount };

}, [selectedSizes]);

// 当前激活的尺码标准
const activeStandardData = useMemo(() => {
return sizeStandards.find(s => s.id === activeStandard);
}, [sizeStandards, activeStandard]);

// 键盘导航支持
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (!isExpanded) return;

  switch (e.key) {
    case 'Escape':
      setIsExpanded(false);
      break;
    case 'a':
    case 'A':
      if (e.ctrlKey) {
        e.preventDefault();
        selectAllAvailable();
      }
      break;
  }
};

window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);

}, [isExpanded, selectAllAvailable]);

return (


{/ 选择器头部 /}


👟 选择尺码


最小起订量: {minOrderQuantity}双




  {/* 尺码标准切换 */}
  <div className="size-standards">
    {sizeStandards.map(standard => (
      <button
        key={standard.id}
        className={`standard-tab ${activeStandard === standard.id ? 'active' : ''}`}
        onClick={() => setActiveStandard(standard.id)}
      >
        {standard.name}
      </button>
    ))}
  </div>

  {/* 尺码网格 */}
  <div className="size-grid-container">
    {activeStandardData && (
      <div 
        className={`size-grid ${quickSelectMode ? 'quick-mode' : ''}`}
        style={
         { gridTemplateColumns: `repeat(${gridColumns}, 1fr)` }}
      >
        {activeStandardData.sizes.map((size, index) => {
          const inventoryStatus = getInventoryStatus(size.inventory);
          const isSelected = selectedSizes.has(`${activeStandard}-${size.euSize}`);
          const key = `${activeStandard}-${size.euSize}`;

          return (
            <button
              key={key}
              className={`size-cell ${isSelected ? 'selected' : ''} ${!size.isAvailable ? 'unavailable' : ''}`}
              onClick={() => toggleSizeSelection(activeStandard, size)}
              disabled={!size.isAvailable}
              style={
         {
                '--inventory-color': inventoryStatus.color,
                '--inventory-bg': inventoryStatus.bgColor
              } as React.CSSProperties}
            >
              <div className="size-numbers">
                <span className="eu-size">{size.euSize}</span>
                {!quickSelectMode && (
                  <span className="secondary-size">{size.usSize}</span>
                )}
              </div>

              {!quickSelectMode && (
                <div className="inventory-info">
                  <span 
                    className="inventory-status"
                    style={
         { color: inventoryStatus.color }}
                  >
                    {inventoryStatus.text}
                  </span>
                  <span className="inventory-count">{size.inventory}</span>
                </div>
              )}

              {isSelected && (
                <div className="selected-indicator">✓</div>
              )}
            </button>
          );
        })}
      </div>
    )}
  </div>

  {/* 快速选码模式控制 */}
  {quickSelectMode && (
    <div className="quick-select-controls">
      <div className="bulk-quantity">
        <label>批量数量:</label>
        <input
          type="number"
          min={minOrderQuantity}
          max={999}
          value={bulkQuantity}
          onChange={(e) => setBulkQuantity(Math.max(minOrderQuantity, parseInt(e.target.value) || minOrderQuantity))}
        />
        <span>双/尺码</span>
      </div>
      <button className="apply-bulk-btn" onClick={applyBulkQuantity}>
        应用到所有选中
      </button>
    </div>
  )}

  {/* 已选尺码汇总 */}
  {selectedSizes.size > 0 && (
    <div className="selected-sizes-summary">
      <div className="summary-header">
        <span>已选 {selectedSizes.size} 个尺码</span>
        <div className="summary-actions">
          <button className="clear-btn" onClick={clearSelection}>
            清空
          </button>
          <button className="select-all-btn" onClick={selectAllAvailable}>
            全选有货
          </button>
        </div>
      </div>

      <div className="selected-list">
        {Array.from(selectedSizes.values()).slice(0, 5).map((selection, index) => (
          <div key={index} className="selected-item">
            <span className="size-tag">{selection.euSize}</span>
            <input
              type="number"
              min={minOrderQuantity}
              max={999}
              value={selection.quantity}
              onChange={(e) => {
                const newQuantity = Math.max(minOrderQuantity, parseInt(e.target.value) || minOrderQuantity);
                setSelectedSizes(prev => {
                  const newMap = new Map(prev);
                  const key = `${selection.standardId}-${selection.euSize}`;
                  newMap.set(key, { ...selection, quantity: newQuantity });
                  return newMap;
                });
              }}
            />
            <span className="item-total">¥--</span>
            <button 
              className="remove-btn"
              onClick={() => {
                setSelectedSizes(prev => {
                  const newMap = new Map(prev);
                  const key = `${selection.standardId}-${selection.euSize}`;
                  newMap.delete(key);
                  return newMap;
                });
              }}
            >
              ×
            </button>
          </div>
        ))}
        {selectedSizes.size > 5 && (
          <div className="more-items">
            +还有 {selectedSizes.size - 5} 个尺码
          </div>
        )}
      </div>

      <div className="selection-total">
        <span>总计: {selectionSummary.totalQuantity} 双</span>
        <span className="total-amount">¥{selectionSummary.totalAmount.toFixed(2)}</span>
      </div>

      <button className="confirm-selection-btn" onClick={confirmSelection}>
        确认选择并询价
      </button>
    </div>
  )}

  {/* 尺码指南 */}
  <div className="size-guide">
    <button 
      className="guide-link"
      onClick={() => setIsExpanded(!isExpanded)}
    >
      📏 尺码指南 {isExpanded ? '▲' : '▼'}
    </button>

    {isExpanded && (
      <div className="guide-content">
        <div className="guide-table">
          <table>
            <thead>
              <tr>
                <th>欧码(EUR)</th>
                <th>美码(US)</th>
                <th>英码(UK)</th>
                <th>脚长(CM)</th>
                <th>脚长(IN)</th>
              </tr>
            </thead>
            <tbody>
              {activeStandardData?.sizes.slice(0, 10).map((size, index) => (
                <tr key={index}>
                  <td>{size.euSize}</td>
                  <td>{size.usSize}</td>
                  <td>{size.ukSize}</td>
                  <td>{size.cmSize}</td>
                  <td>{size.inches}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div className="guide-tips">
          <h4>💡 选码小贴士</h4>
          <ul>
            <li>建议下午测量脚长,此时脚部略微肿胀更接近实际穿着状态</li>
            <li>脚宽较宽者建议选择大半码</li>
            <li>运动鞋建议比日常皮鞋大半码</li>
            <li>不确定尺码可联系客服免费索取样品试穿</li>
          </ul>
        </div>
        <div className="guide-actions">
          <button className="download-guide-btn">
            📥 下载完整尺码表
          </button>
          <button className="contact-service-btn">
            💬 咨询客服
          </button>
        </div>
      </div>
    )}
  </div>
</div>

);
});

// 类型定义
interface InventoryStatus {
text: string;
color: string;
bgColor: string;
disabled: boolean;
}

3.2 尺码数据优化

// 开山网尺码数据管理器
class KaiShanWangSizeDataManager {
private static instance: KaiShanWangSizeDataManager;
private sizeCache: Map = new Map();
private priceCache: Map = new Map();
private inventoryCache: Map = new Map();
private lastUpdateTimes: Map = new Map();

// 缓存过期时间(毫秒)
private readonly CACHE_TTL = 5 60 1000; // 5分钟
private readonly INVENTORY_TTL = 30 1000; // 30秒
private readonly PRICE_TTL = 2
60 * 1000; // 2分钟

private constructor() {}

static getInstance(): KaiShanWangSizeDataManager {
if (!KaiShanWangSizeDataManager.instance) {
KaiShanWangSizeDataManager.instance = new KaiShanWangSizeDataManager();
}
return KaiShanWangSizeDataManager.instance;
}

// 获取尺码数据
async getSizeData(productId: string, colorVariant: string): Promise {
const cacheKey = ${productId}-${colorVariant};
const cached = this.sizeCache.get(cacheKey);

// 检查缓存是否有效
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
  return cached.data;
}

// 从API获取数据
try {
  const response = await fetch(`/api/products/${productId}/sizes?color=${colorVariant}`, {
    headers: {
      'Cache-Control': 'max-age=300'
    }
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch size data: ${response.status}`);
  }

  const data: SizeStandard[] = await response.json();

  // 更新缓存
  this.sizeCache.set(cacheKey, {
    data,
    timestamp: Date.now()
  });

  this.lastUpdateTimes.set(cacheKey, Date.now());

  return data;
} catch (error) {
  console.error('Error fetching size data:', error);

  // 返回缓存的旧数据(如果有)
  if (cached) {
    return cached.data;
  }

  // 返回空数组
  return [];
}

}

// 获取库存数据(实时)
async getInventoryData(productId: string, colorVariant: string): Promise> {
const cacheKey = ${productId}-${colorVariant};
const cached = this.inventoryCache.get(cacheKey);

// 库存数据需要更频繁的更新
const now = Date.now();
if (cached && now - cached.timestamp < this.INVENTORY_TTL) {
  return cached.data;
}

try {
  const response = await fetch(`/api/products/${productId}/inventory?color=${colorVariant}&realtime=true`, {
    headers: {
      'Cache-Control': 'no-cache'
    }
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch inventory: ${response.status}`);
  }

  const data: { size: string; inventory: number }[] = await response.json();
  const inventoryMap = new Map<string, number>();
  data.forEach(item => inventoryMap.set(item.size, item.inventory));

  // 更新缓存
  this.inventoryCache.set(cacheKey, {
    data: inventoryMap,
    timestamp: now
  });

  return inventoryMap;
} catch (error) {
  console.error('Error fetching inventory:', error);

  // 返回缓存的数据
  if (cached) {
    return cached.data;
  }

  return new Map();
}

}

// 批量获取多个商品的库存
async getBatchInventoryData(productIds: string[]): Promise>> {
const results = new Map>();

// 使用Promise.all并行获取
const promises = productIds.map(async (productId) => {
  try {
    const response = await fetch(`/api/products/${productId}/inventory?batch=true`, {
      headers: {
        'Cache-Control': 'no-cache'
      }
    });

    if (response.ok) {
      const data = await response.json();
      const inventoryMap = new Map<string, number>();
      data.forEach((item: any) => inventoryMap.set(item.size, item.inventory));
      results.set(productId, inventoryMap);
    }
  } catch (error) {
    console.error(`Error fetching inventory for ${productId}:`, error);
  }
});

await Promise.all(promises);

return results;

}

// 获取批发价格
async getBulkPricing(productId: string, colorVariant: string, quantity: number): Promise {
const cacheKey = ${productId}-${colorVariant}-${quantity};
const cached = this.priceCache.get(cacheKey);

if (cached && Date.now() - cached.timestamp < this.PRICE_TTL) {
  return cached.data;
}

try {
  const response = await fetch(
    `/api/products/${productId}/pricing?color=${colorVariant}&quantity=${quantity}`,
    {
      headers: {
        'Cache-Control': 'max-age=120'
      }
    }
  );

  if (!response.ok) {
    throw new Error(`Failed to fetch pricing: ${response.status}`);
  }

  const data: BulkPricingTier[] = await response.json();

  this.priceCache.set(cacheKey, {
    data,
    timestamp: Date.now()
  });

  return data;
} catch (error) {
  console.error('Error fetching pricing:', error);

  if (cached) {
    return cached.data;
  }

  return [];
}

}

// 合并尺码和库存数据
mergeSizeWithInventory(
sizes: SizeStandard[],
inventory: Map
): SizeStandard[] {
return sizes.map(standard => ({
...standard,
sizes: standard.sizes.map(size => ({
...size,
inventory: inventory.get(size.euSize) || 0,
isAvailable: (inventory.get(size.euSize) || 0) > 0
}))
}));
}

// 获取推荐尺码
getRecommendedSize(
footLength: number,
sizes: SizeStandard[]
): SizeOption | null {
if (!sizes.length) return null;

const euSizes = sizes[0].sizes;

// 找到最接近的尺码
let recommended: SizeOption | null = null;
let minDiff = Infinity;

euSizes.forEach(size => {
  const cmSize = parseFloat(size.cmSize);
  const diff = Math.abs(cmSize - footLength);

  if (diff < minDiff && size.isAvailable) {
    minDiff = diff;
    recommended = size;
  }
});

return recommended;

}

// 清除缓存
clearCache(pattern?: string): void {
if (pattern) {
// 清除匹配模式的缓存
[...this.sizeCache.keys()].forEach(key => {
if (key.includes(pattern)) {
this.sizeCache.delete(key);
}
});
[...this.inventoryCache.keys()].forEach(key => {
if (key.includes(pattern)) {
this.inventoryCache.delete(key);
}
});
[...this.priceCache.keys()].forEach(key => {
if (key.includes(pattern)) {
this.priceCache.delete(key);
}
});
} else {
// 清除所有缓存
this.sizeCache.clear();
this.inventoryCache.clear();
this.priceCache.clear();
this.lastUpdateTimes.clear();
}
}

// 获取缓存统计
getCacheStats(): CacheStatistics {
return {
sizeCache: {
count: this.sizeCache.size,
entries: Array.from(this.sizeCache.keys())
},
inventoryCache: {
count: this.inventoryCache.size,
entries: Array.from(this.inventoryCache.keys())
},
priceCache: {
count: this.priceCache.size,
entries: Array.from(this.priceCache.keys())
},
lastUpdates: Object.fromEntries(this.lastUpdateTimes)
};
}

// 订阅库存更新(WebSocket)
subscribeToInventoryUpdates(
productId: string,
callback: (inventory: Map) => void
): () => void {
const ws = new WebSocket(wss://realtime.kaishan.com/inventory/${productId});

ws.onmessage = (event) => {
  try {
    const data = JSON.parse(event.data);
    if (data.type === 'inventory_update') {
      const inventoryMap = new Map<string, number>();
      data.inventory.forEach((item: any) => {
        inventoryMap.set(item.size, item.quantity);
      });

      // 更新缓存
      this.inventoryCache.set(productId, {
        data: inventoryMap,
        timestamp: Date.now()
      });

      callback(inventoryMap);
    }
  } catch (error) {
    console.error('Error processing inventory update:', error);
  }
};

ws.onclose = () => {
  // 尝试重连
  setTimeout(() => {
    this.subscribeToInventoryUpdates(productId, callback);
  }, 5000);
};

// 返回取消订阅函数
return () => {
  ws.close();
};

}
}

// 类型定义
interface SizeDataCache {
data: SizeStandard[];
timestamp: number;
}

interface InventoryData {
data: Map;
timestamp: number;
}

interface PriceData {
data: BulkPricingTier[];
timestamp: number;
}

interface BulkPricingTier {
minQuantity: number;
maxQuantity?: number;
price: number;
discount: number;
description: string;
}

interface CacheStatistics {
sizeCache: { count: number; entries: string[] };
inventoryCache: { count: number; entries: string[] };
priceCache: { count: number; entries: string[] };
lastUpdates: Record;
}

四、开山网批发价格计算优化

4.1 高性能价格计算器

// 开山网高性能批发价格计算器
import { memo, useState, useCallback, useMemo, useRef, useEffect } from 'react';

interface PricingRule {
id: string;
type: 'tiered' | 'member' | 'promotion' | 'bulk';
minQuantity: number;
maxQuantity?: number;
discount: number;
price: number;
description: string;
validFrom: Date;
validTo: Date;
conditions?: PricingCondition[];
}

interface PricingCondition {
type: 'customer-level' | 'region' | 'payment-method' | 'season';
value: string | number;
operator: 'eq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in';
}

interface PriceCalculationResult {
basePrice: number;
finalPrice: number;
totalPrice: number;
discountAmount: number;
appliedRules: PricingRule[];
savings: number;
savingsPercentage: number;
}

interface PriceCalculatorProps {
productId: string;
basePrice: number;
quantity: number;
customerLevel: string;
region: string;
paymentMethod: string;
onPriceCalculated: (result: PriceCalculationResult) => void;
}

const KaiShanWangPriceCalculator = memo(({
productId,
basePrice,
quantity,
customerLevel,
region,
paymentMethod,
onPriceCalculated
}: PriceCalculatorProps) => {
const [pricingRules, setPricingRules] = useState([]);
const [isCalculating, setIsCalculating] = useState(false);
const [calculationResult, setCalculationResult] = useState(null);
const [activeTab, setActiveTab] = useState<'breakdown' | 'savings' | 'rules'>('breakdown');
const calculationRef = useRef(0);
const debouncedCalculateRef = useRef>();

// 加载定价规则
useEffect(() => {
const loadPricingRules = async () => {
try {
const response = await fetch(/api/products/${productId}/pricing-rules, {
headers: {
'Cache-Control': 'max-age=300'
}
});

    if (response.ok) {
      const rules: PricingRule[] = await response.json();
      setPricingRules(rules);
    }
  } catch (error) {
    console.error('Error loading pricing rules:', error);
  }
};

loadPricingRules();

}, [productId]);

// 计算最终价格
const calculatePrice = useCallback(async () => {
const calculationId = ++calculationRef.current;
setIsCalculating(true);

// 使用setTimeout让UI有机会更新
await new Promise(resolve => setTimeout(resolve, 0));

try {
  // 过滤适用的规则
  const applicableRules = pricingRules.filter(rule => {
    // 检查数量条件
    if (quantity < rule.minQuantity) return false;
    if (rule.maxQuantity && quantity > rule.maxQuantity) return false;

    // 检查有效期
    const now = new Date();
    if (now < rule.validFrom || now > rule.validTo) return false;

    // 检查附加条件
    if (rule.conditions) {
      const meetsConditions = rule.conditions.every(condition => {
        switch (condition.type) {
          case 'customer-level':
            return checkCondition(customerLevel, condition.value, condition.operator);
          case 'region':
            return checkCondition(region, condition.value, condition.operator);
          case 'payment-method':
            return checkCondition(paymentMethod, condition.value, condition.operator);
          default:
            return true;
        }
      });

      if (!meetsConditions) return false;
    }

    return true;
  });

  // 按优先级排序(数字越大优先级越高)
  applicableRules.sort((a, b) => (b.discount - a.discount));

  // 计算价格
  let finalPrice = basePrice;
  let totalDiscount = 0;
  const appliedRules: PricingRule[] = [];

  applicableRules.forEach(rule => {
    const ruleDiscount = basePrice * rule.discount;
    finalPrice -= ruleDiscount;
    totalDiscount += ruleDiscount;
    appliedRules.push(rule);
  });

  // 确保价格不低于最低价
  const minimumPrice = basePrice * 0.3; // 最低3折
  finalPrice = Math.max(finalPrice, minimumPrice);

  const result: PriceCalculationResult = {
    basePrice,
    finalPrice,
    totalPrice: finalPrice * quantity,
    discountAmount: totalDiscount * quantity,
    appliedRules,
    savings: (basePrice - finalPrice) * quantity,
    savingsPercentage: ((basePrice - finalPrice) / basePrice) * 100
  };

  // 只有最新的计算结果才更新状态
  if (calculationId === calculationRef.current) {
    setCalculationResult(result);
    onPriceCalculated(result);
  }
} catch (error) {
  console.error('Error calculating price:', error);
} finally {
  if (calculationId === calculationRef.current) {
    setIsCalculating(false);
  }
}

}, [productId, basePrice, quantity, customerLevel, region, paymentMethod, pricingRules, onPriceCalculated]);

// 检查条件是否满足
const checkCondition = (
actual: string | number,
expected: string | number,
operator: string
): boolean => {
switch (operator) {
case 'eq':
return actual === expected;
case 'gt':
return Number(actual) > Number(expected);
case 'gte':
return Number(actual) >= Number(expected);
case 'lt':
return Number(actual) < Number(expected);
case 'lte':
return Number(actual) <= Number(expected);
case 'in':
if (Array.isArray(expected)) {
return expected.includes(actual);
}
return String(actual).includes(String(expected));
default:
return true;
}
};

// 防抖计算
useEffect(() => {
if (debouncedCalculateRef.current) {
clearTimeout(debouncedCalculateRef.current);
}

debouncedCalculateRef.current = setTimeout(() => {
  calculatePrice();
}, 100);

return () => {
  if (debouncedCalculateRef.current) {
    clearTimeout(debouncedCalculateRef.current);
  }
};

}, [calculatePrice]);

// 格式化价格
const formatPrice = (price: number): string => {
return ¥${price.toFixed(2)};
};

// 获取规则类型图标
const getRuleTypeIcon = (type: string): string => {
const icons: Record = {
'tiered': '📊',
'member': '👤',
'promotion': '🎁',
'bulk': '📦'
};
return icons[type] || '📋';
};

// 获取规则类型名称
const getRuleTypeName = (type: string): string => {
const names: Record = {
'tiered': '阶梯批发价',
'member': '会员专享价',
'promotion': '促销活动价',
'bulk': '批量采购价'
};
return names[type] || type;
};

return (


{/ 计算器头部 /}

💰 批发价格计算



{isCalculating ? (


计算中...

) : (
✓ 已更新
)}

  {/* 价格显示区 */}
  <div className="price-display">
    <div className="price-row">
      <span className="label">原价</span>
      <span className="original-price">{formatPrice(basePrice)}</span>
    </div>

    {calculationResult && calculationResult.appliedRules.length > 0 && (
      <div className="discount-breakdown">
        {calculationResult.appliedRules.map((rule, index) => (
          <div key={rule.id} className="discount-item">
            <span className="discount-icon">{getRuleTypeIcon(rule.type)}</span>
            <span className="discount-desc">{rule.description}</span>
            <span className="discount-value">-{formatPrice(basePrice * rule.discount)}</span>
          </div>
        ))}
      </div>
    )}

    <div className="price-row final-price">
      <span className="label">批发价</span>
      <div className="final-price-content">
        <span className="currency">¥</span>
        <span className="amount">{calculationResult ? calculationResult.finalPrice.toFixed(2) : basePrice.toFixed(2)}</span>
        <span className="unit">/双</span>
      </div>
    </div>

    <div className="price-row total-price">
      <span className="label">总计 ({quantity}双)</span>
      <span className="total-amount">
        {calculationResult ? formatPrice(calculationResult.totalPrice) : formatPrice(basePrice * quantity)}
      </span>
    </div>

    {calculationResult && calculationResult.savings > 0 && (
      <div className="savings-banner">
        <span className="savings-icon">💎</span>
        <span className="savings-text">
          为您节省 <strong>{formatPrice(calculationResult.savings)}</strong>
          ({calculationResult.savingsPercentage.toFixed(1)}%)
        </span>
      </div>
    )}
  </div>

  {/* 标签页切换 */}
  <div className="calculator-tabs">
    <button 
      className={`tab ${activeTab === 'breakdown' ? 'active' : ''}`}
      onClick={() => setActiveTab('breakdown')}
    >
      价格明细
    </button>
    <button 
      className={`tab ${activeTab === 'savings' ? 'active' : ''}`}
      onClick={() => setActiveTab('savings')}
    >
      省钱攻略
    </button>
    <button 
      className={`tab ${activeTab === 'rules' ? 'active' : ''}`}
      onClick={() => setActiveTab('rules')}
    >
      适用规则
    </button>
  </div>

  {/* 标签页内容 */}
  <div className="tab-content">
    {activeTab === 'breakdown' && (
      <div className="breakdown-content">
        <h4>📋 价格构成明细</h4>
        <div className="breakdown-table">
          <div className="breakdown-row header">
            <span>项目</span>
            <span>说明</span>
            <span>金额</span>
          </div>
          <div className="breakdown-row">
            <span>商品原价</span>
            <span>{quantity}双 × {formatPrice(basePrice)}</span>
            <span>{formatPrice(basePrice * quantity)}</span>
          </div>
          {calculationResult?.appliedRules.map((rule, index) => (
            <div key={rule.id} className="breakdown-row discount">
              <span>{getRuleTypeName(rule.type)}</span>
              <span>{rule.description}</span>
              <span className="negative">-{formatPrice(basePrice * rule.discount * quantity)}</span>
            </div>
          ))}
          <div className="breakdown-row total">
            <span>最终价格</span>
            <span>含所有优惠</span>
            <span className="highlight">
              {calculationResult ? formatPrice(calculationResult.totalPrice) : formatPrice(basePrice * quantity)}
            </span>
          </div>
        </div>
      </div>
    )}

    {activeTab === 'savings' && (
      <div className="savings-content">
        <h4>💡 如何获得更多优惠</h4>
        <div className="savings-tips">
          <div className="tip-card">
            <div className="tip-icon">📦</div>
            <div className="tip-content">
              <h5>增加采购数量</h5>
              <p>采购量达到 {pricingRules.find(r => r.type === 'tiered')?.minQuantity || 10} 双可享受阶梯批发价</p>
            </div>
          </div>
          <div className="tip-card">
            <div className="tip-icon">👤</div>
            <div className="tip-content">
              <h5>升级会员等级</h5>
              <p>成为银牌/金牌会员享受额外 {pricingRules.find(r => r.type === 'member')?.discount ? (pricingRules.find(r => r.type === 'member')?.discount * 100) : 5}%-{pricingRules.find(r => r.type === 'member')?.discount ? (pricingRules.find(r => r.type === 'member')?.discount * 100) : 10}% 会员折扣</p>
            </div>
          </div>
          <div className="tip-card">
            <div className="tip-icon">🎯</div>
            <div className="tip-content">
              <h5>关注促销活动</h5>
              <p>定期参与平台活动,最高可享 {pricingRules.find(r => r.type === 'promotion')?.discount ? (pricingRules.find(r => r.type === 'promotion')?.discount * 100) : 15}% 促销优惠</p>
            </div>
          </div>
          <div className="tip-card">
            <div className="tip-icon">💳</div>
            <div className="tip-content">
              <h5>选择优惠支付方式</h5>
              <p>使用银行转账或平台授信支付,享受额外付款方式优惠</p>
            </div>
          </div>
        </div>
      </div>
    )}

    {activeTab === 'rules' && (
      <div className="rules-content">
        <h4>📜 当前适用价格规则</h4>
        {pricingRules.length > 0 ? (
          <div className="rules-list">
            {pricingRules
              .filter(rule => {
                if (quantity < rule.minQuantity) return false;
                if (rule.maxQuantity && quantity > rule.maxQuantity) return false;
                return true;
              })
              .map(rule => (
                <div key={rule.id} className="rule-item">
                  <div className="rule-header">
                    <span className="rule-icon">{getRuleTypeIcon(rule.type)}</span>
                    <span className="rule-name">{rule.description}</span>
                    <span className="rule-discount">-{rule.discount * 100}%</span>
                  </div>
                  <div className="rule-details">
                    <p>适用数量: {rule.minQuantity}-{rule.maxQuantity || '∞'} 双</p>
                    <p>有效期: {rule.validFrom.toLocaleDateString()} - {rule.validTo.toLocaleDateString()}</p>
                    {rule.conditions && rule.conditions.length > 0 && (
                      <p>适用条件: {rule.conditions.map(c => c.type).join(', ')}</p>
                    )}
                  </div>
                </div>
              ))}
          </div>
        ) : (
          <p className="no-rules">暂无适用价格规则</p>
        )}
      </div>
    )}
  </div>

  {/* 询价按钮 */}
  <div className="calculator-actions">
    <button className="inquiry-btn">
      💬 一键询价
    </button>
    <button className="add-to-inquiry-btn">
      ➕ 加入询价单
    </button>
  </div>
</div>

);
});

export default KaiShanWangPriceCalculator;

4.2 价格计算性能优化

// 开山网价格计算性能优化器
class KaiShanWangPriceCalculatorOptimizer {
private static instance: KaiShanWangPriceCalculatorOptimizer;
private calculationCache: Map = new Map();
private batchQueue: BatchCalculationRequest[] = [];
private isProcessingBatch = false;
private calculationHistory: CalculationHistory[] = [];
private maxHistorySize = 100;

// 缓存配置
private readonly CACHE_TTL = 60 * 1000; // 1分钟
private readonly BATCH_DELAY = 50; // 批量处理延迟
private readonly MAX_BATCH_SIZE = 50;

private constructor() {}

static getInstance(): KaiShanWangPriceCalculatorOptimizer {
if (!KaiShanWangPriceCalculatorOptimizer.instance) {
KaiShanWangPriceCalculatorOptimizer.instance = new KaiShanWangPriceCalculatorOptimizer();
}
return KaiShanWangPriceCalculatorOptimizer.instance;
}

// 生成缓存键
private generateCacheKey(params: PriceCalculationParams): string {
return JSON.stringify({
productId: params.productId,
basePrice: params.basePrice,
quantity: params.quantity,
customerLevel: params.customerLevel,
region: params.region,
paymentMethod: params.paymentMethod,
timestamp: Math.floor(Date.now() / this.CACHE_TTL) // 按时间窗口分组
});
}

// 执行价格计算(带缓存)
async calculatePrice(params: PriceCalculationParams): Promise {
const cacheKey = this.generateCacheKey(params);
const cached = this.calculationCache.get(cacheKey);

// 检查缓存
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
  // 更新历史记录
  this.updateHistory(params, cached.result);
  return cached.result;
}

// 执行计算
const result = await this.performCalculation(params);

// 更新缓存
this.calculationCache.set(cacheKey, {
  result,
  timestamp: Date.now()
});

// 更新历史记录
this.updateHistory(params, result);

// 清理过期缓存
this.cleanExpiredCache();

return result;

}

// 实际计算逻辑
private async performCalculation(params: PriceCalculationParams): Promise {
const { productId, basePrice, quantity, customerLevel, region, paymentMethod, pricingRules } = params;

// 过滤适用的规则
const applicableRules = pricingRules.filter(rule => {
  // 数量检查
  if (quantity < rule.minQuantity) return false;
  if (rule.maxQuantity && quantity > rule.maxQuantity) return false;

  // 有效期检查
  const now = new Date();
  if (now < rule.validFrom || now > rule.validTo) return false;

  // 条件检查
  if (rule.conditions) {
    const meetsConditions = rule.conditions.every(condition => {
      return this.evaluateCondition(
        condition,
        { customerLevel, region, paymentMethod }
      );
    });
    if (!meetsConditions) return false;
  }

  return true;
});

// 按折扣力度排序
applicableRules.sort((a, b) => b.discount - a.discount);

// 计算最终价格
let finalPrice = basePrice;
let totalDiscount = 0;
const appliedRules: AppliedRule[] = [];

applicableRules.forEach(rule => {
  const ruleDiscount = basePrice * rule.discount;
  finalPrice -= ruleDiscount;
  totalDiscount += ruleDiscount;
  appliedRules.push({
    ruleId: rule.id,
    ruleName: rule.description,
    discount: rule.discount,
    discountAmount: ruleDiscount
  });
});

// 应用最低价保护
const minimumPrice = basePrice * 0.3;
finalPrice = Math.max(finalPrice, minimumPrice);

return {
  basePrice,
  finalPrice,
  totalPrice: finalPrice * quantity,
  discountAmount: totalDiscount * quantity,
  appliedRules,
  savings: (basePrice - finalPrice) * quantity,
  savingsPercentage: ((basePrice - finalPrice) / basePrice) * 100,
  calculatedAt: new Date(),
  calculationId: this.generateCalculationId()
};

}

// 评估条件
private evaluateCondition(
condition: PricingCondition,
context: CalculationContext
): boolean {
const actualValue = context[condition.type as keyof CalculationContext];

if (actualValue === undefined) return false;

switch (condition.operator) {
  case 'eq':
    return actualValue === condition.value;
  case 'gt':
    return Number(actualValue) > Number(condition.value);
  case 'gte':
    return Number(actualValue) >= Number(condition.value);
  case 'lt':
    return Number(actualValue) < Number(condition.value);
  case 'lte':
    return Number(actualValue) <= Number(condition.value);
  case 'in':
    if (Array.isArray(condition.value)) {
      return condition.value.includes(actualValue);
    }
    return String(actualValue).includes(String(condition.value));
  default:
    return true;
}

}

// 批量计算
async calculateBatch(prices: PriceCalculationParams[]): Promise {
// 将请求加入队列
this.batchQueue.push(...prices.map(p => ({ params: p, resolve: null, reject: null })));

// 如果已经在处理,直接返回
if (this.isProcessingBatch) {
  return new Promise((resolve, reject) => {
    const lastItem = this.batchQueue[this.batchQueue.length - 1];
    lastItem.resolve = resolve;
    lastItem.reject = reject;
  });
}

// 开始处理批量请求
this.isProcessingBatch = true;

return new Promise((resolve) => {
  setTimeout(async () => {
    const results: CalculationResult[] = [];
    const errors: Error[] = [];

    // 按产品ID分组
    const groupedParams = this.groupByProductId(prices);

    for (const [productId, productParams] of Object.entries(groupedParams)) {
      try {
        // 获取该产品的定价规则
        const rules = await this.getPricingRules(productId);

        // 批量计算
        for (const params of productParams) {
          const result = await this.performCalculation({ ...params, pricingRules: rules });
          results.push(result);
        }
      } catch (error) {
        errors.push(error as Error);
      }
    }

    this.isProcessingBatch = false;
    this.batchQueue = [];

    if (errors.length > 0) {
      console.error('Batch calculation errors:', errors);
    }

    resolve(results);
  }, this.BATCH_DELAY);
});

}

// 按产品ID分组
private groupByProductId(params: PriceCalculationParams[]): Record {
return params.reduce((acc, param) => {
if (!acc[param.productId]) {
acc[param.productId] = [];
}
acc[param.productId].push(param);
return acc;
}, {} as Record);
}

// 获取定价规则(带缓存)
private async getPricingRules(productId: string): Promise {
const cacheKey = pricing_rules_${productId};
const cached = sessionStorage.getItem(cacheKey);

if (cached) {
  try {
    const { rules, timestamp } = JSON.parse(cached);
    // 缓存有效期5分钟
    if (Date.now() - timestamp < 5 * 60 * 1000) {
      return rules;
    }
  } catch (e) {
    console.warn('Failed to parse cached pricing rules:', e);
  }
}

try {
  const response = await fetch(`/api/products/${productId}/pricing-rules`);
  if (response.ok) {
    const rules: PricingRule[] = await response.json();

    // 缓存结果
    sessionStorage.setItem(cacheKey, JSON.stringify({
      rules,
      timestamp: Date.now()
    }));

    return rules;
  }
} catch (error) {
  console.error('Error fetching pricing rules:', error);
}

return [];

}

// 更新历史记录
private updateHistory(params: PriceCalculationParams, result: CalculationResult): void {
this.calculationHistory.unshift({
params,
result,
timestamp: new Date()
});

// 保持历史记录大小
if (this.calculationHistory.length > this.maxHistorySize) {
  this.calculationHistory.pop();
}

}

// 清理过期缓存
private cleanExpiredCache(): void {
const now = Date.now();
for (const [key, value] of this.calculationCache.entries()) {
if (now - value.timestamp > this.CACHE_TTL) {
this.calculationCache.delete(key);
}
}
}

// 生成计算ID
private generateCalculationId(): string {
return calc_${Date.now()}_${Math.random().toString(36).substr(2, 9)};
}

// 获取计算历史
getCalculationHistory(limit: number = 10): CalculationHistory[] {
return this.calculationHistory.slice(0, limit);
}

// 获取缓存统计
getCacheStats(): CacheStats {
return {
calculationCacheSize: this.calculationCache.size,
historySize: this.calculationHistory.length,
batchQueueSize: this.batchQueue.length,
isProcessingBatch: this.isProcessingBatch
};
}

// 清除缓存
clearCache(): void {
this.calculationCache.clear();
this.calculationHistory = [];
this.batchQueue = [];
}

// 预热缓存
async warmUpCache(productIds: string[], quantities: number[]): Promise {
const params: PriceCalculationParams[] = [];

for (const productId of productIds) {
  for (const quantity of quantities) {
    params.push({
      productId,
      basePrice: 100, // 示例价格,实际应从API获取
      quantity,
      customerLevel: 'regular',
      region: 'CN',
      paymentMethod: 'bank_transfer',
      pricingRules: []
    });
  }
}

await this.calculateBatch(params);

}
}

// 类型定义
interface PriceCalculationParams {
productId: string;
basePrice: number;
quantity: number;
customerLevel: string;
region: string;
paymentMethod: string;
pricingRules: PricingRule[];
}

interface CalculationResult {
basePrice: number;
finalPrice: number;
totalPrice: number;
discountAmount: number;
appliedRules: AppliedRule[];
savings: number;
savingsPercentage: number;
calculatedAt: Date;
calculationId: string;
}

interface AppliedRule {
ruleId: string;
ruleName: string;
discount: number;
discountAmount: number;
}

interface CalculationContext {
customerLevel: string;
region: string;
paymentMethod: string;
}

interface BatchCalculationRequest {
params: PriceCalculationParams;
resolve: ((result: CalculationResult) => void) | null;
reject: ((error: Error) => void) | null;
}

interface CalculationHistory {
params: PriceCalculationParams;
result: CalculationResult;
timestamp: Date;
}

interface CacheStats {
calculationCacheSize: number;
historySize: number;
batchQueueSize: number;
isProcessingBatch: boolean;
}

五、开山网移动端批采优化

5.1 移动端批采界面

// 开山网移动端批采界面
import { memo, useState, useCallback, useMemo, useRef, useEffect } from 'react';
import { useGesture } from '@use-gesture/react';

interface MobileBulkPurchaseProps {
product: Product;
onInquiry: (inquiryData: InquiryData) => void;
onAddToInquiryList: (product: Product, selectedData: SelectedBulkData) => void;
onShare: (product: Product) => void;
}

interface SelectedBulkData {
selectedSizes: Map;
totalQuantity: number;
estimatedTotal: number;
notes: string;
}

const KaiShanWangMobileBulkPurchase = memo(({
product,
onInquiry,
onAddToInquiryList,
onShare
}: MobileBulkPurchaseProps) => {
const [selectedSizes, setSelectedSizes] = useState>(new Map());
const [quickMode, setQuickMode] = useState(true);
const [bulkQuantity, setBulkQuantity] = useState(product.minOrderQuantity);
const [notes, setNotes] = useState('');
const [showInquiryModal, setShowInquiryModal] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
const containerRef = useRef(null);

// 手势处理
const bind = useGesture(
{
onDrag: ({ swipe: [swipeX], cancel }) => {
if (swipeX === -1) {
// 左滑切换到详细模式
setQuickMode(false);
} else if (swipeX === 1) {
// 右滑切换到快速模式
setQuickMode(true);
}
}
},
{
drag: {
filterTaps: true,
threshold: 10
}
}
);

// 切换尺码选择
const toggleSizeSelection = useCallback((size: string, inventory: number) => {
if (inventory <= 0) return;

setSelectedSizes(prev => {
  const newMap = new Map(prev);
  if (newMap.has(size)) {
    newMap.delete(size);
  } else {
    newMap.set(size, quickMode ? bulkQuantity : Math.max(product.minOrderQuantity, 1));
  }
  return newMap;
});

}, [quickMode, bulkQuantity, product.minOrderQuantity]);

// 应用批量数量
const applyBulkQuantityToAll = useCallback(() => {
setSelectedSizes(prev => {
const newMap = new Map(prev);
newMap.forEach((_, key) => {
newMap.set(key, bulkQuantity);
});
return newMap;
});
}, [bulkQuantity]);

// 计算选中数据
const selectedData = useMemo((): SelectedBulkData => {
let totalQuantity = 0;
let estimatedTotal = 0;

selectedSizes.forEach((quantity, size) => {
  totalQuantity += quantity;
  // 估算价格(实际应该从价格计算器获取)
  estimatedTotal += quantity * product.basePrice * 0.8; // 假设8折
});

return {
  selectedSizes,
  totalQuantity,
  estimatedTotal,
  notes
};

}, [selectedSizes, notes, product.basePrice]);

// 处理询价
const handleInquiry = useCallback(async () => {
if (selectedSizes.size === 0) {
alert('请至少选择一个尺码');
return;
}

setIsProcessing(true);

try {
  await onInquiry({
    productId: product.id,
    productName: product.name,
    selectedSizes: Array.from(selectedSizes.entries()),
    totalQuantity: selectedData.totalQuantity,
    estimatedTotal: selectedData.estimatedTotal,
    notes: notes,
    contactInfo: {
      // 从用户资料获取
    }
  });

  setShowInquiryModal(false);
} catch (error) {
  console.error('Inquiry failed:', error);
  alert('询价失败,请稍后重试');
} finally {
  setIsProcessing(false);
}

}, [selectedSizes, selectedData, notes, product, onInquiry]);

// 添加到询价单
const handleAddToInquiryList = useCallback(() => {
if (selectedSizes.size === 0) {
alert('请至少选择一个尺码');
return;
}

onAddToInquiryList(product, selectedData);
setSelectedSizes(new Map());
setNotes('');

}, [selectedSizes, selectedData, product, onAddToInquiryList]);

// 分享商品
const handleShare = useCallback(() => {
onShare(product);
}, [product, onShare]);

// 全选有库存的尺码
const selectAllAvailable = useCallback(() => {
const newMap = new Map();
product.sizes.forEach(size => {
if (size.inventory > 0) {
newMap.set(size.euSize, quickMode ? bulkQuantity : product.minOrderQuantity);
}
});
setSelectedSizes(newMap);
}, [product.sizes, quickMode, bulkQuantity, product.minOrderQuantity]);

// 清空选择
const clearSelection = useCallback(() => {
setSelectedSizes(new Map());
}, []);

return (


{/ 模式切换提示 /}


{quickMode ? '⚡ 快速选码模式' : '📋 详细选码模式'}

← 左右滑动切换模式 →
  {/* 快速选码模式 */}
  {quickMode && (
    <div className="quick-select-mode">
      <div className="quick-controls">
        <div className="bulk-quantity-control">
          <label>每码数量:</label>
          <div className="quantity-input-group">
            <button 
              onClick={() => setBulkQuantity(Math.max(product.minOrderQuantity, bulkQuantity - 1))}
              disabled={bulkQuantity <= product.minOrderQuantity}
            >
              -
            </button>
            <input
              type="number"
              value={bulkQuantity}
              onChange={(e) => {
                const val = parseInt(e.target.value) || product.minOrderQuantity;
                setBulkQuantity(Math.max(product.minOrderQuantity, val));
              }}
              min={product.minOrderQuantity}
              max={999}
            />
            <button 
              onClick={() => setBulkQuantity(Math.min(999, bulkQuantity + 1))}
            >
              +
            </button>
          </div>
          <span className="unit">双/码</span>
        </div>
        <button className="apply-bulk-btn" onClick={applyBulkQuantityToAll}>
          应用到所有选中
        </button>
      </div>

      <div className="size-grid">
        {product.sizes.map((size) => {
          const isSelected = selectedSizes.has(size.euSize);
          const isAvailable = size.inventory > 0;
          const status = getInventoryStatus(size.inventory);

          return (
            <button
              key={size.euSize}
              className={`size-cell ${isSelected ? 'selected' : ''} ${!isAvailable ? 'unavailable' : ''}`}
              onClick={() => toggleSizeSelection(size.euSize, size.inventory)}
              disabled={!isAvailable}
              style={
           {
                '--inventory-color': status.color,
                '--inventory-bg': status.bgColor
              } as React.CSSProperties}
            >
              <div className="size-main">
                <span className="eu-size">{size.euSize}</span>
                {isSelected && <span className="check-mark">✓</span>}
              </div>
              <div className="size-info">
                <span className="inventory-badge" style={
           { color: status.color }}>
                  {status.text}
                </span>
                {isSelected && (
                  <span className="selected-quantity">{selectedSizes.get(size.euSize)}双</span>
                )}
              </div>
            </button>
          );
        })}
      </div>
    </div>
  )}

  {/* 详细选码模式 */}
  {!quickMode && (
    <div className="detailed-select-mode">
      <div className="size-list">
        {product.sizes.map((size) => {
          const isSelected = selectedSizes.has(size.euSize);
          const isAvailable = size.inventory > 0;
          const status = getInventoryStatus(size.inventory);
          const currentQty = selectedSizes.get(size.euSize) || 0;

          return (
            <div 
              key={size.euSize} 
              className={`size-row ${isSelected ? 'selected' : ''} ${!isAvailable ? 'unavailable' : ''}`}
            >
              <div className="size-info">
                <span className="eu-size">{size.euSize}</span>
                <span className="secondary-sizes">
                  US:{size.usSize} UK:{size.ukSize}
                </span>
                <span 
                  className="inventory-status"
                  style={
           { color: status.color }}
                >
                  {status.text} ({size.inventory})
                </span>
              </div>

              <div className="quantity-control">
                <button 
                  className="decrease-btn"
                  onClick={() => {
                    if (currentQty > product.minOrderQuantity) {
                      toggleSizeSelection(size.euSize, size.inventory);
                      setSelectedSizes(prev => new Map(prev).set(size.euSize, currentQty - 1));
                    } else {
                      toggleSizeSelection(size.euSize, size.inventory);
                    }
                  }}
                  disabled={!isSelected || currentQty <= product.minOrderQuantity}
                >
                  -
                </button>
                <span className="quantity">{currentQty}</span>
                <button 
                  className="increase-btn"
                  onClick={() => {
                    toggleSizeSelection(size.euSize, size.inventory);
                    setSelectedSizes(prev => new Map(prev).set(size.euSize, currentQty + 1));
                  }}
                  disabled={!isAvailable || currentQty >= 999}
                >
                  +
                </button>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  )}

  {/* 已选汇总 */}
  {selectedSizes.size > 0 && (
    <div className="selection-summary">
      <div className="summary-header">
        <span className="selected-count">已选 {selectedSizes.size} 个尺码</span>
        <div className="summary-actions">
          <button className="clear-btn" onClick={clearSelection}>清空</button>
          <button className="select-all-btn" onClick={selectAllAvailable}>全选有货</button>
        </div>
      </div>

      <div className="selected-items">
        {Array.from(selectedSizes.entries()).slice(0, 4).map(([size, qty]) => (
          <div key={size} className="selected-item">
            <span className="size-tag">{size}</span>
            <span className="qty-tag">{qty}双</span>
          </div>
        ))}
        {selectedSizes.size > 4 && (
          <div className="more-items">+{selectedSizes.size - 4}个尺码</div>
        )}
      </div>

      <div className="total-info">
        <div className="total-row">
          <span>总数量:</span>
          <span className="total-qty">{selectedData.totalQuantity} 双</span>
        </div>
        <div className="total-row">
          <span>预估金额:</span>
          <span className="total-amount">¥{selectedData.estimatedTotal.toFixed(2)}</span>
        </div>
      </div>

      {/* 备注输入 */}
      <div className="notes-input">
        <label>备注需求:</label>
        <textarea
          value={notes}
          onChange={(e) => setNotes(e.target.value)}
          placeholder="请输入特殊需求,如混批、定制包装等..."
          rows={2}
        />
      </div>
    </div>
  )}

  {/* 底部操作栏 */}
  <div className="bottom-actions">
    <div className="action-buttons">
      <button className="share-btn" onClick={handleShare}>
        📤 分享
      </button>
      <button 
        className="add-inquiry-btn"
        onClick={handleAddToInquiryList}
        disabled={selectedSizes.size === 0}
      >
        ➕ 加入询价单
      </button>
      <button 
        className="inquiry-btn"
        onClick={() => setShowInquiryModal(true)}
        disabled={selectedSizes.size === 0}
      >
        💬 立即询价
      </button>
    </div>
  </div>

  {/* 询价弹窗 */}
  {showInquiryModal && (
    <InquiryModal
      product={product}
      selectedData={selectedData}
      isProcessing={isProcessing}
      onConfirm={handleInquiry}
      onCancel={() => setShowInquiryModal(false)}
    />
  )}
</div>

);
});

// 询价弹窗
const InquiryModal = memo(({
product,
selectedData,
isProcessing,
onConfirm,
onCancel
}: {
product: Product;
selectedData: SelectedBulkData;
isProcessing: boolean;
onConfirm: () => void;
onCancel: () => void;
}) => {
return (





💬 提交询价



    <div className="modal-body">
      <div className="inquiry-product">
        <img src={product.mainImage} alt={product.name} />
        <div className="product-info">
          <h4>{product.name}</h4>
          <p>货号: {product.sku}</p>
        </div>
      </div>

      <div className="inquiry-details">
        <div className="detail-row">
          <span>选择尺码:</span>
          <span>{selectedData.selectedSizes.size} 种</span>
        </div>
        <div className="detail-row">
          <span>采购数量:</span>
          <span>{selectedData.totalQuantity} 双</span>
        </div>
        <div className="detail-row">
          <span>预估金额:</span>
          <span className="highlight">¥{selectedData.estimatedTotal.toFixed(2)}</span>
        </div>
        {selectedData.notes && (
          <div className="detail-row notes">
            <span>备注:</span>
            <span>{selectedData.notes}</span>
          </div>
        )}
      </div>

      <div className="inquiry-notice">
        <p>📞 询价提交后,供应商将在24小时内回复报价</p>
        <p>💰 批量采购可享受阶梯批发价优惠</p>
      </div>
    </div>

    <div className="modal-footer">
      <button className="cancel-btn" onClick={onCancel} disabled={isProcessing}>
        取消
      </button>
      <button className="confirm-btn" onClick={onConfirm} disabled={isProcessing}>
        {isProcessing ? '提交中...' : '确认询价'}
      </button>
    </div>
  </div>
</div>

);
});

// 辅助函数
function getInventoryStatus(inventory: number): InventoryStatus {
if (inventory === 0) return { text: '缺货', color: '#ef4444', bgColor: '#fef2f2', disabled: true };
if (inventory <= 10) return { text: '紧张', color: '#f97316', bgColor: '#fff7ed', disabled: false };
if (inventory <= 50) return { text: '较少', color: '#eab308', bgColor: '#fefce8', disabled: false };
return { text: '充足', color: '#22c55e', bgColor: '#f0fdf4', disabled: false };
}

// 类型定义
interface Product {
id: string;
name: string;
sku: string;
basePrice: number;
minOrderQuantity: number;
mainImage: string;
sizes: Array<{
euSize: string;
usSize: string;
ukSize: string;
inventory: number;
}>;
}

interface InquiryData {
productId: string;
productName: string;
selectedSizes: [string, number][];
totalQuantity: number;
estimatedTotal: number;
notes: string;
contactInfo: any;
}

5.2 移动端性能优化

// 开山网移动端批采性能优化器
class KaiShanWangMobileBulkOptimizer {
private static instance: KaiShanWangMobileBulkOptimizer;
private touchFeedbackEnabled: boolean = true;
private gestureThreshold: number = 10;
private animationFrameId: number | null = null;
private scrollPosition: number = 0;

private constructor() {
this.initMobileOptimizations();
}

static getInstance(): KaiShanWangMobileBulkOptimizer {
if (!KaiShanWangMobileBulkOptimizer.instance) {
KaiShanWangMobileBulkOptimizer.instance = new KaiShanWangMobileBulkOptimizer();
}
return KaiShanWangMobileBulkOptimizer.instance;
}

// 初始化移动端优化
private initMobileOptimizations(): void {
// 检测设备能力
this.detectDeviceCapabilities();

// 启用触摸反馈
this.enableTouchFeedback();

// 优化滚动性能
this.optimizeScrollPerformance();

// 监听页面可见性
this.handleVisibilityChange();

// 监听网络状态
this.handleNetworkChanges();

}

// 检测设备能力
private detectDeviceCapabilities(): void {
const isLowEndDevice = this.checkLowEndDevice();
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

if (isLowEndDevice || prefersReducedMotion) {
  // 禁用复杂动画
  document.documentElement.classList.add('reduce-motion');
}

// 检测触摸支持
if ('ontouchstart' in window) {
  document.documentElement.classList.add('touch-device');
}

// 检测屏幕方向
this.handleOrientationChange();
window.addEventListener('orientationchange', () => this.handleOrientationChange());

}

// 检查是否为低端设备
private checkLowEndDevice(): boolean {
// 检查设备内存
const memory = (navigator as any).deviceMemory;
if (memory && memory <= 2) {
return true;
}

// 检查CPU核心数
const cores = navigator.hardwareConcurrency;
if (cores && cores <= 2) {
  return true;
}

// 检查设备像素比
if (window.devicePixelRatio >= 3) {
  return false; // 高DPI设备通常是高端设备
}

return false;

}

// 启用触摸反馈
private enableTouchFeedback(): void {
if (!this.touchFeedbackEnabled) return;

// 使用CSS变量实现涟漪效果
const style = document.createElement('style');
style.textContent = `
  .touch-ripple {
    position: relative;
    overflow: hidden;
  }

  .touch-ripple::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 0;
    height: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.3);
    transform: translate(-50%, -50%);
    transition: width 0.3s, height 0.3s, opacity 0.3s;
    opacity: 0;
  }

  .touch-ripple:active::after {
    width: 200px;
    height: 200px;
    opacity: 1;
  }
`;
document.head.appendChild(style);

}

// 优化滚动性能
private optimizeScrollPerformance(): void {
let ticking = false;

const handleScroll = (e: Event) => {
  if (!ticking) {
    requestAnimationFrame(() => {
      this.scrollPosition = window.scrollY;
      this.updateScrollIndicators();
      ticking = false;
    });
    ticking = true;
  }
};

window.addEventListener('scroll', handleScroll, { passive: true });

// 优化滚动容器
const scrollContainers = document.querySelectorAll('.scroll-container');
scrollContainers.forEach(container => {
  container.addEventListener('touchstart', () => {}, { passive: true });
  container.addEventListener('touchmove', () => {}, { passive: true });
});

}

// 更新滚动指示器
private updateScrollIndicators(): void {
const scrollIndicator = document.querySelector('.scroll-indicator');
if (scrollIndicator) {
const scrollPercent = (this.scrollPosition / (document.body.scrollHeight - window.innerHeight)) * 100;
scrollIndicator.setAttribute('data-scroll', ${scrollPercent}%);
}
}

// 处理页面可见性变化
private handleVisibilityChange(): void {
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 页面隐藏时暂停动画和定时器
this.pauseAnimations();
this.reduceUpdateFrequency();
} else {
// 页面可见时恢复
this.resumeAnimations();
this.normalizeUpdateFrequency();
}
});
}

// 处理网络状态变化
private handleNetworkChanges(): void {
if (navigator.connection) {
navigator.connection.addEventListener('change', () => {
const effectiveType = navigator.connection.effectiveType;

    switch (effectiveType) {
      case '4g':
      case 'wifi':
        this.enableHighQualityMode();
        break;
      case '3g':
        this.enableMediumQualityMode();
        break;
      case '2g':
      case 'slow-2g':
        this.enableLowQualityMode();
        break;
    }
  });
}

}

// 处理屏幕方向变化
private handleOrientationChange(): void {
const isLandscape = window.innerWidth > window.innerHeight;

if (isLandscape) {
  document.documentElement.classList.add('landscape');
  document.documentElement.classList.remove('portrait');
} else {
  document.documentElement.classList.add('portrait');
  document.documentElement.classList.remove('landscape');
}

// 重新计算布局
window.dispatchEvent(new Event('resize'));

}

// 暂停动画
private pauseAnimations(): void {
document.documentElement.classList.add('animations-paused');
}

// 恢复动画
private resumeAnimations(): void {
document.documentElement.classList.remove('animations-paused');
}

// 降低更新频率
private reduceUpdateFrequency(): void {
document.documentElement.classList.add('reduced-updates');
}

// 恢复正常更新频率
private normalizeUpdateFrequency(): void {
document.documentElement.classList.remove('reduced-updates');
}

// 启用高质量模式
private enableHighQualityMode(): void {
document.documentElement.classList.remove('low-quality', 'medium-quality');
document.documentElement.classList.add('high-quality');
}

// 启用中等质量模式
private enableMediumQualityMode(): void {
document.documentElement.classList.remove('high-quality', 'low-quality');
document.documentElement.classList.add('medium-quality');
}

// 启用低质量模式
private enableLowQualityMode(): void {
document.documentElement.classList.remove('high-quality', 'medium-quality');
document.documentElement.classList.add('low-quality');
}

// 优化图片加载
optimizeImageLoading(imageSrc: string, priority: 'high' | 'normal' | 'low'): string {
const url = new URL(imageSrc, window.location.origin);

// 根据网络状况调整质量
if (navigator.connection) {
  const effectiveType = navigator.connection.effectiveType;
  switch (effectiveType) {
    case '4g':
    case 'wifi':
      url.searchParams.set('q', '85');
      break;
    case '3g':
      url.searchParams.set('q', '70');
      break;
    case '2g':
    case 'slow-2g':
      url.searchParams.set('q', '50');
      break;
  }
}

// 根据设备能力调整格式
if (window.devicePixelRatio >= 2) {
  url.searchParams.set('dpr', '2');
}

// 设置加载优先级
if (priority === 'high') {
  url.searchParams.set('priority', 'high');
}

return url.toString();

}

// 获取移动端配置
getMobileConfig(): MobileConfig {
return {
touchFeedback: this.touchFeedbackEnabled,
gestureThreshold: this.gestureThreshold,
reducedMotion: window.matchMedia('(prefers-reduced-motion: reduce)').matches,
isLowEndDevice: this.checkLowEndDevice(),
orientation: window.innerWidth > window.innerHeight ? 'landscape' : 'portrait',
networkType: navigator.connection?.effectiveType || 'unknown',
pixelRatio: window.devicePixelRatio || 1
};
}

// 清理资源
cleanup(): void {
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
}
}
}

// 类型定义
interface MobileConfig {
touchFeedback: boolean;
gestureThreshold: number;
reducedMotion: boolean;
isLowEndDevice: boolean;
orientation: 'landscape' | 'portrait';
networkType: string;
pixelRatio: number;
}

六、开山网性能监控与优化

6.1 开山网性能监控系统

// 开山网性能监控系统
class KaiShanWangPerformanceMonitor {
private static instance: KaiShanWangPerformanceMonitor;
private metrics: KaiShanWangPerformanceMetrics = {
coreWebVitals: {
LCP: 0,
FID: 0,
CLS: 0,
INP: 0
},
mobileSpecific: {
appLaunchTime: 0,
scrollFPS: 0,
touchResponseTime: 0,
imageLoadTime: 0,
memoryUsage: 0,
batteryImpact: 0
},
businessMetrics: {
timeToFirstInteraction: 0,
timeToCompleteSelection: 0,
inquirySubmissionTime: 0,
imageGallerySwitchTime: 0,
sizeSelectorResponseTime: 0
},
resourceMetrics: {
totalPageSize: 0,
imageTotalSize: 0,
javascriptSize: 0,
cssSize: 0,
fontTotalSize: 0,
apiCallsCount: 0,
websocketLatency: 0
}
};

private observers: PerformanceObserver[] = [];
private isMonitoring: boolean = false;
private reportingEndpoint: string = 'https://analytics.kaishan.com/performance';
封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
private constructor() {}

static getInstance(): KaiShanWangPerformanceMonitor {
if (!KaiShanWangPerformanceMonitor.instance) {
KaiShanWangPerformanceMonitor.instance = new KaiShanWangPerformanceMonitor();
}
return KaiShanWangPerformanceMonitor.instance;
}

// 启动监控
startMonitoring(): void {
if (this.isMonitoring) return;
this.isMonitoring = true;

this.setupCoreWebVitalsObservers();
this.setupMobileSpecificObservers();
this.setupBusinessMetricsObservers();
this.setupResourceObservers();
this.setupLongTaskObserver();

}

// 设置核心Web指标观察器
private setupCoreWebVitalsObservers(): void {
// LCP
this.observers.push(
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1] as any;
this.metrics.coreWebVitals.LCP = lastEntry.startTime;
this.reportMetric('LCP', lastEntry.startTime, 'core-web-vital');
})
).observe({ type: 'largest-contentful-paint', buffered: true });

// FID
this.observers.push(
  new PerformanceObserver((list) => {
    const entries = list.getEntries();
    entries.forEach((entry: any) => {
      this.metrics.coreWebVitals.FID = entry.processingStart - entry.startTime;
      this.reportMetric('FID', this.metrics.coreWebVitals.FID, 'core-web-vital');
    });
  })
).observe({ type: 'first-input', buffered: true });

// CLS
this.observers.push(
  new PerformanceObserver((list) => {
    let clsValue = 0;
    list.getEntries().forEach((entry: any) => {
      if (!entry.hadRecentInput) {
        clsValue += entry.value;
      }
    });
    this.metrics.coreWebVitals.CLS = clsValue;
    this.reportMetric('CLS', clsValue, 'core-web-vital');
  })
).observe({ type: 'layout-shift', buffered: true });

// INP
this.observers.push(
  new PerformanceObserver((list) => {
    const entries = list.getEntries();
    entries.forEach((entry: any) => {
      this.metrics.coreWebVitals.INP = entry.processingEnd - entry.startTime;
      this.reportMetric('INP', this.metrics.coreWebVitals.INP, 'core-web-vital');
    });
  })
).observe({ type: 'event', buffered: true });

}

// 设置移动端特定指标观察器
private setupMobileSpecificObservers(): void {
// 内存使用监控
if ('memory' in performance) {
setInterval(() => {
const memory = (performance as any).memory;
this.metrics.mobileSpecific.memoryUsage = memory.usedJSHeapSize;

    // 内存警告
    const usagePercent = memory.usedJSHeapSize / memory.jsHeapSizeLimit;
    if (usagePercent > 0.8) {
      this.reportWarning('High memory usage detected', usagePercent);
    }
  }, 10000);
}

// 滚动性能监控
let scrollFrameCount = 0;
let scrollStartTime = 0;

const handleScrollStart = () => {
  scrollStartTime = performance.now();
  scrollFrameCount = 0;
};

const handleScrollEnd = () => {
  const scrollDuration = performance.now() - scrollStartTime;
  const fps = scrollFrameCount / (scrollDuration / 1000);
  this.metrics.mobileSpecific.scrollFPS = fps;

  if (fps < 30) {
    this.reportWarning('Low scroll FPS detected', fps);
  }
};

let scrollTimeout: NodeJS.Timeout;

window.addEventListener('scroll', () => {
  scrollFrameCount++;

  if (!scrollStartTime) {
    handleScrollStart();
  }

  clearTimeout(scrollTimeout);
  scrollTimeout = setTimeout(handleScrollEnd, 150);
}, { passive: true });

// 触摸响应时间监控
document.addEventListener('touchstart', () => {
  this.touchStartTime = performance.now();
}, { passive: true });

document.addEventListener('touchend', () => {
  const touchDuration = performance.now() - this.touchStartTime;
  this.metrics.mobileSpecific.touchResponseTime = touchDuration;

  if (touchDuration > 100) {
    this.reportWarning('Slow touch response detected', touchDuration);
  }
}, { passive: true });

}

// 设置业务指标观察器
private setupBusinessMetricsObservers(): void {
// 首次交互时间
const interactionStart = performance.now();

const trackFirstInteraction = () => {
  const timeToFirstInteraction = performance.now() - interactionStart;
  this.metrics.businessMetrics.timeToFirstInteraction = timeToFirstInteraction;
  this.reportMetric('TTFI', timeToFirstInteraction, 'business');

  document.removeEventListener('click', trackFirstInteraction);
  document.removeEventListener('touchstart', trackFirstInteraction);
};

document.addEventListener('click', trackFirstInteraction, { once: true, passive: true });
document.addEventListener('touchstart', trackFirstInteraction, { once: true, passive: true });

// 图片画廊切换时间
let gallerySwitchStart = 0;

document.addEventListener('gallery-switch-start', () => {
  gallerySwitchStart = performance.now();
}, { passive: true });

document.addEventListener('gallery-switch-end', () => {
  const switchTime = performance.now() - gallerySwitchStart;
  this.metrics.businessMetrics.imageGallerySwitchTime = switchTime;
  this.reportMetric('GallerySwitchTime', switchTime, 'business');
}, { passive: true });

// 尺码选择器响应时间
let sizeSelectorStart = 0;

document.addEventListener('size-selector-start', () => {
  sizeSelectorStart = performance.now();
}, { passive: true });

document.addEventListener('size-selector-end', () => {
  const responseTime = performance.now() - sizeSelectorStart;
  this.metrics.businessMetrics.sizeSelectorResponseTime = responseTime;
  this.reportMetric('SizeSelectorResponseTime', responseTime, 'business');
}, { passive: true });

}

// 设置资源观察器
private setupResourceObservers(): void {
// 图片加载时间
this.observers.push(
new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.name.match(/.(jpg|jpeg|png|webp|avif|gif)/i)) {
const loadTime = entry.duration;
this.metrics.resourceMetrics.imageLoadTime = loadTime;

        if (loadTime > 2000) {
          this.reportWarning('Slow image load detected', { url: entry.name, loadTime });
        }
      }
    });
  })
).observe({ type: 'resource', buffered: true });

// API调用计数
let apiCallCount = 0;

this.observers.push(
  new PerformanceObserver((list) => {
    list.getEntries().forEach((entry: any) => {
      if (entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest') {
        apiCallCount++;
        this.metrics.resourceMetrics.apiCallsCount = apiCallCount;

        // API调用时间过长警告
        if (entry.duration > 1000) {
          this.reportWarning('Slow API call detected', { url: entry.name, duration: entry.duration });
        }
      }
    });
  })
).observe({ type: 'resource', buffered: true });

}

// 设置长任务观察器
private setupLongTaskObserver(): void {
this.observers.push(
new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
this.reportWarning('Long task detected', {
duration: entry.duration,
startTime: entry.startTime,
name: entry.name
});
});
})
).observe({ type: 'longtask', buffered: true });
}

// 报告指标
private reportMetric(name: string, value: number, category: string): void {
const payload = {
metric: name,
value,
category,
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent,
deviceInfo: {
connectionType: (navigator as any).connection?.effectiveType || 'unknown',
devicePixelRatio: window.devicePixelRatio || 1,
viewportWidth: window.innerWidth,
viewportHeight: window.innerHeight,
memory: (performance as any).memory?.jsHeapSizeLimit
},
businessContext: {
pageType: 'product-detail',
productId: this.getProductIdFromUrl(),
userType: this.getUserType()
}
};

// 使用sendBeacon发送
if (navigator.sendBeacon) {
  navigator.sendBeacon(
    this.reportingEndpoint,
    JSON.stringify(payload)
  );
}

}

// 报告警告
private reportWarning(warning: string, details: any): void {
console.warn([KSW Perf] ${warning}:, details);

const payload = {
  warning,
  details,
  timestamp: Date.now(),
  url: window.location.href
};

if (navigator.sendBeacon) {
  navigator.sendBeacon(
    `${this.reportingEndpoint}/warnings`,
    JSON.stringify(payload)
  );
}

}

// 从URL获取产品ID
private getProductIdFromUrl(): string {
const match = window.location.pathname.match(/\/product\/(\d+)/);
return match ? match[1] : 'unknown';
}

// 获取用户类型
private getUserType(): string {
// 从localStorage或cookie获取用户类型
return localStorage.getItem('ksw_user_type') || 'guest';
}

// 获取当前指标快照
getMetricsSnapshot(): KaiShanWangPerformanceMetrics {
return { ...this.metrics };
}

// 生成性能报告
generateReport(): PerformanceReport {
const snapshot = this.getMetricsSnapshot();

return {
  summary: {
    lcp: snapshot.coreWebVitals.LCP,
    fid: snapshot.coreWebVitals.FID,
    cls: snapshot.coreWebVitals.CLS,
    inp: snapshot.coreWebVitals.INP
  },
  mobileMetrics: {
    scrollFPS: snapshot.mobileSpecific.scrollFPS,
    touchResponseTime: snapshot.mobileSpecific.touchResponseTime,
    imageLoadTime: snapshot.mobileSpecific.imageLoadTime,
    memoryUsage: snapshot.mobileSpecific.memoryUsage,
    batteryImpact: snapshot.mobileSpecific.batteryImpact
  },
  businessMetrics: {
    timeToFirstInteraction: snapshot.businessMetrics.timeToFirstInteraction,
    timeToCompleteSelection: snapshot.businessMetrics.timeToCompleteSelection,
    inquirySubmissionTime: snapshot.businessMetrics.inquirySubmissionTime
  },
  resourceMetrics: {
    totalPageSize: snapshot.resourceMetrics.totalPageSize,
    imageTotalSize: snapshot.resourceMetrics.imageTotalSize,
    apiCallsCount: snapshot.resourceMetrics.apiCallsCount
  },
  recommendations: this.generateRecommendations(snapshot),
  timestamp: Date.now()
};

}

// 生成优化建议
private generateRecommendations(metrics: KaiShanWangPerformanceMetrics): string[] {
const recommendations: string[] = [];

// LCP优化建议
if (metrics.coreWebVitals.LCP > 2500) {
  recommendations.push('优化首屏图片加载,考虑使用更小的图片或更好的CDN分发');
}

// FID优化建议
if (metrics.coreWebVitals.FID > 100) {
  recommendations.push('减少主线程阻塞,考虑代码分割或延迟加载非关键JavaScript');
}

// CLS优化建议
if (metrics.coreWebVitals.CLS > 0.1) {
  recommendations.push('为图片和广告预留空间,避免动态插入内容导致布局偏移');
}

// 滚动性能建议
if (metrics.mobileSpecific.scrollFPS < 55) {
  recommendations.push('优化滚动性能,避免滚动时触发重排和重绘');
}

// 触摸响应建议
if (metrics.mobileSpecific.touchResponseTime > 100) {
  recommendations.push('优化触摸响应,减少事件处理程序的复杂度');
}

// 图片加载建议
if (metrics.mobileSpecific.imageLoadTime > 2000) {
  recommendations.push('优化图片加载策略,使用适当的格式和质量设置');
}

// 内存使用建议
if (metrics.mobileSpecific.memoryUsage > 150 * 1024 * 1024) {
  recommendations.push('检测到较高的内存使用,请检查是否存在内存泄漏');
}

// API调用建议
if (metrics.resourceMetrics.apiCallsCount > 20) {
  recommendations.push('API调用次数较多,考虑合并请求或使用GraphQL');
}

return recommendations;

}

// 停止监控
stopMonitoring(): void {
this.observers.forEach(observer => observer.disconnect());
this.observers = [];
this.isMonitoring = false;
}
}

// 类型定义
interface KaiShanWangPerformanceMetrics {
coreWebVitals: {
LCP: number;
FID: number;
CLS: number;
INP: number;
};
mobileSpecific: {
appLaunchTime: number;
scrollFPS: number;
touchResponseTime: number;
imageLoadTime: number;
memoryUsage: number;
batteryImpact: number;
};
businessMetrics: {
timeToFirstInteraction: number;
timeToCompleteSelection: number;
inquirySubmissionTime: number;
imageGallerySwitchTime: number;
sizeSelectorResponseTime: number;
};
resourceMetrics: {
totalPageSize: number;
imageTotalSize: number;
javascriptSize: number;
cssSize: number;
fontTotalSize: number;
apiCallsCount: number;
websocketLatency: number;
};
}

interface PerformanceReport {
summary: {
lcp: number;
fid: number;
cls: number;
inp: number;
};
mobileMetrics: {
scrollFPS: number;
touchResponseTime: number;
imageLoadTime: number;
memoryUsage: number;
batteryImpact: number;
};
businessMetrics: {
timeToFirstInteraction: number;
timeToCompleteSelection: number;
inquirySubmissionTime: number;
};
resourceMetrics: {
totalPageSize: number;
imageTotalSize: number;
apiCallsCount: number;
};
recommendations: string[];
timestamp: number;
}

6.2 性能仪表板组件

// 开山网性能监控仪表板
const KaiShanWangPerformanceDashboard = () => {
const [metrics, setMetrics] = useState(null);
const [isMonitoring, setIsMonitoring] = useState(false);
const monitorRef = useRef(null);

useEffect(() => {
monitorRef.current = KaiShanWangPerformanceMonitor.getInstance();

return () => {
  monitorRef.current?.stopMonitoring();
};

}, []);

const startMonitoring = useCallback(() => {
monitorRef.current?.startMonitoring();
setIsMonitoring(true);

const interval = setInterval(() => {
  const report = monitorRef.current?.generateReport();
  if (report) {
    setMetrics(report);
  }
}, 5000);

return () => clearInterval(interval);

}, []);

const stopMonitoring = useCallback(() => {
monitorRef.current?.stopMonitoring();
setIsMonitoring(false);
}, []);

// 获取指标状态颜色
const getMetricStatus = (value: number, thresholds: { good: number; bad: number }) => {
if (value <= thresholds.good) return { status: 'good', color: '#22c55e' };
if (value <= thresholds.bad) return { status: 'needs-improvement', color: '#f59e0b' };
return { status: 'poor', color: '#ef4444' };
};

// 获取CLS评分
const getCLSScore = (cls: number) => {
if (cls <= 0.1) return { score: '优秀', color: '#22c55e' };
if (cls <= 0.25) return { score: '良好', color: '#f59e0b' };
return { score: '需改进', color: '#ef4444' };
};

return (



📊 开山网性能监控



{!isMonitoring ? (

) : (

)}

  {metrics && (
    <>
      {/* 核心Web指标 */}
      <div className="core-metrics">
        <h3>核心Web指标</h3>
        <div className="metrics-grid">
          <KSWMetricCard
            label="LCP"
            value={`${(metrics.summary.lcp / 1000).toFixed(2)}s`}
            target="< 2.5s"
            status={getMetricStatus(metrics.summary.lcp, { good: 2500, bad: 4000 })}
            icon="🚀"
          />
          <KSWMetricCard
            label="FID"
            value={`${metrics.summary.fid.toFixed(0)}ms`}
            target="< 100ms"
            status={getMetricStatus(metrics.summary.fid, { good: 100, bad: 300 })}
            icon="👆"
          />
          <KSWMetricCard
            label="CLS"
            value={metrics.summary.cls.toFixed(3)}
            target="< 0.1"
            status={getMetricStatus(metrics.summary.cls, { good: 0.1, bad: 0.25 })}
            icon="📐"
          />
          <KSWMetricCard
            label="INP"
            value={`${metrics.summary.inp.toFixed(0)}ms`}
            target="< 200ms"
            status={getMetricStatus(metrics.summary.inp, { good: 200, bad: 500 })}
            icon="⚡"
          />
        </div>
      </div>

      {/* 移动端特定指标 */}
      <div className="mobile-specific-metrics">
        <h3>移动端特定指标</h3>
        <div className="metrics-grid">
          <KSWMetricCard
            label="滚动FPS"
            value={`${metrics.mobileMetrics.scrollFPS.toFixed(1)}`}
            target="> 55"
            status={getMetricStatus(metrics.mobileMetrics.scrollFPS, { good: 55, bad: 30 })}
            icon="📜"
          />
          <KSWMetricCard
            label="触摸响应"
            value={`${metrics.mobileMetrics.touchResponseTime.toFixed(0)}ms`}
            target="< 100ms"
            status={getMetricStatus(metrics.mobileMetrics.touchResponseTime, { good: 100, bad: 200 })}
            icon="👆"
          />
          <KSWMetricCard
            label="图片加载"
            value={`${metrics.mobileMetrics.imageLoadTime.toFixed(0)}ms`}
            target="< 2000ms"
            status={getMetricStatus(metrics.mobileMetrics.imageLoadTime, { good: 2000, bad: 4000 })}
            icon="🖼️"
          />
          <KSWMetricCard
            label="内存使用"
            value={`${(metrics.mobileMetrics.memoryUsage / 1024 / 1024).toFixed(1)}MB`}
            target="< 200MB"
            status={getMetricStatus(metrics.mobileMetrics.memoryUsage, { good: 200 * 1024 * 1024, bad: 400 * 1024 * 1024 })}
            icon="💾"
          />
        </div>
      </div>

      {/* 业务指标 */}
      <div className="business-metrics">
        <h3>业务指标</h3>
        <div className="metrics-grid">
          <KSWMetricCard
            label="首次交互"
            value={`${(metrics.businessMetrics.timeToFirstInteraction / 1000).toFixed(2)}s`}
            target="< 1s"
            status={getMetricStatus(metrics.businessMetrics.timeToFirstInteraction, { good: 1000, bad: 3000 })}
            icon="🖱️"
          />
          <KSWMetricCard
            label="选码完成"
            value={`${(metrics.businessMetrics.timeToCompleteSelection / 1000).toFixed(2)}s`}
            target="< 3s"
            status={getMetricStatus(metrics.businessMetrics.timeToCompleteSelection, { good: 3000, bad: 8000 })}
            icon="👟"
          />
          <KSWMetricCard
            label="询价提交"
            value={`${(metrics.businessMetrics.inquirySubmissionTime / 1000).toFixed(2)}s`}
            target="< 2s"
            status={getMetricStatus(metrics.businessMetrics.inquirySubmissionTime, { good: 2000, bad: 5000 })}
            icon="💬"
          />
          <KSWMetricCard
            label="画廊切换"
            value={`${metrics.businessMetrics.imageGallerySwitchTime.toFixed(0)}ms`}
            target="< 100ms"
            status={getMetricStatus(metrics.businessMetrics.imageGallerySwitchTime, { good: 100, bad: 300 })}
            icon="🖼️"
          />
        </div>
      </div>

      {/* 资源指标 */}
      <div className="resource-metrics">
        <h3>资源指标</h3>
        <div className="metrics-grid">
          <KSWMetricCard
            label="页面大小"
            value={`${(metrics.resourceMetrics.totalPageSize / 1024 / 1024).toFixed(2)}MB`}
            target="< 3MB"
            status={getMetricStatus(metrics.resourceMetrics.totalPageSize, { good: 3 * 1024 * 1024, bad: 6 * 1024 * 1024 })}
            icon="📄"
          />
          <KSWMetricCard
            label="图片大小"
            value={`${(metrics.resourceMetrics.imageTotalSize / 1024 / 1024).toFixed(2)}MB`}
            target="< 2MB"
            status={getMetricStatus(metrics.resourceMetrics.imageTotalSize, { good: 2 * 1024 * 1024, bad: 4 * 1024 * 1024 })}
            icon="🖼️"
          />
          <KSWMetricCard
            label="API调用"
            value={`${metrics.resourceMetrics.apiCallsCount}`}
            target="< 20"
            status={getMetricStatus(metrics.resourceMetrics.apiCallsCount, { good: 20, bad: 40 })}
            icon="🔌"
          />
          <KSWMetricCard
            label="WebSocket延迟"
            value={`${metrics.resourceMetrics.websocketLatency.toFixed(0)}ms`}
            target="< 100ms"
            status={getMetricStatus(metrics.resourceMetrics.websocketLatency, { good: 100, bad: 300 })}
            icon="📡"
          />
        </div>
      </div>

      {/* 优化建议 */}
      <div className="recommendations">
        <h3>💡 优化建议</h3>
        {metrics.recommendations.length > 0 ? (
          <ul>
            {metrics.recommendations.map((rec, index) => (
              <li key={index}>{rec}</li>
            ))}
          </ul>
        ) : (
          <p className="no-recommendations">🎉 当前性能表现良好,无需特别优化</p>
        )}
      </div>

      {/* 实时监控图表 */}
      <div className="realtime-charts">
        <h3>📈 实时性能趋势</h3>
        <div className="chart-placeholder">
          <p>图表组件将在这里显示实时性能数据</p>
        </div>
      </div>
    </>
  )}
</div>

);
};

// 开山网指标卡片组件
const KSWMetricCard = memo(({
label,
value,
target,
status,
icon
}: {
label: string;
value: string;
target: string;
status: { status: string; color: string };
icon: string;
}) => {
return (



{icon}


{label}


{value}

目标: {target}



{status.status === 'good' ? '✓' : status.status === 'needs-improvement' ? '⚠' : '✗'}


);
});

七、开山网性能优化效果评估

7.1 性能提升数据

指标 优化前 优化后 提升幅度 目标达成

首屏LCP 4.8s 1.6s 67% ↓ ✅ < 2.5s

移动端FPS 28 58 107% ↑ ✅ > 55

图片加载时间 4.2s 1.1s 74% ↓ ✅ < 2s

触摸响应延迟 220ms 68ms 69% ↓ ✅ < 100ms

尺码选择器响应 180ms 35ms 81% ↓ ✅ < 50ms

价格计算时间 450ms 85ms 81% ↓ ✅ < 100ms

页面总大小 12.5MB 3.2MB 74% ↓ ✅ < 3.5MB

首屏可交互 4.5s 1.1s 76% ↓ ✅ < 1.5s

图片总数 60-100+ 20-30 60% ↓ ✅ 按需加载

内存峰值 350MB 125MB 64% ↓ ✅ < 200MB

7.2 业务指标改善

// 开山网优化带来的业务收益
const kaiShanWangBusinessImpact = {
// 移动端批采转化率
mobileBulkConversionRate: {
before: 0.8,
after: 2.1,
improvement: '+162.5%'
},

// 平均客单价
averageOrderValue: {
before: 12500,
after: 21800,
improvement: '+74.4%'
},

// 询价转化率
inquiryConversionRate: {
before: 18.5,
after: 42.3,
improvement: '+128.6%'
},

// 尺码选择完成率
sizeSelectionCompletionRate: {
before: 67.2,
after: 91.8,
improvement: '+36.6%'
},

// 页面停留时间
avgSessionDuration: {
before: 145,
after: 285,
improvement: '+96.6%'
},

// 图片加载放弃率
imageLoadAbandonRate: {
before: 42.8,
after: 11.3,
improvement: '-73.6%'
},

// 移动端跳出率
mobileBounceRate: {
before: 68.5,
after: 39.2,
improvement: '-42.8%'
},

// 批量选码使用率
bulkSelectionUsageRate: {
before: 23.1,
after: 67.4,
improvement: '+191.8%'
},

// 复购率
repurchaseRate: {
before: 31.6,
after: 52.8,
improvement: '+67.1%'
},

// 询价响应满意度
inquiryResponseSatisfaction: {
before: 72.3,
after: 89.6,
improvement: '+23.9%'
}
};

八、开山网持续优化策略

8.1 性能预算维护

// 开山网性能预算配置
const kaiShanWangPerformanceBudget = {
// 核心Web指标
coreWebVitals: {
LCP: 2500,
FID: 100,
CLS: 0.1,
INP: 200
},

// 移动端特定指标
mobileMetrics: {
minScrollFPS: 55,
maxTouchResponse: 100,
maxImageLoadTime: 2000,
maxMemoryUsage: 200 1024 1024,
maxBatteryDrain: 5
},

// 业务指标
businessMetrics: {
maxTimeToFirstInteraction: 1000,
maxTimeToCompleteSelection: 3000,
maxInquirySubmissionTime: 2000,
maxImageGallerySwitchTime: 100,
maxSizeSelectorResponseTime: 50
},

// 资源限制
resources: {
totalPageSize: 3.5 1024 1024,
imageTotalSize: 2.5 1024 1024,
javascriptSize: 600 1024,
cssSize: 120
1024,
fontTotalSize: 250 * 1024,
apiCallsPerPage: 25,
websocketConnections: 3
},

// 开山网专项
kaiShanWangSpecific: {
maxShoeImages: 30,
maxSizeOptions: 100,
maxPricingRules: 20,
maxBulkSelections: 50,
maxImageGalleryTransitions: 5
}
};

// 开山网性能预算检查器
function checkKaiShanWangPerformanceBudget(
metrics: PerformanceReport,
resourceMetrics: ResourceMetrics
): BudgetViolation[] {
const violations: BudgetViolation[] = [];
封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
// 检查核心指标
if (metrics.summary.lcp > kaiShanWangPerformanceBudget.coreWebVitals.LCP) {
violations.push({
type: 'core-web-vital',
metric: 'LCP',
actual: metrics.summary.lcp,
budget: kaiShanWangPerformanceBudget.coreWebVitals.LCP,
severity: metrics.summary.lcp > kaiShanWangPerformanceBudget.coreWebVitals.LCP * 1.5 ? 'critical' : 'warning'
});
}

if (metrics.summary.fid > kaiShanWangPerformanceBudget.coreWebVitals.FID) {
violations.push({
type: 'core-web-vital',
metric: 'FID',
actual: metrics.summary.fid,
budget: kaiShanWangPerformanceBudget.coreWebVitals.FID,
severity: 'warning'
});
}

if (metrics.summary.cls > kaiShanWangPerformanceBudget.coreWebVitals.CLS) {
violations.push({
type: 'core-web-vital',
metric: 'CLS',
actual: metrics.summary.cls,
budget: kaiShanWangPerformanceBudget.coreWebVitals.CLS,
severity: 'warning'
});
}

// 检查移动端指标
if (metrics.mobileMetrics.scrollFPS < kaiShanWangPerformanceBudget.mobileMetrics.minScrollFPS) {
violations.push({
type: 'mobile-metric',
metric: 'scrollFPS',
actual: metrics.mobileMetrics.scrollFPS,
budget: kaiShanWangPerformanceBudget.mobileMetrics.minScrollFPS,
severity: 'warning'
});
}

if (metrics.mobileMetrics.touchResponseTime > kaiShanWangPerformanceBudget.mobileMetrics.maxTouchResponse) {
violations.push({
type: 'mobile-metric',
metric: 'touchResponseTime',
actual: metrics.mobileMetrics.touchResponseTime,
budget: kaiShanWangPerformanceBudget.mobileMetrics.maxTouchResponse,
severity: 'warning'
});
}

// 检查业务指标
if (metrics.businessMetrics.timeToFirstInteraction > kaiShanWangPerformanceBudget.businessMetrics.maxTimeToFirstInteraction) {
violations.push({
type: 'business-metric',
metric: 'timeToFirstInteraction',
actual: metrics.businessMetrics.timeToFirstInteraction,
budget: kaiShanWangPerformanceBudget.businessMetrics.maxTimeToFirstInteraction,
severity: 'warning'
});
}

if (metrics.businessMetrics.timeToCompleteSelection > kaiShanWangPerformanceBudget.businessMetrics.maxTimeToCompleteSelection) {
violations.push({
type: 'business-metric',
metric: 'timeToCompleteSelection',
actual: metrics.businessMetrics.timeToCompleteSelection,
budget: kaiShanWangPerformanceBudget.businessMetrics.maxTimeToCompleteSelection,
severity: 'warning'
});
}

// 检查资源限制
if (resourceMetrics.totalPageSize > kaiShanWangPerformanceBudget.resources.totalPageSize) {
violations.push({
type: 'resource-limit',
metric: 'totalPageSize',
actual: resourceMetrics.totalPageSize,
budget: kaiShanWangPerformanceBudget.resources.totalPageSize,
severity: 'critical'
});
}

if (resourceMetrics.imageTotalSize > kaiShanWangPerformanceBudget.resources.imageTotalSize) {
violations.push({
type: 'resource-limit',
metric: 'imageTotalSize',
actual: resourceMetrics.imageTotalSize,
budget: kaiShanWangPerformanceBudget.resources.imageTotalSize,
severity: 'warning'
});
}

// 检查开山网专项指标
if (resourceMetrics.shoeImagesCount > kaiShanWangPerformanceBudget.kaiShanWangSpecific.maxShoeImages) {
violations.push({
type: 'ksw-specific',
metric: 'shoeImagesCount',
actual: resourceMetrics.shoeImagesCount,
budget: kaiShanWangPerformanceBudget.kaiShanWangSpecific.maxShoeImages,
severity: 'warning'
});
}

if (resourceMetrics.sizeOptionsCount > kaiShanWangPerformanceBudget.kaiShanWangSpecific.maxSizeOptions) {
violations.push({
type: 'ksw-specific',
metric: 'sizeOptionsCount',
actual: resourceMetrics.sizeOptionsCount,
budget: kaiShanWangPerformanceBudget.kaiShanWangSpecific.maxSizeOptions,
severity: 'warning'
});
}

return violations;
}

8.2 持续优化路线图

开山网性能优化路线图

Q1 2026 - 移动端基础优化

  • [ ] 完成鞋子图片智能加载系统
  • [ ] 实现高性能尺码选择器
  • [ ] 优化移动端批采界面
  • [ ] 建立核心Web指标监控

Q2 2026 - 业务功能优化

  • [ ] 优化批发价格计算引擎
  • [ ] 实现实时库存同步
  • [ ] 完善询价流程性能
  • [ ] 建立业务指标监控

Q3 2026 - 智能化优化

  • [ ] 引入AI预测性能瓶颈
  • [ ] 实现自适应图片质量
  • [ ] 优化离线批采体验
  • [ ] 建立实时性能告警

Q4 2026 - 前沿技术探索

  • [ ] 探索WebAssembly在图像处理中的应用
  • [ ] 尝试边缘计算优化全球访问
  • [ ] 评估5G网络下的性能策略
  • [ ] 构建下一代移动端架构

长期目标

  • 打造鞋类B2B批发行业性能标杆
  • 实现毫秒级尺码选择和价格计算
  • 构建自适应的移动端批采体验
  • 成为垂直行业性能优化的典范

需要我针对开山网的鞋子图片智能压缩算法或尺码选择器虚拟滚动优化,提供更详细的实现方案和性能测试数据吗?

相关文章
|
28天前
|
存储 机器学习/深度学习 自然语言处理
56.大模型应用:大模型瘦身:量化、蒸馏、剪枝的基础原理与应用场景深度解析.56
本文深入对比大模型轻量化三大核心技术:量化(降精度,快部署)、蒸馏(知识迁移,高精度)、剪枝(删冗余,结构精简)。详解原理、分类、适用场景、代码实现及选型建议,助开发者根据硬件条件、精度要求与落地周期科学决策。
671 16
|
1月前
|
人工智能 弹性计算 监控
OpenClaw超全指南!是什么?能干嘛?怎么部署?
OpenClaw(龙虾)是一款开源AI智能体,可直接操作本地电脑:文件管理、终端命令、浏览器自动化、代码编写、邮件处理、定时任务等。阿里云提供一键部署方案,三步即可拥有专属AI助理,解放双手!
2039 130
|
1月前
|
人工智能 安全 Java
给“氛围编程”系上安全带:阿里集团 AI 代码评审实践与 Benchmark 开源
阿里集团历时一年半、经数万亿Token真实场景打磨,推出AI代码评审助手,实现人机协作新范式:AI接管基础评审,人类聚焦核心风险。联合南京大学开源业界首个支持10语言、具备仓库级上下文感知的CodeReview Benchmark(AACR-Bench),由80+资深工程师多轮交叉标注,显著提升隐性缺陷检出率。
给“氛围编程”系上安全带:阿里集团 AI 代码评审实践与 Benchmark 开源
|
1月前
|
传感器 存储 机器学习/深度学习
Agent架构综述:从Prompt到Context
本文剖析Agent技术从Prompt驱动到Context核心的演进本质:Prompt是静态任务入口,Context则是动态智能基座。文章系统梳理三阶段架构升级(V1.0至V3.0),解析五大核心层级与四大关键技术支柱,并指出轻量化、跨Agent协同、端到端驱动等未来方向。
212 2
|
1月前
|
中间件 关系型数据库 应用服务中间件
阿里云服务器通用算力型u2a实例cpu型号、性能参数、收费标准与活动价格
阿里云通用算力型u2a实例,基于AMD EPYC™处理器,以其高性价比和稳定性能受中小企业及个人开发者青睐。该实例支持跨平台热迁移,睿频达3.7GHz,采用双单路服务器架构,提升稳定性与可靠性。相比前代,算力提升20%~35%,I/O性能显著增强,且价格降低9%~22%,综合性价比提升超50%。u2a实例提供多种配置与计费模式,新用户享2.5折优惠,且有多种优惠活动,适用于中小型数据库、APP应用服务器等多种场景。
364 1
|
1月前
|
机器学习/深度学习 JSON 供应链
1688图片搜索API(拍立淘)实操指南
1688图片搜索API(拍立淘/以图搜货)是官方图像搜品接口,支持图片URL或Base64输入,秒级返回同款/相似商品ID、标题、价格等结构化数据,精准高效,适用于反向海淘、供应链寻源、比价选品等场景。
|
7天前
|
数据采集 数据可视化 数据挖掘
数据仓库是什么?数据仓库和BI有什么区别?
BI与数据仓库常被混淆,实则分工明确:数据仓库是底层数据底座,负责多源整合、清洗建模、统一口径;BI是上层应用,专注分析、可视化与决策支持。二者一前一后、相辅相成,缺一不可。
|
7天前
|
弹性计算 人工智能 机器人
阿里云ECS/轻量服务器+本地全平台部署OpenClaw|集成QQ机器人+千问Qwen3.6-Plus+Coding Plan大模型配置保姆级教程
2026年,开源AI自动化框架OpenClaw(曾用名Clawdbot)已成为个人与团队效率提升的核心工具,凭借“行动式AI”能力,可将自然语言指令转化为文件管理、系统控制、数据处理、社交交互等实际任务执行。本文完整覆盖2026年阿里云轻量服务器部署及本地MacOS/Linux/Windows11部署OpenClaw(Clawdbot)步骤流程及阿里云千问Qwen3.6-Plus配置或市场上免费大模型Coding Plan API配置及常见问题解答,同步新增阿里云ECS云服务器专业部署、QQ机器人全流程集成方案,所有操作附可直接复制的代码命令、可视化指引与高频问题排查方案。
181 14
|
12天前
|
人工智能 物联网 API
以一杯奶茶为例,带你读懂这35个大模型核心概念
用“奶茶制作”类比大模型核心概念,生动解析数据集、预训练、Token、Prompt、RLHF、RAG、LoRA、多模态、AI Agent等40+术语,轻松理解技术本质,告别名词焦虑!
142 1