PageSourceSearch

https://nimg1.hicustom.com/static/vue/components/components.js?v=1.0.17

js hicustom.com collected 2026-09-26 08:31:50 UTC 89,175 bytes, 2,875 lines download raw bytes

1;(function (){
2	'use strict'
3	let txtRadio = `<div class="txt-radio" id="txtRadio">
4				        <span class="com-search-tit">{{label}}:</span>
5				        <div class="com-search-cont multi"
6				             ref="searchCont"
7				             v-show="!moreboxShow && !multiShow && !multiSelectShow"
8				             style="position: relative">
9							<a class="txt-radio-con" 
10								v-if="isShowAll"
11				               :class="{on: value == ''}"
12				               @click="$emit('input', '')">
13				                全部
14				            </a>
15				            <a v-for="item, index in list"
16				               class="txt-radio-con"
17				               :title="item.name"
18				               :class="{on: currentValue.indexOf(String(item.id)) > -1}"
19				               @click="select(item.id, index)"
20				               ref="searchCon">
21				                {{item.name}}
22				            </a>
23				        </div>
24				        <template>
25				            <div class="multi-search-cont checked-box" v-if="multi" v-show="multiSelectShow && !multiShow">
26				                <div class="checked-cont-bar">{{currentMultiName}}</div>
27				                <div class="txt-muitl-search-clear" @click="clearMulti">
28				                    清除多选<i class="icon-X"></i>
29				                </div>
30				            </div>
31				            <div class="multi-search-cont more-box multi" v-if="multi" v-show="multiShow">
32				                <div class="multi-tit">
33				                    <div class="search-bar">
34				                        <input class="txt-radio-name"
35				                               type="text"
36				                               :value="multiKey"
37				                               @input="multiFilter"
38				                               @compositionstart="banInput(false)"
39				                               @compositionend="banInput(true)"/>
40				                        <span class="multi-seach-btn"><i class="icon-search"></i></span>
41				                        <a class="txt-radio-clear o8 blue" v-show="multiKey" @click="clear('multi')">清除</a>
42				                    </div>
43				                </div>
44				                <div class="multi-cont">
45				                    <div class="multi-item-box letter">
46				                        <div class="multi-item"
47				                             v-for="item, index in filterListMul"
48				                             @click="multiSelect(item.id, index)">
49				                            <span class="span-checkbox"
50				                                  :title="item.name"
51				                                  :class="{'checked-part': multiItem.some((val)=>{return val.id == item.id })}">
52				                            </span>
53				                            {{item.name}}
54				                        </div>
55				                    </div>
56				                </div>
57				                <div class="multi-bottom">
58				                    <div class="checked-item-bar">
59				                        <span>已选{{title}}:</span>
60				                        <label :title="item.name" v-for="item ,index in multiItem" @click="multiItem.splice(index, 1)">
61				                            <span class="checked-part-icon"></span>{{item.name}}
62				                        </label>
63				                    </div>
64				                    <div class="btn-bar">
65				                        <a class="cancel-btn main-btn-w" @click="multiboxToggle(false)">取消</a>
66				                        <a class=" main-btn-b ml15" @click="multiSubmit">提交</a>
67				                    </div>
68				                </div>
69				            </div>
70				            <div class="multi-search-cont more-box more" v-if="morebox" v-show="moreboxShow">
71				                <div class="multi-tit">
72				                    <div class="search-bar">
73				                        <input class="txt-radio-name"
74				                               type="text"
75				                               :value="singleKey"
76				                               @input="singleFilter"
77				                               @compositionstart="banInput(false)"
78				                               @compositionend="banInput(true)" /> 
79				                        <span class="multi-seach-btn"><i class="icon-search"></i></span>
80				                        <a class="txt-radio-clear o8 blue" v-show="singleKey" @click="clear('single')">清除</a>
81				                    </div>
82				                </div>
83				                <div class="multi-cont">
84				                    <div class="multi-item-box letter">
85				                        <div class="multi-item" v-for="item, index in filterListSin">
86				                            <span class="txt-radio-con"
87				                            :title="item.name"
88				                            :class="{on: currentValue.indexOf(String(item.id)) > -1}"
89				                            @click="select(item.id, index)">{{item.name}}</span>
90				                        </div>
91				                    </div>
92				                </div>
93				            </div>
94				            <div class="multi-btn-bar">
95				                <a class="multi-search-btn multi"
96				                   v-if="morebox"
97				                   v-show="!moreboxShow && !multiShow && !multiSelectShow"
98				                   @click="moreboxToggle">
99				                   更多
100				                   <i class="icon-down1"></i>
101				                </a>
102				                <a class="multi-search-btn multi" v-if="multi"  v-show="!multiShow && !moreboxShow" @click="multiboxToggle">+多选</a>
103				                <a class="multi-search-btn multi" v-if="morebox" v-show="moreboxShow" @click="moreboxToggle">收起<i class="icon-top"></i></a>
104				            </div>
105				        </template>
106				    </div>`;
107	/**
108	 * 搜索组件--单选、多选、混合搜索
109	 * @props:
110	 * 		morebox: 是否混合搜索标志位,默认false
111	 * 		multi: 是否多选标志位,默认false
112	 * 		data: 数据列表,支持id-name数组 或 对象
113     * 	    value: 选中的值(双向绑定)
114	 * 		label: 搜索项的title
115	 * 	实例使用: /zwdc/view/factory/process/index.php
116	 *  <txt-radio label="加工状态" :data="processStatus" v-model="param.status"></txt-radio>
117	 */
118	Vue.component('txtRadio', {
119		props: {
120			label: String,
121			data: [Array, Object],
122			value: String,
123			morebox: {
124				type: Boolean,
125				default: false
126			},
127			multi: {
128				type: Boolean,
129				default: false
130			},
131			// 是否显示全部选项
132			isShowAll: {
133				type: Boolean,
134				default: true
135			}
136		},
137		data() {
138			return {
139				list: [], //  单选页面展示数据
140				filterListSin: [],  // 单选box数据源
141				filterListMul: [],  // 多选box数据源
142				multiItem: [], // 多选box已选项
143				singleKey: '', //单选box搜索关键字
144				multiKey: '', //多选box搜索关键字
145				input: true,  //是为输入模式
146				multiSelectShow: false,
147				moreboxShow: false,
148				multiShow: false
149			};
150		},
151		computed: {
152			currentData: function () {
153				return this.data instanceof Array ?
154						this.data :
155							Object.keys(this.data).map((id) => {
156								return {id: id, name: this.data[id]};
157							});
158			},
159			currentValue: function () {
160				return this.value.split(',');
161			},
162			currentMultiValue: function () {
163				if(this.currentValue.length > 1) {
164					this.multiSelectShow = true;
165					return this.currentData.filter((item) => {
166						return this.currentValue.indexOf(String(item.id)) > -1;
167					});
168				}
169				else return [];
170			},
171			currentMultiName: function () {
172				return this.currentMultiValue.map((item) => {
173					return item.name;
174				}).join('、');
175			}
176		},
177		created() {
178			this.list = [...this.currentData];
179			this.filterListSin = this.currentData;
180			this.filterListMul = this.currentData;
181
182			this.multiItem = [...this.currentMultiValue];
183		},
184		mounted() {
185			this.calculate();
186		},
187		methods: {
188			moreboxToggle() {
189				this.moreboxShow = !this.moreboxShow;
190			},
191			multiboxToggle(flag) {
192				this.multiShow = !this.multiShow;
193				if(!flag) {
194					this.multiItem = [];
195				}
196			},
197			select(id, index) {
198				let exist = this.list.some((item) => {
199					return item.id === id;
200				});
201				if(this.value === id) return;
202				this.$emit('input', String(id));
203				if(exist) return;
204				this.list.push(this.currentData[index]);
205				this.moreboxToggle();
206			},
207			multiSelect(id, index) {
208				let exist = this.multiItem.some((item) => {
209					return item.id === id;
210				});
211				if(exist) return;
212				this.multiItem.push(this.currentData[index]);
213			},
214			multiSubmit() {
215				if(this.multiItem.length === 0) {
216					promptInfo('请勾选搜索项');
217					return;
218				}
219				this.$emit('input', this.multiItem.map((item) => { return item.id; }).join(','));
220				this.multiboxToggle(true);
221				this.multiSelectShow = true;
222			},
223			banInput(flag) {
224				this.input = flag;
225			},
226			singleFilter(e) {
227				setTimeout(() => {
228					if(!this.input) return;
229					let value = e.target.value;
230					this.singleKey = value;
231					this.filterListSin = this.currentData.filter((item) => {
232						return item.name.indexOf(value) >= 0;
233					});
234				}, 0);
235			},
236			multiFilter(e) {
237				setTimeout(() => {
238					if(!this.input) return;
239					let value = e.target.value;
240					this.multiKey = value;
241					this.filterListMul = this.currentData.filter((item) => {
242						return item.name.indexOf(value) >= 0;
243					});
244				}, 0);
245			},
246			clearMulti() {
247				this.multiSelectShow = false;
248				this.$emit('input', '');
249				this.$nextTick(()=> {
250					this.calculate();
251				});
252			},
253			clear(type) {
254				if(type === 'single') {
255					this.singleKey = '';
256					this.filterListSin = this.currentData;
257				}
258				else {
259					this.multiKey = '';
260					this.filterListMul = this.currentData;
261				}
262			},
263			calculate() {
264				let startIndex;
265				this.$refs.searchCon.some((item, index) => {
266					if(item.offsetTop > 6) {
267						startIndex = index;
268						return true;
269					}
270				});
271				this.list = this.currentData.slice(0, startIndex);
272			}
273		},
274		template: txtRadio
275	});
276
277	let inputText = `<div class="input-text">
278				        <span class="com-search-tit">{{label}}:</span>
279				        <div class="com-search-cont">
280				            <input class="com-search-input w50"
281				                   :value="value"
282				                   @input="$emit('input', $refs.input.value)"
283				                   ref="input"/>
284				        </div>
285				    </div>`;
286	/**
287	 * 搜索组件--单选框
288	 * @props:
289	 * 		value: 默认值(双向绑定)
290	 * 		label: 搜索项的title
291	 * 	实例使用: /zwdc/view/factory/process/index.php
292	 *  <input-text label="加工单号" v-model="param.process_id" @keydown.enter.native="search()"></input-text>
293	 */
294	Vue.component('inputText', {
295		props: ['label', 'value'],
296		template: inputText
297	});
298
299	let txtTip = `<div :class="['txt-tip', direction]">
300			        <slot></slot>
301			        <div class="txt-tip-wrap" :style="style">
302			            <slot name="tip"></slot>
303			        </div>
304			    </div>`;
305	/**
306	 * 悬浮气泡组件
307	 * @props:
308	 * 		direction: 气泡方向
309	 * 		position: 气泡偏移量
310	 * 	实例使用: /zwdc/view/factory/process/index.php
311	 * 	<txt-tip direction="top" position="-20px">
312     *       <i class="icon icon-question2"></i>
313     *       <template v-slot:tip>
314     *           <p>备货周期=库存周期+收货周期</p>
315     *       </template>
316     *  </txt-tip>
317	 */
318	Vue.component('txtTip', {
319		props: {
320			direction: { // 位置:left, top, bottom
321				type: String,
322			default: 'left'
323			},
324			position: { // 偏移距离:px$, %$
325				type: String
326			}
327		},
328		data() {
329			return {
330				style: '',
331			};
332		},
333		created() {
334			if(this.position){
335				switch(this.direction) {
336				case 'top': {
337					this.style = `left: ${this.position};`;
338					break;
339				}
340				case 'bottom': {
341					this.style = `left: ${this.position};`;
342					break;
343				}
344				default: {
345					this.style = `top: ${this.position};`;
346					break;
347				}
348				}
349			}
350		},
351		template: txtTip
352	});
353
354	let pagination = `<div id="pagination">
355				        <div class="page-sel">
356				            显示
357				            <select class="page-num" v-model="perPage" @change="reset">
358				                <option :value="item" v-for="item, index in pages">{{item}}</option>
359				            </select>
360				            每页
361				        </div>
362				        <div class="page-plugin">
363				            <div class="letter page-div">
364				                <div class="light-pagination light-theme simple-pagination">
365				                    <ul>
366				                        <li class="active" @click="prev(thispage - 1)">
367				                            <span :class="thispage > 1? 'active' : 'current prev'"><div><i class="icon-previous_page"></i></div></span>
368										</li>
369										<template v-if="lastpage < 5">
370											<li v-for="item in lastpage"
371												:class="{active: thispage == item}"
372												@click="goto(item)">
373												<a :class="thispage == item? 'current' : 'page-link'">{{item}}</a>
374											</li>
375										</template>
376										<template v-else>
377											<li v-if="thispage>=2" @click="goto(1)">
378												<a class="page-link">1</a>
379											</li>
380											<template v-if="thispage>=4">
381												<li v-if="thispage==4" @click="goto(4)"><a class="page-link">2</a></li>
382												<li v-else class="disabled"><span class="ellipse">…</span></li>
383											</template>
384											<li v-if="thispage>=3" @click="goto(thispage-1)"><a class="page-link">{{thispage-1}}</a></li>
385											<li class="active"><a class="current">{{thispage}}</a></li>
386											<li v-if="thispage<=lastpage-2" @click="goto(thispage+1)"><a class="page-link">{{thispage+1}}</a></li>
387											<template v-if="thispage<=lastpage-3">
388												<li v-if="lastpage-thispage==3"><a class="page-link">{{lastpage-1}}</a></li>
389												<li v-else class="disabled"><span class="ellipse">…</span></li>
390											</template>
391											<li v-if="thispage<=lastpage-1" @click="goto(lastpage)"><a class="page-link">{{lastpage}}</a></li>
392										</template>
393										<li @click="next(thispage + 1)">
394											<span :class="thispage < lastpage? 'active' : 'current next'"><div><i class="icon-next_page"></i></div></span>
395										</li>
396				                    </ul>
397				                </div>
398				                <div class="page-info">共<span class="total-page">{{lastpage}}</span>页&nbsp;&nbsp;&nbsp;&nbsp;到第
399				                    <input type="text" class="page-input" v-model="nextPage">页<a class="main-btn-w flip-page" @click="goto(nextPage)">确定</a></div>
400				            </div>
401				        </div>
402				    </div>`;
403	/**
404	 * 分页组件
405	 * @props:
406	 * 		pages: 每页显示的项数的列表数组
407	 * 		perpage: 默认每页显示的项数
408	 * 		lastpage: 总页数
409	 * 		thispage: 当前页面
410	 * 	实例使用: /zwdc/view/factory/process/index.php
411	 * 	<pagination :perpage="gridData.per_page" :lastpage="gridData.last_page" @change="search" :thispage="thisPage"></pagination>
412	 */
413	Vue.component('pagination', {
414		props: {
415			pages: {
416				type: Array,
417				default: function () {
418					return [20, 30, 50, 100, 200];
419				}
420			},
421			perpage: {
422				type: Number,
423				default: 20
424			},
425			lastpage: {
426				type: Number,
427				require: true
428			},
429			thispage: {}
430		},
431		data() {
432			return {
433				nextPage: '',
434				perPage: this.perpage
435			};
436		},
437		watch: {
438			'nextPage': function (val) {
439				this.nextPage = val.replace(/\D/g, '');
440			},
441			'perpage': function(val){
442				this.perPage = val;
443			}
444		},
445		created() {
446		},
447		methods: {
448			goto(page) {
449				if(this.thispage == page) return;
450				if(page > this.lastpage) {
451					promptInfo('输入页码大于总页数');
452					return;
453				}
454				this.$emit('change', page, this.perPage);
455				this.nextPage = '';
456			},
457			reset() {
458				this.$emit('change', 1, this.perPage);
459			},
460			prev(page) {
461				if(page < 1) return;
462				this.goto(page);
463			},
464			next(page) {
465				if(page > this.lastpage) return;
466				this.goto(page);
467			}
468		},
469		template: pagination
470	});
471
472	/**
473	 * 查看弹窗
474	 * @props:
475	 * 		title: 弹窗标题
476	 * 		value: 控制弹窗是否显示的变量名,外部传入
477	 * 		width: 弹窗最小宽度
478	 * slot:
479	 * 		默认插槽:弹窗主题
480	 * 		footer: 弹窗底部交互按钮区域
481	 *
482	 * 	实例使用: /zwdc/view/factory/process/index.php
483	 */
484	Vue.component('pop-module', {
485		props: {
486			title: {
487				type: String,
488			default: '查看详情'
489			},
490			value: {
491				type: Boolean,
492			default: false
493			},
494			width: {
495			default: '580px'
496			}
497		},
498		template: `<transition name="pop-ani">
499		            <div style="position: fixed; z-index: 99; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,.4);" 
500		              v-show="value" @click="$emit('input', false)">
501		              <div class="com-pop-module"
502		                  style="display: block;" :style="'min-width:'+ width" @click.stop="">
503		                <div class="com-pop-title com-bg-color-w">
504		                  <a class="pop-close-btn opacity8" @click="$emit('input', false)">
505		                    <i class="icon-X"></i>
506		                  </a>
507		                  {{title}}
508		                </div>
509		                <div class="com-pop-cont">
510		                  <slot></slot>
511		                </div>
512		                <div class="com-pop-bottom" v-if="'footer' in this.$slots">
513		                  <slot name="footer"></slot>
514		                </div>
515		              </div>
516		            </div>
517		          </transition>`
518	});
519
520	let dialogContainer = document.body;
521	let alert = `<pop-module :title="title" :width="width" v-model="isShow">
522			        <div class="box-wrap" style="text-align: center;">
523			            {{text}}
524			        </div>
525			        <template v-slot:footer>
526			            <a class="main-btn-w" @click="close(false)" v-if="buttons[1]">{{buttons[1]}}</a>
527			            <a class="main-btn-b ml15" @click="close(true)">{{buttons[0]}}</a>
528			        </template>
529			    </pop-module>`;
530	/**
531	 * VUE实例方法拓展--弹窗实例
532	 * @param text 提示内容
533	 * @param opt 标题
534	 * @returns {Promise<any>}
535     * vue对象内部使用:this.$alert('弹窗提示内容', '标题opt').then(dlg => { dlg.close();  ... });
535 返回promise对象,接受then回调;
536     * @param opt 也可以是对象,提供更多配置 {
537	 *			title : '标题',
538	 *			width : '360px',
539	 *			buttons : ['确定', '取消'],
540	 *	}
541	 * 使用范例: /zwdc/view/factory/process/materialRelation.php
542	 */
543	function showAlert(text, opt){
544		let vm = null;
545		let options;
546		let defaults = {
547				title : '提示',
548				width : '360px',
549				buttons : ['确定', '取消'],
550		};
551		if(Object.prototype.toString.call(opt).slice(8, -1) === 'String') {
552			options = Object.assign({}, defaults, {title: opt});
553		}
554		else{
555			options = Object.assign({}, defaults, opt);
556		}
557		let exec = new Promise((resolve, reject)=>{
558			let alertOptions = {
559					data:function(){
560						return {
561							title: options.title,
562							text: text,
563							width: options.width,
564							buttons: options.buttons,
565							isShow: true
566						};
567					},
568					watch: {
569						'isShow': function (val) {
570							if(!val) this.close(false);
571						}
572					},
573					methods:{
574						close(flag) {
575							let dlg = () => {dialogClose(vm);}
576							if(flag) {
577								resolve(dlg);
578							}
579							else dlg();
580						}
581					},
582					template: alert
583			};
584			let creator = Vue.extend(alertOptions);
585			vm = new creator().$mount();
586			dialogContainer.appendChild(vm.$el);
587		});
588		return exec;
589	}
590	//删除组件vm(从文本流中移除,并在vue中销毁)
591	function dialogClose(vm){
592		try{ dialogContainer.removeChild(vm.$el); }
593		catch (e) {}
594		vm.$destroy();
595	}
596	Vue.prototype.$alert = showAlert;
597
598	Vue.component('tooltip', {
599		template: `
600			<div v-tip>
601				<slot></slot>
602				<div style="display:none;" class="group-type-wrap">{{content}}</div>
603			</div>
604		`,
605		props: {
606			content: ""
607		},
608		data() {
609			return {
610				show: false
611			}
612		},
613		directives: {
614			tip: {
615				inserted(el) {
616					el.addEventListener('mouseover', () => {
617						el.querySelector('.group-type-wrap').style.display = 'block'
618					})
619					el.addEventListener('mouseout',() => {
620						el.querySelector('.group-type-wrap').style.display = 'none'
621					})
622				}
623			}
624		}
625	})
626
627	Vue.component('sort-th', {
628		template: `
629			<th style="cursor:pointer;" @click="sort">
630				{{title}}
631				<div class="filter-up-down">
632					<span :class='["filter-up", {active: active === "asc"}]'></span>
633					<span :class='["filter-down", {active: active === "desc"}]'></span>
634				</div>
635			</th>
636		`,
637		props: {
638			title: ""
639		},
640		data() {
641			return {
642				active: false
643			}
644		},
645		methods: {
646			reset() {
647				this.active = false
648			},
649			sort() {
650				if (!this.active) {
651					this.active = 'desc'
652				} else if (this.active === 'asc') {
653					this.active = 'desc'
654				} else {
655					this.active = 'asc'
656				}
657				this.$emit('sort', this.active)
658			}
659		}
660
661	})
662
663    // 树形组件
664	Vue.component('tree', {
665		template:
666		`<div class="category-tree" @click.stop>
667			<div class="selected-box" @click="toggleDropdown">
668				<input type="text" :value="selectedCg" readonly>
669				<i class="icon-drop-down"></i>
670			</div>
671			<div class="result-box" v-show="isShow">
672				<div class="search-box">
673					<input type="text" placeholder="搜索分类" :value="keyword" @keydown.13="treeSearch" />
674				</div>
675				<div class="result-list">
676					<tree-item :tree-data="treeData" :keyword="keyword" :selected-node="selectedNode"></tree-item>
677				</div>
678			</div>
679		</div>`,
680		props:{
681			selectedNode:{
682				type: Number,
683				default: -1
684			}
685		},
686		data(){
687			return {
688				treeData: [{
689					title: '所有分类',
690					id: -1,
691					isOpen: true,
692					subCg:[
693						{
694							title: '1服装类',
695							id: 1,
696							isOpen: true,
697							subCg:[
698								{
699									title: '1-1短袖T恤',
700									id: 101,
701									isOpen: false,
702									subCg:[
703										{title: '男装', id: 10101},
704										{title: '女装', id: 10102},
705										{title: '青少年', id: 10103},
706									]
707								}
708							]
709						},{
710							title: '1-2家居用品',
711							id: 2,
712							isOpen: false,
713							subCg:[
714								{title: '客厅用品', id: 201},
715							]
716						}
717					]
718				}],
719				keyword: '',
720				isShow:false,
721				selectedCg: '所有分类'
722			}
723		},
724		methods:{
725			toggleDropdown(e){
726				this.isShow = !this.isShow;
727			},
728			treenodeChange(data){
729				this.isShow = false;
730				this.selectedCg = data;
731			},
732			treeSearch(e){
733				this.keyword = e.target.value;
734			}
735		},
736		created(){
737			this.$root.$on('treenode-change', (data)=>{
738				this.isShow = false;
739				this.selectedCg = data.fullname;
740			})
741		},
742		mounted(){
743			$(document).on('click', ()=>{
744				this.isShow = false;
745			})
746		}
747	});
748	Vue.component('tree-item', {
749		template:
750		`<ul>
751			<li v-for="item in treeDataFilter" 
752				:class="{'open': item.isOpen}"
753				:key="">
754				<div class="node" :style="styless">
755					<template v-if="item.subCg">
756						<!--<i class="icon-drop-down open" @click="item.isOpen=false"></i>
757						<i class="icon-next_page close" @click="item.isOpen=true"></i>-->
758						<i class="icon-drop-down open" @click="changeOpenStatus(item, false)"></i>
759						<i class="icon-next_page close" @click="changeOpenStatus(item, true)"></i>
760					</template>
761					<a @click="selectTreeNode(event, item, iParent+'>'+item.id, iParentName+'>'+item.title)">
762						{{item.title}}
763					</a>
764				</div>
765				<template v-if="item.subCg">
766					<tree-item 
767						:tree-data="item.subCg" 
768						:i-count="count" 
769						:i-parent="iParent+'>'+item.id"
770						:i-parent-name="iParentName+'>'+item.title">
771					</tree-item>
772				</template>
773			</li>
774		</ul>`,
775		props:{
776			treeData:{
777				type: Array,
778				default:[]
779			},
780			keyword: {
781				type: String,
782				default: ''
783			},
784			selectedNode:{
785				type: Number,
786				default: -1
787			},
788			iCount:{
789				type: Number,
790				default: 0
791			},
792			iParent: {
793	            type: String,
794	            default: '',
795	        },
796	        iParentName: {
797	            type: String,
798	            default: '',
799	        }
800		},
801		data(){
802			return{
803				activeNode: this.selectedNode,
804			}
805		},
806		computed: {
807			count(){
808				return ++this.iCount;
809			},
810			styless(){
811				return {
812					'padding-left': this.count>=2 ? this.count*10+'px' : 0
813				}
814			},
815			// treeDataByName(){
816			// 	return this.filterTreeNode(this.treeData, node=>node.title.indexOf(this.keyword)>-1);
817			// },
818			// treeDataById(){
819			// 	return this.filterTreeNode(this.treeData, node=>node.id==this.selectedNode);
820			// },
821			treeDataFilter(){
822				let newTreeData = this.filterTreeNode(this.treeData, node=>node.title.indexOf(this.keyword)>-1);
823				return newTreeData;
824			},
825		},
826		watch:{
827			'keyword': function(){
828				console.log('keyword改变了', this.keyword);
829			}
830		},
831		methods:{
832			filterTreeNode(nodes, predicate) {
833			    // 如果已经没有节点了,结束递归
834			    if (!(nodes && nodes.length)) {
835			        return;
836			    }
837			    // let nodesCopy = [...nodes];
838			    let nodesCopy = base.deepCopy(nodes);
839			    let newChildren = [];
840			    for (let node of nodesCopy) {
841			        if (predicate(node)) {
842			            // 如果自己(节点)符合条件,直接加入到新的节点集
843			            newChildren.push(node);
844			            // 并接着处理其 children
845			            node.subCg = this.filterTreeNode(node.subCg, predicate);
846			        } else {
847			            // 如果自己不符合条件,需要根据子集来判断它是否将其加入新节点集,根据递归调用 filterTreeNode() 的返回值来判断
848			            let subs = this.filterTreeNode(node.subCg, predicate);
849			            if (subs && subs.length) {
850			                // 1. 如果子孙集中有符合要求的节点(返回 [...]),加入
851			                node.subCg = subs;
852			                newChildren.push(node);
853			            }
854			            // 2. 否则,不加入(因为整个子集都没有符合条件的)
855			        }
856			    }
857			    return newChildren.length ? newChildren : void 0;
858			},
859			// 节点选中,派发事件
860			selectTreeNode(e, item, fullpath, fullname){
861	            // this.selectedNode = item.id;
862	            this.$root.$emit('treenode-change', {item, fullpath:fullpath.slice(1), fullname:fullname.slice(1)});
863	        },
864	        changeOpenStatus(item, status){
865	        	this.$set(item, 'isOpen', status);
866	        	this.$forceUpdate();
867	        }
868		},
869		watch:{
870
871		},
872		created(){
873			// console.log('sss');
874			// console.log(this.treeData);
875		}
876	});
877
878	// 搜索下拉框,库存sku/商品sku页面
879	Vue.component('ajax-select', {
880		template: `<div class="custom-select-box" @click.stop>
881			<div class="cont">
882				<div class="option-selected" @click="showDropdown">
883					<div class="overHidden" v-if="selectedTxt.length > 0" v-bind:title="selectedTxt" v-html="selectedTxt"></div>
884					<input v-else class="selected" placeholder="请选择" style="background:#fff !important" :value="selectedTxt" readonly />
885					<i class="icon-moredown"></i>
886				</div>
887				<div class="option-box" v-show="value">
888					<div class="search-box">
889						<input type="text" class="keyword" v-model="keyword" :placeholder="placeholder" @keydown.enter="search" v-focus="value" ref="keyword">
890						<i class="icon-checkout_close clear" @click="clearAll"></i>
891						<i class="icon-search search" @click="search"></i>
892					</div>
893					<div class="option-list scroll-bar">
894						<ul v-if="resultData.length">
895							<template v-if="deleteJudge">
896								<li v-for="item in resultData" :class="{selected: item.isChecked}" :key="item.id" @click="optionSelect($event,item)">
897									<label>
898										<!--<input type="checkbox" v-model="item.isChecked" @click="optionSelect($event,item)" v-show="multiple" />-->
899										<input type="checkbox" :checked="item.isChecked" v-show="multiple" />
900										<span v-html="item.name"></span>
901									</label>
902								</li>
903							</template>
904							<template v-else>
905								<li v-for="item in resultData" :class="{selected: item.isChecked}" :key="item.id">
906									<label>
907										<input type="checkbox" :checked="item.isChecked" v-show="multiple" @change="optionSelect($event,item)" />
908										<span v-html="item.name"></span>
909									</label>
910								</li>
911							</template>
912						</ul>
913						<div class="no-result" v-else>{{noResultTxt}}</div>
914					</div>
915				</div>
916			</div>
917		</div>`,
918		props:{
919			url:{
920				type: String,
921				default: ''
922			},
923			multiple:{
924				type: Boolean,
925				default: false
926			},
927			type:{
928				type: String
929			},
930			init:{ //初始选中值
931				type: Array,
932				default: ()=>[]
933			},
934			deleteJudge:{ //删除时是否进行判断
935				type: Boolean,
936				default: false
937			},
938			placeholder: {
939				type: String,
940				default: '搜索账号、姓名、群组编号'
941			}
942		},
943		data(){
944			return{
945				value: false,
946				keyword: '',
947				noResultTxt: '请先输入搜索关键字',
948				resultData:[],
949				selectedData: this.init ? this.init : []
950			}
951		},
952		computed:{
953			selectedTxt(){
954				let txtArr = this.selectedData.map(item=>{
955					return item.name;
956				})
957				return txtArr.join(',');
958			}
959		},
960		watch:{
961			'selectedData': {
962				handler(newValue, oldValue) {
963					this.$parent.$emit('selected-change', newValue, this.type);
964				},
965				deep: true
966			}
967		},
968		directives:{
969			focus:{
970				// update: function(el, binding, vnode, oldVnode){
971				// 	if(binding.value){
972				// 		el.focus();
973				// 	}
974				// }
975			}
976		},
977		methods:{
978			// 过滤html标签
979			filterHTMLTag(data){
980				data = data.replace(/<\/?[^>]*>/g, ''); //去除HTML Tag
981				data = data.replace(/[|]*\n/, '') 		//去除行尾空格
982				data = data.replace(/&npsp;/ig, ''); 	//去掉npsp
983				return data;
984			},
985			showDropdown(){
986				this.value = !this.value;
987				if(this.value){ //展开时,默认内容为空
988					this.$nextTick(()=>{
989						this.$refs.keyword.focus();
990					})
991					this.keyword = '';
992					this.resultData = [];
993					this.noResultTxt = '请先输入搜索关键字';
994					// 页面中的其它下拉框收起
995					this.$parent.$emit('close-other');
996					this.value = true;
997				}
998			},
999			search(){
1000				if(this.keyword){
1001					this.resultData = [];
1002					this.noResultTxt = '搜索中...';
1003					let self = this;
1004					$.ajax({
1005						type: 'post',
1006						url: this.url,
1007						data:{keyword: self.keyword},
1008						success: function(res){
1009							if(res.status>0){
1010								if(res.data && !$.isEmptyObject(res.data)){
1011									self.resultData = res.data.constructor=='Array' ? res.data : Object.values(res.data);
1012									// 标识选中项
1013									self.resultData.forEach(item=>{
1014										let isExist = self.selectedData.some(sItem=>sItem.id==item.id);
1015										self.$set(item, 'isChecked', isExist ? true : false);
1016									});
1017								} else{
1018									self.noResultTxt = '没有匹配到任何结果';
1019								}
1020							} else{
1021								self.noResultTxt = '没有匹配到任何结果';
1022							}
1023						}
1024					})
1025				} else{
1026					this.resultData = [];
1027					this.noResultTxt = '请先输入搜索关键字';
1028				}
1029			},
1030			clearAll(){
1031				this.keyword = '';
1032				this.resultData = [];
1033				this.noResultTxt = '请先输入搜索关键字';
1034			},
1035			// 将选项设置为选中
1036			optionCheck(item){
1037				this.resultData.forEach(sItem=>{
1038					if(sItem.id==item.id){
1039						this.$set(sItem, 'isChecked', true);
1040					}
1041					return sItem;
1042				});
1043				let isExist = this.selectedData.some(sItem=>sItem.id==item.id);
1044				if(!isExist){
1045					this.selectedData.push(item);
1046				}
1047			},
1048			// 将选项设置为不选中
1049			optionUncheck(item){
1050				this.resultData.forEach(sItem=>{
1051					if(sItem.id==item.id){
1052						this.$set(sItem, 'isChecked', false);
1053					}
1054					return sItem;
1055				});
1056				let _index = this.selectedData.findIndex(sItem=>sItem.id==item.id);
1057				if(_index>-1){
1058					this.selectedData.splice(_index, 1);
1059				}
1060			},
1061			optionSelect(e, item){
1062				if(!this.multiple){ //单选
1063					this.resultData.forEach(sItem=>{
1064						if(sItem.id != item.id){
1065							this.$set(sItem, 'isChecked', false);
1066						} else{
1067							this.$set(sItem, 'isChecked', true);
1068						}
1069						return sItem;
1070					})
1071					this.selectedData = [item];
1072					this.value = false;
1073				} else { //多选
1074					if(!item.isChecked) { //添加
1075						this.optionCheck(item);
1076					} else{ //删除选中
1077						// 如果删除选项需要进行判断,则派发事件给父级,由父级操作,否则直接删除
1078						if(this.deleteJudge){
1079							this.$parent.$emit('option-del', item, e, this.type);
1080						} else{
1081							this.optionUncheck(item);
1082						}
1083					}
1084				}
1085			}
1086		},
1087		beforeMount() {
1088			this._close = e => {
1089				// 如果点击发生在当前组件内部, 则不处理, 否则收起
1090			    if(this.$el.contains(e.target)) {
1091			    	return;
1092				}
1093				this.value = false;
1094			};
1095		},
1096		mounted(){
1097			document.body.addEventListener('click', this._close);
1098		},
1099		beforeDestroy() {
1100			document.body.removeEventListener('click', this._close);
1101		},
1102	})
1103
1104	// 产品选择弹窗
1105	Vue.component('product-select-pop', {
1106		template:
1107		`<transition name="fade">
1108			<div class="popup product-select-popup" v-show="value">
1109				<div class="cont" style="width:740px">
1110					<i class="icon-checkout_close" @click="closePop"></i>
1111					<div class="popup-title">选择产品</div>
1112					<div class="popup-content">
1113						<div class="product-select-pop">
1114							<div class="flex-row flex-x-full">
1115								<div class="form-item flex-row flex-y-center" style="width:50%">
1116									<div class="form-label mr5">产品分类:</div>
1117									<div class="form-content">
1118										<treeselect
1119											v-model="selectedCg"
1120											:options="cgData"
1121											:multiple="false"
1122											placeholder="所有分类"
1123											:show-count="true"
1124											:default-expand-level="0"
1125											@select="selectCg"
1126											:normalizer="normalizer"
1127											noOptionsText="无法读取分类"
1128										/>
1129									</div>
1130								</div>
1131								<div class="form-item ml15 flex-row flex-y-center" style="width:50%">
1132									<div class="form-label mr5">产品类型:</div>
1133									<div class="form-content">
1134										<select v-model="searchParam.type">
1135											<option value="">请选择</option>
1136											<option value="2">促销产品</option>
1137											<option value="1">优选产品</option>
1138											<option value="3">最新产品</option>
1139										</select>
1140									</div>
1141								</div>
1142							</div>
1143							<div class="flex-row flex-wrap mt10">
1144								<div class="form-item flex-row flex-y-center">
1145									<div class="form-label mr5">产品名称/ID:</div>
1146									<div class="form-content">
1147										<input type="text" :placeholder="isMultiple?'多个名称/ID用逗号或空格分开':'请输入产品名称/ID'" v-model="searchParam.pro_name_num" style="width:346px;">
1148									</div>
1149								</div>
1150								<div class="ml15 mt10">
1151									<a class="main-btn mr5" @click="search(1)">搜索</a>
1152									<a class="main-btn gray" @click="reset">重置</a>
1153									<!--<a class="main-btn" @click="batchSelect">批量选取</a>
1154									<a class="main-btn gray" @click="batchCancel">批量取消</a>-->
1155								</div>
1156							</div>
1157							<div style="max-height: 340px;min-height: 260px;overflow-y:auto" class="scrollbar mt10">
1158								<table class="normal product-table">
1159									<thead>
1160										<tr>
1161											<th style="width:40px;">
1162												<input v-if="isMultiple" type="checkbox" v-model="checkAll" @change="toggleCheckAll" />
1163											</th>
1164											<th>编号</th>
1165											<th style="width:260px">产品名称</th>
1166											<th>最低起批价</th>
1167											<th>生产商</th>
1168										</tr>
1169									</thead>
1170									<tbody>
1171										<template v-if="!productList.length">
1172											<tr><td colspan="5">查询无结果</td></tr>
1173										</template>
1174										<template v-else>
1175											<tr v-for="item,index in productList">
1176												<td>
1177													<label><input :type="isMultiple ? 'checkbox' : 'radio'" v-model="checkItems" :value="item.id" @change="toggleCheckItem(item, index)" /></label>
1178												</td>
1179												<td>{{item.id}}</td>
1180												<td class="tl">
1181													<div>
1182														<div class="img-wrap">
1183															<img :src="Object.values(Object.values(item.productTypeImg)[0])[0].small" />
1184														</div>
1185														{{item.pro_name}}
1186													</div>
1187												</td>
1188												<td>{{item.price ? '¥'+item.price : '未设定销售价格'}}</td>
1189												<td>{{item.factory_name}}</td>
1190											</tr>
1191										</template>
1192									</tbody>
1193								</table>
1194							</div>
1195							<div class="flex-row flex-x-full flex-y-center mt10">
1196								<pagination-pro :total="pageTotal" :per-page="perPage" :current-page="curPage" @change="changePage"></pagination-pro>
1197								<div><span v-if="isMultiple">已选择 <span class="blue">{{checkItems.length}}</span> 个产品</span><a class="main-btn red" style="color:#fff !important" @click="save">{{saveBtnLabel}}</a></div>
1198							</div>
1199						</div>
1200					</div>
1201				</div>
1202			</div>
1203		</transition>`,
1204		props: {
1205			value: {
1206				type: Boolean,
1207				default: true
1208			},
1209			categories: {
1210				type: Array,
1211				default:()=>[]
1212			},
1213			products: { //已关联的产品id
1214				type: Array,
1215				default: ()=>[]
1216			},
1217			checkProducts: { //已关联的产品项
1218				type: Array,
1219				default: []
1220			},
1221			extraParams: { //搜索的额外参数
1222				type: Object,
1223				default: ()=>{}
1224			},
1225			saveBtnLabel: {
1226				type: String,
1227				default: '确定关联'
1228			},
1229			searchProductUrl: {
1230				type: String,
1231				default: '/admin/page/searchProduct'
1232			},
1233			getCategoryUrl: {
1234				type: String,
1235				default: '/admin/page/getCategory'
1236			},
1237			isMultiple: { // 是否支持多选,默认多选
1238				type: Boolean,
1239				default: true
1240			}
1241		},
1242		data(){
1243			return {
1244				cgData: this.categories,
1245				productList: [],
1246				perPage: 20,
1247				curPage:1,
1248				pageTotal: 0,
1249				searchParam:{
1250					cat_id: this.selectedCg,
1251					type: '',
1252					pro_name_num: '',
1253				},
1254				selectedCg: -2,
1255				checkAll: false, //是否全选
1256				checkItems: this.products, //选中项
1257				checkProductList: JSON.parse(JSON.stringify(this.checkProducts)) , //选中的行
1258			}
1259		},
1260		watch:{
1261			'selectedCg': function(newValue, oldValue){
1262				if(!newValue){
1263					this.selectedCg = -2;
1264					this.$set(this.searchParam, 'cat_id', this.selectedCg);
1265				}
1266			},
1267		},
1268		methods:{
1269			// 搜索
1270			search(page=this.curPage, pageSize=this.perPage){
1271				let self = this;
1272				self.searchParam = Object.assign({}, self.searchParam, {
1273					page: page,
1274					pageSize: pageSize,
1275					cat_id: !self.searchParam.cat_id || self.searchParam.cat_id==-2 ? '' : self.searchParam.cat_id
1276				}, self.extraParams);
1277				showLoading();
1278				$.ajax({
1279					type: 'post',
1280					url: self.searchProductUrl,
1281					data: self.searchParam,
1282					success: function(res){
1283						hideLoading();
1284						if(res.status>0){
1285							self.productList = res.data.data;
1286							self.curPage = res.data.current_page;
1287							self.pageTotal = res.data.total;
1288							self.checkAll = false;
1289						} else{
1290							promptInfo(res.msg);
1291						}
1292					}
1293				})
1294			},
1295			// 翻页
1296			changePage(page){
1297				this.curPage = page;
1298				this.search();
1299			},
1300			// 重置
1301			reset(){
1302				this.curPage = 1;
1303				this.selectedCg = -2;
1304				this.searchParam = Object.assign({},{
1305					cat_id: '',
1306					type: '',
1307					pro_name_num: '',
1308					page: this.curPage
1309				});
1310				this.search();
1311			},
1312			// 选中产品分类
1313			selectCg(node, instanceId){
1314				this.selectedCg = node.id;
1315				this.$set(this.searchParam, 'cat_id', this.selectedCg);
1316			},
1317			// 全选反选
1318			toggleCheckAll(){
1319				if(this.checkAll){ //全选
1320					this.productList.forEach((item,index)=>{
1321						let isExist = this.checkItems.some(jItem=>jItem==item.id);
1322						if(!isExist){
1323							this.checkItems.push(item.id);
1324							this.checkProductList.push(item)
1325						}
1326					});
1327				} else{ //反选
1328					this.productList.forEach((item,index)=>{
1329						let jIndex = this.checkItems.findIndex(jItem=>jItem==item.id);
1330						if(jIndex>-1){
1331							this.checkItems.splice(jIndex,1);
1332							this.checkProductList.splice(jIndex,1);
1333						}
1334					});
1335				}
1336			},
1337			toggleCheckItem(item, index){
1338				let checkItems = JSON.parse(JSON.stringify(this.checkItems))
1339				if (!this.isMultiple) {
1340					checkItems = [checkItems]
1341				}
1342				// 列表中存在未选中的项时,全选不勾选
1343				this.productList.forEach(item=>{
1344					let isExist = checkItems.some(jItem=>jItem==item.id);
1345					if(!isExist){
1346						this.checkAll = false;
1347						return;
1348					}
1349				})
1350				let jIndex = this.checkProductList.findIndex(jItem=>jItem.id==item.id);
1351				if(jIndex>-1){
1352					this.checkProductList.splice(jIndex,1);
1353				} else {
1354					if (this.isMultiple) {
1355						this.checkProductList.push(item)
1356					} else {
1357						this.checkProductList = [item]
1358					}
1359				}
1360			},
1361			// 确定使用
1362			save(){
1363				this.$emit('save', {checkItems: this.checkItems, checkProductList: this.checkProductList});
1364			},
1365			closePop(){
1366				this.$emit('input', false);
1367			},
1368			// 获取分类
1369			getCategory(){
1370				let self = this;
1371				$.ajax({
1372					type: 'post',
1373					url: self.getCategoryUrl,
1374					success: function(res){
1375						if(res.status>0){
1376							self.cgData = res.data;
1377							self.$emit('updateCgData', self.cgData);
1378						}
1379					}
1380				})
1381			},
1382			normalizer(node){
1383				return {
1384					id: node.id,
1385					label: node.curName,
1386					children: node.subCg,
1387				}
1388			},
1389		},
1390		created(){
1391			if(!this.cgData.length){
1392				// 预设为所有分类,解决显示unknown问题
1393				this.cgData = [{
1394					curName: "所有产品",
1395					id: -2
1396				}];
1397				this.getCategory();
1398			}
1399		},
1400		mounted(){
1401			this.search();
1402		}
1403	})
1404
1405// 定制产品选择弹窗
1406	Vue.component('custom-select-pop', {
1407		template:
1408			`<transition name="fade">
1409			<div class="popup product-select-popup" v-show="value">
1410				<div class="cont" style="width:740px">
1411					<i class="icon-checkout_close" @click="closePop"></i>
1412					<div class="popup-title">选择产品</div>
1413					<div class="popup-content">
1414						<div class="product-select-pop">
1415							<div class="flex-row flex-wrap mt10">
1416								<div class="form-item flex-row flex-y-center">
1417									<div class="form-label mr5">定制产品编号:</div>
1418									<div class="form-content">
1419										<input type="text" :placeholder="isMultiple?'多个编号用逗号或空格分开':'请输入编号'" v-model="searchParam.ids" style="width:346px;">
1420									</div>
1421								</div>
1422								<div class="ml15 mt10">
1423									<a class="main-btn mr5" @click="search(1)">搜索</a>
1424									<a class="main-btn gray" @click="reset">重置</a>
1425								</div>
1426							</div>
1427							<div style="max-height: 340px;min-height: 260px;overflow-y:auto" class="scrollbar mt10">
1428								<table class="normal product-table">
1429									<thead>
1430										<tr>
1431											<th style="width:40px;">
1432												<input v-if="isMultiple" type="checkbox" v-model="checkAll" @change="toggleCheckAll" />
1433											</th>
1434											<th>编号</th>
1435											<th>图片</th>
1436										</tr>
1437									</thead>
1438									<tbody>
1439										<template v-if="!firstFlag && !productList.length">
1440											<tr><td colspan="3">查询无结果</td></tr>
1441										</template>
1442										<template v-else>
1443											<tr v-for="item,index in productList">
1444												<td>
1445													<label><input :type="isMultiple ? 'checkbox' : 'radio'" v-model="checkItems" :value="item.id" @change="toggleCheckItem(item, index)" /></label>
1446												</td>
1447												<td>{{item.id}}</td>
1448												<td><img :src="item.image" /></td>
1449											</tr>
1450										</template>
1451									</tbody>
1452								</table>
1453							</div>
1454							<div class="flex-row flex-x-full flex-y-center mt10">
1455								<pagination-pro :total="pageTotal" :per-page="perPage" :current-page="curPage" @change="changePage"></pagination-pro>
1456								<div><span v-if="isMultiple">已选择 <span class="blue">{{checkItems.length}}</span> 个产品</span><a class="main-btn red" style="color:#fff !important" @click="save">{{saveBtnLabel}}</a></div>
1457							</div>
1458						</div>
1459					</div>
1460				</div>
1461			</div>
1462		</transition>`,
1463		props: {
1464			value: {
1465				type: Boolean,
1466				default: true
1467			},
1468			products: { //已关联的产品id
1469				type: Array,
1470				default: ()=>[]
1471			},
1472			checkProducts: { //已关联的产品项
1473				type: Array,
1474				default: []
1475			},
1476			extraParams: { //搜索的额外参数
1477				type: Object,
1478				default: ()=>{}
1479			},
1480			saveBtnLabel: {
1481				type: String,
1482				default: '确定关联'
1483			},
1484			searchProductUrl: {
1485				type: String,
1486				default: '/admin/product/getProductList'
1487			},
1488			isMultiple: { // 是否支持多选,默认多选
1489				type: Boolean,
1490				default: true
1491			}
1492		},
1493		data(){
1494			return {
1495				firstFlag: true,
1496				productList: [],
1497				perPage: 20,
1498				curPage:1,
1499				pageTotal: 0,
1500				searchParam:{
1501					ids: '',
1502				},
1503				checkAll: false, //是否全选
1504				checkItems: this.products, //选中项
1505				checkProductList: JSON.parse(JSON.stringify(this.checkProducts)) , //选中的行
1506			}
1507		},
1508		methods:{
1509			// 搜索
1510			search(page=this.curPage, pageSize=this.perPage){
1511				this.firstFlag = false;
1512				let self = this;
1513				self.searchParam = Object.assign({}, self.searchParam, {
1514					page: page,
1515					pageSize: pageSize,
1516				}, self.extraParams);
1517				showLoading();
1518				$.ajax({
1519					type: 'post',
1520					url: self.searchProductUrl,
1521					data: self.searchParam,
1522					success: function(res){
1523						hideLoading();
1524						if(res.status>0){
1525							self.productList = res.data.list;
1526							self.curPage = res.data.current_page;
1527							self.pageTotal = res.data.total;
1528							self.checkAll = false;
1529						} else{
1530							promptInfo(res.msg);
1531						}
1532					}
1533				})
1534			},
1535			// 翻页
1536			changePage(page){
1537				this.curPage = page;
1538				this.search();
1539			},
1540			// 重置
1541			reset(){
1542				this.curPage = 1;
1543				this.searchParam = Object.assign({},{
1544					ids: '',
1545					page: this.curPage
1546				});
1547				this.search();
1548			},
1549			// 全选反选
1550			toggleCheckAll(){
1551				if(this.checkAll){ //全选
1552					this.productList.forEach((item,index)=>{
1553						let isExist = this.checkItems.some(jItem=>jItem==item.id);
1554						if(!isExist){
1555							this.checkItems.push(item.id);
1556							this.checkProductList.push(item)
1557						}
1558					});
1559				} else{ //反选
1560					this.productList.forEach((item,index)=>{
1561						let jIndex = this.checkItems.findIndex(jItem=>jItem==item.id);
1562						if(jIndex>-1){
1563							this.checkItems.splice(jIndex,1);
1564							this.checkProductList.splice(jIndex,1);
1565						}
1566					});
1567				}
1568			},
1569			toggleCheckItem(item, index){
1570				let checkItems = JSON.parse(JSON.stringify(this.checkItems))
1571				if (!this.isMultiple) {
1572					checkItems = [checkItems]
1573				}
1574				// 列表中存在未选中的项时,全选不勾选
1575				this.productList.forEach(item=>{
1576					let isExist = checkItems.some(jItem=>jItem==item.id);
1577					if(!isExist){
1578						this.checkAll = false;
1579						return;
1580					}
1581				})
1582				let jIndex = this.checkProductList.findIndex(jItem=>jItem.id==item.id);
1583				if(jIndex>-1){
1584					this.checkProductList.splice(jIndex,1);
1585				} else {
1586					if (this.isMultiple) {
1587						this.checkProductList.push(item)
1588					} else {
1589						this.checkProductList = [item]
1590					}
1591				}
1592			},
1593			// 确定使用
1594			save(){
1595				this.$emit('save', {checkItems: this.checkItems, checkProductList: this.checkProductList});
1596			},
1597			closePop(){
1598				this.$emit('input', false);
1599			},
1600		},
1601		mounted(){
1602			// this.search();
1603		}
1604	})
1605	// 定制产品选择弹窗
1606	Vue.component('custom-select', {
1607		template:
1608			`<div>
1609				<div class="product-select-pop">
1610					<div class="flex-row flex-wrap mt10">
1611						<div class="form-item flex-row flex-y-center">
1612							<div class="form-label mr5">定制产品编号:</div>
1613							<div class="form-content">
1614								<input type="text" :placeholder="isMultiple?'多个编号用逗号分开':'请输入编号'" v-model="searchParam.ids" style="width:346px;">
1615							</div>
1616						</div>
1617						<div class="ml15 mt10">
1618							<a class="main-btn mr5" @click="search(1)">搜索</a>
1619							<a class="main-btn gray" @click="reset">重置</a>
1620						</div>
1621					</div>
1622					<div style="max-height: 340px;min-height:100px;overflow-y:auto" class="scrollbar mt10">
1623						<table class="normal product-table">
1624							<thead>
1625								<tr>
1626									<th style="width:40px;">
1627										<input v-if="isMultiple" type="checkbox" v-model="checkAll" @change="toggleCheckAll" />
1628									</th>
1629									<th>定制产品编号</th>
1630									<th>配套定制产品</th>
1631									<th>图片
1632										<span class='tip-box'>
1633											<span class="tips-icon icon-error_explain"></span>
1634											<div class="tips-info">
1635												<span class="tips-info-trangle"></span>
1636												<p>所选定制产品的主图</p>
1637											</div>
1638										</span>
1639									</th>
1640									<th style='width:100px'>排序值
1641										<span class='tip-box'>
1642											<span class="tips-icon icon-error_explain"></span>
1643											<div class="tips-info l300">
1644												<span class="tips-info-trangle"></span>
1645												<p>按照排序值降序排列,排序值越高,<br>位置越靠前(排序值最高的产品,优先显示定制产品主图)</p>
1646											</div>
1647										</span>
1648									</th>
1649								</tr>
1650							</thead>
1651							<tbody>
1652								<template v-if="!productList.length">
1653									<tr style="height:70px"><td colspan="5">查询无结果</td></tr>
1654								</template>
1655								<template v-else>
1656									<tr v-for="item,index in productList" :data-id='item.id' :key='item.id'>
1657										<td>
1658											<label><input :type="isMultiple ? 'checkbox' : 'radio'" v-model="checkItems" :value="item.id" @change="toggleCheckItem(item, index)" /></label>
1659										</td>
1660										<td>{{item.id}}</td>
1661										<td>
1662											<span class="custompro-id" @click="changeCustomizedProId(item)">{{item.sub_products}}</span>
1663										</td>
1664										<td><img :src="item.image" /></td>
1665										<td><input style="width:100%;height:100%;border:1px solid #949494" class='position' class="sort" type="text" oninput="onlyNum(this)" @blur='inputChange($event,item.id)' maxlength="9" v-model='item.position'></td>
1666									</tr>
1667								</template>
1668							</tbody>
1669						</table>
1670					</div>
1671					<div class="flex-row flex-x-full flex-y-center mt10">
1672						<pagination-pro :total="pageTotal" :per-page="perPage" :current-page="curPage" @change="changePage"></pagination-pro>
1673					</div>
1674				</div>
1675			</div>`,
1676		props: {
1677			value: {
1678				type: Boolean,
1679				default: true
1680			},
1681			products: { //已关联的产品id
1682				type: Array,
1683				default: ()=>[]
1684			},
1685			checkProducts: { //已关联的产品项
1686				type: Array,
1687				default: ()=>[]
1688			},
1689			extraParams: { //搜索的额外参数
1690				type: Object,
1691				default: ()=>{}
1692			},
1693			saveBtnLabel: {
1694				type: String,
1695				default: '确定关联'
1696			},
1697			searchProductUrl: {
1698				type: String,
1699				default: '/admin/product/getProductList'
1700			},
1701			isMultiple: { // 是否支持多选,默认多选
1702				type: Boolean,
1703				default: true
1704			},
1705			productList:{
1706				type: Array,
1707				default: ()=>[]
1708			}
1709		},
1710		data(){
1711			return {
1712				// productList: [],
1713				perPage: 20,
1714				curPage:1,
1715				pageTotal: 0,
1716				searchParam:{
1717					ids: '',
1718				},
1719				checkAll: false, //是否全选
1720				checkItems: this.products, //选中项
1721				checkProductList: JSON.parse(JSON.stringify(this.checkProducts)) , //选中的行
1722				setProducts: []
1723			}
1724		},
1725		methods:{
1726			// 搜索
1727			search(page=this.curPage, pageSize=this.perPage){
1728				let self = this;
1729				self.searchParam = Object.assign({}, self.searchParam, {
1730					page: page,
1731					pageSize: pageSize,
1732				}, self.extraParams);
1733				showLoading();
1734				$.ajax({
1735					type: 'post',
1736					url: self.searchProductUrl,
1737					data: self.searchParam,
1738					success: function(res){
1739						hideLoading();
1740						if(res.status>0){
1741							self.productList = res.data.list;
1742							self.curPage = res.data.current_page;
1743							self.pageTotal = res.data.total;
1744							self.checkAll = false;
1745							self.productList.forEach(item=>{
1746								self.$set(item,'position','')
1747							})
1748							self.$nextTick(()=>{
1749								self.setPosition()
1750								self.$emit('changeproductlist', self.productList);
1751							})
1752						} else{
1753							promptInfo(res.msg);
1754						}
1755					}
1756				})
1757			},
1758			// 翻页
1759			changePage(page){
1760				this.curPage = page;
1761				this.search();
1762			},
1763			// 重置
1764			reset(){
1765				this.curPage = 1;
1766				this.searchParam = Object.assign({},{
1767					ids: '',
1768					page: this.curPage
1769				});
1770				this.$emit('resetlist');
1771				// this.search();
1772			},
1773			inputChange(e,id){
1774				let self = this
1775				self.checkProductList.forEach((item,index)=>{
1776					if(item.id==id){
1777						self.checkProductList[index].position = e.currentTarget._value
1778					}
1779				})
1780				this.setDataInit()
1781			},
1782			// 全选反选
1783			toggleCheckAll(){
1784				if(this.checkAll){ //全选
1785					this.productList.forEach((item,index)=>{
1786						let isExist = this.checkItems.some(jItem=>jItem==item.id);
1787						if(!isExist){
1788							this.checkItems.push(item.id);
1789							this.checkProductList.push(item)
1790						}
1791					});
1792				} else{ //反选
1793					this.productList.forEach((item,index)=>{
1794						let jIndex = this.checkItems.findIndex(jItem=>jItem==item.id);
1795						if(jIndex>-1){
1796							this.checkItems.splice(jIndex,1);
1797							this.checkProductList.splice(jIndex,1);
1798						}
1799					});
1800				}
1801				this.setDataInit()
1802			},
1803			toggleCheckItem(item, index){
1804				let checkItems = JSON.parse(JSON.stringify(this.checkItems))
1805				if (!this.isMultiple) {
1806					checkItems = [checkItems]
1807				}
1808				// 列表中存在未选中的项时,全选不勾选
1809				this.productList.forEach(item=>{
1810					let isExist = checkItems.some(jItem=>jItem==item.id);
1811					if(!isExist){
1812						this.checkAll = false;
1813						return;
1814					}
1815				})
1816				let jIndex = this.checkProductList.findIndex(jItem=>jItem.id==item.id);
1817				if(jIndex>-1){
1818					this.checkProductList.splice(jIndex,1);
1819				} else {
1820					if (this.isMultiple) {
1821						this.checkProductList.push(item)
1822					} else {
1823						this.checkProductList = [item]
1824					}
1825				}
1826				this.setDataInit()
1827			},
1828			// 确定使用
1829			save(){
1830				this.$emit('save', {checkItems: this.checkItems, checkProductList: this.checkProductList});
1831			},
1832			closePop(){
1833				this.$emit('input', false);
1834			},
1835			setDataInit(){
1836				this.$emit('save', {checkItems: this.checkItems, checkProductList: this.checkProductList});
1837			},
1838			setPosition(){
1839				// this.checkProductList.forEach(item=>{
1840				// 	$(`[data-id=${item.product_id}] td`).eq(3).find('input').val(item.position)
1841				// 	$(`[data-id=${item.product_id}] td`).eq(3).find('input')[0].dispatchEvent(new Event('input'))
1842				// })
1843				let self = this
1844				self.productList.forEach(item=>{
1845					self.checkProductList.forEach(item2=>{
1846						if(item.id==item2.id){
1847							item.position = item2.position
1848						}
1849					})
1850				})
1851				// self.checkProductList.forEach(item=>{
1852				// 	$(`[data-id=${item.product_id}] td`).eq(3).find('input').val(item.position)
1853				// 	$(`[data-id=${item.product_id}] td`).eq(3).find('input')[0].dispatchEvent(new Event('input'))
1854				// })
1855			},
1856			changeCustomizedProId(item) {
1857				this.$emit('changecustomizedproid', item)
1858			},
1859		},
1860		mounted(){
1861			// this.search();
1862		},
1863		watch:{
1864			products(){
1865				this.checkItems = this.products
1866			},
1867			checkProducts(){
1868				const self = this
1869				self.checkProductList = JSON.parse(JSON.stringify(this.checkProducts))
1870				self.$nextTick(()=>{
1871					self.setPosition()
1872				})
1873			}
1874		}
1875	})
1876
1877	// 分页(用于产品选择弹窗)
1878	Vue.component('pagination-pro', {
1879		template:
1880        `<div class="pagination">
1881            <a class="icon-previous_page prev" :class="{disabled:curPage<=1}" @click="gotoPrev"></a>
1882            <ul>
1883                <template v-if="max<=5">
1884                    <li v-for="item in max" :class="{active:currentPage==item}" @click="curPage=item">{{item}}</li>
1885                </template>
1886                <template v-else>
1887					<li v-if="curPage>=2" @click="curPage=1">1</li>
1888					<template v-if="curPage>=4">
1889						<li v-if="curPage==4" @click="curPage=4">2</li>
1890						<li v-else>...</li>
1891					</template>
1892                	<li v-if="curPage>=3" @click="--curPage">{{curPage-1}}</li>
1893					<li class="active">{{curPage}}</li>
1894					<li v-if="curPage<=max-2" @click="++curPage">{{curPage+1}}</li>
1895					<template v-if="curPage<=max-3">
1896						<li v-if="max-curPage==3">{{max-1}}</li>
1897						<li v-else>...</li>
1898					</template>
1899					<li v-if="curPage<=max-1" @click="curPage=max">{{max}}</li>
1900                </template>
1901            </ul>
1902            <a class="icon-next_page next" :class="{disabled:curPage>=max}" @click="gotoNext"></a>
1903            <span>共{{max}}页</span>
1904            <span class="ml5 mr5">跳至 <input type="text" v-model="inputPage" @input="onlyNumber" @keydown.13="gotoPage" /> 页</span>
1905            <a class="main-btn gray" @click="gotoPage">确定</a>
1906        </div>`,
1907        props:{
1908            total:{
1909                type: Number,
1910                default: 1
1911            },
1912            perPage:{
1913            	type: Number,
1914            	default: 20
1915            },
1916            currentPage:{
1917            	type: Number,
1918            	default: 1,
1919            }
1920        },
1921        data(){
1922            return {
1923                curPage: this.currentPage || 1,
1924                inputPage: ''
1925            }
1926        },
1927        computed:{
1928        	max(){
1929        		if(this.total<=0){
1930        			return 1;
1931        		}
1932        		return Math.ceil(this.total/this.perPage);
1933        	}
1934        },
1935        methods:{
1936            gotoPrev(){
1937                if(this.curPage<=1){
1938                    return;
1939                }
1940                this.curPage--;
1941            },
1942            gotoNext(){
1943                if(this.curPage>=this.max){
1944                    return;
1945                }
1946                this.curPage++;
1947            },
1948            gotoPage(){
1949                if(!this.inputPage || this.inputPage<1 || this.inputPage>this.max){
1950                    return;
1951                }
1952                this.curPage = Number(this.inputPage);
1953            },
1954            onlyNumber(){
1955            	this.inputPage = this.inputPage.replace(/\D/g,'');
1956            }
1957        },
1958        watch:{
1959            'curPage':function(){
1960                this.$emit('change', this.curPage);
1961            }
1962        }
1963	});
1964
1965	// 分页(用于批次号生成规则)
1966	Vue.component('pagination-index', {
1967		template:
1968		`<div class="pagination">
1969			<span class="prev-page" :class="{'not': curPage==1}" @click="gotoPrev"><i class="icon-previous_page"></i></span>
1970			<input type="text" class="input-page" v-model="curPage" @input="onlyNumber" @keydown.enter="changePage" />
1971			<span class="next-page" :class="{'not': curPage==max}" @click="gotoNext"><i class="icon-next_page"></i></span>
1972			<span class="total-page-box">
1973				共<span class="total-page">{{max}}</span>页 | 
1974			</span>
1975			显示 <select v-model="everyPage" @change="changePageSize">
1976				<option v-for="item in pageSizes" :key="item" :value="item">{{item}}</option>
1977			</select> 每页 | 共找到 {{total}} 条记录
1978		</div>`,
1979        props:{
1980           total: {
1981               type: Number,
1982               default: 1,
1983           },
1984           perPage:{
1985                type: Number,
1986            	default: 20
1987           },
1988           currentPage: {
1989                type: Number,
1990            	default: 1,
1991           },
1992           pageSizes: {
1993               type: Array,
1994               default: ()=>([20, 30, 50, 100, 200])
1995           }
1996        },
1997        data(){
1998            return {
1999                curPage: this.currentPage || 1,
2000                everyPage: this.perPage || 20,
2001            }
2002        },
2003        computed:{
2004        	max(){
2005                if(this.total<=0){
2006                    return 1;
2007                }
2008                return Math.ceil(this.total/this.perPage);
2009            }
2010        },
2011        methods:{
2012            gotoPrev(){
2013                if(this.curPage<=1) return;
2014                this.curPage--;
2015                this.changePage();
2016            },
2017            gotoNext(){
2018                if(this.curPage>=this.max) return;
2019                this.curPage++;
2020                this.changePage();
2021            },
2022            onlyNumber(){
2023                this.curPage = this.curPage.replace(/\D/g,'');
2024                if(Number(this.curPage) == 0){
2025                    this.curPage = '';
2026                }
2027            },
2028            changePage(){
2029                if(!this.curPage){
2030                    promptInfo('请输入页码');
2031                    return;
2032                }
2033                if(this.curPage>this.max){
2034                    promptInfo('输入的页码大于总页数');
2035                    return;
2036                }
2037                this.$emit('change', this.curPage);
2038            },
2039            changePageSize(){
2040                this.$emit('changesize', this.everyPage);
2041            },
2042        }
2043	});
2044
2045	//快捷消息
2046	const quickReply = `
2047	<div>
2048		<div class="quick-reply relative">
2049			<a class="select-btn" :class="showSelect?'active':''" @click="openSelect">
2050				<span class="text">{{title}}</span>
2051				<span class="icon"><i class="icon-drop-down"></i></span>
2052			</a>
2053			<div v-if="showSelect" style="display:block;z-index:10">
2054				<ul>
2055					<li v-for="item in conhtml" :key="item.id" @click="selectSave(item)">{{item.content}}</li>
2056				</ul>
2057				<div class="tr setting-div"><a class="setting-btn" @click="openReplyPop">{{title}}设置</a></div>
2058			</div>
2059		</div>
2060		<div v-if="isReplyList" class="popmask" style="display:block;z-index: 2000" @click="isReplyList = false"></div>
2061		<div v-if="isReplyList" class="popup popup-reply-setting" style="display:block;z-index:2001">
2062			<i class="icon-operation_close" @click="isReplyList = false"></i>
2063			<div class="popup-title">{{title}}设置</div>
2064			<div class="popup-content">
2065				<div class="desc-text">{{title}}</div>
2066				<div class="flex-row flex-x-full">
2067					<ul>
2068						<li :class="item.active?'active':''" v-for="item in conhtml" :key="item.id" @click="selectLine(item)">{{item.content}}</li>
2069					</ul>
2070					<div class="operate-btns">
2071						<p class="mb10"><a class="main-btn big gray" @click="operateReply('add')">添加</a></p>
2072						<p class="mb10"><a :class="isSelect?'':'disabled'" class="main-btn big gray" @click="operateReply('edit')">修改</a></p>
2073						<p><a :class="isSelect?'':'disabled'" class="main-btn big gray" @click="operateReply('del')">删除</a></p>
2074					</div>
2075				</div>
2076			</div>
2077		</div>
2078		<div v-if="isAddReply" class="popmask2" style="display:block;z-index: 3000" @click="isAddReply = false"></div>
2079		<div v-if="isAddReply" class="popup popup-reply-add" style="display:block;z-index:3001">
2080			<i class="icon-operation_close close2" @click="isAddReply = false"></i>
2081			<div class="popup-title">{{popupTitle}}</div>
2082			<div class="popup-content">
2083				<div class="desc-text">内容(500字以内)</div>
2084				<div>
2085					<div class="relative">
2086						<textarea maxlength="500" rows="4" class="w100 border" oninput="stringCalc($(this), 500, 0)" onpaste="stringPasteCalc($(this), 500, 0)" v-model="content"></textarea>
2087						<div class="tr" style="position: absolute; right:10px;bottom:8px"><span class="inputed-total">0</span>/500</div>
2088					</div>
2089					<div v-if="errorMsg" class="error-msg"><i class="icon-warning"></i>请填写内容</div>
2090				</div>
2091			</div>
2092			<div class="popup-btn">
2093				<a class="popup-cancel2" @click="isAddReply = false">取消</a>
2094				<a class="popup-save" @click="saveBtn">确定</a>
2095			</div>
2096		</div>
2097	</div>
2098    `
2099    Vue.component('quickReply', {
2100        template: quickReply,
2101        props: {
2102            replyType: {
2103                require: true,
2104			},
2105			title: {
2106				require: false,
2107				default: '快捷消息'
2108			},
2109			isCache: false,	//是否使用初始缓存数据, 如果使用缓存数据,需要在父组件监听列表变化,(解决快捷回复加载慢的问题)
2110			initial: {
2111				require: false,
2112				default: () => []
2113			}
2114        },
2115        data() {
2116            return {
2117                conhtml: [...this.initial],
2118                isReplyList: false,
2119                isAddReply: false,
2120                isEditReply: false,
2121                popupTitle: '添加' + this.title,
2122                selectItem: null,
2123                content: '',
2124				errorMsg: false,
2125				showSelect: false,
2126				isSaving: false,
2127            }
2128		},
2129		beforeMount() {
2130			this._close = e => {
2131				// 如果点击发生在当前组件内部,则不处理
2132				if (this.$el.contains(e.target)) {
2133					return;
2134				}
2135				this.showSelect = false;
2136			};
2137			document.body.addEventListener('click', this._close);
2138		},
2139        mounted() {
2140		},
2141		computed: {
2142			isSelect() {
2143				return this.conhtml.some(item => {
2144					if(item.active) {
2145						return true
2146					}
2147				})
2148			}
2149		},
2150		watch:{
2151			'initial': {
2152				deep: true,
2153				handler: function(newval, oldval){
2154					this.conhtml = newval
2155				}
2156			},
2157			'conhtml': {
2158				deep: true,
2159				handler: function(newval, oldval){
2160					this.$parent.$emit('list-changed', {data: newval});
2161				}
2162			}
2163		},
2164        methods: {
2165            openSelect() {
2166				if(!this.showSelect){
2167					this.showSelect = true;
2168					const _this = this;
2169					if(!_this.isCache){
2170						$.ajax({
2171							type: 'post',
2172							url: '/admin/QuickReply/getQuickReply',
2173							data: {type: this.replyType},
2174							success(res){
2175								if(res.length){
2176									_this.conhtml = res
2177									_this.conhtml.map(items => {
2178										_this.$set(items, 'active', false)
2179									})
2180								}
2181							}
2182						});
2183					}
2184				}
2185            },
2186            openReplyPop() {
2187
2188								this.isReplyList = true
2189								this.showSelect = false
2190            },
2191            operateReply(type) {
2192				const _this = this
2193                switch(type){
2194                    case 'add':
2195                        this.isAddReply = true
2196                        this.isEditReply = false
2197						this.popupTitle = '添加'+ _this.title;
2198						this.content = ''
2199                        break;
2200                    case 'edit':
2201						if(this.isSelect) {
2202							this.isAddReply = true
2203							this.isEditReply = true
2204							this.popupTitle = '编辑'+ _this.title
2205							this.content = this.selectItem.content
2206						}
2207                        break;
2208                    case 'del':
2209						if(this.isSelect) {
2210							showLoading();
2211							$.ajax({
2212								type: 'post',
2213								url: '/admin/QuickReply/delete',
2214								data: {id: _this.selectItem.id, type: _this.replyType},
2215								success(res){
2216									hideLoading();
2217									if(res.status>0){
2218										_this.conhtml.splice(_this.conhtml.findIndex(item => {return item.id == _this.selectItem.id}),1)
2219									} else{
2220										promptInfo(res.msg);
2221									}
2222								}
2223							});
2224						}
2225                        break;
2226                }
2227            },
2228            selectLine(item) {
2229				this.conhtml.map(items => {
2230					this.$set(items, 'active', false)
2231					if(items.id === item.id) {
2232						this.$set(items, 'active', true)
2233					}
2234				})
2235                this.selectItem = item
2236            },
2237            saveBtn() {
2238				if(this.isSaving) return;
2239                if(this.content === '') {
2240                    this.errorMsg = true
2241                    return
2242				}
2243				const _this = this
2244                let params = {
2245                    type: this.replyType,
2246                    content: this.content
2247                }
2248                if(this.isEditReply) { //编辑快捷消息
2249                    params.id = this.selectItem.id
2250				}
2251				this.isSaving = true;
2252				let self = this;
2253				showLoading();
2254                $.ajax({
2255                    type: 'post',
2256                    url: '/admin/QuickReply/save',
2257                    data: params,
2258                    success(res){
2259						hideLoading();
2260						self.isSaving = false;
2261                        if(res.status>0){
2262                            promptInfo(res.msg);
2263                            $('.popup-reply-add, .popmask2').hide();
2264                            if(_this.isEditReply){
2265                                _this.conhtml.map((item) => {
2266                                    if(item.id == _this.selectItem.id){
2267                                        item.content = res.data.content
2268                                    }
2269                                })
2270                            } else{
2271                                _this.conhtml.push({id: res.data.id, content: res.data.content})
2272                            }
2273                            _this.isAddReply = false
2274                        } else{
2275                            promptInfo(res.msg);
2276                        }
2277					},
2278					error(){
2279						self.isSaving = false;
2280					}
2281                });
2282			},
2283			selectSave(item) {
2284				this.showSelect = false;
2285				this.$emit('selectsave',{item: item, el: this});
2286			}
2287		},
2288		beforeDestroy() {
2289			document.body.removeEventListener('click', this._close);
2290		}
2291	})
2292
2293		//快捷引用
2294		const quickCite = `
2295		<div>
2296			<div class="quick-cite relative">
2297				<a class="select-btn" :class="showSelect?'active':''" @click="openSelect">
2298					<span class="text">{{title}}</span>
2299					<span class="icon"><i class="icon-drop-down"></i></span>
2300				</a>
2301				<div v-if="showSelect" style="display:block;z-index:10;padding:10px">
2302					<div class="display-method mr10">
2303						<div class="tit">
2304							专享价展示方式:
2305							<span class="selected">{{showType}}</span><i class="icon-collection"></i>
2306						</div>
2307						<div class="select-box">
2308							<p class="mb5">选择展示方式:</p>
2309							<div>
2310								<label class="mr10">
2311									<input type="radio" name="display_type" data-val="2" v-model='showType' value="仅看显示" />
2312									仅看显示
2313								</label>
2314								<label>
2315									<input type="radio" name="display_type" data-val="1" value="全部展示" v-model='showType' />
2316									全部展示
2317								</label>
2318							</div>
2319						</div>
2320					</div>
2321					<table class="normal" style="table-layout: fixed;">
2322						<thead>
2323							<th style="width: 120px">件数范围</th>
2324							<th style="width: 80px">专享价(元)</th>
2325							<th style="width: 80px">平台手续费百分比</th>
2326							<th style="width: 80px">手续费折扣</th>
2327							<th style="width: 80px">基础服务费</th>
2328							<th style="width: 80px">平台服务费</th>
2329							<th style="width: 80px">结算价</th>
2330							<th style="width: 100px">专享价规则</th>
2331							<th>操作</th>
2332						</thead>
2333					</table>
2334					<div class="table-box" style="height: 202px;overflow-y: auto;margin-top:unset">
2335						<table class="normal">
2336							<tbody>
2337								<template v-if="citeList.length">
2338									<template v-for="(item, index) in citeList" :key="item.id">
2339										<template v-if="showType=='全部展示'||item.is_show==1">
2340											<tr :class="{'red-background':item.is_default==1,'white-background':item.is_show==1,'gray-background':item.is_show=='-1'}" v-for="(jItem, jIndex) in item.items" :key="jIndex" @click="selectCite(jItem.id,item.items,item.name,index)" :style='index===numI?"background:#E7F3FC;":""'>
2341												<td style="width: 120px">{{jItem.qty_from}} - {{jItem.qty_to}}</td>
2342												<td style="width: 80px">{{jItem.price}}</td>
2343												<td style="width: 80px">{{jItem.base_service_percent}}%</td>
2344												<td style="width: 80px">{{jItem.service_charge_discount}}</td>
2345												<td style="width: 80px">{{getSettlementFee(jItem)}}</td>
2346												<td style="width: 80px">{{getSettlementFee(jItem)}}</td>
2347												<td style="width: 80px">{{jItem.factory_settlement_price}}</td>
2348												<td style="width: 100px" v-if="jIndex==0" :rowspan="item.items.length">{{item.name}}</td>
2349												<td v-if="jIndex==0" :rowspan="item.items.length">
2350													<div>
2351														<span v-if='item.is_default==1'>默认规则</span>
2352														<a v-else @click.stop='setDef(item,index)'>设为默认</a>
2353													</div>
2354													<div>
2355														<a v-if='item.is_show==1' @click.stop='setShowRule(item)'>隐藏规则</a>
2356														<a v-else @click.stop='setShowRule(item)'>显示规则</a>
2357													</div>
2358												</td>
2359											</tr>
2360										</template>
2361									</template>
2362								</template>
2363								<template v-else>
2364									<tr class="empty-tr" height="50">
2365										<td colspan="8">暂无专享价设置</td>
2366									</tr>
2367								</template>
2368							</tbody>
2369						</table>
2370					</div>
2371				</div>
2372			</div>
2373		</div>
2374		`
2375		Vue.component('quickCite', {
2376			template: quickCite,
2377			props: {
2378				title: {
2379					require: false,
2380					default: '快捷引用'
2381				},
2382				numI: {
2383					require: false,
2384					default: ''
2385				},
2386				editId:{
2387					require: false,
2388					default: null,
2389				},
2390				isCache: false,	//是否使用初始缓存数据, 如果使用缓存数据,需要在父组件监听列表变化,(解决快捷回复加载慢的问题)
2391				citeList: {
2392					require: false,
2393					default: () => []
2394				}
2395			},
2396			data() {
2397				return {
2398					conhtml: [],
2399					selectItem: null,
2400					content: '',
2401					errorMsg: false,
2402					showSelect: false,
2403					nowId:'',
2404					showType: '仅看显示',
2405					// numI:''
2406				}
2407			},
2408			beforeMount() {
2409				this._close = e => {
2410					// 如果点击发生在当前组件内部,则不处理
2411					if (this.$el.contains(e.target)) {
2412						return;
2413					}
2414					this.showSelect = false;
2415				};
2416				document.body.addEventListener('click', this._close);
2417			},
2418			mounted() {
2419			},
2420			computed: {
2421				isSelect() {
2422					return this.conhtml.some(item => {
2423						if(item.active) {
2424							return true
2425						}
2426					})
2427				}
2428			},
2429			watch:{
2430				'initial': {
2431					deep: true,
2432					handler: function(newval, oldval){
2433						this.conhtml = newval
2434					}
2435				},
2436				'conhtml': {
2437					deep: true,
2438					handler: function(newval, oldval){
2439						this.$parent.$emit('list-changed', {data: newval});
2440					}
2441				}
2442			},
2443			methods: {
2444				setDef(item){
2445					this.citeList.forEach(citem=>{
2446						this.$set(citem,'is_default',-1)
2447					})
2448					this.citeList = this.citeList.filter(citem=>citem.id!=item.id)
2449					item.is_default = 1
2450					item.is_show = 1
2451					this.citeList.unshift(item)
2452					this.setDefShow(item,'1')
2453				},
2454				setDefShow(item,type,val){
2455					let saveParams = {
2456						id: item.id,
2457						apply_id: this.editId
2458					}
2459					saveParams = Object.assign(saveParams,type==1?{is_default: 1}:{is_show: val})
2460					showLoading();
2461					$.ajax({
2462						type: 'post',
2463						url: '/admin/batchExclusivePrice/saveRecordConf',
2464						data: saveParams,
2465						success: function(res){
2466							hideLoading();
2467							if(res.status>0){
2468								promptInfo('设置成功');
2469							} else{
2470								promptInfo(res.msg);
2471							}
2472						}
2473					})
2474				},
2475				setShowRule(item){
2476					let is_show = null
2477					item.is_show == 1&&item.is_default == 1?this.$set(item,'is_default',-1):""
2478					item.is_show == 1 ? is_show = -1 : is_show = 1
2479					item.is_show = is_show
2480					this.citeList.sort(function (a, b) { return b.is_show - a.is_show; })     
2481					this.setDefShow(item,'2',is_show)   
2482				},
2483				openSelect() {
2484					if(!this.showSelect){
2485						this.showSelect = true;
2486					}
2487				},
2488				selectCite(id,items,name,index) {
2489					this.numI = index
2490					let numL = 0
2491					for(let i=0;i<index;i++){
2492						numL+= this.citeList[i].items.length
2493					}
2494					this.showSelect = false;
2495					this.nowId = id
2496					this.$emit('selectcite',{id: id, el: this,items:items,name:name,numL:numL,numI:index});
2497				},
2498				// 获取平台服务费
2499				getServiceFee(item){
2500					let _price = parseInt(item.price*100);
2501					let _ret = _price*parseInt(item.base_service_percent);
2502					_ret = _ret * item.service_charge_discount;
2503					_ret = (_ret + parseInt(item.base_service_price*10000))/10000;
2504					return accuracyFun2(_ret);
2505				},//获取基础服务费
2506				getSettlementFee(item){
2507					let _price = parseFloat(item.price||0);
2508					let _ret = parseFloat(item.factory_settlement_price!=''?item.factory_settlement_price:0);
2509					_ret =  parseFloat(_price-_ret).toFixed(2);
2510					return _ret<0?0:accuracyFun2(_ret);
2511				},
2512				// 获取结算价
2513				getSettlement(item){
2514					let _price = parseInt(item.price*100),
2515						_fee = parseInt(this.getServiceFee(item)*100);
2516					let _ret = (_price - _fee)/100;
2517					return accuracyFun2(_ret);
2518				},
2519			},
2520			beforeDestroy() {
2521				document.body.removeEventListener('click', this._close);
2522			}
2523		})
2524
2525	/**
2526	 * 选择群组
2527	 * 	实例使用: /zwdc/view/admin/couponRule/index.php
2528	 */
2529	Vue.component('choice-group', {
2530		template: `
2531			<transition name="fade">
2532				<div class="popup popup-group" style="width:700px;display:block">
2533				<i class="icon-checkout_close" @click="closePop"></i>
2534				<div class="popup-title">{{popTitle}}</div>
2535				<div class="popup-content" v-cloak>
2536					<div class="form-item flex-row">
2537		                <div class="form-label">群组类型:</div>
2538		                <div class="form-content">
2539		                    <select class="group_type" v-model="searchParam.group_type">
2540		                        <option value="">全部类型</option>
2541		                        <option v-for="item in groupType" :value="item.value">{{item.key}}</option>
2542		                    </select>
2543		                </div>
2544		            </div>
2545					<div class="form-item flex-row">
2546						<div class="form-label">群组等级:</div>
2547						<div class="form-content">
2548							<select class="level" v-model="searchParam.level">
2549								<option value="">全部等级</option>
2550								<option v-for="item in groupLevel" :value="item.value">{{item.key}}</option>
2551							</select>
2552						</div>
2553					</div>
2554					<div class="group-content flex-row">
2555						<div class="left w50">
2556							<div class="search-box">
2557								<input type="text" placeholder="搜索账号、姓名、群组编号" class="keywords"
2558									v-model.trim="searchParam.keyword"
2559									@keydown.enter="searchGroup"
2560								>
2561								<i class="search icon-search" @click="searchGroup"></i>
2562							</div>
2563							<ul class="all-list" v-if="Object.keys(searchRes).length">
2564								<li v-for="item of searchRes">
2565									<label>
2566										<span v-html="item.name"></span>
2567										<input type="checkbox" v-model="item.isChecked" :value="item.id" :disabled="item.disabled" @change="itemClickHandler($event,item)">
2568									</label>
2569								</li>
2570							</ul>
2571							<div class="no-data" v-else>{{emptyTxt}}</div>
2572						</div>
2573						<div class="right w50">
2574							<div class="selected-number">{{ischecked}}</div>
2575							<ul class="selected-list">
2576								<li v-for="item of selectedData">
2577									<label>
2578										<span v-html="item.name"></span>
2579										<i class="remove icon-operation_close" @click="delSelected(item)"></i>
2580									</label>
2581								</li>
2582							</ul>
2583						</div>
2584					</div>
2585				</div>
2586				<div class="popup-btn">
2587					<a class="popup-cancel" @click="closePop">取消</a>
2588					<a class="popup-save" @click="save">确定</a>
2589				</div>
2590			</div>
2591			</transition>
2592		`,
2593		props: {
2594			groupLevel: {},
2595			groupType: {},
2596			checkedData: {},
2597			isRequire: {
2598				type: Boolean,
2599				default: true
2600			},
2601		},
2602		data() {
2603			return {
2604				emptyTxt: '请先输入搜索关键字',
2605				searchParam:{
2606					level: '',
2607					group_type: '',
2608					keyword: ''
2609				},
2610				searchRes: {},
2611				selectedData: JSON.parse(JSON.stringify(this.checkedData)),
2612				isMultiple: false,
2613				initData: null,
2614				// reverseData: [], //用于存放授权群组设置中的黑名单或者禁用群组的白名单
2615				reqUrl: '',
2616				saveUrl: '',
2617				popFlag: 1,     //弹框标识, 1所属群组, 2授权群组, 3指定禁用群组, 4
2618				// editingId: '',   //编辑的数据编号
2619			}
2620		},
2621		computed: {
2622			popTitle(){
2623				let str = '';
2624				switch(this.popFlag){
2625					case 1:
2626						str = '所属群组';
2627						break;
2628					case 2:
2629						str = '授权群组';
2630						break;
2631					case 3:
2632						str = '指定禁用群组';
2633						break;
2634					case 4:
2635						str = '定制产品指定共享';
2636						break;
2637				}
2638				return str;
2639			},
2640			ischecked() {
2641				let data = {}
2642				if(Object.keys(this.selectedData).length) {
2643					data = this.selectedData
2644				}else {
2645					for(let key in this.searchRes){
2646						if(this.searchRes[key].isChecked) {
2647							data[key] = this.searchRes[key]
2648						}
2649					}
2650				}
2651				if(Object.keys(data).length) {
2652					return `已选择了${Object.keys(data).length}个群组`
2653				}else {
2654					return '请勾选需要添加的群组'
2655				}
2656			},
2657			// selectedData() {
2658			// 	if(Object.keys(this.checkedData).length) {
2659			// 		return this.checkedData
2660			// 	}else {
2661			// 		let data = {}
2662			// 		for(let key in this.searchRes){
2663			// 			if(this.searchRes[key].isChecked) {
2664			// 				data[key] = this.searchRes[key]
2665			// 			}
2666			// 		}
2667			// 		return data
2668			// 	}
2669			// }
2670		},
2671		mounted(){
2672		},
2673		methods:{
2674			// 群组搜索
2675			searchGroup(){
2676				if(!this.searchParam.keyword){
2677					this.searchRes = Object.assign({});
2678					return false;
2679				}
2680				let self = this;
2681				showLoading();
2682				$.ajax({
2683					type: 'post',
2684					url: '/admin/statistics/getGroupInfo',
2685					data: self.searchParam,
2686					success: function(res){
2687						hideLoading();
2688						if(res.status>0){
2689							if(res.data){
2690								self.searchRes = Object.assign({}, res.data);
2691								for(let key in self.searchRes) {
2692									self.$set(self.searchRes[key], 'isChecked', false);
2693								}
2694								// 若是选中的,将checkbox状态设置为true
2695								Object.keys(self.selectedData).map(id=>{
2696									if(self.searchRes[id]){
2697										self.$set(self.searchRes[id], 'isChecked', true);
2698										self.$set(self.searchRes[id], 'disabled', self.selectedData[id].disabled);
2699									}
2700								});
2701								//self.checkedData = {}
2702							} else{
2703								self.searchRes = Object.assign({});
2704								self.emptyTxt = '没有匹配到任何结果';
2705							}
2706						} else{
2707							self.searchRes = Object.assign({});
2708							self.emptyTxt = '没有匹配到任何结果';
2709						}
2710					}
2711				})
2712			},
2713			// 左侧搜索选中,添加或删除
2714			itemClickHandler(event, item){
2715				if(item.isChecked) {
2716					// if(!this.isMultiple){ //单选
2717					// 	for(let i in this.searchRes){
2718					// 		if(i != item.id && this.searchRes[i]){
2719					// 			this.$set(this.searchRes[i], 'isChecked', false);
2720					// 		}
2721					// 	}
2722					// 	this.selectedData = Object.assign({});
2723					// }
2724					this.$set(this.selectedData, item.id, item);
2725				}
2726				else {
2727					this.$delete(this.selectedData, item.id);
2728					if(this.searchRes[item.id]){
2729						this.$set(this.searchRes[item.id], 'isChecked', false);
2730					}
2731				}
2732			},
2733			// 删除选中
2734			delSelected(item){
2735				if (item.disabled) return
2736				this.$delete(this.selectedData, item.id);
2737				if(this.searchRes[item.id]){
2738					this.$set(this.searchRes[item.id], 'isChecked', false);
2739				}
2740			},
2741			// 保存配置
2742			save(){
2743				if(!Object.keys(this.selectedData).length && this.isRequire) {
2744					promptInfo('请添加账户')
2745					return
2746				}
2747				this.$emit('groupsave', {selectedData: this.selectedData})
2748			},
2749			//关闭弹窗
2750			closePop() {
2751				this.$emit('closepop')
2752			}
2753		},
2754	})
2755
2756	/**
2757	 * 自定义导出字段
2758	 */
2759	Vue.component('custom-export', {
2760		template: `
2761		<transition name="fade">
2762			<div class="popup popup-sort" style="z-index: 1011;">
2763				<div class="popup-title">选择需导出的数据字段</div>
2764				<i class="icon-checkout_close" @click="closePop"></i>
2765				<div class="popup-content" v-cloak>
2766					<div class="sort-head">
2767						<span class="blue cursorp" @click="resetFiled()">重置</span>
2768						<span class="check-all cursorp" :class="{select: allChecked}" @click="selectAllItem()">全选</span>
2769					</div>
2770					<div class="sort-box" style="max-height:40vh">
2771						<transition-group class="transition-wrapper" name="sort">
2772							<div v-for="(item, index) in exportList" :key='item.field' 
2773									:draggable="true"
2774									class="sort-item"
2775									style="cursor: move;"
2776									@dragstart="dragstart(item, $event)"
2777									@dragenter="dragenter(item, $event)"
2778									@click="selectCurItem(item)">
2779								<span class="zw_icon-icon_yidong mr10"></span>
2780								<span class="title text-overflow" 
2781											@mouseover="showTitle(item.name, $event)"
2782											@mouseleave="hideTitle()">{{ item.name }}</span>
2783								<span class="zw_icon-icon_tick" v-if="item.status == 1"></span>
2784							</div>
2785						</transition-group>
2786					</div>
2787				</div>
2788				<div class="popup-btn tr pr10 pt10" style="border-top: 1px solid #ccc;">
2789					<a class="popup-cancel mr10" @click="closePop">取消</a>
2790					<a class="popup-save" @click="save">导出</a>
2791				</div>
2792			</div>
2793		</transition>
2794		`,
2795		props: {
2796			exportList: Array
2797		},
2798		data() {
2799			return {
2800				oldData: null
2801			}
2802		},
2803		computed: {
2804			allChecked() {
2805				let hasCheck = this.exportList && this.exportList.find(i => i['status'] == -1)
2806				if (hasCheck) {
2807					return false
2808				} else {
2809					return true
2810				}
2811			}
2812		},
2813		methods: {
2814			resetFiled() {
2815				this.$emit('reset');
2816			},
2817			showTitle(txt, event) {
2818				if (txt.length <= 14) return;
2819				let {top, left} = $(event.target).offset();
2820				if ($('body').find('.color-tip-box').length <= 0) {
2821					$('body').append(`<div class="color-tip-box"><span class="tips-info-trangle"></span><div class="color-tip-txt tl"></div></div>`);
2822				}
2823				$('.color-tip-box').find('.color-tip-txt').html(txt).css('max-width', '180px');
2824				let h = $('.color-tip-box').height();
2825				$('.color-tip-box').css({top: top - h - 20, left: left - 26}).show();
2826			},
2827			hideTitle() {
2828				$('.color-tip-box').css({top: 0, left: 0}).hide();
2829			},
2830			selectCurItem(item) {
2831				this.$set(item, 'status', item.status == 1 ? -1 : 1)
2832			},
2833			selectAllItem() {
2834				let hasCheck = this.exportList.find(i => i['status'] == -1)
2835				if (hasCheck) {
2836					this.exportList.forEach( i => this.$set(i, 'status', 1))
2837				} else {
2838					this.exportList.forEach( i => this.$set(i, 'status', -1))
2839				}
2840			},
2841			dragstart(value, e) {
2842				this.oldData = value
2843			},
2844			dragenter(value, e) {
2845				e.preventDefault()
2846				if (this.oldData !== value) {
2847					let oldIndex = this.exportList.indexOf(this.oldData)
2848					let newIndex = this.exportList.indexOf(value)
2849					let newItems = [...this.exportList]
2850					newItems.splice(oldIndex, 1)
2851					newItems.splice(newIndex, 0, this.oldData)
2852					this.exportList = [...newItems]
2853				}
2854			},
2855			closePop() {
2856				$('.popup-sort, .maskPop').hide()
2857			},
2858			save() {
2859				let resultIds = this.exportList.map((i, index) => {
2860					const {status, field} = i
2861					return {
2862						status,
2863						field,
2864						sort: index + 1,
2865					}
2866				})
2867				if (!resultIds.length) {
2868					promptInfo('请选择要导出的字段')
2869					return
2870				}
2871				this.$emit('save', resultIds)
2872			}
2873		}
2874	})
2875})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.