index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. <template>
  2. <!--后续加按钮 生成订单 为0时才显示 hasGeneratedOrder:0,-->
  3. <div class="ele-body">
  4. <el-card shadow="never" v-loading="loading">
  5. <div class="switch">
  6. <div class="switch_left">
  7. <ul>
  8. <li
  9. v-for="item in tabOptions"
  10. :key="item.key"
  11. :class="{ active: activeComp == item.key }"
  12. @click="activeComp = item.key"
  13. >
  14. {{ item.name }}
  15. </li>
  16. </ul>
  17. </div>
  18. </div>
  19. <ele-split-layout
  20. width="210px"
  21. allow-collapse
  22. :right-style="{ overflow: 'hidden' }"
  23. v-if="activeComp == 'myContact'"
  24. >
  25. <div>
  26. <div
  27. class="ele-border-lighter sys-organization-list"
  28. style="margin-left: 10px"
  29. >
  30. <AssetTree
  31. @handleNodeClick="handleNodeClick"
  32. :defaultExpandedKeys="defaultExpandedKeys"
  33. :defaultExpandAll="false"
  34. id="17"
  35. :isFirstRefreshTable="false"
  36. ref="treeList"
  37. />
  38. </div>
  39. </div>
  40. <template v-slot:content>
  41. <div
  42. class="ele-border-lighter form-content"
  43. v-loading="loading"
  44. style="margin-right: 10px"
  45. >
  46. <contact-search @search="reload"> </contact-search>
  47. <!-- 数据表格 -->
  48. <ele-pro-table
  49. ref="table"
  50. :columns="columns"
  51. :datasource="datasource"
  52. height="calc(100vh - 365px)"
  53. style="margin-bottom: 15px"
  54. full-height="calc(100vh - 116px)"
  55. tool-class="ele-toolbar-form"
  56. :selection.sync="selection"
  57. @columns-change="handleColumnChange"
  58. :cache-key="cacheKeyUrl"
  59. :page-size="20"
  60. >
  61. <!-- 表头工具栏 -->
  62. <template v-slot:toolbar>
  63. <!-- <el-button
  64. size="small"
  65. type="primary"
  66. icon="el-icon-plus"
  67. class="ele-btn-icon"
  68. @click="openEdit('新建', {})"
  69. >
  70. 新建
  71. </el-button> -->
  72. <el-button
  73. size="small"
  74. type="danger"
  75. el-icon-delete
  76. class="ele-btn-icon"
  77. @click="allDelBtn"
  78. :disabled="selection?.length === 0"
  79. >
  80. 批量删除
  81. </el-button>
  82. <el-button
  83. v-if="$hasPermission('eom:contact:push')"
  84. size="small"
  85. type="primary"
  86. class="ele-btn-icon"
  87. @click="allPushBtn"
  88. :disabled="selection?.length === 0"
  89. >
  90. 批量推送
  91. </el-button>
  92. </template>
  93. <template v-slot:name="{ row }">
  94. <el-link
  95. type="primary"
  96. :underline="false"
  97. @click="openDetail(row)"
  98. >
  99. {{ row.name }}</el-link
  100. >
  101. </template>
  102. <template v-slot:qrCode="{ row }">
  103. <el-link
  104. type="primary"
  105. :underline="false"
  106. @click="setCode(row)"
  107. >
  108. 二维码</el-link
  109. >
  110. </template>
  111. <template v-slot:enterpriseScale="{ row }">
  112. {{ getDictValue('企业规模', row.enterpriseScale) }}
  113. </template>
  114. <template v-slot:enterpriseHonor="{ row }">
  115. {{ getDictValue('企业荣誉', row.enterpriseHonor) }}
  116. </template>
  117. <template v-slot:taxpayerQualification="{ row }">
  118. {{ getDictValue('纳税人资质', row.taxpayerQualification) }}
  119. </template>
  120. <!-- 操作列 -->
  121. <template v-slot:action="{ row }">
  122. <el-link
  123. type="primary"
  124. :underline="false"
  125. icon="el-icon-plus"
  126. @click="addOppo('add', row)"
  127. >
  128. 生成商机
  129. </el-link>
  130. <el-link
  131. type="primary"
  132. :underline="false"
  133. icon="el-icon-plus"
  134. @click="addFollowDialog(row)"
  135. >
  136. 跟进
  137. </el-link>
  138. <el-link
  139. type="primary"
  140. :underline="false"
  141. icon="el-icon-edit"
  142. @click="openEdit('编辑', row)"
  143. >
  144. 修改
  145. </el-link>
  146. <el-link
  147. v-if="row.status != 1"
  148. type="primary"
  149. :underline="false"
  150. icon="el-icon-check"
  151. @click="enableOption(row)"
  152. >
  153. 启用
  154. </el-link>
  155. <el-link
  156. v-if="row.status === 1"
  157. type="primary"
  158. :underline="false"
  159. icon="el-icon-close"
  160. @click="disableOption(row)"
  161. >
  162. 禁用
  163. </el-link>
  164. <el-popconfirm
  165. class="ele-action"
  166. title="确定要删除此信息吗?"
  167. @confirm="remove(row)"
  168. >
  169. <template v-slot:reference>
  170. <el-link
  171. type="danger"
  172. :underline="false"
  173. icon="el-icon-delete"
  174. >
  175. 删除
  176. </el-link>
  177. </template>
  178. </el-popconfirm>
  179. </template>
  180. </ele-pro-table>
  181. </div>
  182. </template>
  183. </ele-split-layout>
  184. <contactList
  185. v-if="
  186. activeComp == 'contactList' && $hasPermission('eom:contact:staff')
  187. "
  188. ></contactList>
  189. <contactListAdmin
  190. v-else-if="activeComp == 'contactList'"
  191. ></contactListAdmin>
  192. </el-card>
  193. <AddContactDialog
  194. ref="addContactDialogRef"
  195. :categoryTreeList="treeList"
  196. @done="reload"
  197. ></AddContactDialog>
  198. <ContactDetailDialog ref="contactDetailDialogRef"></ContactDetailDialog>
  199. <!-- 多选删除弹窗 -->
  200. <pop-modal
  201. :visible.sync="delVisible"
  202. content="是否确定删除?"
  203. @done="commitBtn"
  204. />
  205. <add-opportunity-dialog
  206. ref="opportunityRef"
  207. :categoryTreeList="treeList"
  208. @done="reload"
  209. ></add-opportunity-dialog>
  210. <drawer ref="drawerRef"></drawer>
  211. <ele-modal
  212. :visible.sync="visible"
  213. title="跟进记录"
  214. :close-on-click-modal="false"
  215. :append-to-body="true"
  216. width="70%"
  217. @close="visible = false"
  218. :maxable="true"
  219. :resizable="true"
  220. >
  221. <followList ref="followListRef" @success="followListSuccess"></followList>
  222. </ele-modal>
  223. <myqsCode ref="qsCodeRef"></myqsCode>
  224. </div>
  225. </template>
  226. <script>
  227. import tabMixins from '@/mixins/tableColumnsMixin';
  228. import addOpportunityDialog from '@/views/saleManage/businessOpportunity/components/addOpportunityDialog.vue';
  229. import ContactSearch from './components/contactSearch.vue';
  230. import AddContactDialog from './components/addContactDialog.vue';
  231. import ContactDetailDialog from './components/contactDetailDialog.vue';
  232. import myqsCode from './components/qsCode.vue';
  233. import drawer from './components/drawer.vue';
  234. import contactList from './contactList.vue';
  235. import contactListAdmin from './contactListAdmin.vue';
  236. import popModal from '@/components/pop-modal';
  237. import AssetTree from '@/components/AssetTree';
  238. import followList from './components/darwerComponents/followList.vue';
  239. import {
  240. contactDelete,
  241. contactPage,
  242. contactTypeTree,
  243. updateStatus,
  244. contactDetail,
  245. customerAdd
  246. } from '@/api/saleManage/contact';
  247. import dictMixins from '@/mixins/dictMixins';
  248. export default {
  249. mixins: [dictMixins, tabMixins],
  250. components: {
  251. AssetTree,
  252. ContactSearch,
  253. popModal,
  254. AddContactDialog,
  255. ContactDetailDialog,
  256. contactListAdmin,
  257. contactList,
  258. addOpportunityDialog,
  259. drawer,
  260. followList,
  261. myqsCode
  262. },
  263. data() {
  264. return {
  265. activeComp: 'myContact',
  266. tabOptions: [
  267. { key: 'myContact', name: '我的' },
  268. { key: 'contactList', name: '公海' }
  269. ],
  270. selection: [],
  271. defaultExpandedKeys: [],
  272. delVisible: false,
  273. text: '',
  274. // 加载状态
  275. loading: false,
  276. columns: [
  277. {
  278. width: 45,
  279. type: 'selection',
  280. columnKey: 'selection',
  281. align: 'center'
  282. },
  283. {
  284. columnKey: 'index',
  285. label: '序号',
  286. type: 'index',
  287. width: 55,
  288. align: 'center',
  289. showOverflowTooltip: true,
  290. fixed: 'left'
  291. },
  292. {
  293. prop: 'code',
  294. label: '编码',
  295. align: 'center',
  296. showOverflowTooltip: true,
  297. minWidth: 140,
  298. fixed: 'left'
  299. },
  300. {
  301. prop: 'name',
  302. label: '名称',
  303. align: 'center',
  304. slot: 'name',
  305. showOverflowTooltip: true,
  306. minWidth: 200,
  307. fixed: 'left'
  308. },
  309. {
  310. label: '二维码',
  311. align: 'center',
  312. slot: 'qrCode',
  313. showOverflowTooltip: true,
  314. minWidth: 80
  315. },
  316. {
  317. prop: 'serialNo',
  318. label: '代号',
  319. align: 'center',
  320. showOverflowTooltip: true,
  321. minWidth: 140
  322. },
  323. {
  324. prop: 'phone',
  325. label: '电话',
  326. align: 'center',
  327. showOverflowTooltip: true,
  328. minWidth: 120
  329. },
  330. {
  331. prop: 'addressName',
  332. label: '注册地址',
  333. align: 'center',
  334. showOverflowTooltip: true,
  335. minWidth: 120,
  336. formatter: (_row, _column, cellValue) => {
  337. return (
  338. (_row.addressName ? _row.addressName.replaceAll(',', '') : '') +
  339. (_row.address || '')
  340. );
  341. }
  342. },
  343. {
  344. prop: 'otherAddressName',
  345. label: '联系地址',
  346. align: 'center',
  347. showOverflowTooltip: true,
  348. minWidth: 120,
  349. formatter: (_row, _column, cellValue) => {
  350. return (
  351. (_row.otherAddressName
  352. ? _row.otherAddressName.replaceAll(',', '')
  353. : '') + (_row.otherAddress || '')
  354. );
  355. }
  356. },
  357. {
  358. prop: 'linkName',
  359. label: '联系人',
  360. align: 'center',
  361. showOverflowTooltip: true,
  362. minWidth: 120
  363. },
  364. {
  365. prop: 'linkPhone',
  366. label: '联系人电话',
  367. align: 'center',
  368. showOverflowTooltip: true,
  369. minWidth: 120
  370. },
  371. {
  372. prop: 'enterpriseScale',
  373. label: '企业规模',
  374. align: 'center',
  375. showOverflowTooltip: true,
  376. minWidth: 120,
  377. slot: 'enterpriseScale'
  378. },
  379. {
  380. prop: 'lastFollowThroughTime',
  381. label: '最近跟进时间',
  382. align: 'center',
  383. showOverflowTooltip: true,
  384. minWidth: 120
  385. },
  386. {
  387. prop: 'enterpriseHonor',
  388. label: '企业荣誉',
  389. align: 'center',
  390. showOverflowTooltip: true,
  391. minWidth: 120,
  392. slot: 'enterpriseHonor'
  393. },
  394. {
  395. prop: 'taxpayerQualification',
  396. label: '纳税人资质',
  397. align: 'center',
  398. showOverflowTooltip: true,
  399. minWidth: 120,
  400. slot: 'taxpayerQualification'
  401. },
  402. {
  403. prop: 'companyCategoryName',
  404. label: '企业类型',
  405. align: 'center',
  406. showOverflowTooltip: true,
  407. minWidth: 120
  408. },
  409. {
  410. prop: 'parentName',
  411. label: '上级单位',
  412. align: 'center',
  413. showOverflowTooltip: true,
  414. minWidth: 120
  415. },
  416. {
  417. prop: 'externalId',
  418. label: '是否推送',
  419. align: 'center',
  420. showOverflowTooltip: true,
  421. minWidth: 120,
  422. formatter: (_row, _column, cellValue) => {
  423. return _row.externalId? '已推送' : '未推送';
  424. }
  425. },
  426. {
  427. prop: 'status',
  428. label: '状态',
  429. align: 'center',
  430. showOverflowTooltip: true,
  431. minWidth: 100,
  432. formatter: (_row, _column, cellValue) => {
  433. return _row.status === 1 ? '启用' : '禁用';
  434. }
  435. },
  436. {
  437. prop: 'createUsername',
  438. label: '创建人',
  439. align: 'center',
  440. showOverflowTooltip: true,
  441. minWidth: 100
  442. },
  443. {
  444. prop: 'createTime',
  445. label: '创建时间',
  446. align: 'center',
  447. showOverflowTooltip: true,
  448. minWidth: 160,
  449. formatter: (_row, _column, cellValue) => {
  450. return this.$util.toDateString(cellValue);
  451. }
  452. },
  453. {
  454. prop: 'updateTime',
  455. label: '修改时间',
  456. align: 'center',
  457. showOverflowTooltip: true,
  458. minWidth: 160,
  459. formatter: (_row, _column, cellValue) => {
  460. return this.$util.toDateString(cellValue);
  461. }
  462. },
  463. {
  464. columnKey: 'action',
  465. label: '操作',
  466. width: 300,
  467. align: 'center',
  468. resizable: false,
  469. slot: 'action',
  470. showOverflowTooltip: true,
  471. fixed: 'right'
  472. }
  473. ],
  474. current: {},
  475. curNodeData: {},
  476. treeList: [],
  477. treeLoading: false,
  478. formData: {},
  479. rootTreeId: null,
  480. defaultProps: {
  481. children: 'children',
  482. label: 'name'
  483. },
  484. showEdit: true,
  485. visible: false,
  486. codeVisible: false,
  487. cacheKeyUrl: 'eos-6c810d8f-saleManage-contact',
  488. contactId: ''
  489. };
  490. },
  491. provide() {
  492. return {
  493. contactId: () => this.contactId
  494. };
  495. },
  496. computed: {},
  497. created() {
  498. console.log(this.$hasPermission('eom:contact:staff'));
  499. console.log(this.$hasPermission('eom:contact:admin'));
  500. this.requestDict('状态');
  501. this.getTreeData();
  502. },
  503. methods: {
  504. /* 表格数据源 */
  505. datasource({ page, limit, where, order }) {
  506. return contactPage({
  507. pageNum: page,
  508. size: limit,
  509. type: 1,
  510. salesmanId: this.$store.state.user.info.userId,
  511. ...where,
  512. categoryId: this.curNodeData.id
  513. });
  514. },
  515. async addFollowDialog(row) {
  516. this.contactId = row.id;
  517. const data = await contactDetail(row.id);
  518. this.visible = true;
  519. this.$nextTick(() => {
  520. this.$refs.followListRef.init(data);
  521. });
  522. },
  523. followListSuccess() {
  524. this.visible = false;
  525. },
  526. async getTreeData() {
  527. try {
  528. this.treeLoading = true;
  529. const res = await contactTypeTree({ id: '17' });
  530. this.treeLoading = false;
  531. if (res?.code === '0') {
  532. this.treeList = res.data;
  533. this.$nextTick(() => {
  534. // console.log(this.treeList);
  535. this.defaultExpandedKeys = this.treeList?.map(
  536. (item) => item.id
  537. ) || [17];
  538. // 默认高亮第一级树节点
  539. // if (this.treeList[0]) {
  540. // this.rootTreeId = this.treeList[0].id;
  541. // this.getDetail(this.treeList[0].id);
  542. // }
  543. });
  544. return this.treeList;
  545. }
  546. } catch (error) {}
  547. this.treeLoading = false;
  548. },
  549. handleNodeClick(data, node) {
  550. this.curNodeData = data;
  551. this.reload({ categoryId: data.id });
  552. },
  553. /* 刷新表格 */
  554. reload(where) {
  555. this.$refs.table.reload({ page: 1, where });
  556. },
  557. openEdit(row, type) {
  558. this.current = row;
  559. this.showEdit = true;
  560. this.$refs.addContactDialogRef.open(row, type, this.curNodeData.id);
  561. this.$refs.addContactDialogRef.$refs.form &&
  562. this.$refs.addContactDialogRef.$refs.form.clearValidate();
  563. },
  564. addOppo(type, row) {
  565. this.$refs.opportunityRef.open(type, row, row.id);
  566. this.$refs.opportunityRef.$refs.form &&
  567. this.$refs.opportunityRef.$refs.form.clearValidate();
  568. },
  569. //批量删除
  570. allDelBtn() {
  571. if (this.selection.length === 0) return;
  572. this.delVisible = true;
  573. },
  574. allPushBtn() {
  575. const dataId = this.selection.map((v) => v.id);
  576. customerAdd(dataId).then((res) => {
  577. this.$message.success('推送成功!');
  578. this.reload();
  579. });
  580. },
  581. commitBtn() {
  582. console.log(this.selection);
  583. const dataId = this.selection.map((v) => v.id);
  584. contactDelete(dataId).then((res) => {
  585. this.$message.success('删除成功!');
  586. this.reload();
  587. });
  588. },
  589. remove(row) {
  590. contactDelete([row.id]).then((res) => {
  591. this.$message.success('删除成功!');
  592. this.reload();
  593. });
  594. },
  595. setCode(row) {
  596. this.$nextTick(() => {
  597. this.$refs.qsCodeRef.open(row);
  598. });
  599. },
  600. /** 启用 */
  601. enableOption(row) {
  602. updateStatus(row.id, 1)
  603. .then((msg) => {
  604. this.$message.success('启用成功');
  605. this.reload();
  606. })
  607. .catch((e) => {
  608. this.$message.error(e.message);
  609. });
  610. },
  611. /** 禁用 */
  612. disableOption(row) {
  613. updateStatus(row.id, 2)
  614. .then((msg) => {
  615. this.$message.success('禁用成功');
  616. this.reload();
  617. })
  618. .catch((e) => {
  619. this.$message.error(e.message);
  620. });
  621. },
  622. openDetail(row) {
  623. // this.$refs.contactDetailDialogRef.open(row);
  624. this.$refs.drawerRef.open(row, 'myList');
  625. }
  626. }
  627. };
  628. </script>
  629. <style lang="scss" scoped>
  630. :deep .el-card__body {
  631. padding: 0;
  632. }
  633. :deep(.el-link--inner) {
  634. margin-left: 0px !important;
  635. }
  636. .sys-organization-list {
  637. height: calc(100vh - 264px);
  638. box-sizing: border-box;
  639. border-width: 1px;
  640. border-style: solid;
  641. overflow: auto;
  642. }
  643. .sys-organization-list :deep(.el-tree-node__content) {
  644. height: 40px;
  645. & > .el-tree-node__expand-icon {
  646. margin-left: 10px;
  647. }
  648. }
  649. .switch_left ul .active {
  650. border-top: 4px solid var(--color-primary);
  651. color: var(--color-primary-5);
  652. }
  653. .switch {
  654. padding-bottom: 20px;
  655. }
  656. </style>