@cqsjjb/jjb-react-admin-component 3.3.1-beta.7 → 3.3.1-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { ButtonProps } from 'antd';
3
+
4
+ export interface PhoneBoxProps {
5
+ /** 展示内容的URL */
6
+ iframeUrl?: string;
7
+ /** 是否显示空状态,默认false */
8
+ showEmpty?: boolean;
9
+ /** 大小,默认'normal' */
10
+ size?: 'normal' | 'small';
11
+ /** 右侧额外操作按钮 */
12
+ extraAction?: React.ReactNode;
13
+ /** 是否显示右侧的二维码预览,默认'false' */
14
+ showPerview?: string | boolean;
15
+ /** 刷新二维码URL的函数,不传时自动使用时间戳刷新二维码 */
16
+ fetchQrcodeUrl?: () => Promise<{ data: string }>;
17
+ }
18
+
19
+ declare const PhoneBox: React.FC<PhoneBoxProps>;
20
+
21
+ export default PhoneBox;
@@ -0,0 +1,200 @@
1
+ import React, { useEffect, useState, useRef } from 'react';
2
+ import { Empty, Space, message, Tooltip, Button, QRCode } from 'antd';
3
+ import { SyncOutlined } from '@ant-design/icons';
4
+ import './index.less';
5
+ export default props => {
6
+ const {
7
+ iframeUrl,
8
+ // 展示内容url
9
+ extraAction,
10
+ // 额外操作
11
+ showEmpty = false,
12
+ // 是否显示空状态
13
+ size = 'normal',
14
+ // 大小
15
+ showPerview = 'false',
16
+ // 是否显示二维码预览
17
+ fetchQrcodeUrl // 刷新二维码URL的函数
18
+ } = props;
19
+ const [currentTime, setCurrentTime] = useState(''); // 当前时间
20
+ const [qrcodeUrl, setQrcodeUrl] = useState(''); // 二维码URL
21
+ const [qrcodeVisible, setQrcodeVisible] = useState(false); // 二维码预览是否显示
22
+ const [isQrcodeExpire, setIsQrcodeExpire] = useState(false); // 二维码是否过期
23
+ const [qrcodeExpireTime, setQrcodeExpireTime] = useState(3); // 二维码剩余过期时间
24
+ const qrcodeButtonRef = useRef(null); // 扫码预览按钮dom
25
+ const currentRotate = useRef(0); // 刷新二维码icon旋转角度
26
+ const qrcodeTimerId = useRef(null); // 二维码三分钟过期定时器
27
+ const qrcodeExpireTimeUpdateTimerId = useRef(null); // 二维码过期时间更新定时器
28
+
29
+ useEffect(() => {
30
+ if (iframeUrl) {
31
+ setQrcodeUrl(iframeUrl);
32
+ }
33
+ }, [iframeUrl]);
34
+
35
+ // 点击外部区域(按钮、tooltip除外)关闭二维码预览
36
+ useEffect(() => {
37
+ const handleClickOutside = e => {
38
+ const button = qrcodeButtonRef.current;
39
+ const tooltip = document.querySelector('.micro-temp-tooltip');
40
+ if (button && !button.contains(e.target) && tooltip && !tooltip.contains(e.target)) {
41
+ setQrcodeVisible(false);
42
+ }
43
+ };
44
+ document.addEventListener('click', handleClickOutside);
45
+ return () => {
46
+ document.removeEventListener('click', handleClickOutside);
47
+ };
48
+ }, []);
49
+
50
+ // 手机上展示当前时间
51
+ useEffect(() => {
52
+ const formatHourMinute = date => {
53
+ const hours = String(date.getHours()).padStart(2, '0');
54
+ const minutes = String(date.getMinutes()).padStart(2, '0');
55
+ return `${hours}:${minutes}`;
56
+ };
57
+ setCurrentTime(formatHourMinute(new Date()));
58
+ const timer = setInterval(() => {
59
+ setCurrentTime(formatHourMinute(new Date()));
60
+ }, 60000);
61
+ return () => clearInterval(timer);
62
+ }, []);
63
+
64
+ // 清理二维码相关定时器
65
+ useEffect(() => {
66
+ return () => {
67
+ clearTimeout(qrcodeTimerId.current);
68
+ clearInterval(qrcodeExpireTimeUpdateTimerId.current);
69
+ };
70
+ }, []);
71
+
72
+ // 二维码过期状态定时器
73
+ const startQrcodeTimer = () => {
74
+ if (qrcodeTimerId.current) {
75
+ clearTimeout(qrcodeTimerId.current);
76
+ }
77
+ qrcodeTimerId.current = setTimeout(() => {
78
+ setIsQrcodeExpire(true);
79
+ }, 180000);
80
+ };
81
+
82
+ // 二维码过期时间定时器
83
+ const startQrcodeExpireTimeUpdateTimer = () => {
84
+ setQrcodeExpireTime(3);
85
+ if (qrcodeExpireTimeUpdateTimerId.current) {
86
+ clearInterval(qrcodeExpireTimeUpdateTimerId.current);
87
+ }
88
+ qrcodeExpireTimeUpdateTimerId.current = setInterval(() => {
89
+ setQrcodeExpireTime(prev => prev > 0 ? prev - 1 : 0);
90
+ }, 60000);
91
+ };
92
+ const getQrCodeUrl = () => {
93
+ if (fetchQrcodeUrl) {
94
+ fetchQrcodeUrl().then(res => {
95
+ setQrcodeUrl(res.data);
96
+ setIsQrcodeExpire(false); // 重置二维码过期状态
97
+ startQrcodeTimer(); // 启动过期状态定时器
98
+ startQrcodeExpireTimeUpdateTimer(); // 启动过期时间定时器
99
+ });
100
+ } else {
101
+ setQrcodeUrl(`${iframeUrl}?t=${Date.now()}`);
102
+ setIsQrcodeExpire(false); // 重置二维码过期状态
103
+ startQrcodeTimer(); // 启动过期状态定时器
104
+ startQrcodeExpireTimeUpdateTimer(); // 启动过期时间定时器
105
+ }
106
+ };
107
+ return /*#__PURE__*/React.createElement("div", {
108
+ className: `phone-box ${size === 'small' ? 'phone-box-small' : ''}`
109
+ }, /*#__PURE__*/React.createElement("img", {
110
+ alt: "",
111
+ src: require('~/assets/phone.png').default,
112
+ width: 356,
113
+ height: 720
114
+ }), /*#__PURE__*/React.createElement("div", {
115
+ className: "phone-content"
116
+ }, /*#__PURE__*/React.createElement("div", {
117
+ className: "phone-content-header"
118
+ }, /*#__PURE__*/React.createElement("div", {
119
+ className: "phone-header-time"
120
+ }, currentTime), /*#__PURE__*/React.createElement("img", {
121
+ src: require('~/assets/shexiang.png').default,
122
+ width: 76,
123
+ height: 23,
124
+ alt: ""
125
+ }), /*#__PURE__*/React.createElement(Space, {
126
+ className: "phone-header-status"
127
+ }, /*#__PURE__*/React.createElement("img", {
128
+ className: "status-xinhao",
129
+ src: require('~/assets/xinhao.png').default,
130
+ alt: ""
131
+ }), /*#__PURE__*/React.createElement("img", {
132
+ className: "status-wangluo",
133
+ src: require('~/assets/wangluo.png').default,
134
+ alt: ""
135
+ }), /*#__PURE__*/React.createElement("img", {
136
+ className: "status-dianchi",
137
+ src: require('~/assets/dianchi.png').default,
138
+ alt: ""
139
+ }))), showEmpty && !iframeUrl ? /*#__PURE__*/React.createElement("div", {
140
+ style: {
141
+ width: 316,
142
+ height: 625,
143
+ display: 'flex',
144
+ alignItems: 'center',
145
+ justifyContent: 'center'
146
+ }
147
+ }, /*#__PURE__*/React.createElement(Empty, {
148
+ description: "\u6682\u65E0\u5185\u5BB9"
149
+ })) : /*#__PURE__*/React.createElement("iframe", {
150
+ src: iframeUrl,
151
+ width: 316,
152
+ height: 625
153
+ })), /*#__PURE__*/React.createElement("div", {
154
+ className: "phone-box-action"
155
+ }, showPerview && /*#__PURE__*/React.createElement(Tooltip, {
156
+ open: qrcodeVisible,
157
+ placement: "bottom",
158
+ arrow: false,
159
+ color: "#FFF",
160
+ rootClassName: "qrcode-preview-tooltip",
161
+ title: /*#__PURE__*/React.createElement("div", {
162
+ className: "qrcode-preview-container"
163
+ }, /*#__PURE__*/React.createElement(QRCode, {
164
+ value: qrcodeUrl
165
+ }), isQrcodeExpire ? /*#__PURE__*/React.createElement("div", {
166
+ className: "qrcode-preview-container-expire-mask"
167
+ }, "\u4E8C\u7EF4\u7801\u8FC7\u671F") : '', /*#__PURE__*/React.createElement("div", {
168
+ className: "qrcode-preview-container-text"
169
+ }, "\u4E34\u65F6\u9884\u89C8\uFF0C", qrcodeExpireTime ? `${qrcodeExpireTime}分钟后失效` : '已失效'), /*#__PURE__*/React.createElement("a", {
170
+ onClick: () => {
171
+ getQrCodeUrl();
172
+ /** icon旋转动画 */
173
+ const icon = document.getElementById('qrcode-preview-container-icon');
174
+ if (!icon) return;
175
+ icon.classList.remove('icon-rotating');
176
+ // 强制重绘
177
+ void icon.offsetWidth;
178
+ icon.style.setProperty('--start-rotate', `${currentRotate.current}deg`);
179
+ icon.classList.add('icon-rotating');
180
+ setTimeout(() => {
181
+ currentRotate.current += 360;
182
+ icon.classList.remove('icon-rotating');
183
+ }, 300);
184
+ }
185
+ }, /*#__PURE__*/React.createElement(SyncOutlined, {
186
+ id: "qrcode-preview-container-icon",
187
+ style: {
188
+ marginRight: '4px'
189
+ }
190
+ }), "\u91CD\u65B0\u751F\u6210"))
191
+ }, /*#__PURE__*/React.createElement(Button, {
192
+ ref: qrcodeButtonRef,
193
+ onClick: () => {
194
+ setQrcodeVisible(!qrcodeVisible);
195
+ getQrCodeUrl();
196
+ },
197
+ color: "primary",
198
+ variant: "outlined"
199
+ }, "\u626B\u7801\u9884\u89C8")), extraAction));
200
+ };
@@ -0,0 +1,116 @@
1
+ .phone-box {
2
+ display: flex;
3
+ gap: 12px;
4
+ position: relative;
5
+ z-index: 1;
6
+
7
+ .phone-content {
8
+ position: absolute;
9
+ top: 17px;
10
+ left: 20px;
11
+ z-index: 2;
12
+ border-radius: 40px;
13
+ overflow: hidden;
14
+ background-color: #fff;
15
+
16
+ .phone-content-header {
17
+ height: 55px;
18
+ padding: 12px 24px;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: space-between;
22
+
23
+ .phone-header-status {
24
+ .status-xinhao {
25
+ width: 20px;
26
+ height: 18px;
27
+ }
28
+
29
+ .status-wangluo {
30
+ width: 16px;
31
+ height: 14px;
32
+ }
33
+
34
+ .status-dianchi {
35
+ width: 24px;
36
+ height: 22px;
37
+ }
38
+ }
39
+
40
+ .phone-header-time {
41
+ font-size: 14px;
42
+ font-weight: 500;
43
+ color: #000;
44
+ width: 76px;
45
+ }
46
+ }
47
+
48
+ iframe {
49
+ border: none;
50
+ }
51
+ }
52
+
53
+ .phone-box-action {
54
+ position: absolute;
55
+ top: 0;
56
+ left: 456px;
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: 16px;
60
+ }
61
+ }
62
+
63
+ .qrcode-preview-container {
64
+ padding: 4px;
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: 8px;
68
+ align-items: center;
69
+ justify-content: center;
70
+ position: relative;
71
+ .qrcode-preview-container-expire-mask {
72
+ width: 160px;
73
+ height: 160px;
74
+ position: absolute;
75
+ top: 4px;
76
+ left: 4px;
77
+ background-color: rgba(255, 255, 255, 0.7);
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ font-size: 16px;
82
+ border-radius: 6px;
83
+ }
84
+
85
+ .qrcode-preview-container-text {
86
+ font-size: 12px;
87
+ color: #00000066;
88
+ }
89
+
90
+ @keyframes rotate360 {
91
+ from {
92
+ transform: rotate(var(--start-rotate, 0deg));
93
+ }
94
+
95
+ to {
96
+ transform: rotate(calc(var(--start-rotate, 0deg) + 360deg));
97
+ }
98
+ }
99
+
100
+ .icon-rotating {
101
+ animation: rotate360 0.3s linear 1 forwards;
102
+ }
103
+ }
104
+
105
+ .qrcode-preview-tooltip {
106
+ margin-top: 16px;
107
+
108
+ .micro-temp-tooltip-inner {
109
+ border-radius: 12px;
110
+ padding: 16px 24px;
111
+ }
112
+ }
113
+
114
+ .phone-box-small {
115
+ transform: scale(0.5);
116
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cqsjjb/jjb-react-admin-component",
3
- "version": "3.3.1-beta.7",
3
+ "version": "3.3.1-beta.8",
4
4
  "description": "jjb-react-admin-组件库@new",
5
5
  "main": "index.js",
6
6
  "author": "jjb-front-team",