You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
8.8 KiB
Vue

1 year ago
<template>
<view class="tm-treeSelect fulled-height">
<view class="tm-treeSelect-slide ">
<scroll-view scroll-y
:style="{
height:activeHeight+'px'
}"
>
<tm-listitem :disabled="item['disabled']?true:false"
:black="black_tmeme" @click="activeIndex=index"
:disabled-color="bgColor"
v-for="(item,index) in formaData" :key='index'
:color="activeIndex==index?(text?' text ' + color:'white'):bgColor"
:show-right-icon="false"
:margin="[0,0]"
fontSize="26"
:class-style="activeIndex==index?`border-${color_tmeme}-l-2`:'border-grey-lighten-5-l-2'"
round="0" shadow="0"
>
<tm-badges color='red' :fllowTheme="false" :offset="[12,-10]" v-if="item.dot>0&&dot" :dot="false" :label="item.dot"></tm-badges>
<view class="mr-10">
<text :class="[`text-${activeIndex==index?color_tmeme:fontColor}`,item['disabled']?'opacity-3':'']">{{item[rangKey]}}</text>
</view>
</tm-listitem>
</scroll-view>
</view>
<view class="tm-treeSelect-slideitem" >
<scroll-view scroll-y
:style="{
height:activeHeight+'px'
}"
>
<tm-groupcheckbox v-if="formaData[activeIndex]" :max="max" @change="changeOk">
<block v-for="(item,index) in formaData[activeIndex].children" :key='index'>
<tm-checkbox dense
:disabled="item['disabled']||formaData[activeIndex]['disabled']?true:false"
:color="color_tmeme" round="2" @change="itemChange"
:name="item"
v-model="item.checked">
<tm-listitem fontSize="28" :black="black_tmeme" :padding="[24,24]" :margin="[0,0]" :border-bottom="true" round="0" shadow="0"
:title="item[rangKey]" >
<template #default>
<text :class="[item.checked?'text-'+color_tmeme:'']">{{item[rangKey]}}</text>
</template>
<template v-slot:rightIcon>
<view style="line-height: 0;vertical-align: middle;min-width: 40rpx;" class="fulled">
<view v-if="item.checked" class="rounded flex-center" :class="[color_tmeme,`shadow-${color_tmeme}-4`]" style="width: 34rpx;height: 34rpx;">
<text class="iconfont icon-check text-size-xs"></text>
</view>
<!-- <tm-icons dense v-if="item.checked" name="icon-check-circle"></tm-icons> -->
<!-- <tm-button v-if="item.checked" icon="icon-check" fab size="xs"></tm-button> -->
</view>
</template>
</tm-listitem>
</tm-checkbox>
</block>
</tm-groupcheckbox>
</scroll-view>
</view>
</view>
</template>
<script>
/**
* 分类选择
* @property {Number|String} height = [] 默认0单位upx,自动使用父组件的高度
* @property {Array} default-selected = [] 默认[]可以是id索引也可以是对象数组,可以混着来[1]
* @property {Array} list = [] 默认[]数据结构对象必须需要含有唯一标识符id即可[{title:'苏州',id:1}],每一个类目和子类可以含有disabled值用来禁用类目或者选项
* @property {String} rang-key = [] 默认'title'数据结构对象中需要展示标签的key
* @property {Number} max = [] 默认999每一项目最大选择数量1可以实现单选
* @property {String} color = [] 默认 primary主题色名
* @property {String} bg-color = [] 默认 grey-lighten-5主题色名未选择时的背景色
* @property {String} font-color = [] 默认 grey未选中时的文字颜色
* @property {Boolean} text = [] 默认 false使用主题文本色为高亮色
* @property {Boolean} black = [] 默认 false是否暗黑模式
* @property {Boolean} dot = [] 默认 false是否显示角标数字,当前选中的数量
* @property {Function} children-change 选中单个选项时触发返回选中的数据
* @property {Function} change 每次选择变化都会触发全局change,返回当前类目和所有类目选中的数据
* @example <tm-treeSelect color="green" ></tm-treeSelect>
*/
import tmListitem from "@/tm-vuetify/components/tm-listitem/tm-listitem.vue"
import tmGrouplist from "@/tm-vuetify/components/tm-grouplist/tm-grouplist.vue"
import tmBadges from "@/tm-vuetify/components/tm-badges/tm-badges.vue"
import tmGroupcheckbox from "@/tm-vuetify/components/tm-groupcheckbox/tm-groupcheckbox.vue"
import tmCheckbox from "@/tm-vuetify/components/tm-checkbox/tm-checkbox.vue"
export default {
components:{tmListitem,tmGrouplist,tmBadges,tmGroupcheckbox,tmCheckbox},
name:"tm-treeSelect",
props:{
// 高度默认为0时自动使用父组件的高度.
height: {
type: String | Number,
default: 0
},
// 可以是id索引也可以是对象数组,可以混着来。
defaultSelected:{
type:Array,
default:()=>{
return []
}
},
// 对象数组
list:{
type:Array,
default:()=>{
return [];
}
},
// 显示标签的key.
rangKey:{
type:String,
default:'title'
},
// 每一项目最大选择数量1可以实现单选。
max:{
type:Number,
default:999
},
// 主题色名
color:{
type:String,
default:'primary'
},
// 未选择时的背景色。
bgColor:{
type:String,
default:'grey-lighten-5'
},
//未选择时的文字色。
fontColor:{
type:String,
default:'grey-darken-1'
},
// 使用主题文本色为高亮色。
text:{
type:Boolean,
default:false
},
black:{
type:Boolean,
default:null
},
// 是否显示角标数字当前选中的数量。
dot:{
type:Boolean,
default:false
},
// 跟随主题色的改变而改变。
fllowTheme:{
type:Boolean|String,
default:true
}
},
data() {
return {
activeHeight: 0,
activeIndex:0,
formaData:[]
};
},
watch:{
list:{
deep:true,
handler:function(){
this.formaData = [...this.dataList];
}
},
defaultSelected:{
deep:true,
handler:function(){
this.clear()
this.formaData = [...this.clear()]
this.formaData = [...this.dataList];
}
}
},
computed:{
black_tmeme: function() {
if (this.black !== null) return this.black;
return this.$tm.vx.state().tmVuetify.black;
},
color_tmeme:function(){
if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
dataList(){
let t = this;
let p = this.$tm.deepClone(this.list)
for(let j=0;j<p.length;j++){
p[j]['dot'] = 0;
if(p[j].children){
let ic = p[j].children;
for(let k=0;k<ic.length;k++){
if(!ic[k].hasOwnProperty('checked')){
ic[k]['checked'] = false;
}
for(let i=0 ;i < t.defaultSelected.length;i++){
let lsitem = t.defaultSelected[i];
if(typeof lsitem === 'object'){
if(lsitem['id'] == ic[k]['id']){
ic[k]['checked'] = true;
}
}else{
if(lsitem == ic[k]['id']){
ic[k]['checked'] = true;
}
}
}
if(ic[k]['checked']===true){
p[j]['dot'] +=1
}
}
}
}
return p;
},
},
mounted() {
let t = this;
this.$nextTick(async function() {
this.activeHeight = uni.upx2px(this.height);
if (!this.activeHeight) {
let wsz = await this.$Querey(".tm-treeSelect",this).catch(e=>{})
this.activeHeight = wsz[0].height||250;
}
this.formaData = [...this.dataList];
});
},
methods: {
clear(){
let t = this;
let p = this.$tm.deepClone(this.list)
for(let j=0;j<p.length;j++){
p[j]['dot'] = 0;
if(p[j].children){
let ic = p[j].children;
for(let k=0;k<ic.length;k++){
if(!ic[k].hasOwnProperty('checked')){
ic[k]['checked'] = false;
}else{
ic[k]['checked'] = false;
}
}
}
}
return p;
},
// 所有选项。
changeOk(e) {
let p = [];
function ts(obj){
if(Array.isArray(obj)){
obj.forEach(item=>{
if(item.children){
ts(item.children);
}else{
if(item.checked===true){
p.push(item)
}
}
})
}
}
ts(this.dataList);
this.$emit('change',{
all:p,//所有选择项
index:this.activeIndex,//当前数目索引
children:e//当前类目的选中的选择项
});
if(this.formaData.length>0){
this.$set(this.formaData[this.activeIndex],'dot',e.length)
}
},
// 单个数组点击切换产生的选项。
itemChange(e){
let t = this;
//返回的格式: {"index":4,"checked":true,"value":推荐的数据}
this.$emit('children-change',e)
}
},
}
</script>
<style lang="scss" scoped>
.tm-treeSelect{
height: 100%;
display: flex;
justify-content: flex-start;
.tm-treeSelect-slide{
width: 190upx;
}
.tm-treeSelect-slideitem{
width: calc(100% - 190upx);
}
}
</style>