291 lines
7.2 KiB
Vue
291 lines
7.2 KiB
Vue
<template>
|
|
<section class="AiPicker">
|
|
<ai-dialog-btn
|
|
custom-class=""
|
|
v-bind="$attrs"
|
|
append-to-body
|
|
@onConfirm="handleSave"
|
|
:customFooter="false"
|
|
:modal-append-to-body="false"
|
|
:close-on-click-modal="false"
|
|
@close="selected=[]"
|
|
@open="selected=$copy(picked)">
|
|
<template #btn v-if="$scopedSlots.default">
|
|
<slot :selected="picked"/>
|
|
</template>
|
|
<div class="AiWechatSelecter-container">
|
|
<div class="AiWechatSelecter-container__left">
|
|
<div class="AiWechatSelecter-header">
|
|
<div class="AiWechatSelecter-header__left">
|
|
<h2 class="active" v-text="pageTitle"/>
|
|
</div>
|
|
</div>
|
|
<el-scrollbar class="AiWechatSelecter-list">
|
|
<el-tree v-if="refreshTree" lazy :load="getOptions" :props="props">
|
|
<template slot-scope="{data}">
|
|
<el-row type="flex" align="middle" class="optionItem fill" @click.native.stop="handleSelect(data)">
|
|
<div class="fill overHide">
|
|
<ai-open-data v-if="data.openType" :type="data.openType" :openid="data[props.id]"/>
|
|
<p v-else v-text="data[props.label]"/>
|
|
</div>
|
|
<div class="iconfont iconSuccess color-primary" v-if="data.checked&&isSelected(data)"/>
|
|
</el-row>
|
|
</template>
|
|
</el-tree>
|
|
</el-scrollbar>
|
|
</div>
|
|
<div class="AiWechatSelecter-container__right">
|
|
<div class="AiWechatSelecter-header AiWechatSelecter-header__right">
|
|
<h2>已选择</h2>
|
|
<el-button size="mini" icon="el-icon-delete" @click="selected=[]">清空</el-button>
|
|
</div>
|
|
<el-scrollbar class="AiWechatSelecter-list">
|
|
<div class="tags-wrapper">
|
|
<el-tag v-for="(item, index) in selected" :key="item.id" closable @close="handleRemove(index)" type="info">
|
|
<ai-open-data class="fill overHide" v-if="item.openType" :type="item.openType" :openid="item[props.id]"/>
|
|
<p class="fill overHide" v-else v-text="item[props.label]"/>
|
|
</el-tag>
|
|
</div>
|
|
</el-scrollbar>
|
|
</div>
|
|
</div>
|
|
</ai-dialog-btn>
|
|
</section>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: "AiPicker",
|
|
model: {
|
|
prop: "value",
|
|
event: "change"
|
|
},
|
|
props: {
|
|
value: {default: () => []},
|
|
action: {default: "/app/wxcp/wxdepartment/departList"},
|
|
instance: Function,
|
|
meta: {default: () => []},
|
|
pageTitle: {default: "部门"},
|
|
ops: {default: () => ({})},
|
|
multiple: Boolean,
|
|
timer: null,
|
|
},
|
|
data() {
|
|
return {
|
|
selected: [],
|
|
picked: [],
|
|
refreshTree: true
|
|
}
|
|
},
|
|
computed: {
|
|
props: v => ({id: 'id', label: 'name', ...v.ops})
|
|
},
|
|
watch: {
|
|
action(v) {
|
|
if (v) {
|
|
this.refreshTree = false
|
|
this.initValue()
|
|
this.$nextTick(() => this.refreshTree = true)
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
getOptions(node, resolve) {
|
|
const {props: {id}} = this
|
|
if (node.level == 0) {
|
|
this.getTreeData().then(list => resolve(list || []))
|
|
} else {
|
|
const parent = node.data[id]
|
|
this.getTreeData({id: parent}).then(list => resolve(list || []))
|
|
}
|
|
},
|
|
getTreeData(params) {
|
|
const selected = params?.selected, {action} = this
|
|
if (selected) delete params.selected
|
|
return this.instance.post(action, selected, {params, headers: {'Content-Type': 'application/json'}}).then(res => {
|
|
if (res?.data) {
|
|
if (selected) {
|
|
this.picked = res.data.selected
|
|
}
|
|
return res.data.itemList.map(e => ({...e, checked: this.isSelected(e)}))
|
|
}
|
|
})
|
|
},
|
|
handleRemove(i) {
|
|
this.selected.splice(i, 1)
|
|
},
|
|
handleSave() {
|
|
const {id} = this.props
|
|
this.picked = this.$copy(this.selected)
|
|
this.$emit("change", this.selected.map(e => e[id]).filter(Boolean))
|
|
this.$emit("pick", this.selected)
|
|
},
|
|
isSelected(row) {
|
|
const {id: key} = this.props
|
|
return !!this.selected.find(e => e[key] == row[key])
|
|
},
|
|
initValue() {
|
|
const unwatch = this.$watch('value', (v) => {
|
|
if (this.selected.length > 0) unwatch && unwatch()
|
|
else if (!!v?.toString()) {
|
|
this.getTreeData({selected: v?.toString()})
|
|
unwatch && unwatch()
|
|
}
|
|
}, {immediate: true})
|
|
},
|
|
handleSelect(row) {
|
|
row.checked = !row.checked
|
|
if (row.checked) {
|
|
const current = this.$copy(row)
|
|
if (this.multiple) {
|
|
this.selected.push(current)
|
|
} else {
|
|
this.selected = [current]
|
|
}
|
|
} else {
|
|
if (this.multiple) {
|
|
const {id} = this.props, i = this.selected.findIndex(e => e[id] == row[id])
|
|
this.handleRemove(i)
|
|
} else this.selected = []
|
|
}
|
|
}
|
|
},
|
|
created() {
|
|
this.initValue()
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.color-primary {
|
|
color: $primaryColor;
|
|
}
|
|
|
|
.optionItem {
|
|
cursor: pointer;
|
|
user-select: none;
|
|
padding-right: 16px;
|
|
}
|
|
|
|
.AiOpenData {
|
|
pointer-events: none;
|
|
}
|
|
|
|
.AiWechatSelecter-container {
|
|
display: flex;
|
|
height: 480px;
|
|
|
|
.el-tree {
|
|
background: transparent;
|
|
|
|
.el-tree-node__content {
|
|
height: auto;
|
|
margin-top: 2px;
|
|
|
|
&:hover {
|
|
background: #f4f5f6;
|
|
}
|
|
}
|
|
|
|
.el-tree-node__expand-icon {
|
|
height: 24px;
|
|
}
|
|
}
|
|
|
|
& > div {
|
|
width: 280px;
|
|
background: #FCFCFC;
|
|
border: 1px solid #D0D4DC;
|
|
}
|
|
|
|
.AiWechatSelecter-list {
|
|
height: calc(100% - 40px);
|
|
padding: 8px 0;
|
|
|
|
:deep( .el-scrollbar__wrap ){
|
|
margin-bottom: 0 !important;
|
|
overflow-x: hidden;
|
|
}
|
|
}
|
|
|
|
.AiWechatSelecter-container__left {
|
|
flex: 1;
|
|
}
|
|
|
|
.AiWechatSelecter-container__right {
|
|
flex: 1;
|
|
margin-left: 20px;
|
|
|
|
.AiWechatSelecter-list {
|
|
.tags-wrapper {
|
|
padding: 0 8px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.el-tag {
|
|
margin: 0 8px 8px 0;
|
|
color: #222222;
|
|
font-size: 14px;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
.AiWechatSelecter-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
height: 40px;
|
|
padding: 0 8px 0 0;
|
|
border-bottom: 1px solid #D0D4DC;
|
|
background: #F5F7FA;
|
|
|
|
.AiWechatSelecter-header__left {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
h2 {
|
|
width: 60px;
|
|
height: 100%;
|
|
line-height: 40px;
|
|
color: #222222;
|
|
font-size: 14px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
border-bottom: 2px solid transparent;
|
|
|
|
&.active {
|
|
color: $primaryColor;
|
|
border-color: $primaryColor;
|
|
}
|
|
}
|
|
}
|
|
|
|
.el-button {
|
|
height: 28px;
|
|
padding: 7px 5px;
|
|
}
|
|
|
|
.el-input {
|
|
width: 160px;
|
|
}
|
|
}
|
|
|
|
.AiWechatSelecter-header__right {
|
|
padding: 0 8px;
|
|
|
|
h2 {
|
|
color: #222222;
|
|
font-size: 14px;
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
:deep(.overHide) {
|
|
overflow: hidden;
|
|
}
|
|
</style>
|