index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. <template>
  2. <div class="business-container">
  3. <el-tabs v-model="activeName" @tab-click="handleTabClick">
  4. <el-tab-pane label="全部项目" name="all" />
  5. <el-tab-pane label="A类项目" name="10" />
  6. <el-tab-pane label="B类项目" name="20" />
  7. <el-tab-pane label="C类项目" name="30" />
  8. <el-tab-pane label="储备项目" name="50" />
  9. <el-tab-pane label="成交项目" name="40" />
  10. </el-tabs>
  11. <vab-query-form>
  12. <vab-query-form-top-panel>
  13. <el-form ref="queryForm" :inline="true" :model="queryForm" @submit.native.prevent>
  14. <!-- <el-form-item prop="nboName">-->
  15. <!-- <el-input v-model="queryForm.nboName" clearable placeholder="项目名称" @keyup.enter.native="queryData" />-->
  16. <!-- </el-form-item>-->
  17. <el-form-item prop="custName">
  18. <el-input
  19. v-model="queryForm.custName"
  20. clearable
  21. placeholder="客户名称"
  22. size="small"
  23. @keyup.enter.native="queryData" />
  24. </el-form-item>
  25. <el-form-item v-show="activeName === 'all'" prop="nboType">
  26. <el-select v-model="queryForm.nboType" clearable placeholder="项目类别">
  27. <el-option v-for="dict in nboTypeOptions" :key="dict.key" :label="dict.value" :value="dict.key" />
  28. </el-select>
  29. </el-form-item>
  30. <el-form-item prop="saleName">
  31. <el-input
  32. v-model="queryForm.saleName"
  33. clearable
  34. placeholder="销售工程师"
  35. size="small"
  36. @keyup.enter.native="queryData" />
  37. </el-form-item>
  38. <el-form-item prop="productLine">
  39. <el-select v-model="queryForm.productLine" clearable placeholder="产品线">
  40. <el-option v-for="item in productLineOptions" :key="item.key" :label="item.value" :value="item.key" />
  41. </el-select>
  42. </el-form-item>
  43. <el-form-item prop="nboSource">
  44. <el-select v-model="queryForm.nboSource" clearable placeholder="项目来源">
  45. <el-option v-for="dict in nboSourceOptions" :key="dict.key" :label="dict.value" :value="dict.key" />
  46. </el-select>
  47. </el-form-item>
  48. <el-form-item prop="distributorName">
  49. <el-input
  50. v-model="queryForm.distributorName"
  51. clearable
  52. placeholder="经销商/代理商"
  53. size="small"
  54. @keyup.enter.native="queryData" />
  55. </el-form-item>
  56. <el-form-item prop="custProvince">
  57. <el-select v-model="queryForm.custProvince" clearable placeholder="所在省" value-key="id">
  58. <el-option v-for="item in provinceOptions" :key="item.id" :label="item.distName" :value="item" />
  59. </el-select>
  60. </el-form-item>
  61. <el-form-item prop="filingTime">
  62. <el-date-picker
  63. v-model="queryForm.filingTime"
  64. end-placeholder="结束"
  65. start-placeholder="备案日期开始"
  66. type="daterange"
  67. value-format="yyyy-MM-dd" />
  68. </el-form-item>
  69. <el-form-item>
  70. <el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
  71. <el-button icon="el-icon-refresh" type="primary" @click="resetQuery">重置</el-button>
  72. <el-button v-permissions="['proj:business:add']" icon="el-icon-plus" type="primary" @click="handleEdit({})">
  73. 新增项目
  74. </el-button>
  75. <el-button
  76. v-permissions="['proj:business:transfer']"
  77. icon="el-icon-refresh"
  78. type="primary"
  79. @click="handleTransfer">
  80. 转移项目
  81. </el-button>
  82. </el-form-item>
  83. </el-form>
  84. </vab-query-form-top-panel>
  85. <vab-query-form-left-panel :span="12">
  86. <!-- <el-button icon="el-icon-plus" type="primary" @click="handleEdit">创建任务</el-button>-->
  87. <!-- <el-button icon="el-icon-plus" type="primary" @click="handleEdit">创建工单</el-button>-->
  88. <!-- <el-button icon="el-icon-plus" type="primary" @click="handleEdit">创建合同</el-button>-->
  89. <!-- <el-button icon="el-icon-delete" type="danger" @click="handleDelete">删除</el-button>-->
  90. </vab-query-form-left-panel>
  91. <vab-query-form-right-panel :span="12">
  92. <table-tool
  93. ref="tableTool"
  94. :columns.sync="finallyColumns"
  95. :show-columns.sync="showColumns"
  96. :table-type.sync="tableType" />
  97. </vab-query-form-right-panel>
  98. </vab-query-form>
  99. <el-table
  100. :key="tableKey"
  101. ref="busTable"
  102. v-loading="listLoading"
  103. :data="list"
  104. :height="height"
  105. @selection-change="setSelectRows">
  106. <el-table-column align="center" show-overflow-tooltip type="selection" />
  107. <el-table-column
  108. v-for="(item, index) in showColumns"
  109. :key="index"
  110. align="center"
  111. :label="item.label"
  112. :min-width="item.minWidth"
  113. :prop="item.prop"
  114. show-overflow-tooltip
  115. :sortable="item.sortable"
  116. :width="item.width">
  117. <template #default="{ row }">
  118. <el-button
  119. v-if="item.prop === 'nboCode' || item.prop === 'nboName'"
  120. class="link-button"
  121. type="text"
  122. @click="handleDetail(row)">
  123. {{ row[item.prop] }}
  124. </el-button>
  125. <span v-else-if="item.prop === 'nboType'">
  126. {{ selectDictLabel(nboTypeOptions, row.nboType) }}
  127. </span>
  128. <span v-else-if="item.prop === 'nboSource'">
  129. {{ selectDictLabel(nboSourceOptions, row.nboSource) }}
  130. </span>
  131. <span v-else-if="item.prop === 'salesModel'">
  132. {{ selectDictLabel(salesModelOptions, row.salesModel) }}
  133. </span>
  134. <span v-else-if="item.prop === 'approStatus'">
  135. {{ selectDictLabel(approStatusOptions, row.approStatus) }}
  136. </span>
  137. <span v-else-if="item.prop === 'nboStatus'">
  138. {{ selectDictLabel(nboStatusOptions, row.nboStatus) }}
  139. </span>
  140. <span v-else-if="item.prop === 'nboPhase'">
  141. {{ selectDictLabel(nboPhaseOptions, row.nboPhase) }}
  142. </span>
  143. <span v-else-if="item.prop === 'productLine'">
  144. {{ selectDictLabel(productLineOptions, row.productLine) }}
  145. </span>
  146. <span v-else-if="item.prop === 'isBig'">
  147. {{ selectDictLabel(yesOrNoOptions, row.isBig) }}
  148. </span>
  149. <span v-else-if="item.prop === 'estTransPrice'">
  150. {{ formatPrice(row.estTransPrice) }}
  151. </span>
  152. <span v-else-if="item.prop === 'nboBudget'">
  153. {{ formatPrice(row.nboBudget) }}
  154. </span>
  155. <span v-else-if="item.prop === 'contractAmount'">
  156. {{ formatPrice(row.contractAmount) }}
  157. </span>
  158. <span v-else-if="item.prop === 'filingTime'">
  159. {{ parseTime(row.filingTime, '{y}-{m}-{d}') }}
  160. </span>
  161. <span v-else-if="item.prop === 'finalFollowTime'">
  162. {{ parseTime(row.finalFollowTime, '{y}-{m}-{d}') }}
  163. </span>
  164. <span v-else-if="item.prop === 'nextFollowTime'">
  165. {{ parseTime(row.nextFollowTime, '{y}-{m}-{d}') }}
  166. </span>
  167. <span v-else-if="item.prop === 'projClosingTime'">
  168. {{ parseTime(row.projClosingTime, '{y}-{m}-{d}') }}
  169. </span>
  170. <span v-else-if="item.prop === 'projConversionTime'">
  171. {{ parseTime(row.projConversionTime, '{y}-{m}-{d}') }}
  172. </span>
  173. <span v-else>{{ row[item.prop] }}</span>
  174. </template>
  175. </el-table-column>
  176. <el-table-column align="center" fixed="right" label="操作" width="68">
  177. <template #default="{ row }">
  178. <!-- <el-button type="text" @click="handleFollow(row)">跟进</el-button>-->
  179. <el-button v-permissions="['proj:business:edit']" type="text" @click="handleEdit(row)">编辑</el-button>
  180. <!-- <el-button type="text" @click="handleDelete(row)">删除</el-button>-->
  181. </template>
  182. </el-table-column>
  183. </el-table>
  184. <el-pagination
  185. background
  186. :current-page="queryForm.pageNum"
  187. :layout="layout"
  188. :page-size="queryForm.pageSize"
  189. :total="total"
  190. @current-change="handleCurrentChange"
  191. @size-change="handleSizeChange" />
  192. <!-- 添加 -->
  193. <add ref="add" @fetch-data="fetchData" />
  194. <!-- 编辑 -->
  195. <edit ref="edit" @fetch-data="fetchData" />
  196. <!-- 转移 -->
  197. <transfer ref="transfer" @fetch-data="fetchData" />
  198. <!-- 添加跟进记录 -->
  199. <follow-add ref="follow" @fetch-data="fetchData" />
  200. </div>
  201. </template>
  202. <script>
  203. import businessApi from '@/api/proj/business'
  204. import Edit from './components/BusinessEdit'
  205. import Add from './components/BusinessAdd'
  206. import Transfer from './components/Transfer'
  207. import FollowAdd from './components/FollowAdd'
  208. import TableTool from '@/components/table/TableTool'
  209. import customerApi from '@/api/customer'
  210. export default {
  211. name: 'Business',
  212. components: { Edit, Transfer, TableTool, FollowAdd, Add },
  213. data() {
  214. return {
  215. tableKey: 0,
  216. activeName: '',
  217. height: this.$baseTableHeight(4),
  218. queryForm: {
  219. pageNum: 1,
  220. pageSize: 10,
  221. nboName: undefined,
  222. custName: undefined,
  223. nboType: undefined,
  224. saleName: undefined,
  225. productLine: undefined,
  226. nboSource: undefined,
  227. distributorName: undefined,
  228. custProvince: null,
  229. filingTime: undefined,
  230. beginTime: undefined,
  231. endTime: undefined,
  232. },
  233. tableType: 'businessTable',
  234. showColumns: [],
  235. columns: [
  236. {
  237. label: '项目编码',
  238. prop: 'nboCode',
  239. width: '120px',
  240. minWidth: '120px',
  241. sortable: false,
  242. disableCheck: true,
  243. },
  244. {
  245. label: '项目名称',
  246. prop: 'nboName',
  247. width: '240px',
  248. minWidth: '240px',
  249. sortable: false,
  250. disableCheck: true,
  251. },
  252. {
  253. label: '所在省',
  254. prop: 'custProvince',
  255. width: '100px',
  256. },
  257. {
  258. label: '所在市',
  259. prop: 'custCity',
  260. width: '100px',
  261. },
  262. {
  263. label: '销售工程师',
  264. prop: 'saleName',
  265. width: '100px',
  266. },
  267. {
  268. label: '客户名称',
  269. prop: 'custName',
  270. width: 'auto',
  271. minWidth: '240px',
  272. },
  273. {
  274. label: '项目备案时间',
  275. prop: 'filingTime',
  276. width: '110px',
  277. },
  278. {
  279. label: '项目来源',
  280. prop: 'nboSource',
  281. width: '140px',
  282. },
  283. {
  284. label: '销售模式',
  285. prop: 'salesModel',
  286. width: '80px',
  287. },
  288. {
  289. label: '经销商/代理商',
  290. prop: 'distributorName',
  291. minWidth: '240px',
  292. width: 'auto',
  293. },
  294. {
  295. label: '产品线',
  296. prop: 'productLine',
  297. width: '140px',
  298. },
  299. {
  300. label: '项目类别',
  301. prop: 'nboType',
  302. width: '80px',
  303. },
  304. {
  305. label: '项目预算',
  306. prop: 'nboBudget',
  307. width: '120px',
  308. },
  309. {
  310. label: '出货金额',
  311. prop: 'estTransPrice',
  312. width: '120px',
  313. },
  314. {
  315. label: '大项目',
  316. prop: 'isBig',
  317. width: '70px',
  318. },
  319. {
  320. label: '最新跟进时间',
  321. prop: 'finalFollowTime',
  322. width: '110px',
  323. },
  324. {
  325. label: '最新跟进人',
  326. prop: 'finalFollowName',
  327. width: '50px',
  328. },
  329. {
  330. label: '项目成交时间',
  331. prop: 'projClosingTime',
  332. width: '110px',
  333. },
  334. {
  335. label: '合同金额',
  336. prop: 'contractAmount',
  337. width: '140px',
  338. },
  339. {
  340. label: '项目转化时间',
  341. prop: 'projConversionTime',
  342. width: '110px',
  343. },
  344. {
  345. label: '转化原因',
  346. prop: 'projConversionReason',
  347. width: '140px',
  348. },
  349. ],
  350. allColumns: [
  351. '项目编码',
  352. '项目名称',
  353. '销售工程师',
  354. '所在省',
  355. '所在市',
  356. '客户名称',
  357. '项目备案时间',
  358. '项目来源',
  359. '销售模式',
  360. '经销商/代理商',
  361. '产品线',
  362. '项目类别',
  363. '项目预算',
  364. '出货金额',
  365. '大项目',
  366. '最新跟进时间',
  367. ],
  368. abcColumns: [
  369. '项目编码',
  370. '项目名称',
  371. '所在省',
  372. '所在市',
  373. '销售工程师',
  374. '客户名称',
  375. '项目备案时间',
  376. '项目来源',
  377. '销售模式',
  378. '经销商/代理商',
  379. '产品线',
  380. '项目预算',
  381. '出货金额',
  382. '大项目',
  383. '最新跟进时间',
  384. '最新跟进',
  385. ],
  386. dealColumns: [
  387. '项目编码',
  388. '项目名称',
  389. '所在省',
  390. '所在市',
  391. '销售工程师',
  392. '客户名称',
  393. '项目备案时间',
  394. '项目来源',
  395. '销售模式',
  396. '经销商/代理商',
  397. '产品线',
  398. '大项目',
  399. '项目成交时间',
  400. '合同金额',
  401. ],
  402. reserveColumns: [
  403. '项目编码',
  404. '项目名称',
  405. '所在省',
  406. '所在市',
  407. '销售工程师',
  408. '客户名称',
  409. '项目备案时间',
  410. '项目来源',
  411. '销售模式',
  412. '经销商/代理商',
  413. '产品线',
  414. '项目转化时间',
  415. '转化原因',
  416. ],
  417. list: [],
  418. listLoading: true,
  419. layout: 'total, sizes, prev, pager, next, jumper',
  420. total: 0,
  421. selectRows: '',
  422. yesOrNoOptions: [],
  423. nboTypeOptions: [],
  424. nboSourceOptions: [],
  425. salesModelOptions: [],
  426. productLineOptions: [],
  427. nboPhaseOptions: [],
  428. nboStatusOptions: [],
  429. approStatusOptions: [],
  430. followup: {},
  431. finallyColumns: [],
  432. provinceOptions: [],
  433. }
  434. },
  435. watch: {
  436. showColumns: function () {
  437. this.tableKey++
  438. this.$nextTick(() => this.$refs.busTable.doLayout())
  439. },
  440. activeName(newValue) {
  441. this.tableType = 'businessTable' + this.selectDictLabel(this.nboTypeOptions, newValue)
  442. switch (newValue) {
  443. case '10':
  444. case '20':
  445. case '30':
  446. this.finallyColumns = this.columns.filter((item) => this.abcColumns.includes(item.label))
  447. break
  448. case '40':
  449. this.finallyColumns = this.columns.filter((item) => this.dealColumns.includes(item.label))
  450. break
  451. case '50':
  452. this.finallyColumns = this.columns.filter((item) => this.reserveColumns.includes(item.label))
  453. break
  454. default:
  455. this.finallyColumns = this.columns.filter((item) => this.allColumns.includes(item.label))
  456. }
  457. },
  458. },
  459. activated() {
  460. this.fetchData()
  461. },
  462. created() {
  463. this.activeName = 'all'
  464. if (this.$route.params && this.$route.params.length > 0) {
  465. this.queryForm = this.$route.params
  466. this.activeName = this.queryForm.activeName ? this.queryForm.activeName : 'all'
  467. }
  468. this.handleTabClick()
  469. this.getOptions()
  470. },
  471. updated() {
  472. if (this.$refs.busTable && this.$refs.busTable.doLayout) {
  473. this.$refs.busTable.doLayout()
  474. }
  475. },
  476. methods: {
  477. getOptions() {
  478. Promise.all([
  479. this.getDicts('proj_nbo_type'),
  480. this.getDicts('proj_nbo_source'),
  481. this.getDicts('proj_sales_model'),
  482. this.getDicts('sys_product_line'),
  483. this.getDicts('sys_yes_no'),
  484. // this.getDicts('proj_nbo_phase'),
  485. // this.getDicts('proj_nbo_status'),
  486. // this.getDicts('proj_appro_status'),
  487. customerApi.getProvinceDetail(),
  488. ])
  489. .then(([nboType, nboSource, salesModel, productLine, yesOrNo, province]) => {
  490. this.nboTypeOptions = nboType.data.values || []
  491. this.nboSourceOptions = nboSource.data.values || []
  492. this.salesModelOptions = salesModel.data.values || []
  493. this.productLineOptions = productLine.data.values || []
  494. this.yesOrNoOptions = yesOrNo.data.values || []
  495. // this.nboPhaseOptions = nboPhase.data.values || []
  496. // this.nboStatusOptions = nboStatus.data.values || []
  497. // this.approStatusOptions = approStatus.data.values || []
  498. this.provinceOptions = province.data.list || []
  499. })
  500. .catch((err) => console.log(err))
  501. },
  502. handleTabClick() {
  503. this.queryForm.pageNum = 1
  504. if (this.activeName !== 'all') {
  505. this.queryForm.nboType = this.activeName
  506. } else {
  507. this.queryForm.nboType = undefined
  508. }
  509. this.$nextTick(() => {
  510. this.$refs['tableTool'].getInitData()
  511. })
  512. this.fetchData()
  513. },
  514. handleTransfer() {
  515. if (this.selectRows.length !== 1) {
  516. this.$baseMessage('请选择一个项目', 'warning')
  517. return
  518. }
  519. this.$refs['transfer'].open(this.selectRows[0])
  520. },
  521. // 跳转详情
  522. handleDetail(row) {
  523. this.queryForm.activeName = this.activeName
  524. this.$router.push({
  525. name: 'BusinessDetail',
  526. query: {
  527. id: row.id,
  528. },
  529. params: this.queryForm,
  530. })
  531. },
  532. handleFollow(row) {
  533. this.followup = {
  534. targetId: row.id,
  535. targetType: '20',
  536. targetName: row.nboName,
  537. custId: row.custId,
  538. custName: row.custName,
  539. contactsId: row.contactId,
  540. contactsName: row.contactName,
  541. }
  542. console.log(this.followup)
  543. this.$refs.follow.showEdit(this.followup)
  544. },
  545. handleEdit(row) {
  546. if (row.id) {
  547. this.$refs['add'].showEdit(row)
  548. } else {
  549. this.$refs['add'].showEdit(row)
  550. }
  551. },
  552. handleDelete(row) {
  553. if (row.id) {
  554. this.$baseConfirm('你确定要删除当前项吗', null, async () => {
  555. const { msg } = await businessApi.doDelete({ ids: [row.id] })
  556. this.$baseMessage(msg, 'success')
  557. await this.fetchData()
  558. })
  559. } else {
  560. if (this.selectRows.length > 0) {
  561. const ids = this.selectRows.map((item) => item.id)
  562. this.$baseConfirm('你确定要删除选中项吗', null, async () => {
  563. const { msg } = await businessApi.doDelete({ ids })
  564. this.$baseMessage(msg, 'success')
  565. await this.fetchData()
  566. })
  567. } else {
  568. this.$baseMessage('未选中任何行', 'error')
  569. return false
  570. }
  571. }
  572. },
  573. handleSizeChange(val) {
  574. this.queryForm.pageSize = val
  575. this.fetchData()
  576. },
  577. handleCurrentChange(val) {
  578. this.queryForm.pageNum = val
  579. this.fetchData()
  580. },
  581. queryData() {
  582. this.queryForm.pageNum = 1
  583. this.fetchData()
  584. },
  585. /** 重置按钮操作 */
  586. resetQuery() {
  587. this.resetForm('queryForm')
  588. this.handleTabClick()
  589. },
  590. setSelectRows(val) {
  591. this.selectRows = val
  592. },
  593. async fetchData() {
  594. if (this.queryForm.filingTime && this.queryForm.filingTime.length === 2) {
  595. this.queryForm.beginTime = this.queryForm.filingTime[0] + ' 00:00:00'
  596. this.queryForm.endTime = this.queryForm.filingTime[1] + ' 23:59:59'
  597. } else {
  598. this.queryForm.beginTime = undefined
  599. this.queryForm.endTime = undefined
  600. }
  601. this.listLoading = true
  602. this.queryForm.provinceId = this.queryForm.custProvince.id
  603. const { data } = await businessApi.getList(this.queryForm)
  604. const { list, total } = data
  605. this.list = list
  606. this.total = total
  607. this.listLoading = false
  608. this.tableKey++
  609. this.$nextTick(() => this.$refs.busTable.doLayout())
  610. },
  611. },
  612. }
  613. </script>