Переглянути джерело

Merge branch 'develop_vue3' of http://git.chelingzhu.com/jianguan-web/qpls-md-app into develop_vue3

chenrui 4 місяців тому
батько
коміт
2275e2b6ca

+ 124 - 0
components/ba-tree-picker/README.md

@@ -0,0 +1,124 @@
+## 树形层级选择器
+### 简介
+为统一样式而生,树形层级选择器,picker弹窗形式的,样式和比例参照uniapp的picker和uni-data-picker组件
+* 支持单选、多选、父级选择,当然也支持单层选择
+* 支持Object对象属性自定义映射
+* 支持显示全部选中、部分选中、未选中三种状态
+* 支持快速自定义简单样式(分割线、按钮、标题、对齐等),深入样式可复写css
+
+### 使用方法
+在 `script` 中引入组件
+``` javascript
+	import baTreePicker from "@/components/ba-tree-picker/ba-tree-picker.vue"
+	export default {
+		components: {
+			baTreePicker
+		}
+```
+在 `template` 中使用组件
+``` javascript
+	<ba-tree-picker ref="treePicker" :multiple='false' @select-change="selectChange" title="选择城市"
+		:localdata="listData" valueKey="value" textKey="label" childrenKey="children" />
+```
+在 `script` 中定义打开方法,和选择监听
+``` javascript
+		methods: {
+			// 显示选择器
+			showPicker() {
+				this.$refs.treePicker._show();
+			},
+			//监听选择(ids为数组)
+			selectChange(ids, names) {
+				console.log(ids, names)
+			}
+		}
+```
+在 `template` 中调用打开
+``` javascript
+	<view @click="showPicker">调用选择器</view>
+```
+
+### 属性
+|属性名|类型|默认值|说明|
+|:-|:-:|:--:|-:|
+|localdata|Array|[]|源数据,目前支持tree结构,后续会考虑支持扁平化结构|
+|valueKey|String|id|指定 Object 中 key 的值作为节点数据id|
+|textKey|String|name|指定 Object 中 key 的值作为节点显示内容|
+|childrenKey|String|children|指定 Object 中 key 的值作为节点子集|
+|multiple|Boolean|false|是否多选,默认单选|
+|selectParent|Boolean|true|是否可以选父级,默认可以|
+|title|String| |标题|
+|titleColor|String||标题颜色|
+|confirmColor|String|#0055ff|确定按钮颜色|
+|cancelColor|String|#757575|取消按钮颜色|
+|switchColor|String|#666|节点切换图标颜色|
+|border|Boolean|false|是否有分割线,默认无|
+
+
+
+###  数据格式
+
+注意:必须有id、name(id可通过valueKey来配置为其它键值,如value)字段,且唯一
+
+``` json
+[
+    {
+        id: 1,
+        name: '公司1',
+        children: [{
+            id: 11,
+            name: '研发部',
+            children: [{
+                id: 111,
+                name: '张三',
+                
+            },{
+                id: 112,
+                name: '李四',
+                
+            }]
+        },{
+            id: 12,
+            name: '综合部',
+            
+        } ]
+    },
+    {
+        id: 2,
+        name: '公司2',
+        children: [{
+            id: 21,
+            name: '研发部',
+            
+        },{
+            id: 22,
+            name: '综合部',
+            
+        },{
+            id: 23,
+            name: '财务部',
+            
+        }, ]
+    },
+    {
+        id: 3,
+        name: '公司3'
+    },
+    {
+        id: 4,
+        name: '公司4',
+        children: [{
+            id: 41,
+            name: '研发部',
+            
+        }]
+    }
+]
+```
+</details>
+
+### 方法
+|方法名|参数|默认值|说明|
+|:-|:-:|:--:|-:|
+|_show()| | |显示选择器|
+|_hide()| | |隐藏选择器|

+ 644 - 0
components/ba-tree-picker/ba-tree-picker.vue

@@ -0,0 +1,644 @@
+<!-- 树形层级选择器-->
+<!-- 1、支持单选、多选 -->
+<template>
+	<view>
+		<view class="tree-cover" :class="{'show':showDialog}" @tap="_cancel"></view>
+		<view class="tree-dialog" :class="{'show':showDialog}">
+			<view class="tree-bar">
+				<view class="tree-bar-cancel" :style="{'color':cancelColor}" hover-class="hover-c" @tap="_cancel">取消
+				</view>
+				<view class="tree-bar-title" :style="{'color':titleColor}">{{title}}</view>
+				<view class="tree-bar-confirm" :style="{'color':confirmColor}" hover-class="hover-c" @tap="_confirm">
+					{{multiple?'确定':''}}
+				</view>
+			</view>
+			<view class="tree-view">
+				<view class="tree-info flex align_center justify_between" v-if="curData.length">
+					已选 {{curData.length}} 项
+					<text class="clear" @click="clear">清空</text>
+				</view>
+				<scroll-view class="tree-list" :scroll-y="true">
+					<block v-for="(item, index) in treeList" :key="index">
+						<view class="tree-item" :style="[{
+							paddingLeft: item.level*30 + 'rpx'
+						}]" :class="{
+							itemBorder: border === true,
+							show: item.isShow
+						}">
+							<view class="item-label align_center">
+								<view class="item-icon uni-inline-item flex align_center" @tap.stop="_onItemSwitch(item, index)">
+									<view v-if="!item.isLastLevel&&item.isShowChild" class="switch-on"
+										:style="{'border-left-color':switchColor}">
+									</view>
+									<view v-else-if="!item.isLastLevel&&!item.isShowChild" class="switch-off"
+										:style="{'border-top-color':switchColor}">
+									</view>
+									<view v-else class="item-last-dot" :style="{'border-top-color':switchColor}">
+									</view>
+								</view>
+								<view class="flex flex_auto align_center justify_between uni-inline-item">
+									<view class="item-name" v-if="item.isLastLevel" @tap.stop="_onItemSelect(item, index)"> 
+										{{item.name+(item.childCount?"("+item.childCount+")":'')}}
+									</view>
+									<view class="item-name" v-else @tap.stop="_onItemSwitch(item, index)">
+										{{item.name+(item.childCount?"("+item.childCount+")":'')}}
+									</view>
+									<view class="item-check" v-if="selectParent?true:item.isLastLevel" @tap.stop="_onItemSelect(item, index)">
+										<view class="item-check-yes" v-if="item.checkStatus==1"
+											:class="{'radio':!multiple}" :style="{'border-color':confirmColor}">
+											<view class="item-check-yes-part"
+												:style="{'background-color':confirmColor}">
+											</view>
+										</view>
+										<view class="item-check-yes" v-else-if="item.checkStatus==2"
+											:class="{'radio':!multiple}" :style="{'border-color':confirmColor}">
+											<view class="item-check-yes-all" :style="{'background-color':confirmColor}">
+											</view>
+										</view>
+										<view class="item-check-no" v-else :class="{'radio':!multiple}"
+											:style="{'border-color':confirmColor}"></view>
+									</view>
+								</view>
+							</view>
+
+						</view>
+					</block>
+				</scroll-view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		emits: ['select-change'],
+		name: "ba-tree-picker",
+		props: {
+			valueKey: {
+				type: String,
+				default: 'id'
+			},
+			textKey: {
+				type: String,
+				default: 'name'
+			},
+			childrenKey: {
+				type: String,
+				default: 'children'
+			},
+			localdata: {
+				type: Array,
+				default: function() {
+					return []
+				}
+			},
+			localTreeList: { //在已经格式化好的数据
+				type: Array,
+				default: function() {
+					return []
+				}
+			},
+			selectedData: {
+				type: Array,
+				default: function() {
+					return []
+				}
+			},
+			title: {
+				type: String,
+				default: ''
+			},
+			multiple: { // 是否可以多选
+				type: Boolean,
+				default: true
+			},
+			selectParent: { //是否可以选父级
+				type: Boolean,
+				default: true
+			},
+			confirmColor: { // 确定按钮颜色
+				type: String,
+				default: '' // #0055ff
+			},
+			cancelColor: { // 取消按钮颜色
+				type: String,
+				default: '' // #757575
+			},
+			titleColor: { // 标题颜色
+				type: String,
+				default: '' //
+			},
+			switchColor: { // 节点切换图标颜色
+				type: String,
+				default: '' // #666
+			},
+			border: { // 是否有分割线
+				type: Boolean,
+				default: false
+			},
+		},
+		data() {
+			return {
+				showDialog: false,
+				treeList: [],
+				curData: []
+			}
+		},
+		computed: {},
+		methods: {
+			_show() {
+				this.showDialog = true
+			},
+			_hide() {
+				this.showDialog = false
+			},
+			_cancel() {
+				this._hide()
+				this.$emit("cancel", '');
+			},
+			_confirm() { //多选
+				if(this.multiple){
+					let selectedList = []; //如果子集全部选中,只返回父级 id
+					let selectedNames;
+					let currentLevel = -1;
+					this.treeList.forEach((item, index) => {
+						if (currentLevel >= 0 && item.level > currentLevel) {
+					
+						} else {
+							if (item.checkStatus === 2) {
+								currentLevel = item.level;
+								selectedList.push(item.id);
+								selectedNames = selectedNames ? selectedNames + ' / ' + item.name : item.name;
+							} else {
+								currentLevel = -1;
+							}
+						}
+					})
+					//console.log('_confirm', selectedList);
+					this._hide()
+					this.curData = selectedList
+					this.$emit("select-change", selectedList, selectedNames);
+				}
+			},
+			//格式化原数据(原数据为tree结构)
+			_formatTreeData(list = [], level = 0, parentItem, isShowChild = true) {
+				let nextIndex = 0;
+				let parentId = -1;
+				let initCheckStatus = 0;
+				if (parentItem) {
+					nextIndex = this.treeList.findIndex(item => item.id === parentItem.id) + 1;
+					parentId = parentItem.id;
+					if (!this.multiple) { //单选
+						initCheckStatus = 0;
+					} else
+						initCheckStatus = parentItem.checkStatus == 2 ? 2 : 0;
+				}
+				list.forEach(item => {
+					let isLastLevel = true;
+					if (item && item[this.childrenKey]) {
+						let children = item[this.childrenKey];
+						if (Array.isArray(children) && children.length > 0) {
+							isLastLevel = false;
+						}
+					}
+
+					let itemT = {
+						id: item[this.valueKey],
+						name: item[this.textKey],
+						level,
+						isLastLevel,
+						isShow: isShowChild,
+						isShowChild: false,
+						checkStatus: initCheckStatus,
+						orCheckStatus: 0,
+						parentId,
+						children: item[this.childrenKey],
+						childCount: item[this.childrenKey] ? item[this.childrenKey].length : 0,
+						childCheckCount: 0,
+						childCheckPCount: 0
+					};
+
+					if (this.selectedData.indexOf(itemT.id) >= 0) {
+						itemT.checkStatus = 2;
+						itemT.orCheckStatus = 2;
+						itemT.childCheckCount = itemT.children ? itemT.children.length : 0;
+						this._onItemParentSelect(itemT, nextIndex);
+					}
+
+					this.treeList.splice(nextIndex, 0, itemT);
+					nextIndex++;
+				})
+				//console.log(this.treeList);
+			},
+			// 节点打开、关闭切换
+			_onItemSwitch(item, index) {
+				// console.log(item)
+				//console.log('_itemSwitch')
+				if (item.isLastLevel === true) {
+					return;
+				}
+				item.isShowChild = !item.isShowChild;
+				if (item.children) {
+					this._formatTreeData(item.children, item.level + 1, item);
+					item.children = undefined;
+				} else {
+					this._onItemChildSwitch(item, index);
+				}
+			},
+			_onItemChildSwitch(item, index) {
+				//console.log('_onItemChildSwitch')
+				const firstChildIndex = index + 1;
+				if (firstChildIndex > 0)
+					for (var i = firstChildIndex; i < this.treeList.length; i++) {
+						let itemChild = this.treeList[i];
+						if (itemChild.level > item.level) {
+							if (item.isShowChild) {
+								if (itemChild.parentId === item.id) {
+									itemChild.isShow = item.isShowChild;
+									if (!itemChild.isShow) {
+										itemChild.isShowChild = false;
+									}
+								}
+							} else {
+								itemChild.isShow = item.isShowChild;
+								itemChild.isShowChild = false;
+							}
+						} else {
+							return;
+						}
+					}
+			},
+			// 节点选中、取消选中
+			_onItemSelect(item, index) {
+				//console.log('_onItemSelect')
+				//console.log(item)
+				if (!this.multiple) { //单选
+					if(!this.selectParent && !item.isLastLevel){return}
+					item.checkStatus = item.checkStatus == 0 ? 2 : 0;
+					this.treeList.forEach((v, i) => {
+						if (i != index) {
+							this.treeList[i].checkStatus = 0
+						} else {
+							this.treeList[i].checkStatus = 2
+						}
+					})
+
+					let selectedList = [];
+					let selectedNames;
+					selectedList.push(item.id);
+					selectedNames = item.name;
+					this._hide()
+					this.curData = selectedList;
+					this.$emit("select-change", selectedList, selectedNames);
+					return
+				}
+				// 多选
+				let oldCheckStatus = item.checkStatus;
+				switch (oldCheckStatus) {
+					case 0:
+						item.checkStatus = 2;
+						item.childCheckCount = item.childCount;
+						item.childCheckPCount = 0;
+						break;
+					case 1:
+					case 2:
+						item.checkStatus = 0;
+						item.childCheckCount = 0;
+						item.childCheckPCount = 0;
+						break;
+					default:
+						break;
+				}
+				//子节点 全部选中
+				this._onItemChildSelect(item, index);
+				//父节点 选中状态变化
+				this._onItemParentSelect(item, index, oldCheckStatus);
+			},
+			_onItemChildSelect(item, index) {
+				//console.log('_onItemChildSelect')
+				let allChildCount = 0;
+				if (item.childCount && item.childCount > 0) {
+					index++;
+					while (index < this.treeList.length && this.treeList[index].level > item.level) {
+						let itemChild = this.treeList[index];
+						itemChild.checkStatus = item.checkStatus;
+						if (itemChild.checkStatus == 2) {
+							itemChild.childCheckCount = itemChild.childCount;
+							itemChild.childCheckPCount = 0;
+						} else if (itemChild.checkStatus == 0) {
+							itemChild.childCheckCount = 0;
+							itemChild.childCheckPCount = 0;
+						}
+						// console.log('>>>>index:', index, 'item:', itemChild.name, '  status:', itemChild
+						// 	.checkStatus)
+						index++;
+					}
+				}
+			},
+			_onItemParentSelect(item, index, oldCheckStatus) {
+				//console.log('_onItemParentSelect')
+				//console.log(item)
+				const parentIndex = this.treeList.findIndex(itemP => itemP.id == item.parentId);
+				//console.log('parentIndex:' + parentIndex)
+				if (parentIndex >= 0) {
+					let itemParent = this.treeList[parentIndex];
+					let count = itemParent.childCheckCount;
+					let oldCheckStatusParent = itemParent.checkStatus;
+
+					if (oldCheckStatus == 1) {
+						itemParent.childCheckPCount -= 1;
+					} else if (oldCheckStatus == 2) {
+						itemParent.childCheckCount -= 1;
+					}
+					if (item.checkStatus == 1) {
+						itemParent.childCheckPCount += 1;
+					} else if (item.checkStatus == 2) {
+						itemParent.childCheckCount += 1;
+					}
+
+					if (itemParent.childCheckCount <= 0 && itemParent.childCheckPCount <= 0) {
+						itemParent.childCheckCount = 0;
+						itemParent.childCheckPCount = 0;
+						itemParent.checkStatus = 0;
+					} else if (itemParent.childCheckCount >= itemParent.childCount) {
+						itemParent.childCheckCount = itemParent.childCount;
+						itemParent.childCheckPCount = 0;
+						itemParent.checkStatus = 2;
+					} else {
+						itemParent.checkStatus = 1;
+					}
+					//console.log('itemParent:', itemParent)
+					this._onItemParentSelect(itemParent, parentIndex, oldCheckStatusParent);
+				}
+			},
+			// 重置数据
+			_reTreeList() {
+				this.treeList.forEach((v, i) => {
+					this.treeList[i].checkStatus = v.orCheckStatus
+				})
+			},
+			_initTree() {
+				this.treeList = [];
+				this._formatTreeData(this.localdata);
+			},
+			clear(){
+				this.curData = []
+				this.$emit("select-change", null, null);
+				this._initTree()
+			}
+		},
+		watch: {
+			localdata() {
+				this._initTree();
+			},
+			localTreeList() {
+				this.treeList = this.localTreeList;
+			}
+		},
+		mounted() {
+			this._initTree();
+		}
+	}
+</script>
+
+<style scoped>
+	.tree-cover {
+		position: fixed;
+		top: 0rpx;
+		right: 0rpx;
+		bottom: 0rpx;
+		left: 0rpx;
+		z-index: 100;
+		background-color: rgba(0, 0, 0, .4);
+		opacity: 0;
+		transition: all 0.3s ease;
+		visibility: hidden;
+	}
+
+	.tree-cover.show {
+		visibility: visible;
+		opacity: 1;
+	}
+	.clear{
+		color: #007aff;
+	}
+
+	.tree-dialog {
+		position: fixed;
+		top: 0rpx;
+		right: 0rpx;
+		bottom: 0rpx;
+		left: 0rpx;
+		background-color: #fff;
+		border-top-left-radius: 10px;
+		border-top-right-radius: 10px;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		z-index: 1002;
+		top: 20%;
+		transition: all 0.3s ease;
+		transform: translateY(100%);
+	}
+
+	.tree-dialog.show {
+		transform: translateY(0);
+	}
+
+	.tree-bar {
+		/* background-color: #fff; */
+		height: 90rpx;
+		padding-left: 25rpx;
+		padding-right: 25rpx;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		box-sizing: border-box;
+		border-bottom-width: 1rpx !important;
+		border-bottom-style: solid;
+		border-bottom-color: #f5f5f5;
+		font-size: 32rpx;
+		color: #757575;
+		line-height: 1;
+	}
+
+	.tree-bar-confirm {
+		color: #0055ff;
+		padding: 15rpx;
+	}
+
+	.tree-bar-title {}
+
+	.tree-bar-cancel {
+		color: #757575;
+		padding: 15rpx;
+	}
+
+	.tree-view {
+		flex: 1;
+		padding: 10rpx 20rpx;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		overflow: hidden;
+		height: 100%;
+	}
+	.tree-info{
+		padding: 10rpx 20rpx;
+		font-size: 24rpx;
+	}
+
+	.tree-list {
+		flex: 1;
+		height: 100%;
+		overflow: hidden;
+	}
+
+	.tree-item {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		line-height: 1;
+		height: 0;
+		opacity: 0;
+		transition: 0.2s;
+		overflow: hidden;
+	}
+
+	.tree-item.show {
+		padding: 18px 0;
+		opacity: 1;
+	}
+
+	.tree-item.showchild:before {
+		transform: rotate(90deg);
+	}
+
+	.tree-item.last:before {
+		opacity: 0;
+	}
+
+	.switch-on {
+		width: 0;
+		height: 0;
+		border-left: 8rpx solid transparent;
+		border-right: 8rpx solid transparent;
+		border-top: 12rpx solid #666;
+	}
+
+	.switch-off {
+		width: 0;
+		height: 0;
+		border-bottom: 8rpx solid transparent;
+		border-top: 8rpx solid transparent;
+		border-left: 12rpx solid #666;
+	}
+
+	.item-last-dot {
+		position: absolute;
+		width: 10rpx;
+		height: 10rpx;
+		border-radius: 100%;
+		background: #666;
+	}
+
+	.item-icon {
+		width: 26rpx;
+		height: 26rpx;
+		margin-right: 8rpx;
+		padding-right: 20rpx;
+		padding-left: 20rpx;
+	}
+
+	.item-label {
+		flex: 1;
+		display: flex;
+		align-items: center;
+		height: 100%;
+		line-height: 1.2;
+	}
+
+	.item-name {
+		flex: 1;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+		width: 450rpx;
+	}
+
+	.item-check {
+		width: 40px;
+		height: 40px;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.item-check-yes,
+	.item-check-no {
+		width: 16px;
+		height: 16px;
+		border-top-left-radius: 20%;
+		border-top-right-radius: 20%;
+		border-bottom-right-radius: 20%;
+		border-bottom-left-radius: 20%;
+		border-top-width: 1rpx;
+		border-left-width: 1rpx;
+		border-bottom-width: 1rpx;
+		border-right-width: 1rpx;
+		border-style: solid;
+		border-color: #0055ff;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		box-sizing: border-box;
+	}
+
+	.item-check-yes-part {
+		width: 12px;
+		height: 12px;
+		border-top-left-radius: 20%;
+		border-top-right-radius: 20%;
+		border-bottom-right-radius: 20%;
+		border-bottom-left-radius: 20%;
+		background-color: #0055ff;
+	}
+
+	.item-check-yes-all {
+		margin-bottom: 3px;
+		border: 2px solid #007aff;
+		border-left: 0;
+		border-top: 0;
+		height: 10px;
+		width: 5px;
+		transform-origin: center;
+		/* #ifndef APP-NVUE */
+		transition: all 0.3s;
+		/* #endif */
+		transform: rotate(45deg);
+	}
+
+	.item-check .radio {
+		border-top-left-radius: 50%;
+		border-top-right-radius: 50%;
+		border-bottom-right-radius: 50%;
+		border-bottom-left-radius: 50%;
+	}
+
+	.item-check .radio .item-check-yes-b {
+		border-top-left-radius: 50%;
+		border-top-right-radius: 50%;
+		border-bottom-right-radius: 50%;
+		border-bottom-left-radius: 50%;
+	}
+
+	.hover-c {
+		opacity: 0.6;
+	}
+
+	.itemBorder {
+		border-bottom: 1px solid #e5e5e5;
+	}
+</style>

+ 69 - 146
pages/common/productType.vue

@@ -1,64 +1,51 @@
 <template>
-	<u-popup v-model="isShow" class="type-picker" @close="isShow=false" mode="bottom">
-		<view class="type-header flex justify_between align_center">
-			<text class="type-picker-btn" @click="onClean">清空</text>
-			<text>产品分类</text>
-			<text class="type-picker-btn color-blue" @click="isShow=false">
-				<u-icon name="close"></u-icon>
-			</text>
-		</view>
-		<u-row class="choose-info">
-			<u-col :span="3">当前已选:</u-col>
-			<u-col :span="7" :style="{color: $config('primaryColor')}">
-				<view v-for="(item, index) in infoDataS" :key="index" style="display: inline-block;">{{item.productTypeName}}<text v-if="index+1 != infoData.length"> > </text></view>
-			</u-col>
-			<u-col :span="2"><u-button v-if="infoDataS.length>0" @click="handlerConfirm" type="success" size="mini" :custom-style="customStyle" hover-class="none" shape="circle">确定</u-button></u-col>
-		</u-row>
-		<scroll-view class="picker-content" scroll-y>
-			<view class="picker-main">
-				<view class="picker-main-item" v-for="(item, index) in typeList" :key="item.productTypeSn" @click="chooseItem(index)">
-					<view class="item-name">{{item.productTypeName}}</view>
-					<u-icon v-show="item.productTypeSn==(infoDataS[nowInd]&&infoDataS[nowInd].productTypeSn)" class="item-icon" name="checkbox-mark" :color="$config('primaryColor')" size="28"></u-icon>
-				</view>
-				<view v-if="typeList && typeList.length == 0">
-					<u-empty text="数据为空" mode="list" :img-width="200" :margin-top="-60"></u-empty>
-				</view>
-			</view>
-		</scroll-view>
-	</u-popup>
+	<view style="width: 100%;">
+		    <ba-tree-picker 
+			ref="treePicker" 
+			:multiple='multiple' 
+			@select-change="selectChange" 
+			@cancel="cancel"
+			title="选择产品分类"
+		    :localdata="listData" 
+			:selectParent="selectParent" 
+			valueKey="productTypeSn" 
+			textKey="productTypeName" 
+			childrenKey="children" />
+	</view>
 </template>
 
 <script>
 	import { dealerProductTypeList } from '@/api/dealerProductType'
+	import baTreePicker from "@/components/ba-tree-picker/ba-tree-picker.vue"
 	export default {
+		components: {
+			baTreePicker
+		},
 		props: {
 			openModal: { //  弹框显示状态
 				type: Boolean,
 				default: false
 			},
+			selectParent:{
+				type: Boolean,
+				default: false
+			},
+			multiple:{
+				type: Boolean,
+				default: false
+			},
 			nowData: {
-				type: Object,
-				default: ()=>{
-					return {
-						data: [],
-						indArr: [],
-						nowInd: 0
-					}
-				}
+				type: Array,
+				default: ()=>[]
 			}
 		},
 		data() {
 			return {
 				isShow: this.openModal, //  是否打开弹框
 				listData: [],
-				typeList: [],
-				nowInd: 0,
-				indArr: [],
-				infoData: [],
-				infoDataS: [],
 				customStyle: {
 					background: this.$config('primaryColor')
-				}
+				},
 			}
 		},
 		mounted() {
@@ -69,51 +56,49 @@
 				dealerProductTypeList({}).then(res => {
 					if(res.status == 200 && res.data){
 						this.listData = res.data
-						this.typeList = res.data
 					}else{
 						this.listData = []
-						this.typeList = []
 					}
 				})
 			},
-			//  选择
-			chooseItem(ind){
-				if(this.nowInd == 0){
-					this.infoData[this.nowInd] = { productTypeName: this.typeList[ind].productTypeName, productTypeSn: this.typeList[ind].productTypeSn }
-					this.infoData[1] ? delete this.infoData[1] : null
-					this.infoData[2] ? delete this.infoData[2] : null
-					this.indArr[this.nowInd] = ind
-					this.indArr[1] ? delete this.indArr[1] : null
-					this.indArr[2] ? delete this.indArr[2] : null
-					this.nowInd++
-				}else if(this.nowInd == 1){
-					this.infoData[this.nowInd] = { productTypeName: this.typeList[ind].productTypeName, productTypeSn: this.typeList[ind].productTypeSn }
-					this.infoData[2] ? delete this.infoData[2] : null
-					this.indArr[this.nowInd] = ind
-					this.indArr[2] ? delete this.indArr[2] : null
-					this.nowInd++
-				}else if(this.nowInd == 2){
-					this.infoData[this.nowInd] = { productTypeName: this.typeList[ind].productTypeName, productTypeSn: this.typeList[ind].productTypeSn }
-					this.indArr[this.nowInd] = ind
-				}
-				this.infoDataS = JSON.parse(JSON.stringify(this.infoData))
+			// 显示选择器
+			showPicker() {
+				this.$refs.treePicker._show();
+			},
+			hidePicker(){
+				this.$refs.treePicker._hide();
+			},
+			//监听选择(ids为数组)
+			selectChange(ids, names) {
+				const selNodes = ids&&ids.length ? this.findParents(this.listData, ids[0]) : null
+				this.$emit('choose', selNodes)
+				this.cancel()
+			},
+			// 查找所有父级节点的函数
+			findParents(treeData, childId) {
+			    function recursiveFind(nodes, childId, parents = []) {
+			        for (let node of nodes) {
+			            if (node.productTypeSn === childId) {
+			                return [...parents, node]; // 找到目标子节点,返回其所有父节点ID
+			            }
+			            if (node.children && node.children.length > 0) {
+			                const result = recursiveFind(node.children, childId, [...parents, node]);
+			                if (result) {
+			                    return result; // 在子节点中找到目标子节点,返回其所有父节点ID
+			                }
+			            }
+			        }
+			        return null; // 未找到目标子节点
+			    }
+			
+			    const result = recursiveFind(treeData, childId);
+			    return result ? result : []; // 若未找到,则返回空数组(或根据需要返回null)
 			},
 			handlerConfirm(){
-				const params = {
-					data: this.infoDataS,
-					indArr: this.indArr,
-					nowInd: this.nowInd
-				}
-				this.$emit('choose', params)
-				this.isShow = false
+				this.$emit('choose', [])
+				this.cancel()
 			},
-			// 清空
-			onClean(){
-				this.infoData = []
-				this.infoDataS = []
-				this.indArr = []
-				this.nowInd = 0
-				this.$emit('clean')
+			cancel(){
 				this.isShow = false
 			}
 		},
@@ -126,24 +111,14 @@
 			isShow (newValue, oldValue) {
 				if (!newValue) {
 					this.$emit('close')
+					this.hidePicker()
 				}else{
-					this.infoData = JSON.parse(JSON.stringify(this.nowData.data))
-					this.infoDataS = JSON.parse(JSON.stringify(this.nowData.data))
-					this.indArr = this.nowData.indArr
-					this.nowInd = this.nowData.nowInd
+					this.showPicker()
 				}
 			},
-			nowInd (newValue, oldValue) {
-				if (newValue || newValue == 0) {
-					if (newValue == 0) {
-						this.typeList = this.listData || []
-					}else if (newValue == 1) {
-						this.typeList = (this.indArr[0] || this.indArr[0]==0) && this.listData[this.indArr[0]] && this.listData[this.indArr[0]].children ? this.listData[this.indArr[0]].children : []
-					}else if (newValue == 2) {
-						let oList = (this.indArr[0] || this.indArr[0]==0) && this.listData[this.indArr[0]] && this.listData[this.indArr[0]].children ? this.listData[this.indArr[0]].children : []
-						let tList = (this.indArr[1] || this.indArr[1]==0) && oList[this.indArr[1]] && oList[this.indArr[1]].children ? oList[this.indArr[1]].children : []
-						this.typeList = tList
-					}
+			nowData(newValue, oldValue){
+				if(newValue.length == 0){
+					this.$refs.treePicker._reTreeList()
 				}
 			}
 		}
@@ -151,57 +126,5 @@
 </script>
 
 <style lang="scss" scoped>
-	.type-picker{
-		.type-header{
-			padding: 0 30upx;
-			position: relative;
-			.brand-picker-btn{
-				color: rgb(96, 98, 102);
-				margin: 10upx;
-			}
-			.color-blue{
-				display: inline-block;
-				padding: 10upx 20upx;
-				margin: 10upx 0;
-			}
-		}
-		.type-header:after{
-			content: "";
-			position: absolute;
-			border-bottom: 1px solid #eaeef1;
-			-webkit-transform: scaleY(.5);
-			transform: scaleY(.5);
-			bottom: 0;
-			right: 0;
-			left: 0;
-		}
-		.choose-info{
-			padding: 14upx 30upx 14upx;
-			color: rgb(96, 98, 102);
-		}
-		.picker-content{
-			height: 50vh;
-			padding: 6upx 0 20upx;
-			position: relative;
-			.picker-main{
-				width: 100%;
-				.picker-main-item{
-					position: relative;
-					padding: 0 30upx;
-					.item-name{
-						padding: 14upx 0;
-						text-align: center;
-					}
-					.item-icon{
-						position: absolute;
-						right: 100upx;
-						top: 19upx;
-					}
-					&:active{
-						background: #f8f8f8;
-					}
-				}
-			}
-		}
-	}
+	 
 </style>

+ 12 - 23
pages/stock/index.vue

@@ -69,11 +69,7 @@
 				brandModal: false,
 				brandName: '',
 				showTypeModal: false,
-				nowData: {
-					data: [],
-					indArr: [],
-					nowInd: 0
-				},
+				nowData:[],
 				customBtnStyle: {  //  自定义按钮样式
 					backgroundColor: this.$config('primaryColor'),
 					color: '#fff'
@@ -83,7 +79,7 @@
 		computed: {
 			productTypeNameArr: function() {
 				let str = ''
-				this.nowData.data.map(item => {
+				this.nowData.map(item => {
 					str += item.productTypeName+' / '
 				})
 				return str ? str.substr(0, str.length-3) : ''
@@ -147,11 +143,7 @@
 				this.form.productOrigCode = ''
 				this.brandName = ''
 				this.form.productBrandSn = undefined
-				this.nowData = {
-					data: [],
-					indArr: [],
-					nowInd: 0
-				}
+				this.nowData = []
 				this.form.productTypeSn1 = undefined
 				this.form.productTypeSn2 = undefined
 				this.form.productTypeSn3 = undefined
@@ -181,22 +173,19 @@
 			},
 			// 选择分类
 			typeChoose(obj){
-				this.nowData = {
-					data: obj.data,
-					indArr: obj.indArr,
-					nowInd: obj.nowInd
+				console.log(obj)
+				if(obj){
+					this.nowData = obj
+					this.form.productTypeSn1 = obj[0].productTypeSn
+					this.form.productTypeSn2 = obj[1].productTypeSn
+					this.form.productTypeSn3 = obj[2].productTypeSn
+				}else{
+					this.typeClean()
 				}
-				this.form.productTypeSn1 = this.nowData.data[0]&&this.nowData.data[0].productTypeSn ? this.nowData.data[0].productTypeSn : undefined
-				this.form.productTypeSn2 = this.nowData.data[1]&&this.nowData.data[1].productTypeSn ? this.nowData.data[1].productTypeSn : undefined
-				this.form.productTypeSn3 = this.nowData.data[2]&&this.nowData.data[2].productTypeSn ? this.nowData.data[2].productTypeSn : undefined
 			},
 			// 清空分类
 			typeClean(){
-				this.nowData = {
-					data: [],
-					indArr: [],
-					nowInd: 0
-				}
+				this.nowData = []
 				this.form.productTypeSn1 = undefined
 				this.form.productTypeSn2 = undefined
 				this.form.productTypeSn3 = undefined