index.vue 19 KB

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