|
@@ -2,149 +2,155 @@
|
|
|
<el-container style="height: 100%">
|
|
|
<el-aside style="border-right: 1px solid #e6e6e6; padding-right: 20px">
|
|
|
<el-input v-model="input" placeholder="请输入姓名、邮箱或手机号"></el-input>
|
|
|
- <el-tree v-if="!input" :data="rootOrganizations"
|
|
|
- ref="tree"
|
|
|
- :expand-on-click-node="false"
|
|
|
- :props="defaultProps"
|
|
|
- :render-after-expand='false'
|
|
|
- lazy
|
|
|
- :load="loadNode"
|
|
|
- @node-click="handleNodeClick"
|
|
|
+ <el-tree v-if="!input" :data="rootOrganizations" ref="tree" :expand-on-click-node="true"
|
|
|
+ :props="defaultProps" :render-after-expand='false' lazy :load="loadNode" @node-click="handleNodeClick"
|
|
|
@node-expand="handleNodeExpand">
|
|
|
<span class="custom-tree-node" slot-scope="{ node}">
|
|
|
<span>{{ node.label }}</span>
|
|
|
<el-dropdown trigger="click" size="medium" @command="handleDepartmentCommand">
|
|
|
- <span>
|
|
|
+ <span>
|
|
|
<el-icon class="el-icon-more"/>
|
|
|
</span>
|
|
|
<el-dropdown-menu slot="dropdown">
|
|
|
- <el-dropdown-item v-if="!node.data.groupId" :command="{c:'create-org-group', node: node, depart:node.data}">创建组织官方群</el-dropdown-item>
|
|
|
- <el-dropdown-item :command="{c:'edit', node: node, depart:node.data}">编辑部门</el-dropdown-item>
|
|
|
- <el-dropdown-item :command="{c:'add-sub', node: node, depart:node.data}">添加子部门</el-dropdown-item>
|
|
|
- <el-dropdown-item style="color: red" :command="{c:'remove', node: node, depart:node.data}">删除部门</el-dropdown-item>
|
|
|
- </el-dropdown-menu>
|
|
|
+ <el-dropdown-item v-if="!node.data.groupId"
|
|
|
+ :command="{ c: 'create-org-group', node: node, depart: node.data }">创建组织官方群</el-dropdown-item>
|
|
|
+ <el-dropdown-item
|
|
|
+ :command="{ c: 'edit', node: node, depart: node.data }">编辑部门</el-dropdown-item>
|
|
|
+ <el-dropdown-item
|
|
|
+ :command="{ c: 'add-sub', node: node, depart: node.data }">添加子部门</el-dropdown-item>
|
|
|
+ <el-dropdown-item style="color: red"
|
|
|
+ :command="{ c: 'remove', node: node, depart: node.data }">删除部门</el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
</el-dropdown>
|
|
|
- </span>
|
|
|
+ </span>
|
|
|
</el-tree>
|
|
|
<div v-else>
|
|
|
TODO search result
|
|
|
</div>
|
|
|
</el-aside>
|
|
|
- <el-container>
|
|
|
+ <el-container v-if="currentOrg">
|
|
|
<el-header>
|
|
|
- <div style="height: 100%; display: flex; flex-direction: row; align-items: center; justify-content: center">
|
|
|
- <p style="flex: 1 1 auto"> {{ currentOrg && currentOrg.name }}</p>
|
|
|
- <el-button type="primary" icon="el-icon-plus" @click="showAddDepartmentMemberDialog = true">添加成员</el-button>
|
|
|
- <el-button v-if="rootOrganizations.length === 0" @click="importMember">批量导入</el-button>
|
|
|
- <el-button>变更部门</el-button>
|
|
|
- <el-button type="danger">操作离职</el-button>
|
|
|
+ <div
|
|
|
+ style="display: flex; flex-direction: row; align-items: center; justify-content: center; height: 100%">
|
|
|
+ <div v-if="currentOrg" style="flex: 1 1 auto">
|
|
|
+ <p> {{ currentOrg.name }}</p>
|
|
|
+ <p v-if="currentOrg.managerName" style="font-size: 12px"> {{
|
|
|
+ "部门负责人: " + currentOrg.managerName
|
|
|
+ }}</p>
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" icon="el-icon-plus" v-if="rootOrganizations.length > 0"
|
|
|
+ @click="showAddDepartmentMemberDialog = true">添加成员
|
|
|
+ </el-button>
|
|
|
+ <el-button type="primary" v-if="rootOrganizations.length === 0"
|
|
|
+ @click="importMember">批量导入
|
|
|
+ </el-button>
|
|
|
</div>
|
|
|
</el-header>
|
|
|
- <el-table
|
|
|
- ref="multipleTable"
|
|
|
- :data="currentOrgEmployees"
|
|
|
- empty-text="当前公司或部门没有直属员工"
|
|
|
- tooltip-effect="dark"
|
|
|
- style="width: 100%"
|
|
|
- :cell-style="{padding: '0', height: '50px'}"
|
|
|
- @selection-change="handleSelectionChange">
|
|
|
- <el-table-column
|
|
|
- type="selection"
|
|
|
- width="55">
|
|
|
+ <el-table ref="multipleTable" :data="currentOrgEmployees" empty-text="当前公司或部门没有直属员工" tooltip-effect="dark"
|
|
|
+ type="default" style="width: 100%" :cell-style="{ padding: '0', height: '50px' }">
|
|
|
+ <el-table-column type="default" width="55">
|
|
|
</el-table-column>
|
|
|
- <el-table-column
|
|
|
- prop="name"
|
|
|
- label="姓名"
|
|
|
- width="120">
|
|
|
- <!-- <template slot-scope="scope">{{ scope.row.date }}</template>-->
|
|
|
+ <el-table-column prop="name" label="姓名" width="120">
|
|
|
</el-table-column>
|
|
|
- <el-table-column
|
|
|
- prop="title"
|
|
|
- label="职位"
|
|
|
- width="120">
|
|
|
+ <el-table-column prop="title" label="职位" width="120">
|
|
|
</el-table-column>
|
|
|
- <el-table-column
|
|
|
- prop="mobile"
|
|
|
- label="手机号"
|
|
|
- show-overflow-tooltip>
|
|
|
+ <el-table-column prop="mobile" label="手机号" show-overflow-tooltip>
|
|
|
</el-table-column>
|
|
|
<el-table-column>
|
|
|
<template v-slot="scope">
|
|
|
- <el-button class="f-btn" @click="handleClickEmployee(scope.row)" type="text" size="small">查看详情</el-button>
|
|
|
- <el-button class="f-btn" @click="handleClickEmployee(scope.row)" type="text" size="small">变更部门</el-button>
|
|
|
- <el-button class="f-btn" @click="handleClickEmployee(scope.row)" type="text" size="small">操作离职</el-button>
|
|
|
+ <el-button v-if="false" class="f-btn" @click="handleClickEmployee(scope.row)" type="text"
|
|
|
+ size="small">查看详情
|
|
|
+ </el-button>
|
|
|
+ <el-button class="f-btn" @click="handleTransferDepartment(scope.row)" type="text"
|
|
|
+ size="small">变更部门
|
|
|
+ </el-button>
|
|
|
+ <el-button class="f-btn" @click="handleDeleteEmployee(scope.row)" type="text"
|
|
|
+ size="small">操作离职
|
|
|
+ </el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
</el-container>
|
|
|
- <el-drawer
|
|
|
- title="操作离职"
|
|
|
- :visible.sync="showDeleteEmployeeDrawer"
|
|
|
- direction="rtl"
|
|
|
- :before-close="onDeleteEmployee">
|
|
|
- <DeleteEmployee
|
|
|
- :employee="currentEmployee"
|
|
|
- :on-delete-employee="onDeleteEmployee"/>
|
|
|
+ <el-container v-else>
|
|
|
+ <el-header>
|
|
|
+ <div
|
|
|
+ style="display: flex; flex-direction: row; align-items: center; justify-content: center; height: 100%">
|
|
|
+ 请选择部门
|
|
|
+ </div>
|
|
|
+ </el-header>
|
|
|
+
|
|
|
+ </el-container>
|
|
|
+ <el-drawer title="操作离职" :visible.sync="showDeleteEmployeeDrawer" direction="rtl"
|
|
|
+ :before-close="onDeleteEmployee">
|
|
|
+ <DeleteEmployee :employee="currentEmployee" :on-delete-employee="onDeleteEmployee"/>
|
|
|
</el-drawer>
|
|
|
|
|
|
- <el-dialog :visible.sync="showUpdateDepartmentDialog" :before-close="() => this.showUpdateDepartmentDialog= false">
|
|
|
- <UpdateDepartment
|
|
|
- :managers="checkedMembers"
|
|
|
- :current-department="targetDepartment"
|
|
|
- :parent-department="targetDepartment"
|
|
|
- :on-update-department="onUpdateDepartment"
|
|
|
- :on-choose-member="() => {this.checkedMembers = []; this.showChooseMemberDialog = true}"
|
|
|
- :on-uncheck-member="onUncheckMember"
|
|
|
- />
|
|
|
- <el-dialog ref="dialog" :visible.sync="showChooseMemberDialog" append-to-body @hook:mounted="$refs.dialog.rendered = true">>
|
|
|
- <ChooseMember :initial-checked-members="initialCheckedMembers" :max-choose-count="1" :on-cancel="()=> this.showChooseMemberDialog = false" :on-confirm="onCheckMember"/>
|
|
|
- </el-dialog>
|
|
|
+ <el-dialog :visible.sync="showUpdateDepartmentDialog"
|
|
|
+ destroy-on-close
|
|
|
+ :before-close="() => this.showUpdateDepartmentDialog = false">
|
|
|
+ <UpdateDepartment :current-department="targetDepartment" :on-update-department="onUpdateDepartment"/>
|
|
|
</el-dialog>
|
|
|
|
|
|
- <el-dialog :visible.sync="showAddSubDepartmentDialog" :before-close="() => this.showAddSubDepartmentDialog = false">
|
|
|
- <AddSubDepartment
|
|
|
- :managers="checkedMembers"
|
|
|
- :parent-department="currentOrg"
|
|
|
- :on-add-department="onAddDepartment"
|
|
|
- :on-choose-member="() => this.showChooseMemberDialog = true"
|
|
|
- :on-uncheck-member="onUncheckMember"
|
|
|
- />
|
|
|
- <el-dialog ref="dialog" :visible.sync="showChooseMemberDialog" append-to-body @hook:mounted="$refs.dialog.rendered = true">>
|
|
|
- <ChooseMember :initial-checked-members="initialCheckedMembers" :max-choose-count="1" :on-cancel="()=> this.showChooseMemberDialog = false" :on-confirm="onCheckMember"/>
|
|
|
- </el-dialog>
|
|
|
+ <el-dialog :visible.sync="showAddSubDepartmentDialog"
|
|
|
+ destroy-on-close
|
|
|
+ :before-close="() => this.showAddSubDepartmentDialog = false">
|
|
|
+ <AddSubDepartment :parent-department="currentOrg" :on-add-department="onAddDepartment"/>
|
|
|
</el-dialog>
|
|
|
- <el-dialog
|
|
|
- :visible.sync="showAddDepartmentMemberDialog"
|
|
|
- :close-on-click-modal="false"
|
|
|
- :before-close="() => {this.showAddDepartmentMemberDialog = false; this.checkedDepartments =[]}">
|
|
|
- <AddDepartmentMember
|
|
|
- :checked-departments="checkedDepartments"
|
|
|
- :on-cancel="()=> this.showAddDepartmentMemberDialog = false"
|
|
|
- :on-choose-department="() => this.showChooseDepartmentDialog = true"
|
|
|
- :on-uncheck-department="onUncheckDepartment"
|
|
|
- />
|
|
|
+
|
|
|
+ <el-dialog :visible.sync="showAddDepartmentMemberDialog" :close-on-click-modal="false"
|
|
|
+ destroy-on-close
|
|
|
+ :before-close="() => { this.showAddDepartmentMemberDialog = false; this.checkedDepartments = [] }">
|
|
|
+ <AddDepartmentMember :checked-departments="checkedDepartments"
|
|
|
+ :on-cancel="() => this.showAddDepartmentMemberDialog = false"
|
|
|
+ :on-choose-department="() => this.showChooseDepartmentDialog = true"
|
|
|
+ :on-uncheck-department="onUncheckDepartment"/>
|
|
|
<el-dialog :visible.sync="showChooseDepartmentDialog" append-to-body>
|
|
|
- <ChooseDepartment :target-department="currentOrg" :on-cancel="()=> this.showChooseDepartmentDialog = false" :on-confirm="onCheckDepartment"/>
|
|
|
+ <ChooseDepartment :target-department="currentOrg"
|
|
|
+ :on-cancel="() => this.showChooseDepartmentDialog = false" :on-confirm="onCheckDepartment"/>
|
|
|
+ </el-dialog>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <el-dialog title="变更部门" :visible.sync="showTransferDepartmentDialog" :close-on-click-modal="false"
|
|
|
+ :before-close="() => { this.showTransferDepartmentDialog = false; this.transferDepartments = [] }">
|
|
|
+ <div v-if="employeeToTransfer">
|
|
|
+ <p>将 <b>{{ employeeToTransfer.name }}</b> 变更至:</p>
|
|
|
+ <el-input disabled style="margin: 20px 0;">
|
|
|
+ <div v-if="transferDepartments && transferDepartments.length" slot="prepend">
|
|
|
+ <el-tag v-for="(depart, index) in transferDepartments" :key="index" closable
|
|
|
+ @close="onUncheckTransferDepartment(depart)" type="info">
|
|
|
+ {{ depart && depart.name }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ <el-button slot="append" type="text" icon="el-icon-edit"
|
|
|
+ @click="showTransferChooseDepartmentDialog = true"></el-button>
|
|
|
+ </el-input>
|
|
|
+ <div style="text-align: right; margin-top: 20px;">
|
|
|
+ <el-button @click="showTransferDepartmentDialog = false">取消</el-button>
|
|
|
+ <el-button type="primary" :disabled="transferDepartments.length === 0"
|
|
|
+ @click="confirmTransferDepartment">确定
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-dialog :visible.sync="showTransferChooseDepartmentDialog" append-to-body>
|
|
|
+ <ChooseDepartment :on-cancel="() => this.showTransferChooseDepartmentDialog = false"
|
|
|
+ :on-confirm="onCheckTransferDepartment"/>
|
|
|
</el-dialog>
|
|
|
</el-dialog>
|
|
|
</el-container>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-
|
|
|
-import {mapState} from "vuex";
|
|
|
+import {useOrgStore} from "@/store/stores/orgStore";
|
|
|
import AddSubDepartment from "@/components/page/organization/dialog/AddSubDepartment";
|
|
|
import AddDepartmentMember from "@/components/page/organization/dialog/AddDepartmentMember";
|
|
|
import ChooseDepartment from "@/components/page/organization/dialog/ChooseDepartment";
|
|
|
-import ChooseMember from "@/components/page/organization/dialog/ChooseMember";
|
|
|
import DeleteEmployee from "@/components/page/organization/drawer/DeleteEmployee";
|
|
|
import UpdateDepartment from "@/components/page/organization/dialog/UpdateDepartment.vue";
|
|
|
-import fa from "element-ui/src/locale/lang/fa";
|
|
|
import api from "@/api/api";
|
|
|
|
|
|
export default {
|
|
|
name: "Member",
|
|
|
- components: {UpdateDepartment, DeleteEmployee, AddDepartmentMember, AddSubDepartment, ChooseDepartment, ChooseMember},
|
|
|
+ components: {UpdateDepartment, DeleteEmployee, AddDepartmentMember, AddSubDepartment, ChooseDepartment},
|
|
|
data() {
|
|
|
return {
|
|
|
defaultProps: {
|
|
@@ -158,9 +164,7 @@ export default {
|
|
|
multipleSelection: [],
|
|
|
|
|
|
showDeleteEmployeeDrawer: false,
|
|
|
-
|
|
|
showUpdateDepartmentDialog: false,
|
|
|
-
|
|
|
showAddSubDepartmentDialog: false,
|
|
|
showAddDepartmentMemberDialog: false,
|
|
|
|
|
@@ -172,18 +176,16 @@ export default {
|
|
|
showChooseDepartmentDialog: false,
|
|
|
checkedDepartments: [],
|
|
|
|
|
|
- showChooseMemberDialog: false,
|
|
|
- checkedMembers: [],
|
|
|
-
|
|
|
+ showTransferDepartmentDialog: false,
|
|
|
+ showTransferChooseDepartmentDialog: false,
|
|
|
+ employeeToTransfer: null,
|
|
|
+ transferDepartments: [],
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
- initialCheckedMembers() {
|
|
|
- return this.checkedMembers.map(m => m.employeeId);
|
|
|
- },
|
|
|
- ...mapState({
|
|
|
- rootOrganizations: state => state.org.rootOrganizations,
|
|
|
- })
|
|
|
+ rootOrganizations() {
|
|
|
+ return this.orgStore.rootOrganizations;
|
|
|
+ }
|
|
|
},
|
|
|
watch: {
|
|
|
'currentOrg': {
|
|
@@ -202,9 +204,14 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ setup() {
|
|
|
+ const orgStore = useOrgStore();
|
|
|
+ return {orgStore};
|
|
|
+ },
|
|
|
+
|
|
|
activated() {
|
|
|
if (this.rootOrganizations.length === 0) {
|
|
|
- this.$store.dispatch('getRootOrganizationsWithChildren')
|
|
|
+ this.orgStore.getRootOrganizationsWithChildren()
|
|
|
.then(() => {
|
|
|
this.currentOrg = this.rootOrganizations[0];
|
|
|
})
|
|
@@ -218,21 +225,18 @@ export default {
|
|
|
handleNodeClick(data) {
|
|
|
console.log('node click', data)
|
|
|
if (!data._orgWithChildren && data.id) {
|
|
|
- this.$store.dispatch('queryOrganizationWithChildren', data)
|
|
|
+ this.orgStore.queryOrganizationWithChildren(data)
|
|
|
}
|
|
|
this.currentOrg = data;
|
|
|
},
|
|
|
async handleNodeExpand(data) {
|
|
|
console.log('node expand', data);
|
|
|
- // if (!data._orgWithChildren && data.id) {
|
|
|
- // await this.$store.dispatch('queryOrganizationWithChildren', data)
|
|
|
- // }
|
|
|
},
|
|
|
async loadNode(node, resolve) {
|
|
|
console.log('to load data', node)
|
|
|
let data = node.data;
|
|
|
if ((!data._orgWithChildren && data.id) || data._force) {
|
|
|
- await this.$store.dispatch('queryOrganizationWithChildren', data)
|
|
|
+ await this.orgStore.queryOrganizationWithChildren(data)
|
|
|
console.log('load data', data);
|
|
|
this.currentOrg = data;
|
|
|
resolve(data.children);
|
|
@@ -244,22 +248,40 @@ export default {
|
|
|
this.multipleSelection = val;
|
|
|
},
|
|
|
handleClickEmployee(data) {
|
|
|
- // employee
|
|
|
console.log('click employee', data)
|
|
|
+ },
|
|
|
+ handleDeleteEmployee(data) {
|
|
|
this.showDeleteEmployeeDrawer = true;
|
|
|
this.currentEmployee = data;
|
|
|
- // this.$router.push('/organization/departmentanduser/department')
|
|
|
+ },
|
|
|
+ handleTransferDepartment(data) {
|
|
|
+ this.employeeToTransfer = data;
|
|
|
+ this.transferDepartments = [];
|
|
|
+ this.showTransferDepartmentDialog = true;
|
|
|
+ },
|
|
|
+ onCheckTransferDepartment(departments) {
|
|
|
+ this.transferDepartments = departments;
|
|
|
+ this.showTransferChooseDepartmentDialog = false;
|
|
|
+ },
|
|
|
+ onUncheckTransferDepartment(department) {
|
|
|
+ this.transferDepartments = this.transferDepartments.filter(d => d.id !== department.id);
|
|
|
+ },
|
|
|
+ confirmTransferDepartment() {
|
|
|
+ if (this.employeeToTransfer && this.transferDepartments.length > 0) {
|
|
|
+ let targetOrgIds = this.transferDepartments.map(d => d.id);
|
|
|
+ this.orgStore.transferEmployee(this.employeeToTransfer.employeeId, targetOrgIds)
|
|
|
+ }
|
|
|
+ this.showTransferDepartmentDialog = false
|
|
|
+ this.currentOrg = null;
|
|
|
},
|
|
|
importMember() {
|
|
|
this.$router.push('/organization/departmentanduser/import-member')
|
|
|
},
|
|
|
-
|
|
|
handleDepartmentCommand(command) {
|
|
|
console.log('handleDepartmentCommand', command)
|
|
|
switch (command.c) {
|
|
|
case "add-sub":
|
|
|
this.showAddSubDepartmentDialog = true;
|
|
|
- this.targetParentDepartment = command.depart;
|
|
|
this.targetParentNode = command.node;
|
|
|
break;
|
|
|
case "edit":
|
|
@@ -268,7 +290,7 @@ export default {
|
|
|
this.targetNode = command.node;
|
|
|
break;
|
|
|
case "remove":
|
|
|
- this.$store.dispatch('removeOrganization', {organization: command.depart, dismissGroup: true})
|
|
|
+ this.orgStore.removeOrganization({organization: command.depart, dismissGroup: true})
|
|
|
.then(() => {
|
|
|
let parentNode = command.node.parent;
|
|
|
this.updateTreeNode(parentNode);
|
|
@@ -285,24 +307,15 @@ export default {
|
|
|
this.checkedDepartments = departments;
|
|
|
this.showChooseDepartmentDialog = false;
|
|
|
},
|
|
|
- onCheckMember(members) {
|
|
|
- this.showChooseMemberDialog = false;
|
|
|
- this.checkedMembers = members;
|
|
|
- },
|
|
|
- onUncheckMember(member) {
|
|
|
- this.checkedMembers = this.checkedMembers.filter(m => m.employeeId !== member.employeeId);
|
|
|
- },
|
|
|
onUncheckDepartment(department) {
|
|
|
this.checkedDepartments = this.checkedDepartments.filter(d => d.id !== department.id);
|
|
|
},
|
|
|
-
|
|
|
onUpdateDepartment(success) {
|
|
|
if (success) {
|
|
|
this.updateTreeNode(this.targetNode);
|
|
|
}
|
|
|
this.showUpdateDepartmentDialog = false;
|
|
|
},
|
|
|
-
|
|
|
onAddDepartment(success) {
|
|
|
if (success) {
|
|
|
this.updateTreeNode(this.targetParentNode);
|
|
@@ -310,16 +323,12 @@ export default {
|
|
|
}
|
|
|
this.showAddSubDepartmentDialog = false;
|
|
|
},
|
|
|
-
|
|
|
onDeleteEmployee(success) {
|
|
|
this.showDeleteEmployeeDrawer = false;
|
|
|
if (success) {
|
|
|
- this.$store.dispatch('queryOrganizationWithChildren', this.currentOrg);
|
|
|
+ this.orgStore.queryOrganizationWithChildren(this.currentOrg);
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
- // el-tree 绑定的数据更新之后,并不会自动更新,故采用这种方案
|
|
|
- // fyi: https://zhuanlan.zhihu.com/p/370597632
|
|
|
updateTreeNode(node) {
|
|
|
node.loaded = false;
|
|
|
node.data._force = true;
|
|
@@ -330,7 +339,6 @@ export default {
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-
|
|
|
.custom-tree-node {
|
|
|
flex: 1 1 auto;
|
|
|
display: flex;
|