Compare commits
4 Commits
afc92ee583
...
93f43054fd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93f43054fd | ||
|
|
101d042b0e | ||
|
|
a1aa6718e6 | ||
|
|
753727c1c0 |
@@ -63,6 +63,59 @@ const BytedeskWidget = ({
|
|||||||
bytedesk.init();
|
bytedesk.init();
|
||||||
widgetRef.current = bytedesk;
|
widgetRef.current = bytedesk;
|
||||||
|
|
||||||
|
// ⚡ H5 端样式适配:使用 MutationObserver 立即应用样式(避免闪烁)
|
||||||
|
const isMobile = window.innerWidth <= 768;
|
||||||
|
|
||||||
|
const applyBytedeskStyles = () => {
|
||||||
|
const allElements = document.querySelectorAll('body > div');
|
||||||
|
allElements.forEach(el => {
|
||||||
|
const style = window.getComputedStyle(el);
|
||||||
|
// 检查是否是右下角固定定位的元素(Bytedesk 按钮)
|
||||||
|
if (style.position === 'fixed' && style.right && style.bottom) {
|
||||||
|
const rightVal = parseInt(style.right);
|
||||||
|
const bottomVal = parseInt(style.bottom);
|
||||||
|
if (rightVal >= 0 && rightVal < 100 && bottomVal >= 0 && bottomVal < 100) {
|
||||||
|
// H5 端设置按钮尺寸为 48x48(只执行一次)
|
||||||
|
if (isMobile && !el.dataset.bytedeskStyled) {
|
||||||
|
el.dataset.bytedeskStyled = 'true';
|
||||||
|
const button = el.querySelector('button');
|
||||||
|
if (button) {
|
||||||
|
button.style.width = '48px';
|
||||||
|
button.style.height = '48px';
|
||||||
|
button.style.minWidth = '48px';
|
||||||
|
button.style.minHeight = '48px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 提示框 3 秒后隐藏(查找白色气泡框)
|
||||||
|
const children = el.querySelectorAll('div');
|
||||||
|
children.forEach(child => {
|
||||||
|
if (child.dataset.bytedeskTooltip) return; // 已处理过
|
||||||
|
const childStyle = window.getComputedStyle(child);
|
||||||
|
// 白色背景的提示框
|
||||||
|
if (childStyle.backgroundColor === 'rgb(255, 255, 255)') {
|
||||||
|
child.dataset.bytedeskTooltip = 'true';
|
||||||
|
setTimeout(() => {
|
||||||
|
child.style.transition = 'opacity 0.3s';
|
||||||
|
child.style.opacity = '0';
|
||||||
|
setTimeout(() => child.remove(), 300);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 立即执行一次
|
||||||
|
applyBytedeskStyles();
|
||||||
|
|
||||||
|
// 监听 DOM 变化,新元素出现时立即应用样式
|
||||||
|
const observer = new MutationObserver(applyBytedeskStyles);
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
// 5 秒后停止监听(避免性能问题)
|
||||||
|
setTimeout(() => observer.disconnect(), 5000);
|
||||||
|
|
||||||
// ⚡ 屏蔽 STOMP WebSocket 错误日志(不影响功能)
|
// ⚡ 屏蔽 STOMP WebSocket 错误日志(不影响功能)
|
||||||
const originalConsoleError = console.error;
|
const originalConsoleError = console.error;
|
||||||
console.error = function(...args) {
|
console.error = function(...args) {
|
||||||
|
|||||||
@@ -36,3 +36,37 @@ iframe[src*="/visitor/"] {
|
|||||||
[class*="bytedesk-badge"] {
|
[class*="bytedesk-badge"] {
|
||||||
z-index: 1000000 !important;
|
z-index: 1000000 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========== H5 端客服组件整体缩小 ========== */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
/* 整个客服容器缩小(包括按钮和提示框) */
|
||||||
|
[class*="bytedesk"],
|
||||||
|
[id*="bytedesk"],
|
||||||
|
[class*="BytedeskWeb"] {
|
||||||
|
transform: scale(0.7) !important;
|
||||||
|
transform-origin: bottom right !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 提示框 3 秒后自动消失 ========== */
|
||||||
|
/* 提示框("在线客服 点击咨询"气泡)- 扩展选择器 */
|
||||||
|
[class*="bytedesk-bubble"],
|
||||||
|
[class*="bytedesk-tooltip"],
|
||||||
|
[class*="BytedeskWeb"] [class*="bubble"],
|
||||||
|
[class*="BytedeskWeb"] [class*="tooltip"],
|
||||||
|
[class*="bytedesk"] > div:not(button):not(iframe),
|
||||||
|
[class*="BytedeskWeb"] > div:not(button):not(iframe),
|
||||||
|
[id*="bytedesk"] > div:not(button):not(iframe) {
|
||||||
|
animation: bytedeskFadeOut 0.3s ease-out 3s forwards !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bytedeskFadeOut {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -543,7 +543,7 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
<Flex justify="space-between" align="center">
|
<Flex justify="space-between" align="center">
|
||||||
{/* 左侧:标题 + 模式切换按钮 */}
|
{/* 左侧:标题 + 模式切换按钮 */}
|
||||||
<HStack spacing={4}>
|
<HStack spacing={4}>
|
||||||
<Heading size="md" color={PROFESSIONAL_COLORS.text.primary}>
|
<Heading size={isMobile ? "sm" : "md"} color={PROFESSIONAL_COLORS.text.primary}>
|
||||||
<HStack spacing={2}>
|
<HStack spacing={2}>
|
||||||
<TimeIcon color={PROFESSIONAL_COLORS.gold[500]} />
|
<TimeIcon color={PROFESSIONAL_COLORS.gold[500]} />
|
||||||
<Text bgGradient={PROFESSIONAL_COLORS.gradients.gold} bgClip="text">实时要闻·动态追踪</Text>
|
<Text bgGradient={PROFESSIONAL_COLORS.gradients.gold} bgClip="text">实时要闻·动态追踪</Text>
|
||||||
@@ -610,7 +610,9 @@ const [currentMode, setCurrentMode] = useState('vertical');
|
|||||||
<CardBody
|
<CardBody
|
||||||
ref={cardBodyRef}
|
ref={cardBodyRef}
|
||||||
position="relative"
|
position="relative"
|
||||||
pt={4}
|
pt={0}
|
||||||
|
px={0}
|
||||||
|
mx={0}
|
||||||
display="flex"
|
display="flex"
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
overflow="visible"
|
overflow="visible"
|
||||||
|
|||||||
@@ -9,18 +9,12 @@ import {
|
|||||||
Center,
|
Center,
|
||||||
Text,
|
Text,
|
||||||
useBreakpointValue,
|
useBreakpointValue,
|
||||||
Modal,
|
|
||||||
ModalOverlay,
|
|
||||||
ModalContent,
|
|
||||||
ModalHeader,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
useDisclosure
|
useDisclosure
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { InfoIcon } from '@chakra-ui/icons';
|
import { InfoIcon } from '@chakra-ui/icons';
|
||||||
import HorizontalDynamicNewsEventCard from '../EventCard/HorizontalDynamicNewsEventCard';
|
import HorizontalDynamicNewsEventCard from '../EventCard/HorizontalDynamicNewsEventCard';
|
||||||
import EventDetailScrollPanel from './EventDetailScrollPanel';
|
import EventDetailScrollPanel from './EventDetailScrollPanel';
|
||||||
import DynamicNewsDetailPanel from '../DynamicNewsDetail/DynamicNewsDetailPanel';
|
import EventDetailModal from '../EventDetailModal';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 纵向分栏模式布局
|
* 纵向分栏模式布局
|
||||||
@@ -165,20 +159,11 @@ const VerticalModeLayout = React.memo(({
|
|||||||
|
|
||||||
{/* 移动端详情弹窗 */}
|
{/* 移动端详情弹窗 */}
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
<Modal isOpen={isMobileModalOpen} onClose={onMobileModalClose} size="full" scrollBehavior="inside">
|
<EventDetailModal
|
||||||
<ModalOverlay bg="blackAlpha.800" backdropFilter="blur(10px)" />
|
open={isMobileModalOpen}
|
||||||
<ModalContent maxW="100vw" m={0} borderRadius={0}>
|
onClose={onMobileModalClose}
|
||||||
<ModalHeader bg="gray.900" color="white" borderBottom="1px solid" borderColor="gray.700">
|
event={mobileSelectedEvent}
|
||||||
{mobileSelectedEvent?.title || '事件详情'}
|
/>
|
||||||
</ModalHeader>
|
|
||||||
<ModalCloseButton color="white" />
|
|
||||||
<ModalBody p={0} bg="gray.900">
|
|
||||||
{mobileSelectedEvent && (
|
|
||||||
<DynamicNewsDetailPanel event={mobileSelectedEvent} showHeader={false} />
|
|
||||||
)}
|
|
||||||
</ModalBody>
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const CompactMetaBar = ({ event, importance, isFollowing, followerCount, onToggl
|
|||||||
spacing={3}
|
spacing={3}
|
||||||
zIndex={1}
|
zIndex={1}
|
||||||
>
|
>
|
||||||
{/* 重要性徽章 - 与 EventHeaderInfo 样式一致,尺寸略小 */}
|
{/* 重要性徽章 - 与 EventHeaderInfo 样式一致,尺寸略小 - H5 隐藏 */}
|
||||||
<Badge
|
<Badge
|
||||||
px={3}
|
px={3}
|
||||||
py={1.5}
|
py={1.5}
|
||||||
@@ -62,7 +62,7 @@ const CompactMetaBar = ({ event, importance, isFollowing, followerCount, onToggl
|
|||||||
}
|
}
|
||||||
color="white"
|
color="white"
|
||||||
boxShadow="lg"
|
boxShadow="lg"
|
||||||
display="flex"
|
display={{ base: 'none', lg: 'flex' }}
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
gap={1}
|
gap={1}
|
||||||
>
|
>
|
||||||
|
|||||||
36
src/views/Community/components/EventDetailModal.less
Normal file
36
src/views/Community/components/EventDetailModal.less
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
.event-detail-modal {
|
||||||
|
top: 20% !important;
|
||||||
|
margin: 0 auto !important;
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
|
||||||
|
.ant-modal-content {
|
||||||
|
border-radius: 24px !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题样式 - 深色文字(白色背景)
|
||||||
|
.ant-modal-title {
|
||||||
|
color: #1A202C;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭按钮样式 - 深色(白色背景)
|
||||||
|
.ant-modal-close {
|
||||||
|
color: #4A5568;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1A202C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自底向上滑入动画
|
||||||
|
@keyframes slideUp {
|
||||||
|
from {
|
||||||
|
transform: translateY(100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/views/Community/components/EventDetailModal.tsx
Normal file
48
src/views/Community/components/EventDetailModal.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { Modal } from 'antd';
|
||||||
|
import { selectIsMobile } from '@store/slices/deviceSlice';
|
||||||
|
import DynamicNewsDetailPanel from './DynamicNewsDetail/DynamicNewsDetailPanel';
|
||||||
|
import './EventDetailModal.less';
|
||||||
|
|
||||||
|
interface EventDetailModalProps {
|
||||||
|
/** 是否打开弹窗 */
|
||||||
|
open: boolean;
|
||||||
|
/** 关闭弹窗回调 */
|
||||||
|
onClose: () => void;
|
||||||
|
/** 事件对象 */
|
||||||
|
event: any; // TODO: 后续可替换为具体的 Event 类型
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事件详情弹窗组件
|
||||||
|
*/
|
||||||
|
const EventDetailModal: React.FC<EventDetailModalProps> = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
event,
|
||||||
|
}) => {
|
||||||
|
const isMobile = useSelector(selectIsMobile);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onCancel={onClose}
|
||||||
|
footer={null}
|
||||||
|
title={event?.title || '事件详情'}
|
||||||
|
width='100vw'
|
||||||
|
destroyOnClose
|
||||||
|
className="event-detail-modal"
|
||||||
|
styles={{
|
||||||
|
mask: { background: 'transparent' },
|
||||||
|
content: { borderRadius: 24, padding: 0, maxWidth: 1400, background: 'transparent', margin: '0 auto' },
|
||||||
|
header: { background: '#FFFFFF', borderBottom: '1px solid #E2E8F0', padding: '16px 24px', borderRadius: '24px 24px 0 0', margin: 0 },
|
||||||
|
body: { padding: 0 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{event && <DynamicNewsDetailPanel event={event} showHeader={false} />}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EventDetailModal;
|
||||||
@@ -2,19 +2,11 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Card, Badge, Tag, Empty, Carousel, Tooltip } from 'antd';
|
import { Card, Badge, Tag, Empty, Carousel, Tooltip } from 'antd';
|
||||||
import { ArrowUpOutlined, ArrowDownOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
|
import { ArrowUpOutlined, ArrowDownOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
|
||||||
import {
|
import { useDisclosure } from '@chakra-ui/react';
|
||||||
Modal,
|
import EventDetailModal from './EventDetailModal';
|
||||||
ModalOverlay,
|
|
||||||
ModalContent,
|
|
||||||
ModalHeader,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
useDisclosure
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import './HotEvents.css';
|
import './HotEvents.css';
|
||||||
import defaultEventImage from '../../../assets/img/default-event.jpg';
|
import defaultEventImage from '../../../assets/img/default-event.jpg';
|
||||||
import DynamicNewsDetailPanel from './DynamicNewsDetail';
|
|
||||||
|
|
||||||
// 自定义箭头组件
|
// 自定义箭头组件
|
||||||
const CustomArrow = ({ className, style, onClick, direction }) => {
|
const CustomArrow = ({ className, style, onClick, direction }) => {
|
||||||
@@ -196,21 +188,12 @@ const HotEvents = ({ events, onPageChange, onEventClick }) => {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 事件详情弹窗 - 使用 Chakra UI Modal(与平铺模式一致) */}
|
{/* 事件详情弹窗 */}
|
||||||
{isModalOpen ? (
|
<EventDetailModal
|
||||||
<Modal isOpen={isModalOpen} onClose={onModalClose} size="6xl" scrollBehavior="inside">
|
open={isModalOpen}
|
||||||
<ModalOverlay />
|
onClose={onModalClose}
|
||||||
<ModalContent>
|
event={modalEvent}
|
||||||
<ModalHeader>
|
/>
|
||||||
{modalEvent?.title || '事件详情'}
|
|
||||||
</ModalHeader>
|
|
||||||
<ModalCloseButton />
|
|
||||||
<ModalBody pb={6}>
|
|
||||||
{modalEvent && <DynamicNewsDetailPanel event={modalEvent} />}
|
|
||||||
</ModalBody>
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
): null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user