channel.vue 17 KB

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