index.vue 20 KB

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