集成图片集查看功能
This commit is contained in:
parent
f23f5c554d
commit
42b9910df0
|
@ -30,10 +30,13 @@ export default {
|
|||
type: 'image',
|
||||
label: '图片',
|
||||
name: 'image',
|
||||
popOver: {
|
||||
title: '查看大图',
|
||||
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
|
||||
}
|
||||
enlargeAble: true,
|
||||
title: '233',
|
||||
thumbMode: 'cover'
|
||||
// popOver: {
|
||||
// title: '查看大图',
|
||||
// body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
|
||||
// }
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
|
|
|
@ -4,7 +4,39 @@ export default {
|
|||
data: {
|
||||
id: 1,
|
||||
image:
|
||||
'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg'
|
||||
'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg',
|
||||
images: [
|
||||
{
|
||||
image:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg@s_0,w_216,l_1,f_jpg,q_80',
|
||||
src:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg'
|
||||
},
|
||||
{
|
||||
image:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692942/d8e4992057f9.jpeg@s_0,w_216,l_1,f_jpg,q_80',
|
||||
src:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692942/d8e4992057f9.jpeg'
|
||||
},
|
||||
{
|
||||
image:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693148/1314a2a3d3f6.jpeg@s_0,w_216,l_1,f_jpg,q_80',
|
||||
src:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693148/1314a2a3d3f6.jpeg'
|
||||
},
|
||||
{
|
||||
image:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693379/8f2e79f82be0.jpeg@s_0,w_216,l_1,f_jpg,q_80',
|
||||
src:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693379/8f2e79f82be0.jpeg'
|
||||
},
|
||||
{
|
||||
image:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693566/552b175ef11d.jpeg@s_0,w_216,l_1,f_jpg,q_80',
|
||||
src:
|
||||
'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693566/552b175ef11d.jpeg'
|
||||
}
|
||||
]
|
||||
},
|
||||
body: [
|
||||
{
|
||||
|
@ -112,6 +144,16 @@ export default {
|
|||
originalSrc: '${image}'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'static-images',
|
||||
label: '图片集',
|
||||
name: 'images',
|
||||
thumbMode: 'cover',
|
||||
thumbRatio: '4:3',
|
||||
enlargeAble: true,
|
||||
originalSrc: '${src}' // 注意这个取变量是想对数组成员取的。
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
@keyframes disappear {
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}ImageGallery {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
max-width: 1010px !important;
|
||||
|
||||
&-close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
> svg {
|
||||
width: px2rem(16px);
|
||||
height: px2rem(16px);
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
height: px2rem(30px);
|
||||
vertical-align: top;
|
||||
line-height: px2rem(30px);
|
||||
font-size: px2rem(12px);
|
||||
color: $white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-main {
|
||||
background: #000;
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
|
||||
> img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-prevBtn,
|
||||
&-nextBtn {
|
||||
> svg {
|
||||
width: px2rem(48px);
|
||||
height: px2rem(48px);
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
text-shadow: rgba(0, 0, 0, 0.3) 0px 0px 4px;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 0px 0px 4px;
|
||||
}
|
||||
animation-name: disappear;
|
||||
animation-delay: 3s;
|
||||
animation-duration: 0.35s;
|
||||
animation-fill-mode: both;
|
||||
|
||||
&.is-disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-main:hover &-prevBtn,
|
||||
&-main:hover &-nextBtn {
|
||||
animation-name: appear;
|
||||
animation-delay: 0s;
|
||||
animation-duration: 0.35s;
|
||||
}
|
||||
|
||||
&-prevBtn {
|
||||
left: px2rem(20px);
|
||||
}
|
||||
|
||||
&-nextBtn {
|
||||
right: px2rem(20px);
|
||||
}
|
||||
|
||||
&-footer {
|
||||
height: px2rem(74px);
|
||||
background: #222;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&-prevList,
|
||||
&-nextList {
|
||||
width: px2rem(20px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
color: #fff;
|
||||
|
||||
&.is-disabled {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
color: rgba(255, 255, 255, 0.1);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 1);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&-itemsWrap {
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&-items {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&-item {
|
||||
margin: 10px 5px;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
border: 1px solid #666;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
> img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
@supports (object-fit: cover) {
|
||||
> img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
display: block;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid #e5e5e5;
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border: 1px solid #108cee;
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -219,14 +219,22 @@
|
|||
color: $danger;
|
||||
}
|
||||
|
||||
.#{$ns}Modal--full .#{$ns}Modal-content {
|
||||
.#{$ns}Modal--full {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> .#{$ns}Modal-content {
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
margin: 30px;
|
||||
width: calc(100% - 60px);
|
||||
height: calc(100% - 60px);
|
||||
max-width: unset;
|
||||
margin: px2rem(30px);
|
||||
|
||||
> .#{$ns}Modal-body {
|
||||
height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,7 +230,7 @@
|
|||
}
|
||||
|
||||
&[data-position='left']:hover:after {
|
||||
margin: 0 0 0 $Tooltip--attr-gap;
|
||||
margin: 0 $Tooltip--attr-gap 0 0;
|
||||
}
|
||||
|
||||
&[data-position='top']:after {
|
||||
|
|
|
@ -534,6 +534,7 @@ $Card-actions-onChecked-onHover-bg: $white;
|
|||
@import '../components/wrapper';
|
||||
@import '../components/status';
|
||||
@import '../components/carousel';
|
||||
@import '../components/image-gallery';
|
||||
@import '../components/images';
|
||||
|
||||
@import '../components/form/fieldset';
|
||||
|
|
|
@ -200,6 +200,7 @@ pre {
|
|||
@import '../components/wrapper';
|
||||
@import '../components/status';
|
||||
@import '../components/carousel';
|
||||
@import '../components/image-gallery';
|
||||
@import '../components/images';
|
||||
|
||||
@import '../components/form/fieldset';
|
||||
|
|
|
@ -65,6 +65,7 @@ $Form-input-borderColor: #cfdadd;
|
|||
@import '../components/wrapper';
|
||||
@import '../components/status';
|
||||
@import '../components/carousel';
|
||||
@import '../components/image-gallery';
|
||||
@import '../components/images';
|
||||
|
||||
@import '../components/form/fieldset';
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
import React from 'react';
|
||||
import {themeable, ClassNamesFn} from '../theme';
|
||||
import {autobind} from '../utils/helper';
|
||||
import Modal from './Modal';
|
||||
import {Icon} from './icons';
|
||||
|
||||
export interface ImageGalleryProps {
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface ImageGalleryState {
|
||||
isOpened: boolean;
|
||||
index: number;
|
||||
items: Array<{
|
||||
src: string;
|
||||
originalSrc: string;
|
||||
title?: string;
|
||||
caption?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export class ImageGallery extends React.Component<
|
||||
ImageGalleryProps,
|
||||
ImageGalleryState
|
||||
> {
|
||||
state: ImageGalleryState = {
|
||||
isOpened: false,
|
||||
index: -1,
|
||||
items: []
|
||||
};
|
||||
|
||||
@autobind
|
||||
handleImageEnlarge(info: {
|
||||
src: string;
|
||||
originalSrc: string;
|
||||
list?: Array<{
|
||||
src: string;
|
||||
originalSrc: string;
|
||||
title?: string;
|
||||
caption?: string;
|
||||
}>;
|
||||
title?: string;
|
||||
caption?: string;
|
||||
index?: number;
|
||||
}) {
|
||||
this.setState({
|
||||
isOpened: true,
|
||||
items: info.list ? info.list : [info],
|
||||
index: info.index || 0
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
close() {
|
||||
this.setState({
|
||||
isOpened: false
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
prev() {
|
||||
const index = this.state.index;
|
||||
this.setState({
|
||||
index: index - 1
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
next() {
|
||||
const index = this.state.index;
|
||||
this.setState({
|
||||
index: index + 1
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleItemClick(e: React.MouseEvent<HTMLDivElement>) {
|
||||
const index = parseInt(e.currentTarget.getAttribute('data-index')!, 10);
|
||||
this.setState({
|
||||
index
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {children, classnames: cx} = this.props;
|
||||
const {index, items} = this.state;
|
||||
|
||||
return (
|
||||
<>
|
||||
{React.cloneElement(children as any, {
|
||||
onImageEnlarge: this.handleImageEnlarge
|
||||
})}
|
||||
|
||||
<Modal
|
||||
closeOnEsc
|
||||
size="full"
|
||||
onHide={this.close}
|
||||
show={this.state.isOpened}
|
||||
contentClassName={cx('ImageGallery')}
|
||||
>
|
||||
<a
|
||||
data-tooltip="关闭"
|
||||
data-position="left"
|
||||
className={cx('ImageGallery-close')}
|
||||
onClick={this.close}
|
||||
>
|
||||
<Icon icon="close" />
|
||||
</a>
|
||||
{~index && items[index] ? (
|
||||
<>
|
||||
<div className={cx('ImageGallery-title')}>
|
||||
{items[index].title}
|
||||
</div>
|
||||
<div className={cx('ImageGallery-main')}>
|
||||
<img src={items[index].originalSrc} />
|
||||
|
||||
{items.length > 1 ? (
|
||||
<>
|
||||
<a
|
||||
className={cx(
|
||||
'ImageGallery-prevBtn',
|
||||
index <= 0 ? 'is-disabled' : ''
|
||||
)}
|
||||
onClick={this.prev}
|
||||
>
|
||||
<Icon icon="prev" />
|
||||
</a>
|
||||
<a
|
||||
className={cx(
|
||||
'ImageGallery-nextBtn',
|
||||
index >= items.length - 1 ? 'is-disabled' : ''
|
||||
)}
|
||||
onClick={this.next}
|
||||
>
|
||||
<Icon icon="next" />
|
||||
</a>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
{items.length > 1 ? (
|
||||
<div className={cx('ImageGallery-footer')}>
|
||||
<a className={cx('ImageGallery-prevList is-disabled')}>
|
||||
<Icon icon="prev" />
|
||||
</a>
|
||||
<div className={cx('ImageGallery-itemsWrap')}>
|
||||
<div className={cx('ImageGallery-items')}>
|
||||
{items.map((item, i) => (
|
||||
<div
|
||||
key={i}
|
||||
data-index={i}
|
||||
onClick={this.handleItemClick}
|
||||
className={cx(
|
||||
'ImageGallery-item',
|
||||
i === index ? 'is-active' : ''
|
||||
)}
|
||||
>
|
||||
<img src={item.src} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<a className={cx('ImageGallery-nextList is-disabled')}>
|
||||
<Icon icon="next" />
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(ImageGallery);
|
|
@ -17,6 +17,7 @@ import {ClassNamesFn, themeable} from '../theme';
|
|||
|
||||
export interface ModalProps {
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
size?: any;
|
||||
overlay?: boolean;
|
||||
onHide: () => void;
|
||||
|
@ -83,6 +84,7 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
render() {
|
||||
const {
|
||||
className,
|
||||
contentClassName,
|
||||
children,
|
||||
container,
|
||||
show,
|
||||
|
@ -92,6 +94,7 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
} = this.props;
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<Portal container={container}>
|
||||
<Transition
|
||||
mountOnEnter
|
||||
|
@ -116,7 +119,13 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
{overlay ? (
|
||||
<div className={cx(`${ns}Modal-overlay`, fadeStyles[status])} />
|
||||
) : null}
|
||||
<div className={cx(`${ns}Modal-content`, fadeStyles[status])}>
|
||||
<div
|
||||
className={cx(
|
||||
`${ns}Modal-content`,
|
||||
contentClassName,
|
||||
fadeStyles[status]
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -104,6 +104,8 @@ registerIcon('play', PlayIcon);
|
|||
registerIcon('pause', PauseIcon);
|
||||
registerIcon('left-arrow', LeftArrowIcon);
|
||||
registerIcon('right-arrow', RightArrowIcon);
|
||||
registerIcon('prev', LeftArrowIcon);
|
||||
registerIcon('next', RightArrowIcon);
|
||||
registerIcon('check', CheckIcon);
|
||||
registerIcon('plus', PlusIcon);
|
||||
registerIcon('minus', MinusIcon);
|
||||
|
|
|
@ -38,6 +38,7 @@ import {getTheme, ThemeInstance, ClassNamesFn, ThemeContext} from './theme';
|
|||
import find = require('lodash/find');
|
||||
import Alert from './components/Alert2';
|
||||
import {LazyComponent} from './components';
|
||||
import ImageGallery from './components/ImageGallery';
|
||||
|
||||
export interface TestFunc {
|
||||
(
|
||||
|
@ -383,6 +384,7 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
|||
return (
|
||||
<RootStoreContext.Provider value={rootStore}>
|
||||
<ThemeContext.Provider value={this.props.theme || 'default'}>
|
||||
<ImageGallery>
|
||||
{
|
||||
renderChild(
|
||||
pathPrefix || '',
|
||||
|
@ -403,6 +405,7 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
|||
}
|
||||
) as JSX.Element
|
||||
}
|
||||
</ImageGallery>
|
||||
</ThemeContext.Provider>
|
||||
</RootStoreContext.Provider>
|
||||
);
|
||||
|
|
|
@ -403,6 +403,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
{showCloseButton !== false && !store.loading ? (
|
||||
<a
|
||||
data-tooltip="关闭弹窗"
|
||||
data-position="left"
|
||||
onClick={this.handleSelfClose}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
|
|
|
@ -9,17 +9,11 @@ export interface ImageThumbProps {
|
|||
src: string;
|
||||
originalSrc?: string; // 原图
|
||||
enlargeAble?: boolean;
|
||||
onEnlarge?: (info: {
|
||||
src: string;
|
||||
originalSrc: string;
|
||||
title?: string;
|
||||
caption?: string;
|
||||
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
thumbRatio?: '1:1' | '4:3' | '16:9';
|
||||
}) => void;
|
||||
onEnlarge?: (info: ImageThumbProps) => void;
|
||||
showDimensions?: boolean;
|
||||
title?: string;
|
||||
alt?: string;
|
||||
index?: number;
|
||||
className?: string;
|
||||
imageClassName?: string;
|
||||
caption?: string;
|
||||
|
@ -33,26 +27,8 @@ export interface ImageThumbProps {
|
|||
export class ImageThumb extends React.Component<ImageThumbProps> {
|
||||
@autobind
|
||||
handleEnlarge() {
|
||||
const {
|
||||
onEnlarge,
|
||||
src,
|
||||
originalSrc,
|
||||
title,
|
||||
caption,
|
||||
thumbMode,
|
||||
thumbRatio
|
||||
} = this.props;
|
||||
|
||||
onEnlarge &&
|
||||
originalSrc &&
|
||||
onEnlarge({
|
||||
src,
|
||||
originalSrc,
|
||||
title,
|
||||
caption,
|
||||
thumbMode,
|
||||
thumbRatio
|
||||
});
|
||||
const {onEnlarge, ...rest} = this.props;
|
||||
onEnlarge && onEnlarge(rest);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -123,14 +99,17 @@ export interface ImageFieldProps extends RendererProps {
|
|||
thumbRatio: '1:1' | '4:3' | '16:9';
|
||||
originalSrc?: string; // 原图
|
||||
enlargeAble?: boolean;
|
||||
onEnlarge?: (info: {
|
||||
onImageEnlarge?: (
|
||||
info: {
|
||||
src: string;
|
||||
originalSrc: string;
|
||||
title?: string;
|
||||
caption?: string;
|
||||
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
thumbRatio?: '1:1' | '4:3' | '16:9';
|
||||
}) => void;
|
||||
},
|
||||
target: any
|
||||
) => void;
|
||||
showDimensions?: boolean;
|
||||
}
|
||||
|
||||
|
@ -146,6 +125,31 @@ export class ImageField extends React.Component<ImageFieldProps, object> {
|
|||
placeholder: '-'
|
||||
};
|
||||
|
||||
@autobind
|
||||
handleEnlarge({
|
||||
src,
|
||||
originalSrc,
|
||||
title,
|
||||
caption,
|
||||
thumbMode,
|
||||
thumbRatio
|
||||
}: ImageThumbProps) {
|
||||
const {onImageEnlarge} = this.props;
|
||||
|
||||
onImageEnlarge &&
|
||||
onImageEnlarge(
|
||||
{
|
||||
src,
|
||||
originalSrc: originalSrc || src,
|
||||
title,
|
||||
caption,
|
||||
thumbMode,
|
||||
thumbRatio
|
||||
},
|
||||
this.props
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
|
@ -178,9 +182,9 @@ export class ImageField extends React.Component<ImageFieldProps, object> {
|
|||
caption={filter(imageCaption, data)}
|
||||
thumbMode={thumbMode}
|
||||
thumbRatio={thumbRatio}
|
||||
originalSrc={originalSrc}
|
||||
originalSrc={filter(originalSrc, data, '| raw')}
|
||||
enlargeAble={enlargeAble}
|
||||
onEnlarge={onEnlarge}
|
||||
onEnlarge={this.handleEnlarge}
|
||||
showDimensions={showDimensions}
|
||||
/>
|
||||
) : (
|
||||
|
|
|
@ -2,7 +2,8 @@ import React from 'react';
|
|||
import {Renderer, RendererProps} from '../factory';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {resolveVariable, isPureVariable} from '../utils/tpl-builtin';
|
||||
import Image from './Image';
|
||||
import Image, {ImageThumbProps} from './Image';
|
||||
import {autobind} from '../utils/helper';
|
||||
|
||||
export interface ImagesProps extends RendererProps {
|
||||
className: string;
|
||||
|
@ -10,11 +11,22 @@ export interface ImagesProps extends RendererProps {
|
|||
placeholder: string;
|
||||
delimiter: string;
|
||||
thumbMode: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
thumbRatio: '1-1' | '4-3' | '16-9';
|
||||
thumbRatio: '1:1' | '4:3' | '16:9';
|
||||
|
||||
name?: string;
|
||||
value?: any;
|
||||
source?: string;
|
||||
src?: string;
|
||||
originalSrc?: string; // 原图
|
||||
enlargeAble?: boolean;
|
||||
onEnlarge?: (
|
||||
info: ImageThumbProps & {
|
||||
list?: Array<
|
||||
Pick<ImageThumbProps, 'src' | 'originalSrc' | 'title' | 'caption'>
|
||||
>;
|
||||
}
|
||||
) => void;
|
||||
showDimensions?: boolean;
|
||||
}
|
||||
|
||||
export class ImagesField extends React.Component<ImagesProps> {
|
||||
|
@ -33,9 +45,35 @@ export class ImagesField extends React.Component<ImagesProps> {
|
|||
'https://fex.bdstatic.com/n/static/amis/renderers/crud/field/placeholder_cfad9b1.png',
|
||||
placehoder: '-',
|
||||
thumbMode: 'contain',
|
||||
thumbRatio: '1-1'
|
||||
thumbRatio: '1:1'
|
||||
};
|
||||
|
||||
list: Array<any> = [];
|
||||
|
||||
@autobind
|
||||
handleEnlarge(info: ImageThumbProps) {
|
||||
const {onImageEnlarge, src, originalSrc} = this.props;
|
||||
|
||||
onImageEnlarge &&
|
||||
onImageEnlarge(
|
||||
{
|
||||
...info,
|
||||
originalSrc: info.originalSrc || info.src,
|
||||
list: this.list.map(item => ({
|
||||
src: src
|
||||
? filter(src, item, '| raw')
|
||||
: (item && item.image) || item,
|
||||
originalSrc: originalSrc
|
||||
? filter(originalSrc, item, '| raw')
|
||||
: item && item.src,
|
||||
title: item && item.title,
|
||||
caption: item && (item.description || item.caption)
|
||||
}))
|
||||
},
|
||||
this.props
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
|
@ -48,7 +86,10 @@ export class ImagesField extends React.Component<ImagesProps> {
|
|||
placeholder,
|
||||
classnames: cx,
|
||||
source,
|
||||
delimiter
|
||||
delimiter,
|
||||
enlargeAble,
|
||||
src,
|
||||
originalSrc
|
||||
} = this.props;
|
||||
|
||||
let list: any;
|
||||
|
@ -67,19 +108,33 @@ export class ImagesField extends React.Component<ImagesProps> {
|
|||
list = [list];
|
||||
}
|
||||
|
||||
this.list = list;
|
||||
|
||||
return (
|
||||
<div className={cx('ImagesField', className)}>
|
||||
{Array.isArray(list) ? (
|
||||
<div className={cx('Images')}>
|
||||
{list.map((item: any, index: number) => (
|
||||
<Image
|
||||
index={index}
|
||||
className={cx('Images-item')}
|
||||
key={index}
|
||||
src={(item && item.image) || item}
|
||||
src={
|
||||
src
|
||||
? filter(src, item, '| raw')
|
||||
: (item && item.image) || item
|
||||
}
|
||||
originalSrc={
|
||||
originalSrc
|
||||
? filter(originalSrc, item, '| raw')
|
||||
: item && item.src
|
||||
}
|
||||
title={item && item.title}
|
||||
description={item && item.description}
|
||||
caption={item && (item.description || item.caption)}
|
||||
thumbMode={thumbMode}
|
||||
thumbRatio={thumbRatio}
|
||||
enlargeAble={enlargeAble!}
|
||||
onEnlarge={this.handleEnlarge}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -89,6 +89,7 @@ export interface TableProps extends RendererProps {
|
|||
) => void;
|
||||
onSaveOrder?: (moved: Array<object>, items: Array<object>) => void;
|
||||
onQuery: (values: object) => void;
|
||||
onImageEnlarge?: (data: any, target: any) => void;
|
||||
buildItemProps?: (item: any, index: number) => any;
|
||||
checkOnItemClick?: boolean;
|
||||
hideCheckToggler?: boolean;
|
||||
|
@ -860,6 +861,48 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleImageEnlarge(info: any, target: {rowIndex: number; colIndex: number}) {
|
||||
const onImageEnlarge = this.props.onImageEnlarge;
|
||||
|
||||
// 如果已经是多张了,直接跳过
|
||||
if (Array.isArray(info.list)) {
|
||||
return onImageEnlarge && onImageEnlarge(info, target);
|
||||
}
|
||||
|
||||
// 从列表中收集所有图片,然后作为一个图片集合派送出去。
|
||||
const store = this.props.store;
|
||||
const column = store.filteredColumns[target.colIndex].pristine;
|
||||
|
||||
const list: Array<any> = [];
|
||||
store.rows.forEach(row => {
|
||||
const src = resolveVariable(column.name, row.data);
|
||||
|
||||
list.push({
|
||||
src,
|
||||
originalSrc: column.originalSrc
|
||||
? filter(column.originalSrc, row.data)
|
||||
: src,
|
||||
title: column.title ? filter(column.title, row.data) : undefined,
|
||||
caption: column.caption ? filter(column.caption, row.data) : undefined
|
||||
});
|
||||
});
|
||||
|
||||
if (list.length > 1) {
|
||||
onImageEnlarge &&
|
||||
onImageEnlarge(
|
||||
{
|
||||
...info,
|
||||
list,
|
||||
index: target.rowIndex
|
||||
},
|
||||
target
|
||||
);
|
||||
} else {
|
||||
onImageEnlarge && onImageEnlarge(info, target);
|
||||
}
|
||||
}
|
||||
|
||||
renderHeading() {
|
||||
let {
|
||||
title,
|
||||
|
@ -1186,7 +1229,8 @@ export default class Table extends React.Component<TableProps, object> {
|
|||
popOverContainer: this.getPopOverContainer,
|
||||
rowSpan: item.rowSpans[column.name as string],
|
||||
quickEditFormRef: this.subFormRef,
|
||||
prefix
|
||||
prefix,
|
||||
onImageEnlarge: this.handleImageEnlarge
|
||||
};
|
||||
delete subProps.label;
|
||||
|
||||
|
|
Loading…
Reference in New Issue