Allow portrait signature confirmation
This commit is contained in:
@@ -59,41 +59,3 @@
|
|||||||
.signature-overlay-actions {
|
.signature-overlay-actions {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-overlay-rotate {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 24px;
|
|
||||||
gap: 14px;
|
|
||||||
background: #f8fafc;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signature-overlay-rotate-icon {
|
|
||||||
font-size: 64px;
|
|
||||||
color: #1677ff;
|
|
||||||
animation: signature-rotate-hint 1.6s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes signature-rotate-hint {
|
|
||||||
0%, 100% { transform: rotate(0deg); }
|
|
||||||
50% { transform: rotate(90deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.signature-overlay-rotate-text {
|
|
||||||
font-size: 17px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #1f2937;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signature-overlay-rotate-hint {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #6b7280;
|
|
||||||
margin: 0 0 8px;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import { RotateRightOutlined } from '@ant-design/icons';
|
|
||||||
import SignaturePad, { type SignaturePadHandle } from './SignaturePad';
|
import SignaturePad, { type SignaturePadHandle } from './SignaturePad';
|
||||||
import './SignatureOverlay.css';
|
import './SignatureOverlay.css';
|
||||||
|
|
||||||
@@ -10,63 +9,18 @@ interface SignatureOverlayProps {
|
|||||||
onConfirm: (dataUrl: string) => void;
|
onConfirm: (dataUrl: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLandscapeNow = () =>
|
|
||||||
typeof window !== 'undefined' &&
|
|
||||||
(window.matchMedia('(orientation: landscape)').matches ||
|
|
||||||
window.innerWidth > window.innerHeight ||
|
|
||||||
((window.visualViewport?.width ?? 0) > (window.visualViewport?.height ?? 0)) ||
|
|
||||||
Math.abs(window.screen.orientation?.angle ?? 0) % 180 === 90);
|
|
||||||
|
|
||||||
function SignatureOverlay({ open, onCancel, onConfirm }: SignatureOverlayProps) {
|
function SignatureOverlay({ open, onCancel, onConfirm }: SignatureOverlayProps) {
|
||||||
const padRef = useRef<SignaturePadHandle>(null);
|
const padRef = useRef<SignaturePadHandle>(null);
|
||||||
const [, setData] = useState('');
|
const [, setData] = useState('');
|
||||||
const [landscape, setLandscape] = useState<boolean>(isLandscapeNow);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
|
|
||||||
const mq = window.matchMedia('(orientation: landscape)');
|
|
||||||
const update = () => setLandscape(mq.matches || window.innerWidth > window.innerHeight);
|
|
||||||
update();
|
|
||||||
if (typeof mq.addEventListener === 'function') {
|
|
||||||
mq.addEventListener('change', update);
|
|
||||||
} else {
|
|
||||||
mq.addListener(update);
|
|
||||||
}
|
|
||||||
window.addEventListener('resize', update);
|
|
||||||
window.addEventListener('orientationchange', update);
|
|
||||||
window.visualViewport?.addEventListener('resize', update);
|
|
||||||
|
|
||||||
const orientation = (screen as Screen & {
|
|
||||||
orientation?: {
|
|
||||||
lock?: (o: string) => Promise<void>;
|
|
||||||
unlock?: () => void;
|
|
||||||
addEventListener?: (type: 'change', listener: () => void) => void;
|
|
||||||
removeEventListener?: (type: 'change', listener: () => void) => void;
|
|
||||||
};
|
|
||||||
}).orientation;
|
|
||||||
orientation?.addEventListener?.('change', update);
|
|
||||||
if (orientation?.lock) {
|
|
||||||
orientation.lock('landscape').catch(() => {
|
|
||||||
// ignore; iOS Safari and most browsers refuse outside fullscreen
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const prevOverflow = document.body.style.overflow;
|
const prevOverflow = document.body.style.overflow;
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (typeof mq.removeEventListener === 'function') {
|
|
||||||
mq.removeEventListener('change', update);
|
|
||||||
} else {
|
|
||||||
mq.removeListener(update);
|
|
||||||
}
|
|
||||||
window.removeEventListener('resize', update);
|
|
||||||
window.removeEventListener('orientationchange', update);
|
|
||||||
window.visualViewport?.removeEventListener('resize', update);
|
|
||||||
orientation?.removeEventListener?.('change', update);
|
|
||||||
document.body.style.overflow = prevOverflow;
|
document.body.style.overflow = prevOverflow;
|
||||||
orientation?.unlock?.();
|
|
||||||
};
|
};
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
@@ -85,22 +39,7 @@ function SignatureOverlay({ open, onCancel, onConfirm }: SignatureOverlayProps)
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="signature-overlay" role="dialog" aria-modal="true">
|
<div className="signature-overlay" role="dialog" aria-modal="true">
|
||||||
{!landscape && (
|
<div className="signature-overlay-stage">
|
||||||
<div className="signature-overlay-rotate">
|
|
||||||
<RotateRightOutlined className="signature-overlay-rotate-icon" />
|
|
||||||
<p className="signature-overlay-rotate-text">请将手机横置以开始签名</p>
|
|
||||||
<p className="signature-overlay-rotate-hint">
|
|
||||||
如果无法旋转,请检查手机是否锁定了竖屏方向
|
|
||||||
</p>
|
|
||||||
<Button onClick={onCancel}>取消</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* SignaturePad stays mounted so its strokes survive accidental rotation flips */}
|
|
||||||
<div
|
|
||||||
className="signature-overlay-stage"
|
|
||||||
style={{ visibility: landscape ? 'visible' : 'hidden' }}
|
|
||||||
aria-hidden={!landscape}
|
|
||||||
>
|
|
||||||
<div className="signature-overlay-bar">
|
<div className="signature-overlay-bar">
|
||||||
<Button type="text" onClick={onCancel}>
|
<Button type="text" onClick={onCancel}>
|
||||||
取消
|
取消
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ function AftersalesConfirmPage() {
|
|||||||
>
|
>
|
||||||
<EditOutlined />
|
<EditOutlined />
|
||||||
<span>点击此处签名</span>
|
<span>点击此处签名</span>
|
||||||
<small>将进入横屏签名页</small>
|
<small>将进入签名页</small>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user