feat(web-water): 水印设置页面开发
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { useState } from 'react';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { Typography } from 'antd';
|
||||
import type { WatermarkPosition } from '@atlas/contracts';
|
||||
import type { WatermarkTemplateConfig } from '@atlas/contracts';
|
||||
|
||||
/** 九宫格位置选项,顺序与编辑器 3x3 网格一致 */
|
||||
export const WATERMARK_POSITION_OPTIONS: Array<{
|
||||
value: WatermarkPosition;
|
||||
label: string;
|
||||
row: 0 | 1 | 2;
|
||||
col: 0 | 1 | 2;
|
||||
}> = [
|
||||
{ value: 'top_left', label: '左上角', row: 0, col: 0 },
|
||||
{ value: 'top_center', label: '上居中', row: 0, col: 1 },
|
||||
{ value: 'top_right', label: '右上角', row: 0, col: 2 },
|
||||
{ value: 'middle_left', label: '左居中', row: 1, col: 0 },
|
||||
{ value: 'center', label: '正居中', row: 1, col: 1 },
|
||||
{ value: 'middle_right', label: '右居中', row: 1, col: 2 },
|
||||
{ value: 'bottom_left', label: '左下角', row: 2, col: 0 },
|
||||
{ value: 'bottom_center', label: '下居中', row: 2, col: 1 },
|
||||
{ value: 'bottom_right', label: '右下角', row: 2, col: 2 },
|
||||
];
|
||||
|
||||
export const watermarkPositionLabel = (position: string): string =>
|
||||
WATERMARK_POSITION_OPTIONS.find((option) => option.value === position)?.label ?? position;
|
||||
|
||||
const POSITION_FLEX: Record<
|
||||
WatermarkPosition,
|
||||
Pick<CSSProperties, 'justifyContent' | 'alignItems'>
|
||||
> = {
|
||||
top_left: { justifyContent: 'flex-start', alignItems: 'flex-start' },
|
||||
top_center: { justifyContent: 'center', alignItems: 'flex-start' },
|
||||
top_right: { justifyContent: 'flex-end', alignItems: 'flex-start' },
|
||||
middle_left: { justifyContent: 'flex-start', alignItems: 'center' },
|
||||
center: { justifyContent: 'center', alignItems: 'center' },
|
||||
middle_right: { justifyContent: 'flex-end', alignItems: 'center' },
|
||||
bottom_left: { justifyContent: 'flex-start', alignItems: 'flex-end' },
|
||||
bottom_center: { justifyContent: 'center', alignItems: 'flex-end' },
|
||||
bottom_right: { justifyContent: 'flex-end', alignItems: 'flex-end' },
|
||||
};
|
||||
|
||||
interface WatermarkPreviewProps {
|
||||
/** 允许传入部分字段:编辑弹窗按当前表单值实时渲染 */
|
||||
config: Partial<WatermarkTemplateConfig>;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按模板 config 在内置演示底图上实时渲染水印效果(docs/api/watermarks-and-assets.md §3.1),
|
||||
* 不调用服务端渲染;图片使用响应中的短时 preview_url,过期时提示重新读取。
|
||||
*/
|
||||
const WatermarkPreview = ({ config, width = 320, height = 420 }: WatermarkPreviewProps) => {
|
||||
const [imageBroken, setImageBroken] = useState(false);
|
||||
const position = config.position ?? 'bottom_right';
|
||||
const flex = POSITION_FLEX[position] ?? POSITION_FLEX.bottom_right;
|
||||
const previewUrl = config.image_asset?.preview_url;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="watermark-preview"
|
||||
style={{ width, height, ...flex, opacity: Number(config.opacity ?? '1') }}
|
||||
>
|
||||
{config.image_asset ? (
|
||||
imageBroken || !previewUrl ? (
|
||||
<Typography.Text type="secondary">图片预览已过期或不可用</Typography.Text>
|
||||
) : (
|
||||
<img
|
||||
src={previewUrl}
|
||||
alt="水印图片"
|
||||
style={{
|
||||
// scale_ratio 以底图短边为基准的视觉近似:1.0 ≈ 底图宽度的 60%
|
||||
width: Math.round(Number(config.scale_ratio ?? '1') * width * 0.6),
|
||||
maxWidth: '80%',
|
||||
}}
|
||||
onError={() => setImageBroken(true)}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<span
|
||||
style={{
|
||||
fontSize: config.font_size_px ?? 24,
|
||||
fontWeight: 600,
|
||||
color: '#111827',
|
||||
whiteSpace: 'nowrap',
|
||||
textShadow: '0 0 2px rgba(255,255,255,0.8)',
|
||||
}}
|
||||
>
|
||||
{config.text_content || '文字水印'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WatermarkPreview;
|
||||
Reference in New Issue
Block a user