Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 添加抽奖组件 #11476

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/zh-CN/components/lottery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Lottery 九宫格抽奖
description:
type: 0
group: ⚙ 组件
menuName: Lottery 九宫格抽奖
icon:
order: 27
---
bawawa marked this conversation as resolved.
Show resolved Hide resolved
55 changes: 42 additions & 13 deletions examples/components/Index.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
import Outline from '../../packages/amis-editor-core/static/outline.png';
export default {
type: 'page',
title: '标题',
remark: {
title: '标题',
body: '这是一段描述问题,注意到了没,还可以设置标题。而且只有点击了才弹出来。',
icon: 'question-mark',
placement: 'right',
trigger: 'click',
rootClose: true
},
body: '内容部分. 可以使用 \\${var} 获取变量。如: `\\$date`: ${date}',
aside: '边栏部分',
toolbar: '工具栏',
initApi: '/api/mock2/page/initData'

body: {
type: 'lottery',
width: '600',
height: '600',
items: [
{
name: "商品名称名称1",
pictureUrl: Outline,
},
{
name: "没有中奖哦2",
pictureUrl: Outline,
},
{
name: "商品名称名称3",
pictureUrl: Outline,
},
{
name: "商品名称名称4",
pictureUrl: Outline,
},
{
name: "商品名称名称5",
pictureUrl: Outline,
},
{
name: "祥禾饽饽铺京东自营旗舰店6",
pictureUrl: Outline,
},
{
name: "鲜花4+1束 鲜花速递7 ",
pictureUrl: Outline,
},
{
name: "大连萨米托爱心樱桃8",
pictureUrl: Outline,
},
]
}

};
94 changes: 94 additions & 0 deletions packages/amis-ui/scss/components/_lottery.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
@keyframes switch-light {
from {
background-image: url("https://aipage.bce.baidu.com/resources/sys/img/lottery/light.png");
bawawa marked this conversation as resolved.
Show resolved Hide resolved
}
to {
background-image: url("https://aipage.bce.baidu.com/resources/sys/img/lottery/light-2.png");
}
}

.#{$ns}Lottery {
position: relative;
padding: 10px;
box-sizing: content-box;
background-color: #fdd130;
background-size: 100% 100%;
animation: switch-light 0.3s infinite;

.luckNineWrap {
box-sizing: content-box;
display: -webkit-flex;
display: flex;
justify-content: space-around;
align-content: space-around;
position: absolute;
background: #ffa00a;
padding: 5px;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 90%;
height: 90%;
flex-wrap: wrap;
-webkit-flex-wrap: wrap;
border-radius: 10px;
overflow: hidden;
background-size: 100% 100%;
transition: all .05s ease;

.active {
background-image: linear-gradient(#f69d7c, #f46c72) !important;

.luckNineItem-title {
color: #fff !important;
}
}

.luckNineItem {
border-radius: 5px;
bawawa marked this conversation as resolved.
Show resolved Hide resolved
padding: 5px;
background-image: linear-gradient(#ffefd1, #ffc8a4);
display: flex;
flex-direction: column;
justify-content: center;
width: 28%;
height: 28%;
align-items: center;
transition: all .05s ease;

.luckNineItem-title {
margin-top: 2px;
font-size: 12px;
font-weight: bold;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 70px;
height: 16px;
text-align: center;
color: #be602b;
}

.luckNineItem-img {
width: 60%;
height: 60%;
}
}

.startBtn {
cursor: pointer;
background-image: linear-gradient(#ff733e, #ff4e57);
color: rgba(255, 212, 167, 1);
font-size: 26px;
font-weight: bold;
transition: all 1s ease-in;
}

.startBtn:hover {
background-image: linear-gradient(#f69d7c, #f46c72);
transition: all 1s ease-in;
}
}
}
2 changes: 2 additions & 0 deletions packages/amis-ui/scss/themes/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,5 @@
@import '../components/verificationCode';

@import '../components/mobile-dev-tool';

@import '../components/lottery';
191 changes: 191 additions & 0 deletions packages/amis-ui/src/components/Lottery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import React from 'react';
import {themeable, ThemeProps} from 'amis-core';

let now = 0;
let count = 0;
let timer: null | NodeJS.Timer = null;
let speed = 50;
bawawa marked this conversation as resolved.
Show resolved Hide resolved

interface SquareNineProps extends ThemeProps {
//宽度,默认300px
width?: number;
//高度,默认300px
height?: number;
//奖品列表
items: {name: string; pictureUrl: string; id: number}[];
// 开始按钮
children?: React.ReactNode;
//目标索引(中奖)
targetIndex?: number;
// 结束回调
callback?: (index: number) => void;
}

interface CallBackFn {
(now: number): number;
}

interface SquareNineState {
width: number;
height: number;
off: 0 | 1;
}

interface CustomElement extends HTMLElement {
start: (index: number, fn: CallBackFn) => void;
reset: () => void;
flag: 0 | 1;
}

export class Lottery extends React.Component<SquareNineProps, SquareNineState> {
lightRef: React.RefObject<CustomElement> = React.createRef();

constructor(props: SquareNineProps) {
super(props);
this.state = {
width: this.props.width || 300,
height: this.props.height || 300,
off: 1
};
}

start = (index: number, fn?: CallBackFn) => {
//开始抽奖
if (!this.state.off) return;
this.setState({off: 0});
this.changeFn(index, fn);
};

//重置抽奖状态
reset = () => {
this.setState({off: 1});
now = 0;
timer && clearTimeout(timer as unknown as number);
};

componentDidMount() {
if (this.lightRef.current) {
this.lightRef.current.start = this.start;
this.lightRef.current.reset = this.reset;
this.lightRef.current.flag = this.state.off;
}
}

componentDidUpdate(prevProps: SquareNineProps, prevState: SquareNineState) {
if (this.lightRef.current && prevState.off !== this.state.off) {
this.lightRef.current.flag = this.state.off;
}
}

//抽奖动画效果
changeFn = (index: number, fn?: CallBackFn) => {
let _item = document.querySelectorAll('.luckNineWrap .luckNineItem');
bawawa marked this conversation as resolved.
Show resolved Hide resolved
now = ++now % (_item.length - 1);
now == 0 && count++;
_item.forEach((res: HTMLElement) => {
Number(res.dataset.index) == now
? res.classList.add('active')
: res.classList.remove('active');
});
timer = setTimeout(() => {
this.changeFn(index, fn);
}, speed);
if (count > 3) speed += 10;
if (speed > 300 && now == index) {
timer && clearTimeout(timer);
count = 0;
speed = 50;
this.setState({off: 1});
fn && fn(now);
this.props.callback && this.props.callback(now);
}
};

render() {
const {width, height} = this.state;
const {classnames: cx} = this.props;
return (
<div
className={cx('Lottery light')}
ref={this.lightRef as any}
style={{width: width + 'px', height: height + 'px'}}
>
<div className="luckNineWrap">
<div className="luckNineItem" data-index="0">
<img
className="luckNineItem-img"
src={this.props.items[0].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[0].name}</div>
</div>
<div className="luckNineItem" data-index="1">
<img
className="luckNineItem-img"
src={this.props.items[1].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[1].name}</div>
</div>
<div className="luckNineItem" data-index="2">
<img
className="luckNineItem-img"
src={this.props.items[2].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[2].name}</div>
</div>
<div className="luckNineItem" data-index="7">
<img
className="luckNineItem-img"
src={this.props.items[7].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[7].name}</div>
</div>
<div
className="luckNineItem startBtn"
data-index="8"
onClick={() => this.start(this.props.targetIndex || 0)}
>
{this.props.children ? this.props.children : <span>开始</span>}
</div>
<div className="luckNineItem" data-index="3">
<img
className="luckNineItem-img"
src={this.props.items[3].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[3].name}</div>
</div>
<div className="luckNineItem" data-index="6">
<img
className="luckNineItem-img"
src={this.props.items[6].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[6].name}</div>
</div>
<div className="luckNineItem" data-index="5">
<img
className="luckNineItem-img"
src={this.props.items[5].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[5].name}</div>
</div>
<div className="luckNineItem" data-index="4">
<img
className="luckNineItem-img"
src={this.props.items[5].pictureUrl}
alt="奖品图片"
/>
<div className="luckNineItem-title">{this.props.items[5].name}</div>
</div>
</div>
</div>
);
}
}

export default themeable(Lottery);
4 changes: 3 additions & 1 deletion packages/amis-ui/src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ import VerificationCode from './VerificationCode';
import Shape from './Shape';
import type {IShapeType} from './Shape';
import MobileDevTool from './MobileDevTool';
import {Lottery} from './Lottery';

export {
NotFound,
Expand Down Expand Up @@ -287,5 +288,6 @@ export {
VerificationCode,
Shape,
IShapeType,
MobileDevTool
MobileDevTool,
Lottery
};
Loading