活动及套餐包余额购买

This commit is contained in:
lyp 2025-08-07 10:10:19 +08:00
parent a3e0c07467
commit 5b0f18bc3c
4 changed files with 145 additions and 27 deletions

View File

@ -127,7 +127,7 @@ import active from '../../static/active.gif'
import { DownOutlined, UserOutlined, QuestionCircleOutlined, BellOutlined, KeyOutlined, LogoutOutlined, GiftOutlined, AccountBookOutlined, ContainerOutlined, MenuFoldOutlined, UsergroupAddOutlined, TableOutlined } from "@ant-design/icons"; import { DownOutlined, UserOutlined, QuestionCircleOutlined, BellOutlined, KeyOutlined, LogoutOutlined, GiftOutlined, AccountBookOutlined, ContainerOutlined, MenuFoldOutlined, UsergroupAddOutlined, TableOutlined } from "@ant-design/icons";
import { import {
useContext, useEffect, useState, useContext, useEffect, useState,
// useRef useRef
} from "react"; } from "react";
import { import {
put, get, put, get,
@ -159,6 +159,40 @@ import NoticeModal from '../../components/NoticeModal/NoticeModal.tsx';
// import { log } from 'console'; // import { log } from 'console';
// import HeadCouponModal from '../../components/CouponModal/HeadCouponModal.tsx' // import HeadCouponModal from '../../components/CouponModal/HeadCouponModal.tsx'
export default function Head() { export default function Head() {
const activeBtnRef = useRef<HTMLDivElement>(null);
// 计算元素中心点坐标的函数
const calculateCenterPoint = () => {
// 先检查 ref 是否存在,避免 null 错误
if (activeBtnRef.current) {
const rect = activeBtnRef.current.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
// setCenterPoint({ x: centerX, y: centerY });
// console.log(`元素中心点坐标: (${centerX}, ${centerY})`);
dispath({
type: 'upCenterPoint',
val: { x: centerX, y: centerY }
})
}
};
// 组件挂载后计算一次(确保元素已渲染)
useEffect(() => {
calculateCenterPoint();
// 监听窗口大小变化,重新计算(如果元素位置可能因窗口变化而改变)
const handleResize = () => {
calculateCenterPoint();
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
// const currentUrl = window.location.href; // const currentUrl = window.location.href;
// const formRef = useRef<HTMLFormElement>(null); // const formRef = useRef<HTMLFormElement>(null);
// const triggerFormSubmit = () => { // const triggerFormSubmit = () => {
@ -166,6 +200,8 @@ export default function Head() {
// formRef.current.submit(); // formRef.current.submit();
// } // }
// }; // };
// lyp // lyp
const [form] = Form.useForm<any>(); const [form] = Form.useForm<any>();
const [isUpdateWxUsernamePhone, setIsUpdateWxUsernamePhone] = useState(false); // 绑定手机号号弹窗 const [isUpdateWxUsernamePhone, setIsUpdateWxUsernamePhone] = useState(false); // 绑定手机号号弹窗
@ -383,6 +419,7 @@ export default function Head() {
// const [packageType, setPackageType] = useState('') // const [packageType, setPackageType] = useState('')
const packNum = redxuState.packNum const packNum = redxuState.packNum
const phoneModal = redxuState.phoneModal const phoneModal = redxuState.phoneModal
const activityImgShow = redxuState.activityImgShow //是否显示互动图片
// const activityModal = redxuState.activityModal // const activityModal = redxuState.activityModal
// const packItems: MenuProps['items'] = [ // const packItems: MenuProps['items'] = [
// { // {
@ -1285,10 +1322,13 @@ export default function Head() {
{/* <div className="right" style={{backgroundImage: `url(${headRightBg})`}}> */} {/* <div className="right" style={{backgroundImage: `url(${headRightBg})`}}> */}
<div className="right"> <div className="right">
<div style={{ <div
marginRight: 20, ref={activeBtnRef}
cursor:'pointer' style={{
}} marginRight: 20,
cursor: 'pointer',
display:activityImgShow ? 'unset' : 'none',
}}
onClick={() => { onClick={() => {
// setActivityModal(true) // setActivityModal(true)
dispath({ dispath({

View File

@ -234,9 +234,9 @@ newRequest.interceptors.response.use(
// 下载发票 // 下载发票
export const downloadInvoice = (id: string) => { export const downloadInvoice = (id: string) => {
return `${operatorPluginBaseUrl}/operator-plugin/route/file/download/false/${id}` // return `${operatorPluginBaseUrl}/operator-plugin/route/file/download/false/${id}`
//测试 //测试
// return `http://192.168.0.115:8099/operator-plugin/route/file/download/false/${id}` return `http://192.168.0.115:8099/operator-plugin/route/file/download/false/${id}`
}; };

View File

@ -105,6 +105,7 @@ import noFirImg from '../../static/noFir.png'
export default function Index() { export default function Index() {
// 活动图片 // 活动图片
const [activityImg, setActivityImg] = useState('') const [activityImg, setActivityImg] = useState('')
// 活动名称 // 活动名称
@ -135,6 +136,12 @@ export default function Index() {
val: true, val: true,
}) })
} }
if (!res.title) {
dispath({
type: 'setActivityImgShow',
val: false,
})
}
setActivityImg(downloadInvoice(res.image)) setActivityImg(downloadInvoice(res.image))
setActivityTitle(res.title) setActivityTitle(res.title)
setActivityText(res.help) setActivityText(res.help)
@ -287,6 +294,42 @@ export default function Index() {
const redxuState: any = useSelector(state => state) const redxuState: any = useSelector(state => state)
const phoneModal = redxuState.phoneModal const phoneModal = redxuState.phoneModal
const activityModal = redxuState.activityModal const activityModal = redxuState.activityModal
const centerPoint = redxuState.centerPoint
// 动画状态管理----------------------------------------------
const [isClosing, setIsClosing] = useState(false);
const animationDuration = 300; // 动画持续时间(毫秒)
// 定义收缩的目标坐标(固定点)- 可以根据需求调整
// const targetPosition = {
// x: 50, // 目标X坐标从左侧开始计算
// y: 50 // 目标Y坐标从顶部开始计算
// };
const handleClose = () => {
// 开始关闭动画
setIsClosing(true);
// 动画结束后执行状态更新
setTimeout(() => {
dispath({
type: 'setActivityModal',
val: false,
});
// 当勾选"近期不再提示"时设置cookie
if (activityChecked) {
const date = new Date();
date.setDate(date.getDate() + activityCycle);
document.cookie = `closeActivityModal=${activityCycle}; expires=${date.toUTCString()}; path=/`;
}
// 重置关闭状态,为下次显示做准备
setIsClosing(false);
}, animationDuration);
}
// 动画完毕 ---------------------------------------
// const belongArray = redxuState.belongArray // const belongArray = redxuState.belongArray
//监听cookie里面如果有closeActivityModal这个值 则打印这个值 //监听cookie里面如果有closeActivityModal这个值 则打印这个值
@ -2010,7 +2053,7 @@ export default function Index() {
// 获取cookie里面的closeActivityModal的值 // 获取cookie里面的closeActivityModal的值
// console.log(closeActivityModal); // console.log(closeActivityModal);
}, []); }, []);
useEffect(() => { useEffect(() => {
// loactionStorage里的activeMenu // loactionStorage里的activeMenu
@ -4757,10 +4800,31 @@ export default function Index() {
<div className='couponMask-box' <div className='couponMask-box'
style={{ style={{
display: activityModal && (location.pathname == '/' || location.pathname.includes('/home')) ? 'unset' : 'none', display: activityModal && (location.pathname == '/' || location.pathname.includes('/home')) ? 'unset' : 'none',
zIndex: 100 zIndex: 98,
// 动画
pointerEvents: isClosing ? 'none' : 'auto', // 动画期间不响应鼠标事件
}} }}
> >
<div className='couponMask' > <div className='couponMask'
// 动画
style={{
// position: 'absolute',
position: 'absolute',
// 初始位置:居中显示(保持不变)
top: isClosing ? centerPoint.y : '50%', // 关闭时top直接设为目标点y坐标
left: isClosing ? centerPoint.x - 80 : '50%', // 关闭时left直接设为目标点x坐标
// 关键用translate(-50%, -50%)确保元素中心点与目标点对齐
transform: isClosing
? 'translate(-50%, -50%) scale(0.1)' // 关闭时:缩放到目标点(中心点对齐)
: 'translate(-50%, -50%) scale(1)', // 初始时:居中显示
opacity: isClosing ? 0 : 1,
transition: `all ${animationDuration}ms cubic-bezier(0.25, 0.46, 0.45, 0.94)`,
zIndex: 101,
}}
>
<div style={{ <div style={{
// background: 'skyblue', // background: 'skyblue',
// 背景图设置为activityImg // 背景图设置为activityImg
@ -4792,19 +4856,19 @@ export default function Index() {
).then(() => { ).then(() => {
messageApi.success('邀请码已复制到剪贴板'); messageApi.success('邀请码已复制到剪贴板');
}).catch(() => { }).catch(() => {
messageApi.error('复制失败,请手动复制'); messageApi.error('复制失败');
}); });
} else { } else {
// 兼容旧浏览器 // 兼容旧浏览器
const input = document.createElement('input'); const input = document.createElement('input');
input.value = 'http://127.0.0.1:5500/Register.html?code=' + activityCode; input.value = 'http://127.0.0.1:5500/Register.html?code=' + activityCode;
document.body.appendChild(input); document.body.appendChild(input);
input.select(); input.select();
try { try {
document.execCommand('copy'); document.execCommand('copy');
messageApi.success('邀请码已复制到剪贴板'); messageApi.success('邀请码已复制到剪贴板');
} catch { } catch {
messageApi.error('复制失败,请手动复制'); messageApi.error('复制失败');
} }
document.body.removeChild(input); document.body.removeChild(input);
} }
@ -4832,18 +4896,23 @@ export default function Index() {
</div> </div>
<div className='activityMask-close' onClick={() => { <div className='activityMask-close' onClick={
dispath({ // () => {
type: 'setActivityModal', // dispath({
val: false, // type: 'setActivityModal',
}) // val: false,
// 当activityChecked为true时 再cooke中存入一个维持activityCycle天数的值 // })
if (activityChecked) { // // 当activityChecked为true时 再cooke中存入一个维持activityCycle天数的值
const date = new Date(); // if (activityChecked) {
date.setDate(date.getDate() + activityCycle); // const date = new Date();
document.cookie = `closeActivityModal=${activityCycle}; expires=${date.toUTCString()}; path=/`; // date.setDate(date.getDate() + activityCycle);
} // document.cookie = `closeActivityModal=${activityCycle}; expires=${date.toUTCString()}; path=/`;
}}> // }
// }
// 动画
handleClose
}>
<CloseOutlined /> <CloseOutlined />
</div> </div>
</div> </div>

View File

@ -29,7 +29,10 @@ const baseState = {
replaceArray: [], replaceArray: [],
replaceTotal: 0, replaceTotal: 0,
newReplace: false, newReplace: false,
activityModal:false, //活动弹窗 activityModal: false, //活动弹窗
activityImgShow: true, //活动图片是否展示
// 坐标
centerPoint: { x: 0, y: 0 },
} }
// 创建仓库 // 创建仓库
@ -98,9 +101,15 @@ const reducer = (state = baseState, action: any) => {
if (action.type == 'newReplace') { if (action.type == 'newReplace') {
nstate.newReplace = action.val nstate.newReplace = action.val
} }
if (action.type == 'setActivityModal') { if (action.type == 'setActivityModal') {
nstate.activityModal = action.val nstate.activityModal = action.val
} }
if (action.type == 'upCenterPoint') {
nstate.centerPoint = action.val
}
if (action.type == 'setActivityImgShow') {
nstate.activityImgShow = action.val
}
return nstate return nstate
} }
const store = createStore(reducer) const store = createStore(reducer)