Commit 06274019 authored by 周宏民's avatar 周宏民

feat: 弥勒集成登录

parent 191896eb
Pipeline #92084 waiting for manual action with stages
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
...@@ -12,6 +12,7 @@ import TaihuPage from './project/taihu'; ...@@ -12,6 +12,7 @@ import TaihuPage from './project/taihu';
import JimusaerPage from './project/jimusaer'; import JimusaerPage from './project/jimusaer';
import YixingPage from './project/yixing'; import YixingPage from './project/yixing';
import DanlingPage from './project/danling'; import DanlingPage from './project/danling';
import MilePage from './project/mile';
export const guidePage = [ export const guidePage = [
// type 为true 则需要 功能配置 isPanda 为true // type 为true 则需要 功能配置 isPanda 为true
{ {
...@@ -38,6 +39,10 @@ export const guidePage = [ ...@@ -38,6 +39,10 @@ export const guidePage = [
label: '丹棱集成登录', label: '丹棱集成登录',
value: 'danlingPage', value: 'danlingPage',
}, },
{
label: '弥勒集成登录',
value: 'milePage',
},
{ {
label: '演示环境(旧版)', label: '演示环境(旧版)',
type: true, type: true,
...@@ -58,4 +63,5 @@ export const BootPageTemplate = { ...@@ -58,4 +63,5 @@ export const BootPageTemplate = {
jimusaerPage: JimusaerPage, jimusaerPage: JimusaerPage,
yixingPage: YixingPage, yixingPage: YixingPage,
danlingPage: DanlingPage, danlingPage: DanlingPage,
milePage: MilePage,
}; };
{
"listData": [
{
"name": "领导驾驶舱",
"english": "Leadership cockpit",
"label": "",
"url": "https://portal.panda-water.cn/civbase/"
},
{
"name": "营业收费",
"english": "Operating fees",
"label": "",
"url": ""
},
{
"name": "OA办公",
"english": "OA office",
"label": "",
"url": ""
},
{
"name": "资产管理",
"english": "Asset management",
"label": "",
"url": ""
},
{
"name": "在线监测",
"english": "Monitoring Center",
"label": "",
"url": ""
},
{
"name": "控漏管控",
"english": "Leakage control",
"label": "",
"url": ""
},
{
"name": "业务中心",
"english": "Business center",
"label": "",
"url": ""
},
{
"name": "工单中心",
"english": "Ticket center",
"label": "",
"url": ""
}
],
"标题": "弥勒自来水公司信息化平台",
"副标题": "Mile Water Company Information Platform"
}
\ No newline at end of file
/*
* @Title: 弥勒 集成页
* @Author: hongmye
* @Date: 2024-08-26 18:34:42
*/
import { appService } from '@/api';
import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
import { message, Button } from 'antd';
import classNames from 'classnames';
import { debounce } from 'lodash';
import React, { useRef, useEffect, useState, useMemo } from 'react';
import backImg from '@/assets/images/demonstration/返回.png';
import arrowLeftImg from '@/assets/images/demonstration/左箭头.png';
import LoadPage from '@/components/LoadPage';
import $ from 'jquery';
import { connect } from 'react-redux';
import useFullScreen from '../../demonstration/components/useFullScreen';
import defaultConfig from './data.json';
import styles from './index.less';
import Iframe from '../../demonstration/components/Iframe';
const boxWidth = 1920;
const boxHeight = 930;
// const Cripples = require('@/assets/js/ripples/jquery.ripples');
const IntegrationMile = props => {
const [ref, isFullscreen, handleFullScreen, handleExitFullScreen] = useFullScreen(false);
const timer2 = useRef(null);
const timer3 = useRef(null);
const timer4 = useRef(null);
const progressRef2 = useRef(0);
// 退出
const exit = () => {
if (isFullscreen) {
handleExitFullScreen && handleExitFullScreen();
} else {
handleFullScreen && handleFullScreen();
}
};
const [boxSize, setBoxSize] = useState({
scale: 1,
boxHeight: 930,
});
const [linkUrl, setLinkUrl] = useState('');
const [jumpLoading, setJumpLoading] = useState(false);
const [progressValue2, setProgressValue2] = useState(0);
const [showBackBtn, setShowBackBtn] = useState(true); // 是否显示iframe 返回按钮,三维平台用
const configName = '弥勒集成配置文件';
const [configData, setConfigData] = useState(defaultConfig);
const jumpProgressStart = () => {
if (timer2.current) {
clearInterval(timer2.current);
timer2.current = null;
}
progressRef2.current = 0;
setProgressValue2(0);
timer2.current = setInterval(() => {
if (progressRef2.current < 97.5) {
progressRef2.current += 2.5;
setProgressValue2(progressRef2.current);
} else {
setProgressValue2(99);
timer2.current && clearInterval(timer2.current);
timer2.current = null;
}
}, 100);
};
const jumpProgressEnd = () => {
setProgressValue2(100);
timer2.current && clearInterval(timer2.current);
timer2.current = null;
};
const getData = async () => {
appService
.GetConfigJson({
config: configName,
})
.then(res => {
if (res.code === 0 && res.data) {
const data = JSON.parse(res.data) || defaultConfig;
setConfigData(data);
}
});
};
const onResize = () => {
if (ref?.current) {
const { clientWidth, clientHeight } = ref.current;
if (!boxWidth || !boxHeight) return;
const xScale = clientWidth / boxWidth;
const yScale = clientHeight / boxHeight;
const poor = clientHeight / clientWidth - boxHeight / boxWidth;
let n = Math.min(xScale, yScale);
let bHeight = boxHeight;
if (poor > 0.05) {
bHeight = boxHeight + 30;
}
// 高度为偶数
bHeight = parseInt(bHeight, 10);
if (bHeight % 2 !== 0) {
bHeight += 1;
}
n = Number(n.toFixed(4));
setBoxSize({
scale: n,
boxHeight: bHeight,
});
}
};
const handError = err => {
if (err) {
message.error(err);
}
setLinkUrl('');
setJumpLoading(false);
jumpProgressEnd();
};
const onMessageBack = data => {
if (!data?.type) return;
switch (data?.type) {
// 页面加载完成
// 登录成功
case 'runAfterFirstMounted':
case 'loginSuccess':
jumpProgressEnd();
setTimeout(() => {
setJumpLoading(false);
}, 100);
break;
case 'loginError':
message.warning('登录失败,请联系管理人员');
handError();
break;
case '无法连接':
message.warning('该站点无法连接,请联系管理人员');
setTimeout(() => {
handError();
}, 100);
break;
case 'showBack':
setShowBackBtn(true);
break;
case 'hideBack':
setShowBackBtn(false);
break;
default:
break;
}
};
const iframeItem = useMemo(() => {
if (!linkUrl) return null;
return (
<>
<div
className={classNames(!jumpLoading ? styles.scaleInCenter : styles.hide, 'animate__animated')}
style={{ zIndex: 11 }}
>
<Iframe linkUrl={linkUrl} onMessageBack={onMessageBack} />
</div>
</>
);
}, [linkUrl, jumpLoading]);
const startTiming = (time = 2) => {
if (timer3.current) {
clearInterval(timer3.current);
timer3.current = null;
}
timer3.current = setTimeout(() => {
setJumpLoading(false);
timer2.current && clearInterval(timer2.current);
timer2.current = null;
}, time * 1000);
};
const onLink = url => {
if (!url) return message.warning('未配置功能路径');
setJumpLoading(true);
jumpProgressStart();
setLinkUrl(url);
let time = 15;
if (!url.includes('user/noscret')) {
time = 4;
}
startTiming(time);
};
useEffect(() => {
getData();
window.addEventListener('resize', debounce(onResize, 300));
onResize();
return () => {
window.removeEventListener('resize', onResize);
timer2.current && clearInterval(timer2.current);
timer2.current = null;
timer3.current && clearInterval(timer3.current);
timer3.current = null;
};
}, []);
useEffect(() => {
if (!linkUrl) {
if (timer4.current) {
clearTimeout(timer4.current);
timer4.current = null;
}
timer4.current = setTimeout(() => {
if ($('.CarouselRipples')) {
$('.CarouselRipples').ripples({
resolution: 800,
dropRadius: 20, // px
perturbance: 2,
});
}
}, 800);
}
return () => {
if (timer4.current) {
clearTimeout(timer4.current);
timer4.current = null;
}
};
}, [linkUrl]);
return (
<div className={classNames(styles.integrationMile, 'integrationMile')} ref={ref}>
{jumpLoading ? (
<div className={styles.integrationJumpLoad} key="jumpLoading">
<div style={{ width: '285px' }}>
<LoadPage percent={progressValue2 / 100} text="页面加载中~" />
</div>
</div>
) : null}
{!linkUrl ? (
<div className={styles.integrationMile_exit} onClick={exit}>
<Button type="text" style={{ color: '#fff', fontSize: '24px' }}>
{isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
</Button>
</div>
) : null}
<div
className={styles.integration_content}
style={{
width: boxWidth,
height: boxSize.boxHeight,
transform: `scale(${boxSize.scale}) translate(-50%,-50%)`,
zIndex: linkUrl ? 0 : 10,
}}
>
<div className={styles.integrationMile_title}>
<div className={styles.integrationMile_icon}>
<img
src={
props.global &&
props.global.transformDevAssetsBaseURL &&
props.global.transformDevAssetsBaseURL(props.global.logo)
}
alt="logo"
/>
</div>
<div className={styles.integrationMile_title_text}>
<span>{configData?.['标题'] || '智慧水务综合监控平台'}</span>
</div>
</div>
<div className={styles.integrationMile_title_sub}>
{configData?.['副标题'] || 'Mile Water Company Information Platform'}
</div>
<div className={styles.IY_list}>
{configData?.listData
? configData?.listData.map(item => (
<div
onClick={() => onLink(item.url)}
className={styles.IY_item}
key={item.name}
type={item.name}
style={{ zIndex: linkUrl ? 0 : 10 }}
>
<div className={styles.IY_item_name}>{item.label || item.name}</div>
<div className={styles.IY_item_name_sub}>{item.english || ''}</div>
</div>
))
: null}
</div>
</div>
{linkUrl && showBackBtn ? (
<div
className={classNames(styles.iframeExit, 'animate__animated', 'animate__fadeIn')}
onClick={() => setLinkUrl('')}
>
<div className={styles.iframeBackLeft}>
<img src={arrowLeftImg} alt="返回" />
</div>
<div className={styles.iframeExitIcon}>
<img src={backImg} alt="返回" />
返回
</div>
</div>
) : null}
{iframeItem}
{!linkUrl ? <div className={classNames(styles.CarouselRipples, 'CarouselRipples')} data-ripple="ripple" /> : null}
</div>
);
};
const mapStateToProps = state => ({
global: state.getIn(['global', 'globalConfig']),
});
export default connect(mapStateToProps)(IntegrationMile);
.integrationMile {
width: 100%;
position: relative;
height: 100%;
overflow: hidden;
background: url('@/assets/images/integration/danling/背景.png') center/100% 100% no-repeat;
.iframeExitIcon {
position: absolute;
top: 0;
left: -45px;
display: flex;
height: 44px;
width: 44px;
background: rgba(28, 94, 180, 0.95);
border-radius: 0 7px 7px 0;
flex-direction: column;
justify-content: space-around;
align-items: center;
font-size: 12px;
transition: all 0.2s;
padding: 3px 0;
img {
width: 17px;
height: 12px;
}
}
.iframeExit:hover {
.iframeExitIcon {
left: 0;
}
.iframeBackLeft {
left: -15px;
}
}
.iframeBackLeft {
position: absolute;
top: 0;
left: 0;
width: 14px;
height: 44px;
background: rgba(28, 94, 180, 0.95);
border-radius: 0 7px 7px 0;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
img {
width: 6px;
height: 11px;
}
}
.iframeExit {
width: 44px;
height: 44px;
position: absolute;
top: 4px;
left: 0;
color: #FFF;
cursor: pointer;
user-select: none;
position: absolute;
z-index: 110;
}
.integrationMile_exit {
position: absolute;
right: 10px;
top: 10px;
z-index: 100;
}
.integration_content {
display: flex;
flex-direction: column;
align-items: center;
transform-origin: left top;
position: absolute;
left: 50%;
top: 50%;
padding: 0px 20px 10px;
z-index: 10;
pointer-events: none;
}
//基础平台end
.integrationMile_title {
display: flex;
align-items: center;
justify-content: center;
padding-top: 15px;
padding-bottom: 5px;
.integrationMile_icon {
margin-right: 20px;
}
&_text {
flex: none;
color: #fff;
span {
line-height: 64px;
font-weight: bold;
font-size: 36px;
color: #FFFFFF;
letter-spacing: 4px;
// background: linear-gradient(0deg, #56A1EF 0%, #FFFFFF 59%);
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
position: relative;
// top: -8px;
font-family: Microsoft YaHei;
}
}
}
.integrationMile_title_sub {
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 14px;
color: rgba(255, 255, 255, 0.75);
line-height: 22px;
padding: 0 125px;
background: url(@/assets/images/integration/danling/title_left.png) no-repeat left center, url(@/assets/images/integration/danling/title_right.png) no-repeat right center;
background-size: 115px 1px, 115px 1px;
}
.IY_list {
padding-top: 95px;
display: grid;
margin: auto;
grid-template-columns: 270px 270px 270px 270px;
grid-template-rows: 280px 280px 280px 280px;
gap: 56px 68px;
z-index: 1000;
}
.IY_item {
border-radius: 50px;
text-align: center;
padding-top: 198px;
transition: all 0.3s;
position: relative;
top: 0;
cursor: pointer;
z-index: 10;
pointer-events: all;
.IY_item_name {
font-weight: bold;
font-size: 24px;
line-height: 42px;
color: #FFFFFF;
}
.IY_item_name_sub {
font-weight: 400;
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
}
}
.IY_item:hover {
top: -15px;
}
.IY_item[type='领导驾驶舱'] {
background: url('@/assets/images/integration/mile/领导驾驶舱.png') center/100% 100% no-repeat;
}
.IY_item[type='营业收费'] {
background: url('@/assets/images/integration/mile/营业收费.png') center/100% 100% no-repeat;
}
.IY_item[type='OA办公'] {
background: url('@/assets/images/integration/mile/OA办公.png') center/100% 100% no-repeat;
}
.IY_item[type='资产管理'] {
background: url('@/assets/images/integration/mile/资产管理.png') center/100% 100% no-repeat;
}
.IY_item[type='在线监测'] {
background: url('@/assets/images/integration/mile/在线监测.png') center/100% 100% no-repeat;
}
.IY_item[type='控漏管控'] {
background: url('@/assets/images/integration/mile/控漏管控.png') center/100% 100% no-repeat;
}
.IY_item[type='业务中心'] {
background: url('@/assets/images/integration/mile/业务中心.png') center/100% 100% no-repeat;
}
.IY_item[type='工单中心'] {
background: url('@/assets/images/integration/mile/工单中心.png') center/100% 100% no-repeat;
}
}
.integrationJumpLoad {
width: 100%;
height: 100%;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
z-index: 1080;
padding-bottom: 50px;
background-color: rgba(0, 0, 0, 0.6);
}
.hide {
visibility: hidden;
}
@-webkit-keyframes scale-in-center {
0% {
-webkit-transform: scaleY(0);
transform: scaleY(0);
opacity: 1;
}
100% {
-webkit-transform: scaleY(1);
transform: scaleY(1);
opacity: 1;
}
}
@keyframes scale-in-center {
0% {
-webkit-transform: scaleY(0);
transform: scaleY(0);
opacity: 1;
}
100% {
-webkit-transform: scaleY(1);
transform: scaleY(1);
opacity: 1;
}
}
.scaleInCenter {
visibility: visible;
-webkit-animation: scale-in-center .3s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
animation: scale-in-center .3s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.CarouselRipples {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
& :global {
.CarouselRipples:before {
content: '';
display: inline-block;
vertical-align: middle;
height: 100%;
}
.integrationMile {
.anticon {
vertical-align: 0.125em;
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment