ソースを参照

审核商品查看详情功能

ytf 2 年 前
コミット
91b2be9df4

+ 6 - 0
admin/config/router.config.js

@@ -218,6 +218,12 @@ export default [
218 218
             name: 'goods_list',
219 219
             component: './manage/product/goods_list',
220 220
           },
221
+          //待审核商品_发布商品
222
+          {
223
+            path: '/manage_product/goods_check_list_to_add',
224
+            name: '',
225
+            component: './manage/goods/add_goods',
226
+          },
221 227
           //分类管理
222 228
           {
223 229
             path: '/manage_product/cate_lists',

+ 1 - 1
admin/src/components/SldTableRowTwo/index.js

@@ -598,7 +598,7 @@ export default class SldTableRowTwo extends PureComponent {
598 598
 	            backgroundColor: '#FFFAF7',
599 599
 	            height: val.item_height!=undefined?val.item_height+2:cur_height + 2,
600 600
             }}>
601
-              {val.required != undefined && val.required && <span style={{ color: 'red' }}>*</span>}
601
+              {val.required != undefined && val.required && <span style={{ color: 'red',fontSize:'40px' }}>*</span>}
602 602
 	            <span className={styles.sld_det_r_text} style={{ fontWeight: this.props.l_fontw!=undefined?this.props.l_fontw:'600',color:this.props.l_color!=undefined?this.props.l_color:'#333'}}>{val.label}</span>
603 603
             </span>
604 604
 							<span className={styles.sld_det_r_item} style={{

+ 643 - 0
admin/src/components/SldTableRowTwoSeller/index.js

@@ -0,0 +1,643 @@
1
+/*
2
+*发布商品的布局(表单内容)   一行多列  左侧label 右侧内容
3
+* */
4
+import React, { PureComponent, Fragment } from 'react';
5
+import {
6
+	Form, Select, Icon, Row, Col, Input, InputNumber, DatePicker, TreeSelect, Cascader, Checkbox, Radio, Upload,  Tooltip,
7
+} from 'antd';
8
+import global from '@/global.less';
9
+import styles from './index.less';
10
+import { sldInputAfterAddons, sldBeforeUpload, getSldComImg, getLocalStorageStingVal,sldBeforeUploadVideo } from '@/utils/utils';
11
+import ALibbSvg from '@/components/ALibbSvg';
12
+
13
+const FormItem = Form.Item;
14
+const { RangePicker } = DatePicker;
15
+const InputGroup = Input.Group;
16
+const RadioGroup = Radio.Group;
17
+const CheckboxGroup = Checkbox.Group;
18
+const Option = Select.Option;
19
+const { TextArea } = Input;
20
+
21
+export default class SldTableRowTwo extends PureComponent {
22
+	constructor(props) {
23
+		super(props);
24
+		this.state = {
25
+			props_data: props,
26
+		};
27
+	}
28
+
29
+	componentWillReceiveProps(props) {
30
+		this.setState({
31
+			props_data: props,
32
+		});
33
+	}
34
+
35
+	//处理input内容变化事件
36
+	handleInputOnchange = (e, item) => {
37
+		if (item.handleChange) {
38
+			item.handleChange(e);
39
+		}
40
+	};
41
+
42
+	//处理复选框变化事件
43
+	handleSingleCheckboxOnchange = (e, item) => {
44
+		if (item.onChange) {
45
+			item.onChange(e);
46
+		}
47
+	};
48
+
49
+	//多选事件
50
+	sldCheckShop = (items, value) => {
51
+		if (items.sldCheckShop) {
52
+			items.sldCheckShop(value);
53
+		}
54
+	};
55
+
56
+	redioOnChange = (e, val) => {
57
+		if (val.onChange) {
58
+			val.onChange(e.target.value);
59
+		}
60
+	};
61
+
62
+  //图品的点击预览
63
+  sldShowImgPre = (val,item) => {
64
+    if (val.preView) {
65
+      val.preView(true, item);
66
+    }
67
+  };
68
+
69
+  radio_select = (e, item) => {
70
+    if (item.callback) {
71
+      item.callback(e);
72
+    }
73
+  };
74
+
75
+	commonCon = (val, index) => {
76
+		let {
77
+			form: { getFieldDecorator }, item_width,
78
+		} = this.props;
79
+		//普通输入框
80
+		item_width = item_width != undefined ? item_width : 'auto';
81
+		const uploadButton = (
82
+			<div>
83
+				<Icon type="plus"/>
84
+				<div className="ant-upload-text">上传图片</div>
85
+			</div>
86
+		);
87
+    const uploadButtonVideo = (
88
+      <div>
89
+        <Icon type="plus"/>
90
+        <div className="ant-upload-text">上传视频</div>
91
+      </div>
92
+    );
93
+		if (val.type == 'input') {
94
+			return (<FormItem
95
+					key={index}
96
+					extra={val.extra}
97
+					style={{ width: '80%' }}
98
+				>
99
+					{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
100
+						<Input maxLength={val.maxLength!=undefined?val.maxLength:250} disabled={val.disable != undefined ? val.disable : false} className={styles.item}
101
+						        placeholder={val.placeholder}/>,
102
+					)}
103
+				</FormItem>
104
+			);
105
+		}else if (val.type == 'show_text') {
106
+		  //内容展示,目前用于商品详情页
107
+      return (<FormItem
108
+          key={index}
109
+          extra={val.extra}
110
+          style={{ width: '80%' }}
111
+        >
112
+          <div style={{color:this.props.r_color!=undefined?this.props.r_color:'#999',fontWeight: this.props.r_fontw!=undefined?this.props.r_fontw:'500',lineHeight:'16px'}}>
113
+            {val.text.length>84
114
+              ?<Tooltip placement="bottomRight" title={val.text}>
115
+                <span className={styles.word_break}>{val.text.substring(0,83)}...</span>
116
+              </Tooltip>
117
+              :val.text
118
+            }
119
+          </div>
120
+        </FormItem>
121
+      );
122
+    }else if (val.type == 'show_text1') {
123
+        //内容展示,目前用于商品详情页
124
+    return (<FormItem
125
+        key={index}
126
+        extra={val.extra}
127
+        style={{ width: '80%' }}
128
+      >
129
+        <div style={{color:this.props.r_color!=undefined?this.props.r_color:'#999',fontWeight: this.props.r_fontw!=undefined?this.props.r_fontw:'500',lineHeight:'16px'}} title={val.text}>{val.text.length > 30 ? val.text.substring(0,30) + '...' : val.text}</div>
130
+      </FormItem>
131
+    );
132
+  }else if (val.type == 'show_goods_img_more') {
133
+		  //展示商品图片(多图),目前用于商品详情页
134
+      return (<FormItem
135
+          key={index}
136
+          extra={val.extra}
137
+          style={{ width: '100%' }}
138
+        >
139
+          <div style={{flexDirection:'row',justifyContent:'flex-start',}}>
140
+            {val.data.length > 0 ?  val.data.map((item,index)=>{
141
+              return <div key={index} onClick={() => this.sldShowImgPre(val,item.imageUrl)} style={{flexDirection:'row',justifyContent:'center',alignItems:'center',overFlow:'hidden',width:100,height:100,display:'inline-flex',backgroundColor:'#F8F8F8',marginRight:10}}>
142
+                <img style={{ maxWidth: '100%', maxHeight: '100%' }} src={item.imageUrl} />
143
+              </div>;
144
+            })
145
+              :'--'
146
+            }
147
+          </div>
148
+        </FormItem>
149
+      );
150
+    } else if (val.type == 'inputnum') {
151
+			//数字搜索框
152
+			return (
153
+				<FormItem key={index}
154
+				          style={{ width: '80%' }}
155
+				          extra={val.extra}
156
+				>
157
+					{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(<InputNumber
158
+						min={val.min != undefined ? val.min : 0}
159
+						max={val.max != undefined ? val.max : 999999999}
160
+						step={val.step ? val.step : 1} className={styles.item} placeholder={val.placeholder}
161
+						precision={val.precision != undefined ? val.precision : 0} disabled={val.disable}
162
+						onChange={(e) => this.handleInputOnchange(e, val)}/>)}
163
+				</FormItem>
164
+			);
165
+
166
+		} else if (val.type == 'select') {
167
+			//下拉选择框
168
+			return (<FormItem
169
+					key={index}
170
+					style={{ width: val.width != undefined ? val.width : ' 80%' }}
171
+					extra={val.extra}
172
+				>
173
+					{getFieldDecorator(val.name, val.initialValue ? {
174
+						initialValue: val.initialValue,
175
+						rules: val.rules,
176
+					} : {
177
+						rules: val.rules,
178
+					})(
179
+						<Select placeholder={val.placeholder}
180
+                    className={styles.item}
181
+                    onChange={val.onChange}
182
+                    getPopupContainer={triggerNode => triggerNode.parentNode}
183
+            >
184
+							{val.sel_data.map((items, indexs) => {
185
+								return <Option key={indexs}
186
+								               value={val.diy != undefined && val.diy ? items[val.sele_key] : items.key}>{val.diy != undefined && val.diy ? items[val.sele_name] : items.name}</Option>;
187
+							})}
188
+						</Select>,
189
+					)}
190
+				</FormItem>
191
+			);
192
+
193
+		} else if (val.type == 'multiple_select') {
194
+			//下拉多选框
195
+			return (<FormItem
196
+					key={index}
197
+					style={{ width: val.width != undefined ? val.width : ' 80%' }}
198
+					extra={val.extra}
199
+				>
200
+					{getFieldDecorator(val.name, val.initialValue ? {
201
+						initialValue: val.initialValue,
202
+						rules: val.rules,
203
+					} : {
204
+						rules: val.rules,
205
+					})(
206
+						<Select mode="multiple"
207
+                    placeholder={val.placeholder}
208
+                    className={styles.item}
209
+                    onChange={val.onChange}
210
+                    getPopupContainer={triggerNode => triggerNode.parentNode}
211
+            >
212
+							{val.sel_data.map((items, indexs) => {
213
+								return <Option key={indexs}
214
+								               value={val.diy != undefined && val.diy ? items[val.sele_key] : items.key}>{val.diy != undefined && val.diy ? items[val.sele_name] : items.name}</Option>;
215
+							})}
216
+						</Select>,
217
+					)}
218
+				</FormItem>
219
+			);
220
+
221
+		} else if (val.type == 'textarea') {
222
+
223
+			return (<FormItem
224
+				key={index}
225
+				help={val.help}
226
+				extra={val.extra}
227
+				style={{ width: '100%' }}
228
+			>
229
+				{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
230
+					<TextArea className={styles.item}
231
+                    maxLength={val.maxLength!=undefined?val.maxLength:250}
232
+					          disabled={val.is_disable != undefined && val.is_disable ? true : false}
233
+					          style={{ minHeight: 32 }} rows={2} placeholder={val.placeholder}/>,
234
+				)}
235
+			</FormItem>);
236
+		} else if (val.type == 'rangepicker') {
237
+			//时间范围选择器
238
+			return (<FormItem
239
+					key={index}
240
+					style={{ width: '100%' }}
241
+					extra={val.extra}
242
+				>
243
+					{getFieldDecorator(val.name)(
244
+						<RangePicker
245
+							className={styles.item}
246
+							placeholder={[val.placeholder1, val.placeholder2,]}
247
+              showTime={val.show_time != undefined ? val.show_time : false}
248
+              getCalendarContainer={(triggerNode)=>{
249
+                return triggerNode.parentNode
250
+              }}
251
+						/>,
252
+					)}
253
+				</FormItem>
254
+			);
255
+		} else if (val.type == 'datepicker') {
256
+			//时间选择器
257
+			return (<FormItem key={index}
258
+			                  extra={val.extra}
259
+			                  style={{ width: '100%' }}
260
+				>
261
+					{val.initialValue && getFieldDecorator(val.name, {
262
+						initialValue: val.initialValue,
263
+						rules: val.rules,
264
+					})(
265
+						<DatePicker className={styles.item} placeholder={val.placeholder} showTime={val.show_time != undefined ? val.show_time : false}
266
+              getCalendarContainer={(triggerNode)=>{
267
+                return triggerNode.parentNode
268
+              }}
269
+            />,
270
+					)}
271
+					{!val.initialValue && getFieldDecorator(val.name, { rules: val.rules })(
272
+						<DatePicker className={styles.item} placeholder={val.placeholder} showTime={val.show_time != undefined ? val.show_time : false}
273
+              getCalendarContainer={(triggerNode)=>{
274
+                return triggerNode.parentNode
275
+              }}
276
+            />,
277
+					)}
278
+				</FormItem>
279
+			);
280
+		} else if (val.type == 'rangeval') {
281
+			//范围选择器
282
+			return (<FormItem
283
+					key={index}
284
+					extra={val.extra}
285
+					style={{ width: '100%' }}
286
+				>
287
+					<InputGroup compact className={styles.item}>
288
+						{getFieldDecorator([val.name1])(<Input maxLength={250} style={{ width: '40%', textAlign: 'center' }}
289
+						                                       placeholder={val.placeholder1}/>)}
290
+
291
+						<Input maxLength={250} style={{ width: '20%', borderLeft: 0, pointerEvents: 'none', backgroundColor: '#fff' }}
292
+						       placeholder="~" disabled/>
293
+						{getFieldDecorator([val.name2])(<Input
294
+							style={{ width: '40%', textAlign: 'center', borderLeft: 0 }}
295
+							placeholder={val.placeholder2}/>)}
296
+					</InputGroup>
297
+				</FormItem>
298
+			);
299
+
300
+		} else if (val.type == 'input_after') {
301
+			//带图标后缀
302
+			return (<FormItem
303
+				key={index}
304
+				extra={val.extra}
305
+				style={{ width: '100%' }}
306
+			>
307
+				<div onClick={() => val.callback(val.operate_obj)}>
308
+					{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
309
+						<Input maxLength={250} style={{ width: 150, marginLeft: 3 }} disabled={true} addonAfter={sldInputAfterAddons()}
310
+						       placeholder={val.placeholder}/>,
311
+					)}
312
+				</div>
313
+			</FormItem>);
314
+		} else if (val.type == 'textarea_single') {
315
+			return <FormItem
316
+				key={index}
317
+				extra={val.extra}
318
+				style={{ width: '100%' }}
319
+			>
320
+				{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
321
+					<TextArea className={styles.item} style={{ minHeight: 30 }} rows={1}/>,
322
+				)}
323
+			</FormItem>;
324
+		} else if (val.type == 'TreeSelect') {
325
+			return <FormItem key={index} extra={val.extra} style={{ width: ' 80%' }}>
326
+				{getFieldDecorator(val.name, {
327
+					initialValue: val.initialValue == '' ? undefined : val.initialValue,
328
+					rules: val.rules,
329
+				})(
330
+					<TreeSelect
331
+						className={styles.item}
332
+						treeData={val.data}
333
+						showSearch={true}
334
+						placeholder={val.placeholder}
335
+						allowClear={val.allowClear}
336
+						onSelect={val.onSelect}
337
+            dropdownStyle={{maxHeight:300}}
338
+            getPopupContainer={triggerNode => triggerNode.parentNode}
339
+					/>,
340
+				)}
341
+			</FormItem>;
342
+		} else if (val.type == 'tree_select_more') {
343
+		  //树选择器——多选
344
+			return <FormItem key={index} extra={val.extra} style={{ width: ' 80%' }}>
345
+				{getFieldDecorator(val.name, {
346
+					initialValue: val.initialValue == '' ? undefined : val.initialValue,
347
+					rules: val.rules,
348
+				})(
349
+					<TreeSelect
350
+						className={styles.item}
351
+						treeData={val.data}
352
+            treeCheckable={true}
353
+            treeDefaultExpandAll={true}
354
+            showCheckedStrategy={'SHOW_PARENT'}
355
+						placeholder={val.placeholder}
356
+						allowClear={val.allowClear}
357
+            onChange={val.onChange}
358
+            dropdownStyle={{maxHeight:300}}
359
+            getPopupContainer={triggerNode => triggerNode.parentNode}
360
+					/>,
361
+				)}
362
+			</FormItem>;
363
+		} else if (val.type == 'cascader') {
364
+			//店铺分类选择
365
+			return (<FormItem
366
+					key={index}
367
+					extra={val.extra}
368
+					style={{ width: '80%' }}
369
+				>
370
+					{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
371
+						<Cascader
372
+							disabled={val.disable != undefined && val.disable ? val.disable : false}
373
+							fieldNames={{ label: 'title', value: 'key', children: 'children' }}
374
+							className={styles.item} options={val.options}
375
+							placeholder={val.placeholder}/>,
376
+					)}
377
+				</FormItem>
378
+			);
379
+		}else if (val.type == 'cascader_area') {
380
+			//三级地址选择
381
+			return (<FormItem
382
+					key={index}
383
+					extra={val.extra}
384
+					style={{ width: '80%' }}
385
+				>
386
+					{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
387
+						<Cascader
388
+							disabled={val.disable != undefined ? val.disable : false}
389
+							options={JSON.parse(localStorage.getItem('common_area_list'))}
390
+							placeholder={val.placeholder}
391
+						/>,
392
+					)}
393
+				</FormItem>
394
+			);
395
+		} else if (val.type == 'single_checkbox') {
396
+			//选择框
397
+			return (<FormItem
398
+					key={index}
399
+					extra={val.extra}
400
+					style={{ width: '100%' }}
401
+				>
402
+					{getFieldDecorator(val.name, {
403
+						valuePropName: 'checked',
404
+						initialValue: val.initialValue,
405
+						rules: val.rules,
406
+					})(
407
+						<Checkbox
408
+							disabled={val.disable != undefined && val.disable ? val.disable : false}
409
+							className={styles.item}
410
+							onChange={(e) => this.handleSingleCheckboxOnchange(e, val)}
411
+						>
412
+							{val.check_con}
413
+						</Checkbox>,
414
+					)}
415
+				</FormItem>
416
+			);
417
+		} else if (val.type == 'radio') {
418
+			//radio
419
+			return (<FormItem
420
+					key={index}
421
+					extra={val.extra}
422
+					style={{ width: '100%' }}
423
+				>
424
+					{getFieldDecorator(val.name, {
425
+						valuePropName: 'checked',
426
+						rules: val.rules,
427
+						initialValue: val.initialValue,
428
+					})(
429
+						<RadioGroup size={'small'} defaultValue={val.initialValue} className={styles.item}
430
+						            onChange={(e) => this.redioOnChange(e, val)}>
431
+							{val.sel_data.map((item, index) => {
432
+								return <Radio key={index} value={item.key}>{item.name}</Radio>;
433
+							})}
434
+						</RadioGroup>,
435
+					)}
436
+				</FormItem>
437
+			);
438
+		} else if (val.type == 'radio_select') {
439
+      return (<FormItem
440
+        key={index}
441
+        extra={val.extra}
442
+        style={{ width: '100%' }}
443
+      >
444
+        {getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
445
+          <Radio.Group size={'small'} buttonStyle="solid" disabled={val.disable}
446
+                       onChange={(e) => this.radio_select(e, val)}>
447
+            {val.data.map((cval, ckey) => {
448
+              return <Radio.Button key={ckey} value={cval.key}>{cval.value}</Radio.Button>;
449
+            })}
450
+
451
+          </Radio.Group>,
452
+        )}
453
+      </FormItem>);
454
+    } else if (val.type == 'checkboxgroup') {
455
+			//radio
456
+			return (<FormItem
457
+					key={index}
458
+					style={{ width: '100%' }}
459
+					extra={val.extra}
460
+				>
461
+					{getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
462
+						<CheckboxGroup className={styles.item} options={val.sldOptions}
463
+						               onChange={(value) => this.sldCheckShop(val, value)}/>,
464
+					)}
465
+				</FormItem>
466
+			);
467
+		} else if (val.type == 'upload_img_upload') {
468
+			return <FormItem
469
+				key={index}
470
+				style={{ width: '100%' }}
471
+				extra={val.extra}
472
+			>
473
+				<Upload
474
+					beforeUpload={sldBeforeUpload}
475
+					withCredentials={true}
476
+					accept={'.gif, .jpeg, .png,.jpg,'}
477
+					name={val.upload_name}
478
+					action={val.upload_url}
479
+					listType="picture-card"
480
+					fileList={val.fileList}
481
+					onPreview={(info) => val.uploadPreview(info)}
482
+					onChange={(info) => val.uploadChange(info,val.extra_param!=undefined?val.extra_param:{})}
483
+          headers={{
484
+            Authorization: 'Bearer ' + getLocalStorageStingVal('sld_token')
485
+          }}
486
+				>
487
+					{val.fileList.length >= (val.num!=undefined?val.num:6) ? null : uploadButton}
488
+				</Upload>
489
+			</FormItem>;
490
+		} else if (val.type == 'upload_video') {
491
+      return <FormItem
492
+        key={index}
493
+        style={{ width: '100%' }}
494
+        extra={val.extra}
495
+      >
496
+        {val.fileList.length > 0 && val.fileList[0].status == 'done'&&val.fileList[0].response!=undefined
497
+          ?<div style={{marginTop:12,position:'relative'}}>
498
+            <video width={102} height={102} src={val.fileList[0].response.data.url} controls autoPlay/>
499
+            <div style={{position:'absolute',zIndex:99,top:'-11px',left:'93px'}} onClick={()=>val.delVideo()}>
500
+              <ALibbSvg
501
+                fill={'#c8c8c8'} width={18} height={18} type={'qingchu'}/>
502
+            </div>
503
+          </div>
504
+          :<Upload
505
+            beforeUpload={sldBeforeUploadVideo}
506
+            withCredentials={true}
507
+            accept={'.mp4'}
508
+            name={val.upload_name}
509
+            action={val.upload_url}
510
+            listType="picture-card"
511
+            fileList={val.fileList}
512
+            onPreview={(info) => val.uploadPreview(info)}
513
+            onChange={(info) => val.uploadChange(info,val.extra_param!=undefined?val.extra_param:{})}
514
+          >
515
+            {val.fileList.length ==0 && uploadButtonVideo}
516
+          </Upload>
517
+        }
518
+      </FormItem>;
519
+    } else if (val.type == 'show_img_more') {
520
+      return <FormItem
521
+        key={index}
522
+        style={{ width: '100%' }}
523
+        extra={val.extra}
524
+      >
525
+        <div className={`${global.flex_row_start_center}`}>
526
+          {val.data.map(item=>{
527
+            return <div  className={`${global.flex_row_center_center}`}>
528
+              {getSldComImg(item,200,200,100,100)}
529
+            </div>
530
+          })}
531
+
532
+        </div>
533
+      </FormItem>;
534
+    } else if (val.type == 'goods_spec_sele') {
535
+			let con = <div className={styles.spec_wrap}>
536
+				{
537
+					val.sel_data.length > 0 && val.sel_data.map((vall, keyl) => {
538
+						return <div key={keyl}
539
+						            className={`${styles.spec_r_wrap} ${keyl != val.sel_data.length - 1 ? styles.show_bot_border : null}`}>
540
+							<span className={styles.spec_l}>{vall.name}</span>
541
+							{vall.attrList.length > 0 &&
542
+							<div className={styles.spec_item_wrap}>
543
+								<Checkbox.Group disabled={val.disable != undefined && val.disable ? val.disable : false}
544
+								                style={{ width: '100%' }}>
545
+									<Row>
546
+										{vall.attrList.map((valr, keyr) => {
547
+											return <Col key={keyr} span={4}><Checkbox
548
+												value={valr.id}>{valr.name}</Checkbox>
549
+												{vall.type == 2 &&
550
+												<Upload
551
+													beforeUpload={sldBeforeUpload}
552
+													withCredentials={true}
553
+													accept={'.gif, .jpeg, .png,.jpg,'}
554
+													name={val.upload_name}
555
+													action={val.upload_url}
556
+													listType="picture-card"
557
+													fileList={[]}
558
+													onPreview={(info) => val.uploadPreview(info)}
559
+													onChange={(info) => val.uploadChange(info)}
560
+                          headers={{
561
+                            Authorization: 'Bearer ' + getLocalStorageStingVal('sld_token')
562
+                          }}
563
+												>
564
+													{uploadButton}
565
+												</Upload>
566
+												}
567
+
568
+											</Col>;
569
+										})}
570
+									</Row>
571
+								</Checkbox.Group>
572
+							</div>
573
+							}
574
+						</div>;
575
+					})
576
+				}
577
+			</div>;
578
+
579
+			return con;
580
+		} else if (val.type == 'show_text_btn') {
581
+			return <FormItem
582
+				key={index}
583
+				style={{ width: '100%' }}
584
+				extra={val.extra}
585
+			>
586
+				<div className={`${global.flex_row_start_center}`}>
587
+					<span>{val.initialValue}</span>
588
+					{val.btn != undefined &&
589
+          <div onClick={val.btn.callback} className={`${global.add_goods_bottom_btn}`} style={{width:95,marginLeft:10}}>
590
+            {val.btn.text}
591
+          </div>
592
+					}
593
+				</div>
594
+			</FormItem>;
595
+		}
596
+	};
597
+
598
+	render() {
599
+		const { data, lwidth, rwidth, totalHeght, part_width } = this.state.props_data;
600
+		let {
601
+			form: { getFieldDecorator },
602
+		} = this.props;
603
+		const total_width = document.body.clientWidth-208;
604
+		const cur_height = totalHeght != undefined ? totalHeght : 70;
605
+		return (
606
+			<div className={styles.sld_table_row_two} style={{ height: totalHeght }}>
607
+				<div className={styles.sld_det_lr_wrap}>
608
+					{data != undefined && data.length > 0 && data.map((val, index) => {
609
+						return <div className={styles.sld_det_lr_item_wrap} key={index} style={{
610
+							width: `${(part_width != undefined ? part_width : 50)*0.01*total_width-2}px`,
611
+							height: val.item_height!=undefined?val.item_height+1:cur_height + 1,
612
+						}}>
613
+            <span className={styles.sld_det_r_item} style={{
614
+	            flexDirection: 'row',
615
+	            alignItems: 'center',
616
+	            justifyContent: 'flex-end',
617
+	            width: `${lwidth != undefined ? lwidth : 20}%`,
618
+	            backgroundColor: '#fff',
619
+	            height: val.item_height!=undefined?val.item_height+2:cur_height + 2,
620
+              borderTopWidth:val.lTopWidth!=undefined?val.lTopWidth:1
621
+            }}>
622
+              {val.required != undefined && val.required && <span style={{ color: 'red',fontSize:'40px' }}>*</span>}
623
+	            <span className={styles.sld_det_r_text} style={{ fontWeight: this.props.l_fontw!=undefined?this.props.l_fontw:'600',color:this.props.l_color!=undefined?this.props.l_color:'#333'}}>{val.label}</span>
624
+            </span>
625
+							<span className={styles.sld_det_r_item} style={{
626
+								width: `${rwidth != undefined ? rwidth : 80}%`,
627
+								alignItems: 'flex-start',
628
+								paddingLeft: 20,
629
+								height: val.item_height!=undefined?val.item_height+2:cur_height + 2,
630
+								borderRightWidth: 1,
631
+                borderTopWidth:val.rTopWidth!=undefined?val.rTopWidth:1,
632
+							}}>
633
+              <span className={styles.sld_det_r_text} style={{ width: '100%', }}>
634
+                {this.commonCon(val, index)}
635
+              </span>
636
+            </span>
637
+						</div>;
638
+					})}
639
+				</div>
640
+			</div>
641
+		);
642
+	}
643
+}

+ 83 - 0
admin/src/components/SldTableRowTwoSeller/index.less

@@ -0,0 +1,83 @@
1
+.sld_table_row_two{
2
+  :global{
3
+    .ant-form-item-control-wrapper{
4
+      width: 100%;
5
+    }
6
+  }
7
+}
8
+.sld_det_lr_wrap {
9
+  display: flex;
10
+  flex-wrap: wrap;
11
+  flex-direction: row;
12
+  justify-content: flex-start;
13
+  align-items: flex-start;
14
+  border-left:1px solid #F0F0F0;
15
+  padding-top: 1px;
16
+  width:100%;
17
+}
18
+
19
+.sld_det_lr_item_wrap {
20
+  display: flex;
21
+  flex-wrap: nowrap;
22
+  flex-direction: row;
23
+  justify-content: flex-start;
24
+  align-items: center;
25
+}
26
+
27
+.sld_det_r_item {
28
+  flex-direction: column;
29
+  justify-content: center;
30
+  align-items: flex-end;
31
+  padding-right: 10px;
32
+  display: flex;
33
+  border:1px solid #F0F0F0;
34
+  border-left:0;
35
+}
36
+.sld_det_r_text {
37
+  font-size: 13px !important;
38
+  color: #333;
39
+}
40
+.item{
41
+  width:100%;
42
+}
43
+.spec_wrap{
44
+  display: flex;
45
+  flex-direction: column;
46
+  align-items: flex-start;
47
+  justify-content: flex-start;
48
+}
49
+
50
+.spec_r_wrap{
51
+  width:100%;
52
+  display: flex;
53
+  flex-direction: row;
54
+  justify-content: flex-start;
55
+  align-items: flex-start;
56
+  .spec_l{
57
+    width:100px;
58
+    justify-content: flex-end;
59
+    align-items: center;
60
+    padding-top: 10px;
61
+  }
62
+  .spec_item_wrap{
63
+    width: 100%;
64
+    padding: 10px;
65
+  }
66
+}
67
+
68
+.show_bot_border{
69
+  border-bottom: 1px dashed #DCDCDC;
70
+}
71
+
72
+.sld_det_r_text{
73
+  :global {
74
+    .ant-form-item {
75
+      margin-bottom: 0!important;
76
+    }
77
+  }
78
+}
79
+
80
+.word_break{
81
+  word-wrap: break-word;
82
+  word-break: break-all;
83
+}

+ 1 - 1
admin/src/pages/CheckLogin.js

@@ -39,7 +39,7 @@ export default ({ children }) => {
39 39
     let all_routes = JSON.parse(localStorage.sld_all_routes);
40 40
     let contain_redirect_flag = false;
41 41
     for (let i = 0; i < all_routes.length; i++) {
42
-      if (children.props.location.pathname.indexOf(all_routes[i]) > -1) {
42
+      if (children.props.location.pathname.indexOf("/manage_product/") >-1 || children.props.location.pathname.indexOf(all_routes[i]) > -1) {
43 43
         contain_redirect_flag = true;
44 44
         break;
45 45
       }

File diff suppressed because it is too large
+ 2809 - 0
admin/src/pages/manage/goods/add_goods.js


File diff suppressed because it is too large
+ 2071 - 0
admin/src/pages/manage/goods/global.less


+ 86 - 0
admin/src/pages/manage/goods/models/product.js

@@ -0,0 +1,86 @@
1
+import { sldCommonService } from '@/utils/utils';
2
+import { sldComLanguage } from '@/utils/utils';
3
+
4
+export default {
5
+  namespace: 'gproduct',
6
+  state: {
7
+    loading: false,//加载状态
8
+    data: {
9
+      list: [],
10
+      pagination: {},
11
+    },
12
+  },
13
+
14
+  effects: {
15
+     //slodon_获取分类列表_根据分类id获取下级分类
16
+    * get_cate_list_by_id({ payload, callback }, { call }) {
17
+      const response = yield call(sldCommonService, payload, 'get', `v3/goods/admin/seller/list`);
18
+      if (callback) callback(response);
19
+    },
20
+    //slodon_获取商品规格列表
21
+    * get_goods_spec_list({ payload, callback }, { call }) {
22
+      const response = yield call(sldCommonService, payload, 'get', `v3/goods/admin/seller/ggList`);
23
+      if (callback) callback(response);
24
+    },
25
+    //slodon_获取商品标签列表
26
+    * get_goods_label_lists({ payload, callback }, { call }) {
27
+      const response = yield call(sldCommonService, payload, 'get', `v3/goods/admin/seller/bqList`);
28
+      if (callback) callback(response);
29
+    },
30
+    //slodon_获取分类绑定的品牌和属性信息
31
+    * get_brand_attr_detail({ payload, callback }, { call }) {
32
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/admin/seller/listByCategoryId');
33
+      if (callback) callback(response);
34
+    },
35
+    //slodon_获取店铺分类列表
36
+    * get_store_category_list({ payload, callback }, { call }) {
37
+      const response = yield call(sldCommonService, payload, 'get', 'v3/seller/admin/seller/dpList');
38
+      if (callback) callback(response);
39
+    },
40
+    //slodon_获取商品详情
41
+    * get_goods_detail({ payload, callback }, { call }) {
42
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/admin/seller/getGoodsInfo');
43
+      if (callback) callback(response);
44
+    },
45
+    //slodon_获取商品列表
46
+    * get_goods_lists({ payload, callback }, { call }) {
47
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/seller/goods/list');
48
+      if (callback) callback(response);
49
+    },
50
+    // slodon_获取关联版式列表
51
+    * get_related_template_lists({ payload, callback }, { call }) {
52
+      const response = yield call(sldCommonService, payload, 'get', `v3/goods/admin/seller/bsList`);
53
+      if (callback) callback(response);
54
+    },
55
+    //slodon_获取属性分组列表
56
+    * get_attribute_group_lists({ payload, callback }, { call }) {
57
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/seller/goodsParameterGroup/list');
58
+      if (callback) callback(response);
59
+    },
60
+    //slodon_获取可用的属性分组列表
61
+    * get_attribute_group_lists_can_use({ payload, callback }, { call }) {
62
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/admin/seller/canUseList');
63
+      if (callback) callback(response);
64
+    },
65
+    //slodon_获取属性列表
66
+    * get_attribute_lists({ payload, callback }, { call }) {
67
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/seller/goodsParameter/list');
68
+      if (callback) callback(response);
69
+    },
70
+    //slodon_获取可用的属性列表
71
+    * get_attribute_lists_can_use({ payload, callback }, { call }) {
72
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/seller/goodsParameter/canUseList');
73
+      if (callback) callback(response);
74
+    },
75
+    //slodon_申请通过的商品分类
76
+    * get_system_seller_cate_list({ payload, callback }, { call }) {
77
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/admin/seller/cateList');
78
+      if (callback) callback(response);
79
+    },
80
+    //slodon_获取店铺运费模板列表
81
+    * get_transport_lists({ payload, callback }, { call }) {
82
+      const response = yield call(sldCommonService, payload, 'get', 'v3/goods/admin/seller/yfList');
83
+      if (callback) callback(response);
84
+    },
85
+  },
86
+};

+ 83 - 0
admin/src/pages/manage/goods/product.less

@@ -0,0 +1,83 @@
1
+.right_nav {
2
+  position: fixed;
3
+  top: 20vh;
4
+  right: 10px;
5
+  width:120px;
6
+  background:rgba(255,255,255,1);
7
+  box-shadow:0 0 15px 0 rgba(153,153,153,0.15);
8
+  .nav_title{
9
+    height:38px;
10
+    line-height: 38px;
11
+    width: 100%;
12
+    display: inline-block;
13
+    background:rgba(236,245,255,1);
14
+    text-align:center;
15
+    color: #08A9B7;
16
+    font-size: 14px;
17
+    font-weight: 700;
18
+  }
19
+  .nav_item{
20
+    color: #999;
21
+    font-size: 12px;
22
+    font-weight: 700;
23
+    padding: 9px 35px 9px 26px;
24
+    width:111px;
25
+    height:30px;
26
+    line-height: 12px;
27
+    background:#fff;
28
+    border-radius:15px 0 0 15px;
29
+    display: block;
30
+    margin: 10px 0 10px 9px;
31
+  }
32
+  .nav_item:hover,.nav_item.nav_sel{
33
+    color: #333;
34
+    background:rgba(65,157,253,.1);
35
+  }
36
+}
37
+
38
+.goods_detail_body{
39
+  border: 1px solid #F2F2F2;
40
+  padding: 15px;
41
+}
42
+
43
+.goods_info{
44
+  .goods_detail{
45
+    height: 80px;
46
+    margin-left: 10px;
47
+    flex: 1;
48
+  }
49
+  .goods_img{
50
+    width:80px;
51
+    height:80px;
52
+    background:rgba(248,248,248,1);
53
+    border:1px solid rgba(226,229,246,1);
54
+    border-radius:3px;
55
+    overflow: hidden;
56
+    display: inline-block;
57
+  }
58
+  .goods_name{
59
+    overflow: hidden;
60
+    text-overflow: ellipsis;
61
+    display: -webkit-box;
62
+    -webkit-line-clamp: 2;
63
+    /*! autoprefixer: off */
64
+    -webkit-box-orient: vertical;
65
+    word-break: break-word;
66
+    color:#333;
67
+    font-size: 14px;
68
+    line-height: 17px;
69
+    text-align: left;
70
+    height: 34px;
71
+    flex-shrink: 0;
72
+  }
73
+  .goods_brief{
74
+    color: #666;
75
+    font-size: 12px;
76
+    overflow: hidden;
77
+    text-overflow: ellipsis;
78
+    white-space: nowrap;
79
+    text-align: left;
80
+    width: 100%;
81
+    display: inline-block;
82
+  }
83
+}

+ 99 - 0
admin/src/pages/manage/goods/sel_goods_cat.js

@@ -0,0 +1,99 @@
1
+/*发布商品选择商品分类组件*/
2
+import { connect } from 'dva/index';
3
+import React, { Component, Fragment } from 'react';
4
+import { Form, } from 'antd';
5
+import {
6
+	failTip,
7
+	getSldEmptyH,sldFullHeight,
8
+	sldComLanguage,
9
+} from '@/utils/utils';
10
+import global from './global.less';
11
+import { Scrollbars } from 'react-custom-scrollbars';
12
+
13
+let sthis = '';
14
+@connect(({ gproduct, global }) => ({
15
+	gproduct, global,
16
+}))
17
+@Form.create()
18
+export default class SelGoodsCat extends Component {
19
+	constructor(props) {
20
+		super(props);
21
+		sthis = this;
22
+		this.state = {
23
+			modalVisible: props.modalVisible,
24
+			data: props.data,
25
+			sele_goods_cat_data: [],
26
+		};
27
+	}
28
+
29
+	componentDidMount() {
30
+
31
+	}
32
+
33
+	componentWillReceiveProps(nextProps, nextContext) {
34
+		this.setState({ modalVisible: nextProps.modalVisible, sele_goods_cat_data: nextProps.sele_goods_cat_data });
35
+	}
36
+
37
+	componentWillUnmount() {
38
+
39
+	}
40
+
41
+	//下一步事件
42
+	addGoodsNext = () => {
43
+		if (this.props.sele_goods_cat_data.length == 3) {
44
+			this.props.sldAddGoodsSecond();
45
+		} else {
46
+			failTip(`${sldComLanguage('分类必须选到第三级才可以发布商品')}`);
47
+		}
48
+	};
49
+
50
+	//获取下级分类
51
+	getChild = (item, index) => {
52
+		this.props.sldHandleGoodsCat(item, index);
53
+	};
54
+
55
+	render() {
56
+		const { data, sele_goods_cat_data } = this.state;
57
+		let sele_cat_str = '';
58
+		if (sele_goods_cat_data.length == 0) {
59
+			sele_cat_str = `${sldComLanguage('请选择商品类别')}`;
60
+		} else {
61
+			sele_cat_str = `${sldComLanguage('您选择商品类别是:')}`;
62
+			sele_goods_cat_data.map((item, index) => {
63
+				sele_cat_str += item.categoryName;
64
+				if (index != sele_goods_cat_data.length - 1) {
65
+					sele_cat_str += ' > ';
66
+				}
67
+			});
68
+		}
69
+		return (
70
+			<div className={global.sele_goods_cat}>
71
+				<div className={global.goods_cat_wrap} style={{marginTop:sldFullHeight(34),marginBottom:sldFullHeight(17),height:sldFullHeight(600)}}>
72
+					{data.map((item, index) => {
73
+						return index < 3 &&
74
+							<div className={global.wrap} key={index} style={{ marginLeft: index == 0 ? 0 : 16,paddingTop:10 }}>
75
+								<Scrollbars autoHeight
76
+								            autoHeightMin={0}
77
+								            autoHeightMax={sldFullHeight(530)}>
78
+									{item.length > 0 && item.map((items, indexs) => {
79
+										return <div onClick={() => this.getChild(items, index + 1)}
80
+										            className={`${global.goods_cat_item} ${sele_goods_cat_data[index] != undefined && items.categoryId == sele_goods_cat_data[index].categoryId ? global.select : null}`}
81
+										            key={indexs}>{items.categoryName}</div>;
82
+									})}
83
+                  {getSldEmptyH(15)}
84
+                </Scrollbars>
85
+							</div>;
86
+					})}
87
+				</div>
88
+				<div className={`${global.sele_cat_info} ${sele_goods_cat_data.length == 0 ? 'tip_bg' : null}`}>
89
+					<span className={`${sele_goods_cat_data.length == 0 ? 'tip' : null}`}>{sele_cat_str}</span>
90
+				</div>
91
+				<div className={global.com_flex_column_center} style={{marginTop:sldFullHeight(41)}}>
92
+					<div className={global.add_goods_step1_btn} onClick={() => this.addGoodsNext()}>
93
+						<span className={global.text}>{sldComLanguage('下一步,填写商品信息')}</span>
94
+					</div>
95
+				</div>
96
+			</div>
97
+		);
98
+	}
99
+}

+ 10 - 4
admin/src/pages/manage/product/goods_check_lists.js

@@ -20,11 +20,13 @@ import {
20 20
   sldPopConfirmDiy,
21 21
   sldPopConfirm,
22 22
 } from '@/utils/utils';
23
+import Link from 'umi/link';
23 24
 import global from '@/global.less';
24 25
 import styles from './product.less';
25 26
 import StandardTable from '@/components/StandardTable';
26 27
 import Search from '@/components/Search/Search';
27 28
 import SldModal from '@/components/SldModal/SldModal';
29
+import router from 'umi/router';
28 30
 
29 31
 let pageSize = list_com_page_size_10;
30 32
 @connect(({ product }) => ({
@@ -159,7 +161,7 @@ export default class GoodsCheckLists extends Component {
159 161
           title: `${sldComLanguage('拒绝理由')}`,//拒绝理由
160 162
           dataIndex: 'auditReason',
161 163
           align: 'center',
162
-          width: 150,
164
+          width: 130,
163 165
           render: (text, record) =>{
164 166
             return (text?text:'')+(record.auditComment?(','+record.auditComment):'')
165 167
           }
@@ -168,25 +170,29 @@ export default class GoodsCheckLists extends Component {
168 170
           title: `${sldComLanguage('发布时间')}`,//发布时间
169 171
           dataIndex: 'createTime',
170 172
           align: 'center',
171
-          width: 150,
173
+          width: 130,
172 174
         },
173 175
         {
174 176
           title: `${sldComLanguage('操作')}`,//操作
175 177
           align: 'center',
176
-          width: 100,
178
+          width: 120,
177 179
           render: (text, record) => {
178 180
             return (record.state == 20||record.state == 21)?<Fragment>
179 181
               {sldPopConfirmDiy('leftBottom', `${sldComLanguage('确认审核通过该商品吗?')}`, () => this.operateGoods({goodsIds:record.goodsId,state:1}), `${sldComLanguage('确定')}`, `${sldComLanguage('取消')}`,
180 182
                 sldtbaleOpeBtnText(`${sldComLanguage('审核通过')}`, () => null))}
181 183
               <span className={global.splitLine}></span>
182 184
               {sldtbaleOpeBtnText(`${sldComLanguage('审核拒绝')}`, () => this.refuseGoods(record.goodsId))}
185
+              <span className={global.splitLine}></span>
186
+              {sldtbaleOpeBtnText(`${sldComLanguage('查看')}`, () => this.goDetail(record))}
183 187
             </Fragment>:'--'
184 188
           },
185 189
         },
186 190
       ],
187 191
     };
188 192
   }
189
-
193
+  goDetail = (val) =>{
194
+    router.push(`/manage_product/goods_check_list_to_add?id=${val.goodsId}&storeId=${val.storeId}`);
195
+  }
190 196
   operate_ids = '';//当前操作的商品id串
191 197
   reason_list = [];
192 198