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.

1297 lines
44 KiB

  1. <template>
  2. <div class="customer-css">
  3. <!-- 查询条件 -->
  4. <el-form :inline="true" label-position="top" class="pi-search-form">
  5. <el-form-item :label="'询价单号'">
  6. <el-input v-model="searchData.orderNo" placeholder="询价单号" style="width:160px" @keyup.enter.native="getList" clearable />
  7. </el-form-item>
  8. <el-form-item :label="'供应商编码'">
  9. <el-input v-model="searchData.supplierId" placeholder="供应商编码" style="width:160px" @keyup.enter.native="getList" clearable />
  10. </el-form-item>
  11. <el-form-item :label="'供应商名称'">
  12. <el-input v-model="searchData.supplierName" placeholder="供应商名称" style="width:200px" @keyup.enter.native="getList" clearable />
  13. </el-form-item>
  14. <el-form-item :label="'状态'">
  15. <el-select v-model="searchData.status" placeholder="请选择" style="width:100px" clearable>
  16. <el-option label="全部" value="" />
  17. <el-option label="已计划" value="已计划" />
  18. <el-option label="已下达" value="已下达" />
  19. </el-select>
  20. </el-form-item>
  21. <el-form-item label=" ">
  22. <el-button type="primary" class="customer-bun-min" @click="getList">查询</el-button>
  23. <el-button type="primary" class="customer-bun-min" @click="openDialog()">新增</el-button>
  24. </el-form-item>
  25. </el-form>
  26. <!-- 主表询价单列表 -->
  27. <el-table :data="dataList" :height="tableHeight" border highlight-current-row @row-click="selectInquiry" v-loading="loading" style="width:100%">
  28. <el-table-column fixed="right" label="操作" header-align="center" align="center" width="140">
  29. <template slot-scope="scope">
  30. <a class="customer-a" @click.stop="openDialog(scope.row)">编辑 |</a>
  31. <a class="customer-a" @click.stop="handleDelete(scope.row)">删除</a>
  32. <a class="customer-a" @click="updateQuoDetail(scope.row)">提交</a>
  33. </template>
  34. </el-table-column>
  35. <el-table-column prop="orderNo" label="询价单号" min-width="140" header-align="center" align="left" show-overflow-tooltip fixed="left" />
  36. <el-table-column prop="supplierId" label="供应商编码" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  37. <el-table-column prop="supplierName" label="供应商名称" min-width="180" header-align="center" align="left" show-overflow-tooltip />
  38. <el-table-column prop="orderDate" label="询价日期" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  39. <el-table-column prop="wantReplyDate" label="要求报价日期" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  40. <el-table-column prop="userName" label="录入人" min-width="100" header-align="center" align="center" show-overflow-tooltip />
  41. <el-table-column prop="buyer" label="采购员" min-width="100" header-align="center" align="center" show-overflow-tooltip />
  42. <el-table-column prop="paymentTermDesc" label="付款方式" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  43. <el-table-column prop="deliveryTermDesc" label="交易条款" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  44. <el-table-column prop="currency" label="货币" min-width="80" header-align="center" align="center" show-overflow-tooltip />
  45. <el-table-column prop="currencyRate" label="货币汇率" min-width="100" header-align="center" align="center" show-overflow-tooltip />
  46. <el-table-column prop="taxRate" label="税率" min-width="80" header-align="center" align="center" show-overflow-tooltip />
  47. <el-table-column prop="otherCondition" label="其他要求" min-width="180" header-align="center" align="left" show-overflow-tooltip />
  48. <el-table-column prop="phoneNo" label="电话号码" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  49. <el-table-column prop="faxNo" label="传真" min-width="120" header-align="center" align="center" show-overflow-tooltip />
  50. <el-table-column prop="contact" label="联系人" min-width="100" header-align="center" align="center" show-overflow-tooltip />
  51. <el-table-column prop="remark" label="备注" min-width="180" header-align="center" align="left" show-overflow-tooltip />
  52. <el-table-column prop="status" label="状态" min-width="80" header-align="center" align="center" show-overflow-tooltip />
  53. </el-table>
  54. <!-- 分页 -->
  55. <el-pagination
  56. style="margin-top:5px"
  57. @size-change="sizeChangeHandle"
  58. @current-change="currentChangeHandle"
  59. :current-page="pageIndex"
  60. :page-sizes="[20,50,100,200]"
  61. :page-size="pageSize"
  62. :total="totalPage"
  63. layout="total, sizes, prev, pager, next, jumper" />
  64. <!-- 子表物料明细列表 - 始终显示表头 -->
  65. <div class="sub-title">
  66. 物料明细列表
  67. <el-button type="primary" class="customer-bun-min" @click="openMaterialDialog()" style="margin-left: 10px;">新增物料</el-button>
  68. </div>
  69. <el-table
  70. :data="materialList"
  71. :height="subTableHeight"
  72. border
  73. v-loading="materialLoading"
  74. style="width:100%">
  75. <el-table-column fixed="right" label="操作" header-align="center" align="center" width="120">
  76. <template slot-scope="scope">
  77. <a class="material-action-btn" @click="openMaterialDialog(scope.row)">编辑</a>
  78. <a class="material-action-btn" @click="deleteMaterial(scope.row)">删除</a>
  79. <a class="material-action-btn" @click="openUploadDialog(scope.row)">附件</a>
  80. </template>
  81. </el-table-column>
  82. <el-table-column prop="partNo" label="物料编码" min-width="130" header-align="center" align="center" show-overflow-tooltip />
  83. <el-table-column prop="partDesc" label="物料名称" min-width="150" header-align="center" align="left" show-overflow-tooltip />
  84. <el-table-column prop="umid" label="计量单位" min-width="80" header-align="center" align="center" />
  85. <el-table-column prop="spec" label="规格型号" min-width="150" header-align="center" align="left" show-overflow-tooltip />
  86. <el-table-column prop="qty" label="询价数量" min-width="100" header-align="center" align="right">
  87. <template slot-scope="scope">{{ scope.row.qty || 0 }}</template>
  88. </el-table-column>
  89. <el-table-column prop="remark2" label="特殊要求" min-width="150" header-align="center" align="left" show-overflow-tooltip>
  90. <template slot-scope="scope">{{ scope.row.remark2 || '-' }}</template>
  91. </el-table-column>
  92. <el-table-column prop="status" label="状态" min-width="80" header-align="center" align="center">
  93. <template slot-scope="scope">{{ scope.row.status }}
  94. <!-- <span :class="'status-badge ' + (scope.row.status === 'Y' ? 'status-sent' : 'status-closed')">{{ scope.row.status === 'Y' ? '启用' : '停用' }}</span> -->
  95. </template>
  96. </el-table-column>
  97. </el-table>
  98. <!-- 空数据提示 -->
  99. <div v-if="materialList.length === 0 && !materialLoading" style="margin-top: 8px; color: #909399; font-size: 12px; text-align: center;">
  100. {{ currentInquiry ? '暂无物料数据' : '请点击左侧询价单查看物料明细' }}
  101. </div>
  102. <!-- 新增/编辑 询价单弹窗 -->
  103. <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="700px" :close-on-click-modal="false" append-to-body>
  104. <el-form label-position="top" class="pi-form" :model="form" label-width="120px">
  105. <el-row :gutter="20">
  106. <el-col :span="12">
  107. <el-form-item>
  108. <span style="cursor: pointer" slot="label" @click="getBaseList(520)"><a href="javascript:void(0)">供应商编码</a></span>
  109. <el-input v-model="form.supplierId" @change="handleSupplierIdChange" />
  110. </el-form-item>
  111. </el-col>
  112. <el-col :span="12">
  113. <el-form-item label="供应商名称" :required="true">
  114. <el-input v-model="form.supplierName"/>
  115. </el-form-item>
  116. </el-col>
  117. </el-row>
  118. <el-row :gutter="20">
  119. <el-col :span="12">
  120. <el-form-item label="询价日期">
  121. <el-date-picker v-model="form.orderDate" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width:100%" />
  122. </el-form-item>
  123. </el-col>
  124. <el-col :span="12">
  125. <el-form-item label="要求报价日期">
  126. <el-date-picker v-model="form.wantReplyDate" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width:100%" />
  127. </el-form-item>
  128. </el-col>
  129. </el-row>
  130. <el-row :gutter="20">
  131. <el-col :span="12">
  132. <el-form-item label="货币汇率">
  133. <el-input-number v-model="form.currencyRate" :precision="4" :step="0.1" style="width:100%" />
  134. </el-form-item>
  135. </el-col>
  136. <el-col :span="6">
  137. <el-form-item label="税率(%)">
  138. <!-- <el-input-number v-model="form.taxRate" :precision="2" :step="1" style="width:100%" /> -->
  139. <el-select v-model="taxForm.taxRate" placeholder="请选择" clearable>
  140. <el-option
  141. v-for = "t in taxList"
  142. :key = "t.taxCode"
  143. :label = "t.taxRate"
  144. :value = "t.taxRate">
  145. </el-option>
  146. </el-select>
  147. </el-form-item>
  148. </el-col>
  149. <el-col :span="6">
  150. <el-form-item label="货币">
  151. <!-- <el-input-number v-model="form.taxRate" :precision="2" :step="1" style="width:100%" /> -->
  152. <el-select v-model="currencyForm.currency" placeholder="请选择" clearable>
  153. <el-option
  154. v-for = "t in currencyList"
  155. :key = "t.currency"
  156. :label = "t.currencyDesc"
  157. :value = "t.currency">
  158. </el-option>
  159. </el-select>
  160. </el-form-item>
  161. </el-col>
  162. </el-row>
  163. <el-row :gutter="20">
  164. <el-col :span="6">
  165. <el-form-item>
  166. <span style="cursor: pointer" slot="label" @click="getBaseList(529)"><a href="javascript:void(0)">采购员</a></span>
  167. <el-input v-model="form.buyer" style="width: 130px" />
  168. </el-form-item>
  169. </el-col>
  170. <el-col :span="6">
  171. <el-form-item label="付款方式">
  172. <!-- <el-input v-model="form.paymentTermDesc" /> -->
  173. <el-select v-model="paymentForm.paymentTerm" placeholder="请选择" clearable>
  174. <el-option
  175. v-for = "t in paymentList"
  176. :key = "t.paymentTermId"
  177. :label = "t.paymentTerm"
  178. :value = "t.paymentTermId">
  179. </el-option>
  180. </el-select>
  181. </el-form-item>
  182. </el-col>
  183. <el-col :span="12">
  184. <el-form-item label="交易条款">
  185. <!-- <el-input v-model="form.deliveryTermDesc" /> -->
  186. <el-select v-model="deliveryForm.deliveryTermId" placeholder="请选择" clearable style="width: 100%">
  187. <el-option
  188. v-for = "t in deliveryList"
  189. :key = "t.deliveryTermId"
  190. :label = "t.deliveryTerm"
  191. :value = "t.deliveryTermId">
  192. </el-option>
  193. </el-select>
  194. </el-form-item>
  195. </el-col>
  196. </el-row>
  197. <el-row :gutter="20">
  198. <el-col :span="6">
  199. <el-form-item label="电话号码">
  200. <el-input v-model="form.phoneNo" />
  201. </el-form-item>
  202. </el-col>
  203. <el-col :span="6">
  204. <el-form-item label="传真">
  205. <el-input v-model="form.faxNo" />
  206. </el-form-item>
  207. </el-col>
  208. <el-col :span="6">
  209. <el-form-item label="联系人">
  210. <el-input v-model="form.contact" />
  211. </el-form-item>
  212. </el-col>
  213. </el-row>
  214. <el-row :gutter="20">
  215. <el-col :span="24">
  216. <el-form-item label="其他要求">
  217. <el-input v-model="form.otherCondition" />
  218. </el-form-item>
  219. </el-col>
  220. </el-row>
  221. <el-row :gutter="20">
  222. <el-col :span="24">
  223. <el-form-item label="备注">
  224. <el-input type="textarea" v-model="form.remark" :rows="2" />
  225. </el-form-item>
  226. </el-col>
  227. </el-row>
  228. </el-form>
  229. <div slot="footer" class="dialog-footer" style="margin-top: 20px">
  230. <el-button type="primary" @click="submitForm" :loading="submitLoading">保存</el-button>
  231. <el-button @click="dialogVisible=false">取消</el-button>
  232. </div>
  233. </el-dialog>
  234. <!-- 物料明细新增/编辑弹窗 -->
  235. <el-dialog :title="materialDialogTitle" :visible.sync="materialDialogVisible" width="700px" :close-on-click-modal="false" append-to-body>
  236. <el-form label-position="top" class="pi-form" :model="materialForm">
  237. <el-row :gutter="20">
  238. <el-col :span="12">
  239. <el-form-item >
  240. <span style="cursor: pointer" slot="label" @click="getBaseList(507)"><a href="#">物料编码</a></span>
  241. <el-input v-model="materialForm.partNo" placeholder="请输入物料编码" @change="handlePartNoChange"/>
  242. </el-form-item>
  243. </el-col>
  244. <el-col :span="12">
  245. <el-form-item label="物料名称" required>
  246. <el-input v-model="materialForm.partDesc" placeholder="请输入物料名称" />
  247. </el-form-item>
  248. </el-col>
  249. </el-row>
  250. <el-row :gutter="20">
  251. <el-col :span="12">
  252. <el-form-item label="规格型号">
  253. <el-input v-model="materialForm.spec" placeholder="规格型号" />
  254. </el-form-item>
  255. </el-col>
  256. <el-col :span="6">
  257. <el-form-item >
  258. <span style="cursor: pointer" slot="label" @click="getBaseList(510)"><a href="#">计量单位</a></span>
  259. <el-input v-model="materialForm.umid" placeholder="计量单位" />
  260. </el-form-item>
  261. </el-col>
  262. <el-col :span="6">
  263. <el-form-item label="询价数量">
  264. <el-input-number v-model="materialForm.qty" :min="0" :precision="0" style="width:100%" />
  265. </el-form-item>
  266. </el-col>
  267. </el-row>
  268. <el-row :gutter="20">
  269. <el-col :span="24">
  270. <el-form-item label="特殊要求">
  271. <el-input type="textarea" v-model="materialForm.remark2" :rows="2" placeholder="特殊要求" />
  272. </el-form-item>
  273. </el-col>
  274. </el-row>
  275. </el-form>
  276. <div slot="footer" class="dialog-footer" style="margin-top: 20px">
  277. <el-button type="primary" @click="saveMaterial" :loading="materialSubmitLoading">保存</el-button>
  278. <el-button @click="materialDialogVisible=false">取消</el-button>
  279. </div>
  280. </el-dialog>
  281. <el-dialog
  282. :title="dialogTitle"
  283. :visible.sync="uploadDialogVisible"
  284. width="800px"
  285. :close-on-click-modal="false"
  286. append-to-body
  287. @close="handleClose">
  288. <div class="customer-css">
  289. <!-- 上传按钮 -->
  290. <el-form label-position="top" style="margin-top: -5px;">
  291. <el-row style="margin-top: 10px">
  292. <el-col :span="4">
  293. <el-button class="customer-bun-min" type="primary" @click="handleUpload">Upload</el-button>
  294. </el-col>
  295. </el-row>
  296. <!-- 文件列表表格 -->
  297. <el-table
  298. :height="240"
  299. :data="fileList"
  300. ref="fileTableRef"
  301. style="width: 100%; margin-top: 10px;">
  302. <el-table-column
  303. prop="fileName"
  304. header-align="center"
  305. align="left"
  306. min-width="200"
  307. label="File">
  308. </el-table-column>
  309. <el-table-column
  310. prop="createdBy"
  311. header-align="center"
  312. align="center"
  313. min-width="100"
  314. label="Upload By">
  315. </el-table-column>
  316. <el-table-column
  317. prop="createDate"
  318. header-align="center"
  319. align="center"
  320. min-width="100"
  321. label="Upload Time">
  322. </el-table-column>
  323. <el-table-column
  324. header-align="center"
  325. align="center"
  326. width="100"
  327. fixed="right"
  328. label="Actions">
  329. <template slot-scope="scope">
  330. <a type="text" size="small" v-if="scope.row.id" @click="handleDownload(scope.row)">View |</a>
  331. <a type="text" size="small" v-if="scope.row.id" @click="deleteFileReal(scope.row)"> delete</a>
  332. <a type="text" size="small" v-else @click="deleteFile(scope.$index)"> delete</a>
  333. </template>
  334. </el-table-column>
  335. </el-table>
  336. </el-form>
  337. </div>
  338. <!-- File Upload Dialog -->
  339. <el-dialog
  340. title="UpLoad"
  341. :visible.sync="ossVisible"
  342. v-drag
  343. width="400px"
  344. append-to-body
  345. :close-on-click-modal="false"
  346. @close="handleUploadClose">
  347. <el-form ref="form" class="rq" label-width="80px" label-position="top">
  348. <el-row :gutter="10">
  349. <slot></slot>
  350. <el-col :span="24">
  351. <el-form-item label=" " class="auto">
  352. <el-upload
  353. drag
  354. :file-list="fileList2"
  355. action="#"
  356. ref="upload"
  357. :on-remove="onRemoveFile"
  358. :on-change="onChangeFile"
  359. multiple
  360. :auto-upload="false">
  361. <i class="el-icon-upload"></i>
  362. <div class="el-upload__text">Drag files here, or<em> click to upload</em></div>
  363. </el-upload>
  364. </el-form-item>
  365. </el-col>
  366. <el-col :span="24">
  367. <el-form-item label="Remark" class="auto">
  368. <el-input type="textarea" v-model="ossForm.remark" resize="none" :autosize="{minRows: 3, maxRows: 3}"></el-input>
  369. </el-form-item>
  370. </el-col>
  371. </el-row>
  372. </el-form>
  373. <span slot="footer" class="dialog-footer">
  374. <el-button type="primary" :loading="uploadLoading" @click="submitData">Confirm</el-button>
  375. <el-button @click="ossVisible = false">Close</el-button>
  376. </span>
  377. </el-dialog>
  378. <div slot="footer" class="dialog-footer">
  379. <el-button @click="uploadDialogVisible = false">关闭</el-button>
  380. </div>
  381. </el-dialog>
  382. <Chooselist ref="baseList" @getBaseData="getBaseData" />
  383. </div>
  384. </template>
  385. <script>
  386. import Chooselist from '@/views/modules/common/Chooselist_eam'
  387. import {
  388. searchPurHeaderList,
  389. createPurHeader,
  390. updatePurHeader,
  391. deletePurHeader,
  392. searchMaterialList,
  393. createMaterial,
  394. updateMaterial,
  395. deleteMaterial,
  396. updatePurDetailStatus
  397. } from '@/api/supplier/purQuotation.js'
  398. import {
  399. getSupplierInfo
  400. } from '@/api/srm/srmSupplier.js'
  401. import {
  402. ossUploadNoSaveOSSForYJY,
  403. queryOssFilePlus,
  404. removeOss,
  405. downLoadObjectFile
  406. } from "../../../api/oss/oss";
  407. import {
  408. searchTaxList
  409. } from "@/api/base/tax.js";
  410. import {
  411. searchCurrencyList
  412. } from "@/api/base/currency.js";
  413. import {
  414. searchPaymentList
  415. } from "@/api/base/paymentTerm.js";
  416. import {
  417. searchDeliveryList
  418. } from "@/api/base/deliveryTerm.js";
  419. // 添加物料信息查询接口
  420. import {
  421. searchPartInfo
  422. } from '@/api/part/partInfo.js'
  423. export default {
  424. components: {
  425. Chooselist
  426. },
  427. name: 'InquiryList',
  428. data() {
  429. return {
  430. tableHeight: 200,
  431. subTableHeight: 200,
  432. loading: false,
  433. submitLoading: false,
  434. materialLoading: false,
  435. materialSubmitLoading: false,
  436. taxLoading: false,
  437. currencyLoading: false,
  438. pamentLoading: false,
  439. deliveryLoading: false,
  440. dataList: [],
  441. pageIndex: 1,
  442. pageSize: 20,
  443. totalPage: 0,
  444. searchData: {
  445. site: this.$store.state.user.site,
  446. orderNo: '',
  447. supplierId: '',
  448. supplierName: '',
  449. status: ''
  450. },
  451. taxList: [],
  452. taxForm: {
  453. taxRate: '',
  454. taxCode: null,
  455. taxDesc: ''
  456. },
  457. currencyList: [],
  458. currencyForm: {
  459. currency: '',
  460. currencyDesc: ''
  461. },
  462. paymentList: [],
  463. paymentForm: {
  464. paymentTermId: '',
  465. paymentTerm: ''
  466. },
  467. deliveryList: [],
  468. deliveryForm: {
  469. deliveryTermId:'',
  470. deliveryTerm:''
  471. },
  472. dialogVisible: false,
  473. dialogTitle: '新增询价单',
  474. editMode: false,
  475. form: {
  476. id: '',
  477. paymentTermDesc: '',
  478. deliveryTermDesc: '',
  479. currency: '',
  480. orderNo: '',
  481. supplierId: '',
  482. supplierName: '',
  483. orderDate: '',
  484. wantReplyDate: '',
  485. userName: '',
  486. buyer: '',
  487. currencyRate: 1,
  488. taxRate: 0,
  489. taxCode:'',
  490. otherCondition: '',
  491. phoneNo: '',
  492. faxNo: '',
  493. contact: '',
  494. remark: '',
  495. printed : "N",
  496. status: '已计划'
  497. },
  498. // 物料子表相关
  499. currentInquiry: null,
  500. materialList: [],
  501. materialDialogVisible: false,
  502. materialDialogTitle: '新增物料',
  503. materialForm: {
  504. id: null,
  505. site: this.$store.state.user.site,
  506. partNo: '',
  507. partDesc: '',
  508. umid: '',
  509. spec: '',
  510. qty: 0,
  511. remark2: '',
  512. status: '待提交'
  513. },
  514. searchParams: {
  515. orderRef1: '',
  516. orderRef2: '',
  517. orderRef3: '',
  518. orderReftype: ''
  519. },
  520. fileList: [],
  521. fileList2: [],
  522. ossVisible: false,
  523. ossForm: {
  524. remark: '',
  525. },
  526. uploadLoading: false,
  527. // staged files selected in upload dialog but not yet persisted
  528. stagedFiles: [],
  529. stagedFileRemark: '',
  530. uploadDialogTitle: '上传附件',
  531. uploadDialogVisible: false,
  532. tagNo: null,
  533. tagNo1: null
  534. }
  535. },
  536. mounted() {
  537. this.$nextTick(() => {
  538. this.tableHeight = (window.innerHeight - 250) / 2
  539. this.subTableHeight = (window.innerHeight - 250) / 2
  540. })
  541. // this.calcHeight()
  542. // window.addEventListener('resize', this.calcHeight)
  543. this.getList()
  544. this.getTaxList()
  545. this.getCurrencyList()
  546. this.getPamentList()
  547. this.getDeliveryList()
  548. },
  549. beforeDestroy() {
  550. // window.removeEventListener('resize', this.calcHeight)
  551. },
  552. methods: {
  553. // calcHeight() {
  554. // this.$nextTick(() => {
  555. // this.tableHeight = window.innerHeight - 360
  556. // this.subTableHeight = 220
  557. // })
  558. // },
  559. getBaseList(val, type) {
  560. this.tagNo = val
  561. this.tagNo1 = type
  562. this.$nextTick(() => {
  563. let strVal = ''
  564. if (val === 520) {
  565. if(type == 1) {
  566. strVal = this.form.supplierId
  567. }
  568. }
  569. if (val === 529) {
  570. strVal = this.form.buyer
  571. }
  572. if(val === 507) {
  573. strVal = this.form.part_spec
  574. }
  575. if (val === 510) {
  576. strVal = this.form.unit
  577. }
  578. this.$refs.baseList.init(val, strVal?strVal:'')
  579. })
  580. },
  581. getBaseData(val) {
  582. if (this.tagNo === 520) {
  583. this.form.supplierId = val.supplier_no
  584. this.form.supplierName = val.supplier_name
  585. this.searchSupplierInfo()
  586. }
  587. if (this.tagNo === 529) {
  588. this.form.buyer = val.UserName
  589. }
  590. if(this.tagNo === 507) {
  591. this.materialForm.partNo = val.part_no
  592. this.materialForm.partDesc = val.part_desc
  593. this.materialForm.spec = val.part_spec
  594. this.materialForm.umid = val.unit
  595. this.getPartInfo()
  596. }
  597. if (this.tagNo === 510) {
  598. this.materialForm.umid = val.UMID
  599. }
  600. },
  601. // 供应商编码变化时触发,自动带出供应商信息
  602. handleSupplierIdChange(val) {
  603. if (!val || val.trim() === '') {
  604. return
  605. }
  606. // 调用查询供应商信息接口
  607. const params = {
  608. site: this.$store.state.user.site,
  609. supplierNo: val.trim()
  610. }
  611. this.searchSupplierInfo()
  612. },
  613. searchSupplierInfo() {
  614. const params = {
  615. site: this.$store.state.user.site,
  616. supplierNo: this.form.supplierId
  617. }
  618. getSupplierInfo(params).then(({data}) => {
  619. if (data.code === 0) {
  620. this.form.supplierId = data.row.supplierId || this.form.supplierId
  621. this.form.supplierName = data.row.supplierName || this.form.supplierName
  622. this.form.phoneNo = data.row.phoneNo || this.form.phoneNo
  623. this.form.faxNo = data.row.faxNo || this.form.faxNo
  624. this.form.contact = data.row.contact || this.form.contact
  625. this.taxForm.taxRate = data.row.taxRate || this.taxForm.taxRate
  626. this.taxForm.taxCode = data.row.taxCode || this.taxForm.taxCode
  627. this.paymentForm.paymentTermId = data.row.paymentTerm || this.paymentForm.paymentTermId
  628. this.paymentForm.paymentTerm = data.row.paymentTermDesc || this.paymentForm.paymentTerm
  629. this.deliveryForm.deliveryTermId = data.row.deliveryTerm || this.deliveryForm.deliveryTermId
  630. this.deliveryForm.deliveryTerm = data.row.deliveryTermDesc || this.deliveryForm.deliveryTerm
  631. this.currencyForm.currency = data.row.currency || this.currencyForm.currency
  632. } else {
  633. this.$message.error((data && data.msg) || '获取列表失败')
  634. }
  635. }).catch(() => {
  636. this.$message.error('请求失败')
  637. })
  638. },
  639. getList() {
  640. this.loading = true
  641. const params = {
  642. ...this.searchData,
  643. limit: this.pageSize,
  644. page: this.pageIndex
  645. }
  646. searchPurHeaderList(params).then(({data}) => {
  647. if (data.code === 0) {
  648. this.dataList = data.page.list
  649. this.totalPage = data.page.totalCount
  650. // 保留选中状态
  651. if (this.currentInquiry) {
  652. const exists = this.dataList.some(item => item.orderNo === this.currentInquiry.orderNo)
  653. if (exists) {
  654. this.selectInquiry(this.currentInquiry)
  655. } else {
  656. this.materialList = []
  657. this.currentInquiry = null
  658. }
  659. } else if (this.dataList.length > 0 && !this.currentInquiry) {
  660. this.selectInquiry(this.dataList[0])
  661. }
  662. } else {
  663. this.$message.error((data && data.msg) || '获取列表失败')
  664. }
  665. this.loading = false
  666. }).catch(() => {
  667. this.loading = false
  668. this.$message.error('请求失败')
  669. })
  670. },
  671. sizeChangeHandle(val) {
  672. this.pageSize = val
  673. this.pageIndex = 1
  674. this.getList()
  675. },
  676. currentChangeHandle(val) {
  677. this.pageIndex = val
  678. this.getList()
  679. },
  680. selectInquiry(row) {
  681. this.currentInquiry = row
  682. this.loadMaterialList(row.orderNo)
  683. },
  684. //加载税率列表
  685. getTaxList() {
  686. this.taxLoading = true
  687. searchTaxList({
  688. site: this.$store.state.user.site
  689. }).then(({data}) => {
  690. if (data.code === 0) {
  691. this.taxList = data.rows || []
  692. } else {
  693. this.taxList = []
  694. }
  695. this.taxLoading = false
  696. }).catch(() => {
  697. this.taxList = []
  698. this.taxLoading = false
  699. this.$message.error('获取税率列表失败')
  700. })
  701. },
  702. //加载货币列表
  703. getCurrencyList() {
  704. this.currencyLoading = true
  705. searchCurrencyList({
  706. site: this.$store.state.user.site
  707. }).then(({data}) => {
  708. if (data.code === 0) {
  709. this.currencyList = data.rows || []
  710. } else {
  711. this.currencyList = []
  712. }
  713. this.currencyLoading = false
  714. }).catch(() => {
  715. this.currencyList = []
  716. this.currencyLoading = false
  717. this.$message.error('获取货币列表失败')
  718. })
  719. },
  720. //加载付款方式列表
  721. getPamentList() {
  722. this.pamentLoading = true
  723. searchPaymentList({
  724. site: this.$store.state.user.site
  725. }).then(({data}) => {
  726. if (data.code === 0) {
  727. this.paymentList = data.rows || []
  728. } else {
  729. this.paymentList = []
  730. }
  731. this.pamentLoading = false
  732. }).catch(() => {
  733. this.paymentList = []
  734. this.pamentLoading = false
  735. this.$message.error('获取付款方式列表失败')
  736. })
  737. },
  738. //加载交易条款列表
  739. getDeliveryList() {
  740. this.deliveryLoading = true
  741. searchDeliveryList({
  742. site: this.$store.state.user.site
  743. }).then(({data}) => {
  744. if (data.code === 0) {
  745. this.deliveryList = data.rows || []
  746. } else {
  747. this.deliveryList = []
  748. }
  749. this.deliveryLoading = false
  750. }).catch(() => {
  751. this.deliveryList = []
  752. this.deliveryLoading = false
  753. this.$message.error('获取交易条款列表失败')
  754. })
  755. },
  756. // 加载物料列表
  757. loadMaterialList(orderNo) {
  758. this.materialLoading = true
  759. searchMaterialList({ orderNo: orderNo }).then(({data}) => {
  760. if (data.code === 0) {
  761. this.materialList = data.rows || []
  762. } else {
  763. this.materialList = []
  764. }
  765. this.materialLoading = false
  766. }).catch(() => {
  767. this.materialList = []
  768. this.materialLoading = false
  769. this.$message.error('获取物料列表失败')
  770. })
  771. },
  772. openDialog(row) {
  773. if (row) {
  774. this.dialogTitle = '编辑询价单'
  775. this.editMode = true
  776. this.form = { ...row }
  777. } else {
  778. this.dialogTitle = '新增询价单'
  779. this.editMode = false
  780. const today = this.getTodayDate()
  781. this.form = {
  782. id: '',
  783. site: this.$store.state.user.site,
  784. orderNo: '',
  785. supplierId: '',
  786. supplierName: '',
  787. orderDate: today,
  788. wantReplyDate: today,
  789. userName: this.$store.state.user.name,
  790. buyer: '',
  791. paymentTermDesc: '',
  792. deliveryTermDesc: '',
  793. currency: '',
  794. currencyRate: 0,
  795. taxRate: 0,
  796. taxCode:'',
  797. otherCondition: '',
  798. phoneNo: '',
  799. faxNo: '',
  800. contact: '',
  801. remark: '',
  802. printed : "N",
  803. status: '已计划'
  804. }
  805. }
  806. this.dialogVisible = true
  807. },
  808. validateForm() {
  809. if (!this.form.supplierId) { this.$message.warning('供应商编码不能为空'); return false }
  810. if (!this.form.supplierName) { this.$message.warning('供应商名称不能为空'); return false }
  811. return true
  812. },
  813. getTodayDate() {
  814. const today = new Date()
  815. const year = today.getFullYear()
  816. const month = String(today.getMonth() + 1).padStart(2, '0')
  817. const day = String(today.getDate()).padStart(2, '0')
  818. return `${year}-${month}-${day}`
  819. },
  820. submitForm() {
  821. if (!this.validateForm()) return
  822. this.submitLoading = true
  823. const api = this.editMode ? updatePurHeader : createPurHeader
  824. api(this.form).then(({data}) => {
  825. if (data && data.code === 0) {
  826. this.$message.success('保存成功')
  827. this.dialogVisible = false
  828. this.getList()
  829. } else {
  830. this.$message.error((data && data.msg) || '保存失败')
  831. }
  832. }).catch(err => {
  833. this.$message.error('请求失败: ' + err.message)
  834. }).finally(() => {
  835. this.submitLoading = false
  836. })
  837. },
  838. handleDelete(row) {
  839. this.$confirm('确定删除询价单: ' + row.orderNo + ' ?', '提示', { type: 'warning' }).then(() => {
  840. deletePurHeader({ id: row.id }).then(({data}) => {
  841. if (data && data.code === 0) {
  842. this.$message.success('删除成功')
  843. this.getList()
  844. } else {
  845. this.$message.error((data && data.msg) || '删除失败')
  846. }
  847. }).catch(err => {
  848. this.$message.error('删除失败: ' + err.message)
  849. })
  850. }).catch(() => {})
  851. },
  852. updateQuoDetail(row) {
  853. this.$confirm('确定提交询价单: ' + row.orderNo + ' ?', '提示', { type: 'warning' }).then(() => {
  854. updatePurDetailStatus({
  855. orderNo: row.orderNo,
  856. site: row.site,
  857. status : "待报价",
  858. submitFlag : "Y"
  859. }).then(({data}) => {
  860. if (data && data.code === 0) {
  861. this.$message.success('提交成功')
  862. this.getList()
  863. } else {
  864. this.$message.error((data && data.msg) || '提交失败')
  865. }
  866. }).catch(err => {
  867. this.$message.error('提交失败: ' + err.message)
  868. })
  869. }).catch(() => {})
  870. },
  871. // 物料操作
  872. openMaterialDialog(row) {
  873. if (!this.currentInquiry) {
  874. this.$message.warning('请先选择一个询价单')
  875. return
  876. }
  877. if (row) {
  878. this.materialDialogTitle = '编辑物料'
  879. this.materialForm = { ...row }
  880. } else {
  881. this.materialDialogTitle = '新增物料'
  882. this.materialForm = {
  883. id: null,
  884. site: this.$store.state.user.site,
  885. partNo: '',
  886. partDesc: '',
  887. umid: '',
  888. spec: '',
  889. qty: 0,
  890. remark2: '',
  891. status: '待提交'
  892. }
  893. }
  894. this.materialDialogVisible = true
  895. },
  896. // 物料编码变化时触发,自动带出物料信息
  897. handlePartNoChange(val) {
  898. if (!val || val.trim() === '') {
  899. return
  900. }
  901. // 假设有一个 getPartInfo 接口
  902. this.getPartInfo()
  903. },
  904. getPartInfo(){
  905. // 调用物料信息查询接口
  906. const params = {
  907. site: this.$store.state.user.site,
  908. partNo: this.materialForm.partNo
  909. }
  910. searchPartInfo(params).then(({data}) => {
  911. console.log(data)
  912. if (data.code === 0) {
  913. // 自动填充物料相关信息
  914. this.materialForm.partNo = data.data.partNo || val
  915. this.materialForm.partDesc = data.data.partDesc || this.materialForm.partDesc
  916. this.materialForm.spec = data.data.partSpec || this.materialForm.spec
  917. this.materialForm.umid = data.data.unit || this.materialForm.umid
  918. this.$message.success('已自动获取物料信息')
  919. } else {
  920. this.$message.warning('未找到该物料信息,请手动填写')
  921. }
  922. }).catch(() => {
  923. this.$message.error('获取物料信息失败')
  924. })
  925. },
  926. saveMaterial() {
  927. if (!this.materialForm.partNo) {
  928. this.$message.warning('物料编码不能为空')
  929. return
  930. }
  931. if (!this.materialForm.partDesc) {
  932. this.$message.warning('物料名称不能为空')
  933. return
  934. }
  935. if(!this.materialForm.umid){
  936. this.$message.warning('请选择计量单位')
  937. return
  938. }
  939. if(this.materialForm.qty <= 0){
  940. this.$message.warning('请选择询价数量')
  941. return
  942. }
  943. this.materialSubmitLoading = true
  944. const submitData = {
  945. ...this.materialForm,
  946. orderNo: this.currentInquiry.orderNo
  947. }
  948. const api = this.materialForm.id ? updateMaterial : createMaterial
  949. api(submitData).then(({data}) => {
  950. if (data && data.code === 0) {
  951. this.$message.success('保存成功')
  952. this.materialDialogVisible = false
  953. this.loadMaterialList(this.currentInquiry.orderNo)
  954. } else {
  955. this.$message.error((data && data.msg) || '保存失败')
  956. }
  957. }).catch(err => {
  958. this.$message.error('保存失败: ' + err.message)
  959. }).finally(() => {
  960. this.materialSubmitLoading = false
  961. })
  962. },
  963. deleteMaterial(row) {
  964. this.$confirm('确定删除物料: ' + row.partNo + ' ?', '提示', { type: 'warning' }).then(() => {
  965. deleteMaterial({ id: row.id }).then(({data}) => {
  966. if (data && data.code === 0) {
  967. this.$message.success('删除成功')
  968. this.loadMaterialList(this.currentInquiry.orderNo)
  969. } else {
  970. this.$message.error((data && data.msg) || '删除失败')
  971. }
  972. }).catch(err => {
  973. this.$message.error('删除失败: ' + err.message)
  974. })
  975. }).catch(() => {})
  976. },
  977. openUploadDialog(row) {
  978. if (!row) {
  979. this.$message.warning('请先选择一个物料')
  980. return
  981. }
  982. if (row) {
  983. this.uploadDialogTitle = '上传附件'
  984. this.searchParams = {
  985. orderRef1: this.$store.state.user.site,
  986. orderRef2: row.orderNo,
  987. orderRef3: row.partNo,
  988. orderReftype: 'purQuotationDetail'
  989. }
  990. }
  991. this.uploadDialogVisible = true
  992. this.searchTable()
  993. },
  994. // 关闭弹窗
  995. handleClose() {
  996. this.$emit('update:visible', false);
  997. this.$emit('close');
  998. },
  999. // 关闭上传弹窗
  1000. handleUploadClose() {
  1001. this.fileList2 = [];
  1002. this.ossForm.remark = '';
  1003. },
  1004. // 查询文件列表
  1005. searchTable() {
  1006. queryOssFilePlus(this.searchParams).then(({ data }) => {
  1007. if (data && data.code == 0) {
  1008. this.fileList = data.rows || [];
  1009. } else {
  1010. this.fileList = [];
  1011. }
  1012. }).catch(() => {
  1013. this.fileList = [];
  1014. });
  1015. },
  1016. // 打开上传弹窗
  1017. handleUpload() {
  1018. this.$nextTick(() => {
  1019. if (this.$refs.upload) {
  1020. this.$refs.upload.clearFiles();
  1021. }
  1022. })
  1023. this.fileList2 = [];
  1024. this.ossForm.remark = '';
  1025. this.ossVisible = true;
  1026. },
  1027. onRemoveFile(file, fileList) {
  1028. this.fileList2 = fileList;
  1029. },
  1030. onChangeFile(file, fileList) {
  1031. this.fileList2 = fileList;
  1032. },
  1033. // 提交上传
  1034. submitData() {
  1035. if (this.fileList2.length === 0) {
  1036. this.$message.error('请选择文件');
  1037. return;
  1038. }
  1039. this.stagedFileRemark = this.ossForm.remark || '';
  1040. this.uploadLoading = true;
  1041. // 准备要上传的文件
  1042. const stagedFiles = [];
  1043. for (let i = 0; i < this.fileList2.length; i++) {
  1044. stagedFiles.push(this.fileList2[i].raw);
  1045. }
  1046. // 立即关闭弹窗
  1047. this.ossVisible = false;
  1048. this.fileList2 = [];
  1049. this.ossForm.remark = '';
  1050. // 上传文件
  1051. const formData = new FormData();
  1052. for (let i = 0; i < stagedFiles.length; i++) {
  1053. formData.append('file', stagedFiles[i]);
  1054. }
  1055. formData.append('orderRef1', this.searchParams.orderRef1 || '');
  1056. formData.append('orderRef2', this.searchParams.orderRef2 || '');
  1057. formData.append('orderRef3', this.searchParams.orderRef3 || '');
  1058. formData.append('createdBy', this.$store.state.user.name);
  1059. formData.append('fileRemark', this.stagedFileRemark || '');
  1060. formData.append('orderReftype', this.searchParams.orderReftype || 'purQuotationDetail');
  1061. ossUploadNoSaveOSSForYJY(formData)
  1062. .then(({ data }) => {
  1063. if (data && data.code === 0) {
  1064. // 移除临时文件,添加上传成功的文件
  1065. this.fileList = this.fileList.filter(f => !f._staged);
  1066. for (let i = 0; i < data.rows.length; i++) {
  1067. this.fileList.push(data.rows[i]);
  1068. }
  1069. // 清除暂存数据
  1070. this.stagedFiles = [];
  1071. this.stagedFileRemark = '';
  1072. this.uploadLoading = false;
  1073. this.$message.success('上传成功');
  1074. this.$emit('upload-success', data.rows);
  1075. } else {
  1076. this.uploadLoading = false;
  1077. this.$message.warning(data.msg || '文件上传失败');
  1078. }
  1079. })
  1080. .catch(err => {
  1081. this.uploadLoading = false;
  1082. this.$message.error(err.message || err);
  1083. });
  1084. },
  1085. // 下载/预览文件
  1086. handleDownload(row) {
  1087. let image = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
  1088. let video = ['mp4', 'avi', 'mov', 'wmv', 'flv'];
  1089. let office = ['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'];
  1090. let txt = ['txt'];
  1091. let pdf = ['pdf'];
  1092. let type = '';
  1093. if (image.includes(row.fileType.toLowerCase())) {
  1094. type = 'image/' + row.fileType;
  1095. downLoadObjectFile(row).then(({ data }) => {
  1096. const blob = new Blob([data], { type: type });
  1097. const fileURL = URL.createObjectURL(blob);
  1098. window.open(fileURL, '_blank');
  1099. });
  1100. } else if (video.includes(row.fileType.toLowerCase())) {
  1101. type = 'video/' + row.fileType;
  1102. downLoadObjectFile(row).then(({ data }) => {
  1103. const blob = new Blob([data], { type: type });
  1104. const fileURL = URL.createObjectURL(blob);
  1105. window.open(fileURL, '_blank');
  1106. });
  1107. } else if (txt.includes(row.fileType.toLowerCase())) {
  1108. type = 'text/plain';
  1109. downLoadObjectFile(row).then(({ data }) => {
  1110. const blob = new Blob([data], { type: type });
  1111. const fileURL = URL.createObjectURL(blob);
  1112. window.open(fileURL, '_blank');
  1113. });
  1114. } else if (office.includes(row.fileType.toLowerCase())) {
  1115. if (row.fileType.toLowerCase() === 'doc' || row.fileType.toLowerCase() === 'docx') {
  1116. type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
  1117. } else if (row.fileType.toLowerCase() === 'ppt' || row.fileType.toLowerCase() === 'pptx') {
  1118. type = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
  1119. } else {
  1120. type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  1121. }
  1122. downLoadObjectFile(row).then(({ data }) => {
  1123. const blob = new Blob([data], { type: 'application/octet-stream;charset=utf-8' });
  1124. const fileName = row.fileName;
  1125. const linkNode = document.createElement('a');
  1126. linkNode.download = fileName;
  1127. linkNode.style.display = 'none';
  1128. linkNode.href = URL.createObjectURL(blob);
  1129. document.body.appendChild(linkNode);
  1130. linkNode.click();
  1131. URL.revokeObjectURL(linkNode.href);
  1132. document.body.removeChild(linkNode);
  1133. });
  1134. } else if (pdf.includes(row.fileType.toLowerCase())) {
  1135. type = 'application/pdf';
  1136. downLoadObjectFile(row).then(({ data }) => {
  1137. const blob = new Blob([data], { type: type });
  1138. const fileURL = URL.createObjectURL(blob);
  1139. window.open(fileURL, '_blank');
  1140. });
  1141. } else {
  1142. this.$message({
  1143. message: '不支持的文件类型',
  1144. type: 'warning'
  1145. });
  1146. }
  1147. },
  1148. // 删除已保存的文件
  1149. deleteFileReal(row) {
  1150. if (!row || !row.id) return;
  1151. this.$confirm('确定要删除该文件吗?', '删除确认', {
  1152. confirmButtonText: '确定',
  1153. cancelButtonText: '取消',
  1154. type: 'warning'
  1155. }).then(() => {
  1156. removeOss([row.id]).then(({ data }) => {
  1157. if (data && data.code === 0) {
  1158. const idx = this.fileList.findIndex(f => f.id === row.id);
  1159. if (idx !== -1) this.fileList.splice(idx, 1);
  1160. this.$message.success(data.msg || '文件已删除');
  1161. this.$emit('delete-success', row);
  1162. } else {
  1163. this.$message.warning(data.msg || '删除失败');
  1164. }
  1165. }).catch(err => {
  1166. this.$message.error('删除失败:' + (err.message || err));
  1167. });
  1168. }).catch(() => { });
  1169. },
  1170. // 删除临时文件
  1171. deleteFile(index) {
  1172. const f = this.fileList[index];
  1173. if (f && f._staged && f.raw) {
  1174. const idx = this.stagedFiles.findIndex(sf => sf.name === f.raw.name && sf.size === f.raw.size);
  1175. if (idx !== -1) this.stagedFiles.splice(idx, 1);
  1176. }
  1177. this.fileList.splice(index, 1);
  1178. },
  1179. // 刷新列表
  1180. refresh() {
  1181. this.searchTable();
  1182. }
  1183. }
  1184. }
  1185. </script>
  1186. <style scoped>
  1187. .pi-search-form { margin-top:0; }
  1188. .pi-form { margin-top:-5px; }
  1189. .customer-a {
  1190. color: #409EFF;
  1191. cursor: pointer;
  1192. text-decoration: none;
  1193. }
  1194. .customer-a:hover {
  1195. text-decoration: underline;
  1196. }
  1197. .customer-bun-min {
  1198. margin-right: 8px;
  1199. }
  1200. .sub-title {
  1201. font-weight: 600;
  1202. margin: 16px 0 8px 0;
  1203. padding-left: 4px;
  1204. border-left: 4px solid #409eff;
  1205. line-height: 1.2;
  1206. color: #303133;
  1207. }
  1208. .status-badge {
  1209. display: inline-block;
  1210. padding: 2px 8px;
  1211. border-radius: 4px;
  1212. font-size: 12px;
  1213. }
  1214. .status-sent { background-color: #e6f7ff; color: #409eff; }
  1215. .status-closed { background-color: #fef0e6; color: #e6a23c; }
  1216. .material-action-btn {
  1217. color: #409EFF;
  1218. cursor: pointer;
  1219. margin: 0 4px;
  1220. }
  1221. .material-action-btn:hover {
  1222. text-decoration: underline;
  1223. }
  1224. .dialog-footer {
  1225. text-align: center;
  1226. }
  1227. .rq .auto /deep/ .el-form-item__content {
  1228. height: auto;
  1229. line-height: 1.5;
  1230. }
  1231. </style>