list.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. <!--
  2. * @Author: wanglj 471442253@qq.com
  3. * @Date: 2022-12-26 16:34:37
  4. * @LastEditors: niezch@dashoo.cn
  5. * @LastEditTime: 2023-04-03 13:51:12
  6. * @Description: file content
  7. * @FilePath: \opms_frontend\src\views\customer\list.vue
  8. -->
  9. <template>
  10. <div class="list-container">
  11. <el-tabs v-model="activeName" @tab-click="handleClick">
  12. <el-tab-pane label="全部客户" name="all" />
  13. <el-tab-pane label="我的客户" name="self" />
  14. <el-tab-pane label="下属的客户" name="other" />
  15. </el-tabs>
  16. <el-row :gutter="10" style="margin-bottom: 10px">
  17. <!-- <el-col :span="4">
  18. <el-input v-model="queryForm.custCode" placeholder="客户编码" clearable @keyup.enter.native="handleSearch" />
  19. </el-col> -->
  20. <el-col :span="3.5">
  21. <el-input v-model="queryForm.custName" clearable placeholder="客户名称" @keyup.enter.native="handleSearch" />
  22. </el-col>
  23. <!-- <el-col :span="4">
  24. <el-select v-model="queryForm.custIndustry" clearable placeholder="客户类型" style="width: 100%">
  25. <el-option v-for="item in industryOptions" :key="item.key" :label="item.value" :value="item.key" />
  26. </el-select>
  27. </el-col> -->
  28. <el-col :span="3.5">
  29. <el-select v-model="queryForm.province" clearable placeholder="所在省" value-key="id">
  30. <el-option v-for="item in provinceOptions" :key="item.id" :label="item.distName" :value="item" />
  31. </el-select>
  32. <!-- <el-input v-model="queryForm.custProvince" clearable placeholder="所在省" @keyup.enter.native="handleSearch" /> -->
  33. </el-col>
  34. <el-col :span="3.5">
  35. <el-select v-model="queryForm.custCity" clearable placeholder="所在市" value-key="id">
  36. <el-option
  37. v-for="item in queryForm.province ? queryForm.province.children : []"
  38. :key="item.id"
  39. clearable
  40. :label="item.distName"
  41. :value="item.distName" />
  42. </el-select>
  43. <!-- <el-input v-model="queryForm.custCity" clearable placeholder="所在市" @keyup.enter.native="handleSearch" /> -->
  44. </el-col>
  45. <el-col :span="3.5">
  46. <el-select v-model="queryForm.salesName" clearable placeholder="所属销售" value-key="id">
  47. <el-option v-for="item in sellOptions" :key="item.id" :label="item.nickName" :value="item.nickName" />
  48. </el-select>
  49. <!-- <el-input v-model="queryForm.salesName" clearable placeholder="所属销售" @keyup.enter.native="handleSearch" /> -->
  50. </el-col>
  51. <!-- <el-col :span="4">
  52. <el-select v-model="queryForm.custLevel" placeholder="客户级别" style="width: 100%">
  53. <el-option v-for="item in levelOptions" :key="item.value" :label="item.value" :value="item.value" />
  54. </el-select>
  55. </el-col> -->
  56. <el-col :span="6">
  57. <!-- <el-date-picker
  58. v-model="queryForm.followUpDate"
  59. placeholder="最后跟进时间"
  60. style="width: 100%"
  61. type="date"
  62. value-format="yyyy-MM-dd" /> -->
  63. <el-date-picker
  64. v-model="queryForm.followUpDate"
  65. end-placeholder="跟进结束时间"
  66. range-separator="至"
  67. start-placeholder="跟进开始时间"
  68. style="width: 100%"
  69. type="daterange"
  70. value-format="yyyy-MM-dd" />
  71. </el-col>
  72. <el-col :span="4">
  73. <el-button icon="el-icon-plus" type="primary" @click="handleSearch">查询</el-button>
  74. <el-button icon="el-icon-refresh-right" @click="reset">重置</el-button>
  75. </el-col>
  76. </el-row>
  77. <vab-query-form>
  78. <vab-query-form-left-panel :span="12">
  79. <el-button
  80. v-permissions="['cust:list:add']"
  81. icon="el-icon-plus"
  82. size="mini"
  83. type="primary"
  84. @click="$refs.edit.init()">
  85. 新建
  86. </el-button>
  87. <el-button
  88. v-permissions="['cust:list:shift']"
  89. icon="el-icon-plus"
  90. size="mini"
  91. type="primary"
  92. @click="handleShift">
  93. 转移客户
  94. </el-button>
  95. <el-button
  96. v-permissions="['cust:list:open']"
  97. icon="el-icon-plus"
  98. size="mini"
  99. type="primary"
  100. @click="handleToOpen">
  101. 移入公海
  102. </el-button>
  103. <el-button
  104. v-permissions="['cust:list:merge']"
  105. icon="el-icon-plus"
  106. size="mini"
  107. type="primary"
  108. @click="handleMerge">
  109. 合并客户
  110. </el-button>
  111. <el-button
  112. v-permissions="['cust:list:sysadmin_transfer']"
  113. icon="el-icon-refresh"
  114. type="primary"
  115. @click="handleSysAdminTransfer">
  116. 管理员转移客户
  117. </el-button>
  118. </vab-query-form-left-panel>
  119. <vab-query-form-right-panel :span="12">
  120. <!-- <el-button icon="el-icon-download" @click="exportData" />-->
  121. <table-tool :columns="columns" :show-columns.sync="showColumns" table-type="customerTable" />
  122. </vab-query-form-right-panel>
  123. </vab-query-form>
  124. <el-table
  125. ref="table"
  126. v-loading="listLoading"
  127. border
  128. :data="list"
  129. :height="$baseTableHeight(3)"
  130. @selection-change="setSelectRows">
  131. <el-table-column align="center" show-overflow-tooltip type="selection" />
  132. <el-table-column
  133. v-for="(item, index) in showColumns"
  134. :key="index"
  135. align="center"
  136. :label="item.label"
  137. :min-width="item.width"
  138. :prop="item.prop"
  139. show-overflow-tooltip
  140. :sortable="item.sortable">
  141. <template #default="{ row }">
  142. <el-button v-if="item.prop === 'custName'" class="link-button" type="text" @click="handleDetail(row)">
  143. {{ row.custName }}
  144. </el-button>
  145. <span v-else-if="item.prop === 'custStatus'">
  146. {{ row.custStatus == 10 ? '正常' : '异常' }}
  147. </span>
  148. <span v-else-if="item.prop === 'custIndustry'">
  149. {{ selectDictLabel(industryOptions, row.custIndustry) }}
  150. </span>
  151. <span v-else-if="item.prop === 'followUpDate'">
  152. {{ parseTime(row.followUpDate, '{y}-{m}-{d}') }}
  153. </span>
  154. <span v-else-if="item.prop === 'createdTime'">
  155. {{ parseTime(row.createdTime, '{y}-{m}-{d}') }}
  156. </span>
  157. <span v-else>{{ row[item.prop] }}</span>
  158. </template>
  159. </el-table-column>
  160. <el-table-column align="center" fixed="right" label="操作" width="90px">
  161. <template slot-scope="scope">
  162. <el-button v-permissions="['cust:list:edit']" type="text" @click="handleEdit(scope.row)">编辑</el-button>
  163. <el-button v-permissions="['cust:list:delete']" type="text" @click="handleDelete(scope.row)">删除</el-button>
  164. </template>
  165. </el-table-column>
  166. </el-table>
  167. <el-pagination
  168. background
  169. :current-page="queryForm.pageNum"
  170. :layout="layout"
  171. :page-size="queryForm.pageSize"
  172. :total="total"
  173. @current-change="handleCurrentChange"
  174. @size-change="handleSizeChange" />
  175. <!-- 新增编辑客户弹窗 -->
  176. <Edit ref="edit" @createContact="createContact" @customerSave="fetchData" />
  177. <!-- 新建联系人弹窗 -->
  178. <Contact ref="contact" />
  179. <!-- 转移客户 -->
  180. <Shift ref="shift" @refresh="fetchData" />
  181. <!-- 移入公海 -->
  182. <ToOpen ref="toOpen" @refresh="fetchData" />
  183. <!-- 合并客户 -->
  184. <Merge ref="merge" @refresh="fetchData" />
  185. </div>
  186. </template>
  187. <script>
  188. import to from 'await-to-js'
  189. import api from '@/api/customer'
  190. import Edit from './components/Edit'
  191. import Contact from './components/Contact'
  192. import Shift from './components/Shift'
  193. import ToOpen from './components/ToOpen'
  194. import Merge from './components/Merge'
  195. import TableTool from '@/components/table/TableTool'
  196. import downloadFileByByte from '@/utils/base64ToFile'
  197. import userApi from '@/api/system/user'
  198. export default {
  199. name: 'ReserveCustomer',
  200. components: {
  201. Edit,
  202. Contact,
  203. Shift,
  204. ToOpen,
  205. Merge,
  206. TableTool,
  207. },
  208. data() {
  209. return {
  210. activeName: 'all',
  211. layout: 'total, sizes, prev, pager, next, jumper',
  212. queryForm: {
  213. custCode: '',
  214. custName: '',
  215. indusTry: '',
  216. targetType: '',
  217. pageNum: 1,
  218. pageSize: 10,
  219. isPublic: false,
  220. salesName: '',
  221. followUpDate: [],
  222. custProvince: '',
  223. custCity: '',
  224. province: {},
  225. },
  226. total: 0,
  227. listLoading: false,
  228. list: [],
  229. selectRows: [],
  230. industryOptions: [], //客户类型
  231. levelOptions: [], //客户级别
  232. provinceOptions: [],
  233. provinceDetail: [],
  234. sellOptions: [],
  235. // 自定义列表
  236. showColumns: [],
  237. columns: [
  238. {
  239. label: '客户编码',
  240. width: '120px',
  241. prop: 'custCode',
  242. sortable: false,
  243. disableCheck: false,
  244. },
  245. {
  246. label: '客户名称',
  247. width: '200px',
  248. prop: 'custName',
  249. sortable: false,
  250. disableCheck: true,
  251. },
  252. {
  253. label: '助记名',
  254. width: '120px',
  255. prop: 'abbrName',
  256. sortable: false,
  257. disableCheck: false,
  258. },
  259. {
  260. label: '所在省',
  261. width: '120px',
  262. prop: 'custProvince',
  263. sortable: false,
  264. disableCheck: false,
  265. },
  266. {
  267. label: '所在市',
  268. width: '100px',
  269. prop: 'custCity',
  270. sortable: false,
  271. disableCheck: false,
  272. },
  273. {
  274. label: '客户类型',
  275. width: '100px',
  276. prop: 'custIndustry',
  277. sortable: false,
  278. disableCheck: false,
  279. },
  280. // {
  281. // label: '客户级别',
  282. // width: 'auto',
  283. // prop: 'custLevel',
  284. // sortable: false,
  285. // disableCheck: false,
  286. // },
  287. // {
  288. // label: '客户状态',
  289. // width: '100px',
  290. // prop: 'custStatus',
  291. // sortable: false,
  292. // disableCheck: false,
  293. // },
  294. {
  295. label: '最后跟进时间',
  296. width: '100px',
  297. prop: 'followUpDate',
  298. sortable: false,
  299. disableCheck: false,
  300. },
  301. {
  302. label: '最后跟进人',
  303. width: '100px',
  304. prop: 'followUpMan',
  305. sortable: false,
  306. disableCheck: false,
  307. },
  308. {
  309. label: '所属销售',
  310. width: '100px',
  311. prop: 'salesName',
  312. sortable: false,
  313. disableCheck: false,
  314. },
  315. {
  316. label: '创建时间',
  317. width: '100px',
  318. prop: 'createdTime',
  319. sortable: false,
  320. disableCheck: false,
  321. },
  322. {
  323. label: '备注',
  324. width: '120px',
  325. prop: 'remark',
  326. sortable: false,
  327. disableCheck: false,
  328. },
  329. ],
  330. }
  331. },
  332. watch: {
  333. showColumns: function () {
  334. this.$nextTick(() => this.$refs.table.doLayout())
  335. },
  336. },
  337. activated() {
  338. this.fetchData()
  339. },
  340. mounted() {
  341. this.getOptions()
  342. this.fetchData()
  343. },
  344. methods: {
  345. getOptions() {
  346. Promise.all([
  347. api.getProvinceDetail(),
  348. this.getDicts('cust_level'),
  349. this.getDicts('cust_idy'),
  350. userApi.getList({
  351. orderBy: 'userName',
  352. roles: ['SalesEngineer', 'ProductLineManager', 'SalesDirector'],
  353. pageNum: 1,
  354. pageSize: 50,
  355. }),
  356. ])
  357. .then(([province, level, industry, sell]) => {
  358. this.provinceOptions = province.data.list || []
  359. this.levelOptions = level.data.values || []
  360. this.industryOptions = industry.data.values || []
  361. this.sellOptions = sell.data.list || []
  362. })
  363. .catch((err) => console.log(err))
  364. },
  365. handleClick(tab) {
  366. console.log(tab, 'tab')
  367. this.queryForm.pageNum = 1
  368. this.queryForm.targetType = this.activeName
  369. this.fetchData()
  370. },
  371. async fetchData() {
  372. this.listLoading = true
  373. const params = { ...this.queryForm }
  374. if (this.queryForm.followUpDate && this.queryForm.followUpDate.length === 2) {
  375. params.beginTime = this.queryForm.followUpDate[0]
  376. params.endTime = this.queryForm.followUpDate[1]
  377. }
  378. params.custProvince = params.province.distName ? params.province.distName : ''
  379. const [err, res] = await to(api.getList(params))
  380. if (err) return (this.listLoading = false)
  381. this.list = res.data.list || []
  382. this.total = res.data.total
  383. this.listLoading = false
  384. this.$nextTick(() => this.$refs.table.doLayout())
  385. },
  386. handleSearch() {
  387. this.queryForm.pageNum = 1
  388. this.fetchData()
  389. },
  390. exportData() {
  391. this.queryForm.isPublic = false
  392. let exportFrom = JSON.parse(JSON.stringify(this.queryForm))
  393. exportFrom.columns = this.showColumns.map((item) => item.label)
  394. api
  395. .deriveList(exportFrom)
  396. .then((res) => {
  397. if (res.data.list.content) {
  398. downloadFileByByte(res.data.list.content, '客户数据.xlsx')
  399. }
  400. })
  401. .catch((err) => {
  402. console.error(err)
  403. })
  404. },
  405. reset() {
  406. this.queryForm = {
  407. pageNum: 1,
  408. pageSize: 10,
  409. custCode: '', // 客户编码
  410. custName: '', //客户名称
  411. indusTry: '', // 客户类型 ()
  412. salesName: '',
  413. followUpDate: [],
  414. custProvince: '',
  415. custCity: '',
  416. province: {},
  417. }
  418. this.fetchData()
  419. },
  420. // 客户编辑
  421. handleEdit(row) {
  422. this.$refs.edit.init([row.id])
  423. },
  424. // 联系人弹窗
  425. async createContact(res) {
  426. this.$refs.contact.contactForm.custId = res.id
  427. this.$refs.contact.contactForm.custName = res.name
  428. this.$refs.contact.contactVisible = true
  429. },
  430. // 客户详情
  431. handleDetail(row) {
  432. this.$router.push({
  433. path: '/customer/detail',
  434. query: {
  435. id: row.id,
  436. },
  437. })
  438. },
  439. // 客户删除
  440. handleDelete(row) {
  441. this.$confirm('确认删除?', '提示', {
  442. confirmButtonText: '确定',
  443. cancelButtonText: '取消',
  444. type: 'warning',
  445. })
  446. .then(async () => {
  447. const [err, res] = await to(api.deleteCustomer({ Ids: [row.id] }))
  448. if (err) return
  449. if (res.code == 200) {
  450. this.$message({
  451. type: 'success',
  452. message: '删除成功!',
  453. })
  454. this.fetchData()
  455. }
  456. })
  457. .catch(() => {})
  458. },
  459. handleSizeChange(val) {
  460. this.queryForm.pageSize = val
  461. this.fetchData()
  462. },
  463. handleCurrentChange(val) {
  464. this.queryForm.pageNum = val
  465. this.fetchData()
  466. },
  467. setSelectRows(val) {
  468. this.selectRows = val
  469. },
  470. // 转移客户
  471. handleShift() {
  472. if (!this.selectRows.length) return this.$message.warning('请选择需要转移的客户')
  473. this.$refs['shift'].open(this.selectRows)
  474. },
  475. // 移入公海
  476. handleToOpen() {
  477. if (!this.selectRows.length) return this.$message.warning('请选择要移入公海的客户')
  478. this.$refs.toOpen.form.ids = this.selectRows.map((item) => item.id)
  479. this.$refs.toOpen.visible = true
  480. },
  481. async handleMerge() {
  482. if (this.selectRows.length < 2) return this.$message.warning('请选择两个以上客户进行合并')
  483. const ids = this.selectRows.map((item) => item.id)
  484. const [err, res] = await to(api.getDetail({ ids }))
  485. if (err) return
  486. this.$refs.merge.init(res, ids)
  487. },
  488. handleSysAdminTransfer() {
  489. if (this.selectRows.length === 0) {
  490. this.$baseMessage('请选择客户', 'warning')
  491. return
  492. }
  493. this.$refs['shift'].sysAdminOpen(this.selectRows)
  494. },
  495. },
  496. }
  497. </script>
  498. <style lang="scss" scoped>
  499. $base: '.list';
  500. .link-button {
  501. font-size: 14px;
  502. width: 100%;
  503. overflow: hidden;
  504. text-overflow: ellipsis;
  505. white-space: nowrap;
  506. }
  507. </style>