You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

625 lines
18 KiB

  1. <template>
  2. <div class="mod-config">
  3. <!-- 查询条件 -->
  4. <el-form :inline="true" label-position="top" :model="searchData">
  5. <el-form-item label="Customer">
  6. <el-input v-model="searchData.customer" clearable style="width: 120px" @keyup.enter.native="getDataList"></el-input>
  7. </el-form-item>
  8. <el-form-item label="供应商名称">
  9. <el-input v-model="searchData.supplierName" clearable style="width: 140px" @keyup.enter.native="getDataList"></el-input>
  10. </el-form-item>
  11. <el-form-item label="物料编号">
  12. <el-input v-model="searchData.partNo" clearable style="width: 120px" @keyup.enter.native="getDataList"></el-input>
  13. </el-form-item>
  14. <el-form-item label="Buyer">
  15. <el-input v-model="searchData.buyer" clearable style="width: 120px" @keyup.enter.native="getDataList"></el-input>
  16. </el-form-item>
  17. <el-form-item label="PO No">
  18. <el-input v-model="searchData.poNo" clearable style="width: 140px" @keyup.enter.native="getDataList"></el-input>
  19. </el-form-item>
  20. <el-form-item label="SKU">
  21. <el-input v-model="searchData.sku" clearable style="width: 120px" @keyup.enter.native="getDataList"></el-input>
  22. </el-form-item>
  23. <el-form-item label="Status">
  24. <el-select v-model="searchData.status" placeholder="请选择" style="width:100px" clearable>
  25. <el-option label="全部" value=""></el-option>
  26. <el-option label="已下达" value="已下达"></el-option>
  27. <el-option label="已取消" value="已取消"></el-option>
  28. </el-select>
  29. </el-form-item>
  30. </el-form>
  31. <el-form :inline="true" label-position="top" style="margin-top:10px">
  32. <el-form-item>
  33. <el-button type="primary" @click="getDataList">查询</el-button>
  34. <el-button type="primary" @click="exportExcel" style="margin-left: 2px">导出</el-button>
  35. <el-button @click="resetSearch">重置</el-button>
  36. </el-form-item>
  37. </el-form>
  38. <!-- 数据表格 -->
  39. <el-table
  40. ref="poTable"
  41. :height="height"
  42. :data="dataList"
  43. border
  44. highlight-current-row
  45. v-loading="loading"
  46. @row-click="changeData"
  47. style="width: 100%;">
  48. <el-table-column
  49. v-for="(item, index) in visibleColumns"
  50. :key="item.serialNumber || index"
  51. :sortable="item.columnSortable"
  52. :prop="item.columnProp"
  53. :header-align="item.headerAlign"
  54. :show-overflow-tooltip="item.showOverflowTooltip"
  55. :align="item.align"
  56. :fixed="item.fixed === '' ? false : item.fixed"
  57. :min-width="item.columnWidth"
  58. :label="item.columnLabel">
  59. <template slot-scope="scope">
  60. <span>{{ scope.row[item.columnProp] }}</span>
  61. </template>
  62. </el-table-column>
  63. </el-table>
  64. <!-- 分页 -->
  65. <el-pagination
  66. @size-change="sizeChangeHandle"
  67. @current-change="currentChangeHandle"
  68. :current-page="pageIndex"
  69. :page-sizes="[20, 50, 100, 200, 500]"
  70. :page-size="pageSize"
  71. :total="totalPage"
  72. layout="total, sizes, prev, pager, next, jumper">
  73. </el-pagination>
  74. <!-- 详情页签 -->
  75. <el-tabs v-model="activeTab" style="margin-top: 0px; width: 99%;" @tab-click="handleTabClick" class="customer-tab" type="border-card">
  76. <!-- 物流信息 -->
  77. <el-tab-pane label="物流" name="logistics">
  78. <logistics-po-list ref="logisticsPoList" />
  79. </el-tab-pane>
  80. <!-- 验货明细 -->
  81. <el-tab-pane label="验货明细" name="inspectionDetail">
  82. <inspection-detail-list ref="inspectionDetailList" />
  83. </el-tab-pane>
  84. </el-tabs>
  85. </div>
  86. </template>
  87. <script>
  88. import { searchPoDetailPage } from '@/api/order/poOrder.js'
  89. import excel from '@/utils/excel-util.js'
  90. import LogisticsPoList from './com_logisticsPoList.vue'
  91. import InspectionDetailList from './com_inspectionDetailList.vue'
  92. export default {
  93. components: {
  94. LogisticsPoList,
  95. InspectionDetailList
  96. },
  97. name: 'PoOrderQuery',
  98. data() {
  99. return {
  100. loading: false,
  101. exportLoading: false,
  102. height: 400,
  103. activeTab: 'logistics',
  104. pageIndex: 1,
  105. pageSize: 20,
  106. totalPage: 0,
  107. dataList: [],
  108. currentRow: {},
  109. searchData: {
  110. site: this.$store.state.user.site,
  111. customer: '',
  112. buyer: '',
  113. poNo: '',
  114. sku: '',
  115. status: '',
  116. supplierName: '',
  117. partNo: '',
  118. feeDateStart: '',
  119. feeDateEnd: ''
  120. },
  121. // 列配置(与原始页面保持一致,但隐藏编辑相关列)
  122. columnList: [
  123. {
  124. columnProp: 'customer',
  125. columnLabel: 'Customer',
  126. align: 'center',
  127. columnWidth: 100,
  128. showOverflowTooltip: true,
  129. headerAlign: 'center'
  130. },
  131. {
  132. columnProp: 'buyer',
  133. columnLabel: 'Buyer',
  134. align: 'center',
  135. columnWidth: 90,
  136. showOverflowTooltip: true,
  137. headerAlign: 'center'
  138. },
  139. {
  140. columnProp: 'supplierName',
  141. columnLabel: 'Vendor Name',
  142. align: 'center',
  143. columnWidth: 120,
  144. showOverflowTooltip: true,
  145. headerAlign: 'center'
  146. },
  147. {
  148. columnProp: 'shortOffice',
  149. columnLabel: 'V_Short_Office',
  150. align: 'center',
  151. columnWidth: 110,
  152. showOverflowTooltip: true,
  153. headerAlign: 'center'
  154. },
  155. {
  156. columnProp: 'shortNpc',
  157. columnLabel: 'V_Short_NPC',
  158. align: 'center',
  159. columnWidth: 100,
  160. showOverflowTooltip: true,
  161. headerAlign: 'center'
  162. },
  163. {
  164. columnProp: 'poNo',
  165. columnLabel: 'PO_No',
  166. align: 'center',
  167. columnWidth: 120,
  168. showOverflowTooltip: true,
  169. headerAlign: 'center'
  170. },
  171. {
  172. columnProp: 'partNo',
  173. columnLabel: 'Item',
  174. align: 'center',
  175. columnWidth: 90,
  176. showOverflowTooltip: true,
  177. headerAlign: 'center'
  178. },
  179. {
  180. columnProp: 'category',
  181. columnLabel: 'Category',
  182. align: 'center',
  183. columnWidth: 90,
  184. showOverflowTooltip: true,
  185. headerAlign: 'center'
  186. },
  187. {
  188. columnProp: 'sku',
  189. columnLabel: 'SKU',
  190. align: 'center',
  191. columnWidth: 100,
  192. showOverflowTooltip: true,
  193. headerAlign: 'center'
  194. },
  195. {
  196. columnProp: 'price',
  197. columnLabel: 'Unit Price',
  198. align: 'center',
  199. columnWidth: 90,
  200. showOverflowTooltip: true,
  201. headerAlign: 'center'
  202. },
  203. {
  204. columnProp: 'qty',
  205. columnLabel: 'PO Qty',
  206. align: 'center',
  207. columnWidth: 80,
  208. showOverflowTooltip: true,
  209. headerAlign: 'center'
  210. },
  211. {
  212. columnProp: 'value',
  213. columnLabel: 'PO Value',
  214. align: 'center',
  215. columnWidth: 90,
  216. showOverflowTooltip: true,
  217. headerAlign: 'center'
  218. },
  219. {
  220. columnProp: 'shipQty',
  221. columnLabel: 'A-Qty',
  222. align: 'center',
  223. columnWidth: 80,
  224. showOverflowTooltip: true,
  225. headerAlign: 'center'
  226. },
  227. {
  228. columnProp: 'sumPrice',
  229. columnLabel: 'A-Value',
  230. align: 'center',
  231. columnWidth: 90,
  232. showOverflowTooltip: true,
  233. headerAlign: 'center'
  234. },
  235. {
  236. columnProp: 'departure',
  237. columnLabel: 'Departure Port',
  238. align: 'center',
  239. columnWidth: 100,
  240. showOverflowTooltip: true,
  241. headerAlign: 'center'
  242. },
  243. {
  244. columnProp: 'destination',
  245. columnLabel: 'Destination Port',
  246. align: 'center',
  247. columnWidth: 110,
  248. showOverflowTooltip: true,
  249. headerAlign: 'center'
  250. },
  251. {
  252. columnProp: 'shipVia',
  253. columnLabel: 'Method',
  254. align: 'center',
  255. columnWidth: 90,
  256. showOverflowTooltip: true,
  257. headerAlign: 'center'
  258. },
  259. {
  260. columnProp: 'orderDate',
  261. columnLabel: 'Buyer Release Date',
  262. align: 'center',
  263. columnWidth: 130,
  264. showOverflowTooltip: true,
  265. headerAlign: 'center'
  266. },
  267. {
  268. columnProp: 'enquiry',
  269. columnLabel: 'Planner Release Date',
  270. align: 'center',
  271. columnWidth: 140,
  272. showOverflowTooltip: true,
  273. headerAlign: 'center'
  274. },
  275. {
  276. columnProp: 'status',
  277. columnLabel: 'Status',
  278. align: 'center',
  279. columnWidth: 80,
  280. showOverflowTooltip: true,
  281. headerAlign: 'center'
  282. },
  283. {
  284. columnProp: 'confirmed',
  285. columnLabel: 'PI Confirmed Date',
  286. align: 'center',
  287. columnWidth: 120,
  288. showOverflowTooltip: true,
  289. headerAlign: 'center'
  290. },
  291. {
  292. columnProp: 'wantReceiveDate',
  293. columnLabel: 'Original Arrival Date',
  294. align: 'center',
  295. columnWidth: 130,
  296. showOverflowTooltip: true,
  297. headerAlign: 'center'
  298. },
  299. {
  300. columnProp: 'narrival',
  301. columnLabel: 'Final Confirmed Arrival Date',
  302. align: 'center',
  303. columnWidth: 110,
  304. showOverflowTooltip: true,
  305. headerAlign: 'center'
  306. },
  307. {
  308. columnProp: 'crd',
  309. columnLabel: 'PI Confirmed CRD',
  310. align: 'center',
  311. columnWidth: 120,
  312. showOverflowTooltip: true,
  313. headerAlign: 'center'
  314. },
  315. {
  316. columnProp: 'inspection',
  317. columnLabel: 'Inspection Date',
  318. align: 'center',
  319. columnWidth: 100,
  320. showOverflowTooltip: true,
  321. headerAlign: 'center'
  322. },
  323. {
  324. columnProp: 'realCrd',
  325. columnLabel: 'Actual Completion Date',
  326. align: 'center',
  327. columnWidth: 150,
  328. showOverflowTooltip: true,
  329. headerAlign: 'center'
  330. },
  331. {
  332. columnProp: 'eta',
  333. columnLabel: 'ETA',
  334. align: 'center',
  335. columnWidth: 100,
  336. showOverflowTooltip: true,
  337. headerAlign: 'center'
  338. },
  339. {
  340. columnProp: 'flexid',
  341. columnLabel: 'Flexport Id',
  342. align: 'center',
  343. columnWidth: 90,
  344. showOverflowTooltip: true,
  345. headerAlign: 'center'
  346. },
  347. {
  348. columnProp: 'obd',
  349. columnLabel: 'On Board Date',
  350. align: 'center',
  351. columnWidth: 100,
  352. showOverflowTooltip: true,
  353. headerAlign: 'center'
  354. },
  355. {
  356. columnProp: 'docSent',
  357. columnLabel: 'Doc Sent',
  358. align: 'center',
  359. columnWidth: 90,
  360. showOverflowTooltip: true,
  361. headerAlign: 'center'
  362. },
  363. {
  364. columnProp: 'telexRelease',
  365. columnLabel: 'Telex Release',
  366. align: 'center',
  367. columnWidth: 100,
  368. showOverflowTooltip: true,
  369. headerAlign: 'center'
  370. },
  371. {
  372. columnProp: 'advancePayment',
  373. columnLabel: 'Advance Payment',
  374. align: 'center',
  375. columnWidth: 120,
  376. showOverflowTooltip: true,
  377. headerAlign: 'center'
  378. },
  379. {
  380. columnProp: 'advancePaid',
  381. columnLabel: 'Advanc Paid',
  382. align: 'center',
  383. columnWidth: 100,
  384. showOverflowTooltip: true,
  385. headerAlign: 'center'
  386. },
  387. {
  388. columnProp: 'createTime',
  389. columnLabel: 'Create Date',
  390. align: 'center',
  391. columnWidth: 100,
  392. showOverflowTooltip: true,
  393. headerAlign: 'center'
  394. },
  395. {
  396. columnProp: 'planner',
  397. columnLabel: 'M-Planner',
  398. align: 'center',
  399. columnWidth: 100,
  400. showOverflowTooltip: true,
  401. headerAlign: 'center'
  402. },
  403. {
  404. columnProp: 'edit',
  405. columnLabel: 'Edit Date',
  406. align: 'center',
  407. columnWidth: 100,
  408. showOverflowTooltip: true,
  409. headerAlign: 'center'
  410. },
  411. {
  412. columnProp: 'endPlanner',
  413. columnLabel: 'Last Editor',
  414. align: 'center',
  415. columnWidth: 100,
  416. showOverflowTooltip: true,
  417. headerAlign: 'center'
  418. },
  419. {
  420. columnProp: 'remarkDelay',
  421. columnLabel: 'Remark Delay',
  422. align: 'center',
  423. columnWidth: 110,
  424. showOverflowTooltip: true,
  425. headerAlign: 'center'
  426. },
  427. {
  428. columnProp: 'remark',
  429. columnLabel: 'Comments',
  430. align: 'center',
  431. columnWidth: 140,
  432. showOverflowTooltip: true,
  433. headerAlign: 'center'
  434. }
  435. ]
  436. }
  437. },
  438. computed: {
  439. visibleColumns() {
  440. return this.columnList.filter(c => !c.columnHidden)
  441. }
  442. },
  443. created() {
  444. this.getDataList()
  445. },
  446. mounted() {
  447. this.$nextTick(() => {
  448. // 模仿 supplierList.vue 的高度分配方式
  449. this.height = (window.innerHeight - 220) / 2
  450. })
  451. },
  452. methods: {
  453. // 查询数据
  454. getDataList() {
  455. this.loading = true
  456. const params = {
  457. ...this.searchData,
  458. page: this.pageIndex,
  459. limit: this.pageSize
  460. }
  461. searchPoDetailPage(params).then(({ data }) => {
  462. if (data.code === 0) {
  463. this.dataList = data.page.list || []
  464. this.pageIndex = data.page.currPage
  465. this.pageSize = data.page.pageSize
  466. this.totalPage = data.page.totalCount
  467. // 如果有数据,默认选中第一行并触发页签查询
  468. if (this.dataList.length > 0) {
  469. this.$nextTick(() => {
  470. if (this.$refs.poTable) {
  471. this.$refs.poTable.setCurrentRow(this.dataList[0])
  472. }
  473. this.changeData(this.dataList[0])
  474. })
  475. }
  476. } else {
  477. this.$message.error((data && data.msg) || '获取列表失败')
  478. }
  479. this.loading = false
  480. }).catch(() => {
  481. this.loading = false
  482. this.$message.error('请求失败')
  483. })
  484. },
  485. // 重置查询条件
  486. resetSearch() {
  487. this.searchData = {
  488. site: this.$store.state.user.site,
  489. customer: '',
  490. buyer: '',
  491. poNo: '',
  492. sku: '',
  493. status: '',
  494. supplierName: '',
  495. partNo: '',
  496. feeDateStart: '',
  497. feeDateEnd: ''
  498. }
  499. this.pageIndex = 1
  500. this.getDataList()
  501. },
  502. // 导出
  503. exportExcel () {
  504. console.log('开始导出...')
  505. // 生成文件名
  506. const now = new Date()
  507. const year = now.getFullYear()
  508. const month = String(now.getMonth() + 1).padStart(2, '0')
  509. const day = String(now.getDate()).padStart(2, '0')
  510. const hour = String(now.getHours()).padStart(2, '0')
  511. const minute = String(now.getMinutes()).padStart(2, '0')
  512. const second = String(now.getSeconds()).padStart(2, '0')
  513. const exportName = `PO订单列表${year}${month}${day}${hour}${minute}${second}`
  514. // 获取当前查询条件
  515. const exportParams = {
  516. ...this.searchData,
  517. limit: 99999,
  518. page: 1
  519. }
  520. console.log('导出参数:', exportParams)
  521. try {
  522. excel.exportTable({
  523. url: 'pODetail/page',
  524. columnMapping: this.visibleColumns,
  525. mergeSetting: [],
  526. params: exportParams,
  527. fileName: exportName + '.xlsx',
  528. rowFetcher: res => {
  529. console.log('导出接口响应:', res)
  530. // 接口返回 {code, msg, rows} 结构
  531. return { rows: (res.data && res.data.rows) || [] }
  532. },
  533. columnFormatter: [],
  534. dropColumns: []
  535. })
  536. console.log('导出请求已发送')
  537. } catch (error) {
  538. console.error('导出失败:', error)
  539. this.$message.error('导出失败: ' + error.message)
  540. }
  541. },
  542. // 每页数
  543. sizeChangeHandle(val) {
  544. this.pageSize = val
  545. this.pageIndex = 1
  546. this.getDataList()
  547. },
  548. // 当前页
  549. currentChangeHandle(val) {
  550. this.pageIndex = val
  551. this.getDataList()
  552. },
  553. // 行点击事件(模仿 supplierList.vue 的 changeData 模式)
  554. changeData(row) {
  555. this.currentRow = JSON.parse(JSON.stringify(row))
  556. this.refreshCurrentTabTable()
  557. },
  558. // 刷新当前页签的表格数据(模仿 supplierList.vue 的 refreshCurrentTabTable)
  559. refreshCurrentTabTable() {
  560. if (this.currentRow === '' || this.currentRow === null) {
  561. this.currentRow = { flexid: '', supplierNo: '' }
  562. }
  563. if (this.activeTab === 'logistics') {
  564. this.refreshLogisticsTable()
  565. }
  566. if (this.activeTab === 'inspectionDetail') {
  567. this.refreshInspectionTable()
  568. }
  569. },
  570. // 刷新物流页签表格(模仿 supplierList.vue 的 refreshShareTable)
  571. refreshLogisticsTable() {
  572. let inData = {
  573. flexId: this.currentRow.flexid,
  574. supplierNo: this.currentRow.supplierNo,
  575. site: this.$store.state.user.site,
  576. height: Number(this.height) - 20
  577. }
  578. this.$refs.logisticsPoList.init(inData)
  579. },
  580. // 刷新验货明细页签表格
  581. refreshInspectionTable() {
  582. let inData = {
  583. site: this.$store.state.user.site,
  584. orderRef1: this.currentRow.poNo || '',
  585. height: Number(this.height) - 20
  586. }
  587. this.$refs.inspectionDetailList.init(inData)
  588. },
  589. // 页签点击事件(模仿 supplierList.vue 的 tabClick)
  590. handleTabClick(tab, event) {
  591. this.refreshCurrentTabTable()
  592. }
  593. }
  594. }
  595. </script>
  596. <style scoped lang="scss">
  597. .el-table /deep/ .cell {
  598. height: auto;
  599. line-height: 1.5;
  600. }
  601. /deep/ .customer-tab .el-tabs__content {
  602. padding: 5px !important;
  603. }
  604. </style>