|
|
@@ -0,0 +1,567 @@
|
|
|
+import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
+import type { CSSProperties } from 'react';
|
|
|
+import { useNavigate, useSearchParams } from 'react-router-dom';
|
|
|
+import { useTranslation } from 'react-i18next';
|
|
|
+import { px2vmin, px2vw } from '@/utils/viewport';
|
|
|
+import { getOssUrl } from '@/utils/oss';
|
|
|
+import { wrapTrackedClick } from '@/utils/tracking';
|
|
|
+import { onScreenResize, updateTooSmallFlag } from '@/utils/screenSize';
|
|
|
+import { STOOL_LAYOUT } from '@/constants/chatbot';
|
|
|
+import { updateUserUIState } from '@/utils/api';
|
|
|
+import { getStorage, getUserId, setCurrentAvatarId as persistAvatarIdToStorage, STORAGE_KEYS } from '@/utils/storage';
|
|
|
+import '@/styles/chatbot-fix.css';
|
|
|
+
|
|
|
+const treesImageUrl = getOssUrl('init3.png');
|
|
|
+const stoolImageUrl = getOssUrl('stool.png');
|
|
|
+const backButtonIcon = getOssUrl('backbutn-icon.png');
|
|
|
+const lumiOutfitImg = getOssUrl('lumi-outfit-img.png');
|
|
|
+const headCapImg = getOssUrl('head-cap.png');
|
|
|
+const wenhaoImg = getOssUrl('wenhao.png');
|
|
|
+const secondaryDefaultButton = getOssUrl('secondary-default.png');
|
|
|
+/** 与 Profile Lumi 背包「家具 / 服装」卡片一致 */
|
|
|
+const chairBagImg = getOssUrl('Chair.png');
|
|
|
+const glovesBagImg = getOssUrl('Gloves.png');
|
|
|
+
|
|
|
+/** 与 ChatBotPage 一致:默认形象(无帽) / 注册赠送(戴帽) */
|
|
|
+const AVATAR_ID_DEFAULT = 'avatar_default';
|
|
|
+const AVATAR_ID_REGISTERED = 'avatar_registered_cap';
|
|
|
+
|
|
|
+/** 与 ChatBotPage 中 getTreesImageStyle 一致(/chatbot 默认前景,含窗户与树木) */
|
|
|
+const getTreesImageStyle = (): CSSProperties => ({
|
|
|
+ width: '100%',
|
|
|
+ height: '100%',
|
|
|
+ top: 0,
|
|
|
+ left: 0,
|
|
|
+ objectFit: 'cover',
|
|
|
+ zIndex: 1,
|
|
|
+ opacity: 1,
|
|
|
+});
|
|
|
+
|
|
|
+export const LumiOutfitsPage = () => {
|
|
|
+ const navigate = useNavigate();
|
|
|
+ const [searchParams] = useSearchParams();
|
|
|
+ const { t } = useTranslation('common');
|
|
|
+ const { t: tProfile } = useTranslation('profile');
|
|
|
+
|
|
|
+ const [currentAvatarId, setCurrentAvatarId] = useState<string | null>(() =>
|
|
|
+ getStorage(STORAGE_KEYS.CURRENT_AVATAR_ID),
|
|
|
+ );
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ updateTooSmallFlag();
|
|
|
+ return onScreenResize(() => {
|
|
|
+ updateTooSmallFlag();
|
|
|
+ });
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const sync = () => {
|
|
|
+ setCurrentAvatarId(getStorage(STORAGE_KEYS.CURRENT_AVATAR_ID));
|
|
|
+ };
|
|
|
+ const onStorage = (e: StorageEvent) => {
|
|
|
+ if (e.key === STORAGE_KEYS.CURRENT_AVATAR_ID) {
|
|
|
+ sync();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ window.addEventListener('storage', onStorage);
|
|
|
+ window.addEventListener('focus', sync);
|
|
|
+ return () => {
|
|
|
+ window.removeEventListener('storage', onStorage);
|
|
|
+ window.removeEventListener('focus', sync);
|
|
|
+ };
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const capCardBorderStyle = useMemo((): CSSProperties => {
|
|
|
+ if (currentAvatarId === AVATAR_ID_REGISTERED) {
|
|
|
+ return { border: '1PX solid #BF9DF8' };
|
|
|
+ }
|
|
|
+ return { border: 'none' };
|
|
|
+ }, [currentAvatarId]);
|
|
|
+
|
|
|
+ const handleBack = useCallback(() => {
|
|
|
+ navigate(-1);
|
|
|
+ }, [navigate]);
|
|
|
+
|
|
|
+ const onBackClick = useMemo(
|
|
|
+ () => wrapTrackedClick('lumi_outfits', 'back', handleBack),
|
|
|
+ [handleBack],
|
|
|
+ );
|
|
|
+
|
|
|
+ const handleChatNow = useCallback(() => {
|
|
|
+ navigate('/chatbot');
|
|
|
+ }, [navigate]);
|
|
|
+
|
|
|
+ const onChatNowClick = useMemo(
|
|
|
+ () => wrapTrackedClick('lumi_outfits', 'chat_now', handleChatNow),
|
|
|
+ [handleChatNow],
|
|
|
+ );
|
|
|
+
|
|
|
+ const handleToggleCapOutfit = useCallback(() => {
|
|
|
+ const next =
|
|
|
+ currentAvatarId === AVATAR_ID_REGISTERED ? AVATAR_ID_DEFAULT : AVATAR_ID_REGISTERED;
|
|
|
+ persistAvatarIdToStorage(next);
|
|
|
+ setCurrentAvatarId(next);
|
|
|
+ const userId = getUserId();
|
|
|
+ if (userId) {
|
|
|
+ void updateUserUIState(userId, { current_avatar_id: next }).catch(() => {
|
|
|
+ // 本地已更新,后端同步失败不阻断切换
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, [currentAvatarId]);
|
|
|
+
|
|
|
+ const onCapCardClick = useMemo(
|
|
|
+ () => wrapTrackedClick('lumi_outfits', 'cap_outfit_card', handleToggleCapOutfit),
|
|
|
+ [handleToggleCapOutfit],
|
|
|
+ );
|
|
|
+
|
|
|
+ const [lumiBagTab, setLumiBagTab] = useState<'furniture' | 'outfits'>('outfits');
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const tab = searchParams.get('tab');
|
|
|
+ setLumiBagTab(tab === 'furniture' ? 'furniture' : 'outfits');
|
|
|
+ }, [searchParams]);
|
|
|
+
|
|
|
+ const handleSelectFurnitureTab = useCallback(() => {
|
|
|
+ setLumiBagTab('furniture');
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const handleSelectOutfitsTab = useCallback(() => {
|
|
|
+ setLumiBagTab('outfits');
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const onFurnitureTabClick = useMemo(
|
|
|
+ () => wrapTrackedClick('lumi_outfits', 'bag_furniture_tab', handleSelectFurnitureTab),
|
|
|
+ [handleSelectFurnitureTab],
|
|
|
+ );
|
|
|
+
|
|
|
+ const onOutfitsTabClick = useMemo(
|
|
|
+ () => wrapTrackedClick('lumi_outfits', 'bag_outfits_tab', handleSelectOutfitsTab),
|
|
|
+ [handleSelectOutfitsTab],
|
|
|
+ );
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <div
|
|
|
+ className="chatbot-container"
|
|
|
+ style={{
|
|
|
+ position: 'relative',
|
|
|
+ width: '100%',
|
|
|
+ minHeight: '100dvh',
|
|
|
+ overflow: 'hidden',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src={treesImageUrl}
|
|
|
+ alt={t('a11y.trees')}
|
|
|
+ className="chatbot-trees absolute pointer-events-none"
|
|
|
+ style={getTreesImageStyle()}
|
|
|
+ fetchPriority="low"
|
|
|
+ loading="lazy"
|
|
|
+ draggable={false}
|
|
|
+ />
|
|
|
+
|
|
|
+ <img
|
|
|
+ src={stoolImageUrl}
|
|
|
+ alt=""
|
|
|
+ className="absolute pointer-events-none"
|
|
|
+ fetchPriority="low"
|
|
|
+ style={{
|
|
|
+ width: px2vmin(STOOL_LAYOUT.width),
|
|
|
+ height: px2vmin(STOOL_LAYOUT.height),
|
|
|
+ left: px2vmin(STOOL_LAYOUT.left),
|
|
|
+ top: px2vmin(STOOL_LAYOUT.top),
|
|
|
+ zIndex: 2,
|
|
|
+ objectFit: 'contain',
|
|
|
+ }}
|
|
|
+ draggable={false}
|
|
|
+ />
|
|
|
+
|
|
|
+ {lumiBagTab === 'outfits' && (
|
|
|
+ <img
|
|
|
+ src={lumiOutfitImg}
|
|
|
+ alt=""
|
|
|
+ className="absolute pointer-events-none"
|
|
|
+ style={{
|
|
|
+ width: px2vmin(240),
|
|
|
+ height: px2vmin(240),
|
|
|
+ left: '50%',
|
|
|
+ top: px2vmin(231),
|
|
|
+ transform: 'translateX(-50%)',
|
|
|
+ zIndex: 5,
|
|
|
+ objectFit: 'contain',
|
|
|
+ }}
|
|
|
+ draggable={false}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ onClick={onBackClick}
|
|
|
+ style={{
|
|
|
+ position: 'fixed',
|
|
|
+ left: px2vmin(24),
|
|
|
+ top: px2vmin(125),
|
|
|
+ width: px2vmin(32),
|
|
|
+ height: px2vmin(32),
|
|
|
+ padding: 0,
|
|
|
+ border: 'none',
|
|
|
+ background: 'none',
|
|
|
+ borderRadius: '50%',
|
|
|
+ zIndex: 100,
|
|
|
+ cursor: 'pointer',
|
|
|
+ }}
|
|
|
+ aria-label={t('a11y.back')}
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src={backButtonIcon}
|
|
|
+ alt=""
|
|
|
+ style={{
|
|
|
+ width: '100%',
|
|
|
+ height: '100%',
|
|
|
+ display: 'block',
|
|
|
+ pointerEvents: 'none',
|
|
|
+ }}
|
|
|
+ draggable={false}
|
|
|
+ />
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 底部弹窗 + 上方家具/服装切换(与 Profile Lumi 背包 icon 一致) */}
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ position: 'fixed',
|
|
|
+ bottom: 0,
|
|
|
+ left: '50%',
|
|
|
+ transform: 'translateX(-50%)',
|
|
|
+ width: px2vw(375),
|
|
|
+ zIndex: 9999,
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ paddingLeft: px2vmin(24),
|
|
|
+ marginBottom: px2vmin(10),
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'flex-start',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ role="tablist"
|
|
|
+ aria-label={tProfile('lumiBagTitle')}
|
|
|
+ style={{
|
|
|
+ width: px2vmin(80),
|
|
|
+ height: px2vmin(32),
|
|
|
+ borderRadius: px2vmin(12),
|
|
|
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'row',
|
|
|
+ alignItems: 'stretch',
|
|
|
+ padding: px2vmin(2),
|
|
|
+ gap: px2vmin(2),
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ role="tab"
|
|
|
+ aria-selected={lumiBagTab === 'furniture'}
|
|
|
+ onClick={onFurnitureTabClick}
|
|
|
+ style={{
|
|
|
+ flex: 1,
|
|
|
+ minWidth: 0,
|
|
|
+ margin: 0,
|
|
|
+ padding: 0,
|
|
|
+ border: 'none',
|
|
|
+ cursor: 'pointer',
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ borderRadius: px2vmin(10),
|
|
|
+ backgroundColor:
|
|
|
+ lumiBagTab === 'furniture' ? 'rgba(245, 243, 240, 0.2)' : 'transparent',
|
|
|
+ WebkitTapHighlightColor: 'transparent',
|
|
|
+ }}
|
|
|
+ aria-label={tProfile('lumiBagFurniture')}
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src={chairBagImg}
|
|
|
+ alt=""
|
|
|
+ draggable={false}
|
|
|
+ style={{
|
|
|
+ width: px2vmin(20),
|
|
|
+ height: px2vmin(20),
|
|
|
+ objectFit: 'contain',
|
|
|
+ display: 'block',
|
|
|
+ pointerEvents: 'none',
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ role="tab"
|
|
|
+ aria-selected={lumiBagTab === 'outfits'}
|
|
|
+ onClick={onOutfitsTabClick}
|
|
|
+ style={{
|
|
|
+ flex: 1,
|
|
|
+ minWidth: 0,
|
|
|
+ margin: 0,
|
|
|
+ padding: 0,
|
|
|
+ border: 'none',
|
|
|
+ cursor: 'pointer',
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ borderRadius: px2vmin(10),
|
|
|
+ backgroundColor:
|
|
|
+ lumiBagTab === 'outfits' ? 'rgba(245, 243, 240, 0.2)' : 'transparent',
|
|
|
+ WebkitTapHighlightColor: 'transparent',
|
|
|
+ }}
|
|
|
+ aria-label={tProfile('lumiBagOutfits')}
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src={glovesBagImg}
|
|
|
+ alt=""
|
|
|
+ draggable={false}
|
|
|
+ style={{
|
|
|
+ width: px2vmin(20),
|
|
|
+ height: px2vmin(20),
|
|
|
+ objectFit: 'contain',
|
|
|
+ display: 'block',
|
|
|
+ pointerEvents: 'none',
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ height: px2vmin(318),
|
|
|
+ backgroundColor: '#34313D',
|
|
|
+ borderTopLeftRadius: px2vmin(32),
|
|
|
+ borderTopRightRadius: px2vmin(32),
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ paddingBottom: 'max(env(safe-area-inset-bottom, 0px), 0px)',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ position: 'relative',
|
|
|
+ width: '100%',
|
|
|
+ height: '100%',
|
|
|
+ overflow: 'hidden',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {/* 文字距弹窗顶 194(vmin);提示文案 + 去聊天 */}
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ position: 'absolute',
|
|
|
+ top: px2vmin(194),
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'column',
|
|
|
+ alignItems: 'center',
|
|
|
+ paddingLeft: px2vmin(32),
|
|
|
+ paddingRight: px2vmin(32),
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ zIndex: 10,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <p
|
|
|
+ style={{
|
|
|
+ margin: 0,
|
|
|
+ width: '100%',
|
|
|
+ color: '#FFFFFF',
|
|
|
+ fontSize: px2vmin(14),
|
|
|
+ lineHeight: px2vmin(24),
|
|
|
+ textAlign: 'center',
|
|
|
+ fontWeight: 400,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {tProfile('lumiOutfitsShopHint')}
|
|
|
+ </p>
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ onClick={onChatNowClick}
|
|
|
+ onKeyDown={(e) => {
|
|
|
+ if (e.key === 'Enter' || e.key === ' ') {
|
|
|
+ e.preventDefault();
|
|
|
+ onChatNowClick();
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ style={{
|
|
|
+ marginTop: px2vmin(10),
|
|
|
+ width: px2vmin(312),
|
|
|
+ height: px2vmin(56),
|
|
|
+ padding: 0,
|
|
|
+ border: 'none',
|
|
|
+ borderRadius: px2vmin(12),
|
|
|
+ background: `url(${secondaryDefaultButton}) center/cover no-repeat`,
|
|
|
+ cursor: 'pointer',
|
|
|
+ transition: 'opacity 0.2s ease',
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ fontFamily:
|
|
|
+ '-apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif',
|
|
|
+ fontWeight: 500,
|
|
|
+ fontSize: px2vmin(16),
|
|
|
+ lineHeight: px2vmin(24),
|
|
|
+ color: '#fff',
|
|
|
+ WebkitTapHighlightColor: 'transparent',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {tProfile('chatNowButton')}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 顶部 44:与能量石弹窗一致留出手势条区域 */}
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ position: 'absolute',
|
|
|
+ top: 0,
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ height: px2vmin(44),
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ pointerEvents: 'none',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ width: px2vmin(32),
|
|
|
+ height: px2vmin(4),
|
|
|
+ backgroundColor: '#79747E',
|
|
|
+ borderRadius: px2vmin(4),
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 距弹窗顶部 44、高度 274(随弹窗总高 318) */}
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ position: 'absolute',
|
|
|
+ top: px2vmin(44),
|
|
|
+ left: 0,
|
|
|
+ width: '100%',
|
|
|
+ height: px2vmin(274),
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {/** 服装行:距父区域顶部 32,宽 310,高 90,水平居中 */}
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ marginTop: px2vmin(32),
|
|
|
+ marginLeft: 'auto',
|
|
|
+ marginRight: 'auto',
|
|
|
+ width: px2vmin(310),
|
|
|
+ height: px2vmin(90),
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'row',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ columnGap: px2vmin(20),
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {lumiBagTab === 'furniture' ? (
|
|
|
+ <p
|
|
|
+ style={{
|
|
|
+ margin: 0,
|
|
|
+ width: '100%',
|
|
|
+ textAlign: 'center',
|
|
|
+ color: 'rgba(255, 255, 255, 0.6)',
|
|
|
+ fontSize: px2vmin(14),
|
|
|
+ lineHeight: px2vmin(20),
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {tProfile('lumiTabPlaceholder')}
|
|
|
+ </p>
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ {/* 卡片 1:帽子 — 点击在戴帽/默认形象间切换 current_avatar_id */}
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ onClick={onCapCardClick}
|
|
|
+ onKeyDown={(e) => {
|
|
|
+ if (e.key === 'Enter' || e.key === ' ') {
|
|
|
+ e.preventDefault();
|
|
|
+ onCapCardClick();
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ style={{
|
|
|
+ width: px2vmin(90),
|
|
|
+ height: px2vmin(90),
|
|
|
+ borderRadius: px2vmin(16),
|
|
|
+ backgroundColor: 'rgba(245, 243, 240, 0.1)',
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ flexShrink: 0,
|
|
|
+ padding: 0,
|
|
|
+ border: 'none',
|
|
|
+ cursor: 'pointer',
|
|
|
+ WebkitTapHighlightColor: 'transparent',
|
|
|
+ ...capCardBorderStyle,
|
|
|
+ }}
|
|
|
+ aria-pressed={currentAvatarId === AVATAR_ID_REGISTERED}
|
|
|
+ aria-label={tProfile('lumiOutfitsCapCardToggleA11y')}
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src={headCapImg}
|
|
|
+ alt=""
|
|
|
+ draggable={false}
|
|
|
+ style={{
|
|
|
+ width: px2vmin(64),
|
|
|
+ height: px2vmin(64),
|
|
|
+ objectFit: 'contain',
|
|
|
+ display: 'block',
|
|
|
+ pointerEvents: 'none',
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </button>
|
|
|
+
|
|
|
+ {/* 卡片 2、3 */}
|
|
|
+ {[0, 1].map((i) => (
|
|
|
+ <div
|
|
|
+ key={`wenhao-${i}`}
|
|
|
+ style={{
|
|
|
+ width: px2vmin(90),
|
|
|
+ height: px2vmin(90),
|
|
|
+ borderRadius: px2vmin(16),
|
|
|
+ boxSizing: 'border-box',
|
|
|
+ display: 'flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ flexShrink: 0,
|
|
|
+ overflow: 'hidden',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src={wenhaoImg}
|
|
|
+ alt=""
|
|
|
+ draggable={false}
|
|
|
+ style={{
|
|
|
+ width: '100%',
|
|
|
+ height: '100%',
|
|
|
+ objectFit: 'contain',
|
|
|
+ display: 'block',
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ );
|
|
|
+};
|