list.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. }
  324. },
  325. watch: {
  326. showColumns: function () {
  327. this.$nextTick(() => this.$refs.table.doLayout())
  328. },
  329. },
  330. activated() {
  331. this.fetchData()
  332. },
  333. mounted() {
  334. this.getOptions()
  335. this.fetchData()
  336. },
  337. methods: {
  338. getOptions() {
  339. Promise.all([
  340. api.getProvinceDetail(),
  341. this.getDicts('cust_level'),
  342. this.getDicts('cust_idy'),
  343. userApi.getList({
  344. orderBy: 'userName',
  345. roles: ['SalesEngineer', 'ProductLineManager'],
  346. pageNum: 1,
  347. pageSize: 50,
  348. }),
  349. ])
  350. .then(([province, level, industry, sell]) => {
  351. this.provinceOptions = province.data.list || []
  352. this.levelOptions = level.data.values || []
  353. this.industryOptions = industry.data.values || []
  354. this.sellOptions = sell.data.list || []
  355. })
  356. .catch((err) => console.log(err))
  357. },
  358. handleClick(tab) {
  359. console.log(tab, 'tab')
  360. this.queryForm.pageNum = 1
  361. this.queryForm.targetType = this.activeName
  362. this.fetchData()
  363. },
  364. async fetchData() {
  365. this.listLoading = true
  366. const params = { ...this.queryForm }
  367. if (this.queryForm.followUpDate && this.queryForm.followUpDate.length === 2) {
  368. params.beginTime = this.queryForm.followUpDate[0]
  369. params.endTime = this.queryForm.followUpDate[1]
  370. }
  371. params.custProvince = params.province.distName ? params.province.distName : ''
  372. const [err, res] = await to(api.getList(params))
  373. if (err) return (this.listLoading = false)
  374. this.list = res.data.list || []
  375. this.total = res.data.total
  376. this.listLoading = false
  377. this.$nextTick(() => this.$refs.table.doLayout())
  378. },
  379. handleSearch() {
  380. this.queryForm.pageNum = 1
  381. this.fetchData()
  382. },
  383. exportData() {
  384. this.queryForm.isPublic = false
  385. let exportFrom = JSON.parse(JSON.stringify(this.queryForm))
  386. exportFrom.columns = this.showColumns.map((item) => item.label)
  387. api
  388. .deriveList(exportFrom)
  389. .then((res) => {
  390. if (res.data.list.content) {
  391. downloadFileByByte(res.data.list.content, '客户数据.xlsx')
  392. }
  393. })
  394. .catch((err) => {
  395. console.error(err)
  396. })
  397. },
  398. reset() {
  399. this.queryForm = {
  400. pageNum: 1,
  401. pageSize: 10,
  402. custCode: '', // 客户编码
  403. custName: '', //客户名称
  404. indusTry: '', // 客户类型 ()
  405. salesName: '',
  406. followUpDate: [],
  407. custProvince: '',
  408. custCity: '',
  409. province: {},
  410. }
  411. this.fetchData()
  412. },
  413. // 客户编辑
  414. handleEdit(row) {
  415. this.$refs.edit.init([row.id])
  416. },
  417. // 联系人弹窗
  418. async createContact(res) {
  419. this.$refs.contact.contactForm.custId = res.id
  420. this.$refs.contact.contactForm.custName = res.name
  421. this.$refs.contact.contactVisible = true
  422. },
  423. // 客户详情
  424. handleDetail(row) {
  425. this.$router.push({
  426. path: '/customer/detail',
  427. query: {
  428. id: row.id,
  429. },
  430. })
  431. },
  432. // 客户删除
  433. handleDelete(row) {
  434. this.$confirm('确认删除?', '提示', {
  435. confirmButtonText: '确定',
  436. cancelButtonText: '取消',
  437. type: 'warning',
  438. })
  439. .then(async () => {
  440. const [err, res] = await to(api.deleteCustomer({ Ids: [row.id] }))
  441. if (err) return
  442. if (res.code == 200) {
  443. this.$message({
  444. type: 'success',
  445. message: '删除成功!',
  446. })
  447. this.fetchData()
  448. }
  449. })
  450. .catch(() => {})
  451. },
  452. handleSizeChange(val) {
  453. this.queryForm.pageSize = val
  454. this.fetchData()
  455. },
  456. handleCurrentChange(val) {
  457. this.queryForm.pageNum = val
  458. this.fetchData()
  459. },
  460. setSelectRows(val) {
  461. this.selectRows = val
  462. },
  463. // 转移客户
  464. handleShift() {
  465. if (!this.selectRows.length) return this.$message.warning('请选择需要转移的客户')
  466. this.$refs['shift'].open(this.selectRows)
  467. },
  468. // 移入公海
  469. handleToOpen() {
  470. if (!this.selectRows.length) return this.$message.warning('请选择要移入公海的客户')
  471. this.$refs.toOpen.form.ids = this.selectRows.map((item) => item.id)
  472. this.$refs.toOpen.visible = true
  473. },
  474. async handleMerge() {
  475. if (this.selectRows.length < 2) return this.$message.warning('请选择两个以上客户进行合并')
  476. const ids = this.selectRows.map((item) => item.id)
  477. const [err, res] = await to(api.getDetail({ ids }))
  478. if (err) return
  479. this.$refs.merge.init(res, ids)
  480. },
  481. handleSysAdminTransfer() {
  482. if (this.selectRows.length === 0) {
  483. this.$baseMessage('请选择客户', 'warning')
  484. return
  485. }
  486. this.$refs['shift'].sysAdminOpen(this.selectRows)
  487. },
  488. },
  489. }
  490. </script>
  491. <style lang="scss" scoped>
  492. $base: '.list';
  493. .link-button {
  494. font-size: 14px;
  495. width: 100%;
  496. overflow: hidden;
  497. text-overflow: ellipsis;
  498. white-space: nowrap;
  499. }
  500. </style>