team.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. <template>
  2. <div class="team">
  3. <el-row :gutter="20" style="width: 100%; overflow:hidden;">
  4. <el-col :span="4">
  5. <div class="teamTree">
  6. <el-input class="search-input" v-model="treeValue" placeholder="团队名称查找" prefix-icon="Search"
  7. @keyup.enter="initTeam"></el-input>
  8. <div class="custom-tree-node" v-for="item in teamData" :key="item.id" @click.stop="initList(item)">
  9. <span class="custom-tree-node-label">{{ item.name }}</span>
  10. <el-dropdown class="custom-tree-node-more" @command="treeNodeCommend(item, $event)">
  11. <el-icon>
  12. <MoreFilled />
  13. </el-icon>
  14. <template #dropdown>
  15. <el-dropdown-menu>
  16. <el-dropdown-item command="编辑">编辑</el-dropdown-item>
  17. <el-dropdown-item command="删除">删除</el-dropdown-item>
  18. </el-dropdown-menu>
  19. </template>
  20. </el-dropdown>
  21. </div>
  22. </div>
  23. <el-button class="add-btn" icon="plus" @click="addTeamDraw">添加团队</el-button>
  24. </el-col>
  25. <el-col :span="20">
  26. <el-row :gutter="20">
  27. <el-col :span="22" class="info">
  28. <h3>{{ teamInfo.name }}</h3>
  29. <p>所属机构: {{ teamInfo?.deptName }}</p>
  30. <p>管理人: {{ teamInfo?.managerName ? `${teamInfo?.managerName}-` : '' }}{{ teamInfo?.managerId }}</p>
  31. <p>描述:{{ teamInfo?.describeInformation }}</p>
  32. </el-col>
  33. <el-col :span="2" class="btn">
  34. <el-button plain @click="setPeople">设置负责人</el-button>
  35. </el-col>
  36. </el-row>
  37. <el-input style="width: 300px; margin: 10px 0" v-model="searchValue" prefix-icon="Search"
  38. placeholder="输入姓名,手机号,工号查找" clearable @keyup.enter="initList(teamInfo)"></el-input>
  39. <el-table :data="tableData" ref="operationListRef" height="530" @selection-change="handleSelectionChange">
  40. <el-table-column type="selection" width="55"></el-table-column>
  41. <el-table-column label="姓名" prop="name" width="80">
  42. <template #default="scope">
  43. <div class="nameInfo">{{ scope.row.name }}<span v-show="scope.row.manager === '1'">负责人</span></div>
  44. </template>
  45. </el-table-column>
  46. <el-table-column label="手机号" prop="mobile" width="150"></el-table-column>
  47. <el-table-column label="工号" prop="workNumber" width="200"></el-table-column>
  48. <el-table-column label="类型" prop="typeAttr" width="100">
  49. <template #default="scope">
  50. {{ typeAttrMap(scope.row.typeAttr) }}
  51. </template>
  52. </el-table-column>
  53. <el-table-column label="归属" prop="organizationName" width="200"></el-table-column>
  54. <el-table-column label="所属机构" prop="deptName" width="200"></el-table-column>
  55. <el-table-column label="人员状态" prop="status" width="150">
  56. <template #default="scope">
  57. {{ statusMap(scope.row.status) }}
  58. </template>
  59. </el-table-column>
  60. <el-table-column label="账号状态" prop="isEnable" width="150">
  61. <template #default="scope">
  62. {{ scope.row.isEnable == '1' ? '禁用' : scope.row.isEnable == '0' ? '启用' : '--' }}
  63. </template>
  64. </el-table-column>
  65. <el-table-column label="管理人" prop="leaderName" width="150"></el-table-column>
  66. <el-table-column label="管理人工号" prop="leaderId" width="200"></el-table-column>
  67. <el-table-column label="推荐人" prop="referrerName" width="150"></el-table-column>
  68. <el-table-column label="推荐人工号" prop="referrerId" width="200"></el-table-column>
  69. <el-table-column fixed="right" label="操作" width="120">
  70. <template #default="scope">
  71. <div style="display: flex; align-items: center; justify-content: space-between">
  72. <a style="color: #409EFF; cursor: pointer" @click="showDetail(scope)">详情</a>&nbsp;
  73. <el-dropdown placement="bottom" trigger="click" @command="tableDataCommand(scope, $event)">
  74. <a style="color: #409EFF; cursor: pointer">更多</a>
  75. <template #dropdown>
  76. <el-dropdown-menu>
  77. <el-dropdown-item command="编辑">编辑</el-dropdown-item>
  78. <el-dropdown-item command="启用">启用</el-dropdown-item>
  79. <el-dropdown-item command="禁用">禁用</el-dropdown-item>
  80. <el-dropdown-item command="删除">删除</el-dropdown-item>
  81. <el-dropdown-item command="分配管理人">分配管理人</el-dropdown-item>
  82. </el-dropdown-menu>
  83. </template>
  84. </el-dropdown>
  85. </div>
  86. </template>
  87. </el-table-column>
  88. </el-table>
  89. <div style="display: flex; justify-content: center; margin-top: 15px">
  90. <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[10, 20, 30, 40]"
  91. layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"
  92. @current-change="handleCurrentChange" />
  93. </div>
  94. </el-col>
  95. </el-row>
  96. <el-dialog v-model="dialogShow" :title="title" width="1000">
  97. <addOperation ref="AddOperationRef" @closeDialog="closeAddOperation"></addOperation>
  98. </el-dialog>
  99. <el-dialog v-model="addTeamShow" title="添加" width="800">
  100. <addTeam ref="AddTeamRef" @closeDialog="closeAddTeamDialog"></addTeam>
  101. </el-dialog>
  102. <el-dialog v-model="allocationShow" title="分配管理人" width="800">
  103. <allocation ref="AllocationRef" @closeDialog="closeAllocation"></allocation>
  104. </el-dialog>
  105. <el-dialog v-model="peopleShow" title="设置负责人" width="800">
  106. <el-row :gutter="20">
  107. <el-col :span="12">
  108. <el-tree ref="treeRef" :data="options" :props="cascaderProps" @node-click="handleNodeClick" />
  109. </el-col>
  110. <el-col :span="12">
  111. <el-radio-group v-if="tableData?.length > 0" v-model="radioValue" class="allocation-radio">
  112. <el-radio v-for="item in tableData" :value="item.id" size="large">
  113. <template #default>
  114. <div>{{ item.name }}</div>
  115. <div>{{ item.id }}</div>
  116. </template>
  117. </el-radio>
  118. </el-radio-group>
  119. <el-empty v-else description="暂无数据" />
  120. </el-col>
  121. </el-row>
  122. <template #footer>
  123. <el-button @click="onCancel">取消</el-button>
  124. <el-button type="primary" @click="onConfirm">确定</el-button>
  125. </template>
  126. </el-dialog>
  127. </div>
  128. </template>
  129. <script setup lang="ts">
  130. import { ElMessageBox, ElMessage, TableInstance } from 'element-plus'
  131. import { useRouter } from 'vue-router'
  132. import api from "@/api";
  133. import addOperation from './modules/addOperation.vue'
  134. import allocation from './modules/allocation.vue'
  135. import addTeam from './modules/addTeam.vue'
  136. import { initial } from "lodash-es";
  137. import team from "@/api/modules/team.ts";
  138. let myRouter = useRouter()
  139. const AddTeamRef = ref(null)
  140. const AddOperationRef = ref(null)
  141. const AllocationRef = ref(null)
  142. // 机构数据
  143. const cascaderProps = {
  144. value: 'id',
  145. label: 'name',
  146. children: 'children'
  147. }
  148. let options = ref([])
  149. // 获取机构数据
  150. const institutionList = () => {
  151. api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
  152. if (res?.code == 200) {
  153. options.value = res.data
  154. } else {
  155. ElMessage({
  156. message: res.msg,
  157. type: 'warning'
  158. })
  159. }
  160. })
  161. }
  162. const handleNodeClick = (data) => {
  163. initList(teamData.value[0])
  164. }
  165. const statusMap = (value: any) => {
  166. const map = {
  167. "0": '未认证',
  168. "1": '认证中',
  169. "2": '认证失败',
  170. "3": '待入职',
  171. "4": '入司审核中',
  172. "5": '入司审核失败',
  173. "6": '已入职',
  174. "7": '离职待审核',
  175. "8": '离职',
  176. }
  177. return map[value]
  178. }
  179. const typeAttrMap=(value)=>{
  180. const map = {
  181. "1": '前线人员',
  182. "2": '后线人员',
  183. "3": '合伙人',
  184. "4": '工作是管理员',
  185. "5": '团队',
  186. "6": '个代',
  187. "7": '渠道',
  188. "8": '电销',
  189. }
  190. return map[value]
  191. }
  192. // 团队
  193. let treeValue = ref('')
  194. let teamData = ref([])
  195. let addTeamShow = ref(false)
  196. const initTeam = () => {
  197. api.teamApi.teamList({
  198. param: treeValue.value,
  199. attribute: 1
  200. }).then(res => {
  201. if (res.code == 200) {
  202. teamData.value = res.data
  203. if (teamData.value) {
  204. initList(teamData.value[0])
  205. }
  206. } else {
  207. ElMessage({
  208. message: res.msg,
  209. type: 'warning'
  210. })
  211. }
  212. })
  213. }
  214. // 分页
  215. let currentPage = ref(1)
  216. let pageSize = ref(10)
  217. let total = ref(0)
  218. const handleSizeChange = (size) => {
  219. pageSize.value = size
  220. initTeam()
  221. }
  222. const handleCurrentChange = (page) => {
  223. currentPage.value = page
  224. initTeam()
  225. }
  226. // 初始化列表
  227. let teamInfo = ref({
  228. name: '',
  229. deptName: '',
  230. managerName: '',
  231. managerId: '',
  232. describeInformation: ''
  233. })
  234. const initList = (item) => {
  235. teamInfo.value = item
  236. api.teamApi.getTeamUser({
  237. id: item.id,
  238. name: searchValue.value,
  239. pages: currentPage.value,
  240. size: pageSize.value
  241. }).then(res => {
  242. if (res.code == 200) {
  243. tableData.value = res.data.records
  244. total.value = res.data.total
  245. } else {
  246. ElMessage({
  247. message: res.msg,
  248. type: 'warning'
  249. })
  250. }
  251. })
  252. }
  253. const treeNodeCommend = (item, e) => {
  254. switch (e) {
  255. case '编辑':
  256. addTeamShow.value = true
  257. nextTick(() => {
  258. AddTeamRef.value.initEdit(item, true, 1)
  259. })
  260. break;
  261. case '删除':
  262. ElMessageBox({
  263. title: '删除团队',
  264. message: '确定要删除该团队吗?',
  265. type: 'warning',
  266. showCancelButton: true,
  267. confirmButtonText: '确定',
  268. cancelButtonText: '取消',
  269. }).then((action) => {
  270. if (action === 'confirm') {
  271. api.teamApi.deleteById(item.id).then(res => {
  272. if (res.code == 200) {
  273. ElMessage({
  274. message: res.msg,
  275. type: 'success'
  276. })
  277. initTeam()
  278. } else {
  279. ElMessage({
  280. message: res.msg,
  281. type: 'warning'
  282. })
  283. }
  284. })
  285. }
  286. }).catch((action) => {
  287. })
  288. break;
  289. }
  290. }
  291. const addTeamDraw = () => {
  292. addTeamShow.value = true
  293. nextTick(() => {
  294. AddTeamRef.value.teamForm.attribute = 1
  295. })
  296. }
  297. const closeAddTeamDialog = (type) => {
  298. addTeamShow.value = false
  299. initTeam()
  300. }
  301. // 搜索字段
  302. let searchValue = ref('')
  303. // 列表数据
  304. let tableData = ref([])
  305. // 编辑弹框
  306. let dialogShow = ref(false)
  307. // 编辑弹框标题
  308. let title = ref('编辑')
  309. // 表格组件中的勾选
  310. const handleSelectionChange = (row) => {
  311. }
  312. // 详情
  313. const showDetail = (scope) => {
  314. myRouter.push({
  315. path: '/operationDetail',
  316. query: {
  317. id: scope.row.userId
  318. }
  319. })
  320. }
  321. // 分配管理人
  322. let allocationShow = ref(false)
  323. // 设置负责人
  324. let peopleShow = ref(false)
  325. let radioValue = ref('')
  326. const setPeople = () => {
  327. peopleShow.value = true
  328. // pageSize.value = 99999
  329. initList(teamInfo.value)
  330. }
  331. const onCancel = () => {
  332. peopleShow.value = false
  333. radioValue.value = ''
  334. }
  335. const onConfirm = () => {
  336. if (!radioValue.value) {
  337. ElMessage({
  338. message: '请选择负责人',
  339. type: 'warning'
  340. })
  341. return
  342. }
  343. api.teamApi.setResponsiblePerson({
  344. id: teamInfo.value.id,
  345. managerId: radioValue.value
  346. }).then(res => {
  347. if (res.code == 200) {
  348. ElMessage({
  349. message: res.msg,
  350. type: 'success'
  351. })
  352. initList(teamInfo.value)
  353. } else {
  354. ElMessage({
  355. message: res.msg,
  356. type: 'warning'
  357. })
  358. }
  359. peopleShow.value = false
  360. })
  361. }
  362. // 关闭设置负责人
  363. const closeAllocation = (type: boolean) => {
  364. allocationShow.value = type
  365. }
  366. // 更多
  367. const tableDataCommand = (scope, e) => {
  368. switch (e) {
  369. case '编辑':
  370. dialogShow.value = true
  371. nextTick(() => {
  372. AddOperationRef.value.initEditData(scope.row.userId, scope.row.id)
  373. })
  374. title.value = '编辑'
  375. break;
  376. case '删除':
  377. ElMessageBox({
  378. title: '删除业务员',
  379. message: '确定要删除该业务员吗?',
  380. type: 'warning',
  381. showCancelButton: true,
  382. confirmButtonText: '确定',
  383. cancelButtonText: '取消',
  384. }).then((action) => {
  385. if (action === 'confirm') {
  386. api.teamApi.deleteAssociatedUsers({
  387. id: teamInfo.value.id,
  388. userIds: [scope.row.userId]
  389. }).then(res => {
  390. if (res?.code == 200) {
  391. ElMessage({
  392. message: res.msg,
  393. type: 'success'
  394. })
  395. initList(teamInfo.value)
  396. } else {
  397. ElMessage({
  398. message: res.msg,
  399. type: 'warning'
  400. })
  401. }
  402. })
  403. }
  404. }).catch((action) => {
  405. })
  406. break;
  407. case '禁用':
  408. ElMessageBox({
  409. title: '禁用业务员',
  410. message: '确定要禁用该业务员吗?',
  411. type: 'warning',
  412. showCancelButton: true,
  413. confirmButtonText: '确定',
  414. cancelButtonText: '取消',
  415. }).then((action) => {
  416. if (action === 'confirm') {
  417. let data = {
  418. ids: [scope.row.id],
  419. isEnable: 1,
  420. getAll: 0
  421. }
  422. api.operationApi.operationIsEnable(data).then(res => {
  423. if (res?.code == 200) {
  424. ElMessage({
  425. message: res.msg,
  426. type: 'success'
  427. })
  428. initList(teamInfo.value)
  429. } else {
  430. ElMessage({
  431. message: res.msg,
  432. type: 'warning'
  433. })
  434. }
  435. })
  436. }
  437. }).catch((action) => {
  438. })
  439. break;
  440. case '启用':
  441. ElMessageBox({
  442. title: '启用业务员',
  443. message: '确定要启用该业务员吗?',
  444. type: 'warning',
  445. showCancelButton: true,
  446. confirmButtonText: '确定',
  447. cancelButtonText: '取消',
  448. }).then((action) => {
  449. if (action === 'confirm') {
  450. let data = {
  451. ids: [scope.row.id],
  452. isEnable: 0,
  453. getAll: 0
  454. }
  455. api.operationApi.operationIsEnable(data).then(res => {
  456. if (res?.code == 200) {
  457. ElMessage({
  458. message: res.msg,
  459. type: 'success'
  460. })
  461. initList(teamInfo.value)
  462. } else {
  463. ElMessage({
  464. message: res.msg,
  465. type: 'warning'
  466. })
  467. }
  468. })
  469. }
  470. }).catch((action) => {
  471. })
  472. break;
  473. case '分配管理人':
  474. allocationShow.value = true
  475. nextTick(() => {
  476. AllocationRef.value.initCheckedKeys(scope.row.deptId, null, [scope.row.id], scope.row.leaderId)
  477. })
  478. break;
  479. }
  480. }
  481. const closeAddOperation = (type: string) => {
  482. dialogShow.value = false;
  483. initList(teamInfo.value)
  484. }
  485. onMounted(() => {
  486. institutionList()
  487. initTeam()
  488. })
  489. </script>
  490. <style scoped lang="scss">
  491. .team {
  492. height: 770px;
  493. background: #fff;
  494. .search-input {
  495. padding: 10px 20px;
  496. }
  497. .teamTree {
  498. height: 700px;
  499. overflow-y: auto;
  500. background: #fff;
  501. .custom-tree-node {
  502. width: calc(100% - 40px);
  503. display: flex;
  504. justify-content: space-between;
  505. align-items: center;
  506. padding: 5px 10px;
  507. margin: 5px auto;
  508. cursor: pointer;
  509. &:hover {
  510. background: rgba(0, 0, 0, .1);
  511. }
  512. .custom-tree-node-label {
  513. width: 70%;
  514. overflow: hidden;
  515. white-space: nowrap;
  516. text-overflow: ellipsis;
  517. }
  518. }
  519. }
  520. .add-btn {
  521. display: block;
  522. margin: 0 auto;
  523. }
  524. .info {
  525. h3 {
  526. margin: 10px 0;
  527. }
  528. p {
  529. margin: 6px 0;
  530. font-size: 14px;
  531. color: rgba(0, 0, 0, .7);
  532. }
  533. }
  534. .btn {
  535. display: flex;
  536. justify-content: flex-end;
  537. align-items: flex-end;
  538. }
  539. .nameInfo {
  540. display: flex;
  541. justify-content: center;
  542. align-content: center;
  543. span {
  544. background: #f0f0f0;
  545. padding: 2px 4px;
  546. border-radius: 2px;
  547. }
  548. }
  549. }
  550. </style>