集成图片集查看功能
This commit is contained in:
parent
f23f5c554d
commit
42b9910df0
|
@ -30,10 +30,13 @@ export default {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
label: '图片',
|
label: '图片',
|
||||||
name: 'image',
|
name: 'image',
|
||||||
popOver: {
|
enlargeAble: true,
|
||||||
title: '查看大图',
|
title: '233',
|
||||||
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
|
thumbMode: 'cover'
|
||||||
}
|
// popOver: {
|
||||||
|
// title: '查看大图',
|
||||||
|
// body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'date',
|
name: 'date',
|
||||||
|
|
|
@ -4,7 +4,39 @@ export default {
|
||||||
data: {
|
data: {
|
||||||
id: 1,
|
id: 1,
|
||||||
image:
|
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: [
|
body: [
|
||||||
{
|
{
|
||||||
|
@ -112,6 +144,16 @@ export default {
|
||||||
originalSrc: '${image}'
|
originalSrc: '${image}'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
type: 'static-images',
|
||||||
|
label: '图片集',
|
||||||
|
name: 'images',
|
||||||
|
thumbMode: 'cover',
|
||||||
|
thumbRatio: '4:3',
|
||||||
|
enlargeAble: true,
|
||||||
|
originalSrc: '${src}' // 注意这个取变量是想对数组成员取的。
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
type: 'divider'
|
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;
|
color: $danger;
|
||||||
}
|
}
|
||||||
|
|
||||||
.#{$ns}Modal--full .#{$ns}Modal-content {
|
.#{$ns}Modal--full {
|
||||||
width: calc(100% - 60px);
|
display: flex;
|
||||||
height: calc(100% - 60px);
|
flex-direction: column;
|
||||||
max-width: unset;
|
justify-content: center;
|
||||||
margin: px2rem(30px);
|
align-items: center;
|
||||||
|
|
||||||
> .#{$ns}Modal-body {
|
> .#{$ns}Modal-content {
|
||||||
height: 0;
|
flex-basis: 0;
|
||||||
overflow: auto;
|
flex-grow: 1;
|
||||||
|
margin: 30px;
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
max-width: unset;
|
||||||
|
|
||||||
|
> .#{$ns}Modal-body {
|
||||||
|
height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,7 +230,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-position='left']:hover:after {
|
&[data-position='left']:hover:after {
|
||||||
margin: 0 0 0 $Tooltip--attr-gap;
|
margin: 0 $Tooltip--attr-gap 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-position='top']:after {
|
&[data-position='top']:after {
|
||||||
|
|
|
@ -534,6 +534,7 @@ $Card-actions-onChecked-onHover-bg: $white;
|
||||||
@import '../components/wrapper';
|
@import '../components/wrapper';
|
||||||
@import '../components/status';
|
@import '../components/status';
|
||||||
@import '../components/carousel';
|
@import '../components/carousel';
|
||||||
|
@import '../components/image-gallery';
|
||||||
@import '../components/images';
|
@import '../components/images';
|
||||||
|
|
||||||
@import '../components/form/fieldset';
|
@import '../components/form/fieldset';
|
||||||
|
|
|
@ -200,6 +200,7 @@ pre {
|
||||||
@import '../components/wrapper';
|
@import '../components/wrapper';
|
||||||
@import '../components/status';
|
@import '../components/status';
|
||||||
@import '../components/carousel';
|
@import '../components/carousel';
|
||||||
|
@import '../components/image-gallery';
|
||||||
@import '../components/images';
|
@import '../components/images';
|
||||||
|
|
||||||
@import '../components/form/fieldset';
|
@import '../components/form/fieldset';
|
||||||
|
|
|
@ -65,6 +65,7 @@ $Form-input-borderColor: #cfdadd;
|
||||||
@import '../components/wrapper';
|
@import '../components/wrapper';
|
||||||
@import '../components/status';
|
@import '../components/status';
|
||||||
@import '../components/carousel';
|
@import '../components/carousel';
|
||||||
|
@import '../components/image-gallery';
|
||||||
@import '../components/images';
|
@import '../components/images';
|
||||||
|
|
||||||
@import '../components/form/fieldset';
|
@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 {
|
export interface ModalProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
contentClassName?: string;
|
||||||
size?: any;
|
size?: any;
|
||||||
overlay?: boolean;
|
overlay?: boolean;
|
||||||
onHide: () => void;
|
onHide: () => void;
|
||||||
|
@ -83,6 +84,7 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
className,
|
className,
|
||||||
|
contentClassName,
|
||||||
children,
|
children,
|
||||||
container,
|
container,
|
||||||
show,
|
show,
|
||||||
|
@ -92,6 +94,7 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
// @ts-ignore
|
||||||
<Portal container={container}>
|
<Portal container={container}>
|
||||||
<Transition
|
<Transition
|
||||||
mountOnEnter
|
mountOnEnter
|
||||||
|
@ -116,7 +119,13 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
||||||
{overlay ? (
|
{overlay ? (
|
||||||
<div className={cx(`${ns}Modal-overlay`, fadeStyles[status])} />
|
<div className={cx(`${ns}Modal-overlay`, fadeStyles[status])} />
|
||||||
) : null}
|
) : null}
|
||||||
<div className={cx(`${ns}Modal-content`, fadeStyles[status])}>
|
<div
|
||||||
|
className={cx(
|
||||||
|
`${ns}Modal-content`,
|
||||||
|
contentClassName,
|
||||||
|
fadeStyles[status]
|
||||||
|
)}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -104,6 +104,8 @@ registerIcon('play', PlayIcon);
|
||||||
registerIcon('pause', PauseIcon);
|
registerIcon('pause', PauseIcon);
|
||||||
registerIcon('left-arrow', LeftArrowIcon);
|
registerIcon('left-arrow', LeftArrowIcon);
|
||||||
registerIcon('right-arrow', RightArrowIcon);
|
registerIcon('right-arrow', RightArrowIcon);
|
||||||
|
registerIcon('prev', LeftArrowIcon);
|
||||||
|
registerIcon('next', RightArrowIcon);
|
||||||
registerIcon('check', CheckIcon);
|
registerIcon('check', CheckIcon);
|
||||||
registerIcon('plus', PlusIcon);
|
registerIcon('plus', PlusIcon);
|
||||||
registerIcon('minus', MinusIcon);
|
registerIcon('minus', MinusIcon);
|
||||||
|
|
|
@ -38,6 +38,7 @@ import {getTheme, ThemeInstance, ClassNamesFn, ThemeContext} from './theme';
|
||||||
import find = require('lodash/find');
|
import find = require('lodash/find');
|
||||||
import Alert from './components/Alert2';
|
import Alert from './components/Alert2';
|
||||||
import {LazyComponent} from './components';
|
import {LazyComponent} from './components';
|
||||||
|
import ImageGallery from './components/ImageGallery';
|
||||||
|
|
||||||
export interface TestFunc {
|
export interface TestFunc {
|
||||||
(
|
(
|
||||||
|
@ -383,26 +384,28 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
||||||
return (
|
return (
|
||||||
<RootStoreContext.Provider value={rootStore}>
|
<RootStoreContext.Provider value={rootStore}>
|
||||||
<ThemeContext.Provider value={this.props.theme || 'default'}>
|
<ThemeContext.Provider value={this.props.theme || 'default'}>
|
||||||
{
|
<ImageGallery>
|
||||||
renderChild(
|
{
|
||||||
pathPrefix || '',
|
renderChild(
|
||||||
isPlainObject(schema)
|
pathPrefix || '',
|
||||||
? {
|
isPlainObject(schema)
|
||||||
type: 'page',
|
? {
|
||||||
...(schema as Schema)
|
type: 'page',
|
||||||
}
|
...(schema as Schema)
|
||||||
: schema,
|
}
|
||||||
{
|
: schema,
|
||||||
...rest,
|
{
|
||||||
resolveDefinitions: this.resolveDefinitions,
|
...rest,
|
||||||
location: location,
|
resolveDefinitions: this.resolveDefinitions,
|
||||||
data: finalData,
|
location: location,
|
||||||
env,
|
data: finalData,
|
||||||
classnames: theme.classnames,
|
env,
|
||||||
classPrefix: theme.classPrefix
|
classnames: theme.classnames,
|
||||||
}
|
classPrefix: theme.classPrefix
|
||||||
) as JSX.Element
|
}
|
||||||
}
|
) as JSX.Element
|
||||||
|
}
|
||||||
|
</ImageGallery>
|
||||||
</ThemeContext.Provider>
|
</ThemeContext.Provider>
|
||||||
</RootStoreContext.Provider>
|
</RootStoreContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -403,6 +403,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
||||||
{showCloseButton !== false && !store.loading ? (
|
{showCloseButton !== false && !store.loading ? (
|
||||||
<a
|
<a
|
||||||
data-tooltip="关闭弹窗"
|
data-tooltip="关闭弹窗"
|
||||||
|
data-position="left"
|
||||||
onClick={this.handleSelfClose}
|
onClick={this.handleSelfClose}
|
||||||
className={cx('Modal-close')}
|
className={cx('Modal-close')}
|
||||||
>
|
>
|
||||||
|
|
|
@ -9,17 +9,11 @@ export interface ImageThumbProps {
|
||||||
src: string;
|
src: string;
|
||||||
originalSrc?: string; // 原图
|
originalSrc?: string; // 原图
|
||||||
enlargeAble?: boolean;
|
enlargeAble?: boolean;
|
||||||
onEnlarge?: (info: {
|
onEnlarge?: (info: ImageThumbProps) => void;
|
||||||
src: string;
|
|
||||||
originalSrc: string;
|
|
||||||
title?: string;
|
|
||||||
caption?: string;
|
|
||||||
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
|
||||||
thumbRatio?: '1:1' | '4:3' | '16:9';
|
|
||||||
}) => void;
|
|
||||||
showDimensions?: boolean;
|
showDimensions?: boolean;
|
||||||
title?: string;
|
title?: string;
|
||||||
alt?: string;
|
alt?: string;
|
||||||
|
index?: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
imageClassName?: string;
|
imageClassName?: string;
|
||||||
caption?: string;
|
caption?: string;
|
||||||
|
@ -33,26 +27,8 @@ export interface ImageThumbProps {
|
||||||
export class ImageThumb extends React.Component<ImageThumbProps> {
|
export class ImageThumb extends React.Component<ImageThumbProps> {
|
||||||
@autobind
|
@autobind
|
||||||
handleEnlarge() {
|
handleEnlarge() {
|
||||||
const {
|
const {onEnlarge, ...rest} = this.props;
|
||||||
onEnlarge,
|
onEnlarge && onEnlarge(rest);
|
||||||
src,
|
|
||||||
originalSrc,
|
|
||||||
title,
|
|
||||||
caption,
|
|
||||||
thumbMode,
|
|
||||||
thumbRatio
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
onEnlarge &&
|
|
||||||
originalSrc &&
|
|
||||||
onEnlarge({
|
|
||||||
src,
|
|
||||||
originalSrc,
|
|
||||||
title,
|
|
||||||
caption,
|
|
||||||
thumbMode,
|
|
||||||
thumbRatio
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -123,14 +99,17 @@ export interface ImageFieldProps extends RendererProps {
|
||||||
thumbRatio: '1:1' | '4:3' | '16:9';
|
thumbRatio: '1:1' | '4:3' | '16:9';
|
||||||
originalSrc?: string; // 原图
|
originalSrc?: string; // 原图
|
||||||
enlargeAble?: boolean;
|
enlargeAble?: boolean;
|
||||||
onEnlarge?: (info: {
|
onImageEnlarge?: (
|
||||||
src: string;
|
info: {
|
||||||
originalSrc: string;
|
src: string;
|
||||||
title?: string;
|
originalSrc: string;
|
||||||
caption?: string;
|
title?: string;
|
||||||
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
caption?: string;
|
||||||
thumbRatio?: '1:1' | '4:3' | '16:9';
|
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||||
}) => void;
|
thumbRatio?: '1:1' | '4:3' | '16:9';
|
||||||
|
},
|
||||||
|
target: any
|
||||||
|
) => void;
|
||||||
showDimensions?: boolean;
|
showDimensions?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +125,31 @@ export class ImageField extends React.Component<ImageFieldProps, object> {
|
||||||
placeholder: '-'
|
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() {
|
render() {
|
||||||
const {
|
const {
|
||||||
className,
|
className,
|
||||||
|
@ -178,9 +182,9 @@ export class ImageField extends React.Component<ImageFieldProps, object> {
|
||||||
caption={filter(imageCaption, data)}
|
caption={filter(imageCaption, data)}
|
||||||
thumbMode={thumbMode}
|
thumbMode={thumbMode}
|
||||||
thumbRatio={thumbRatio}
|
thumbRatio={thumbRatio}
|
||||||
originalSrc={originalSrc}
|
originalSrc={filter(originalSrc, data, '| raw')}
|
||||||
enlargeAble={enlargeAble}
|
enlargeAble={enlargeAble}
|
||||||
onEnlarge={onEnlarge}
|
onEnlarge={this.handleEnlarge}
|
||||||
showDimensions={showDimensions}
|
showDimensions={showDimensions}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -2,7 +2,8 @@ import React from 'react';
|
||||||
import {Renderer, RendererProps} from '../factory';
|
import {Renderer, RendererProps} from '../factory';
|
||||||
import {filter} from '../utils/tpl';
|
import {filter} from '../utils/tpl';
|
||||||
import {resolveVariable, isPureVariable} from '../utils/tpl-builtin';
|
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 {
|
export interface ImagesProps extends RendererProps {
|
||||||
className: string;
|
className: string;
|
||||||
|
@ -10,11 +11,22 @@ export interface ImagesProps extends RendererProps {
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
delimiter: string;
|
delimiter: string;
|
||||||
thumbMode: 'w-full' | 'h-full' | 'contain' | 'cover';
|
thumbMode: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||||
thumbRatio: '1-1' | '4-3' | '16-9';
|
thumbRatio: '1:1' | '4:3' | '16:9';
|
||||||
|
|
||||||
name?: string;
|
name?: string;
|
||||||
value?: any;
|
value?: any;
|
||||||
source?: string;
|
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> {
|
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',
|
'https://fex.bdstatic.com/n/static/amis/renderers/crud/field/placeholder_cfad9b1.png',
|
||||||
placehoder: '-',
|
placehoder: '-',
|
||||||
thumbMode: 'contain',
|
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() {
|
render() {
|
||||||
const {
|
const {
|
||||||
className,
|
className,
|
||||||
|
@ -48,7 +86,10 @@ export class ImagesField extends React.Component<ImagesProps> {
|
||||||
placeholder,
|
placeholder,
|
||||||
classnames: cx,
|
classnames: cx,
|
||||||
source,
|
source,
|
||||||
delimiter
|
delimiter,
|
||||||
|
enlargeAble,
|
||||||
|
src,
|
||||||
|
originalSrc
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let list: any;
|
let list: any;
|
||||||
|
@ -67,19 +108,33 @@ export class ImagesField extends React.Component<ImagesProps> {
|
||||||
list = [list];
|
list = [list];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.list = list;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx('ImagesField', className)}>
|
<div className={cx('ImagesField', className)}>
|
||||||
{Array.isArray(list) ? (
|
{Array.isArray(list) ? (
|
||||||
<div className={cx('Images')}>
|
<div className={cx('Images')}>
|
||||||
{list.map((item: any, index: number) => (
|
{list.map((item: any, index: number) => (
|
||||||
<Image
|
<Image
|
||||||
|
index={index}
|
||||||
className={cx('Images-item')}
|
className={cx('Images-item')}
|
||||||
key={index}
|
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}
|
title={item && item.title}
|
||||||
description={item && item.description}
|
caption={item && (item.description || item.caption)}
|
||||||
thumbMode={thumbMode}
|
thumbMode={thumbMode}
|
||||||
thumbRatio={thumbRatio}
|
thumbRatio={thumbRatio}
|
||||||
|
enlargeAble={enlargeAble!}
|
||||||
|
onEnlarge={this.handleEnlarge}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -89,6 +89,7 @@ export interface TableProps extends RendererProps {
|
||||||
) => void;
|
) => void;
|
||||||
onSaveOrder?: (moved: Array<object>, items: Array<object>) => void;
|
onSaveOrder?: (moved: Array<object>, items: Array<object>) => void;
|
||||||
onQuery: (values: object) => void;
|
onQuery: (values: object) => void;
|
||||||
|
onImageEnlarge?: (data: any, target: any) => void;
|
||||||
buildItemProps?: (item: any, index: number) => any;
|
buildItemProps?: (item: any, index: number) => any;
|
||||||
checkOnItemClick?: boolean;
|
checkOnItemClick?: boolean;
|
||||||
hideCheckToggler?: 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() {
|
renderHeading() {
|
||||||
let {
|
let {
|
||||||
title,
|
title,
|
||||||
|
@ -1186,7 +1229,8 @@ export default class Table extends React.Component<TableProps, object> {
|
||||||
popOverContainer: this.getPopOverContainer,
|
popOverContainer: this.getPopOverContainer,
|
||||||
rowSpan: item.rowSpans[column.name as string],
|
rowSpan: item.rowSpans[column.name as string],
|
||||||
quickEditFormRef: this.subFormRef,
|
quickEditFormRef: this.subFormRef,
|
||||||
prefix
|
prefix,
|
||||||
|
onImageEnlarge: this.handleImageEnlarge
|
||||||
};
|
};
|
||||||
delete subProps.label;
|
delete subProps.label;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue