529 lines
12 KiB
Vue
529 lines
12 KiB
Vue
<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> |