Browse Source

dev: 添加悬赏系列组件

Roxas 4 years ago
parent
commit
66a6b23788
27 changed files with 449 additions and 187 deletions
  1. 1
    1
      .storybook/config.js
  2. 1
    0
      .storybook/preview-head.html
  3. 1
    1
      rollup.config.js
  4. 42
    0
      src/components/Common/Modal/Modal.less
  5. 51
    0
      src/components/Common/Modal/index.tsx
  6. 3
    0
      src/components/Common/Utils/utils.ts
  7. 2
    0
      src/components/Common/index.ts
  8. 1
    1
      src/components/Payment/AllocWantedModal/AllocWantedModal.less
  9. 94
    82
      src/components/Payment/AllocWantedModal/index.tsx
  10. 1
    1
      src/components/Payment/ConsumeListView/ConsumeListView.less
  11. 1
    1
      src/components/Payment/ConsumeListView/index.tsx
  12. 0
    1
      src/components/Payment/PriceOptions/PriceOptions.less
  13. 17
    6
      src/components/Payment/PriceOptions/index.tsx
  14. 1
    1
      src/components/Payment/Utils/utils.ts
  15. 1
    1
      src/components/Payment/WaitPayInfoView/index.tsx
  16. 0
    0
      src/components/Payment/WantedPublishPopover/WantedPublishPopover.less
  17. 15
    14
      src/components/Payment/WantedPublishPopover/index.tsx
  18. 0
    0
      src/components/Payment/WantedPublishView/WantedPublishView.less
  19. 13
    10
      src/components/Payment/WantedPublishView/index.tsx
  20. BIN
      src/components/Payment/assets/cover_wanted@2x.png
  21. 0
    0
      src/components/Payment/assets/icon/btn_toggle.png
  22. BIN
      src/components/Payment/assets/icon/close.png
  23. BIN
      src/components/Payment/assets/icon/close@2x.png
  24. 0
    0
      src/components/Payment/assets/icon/icon-info-blue@2x.svg
  25. 0
    0
      src/components/Payment/assets/icon/popovers_list_huangguan.png
  26. 4
    1
      src/components/Payment/index.ts
  27. 200
    66
      stories/Payment.stories.tsx

+ 1
- 1
.storybook/config.js View File

@@ -6,7 +6,7 @@ import { withConsole } from '@storybook/addon-console';
6 6
 import bilingoTheme from './bilingoTheme';
7 7
 
8 8
 import 'antd/dist/antd.less';
9
- 
9
+
10 10
 addParameters({
11 11
   info: { inline: true },
12 12
   viewport: {

+ 1
- 0
.storybook/preview-head.html View File

@@ -0,0 +1 @@
1
+<link rel="stylesheet" href="//at.alicdn.com/t/font_1158309_1tkgtp97s75.css" />

+ 1
- 1
rollup.config.js View File

@@ -133,7 +133,7 @@ export default {
133 133
       entries: [
134 134
         { find: '@', replacement: 'src' },
135 135
         { find: '@components', replacement: 'src/components' },
136
-      ]
136
+      ],
137 137
     }),
138 138
     visualizer({
139 139
       sourcemap: true,

+ 42
- 0
src/components/Common/Modal/Modal.less View File

@@ -0,0 +1,42 @@
1
+.wrapper {
2
+  position: fixed;
3
+  width: 100vw;
4
+  height: 100vh;
5
+  top: 0;
6
+  left: 0;
7
+  z-index: 1000;
8
+}
9
+
10
+.overlay {
11
+  width: 100vw;
12
+  height: 100vh;
13
+  background: #000;
14
+  animation: overlayer .3s forwards;
15
+}
16
+
17
+.container {
18
+  position: absolute;
19
+  top: 20%;
20
+  left: 50%;
21
+  animation: container .3s forwards;
22
+}
23
+
24
+@keyframes overlayer {
25
+  from {
26
+    opacity: 0;
27
+  }
28
+  to {
29
+    opacity: .3;
30
+  }
31
+}
32
+
33
+
34
+@keyframes container {
35
+  from {
36
+    transform: translateX(-50%) scale(0, 0);
37
+  }
38
+  to {
39
+    transform: translateX(-50%) scale(1, 1);
40
+  }
41
+}
42
+

+ 51
- 0
src/components/Common/Modal/index.tsx View File

@@ -0,0 +1,51 @@
1
+import React from 'react';
2
+import { createPortal } from 'react-dom';
3
+import { isBrowser } from '../Utils/utils';
4
+
5
+import styles from './Modal.less';
6
+
7
+export interface ModalProps {
8
+  visible: boolean
9
+  onCancel: (e: any) => void
10
+  container?: HTMLElement | null
11
+}
12
+
13
+export class Modal extends React.PureComponent<ModalProps> {
14
+  static hasShowWarning = false;
15
+
16
+  render() {
17
+    if (!isBrowser()) return null; // 服务端无需渲染下列代码,渲染也会出错
18
+    const DEFAULT_CONTAINER: HTMLElement | null = document.getElementById('container');
19
+    const { children, visible, onCancel, container = DEFAULT_CONTAINER } = this.props
20
+    let finalMountContainer: HTMLElement = document.body;
21
+    if (!container) {
22
+      if (!DEFAULT_CONTAINER) {
23
+        if (!Modal.hasShowWarning) {
24
+          Modal.hasShowWarning = true;
25
+        }
26
+        finalMountContainer = document.body;
27
+      } else {
28
+        if (!Modal.hasShowWarning) {
29
+          Modal.hasShowWarning = true;
30
+        }
31
+        finalMountContainer = DEFAULT_CONTAINER;
32
+      }
33
+    }
34
+    return visible && createPortal(
35
+      <div className={ styles.wrapper }>
36
+        <div
37
+          className={ styles.overlay }
38
+          onClick={ onCancel }
39
+        />
40
+        <div
41
+          className={ styles.container }
42
+        >
43
+          { children }
44
+        </div>
45
+      </div>,
46
+      finalMountContainer,
47
+    )
48
+  }
49
+}
50
+
51
+export default Modal;

+ 3
- 0
src/components/Common/Utils/utils.ts View File

@@ -0,0 +1,3 @@
1
+export function isBrowser() {
2
+  return !(typeof window === undefined);
3
+}

+ 2
- 0
src/components/Common/index.ts View File

@@ -1 +1,3 @@
1 1
 export { Test } from './test';
2
+
3
+export { default as Modal } from './Modal';

src/components/Payment/temp/SendWantedValueModal.less → src/components/Payment/AllocWantedModal/AllocWantedModal.less View File

@@ -1,4 +1,4 @@
1
-.sendWantedModalContent {
1
+.wantedModalContent {
2 2
   background-color: white;
3 3
   width: 360px;
4 4
   height: 314px;

src/components/Payment/temp/SendWantedValueModal.tsx → src/components/Payment/AllocWantedModal/index.tsx View File

@@ -1,58 +1,62 @@
1
-import React, { RefObject } from 'react';
2
-import PropTypes from 'prop-types';
3
-import { Input, Button, Popover, Tooltip } from 'antd';
4
-import { Modal } from '@/components/Common/Modal';
1
+import React, { RefObject } from "react";
2
+import { Input, Button, Popover, Tooltip } from "antd";
3
+import { Modal } from "@/components/Common/Modal/index.tsx";
5 4
 
6
-import CloseButtonIcon from '@/assets/bilingually/close.png';
5
+import CloseButtonIcon from "../assets/icon/close.png";
7 6
 
8
-import styles from './SendWantedValueModal.less';
9
-import { sendgift } from '@/services/bilingually/qa';
7
+import styles from "./AllocWantedModal.less";
10 8
 
11
-interface SendWantedValueModalProps {
12
-  wantedValue: string|number|null;
13
-  sendValueRange: Array<string|number>;
9
+interface AllocWantedModalProps {
10
+  allocValue: string | number | null;
11
+  sendValueRange: Array<string | number>;
12
+  sendRequest: Function;
14 13
   sendGiftData: {
15
-    answerId: string|number;
16
-    questionId: string|number;
17
-    toUserId: string|number;
14
+    answerId: string | number;
15
+    questionId: string | number;
16
+    toUserId: string | number;
18 17
   };
19
-  handleVisiableChange: Function;
18
+  handleVisibleChange: (visible: boolean) => void;
20 19
 }
21
-interface SendWantedValueModalState {
22
-  visiable: boolean;
20
+interface AllocWantedModalState {
21
+  visible: boolean;
23 22
   outRangeTip: boolean;
24
-  sendValue: string|number;
23
+  sendValue: string | number;
25 24
 }
26 25
 
27
-class SendWantedValueModal extends React.Component<SendWantedValueModalProps, SendWantedValueModalState> {
26
+class AllocWantedModal extends React.Component<
27
+  AllocWantedModalProps,
28
+  AllocWantedModalState
29
+> {
28 30
   ModalInputRef: RefObject<Input>;
31
+  ModalContentRef: RefObject<any>;
29 32
 
30
-  constructor(props: SendWantedValueModalProps) {
33
+  constructor(props: AllocWantedModalProps) {
31 34
     super(props);
32 35
     this.state = {
33
-      visiable: false,
36
+      visible: false,
34 37
       sendValue: 0,
35
-      outRangeTip: false,
38
+      outRangeTip: false
36 39
     };
40
+    this.ModalContentRef = React.createRef();
37 41
     this.ModalInputRef = React.createRef();
38 42
   }
39 43
 
40
-  handleSendValueChange = (v: string|number) => {
44
+  handleSendValueChange = (v: string | number) => {
41 45
     if (this.state.outRangeTip) {
42 46
       this.setState({
43
-        outRangeTip: !this.checkSendValue(),
47
+        outRangeTip: !this.checkSendValue()
44 48
       });
45 49
     }
46 50
     this.setState({
47
-      sendValue: v,
51
+      sendValue: v
48 52
     });
49
-  }
53
+  };
50 54
 
51 55
   checkSendValue = () => {
52 56
     const { sendValueRange } = this.props;
53 57
     const { sendValue } = this.state;
54 58
     let min = 0;
55
-    let max = Number(this.props.wantedValue);
59
+    let max = Number(this.props.allocValue);
56 60
     if (sendValueRange) {
57 61
       min = Number(sendValueRange[0]);
58 62
       max = Number(sendValueRange[1]);
@@ -60,36 +64,42 @@ class SendWantedValueModal extends React.Component<SendWantedValueModalProps, Se
60 64
     if (sendValue > max) {
61 65
       this.setState({
62 66
         // sendValue: max,
63
-        outRangeTip: true,
67
+        outRangeTip: true
64 68
       });
65 69
       return false;
66 70
     } else if (sendValue < min) {
67 71
       this.setState({
68 72
         // sendValue: max,
69
-        outRangeTip: true,
73
+        outRangeTip: true
70 74
       });
71 75
       return false;
72 76
     }
73 77
     return true;
74
-  }
78
+  };
75 79
 
76 80
   handleCloseAction = () => {
77
-    this.setState({
78
-      visiable: false,
79
-      sendValue: 0,
80
-      outRangeTip: false,
81
-    }, () => {
82
-      this.props.handleVisiableChange(false);
83
-    });
84
-  }
81
+    this.setState(
82
+      {
83
+        visible: false,
84
+        sendValue: 0,
85
+        outRangeTip: false
86
+      },
87
+      () => {
88
+        this.props.handleVisibleChange(false);
89
+      }
90
+    );
91
+  };
85 92
 
86 93
   handleShowAction = () => {
87
-    this.setState({
88
-      visiable: true,
89
-    }, () => {
90
-      this.props.handleVisiableChange(true);
91
-    });
92
-  }
94
+    this.setState(
95
+      {
96
+        visible: true
97
+      },
98
+      () => {
99
+        this.props.handleVisibleChange(true);
100
+      }
101
+    );
102
+  };
93 103
 
94 104
   handleConfirm = () => {
95 105
     const { sendGiftData } = this.props;
@@ -99,23 +109,24 @@ class SendWantedValueModal extends React.Component<SendWantedValueModalProps, Se
99 109
       return null;
100 110
     }
101 111
     // 进行分配请求
102
-    sendgift({
103
-      business_type: 14, // 表示悬赏答案
104
-      ref_id: sendGiftData.answerId.toString(), // 对应回答的id
105
-      origin_id: sendGiftData.questionId, // 对应问题的id
106
-      to_user: sendGiftData.toUserId, // 悬赏给谁
107
-      goods_id: 2, // 礼物id 帮币的话为2
108
-      num: Number(this.state.sendValue), // 礼物数量
109
-    }).then((res: any) => {
110
-      console.log('res: ', res);
111
-      console.log("after send gift");
112
+    Promise.resolve(
113
+      this.props.sendRequest({
114
+        business_type: 14, // 表示悬赏答案
115
+        ref_id: sendGiftData.answerId.toString(), // 对应回答的id
116
+        origin_id: sendGiftData.questionId, // 对应问题的id
117
+        to_user: sendGiftData.toUserId, // 悬赏给谁
118
+        goods_id: 2, // 礼物id 帮币的话为2
119
+        num: Number(this.state.sendValue) // 礼物数量
120
+      })
121
+    ).then((res: any) => {
122
+      console.log("res: ", res);
112 123
       if (res) {
113 124
         this.handleCloseAction();
114 125
       } else {
115 126
         this.handleCloseAction();
116 127
       }
117
-    })
118
-  }
128
+    });
129
+  };
119 130
 
120 131
   renderCloseButton = () => {
121 132
     return (
@@ -129,20 +140,24 @@ class SendWantedValueModal extends React.Component<SendWantedValueModalProps, Se
129 140
       >
130 141
         <img src={CloseButtonIcon} alt="close button for send wanted" />
131 142
       </div>
132
-    )
133
-  }
143
+    );
144
+    // return null;
145
+  };
134 146
 
135 147
   renderModalContent = () => {
136 148
     return (
137
-      <div className={styles.sendWantedModalContent}>
149
+      <div className={styles.wantedModalContent} ref={this.ModalContentRef}>
138 150
         {this.renderCloseButton()}
139 151
         <h4 className={styles.title}>分配悬赏奖金</h4>
140
-        <div className={styles.wantedValueText}>{`剩余可分配 ${this.props.wantedValue}元`}</div>
152
+        <div
153
+          className={styles.wantedValueText}
154
+        >{`剩余可分配 ${this.props.allocValue}元`}</div>
141 155
         <Tooltip
142 156
           visible={this.state.outRangeTip}
143
-          title="超过范围值"
157
+          title="超过范围值"
144 158
           placement="bottom"
145 159
           overlayClassName={styles.outRangeTextTip}
160
+          getTooltipContainer={() => this.ModalContentRef && this.ModalContentRef.current}
146 161
         >
147 162
           <Input
148 163
             ref={this.ModalInputRef}
@@ -150,26 +165,28 @@ class SendWantedValueModal extends React.Component<SendWantedValueModalProps, Se
150 165
             suffix="元"
151 166
             value={this.state.sendValue}
152 167
             onChange={e => this.handleSendValueChange(e.target.value)}
153
-            onFocus={e => e.target.setSelectionRange(0, String(this.state.sendValue).length)}
168
+            onFocus={e =>
169
+              e.target.setSelectionRange(0, String(this.state.sendValue).length)
170
+            }
154 171
           />
155 172
         </Tooltip>
156
-        <div className={styles.wantedValueTipBottom}>需要在悬赏时间结束前将奖金分配完成, 否则将按照规则自动分配</div>
173
+        <div className={styles.wantedValueTipBottom}>
174
+          需要在悬赏时间结束前将奖金分配完成, 否则将按照规则自动分配
175
+        </div>
157 176
         <div className={styles.buttonRow}>
158
-          <div className={styles.tipsButton}/>
159
-          <Button
160
-            className={styles.confirmButton}
161
-            onClick={this.handleConfirm}
162
-          >
177
+          <div className={styles.tipsButton} />
178
+          <Button className={styles.confirmButton} onClick={this.handleConfirm}>
163 179
             确认
164 180
           </Button>
165 181
           <div className={styles.tipsButton}>
166 182
             <Popover
167 183
               placement="bottom"
168 184
               trigger="click"
185
+              getPopupContainer={() => this.ModalContentRef && this.ModalContentRef.current}
169 186
               overlayStyle={{
170
-                width: '320px'
187
+                width: "320px"
171 188
               }}
172
-              content={(
189
+              content={
173 190
                 <div className={styles.tipsView}>
174 191
                   <h6>1、如何参与悬赏?</h6>
175 192
                   <div>
@@ -184,37 +201,32 @@ class SendWantedValueModal extends React.Component<SendWantedValueModalProps, Se
184 201
                     赏金只会在以下2种情况进行退款:一、悬赏时间到期,回答数小于2,赏金将自动退还至提问者的钱包;二、悬赏时间到期,悬赏者未分配完赏金,系统自动将剩余的赏金退还至提问者的钱包。
185 202
                   </div>
186 203
                 </div>
187
-              )}
204
+              }
188 205
             >
189
-              <i
190
-                className="schedule schedule-icon_rewardtips"
191
-              />
206
+              <i className="schedule schedule-icon_rewardtips" />
192 207
             </Popover>
193 208
           </div>
194 209
         </div>
195 210
       </div>
196
-    )
197
-  }
211
+    );
212
+  };
198 213
 
199 214
   render() {
200 215
     const { children } = this.props;
201 216
     return (
202 217
       <>
203
-        <div
204
-          className={styles.wrapper} 
205
-          onClick={() => this.handleShowAction()}
206
-        >
218
+        <div className={styles.wrapper} onClick={() => this.handleShowAction()}>
207 219
           {children}
208 220
         </div>
209 221
         <Modal
210
-          visible={this.state.visiable}
222
+          visible={this.state.visible}
211 223
           onCancel={() => this.handleCloseAction()}
212 224
         >
213 225
           {this.renderModalContent()}
214 226
         </Modal>
215 227
       </>
216
-    )
228
+    );
217 229
   }
218 230
 }
219 231
 
220
-export default SendWantedValueModal;
232
+export default AllocWantedModal;

+ 1
- 1
src/components/Payment/ConsumeListView/ConsumeListView.less View File

@@ -49,7 +49,7 @@
49 49
       border-radius: 50%;
50 50
       color: #a8adb6;
51 51
       cursor: pointer;
52
-      background-image: url(../assets/btn_toggle.png);
52
+      background-image: url(../assets/icon/btn_toggle.png);
53 53
       background-position: center;
54 54
 
55 55
       &.expand {

+ 1
- 1
src/components/Payment/ConsumeListView/index.tsx View File

@@ -3,7 +3,7 @@ import classnames from 'classnames';
3 3
 
4 4
 // import { DEFAULT_AVATAR } from '@/constants';
5 5
 import { addImageProcess } from '../Utils/utils';
6
-import KingDomPic from '../assets/popovers_list_huangguan.png';
6
+import KingDomPic from '../assets/icon/popovers_list_huangguan.png';
7 7
 
8 8
 import styles from './ConsumeListView.less';
9 9
 

+ 0
- 1
src/components/Payment/PriceOptions/PriceOptions.less View File

@@ -1,7 +1,6 @@
1 1
 @item_width: 70px;
2 2
 @item_margin: 6px;
3 3
 .options{
4
-  padding: 20px 50px;
5 4
   border-bottom: 1px dashed #00000017;
6 5
   p {
7 6
     font-size:14px;

+ 17
- 6
src/components/Payment/PriceOptions/index.tsx View File

@@ -14,6 +14,7 @@ interface Props {
14 14
   priceOptions?: Array<any>;
15 15
   priceRender?: Function;
16 16
   inputPriceRender?: Function;
17
+  inputSuffix?: string | JSX.Element[] | JSX.Element;
17 18
   inputRef: React.RefObject<any>;
18 19
 }
19 20
 
@@ -28,11 +29,13 @@ const PriceOptions = ({
28 29
   priceOptions = [100, 600, 800],
29 30
   priceRender = (i: any) => i / 100,
30 31
   inputPriceRender = (i: any) => (i ? i / 100 : ""),
32
+  inputSuffix = "¥",
31 33
   inputRef
32 34
 }: Props) => {
33 35
   const defaultOptions = priceOptions;
34 36
   // 控制是否为其他金额输入情况
35 37
   const [inputStatus, setInputStatus] = useState(false);
38
+  const [inputPrice, setInputPrice] = useState('');
36 39
 
37 40
   return (
38 41
     <div className={classnames(styles.options)}>
@@ -63,9 +66,9 @@ const PriceOptions = ({
63 66
               inputRef.current.select();
64 67
             }
65 68
           }}
66
-          suffix="¥"
69
+          suffix={inputSuffix}
67 70
           className={styles.priceInput}
68
-          value={inputStatus ? inputPriceRender(price) : ""}
71
+          value={inputStatus ? inputPriceRender(inputPrice) : ""}
69 72
           placeholder={inputPlaceholderText}
70 73
           onChange={e => {
71 74
             const n = +e.target.value;
@@ -73,22 +76,30 @@ const PriceOptions = ({
73 76
               return;
74 77
             }
75 78
             // 测试暂时改成1分
79
+            setInputPrice(`${n * 100}`);
76 80
             onPriceChange(n * 100);
77 81
           }}
78 82
           onClick={e => {
79
-            onPriceChange(0);
80
-            setInputStatus(true);
83
+            if (!inputStatus) {
84
+              setInputPrice('');
85
+              setInputStatus(true);
86
+            }
81 87
           }}
82 88
           onFocus={e => {
83 89
             e.target.placeholder = "";
84
-            setInputStatus(true);
90
+            if (inputStatus) {
91
+              setInputPrice(`${price}`);
92
+            } else {
93
+              setInputPrice('');
94
+              setInputStatus(true);
95
+            }
85 96
             if (focusScroll) {
86 97
               e.target.scrollIntoView();
87 98
             }
88 99
           }}
89 100
           onBlur={e => {
90 101
             e.target.placeholder = inputPlaceholderText;
91
-            if (price) {
102
+            if (inputPrice) {
92 103
               setInputStatus(true);
93 104
             } else {
94 105
               setInputStatus(false);

+ 1
- 1
src/components/Payment/Utils/utils.ts View File

@@ -3,7 +3,7 @@ export const IMAGE_PROCESS = '?x-oss-process=image/resize,h_350';
3 3
 export const IMAGE_PROCESS_SMALL = '?x-oss-process=image/resize,h_100';
4 4
 export const IMAGE_PROCESS_LARGE = '?x-oss-process=image/resize,h_500';
5 5
 
6
-type AddImageProcessOptions = {
6
+interface AddImageProcessOptions {
7 7
   small?: boolean;
8 8
   large?: boolean;
9 9
   custom?: boolean;

+ 1
- 1
src/components/Payment/WaitPayInfoView/index.tsx View File

@@ -2,7 +2,7 @@ import React, { Component } from 'react';
2 2
 import classnames from 'classnames';
3 3
 import styles from './WaitPayInfoView.less';
4 4
 
5
-import infoIconImg from '../assets/icon-info-blue@2x.svg';
5
+import infoIconImg from '../assets/icon/icon-info-blue@2x.svg';
6 6
 
7 7
 const Button = (...props: any) => <button {...props}>button</button>;
8 8
 

src/components/Payment/temp/WantedPaymentPopover.less → src/components/Payment/WantedPublishPopover/WantedPublishPopover.less View File


src/components/Payment/temp/WantedPaymentPopover.tsx → src/components/Payment/WantedPublishPopover/index.tsx View File

@@ -1,28 +1,29 @@
1 1
 import React from 'react';
2 2
 import { Popover, Divider, Input, Button } from 'antd';
3
-import WantedpaymentView from './WantedPaymentView';
3
+import WantedPublishView from '../WantedPublishView';
4 4
 
5
-import popClose from '@/assets/bilingually/close@2x.png';
6
-import styles from './WantedPaymentPopover.less';
5
+import popClose from '../assets/icon/close@2x.png';
6
+import styles from './WantedPublishPopover.less';
7 7
 
8
-export interface WantedPaymentPopoverProp {
8
+export interface WantedPublishPopoverProp {
9 9
   popoverConfig?: {
10 10
     placement?: "left" | "top" | "right" | "bottom" | "topLeft" | "topRight" | "bottomLeft" | "bottomRight" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | undefined;
11 11
     trigger?: "hover" | "focus" | "click" | "contextMenu" | undefined;
12
+    getPopupContainer?: any;
12 13
   };
13 14
   handleConfirm?: Function;
14 15
 }
15 16
 
16
-export interface WantedPaymentPopoverState {
17
-  visiable: boolean;
17
+export interface WantedPublishPopoverState {
18
+  visible: boolean;
18 19
   current_wanted: number|string|null;
19 20
 }
20 21
 
21
-export class WantedPaymentPopover extends React.Component<WantedPaymentPopoverProp, WantedPaymentPopoverState> {
22
-  constructor(props: WantedPaymentPopoverProp) {
22
+export class WantedPublishPopover extends React.Component<WantedPublishPopoverProp, WantedPublishPopoverState> {
23
+  constructor(props: WantedPublishPopoverProp) {
23 24
     super(props);
24 25
     this.state = {
25
-      visiable: false,
26
+      visible: false,
26 27
 
27 28
       current_wanted: null,
28 29
     }
@@ -35,7 +36,7 @@ export class WantedPaymentPopover extends React.Component<WantedPaymentPopoverPr
35 36
         handleConfirm(Number(value).toFixed(2));
36 37
       });
37 38
     }
38
-    this.setState({ visiable: false });
39
+    this.setState({ visible: false });
39 40
   }
40 41
 
41 42
   clearCurrentWanted = (cb: Function) => {
@@ -61,7 +62,7 @@ export class WantedPaymentPopover extends React.Component<WantedPaymentPopoverPr
61 62
   renderInitView() {
62 63
     const { current_wanted } = this.state; 
63 64
     return (
64
-      <WantedpaymentView
65
+      <WantedPublishView
65 66
         type="pop"
66 67
         current_wanted={current_wanted}
67 68
         InputWantedValueChange={(v: string) => this.setState({ current_wanted: v })}
@@ -80,12 +81,12 @@ export class WantedPaymentPopover extends React.Component<WantedPaymentPopoverPr
80 81
       <Popover
81 82
         placement="left"
82 83
         trigger="click"
83
-        visible={this.state.visiable}
84
+        visible={this.state.visible}
84 85
         onVisibleChange={(value: boolean) => {
85 86
           if (!value) {
86 87
             this.handleClose();
87 88
           }
88
-          this.setState({ visiable: value });
89
+          this.setState({ visible: value });
89 90
         }}
90 91
         {...popoverConfig}
91 92
         content={
@@ -105,4 +106,4 @@ export class WantedPaymentPopover extends React.Component<WantedPaymentPopoverPr
105 106
   }
106 107
 }
107 108
 
108
-export default WantedPaymentPopover;
109
+export default WantedPublishPopover;

src/components/Payment/temp/WantedPaymentView.less → src/components/Payment/WantedPublishView/WantedPublishView.less View File


src/components/Payment/temp/WantedPaymentView.tsx → src/components/Payment/WantedPublishView/index.tsx View File

@@ -1,12 +1,13 @@
1 1
 import React from 'react';
2
-import PropTypes from 'prop-types';
2
+import classnames from 'classnames';
3 3
 import { Divider, Input, Button } from 'antd';
4 4
 
5
-import wantedCover from '@/assets/payment/cover_wanted@2x.png';
6
-import styles from './WantedPaymentView.less';
5
+import wantedCover from '../assets/cover_wanted@2x.png';
6
+import styles from './WantedPublishView.less';
7 7
 
8
-interface WantedpaymentViewProps {
8
+interface WantedPublishViewProps {
9 9
   type?: 'pop'|'modal';
10
+  wrapperClass?: string;
10 11
   current_wanted: number|string|null;
11 12
   InputWantedValueChange: Function;
12 13
   InputWantedPressEnter: Function;
@@ -14,20 +15,22 @@ interface WantedpaymentViewProps {
14 15
   InputWantedClear: Function;
15 16
   CloseFunction: Function;
16 17
 }
17
-interface WantedpaymentViewState {
18
+interface WantedPublishViewState {
18 19
   payment?: number
19 20
 }
20 21
 
21
-class WantedpaymentView extends React.Component<WantedpaymentViewProps, WantedpaymentViewState> {
22
-  constructor(props: WantedpaymentViewProps) {
22
+class WantedPublishView extends React.Component<WantedPublishViewProps, WantedPublishViewState> {
23
+  constructor(props: WantedPublishViewProps) {
23 24
     super(props);
24 25
     this.state = {};
25 26
   }
26 27
 
27 28
   render() {
28
-    const { current_wanted } = this.props; 
29
+    const { current_wanted, wrapperClass } = this.props; 
29 30
     return (
30
-      <div className={styles.wrapper}>
31
+      <div className={classnames(styles.wrapper, {
32
+        [wrapperClass ? wrapperClass : '']: true
33
+      })}>
31 34
         <header>设置悬赏金额</header>
32 35
         <section className={styles.wanted_middle}>
33 36
           <img className={styles.wanted_cover} src={wantedCover} alt="wanted_image"/>
@@ -77,4 +80,4 @@ class WantedpaymentView extends React.Component<WantedpaymentViewProps, Wantedpa
77 80
   }
78 81
 }
79 82
 
80
-export default WantedpaymentView;
83
+export default WantedPublishView;

BIN
src/components/Payment/assets/cover_wanted@2x.png View File


src/components/Payment/assets/btn_toggle.png → src/components/Payment/assets/icon/btn_toggle.png View File


BIN
src/components/Payment/assets/icon/close.png View File


BIN
src/components/Payment/assets/icon/close@2x.png View File


src/components/Payment/assets/icon-info-blue@2x.svg → src/components/Payment/assets/icon/icon-info-blue@2x.svg View File


src/components/Payment/assets/popovers_list_huangguan.png → src/components/Payment/assets/icon/popovers_list_huangguan.png View File


+ 4
- 1
src/components/Payment/index.ts View File

@@ -1,4 +1,7 @@
1 1
 export { default as ConsumeListView } from './ConsumeListView';
2 2
 export { default as PayPlatformOptions } from './PayPlatformOptions';
3 3
 export { default as PriceOptions } from './PriceOptions';
4
-export { default as WaitPayInfoView } from './WaitPayInfoView';
4
+export { default as WaitPayInfoView } from './WaitPayInfoView';
5
+export { default as AllocWantedModal } from './AllocWantedModal';
6
+export { default as WantedPublishPopover } from './WantedPublishPopover';
7
+export { default as WantedPublishView } from './WantedPublishView';

+ 200
- 66
stories/Payment.stories.tsx View File

@@ -1,43 +1,61 @@
1
-import React, { MouseEvent } from 'react';
2
-import { storiesOf } from '@storybook/react';
3
-import { action } from '@storybook/addon-actions';
1
+import React, { MouseEvent } from "react";
2
+import { storiesOf } from "@storybook/react";
3
+import { action } from "@storybook/addon-actions";
4 4
 import { withInfo } from "@storybook/addon-info";
5
-import { withKnobs, number, boolean, select, text, array } from "@storybook/addon-knobs";
6
-import { addReadme } from 'storybook-readme';
7
-import { Divider } from 'antd';
5
+import {
6
+  withKnobs,
7
+  number,
8
+  boolean,
9
+  select,
10
+  text,
11
+  array
12
+} from "@storybook/addon-knobs";
13
+import { addReadme } from "storybook-readme";
14
+import { Divider, Button } from "antd";
8 15
 
9
-import ConsumeListView from '@/components/Payment/ConsumeListView';
10
-import ConsumeListViewDoc from '@components/Payment/ConsumeListView/README.md';
11
-import PayPlatFormOptions, { PAY_CHANNEL } from '@/components/Payment/PayPlatformOptions';
12
-import PayPlatFormOptionsDoc from '@components/Payment/PayPlatformOptions/README.md';
13
-import PriceOptions from '@/components/Payment/PriceOptions';
14
-import PriceOptionsDoc from '@components/Payment/PriceOptions/README.md';
15
-import WaitPayInfoView from '@/components/Payment/WaitPayInfoView';
16
-import WaitPayInfoViewDoc from '@components/Payment/WaitPayInfoView/README.md';
17
-import { formatMoney } from '@components/Payment/Utils/utils';
16
+import ConsumeListView from "@/components/Payment/ConsumeListView";
17
+import ConsumeListViewDoc from "@components/Payment/ConsumeListView/README.md";
18
+import PayPlatFormOptions, {
19
+  PAY_CHANNEL
20
+} from "@/components/Payment/PayPlatformOptions";
21
+import PayPlatFormOptionsDoc from "@components/Payment/PayPlatformOptions/README.md";
22
+import PriceOptions from "@/components/Payment/PriceOptions";
23
+import PriceOptionsDoc from "@components/Payment/PriceOptions/README.md";
24
+import WaitPayInfoView from "@/components/Payment/WaitPayInfoView";
25
+import WaitPayInfoViewDoc from "@components/Payment/WaitPayInfoView/README.md";
26
+import AllocWantedModal from "@/components/Payment/AllocWantedModal";
27
+import WantedPublishView from "@/components/Payment/WantedPublishView";
28
+import WantedPublishPopover from '@/components/Payment/WantedPublishPopover';
29
+import { formatMoney } from "@components/Payment/Utils/utils";
18 30
 
19
-import { consumeList} from './data/consumeList.json';
31
+import { consumeList } from "./data/consumeList.json";
20 32
 
21 33
 const consumeData: any = consumeList;
22 34
 
23
-const stories = storiesOf('Payment', module);
24
-stories.addDecorator((storyFn) => <div style={{padding: "0px 40px"}}>{storyFn()}</div>)
35
+const stories = storiesOf("Payment", module);
36
+stories.addDecorator(storyFn => (
37
+  <div style={{ padding: "0px 40px" }}>{storyFn()}</div>
38
+));
25 39
 stories.addDecorator(withKnobs);
26 40
 stories.addDecorator(withInfo);
27 41
 stories.addDecorator(addReadme);
28 42
 
29 43
 stories.add(
30
-  'ConsumeListView',
44
+  "ConsumeListView",
31 45
   () => {
32 46
     const [toggle, setToggle] = React.useState(false);
33
-    return <ConsumeListView
34
-      isToggle={toggle}
35
-      onToggleChange={() => setToggle(!toggle)}
36
-      onConsumeItemClick={(e: MouseEvent, clickData: any) => { console.log(clickData); }}
37
-      dataSource={consumeData}
38
-      listLength={consumeData.length}
39
-      showLength={number("showLength", 5)}
40
-    />
47
+    return (
48
+      <ConsumeListView
49
+        isToggle={toggle}
50
+        onToggleChange={() => setToggle(!toggle)}
51
+        onConsumeItemClick={(e: MouseEvent, clickData: any) => {
52
+          console.log(clickData);
53
+        }}
54
+        dataSource={consumeData}
55
+        listLength={consumeData.length}
56
+        showLength={number("showLength", 5)}
57
+      />
58
+    );
41 59
   },
42 60
   {
43 61
     info: {
@@ -64,99 +82,215 @@ stories.add(
64 82
       //   })
65 83
       // },
66 84
       source: false,
67
-      maxPropStringLength: 500,
85
+      maxPropStringLength: 500
68 86
     },
69
-    notes: 'A very simple example of addon notes',
87
+    notes: "A very simple example of addon notes",
70 88
     readme: {
71
-      sidebar: ConsumeListViewDoc,
89
+      sidebar: ConsumeListViewDoc
72 90
     }
73 91
   }
74 92
 );
75 93
 
76 94
 stories.add(
77
-  'PayPlatFormOptions',
95
+  "PayPlatFormOptions",
78 96
   () => {
79 97
     const [payChannel, setPayChannel] = React.useState(PAY_CHANNEL.PAYPAL);
80 98
     return (
81 99
       <PayPlatFormOptions
82 100
         payChannel={payChannel}
83
-        onPayChannelChange={(value) => {
101
+        onPayChannelChange={value => {
84 102
           action(`PayItemChange: ${value}`);
85 103
           setPayChannel(value);
86 104
         }}
87 105
         isMobile={boolean("isMobile", false)}
88
-        size={select("size", { Small: "small", Normal: "normal", Large: "large"}, "normal")}
106
+        size={select(
107
+          "size",
108
+          { Small: "small", Normal: "normal", Large: "large" },
109
+          "normal"
110
+        )}
89 111
         withTitle={boolean("withTitle", false)}
90
-        locale={select("locale", { ZH: 'zh', EN: 'en' }, "zh")}
112
+        locale={select("locale", { ZH: "zh", EN: "en" }, "zh")}
91 113
       />
92
-    )
114
+    );
93 115
   },
94 116
   {
95 117
     info: {
96 118
       inline: true,
97 119
       text: ``,
98 120
       source: false,
99
-      maxPropStringLength: 500,
121
+      maxPropStringLength: 500
100 122
     },
101
-    notes: 'A very simple example of addon notes',
123
+    notes: "A very simple example of addon notes",
102 124
     readme: {
103
-      sidebar: PayPlatFormOptionsDoc,
125
+      sidebar: PayPlatFormOptionsDoc
104 126
     }
105 127
   }
106 128
 );
107 129
 
108 130
 stories.add(
109
-  'PriceOptions',
131
+  "PriceOptions",
110 132
   () => {
111 133
     const [price, setPrice] = React.useState(0);
112 134
     const refInput = React.useRef(null);
113 135
     return (
114 136
       <>
115
-      <PriceOptions
116
-        price={price}
117
-        onPriceChange={(v) => setPrice(v)}
118
-        size={select("size", { Small: "small", Normal: "normal", Large: "large"}, "normal")}
119
-        withTitle={boolean("withTitle", false)}
120
-        titleText={text("titleText", "")}
121
-        inputPlaceholderText={text("inputPlaceholderText", "其他金额")}
122
-        focusScroll={boolean("focusScroll", false)}
123
-        priceOptions={array("priceOptions", ["100", "600", "800"])}
124
-        priceRender={(i: number) => `${formatMoney(i/100, 0)}¥`}
125
-        inputRef={refInput}
126
-      />
127
-      <Divider />
128
-      <div>
129
-        price: {price}
130
-      </div>
137
+        <PriceOptions
138
+          price={price}
139
+          onPriceChange={v => setPrice(v)}
140
+          size={select(
141
+            "size",
142
+            { Small: "small", Normal: "normal", Large: "large" },
143
+            "normal"
144
+          )}
145
+          withTitle={boolean("withTitle", false)}
146
+          titleText={text("titleText", "")}
147
+          inputPlaceholderText={text("inputPlaceholderText", "其他金额")}
148
+          focusScroll={boolean("focusScroll", false)}
149
+          priceOptions={array("priceOptions", ["100", "600", "800"])}
150
+          priceRender={(i: number) => `${formatMoney(i / 100, 0)}¥`}
151
+          inputRef={refInput}
152
+        />
153
+        <Divider />
154
+        <div>price: {price}</div>
131 155
       </>
132
-    )
156
+    );
133 157
   },
134 158
   {
135 159
     info: {
136 160
       inline: true,
137 161
       text: ``,
138 162
       source: false,
139
-      maxPropStringLength: 500,
163
+      maxPropStringLength: 500
140 164
     },
141
-    notes: 'A very simple example of addon notes',
165
+    notes: "A very simple example of addon notes",
142 166
     readme: {
143
-      sidebar: PriceOptionsDoc,
167
+      sidebar: PriceOptionsDoc
144 168
     }
145 169
   }
146
-)
170
+);
147 171
 
148 172
 stories.add(
149
-  'WaitPayInfoView',
173
+  "WaitPayInfoView",
150 174
   () => {
151
-    return (
152
-      <WaitPayInfoView />
153
-    )
175
+    return <WaitPayInfoView />;
154 176
   },
155 177
   {
156 178
     info: { inline: true, text: ``, source: false, maxPropStringLength: 500 },
157
-    notes: 'A very simple example of addon notes',
179
+    notes: "A very simple example of addon notes",
158 180
     readme: {
159
-      sidebar: WaitPayInfoViewDoc,
181
+      sidebar: WaitPayInfoViewDoc
160 182
     }
161 183
   }
184
+);
185
+
186
+stories.add(
187
+  "AllocWantedModal",
188
+  () => {
189
+    return (
190
+      <AllocWantedModal
191
+        allocValue={number("allocValue", 100)}
192
+        sendValueRange={[number("minValue", 0), number("maxValue", 100)]}
193
+        sendRequest={(...args: any) => {
194
+          console.log(args);
195
+        }}
196
+        sendGiftData={{
197
+          answerId: text("answerId", '1'),
198
+          questionId: text("questionId", '1'),
199
+          toUserId: text("toUserId", '1')
200
+        }}
201
+        handleVisibleChange={visiable => {
202
+          console.log(visiable);
203
+        }}
204
+      >
205
+        <Button>Click it</Button>
206
+      </AllocWantedModal>
207
+    );
208
+  },
209
+  {
210
+    info: { inline: true },
211
+    notes: "A very simple example of addon notes"
212
+  }
213
+);
214
+
215
+stories.add(
216
+  "WantedPushView",
217
+  () => {
218
+    const [currentWanted, setCurrentWanted] = React.useState(0);
219
+    return (
220
+      <>
221
+        <WantedPublishView
222
+          type={select("type", {
223
+            POP: "pop",
224
+            Modal: 'modal',
225
+          }, "pop")}
226
+          wrapperClass="test_wrapper"
227
+          current_wanted={currentWanted}
228
+          InputWantedValueChange={(value: any) => setCurrentWanted(value)}
229
+          InputWantedOnBlur={(blurValue: any) => setCurrentWanted(blurValue)}
230
+          InputWantedClear={() => setCurrentWanted(0)}
231
+          InputWantedPressEnter={(enterValue: any) => setCurrentWanted(enterValue)}
232
+          CloseFunction={() => { console.log("Close Button"); }}
233
+        />
234
+        <Divider />
235
+        <div>
236
+          currentWanted: {currentWanted}
237
+        </div>
238
+      </>
239
+    )
240
+  },
241
+  {
242
+    info: { inline: true },
243
+    notes: "A very simple example of addon notes"
244
+  }
162 245
 )
246
+
247
+stories.add(
248
+  "WantedPublishPopover",
249
+  () => {
250
+    const [wanted, setWanted] = React.useState('');
251
+    return (
252
+      <div>
253
+        <WantedPublishPopover
254
+          popoverConfig={{
255
+            placement: select("popoverConfigPlacement", {
256
+              Undefined: undefined,
257
+              Left: "left",
258
+              Right: "right",
259
+              Top: "top",
260
+              Bottom: "bottom",
261
+              TopLeft: "topLeft",
262
+              TopRight: "topRight",
263
+              BottomLeft: "bottomLeft",
264
+              BottomRight: "bottomRight",
265
+              LeftTop: "leftTop",
266
+              LeftBottom: "leftBottom",
267
+              RightTop: "rightTop",
268
+              RightBottom: "rightBottom",
269
+            }, undefined),
270
+            trigger: select("popoverConfigTrigger", {
271
+              Undefined: undefined,
272
+              Hover: "hover",
273
+              Click: "click",
274
+              Focus: "focus",
275
+              ContextMenu: "contextMenu",
276
+            }, undefined),
277
+          }}
278
+          handleConfirm={(value: any) => {
279
+            setWanted(value);
280
+          }}
281
+        >
282
+          <Button>HoverIt{wanted}</Button>
283
+        </WantedPublishPopover>
284
+        <Divider />
285
+        {/* 下面用于分割wanted值的渲染,防止Error */}
286
+        {
287
+          ((wanted) => <div>wanted{wanted}</div>)(wanted)
288
+        }
289
+      </div>
290
+    )
291
+  },
292
+  {
293
+    info: { inline: true },
294
+    notes: "A very simple example of addon notes"
295
+  }
296
+)