529 lines
12 KiB
Vue
Raw Permalink Normal View History

<template>
<view>
<uni-popup ref="orgPickerPopup" class="uni-popup" style="touch-action:none" :catchtouchmove="true"
@close="isShowPicker = false">
<uni-nav-bar v-if="$props.showNav" statusBar :title="$props.title" color="#fff"
backgroundColor="#4C87F3"></uni-nav-bar>
<view class="w-orgPicker-popup" :style="{height: wheight + 'px'}">
<view style="padding: 0 0 16rpx 0; background-color: white;">
<view class="search">
<uni-search-bar v-model="searchValue" bgColor="#EEEEEE" radius="5" placeholder="搜索"
clearButton="auto" cancelButton="none" />
<!-- :readonly="type === 'dept' || type === 'role'" -->
</view>
<view style="padding: 6rpx 16rpx;">
<scroll-view scroll-x>
<uni-breadcrumb separator=">">
<uni-breadcrumb-item v-for="(org, index) in orgPaths" :key="index"
>
<view
@click.stop="toDept(org.id, index)"
:style="{color: index + 1 === orgPaths.length ? '#989996':'#1E90FD','font-size': '32rpx'}">
{{org.name}}
</view>
</uni-breadcrumb-item>
</uni-breadcrumb>
</scroll-view>
</view>
</view>
<scroll-view v-if="orgList.length > 0" class="w-org-list contentHeight" scroll-y
:style="{height: contentHeight + 'px'}">
<uni-list>
<uni-list-item clickable v-for="(org, i) in orgDatas" class="w-org-item"
:key="`${org.type}_${org.id}`" :showArrow="$props.type === 'user' && org.type !== 'user'"
@click="selectChange(org)">
<template v-slot:header>
<view style="display: flex; align-items: center;">
<radio v-if="!($props.type === 'user' && org.type === 'dept')" :value="org.id"
:checked="org.selected" @click.stop="selectChange(org)"
style="transform:scale(0.9)" />
<view class="w-org-avatar">
<Avatar v-if="org.type === 'user'" :name="org.name" :src="getRes(org.avatar)"
:showName="false">
</Avatar>
<image class="w-dept-img" lazy-load mode="aspectFit" v-else
src="/static/image/dept.png"></image>
</view>
</view>
</template>
<template v-slot:body>
<view style="flex: 1; display: flex; align-items: center;">
<text
style="display: flex; align-items: center; font-size: 32rpx">{{org.name}}</text>
<view v-if="org.isLeader"
style="display: flex; align-items: center; margin-left: 16rpx;">
<uni-tag style="font-weight: 400;" type="warning" size="mini" text="部门负责人"
inverted></uni-tag>
</view>
</view>
</template>
<template v-slot:footer v-if="$props.type !== 'user' && org.type !== 'user'">
<view @click.stop="toInnerOrg(org)" :class="{'w-org-next': true, 'w-org-dis': false}">
<view>下级</view>
<uni-icons2 type="redo" :size="20" color="#4478F7"></uni-icons2>
</view>
</template>
</uni-list-item>
</uni-list>
</scroll-view>
<view v-else class="contentHeight" :style="{width: '100%', height: contentHeight + 'px'}">
<image mode="aspectFit" style="width: 100%;" src="/static/image/noUser.png"></image>
</view>
<view class="w-orgPicker-options">
<label v-show="$props.multiple">
<radio :checked="false" style="transform: scale(0.8);" />
全选
</label>
<view @click="showSelected">
<text>已选 [{{selectedMap.size}}] </text>
<uni-icons2 type="down" color="#4478F7"></uni-icons2>
</view>
<view>
<button class="w-button" style="margin-right: 20rpx;" type="default" size="mini"
@click="close">取消</button>
<button class="w-button" type="primary" size="mini" @click="selectOk">确认</button>
</view>
</view>
</view>
</uni-popup>
<uni-popup ref="orgPickerSelectedPopup" type="bottom">
<view class="w-orgPicker-selected">
<view class="w-selected" v-for="org in selectedUp" :key="`${org.type}_${org.id}`">
<view>
<Avatar :type="org.type" v-if="org.type==='user'" :closeable="org.enableEdit"
:src="getRes(org.avatar)" :size="25" :name="org.name" :showName="false"></Avatar>
</view>
<view>{{org.name}}</view>
<button size="mini" @click="removeSelected(org)">移除</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import Avatar from './Avatar.vue'
import {
getOrgTree,
getUserByName,
getDeptByName,
getEnterpriseByName
} from '@/api/org.js'
const selectedMap = new Map();
export default {
props: {
title: {
default: '请选择',
type: String
},
type: {
default: 'org', //org选择部门/人员 user-选人 dept-选部门 role-选角色
type: String
},
multiple: { //是否多选
default: false,
type: Boolean
},
selected: {
default: () => {
return []
},
type: Array
},
position: {
type: String,
default: 'right'
},
showNav: Boolean
},
components: {
Avatar
},
data() {
return {
wheight: 0,
selectAll: false,
isShowPicker: false,
selectedMap: null,
selectedMapNum: 0,
//当前展示的部门id
currentDeptId: 0,
searchValue: "",
//搜索结果
searchUsers: [],
//主数据
orgList: [],
//部门路径
orgPaths: [{
name: '组织',
id: 0
}],
isSearchMode: false,
}
},
computed: {
contentHeight() {
const baseH = uni.getSystemInfoSync().windowHeight - 168
//减去导航栏高度
// #ifdef H5
return baseH - (this.$props.showNav ? 44 : 0)
// #endif
// #ifndef H5
return baseH - (this.$props.showNav ? 88 : 0)
// #endif
},
selectedUp() {
const x = this.selectedMapNum;
const temp = []
this.selectedMap.forEach(v => temp.push({
id: v.id,
name: v.name,
avatar: v.avatar,
type: v.type
}))
console.log("我发生改变了")
return temp
},
selectCount() {
const x = this.selectedMapNum;
console.log("我发生改变了111")
return this.selectedMap.size
},
orgDatas() {
if (this.searchValue.trim() !== '') {
return this.searchUsers
}
return this.orgList
},
//获取文件访问路径
getRes() {
return (url) => {
if (url) {
const reg = /^(http:|https:).*/gi
return reg.test(url) ? url : this.url_config + 'image/' + url
} else {
return url
}
}
},
},
created() {
this.selectedMap = selectedMap;
this.wheight = uni.getSystemInfoSync().windowHeight
},
onLoad() {
},
mounted() {
if (this.$props.type == "dept") {
this.orgPaths = [{
name: '部门',
id: 0
}]
}
},
onShow() {
},
onBackPress() {
this.backToParent()
},
methods: {
toDept(orgId, i) {
this.currentDeptId = orgId
this.orgPaths.length = i + 1
this.getOrgList()
},
showPicker() {
//加载选中数据
(this.$props.selected || []).forEach(org => {
const _org = Object.assign({}, org)
_org.selected = true
this.selectedMap.set(org.id + org.type, _org)
this.selectedMapNum += 1;
})
this.isShowPicker = true
},
backToParent() {
if (this.orgPaths.length > 1) {
this.orgPaths.length--
this.currentDeptId = this.orgPaths[this.orgPaths.length - 1].id
this.getOrgList()
return true;
} else if (this.$refs.orgPickerPopup.close instanceof Function) {
this.$refs.orgPickerPopup.close()
return false;
}
},
toInnerOrg(org) {
console.log(org);
if (org.type === 'dept') {
this.currentDeptId = org.id
this.orgPaths.push({
name: org.name,
id: org.id
})
this.getOrgList()
} else if (org.type === 'enterprise') {
this.currentDeptId = org.id
this.orgPaths.push({
name: org.name,
id: org.id
})
this.getOrgList()
}
},
getOrgList() {
const sn = JSON.parse(uni.getStorageSync('projectDetail')).projectSn
getOrgTree({
deptId: this.currentDeptId + "P" + sn,
type: this.$props.type
}).then(rsp => {
this.orgList = rsp.data
this.loadSelected(this.orgList)
}).catch(err => {
})
},
searchUser() {
this.searchUsers.length = 0
console.log(this.$props.type, "type");
let request = null;
let name = ""
switch (this.$props.type) {
case "user":
name = "userName"
request = getUserByName
break;
case "enterprise":
name = "enterpriseName";
request = getEnterpriseByName
break;
case "dept":
name = "deptName";
request = getDeptByName
break;
}
request({
[name]: this.searchValue.trim()
}).then(rsp => {
this.searchUsers = rsp.data.map(org => {
org.selected = this.selectedMap.has(org.id + org.type)
return org
})
}).catch(err => {
})
},
/**
* 打开组织架构选择器
* @param {Object} rootDeptId 根部门ID
*/
show(rootDeptId = 0) {
// debugger
this.currentDeptId = rootDeptId
this.orgPaths[0].id = rootDeptId
this.getOrgList()
this.$refs.orgPickerPopup.open(this.$props.position)
this.showPicker()
},
close() {
this.selectedMap.clear()
this.$refs.orgPickerPopup.close()
this.orgPaths = [{
name: '部门',
id: 0
}];
},
/**
* 确认选中
*/
selectOk() {
if (this.selectedUp.length === 0) {
uni.showToast({
icon: 'none',
title: '无选中项😥'
})
} else {
this.$emit('ok', this.selectedUp)
this.close()
}
},
selectChange(org) {
console.log(org, "org");
if (org.type === 'dept' && this.$props.type === 'user') {
//选用户时不触发部门,直接进入子部门
this.toInnerOrg(org)
return;
}
const orgId = org.id + org.type
if (this.selectedMap.has(orgId)) {
//取消选中
org.selected = false
this.selectedMap.delete(orgId)
} else {
//选中
if (!this.$props.multiple) {
//单选的话清除之前选的
this.selectedMap.forEach(v => v.selected = false)
// 清空之前选中的
this.orgDatas.forEach(v => v.selected = false)
org.selected = true
this.selectedMap.clear()
}
this.selectedMap.set(orgId, org)
console.log(this.selectedMap, "this.selectedMap", this.$props);
}
this.selectedMapNum += 1;
},
//加载选中数据状态
loadSelected(orgs) {
orgs.forEach(org => {
const orgId = org.id + org.type
org.selected = this.selectedMap.has(org.id + org.type)
})
},
showSelected() {
if (this.selectedMap.size === 0) {
uni.showToast({
icon: 'none',
title: '没有选中的项'
})
} else {
this.$refs.orgPickerSelectedPopup.open()
}
},
removeSelected(org) {
const orgId = org.id + org.type
this.selectedMap.get(orgId).selected = false
this.selectedMap.delete(orgId)
if (this.selectedMap.size === 0) {
this.$refs.orgPickerSelectedPopup.close()
}
this.selectedMapNum += 1;
},
},
watch: {
searchValue: {
handler(newVal) {
if (this.searchValue.trim() !== '') {
this.searchUser()
}
},
},
},
}
</script>
<style lang="less" scoped>
page {
background-color: #F4F5F7;
}
.contentHeight {
height: 926rpx !important;
}
.w-org-paths {
background-color: white;
}
:deep(.w-org-list) {
font-size: 32rpx;
margin-top: 26rpx;
.w-org-item {
z-index: 11;
.uni-list-item__container {
align-items: center;
}
}
}
.w-org-avatar {
display: flex;
justify-content: center;
align-items: center;
.w-dept-img {
width: 51rpx;
height: 51rpx;
padding: 13rpx;
border-radius: 20rpx;
background-color: #c4d7ff;
}
margin-right: 26rpx;
}
.search {
.search-input {
font-size: 32rpx;
background-color: #F4F5F7;
border-radius: 13rpx;
}
}
.w-orgPicker-popup {
width: 100vw;
height: 100vh;
background-color: #F4F5F7;
}
.w-org-next {
color: #4478F7;
display: flex;
align-items: center;
}
.w-orgPicker-options {
height: 120rpx;
padding: 32rpx;
background-color: #F1F1F1;
display: flex;
align-items: center;
&>label {
display: flex;
align-items: center;
}
&>view:nth-child(2) {
flex: 1;
color: #4478F7;
margin-left: 20rpx;
}
}
.w-orgPicker-selected {
padding: 32rpx;
background-color: white;
.w-selected {
display: flex;
align-items: center;
padding: 10rpx;
background-color: #F1F1F1;
border-radius: 10rpx;
margin: 4rpx 0;
&>view:first-child {
margin-right: 10rpx;
image {
width: 40rpx;
height: 40rpx;
}
}
&>view:nth-child(2) {
flex: 1;
}
}
}
</style>