quoted-price.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. <!-- 初始报价、精准报价 -->
  2. <template>
  3. <div>
  4. <div class="my-title">{{ title }}</div>
  5. <el-form
  6. :model="dataForm"
  7. :rules="dataRule"
  8. ref="dataForm"
  9. label-width="160px"
  10. >
  11. <el-row>
  12. <el-col :span="8">
  13. <el-form-item label="沟通信息" prop="coId">
  14. <el-select
  15. v-model="dataForm.coId"
  16. placeholder="请选择"
  17. style="width: 100%"
  18. disabled
  19. >
  20. <el-option
  21. v-for="item in coOption"
  22. :key="item.coId"
  23. :label="item.coCode + ' (' + item.customerName + ')'"
  24. :value="item.coId"
  25. >
  26. </el-option>
  27. </el-select>
  28. </el-form-item>
  29. </el-col>
  30. <el-col :span="8">
  31. <el-form-item label="项目名称" prop="projectName">
  32. <el-input
  33. v-model="dataForm.projectName"
  34. placeholder="项目名称"
  35. disabled
  36. ></el-input>
  37. </el-form-item>
  38. </el-col>
  39. <el-col :span="8">
  40. <el-form-item label="项目类别" prop="type">
  41. <el-select
  42. v-model="dataForm.type"
  43. placeholder="请选择"
  44. style="width: 100%"
  45. disabled
  46. >
  47. <el-option
  48. v-for="item in productTypeOption"
  49. :key="item.value"
  50. :label="item.label"
  51. :value="item.value"
  52. >
  53. </el-option>
  54. </el-select>
  55. </el-form-item>
  56. </el-col>
  57. </el-row>
  58. <el-row>
  59. <el-col :span="16">
  60. <el-form-item label="备注">
  61. <el-input
  62. v-model="dataForm.remark"
  63. type="textarea"
  64. placeholder="请输入备注"
  65. ></el-input>
  66. </el-form-item>
  67. </el-col>
  68. </el-row>
  69. <el-row>
  70. <el-col :span="8">
  71. <el-form-item label="关联BOM物料清单" prop="productId">
  72. <el-select
  73. v-model="dataForm.productId"
  74. remote
  75. filterable
  76. clearable
  77. :remote-method="productIdQueryHandle"
  78. :loading="productSearchLoading"
  79. @change="productIdChangeHandle"
  80. placeholder="请选择"
  81. style="width: 100%"
  82. disabled
  83. >
  84. <el-option
  85. v-for="item in productIdOption"
  86. :key="item.value"
  87. :label="item.label"
  88. :value="item.value"
  89. >
  90. </el-option>
  91. </el-select>
  92. </el-form-item>
  93. </el-col>
  94. </el-row>
  95. <div>
  96. <div class="title">BOM物料明细报价</div>
  97. <el-row>
  98. <el-table :data="dataForm.quotedPriceProductList" border style="width: 100%">
  99. <el-table-column
  100. label="序号"
  101. type="index"
  102. width="50"
  103. align="center"
  104. >
  105. </el-table-column>
  106. <el-table-column
  107. prop="productName"
  108. header-align="center"
  109. align="center"
  110. :show-tooltip-when-overflow="true"
  111. label="物料名称"
  112. >
  113. </el-table-column>
  114. <el-table-column
  115. prop="productSpec"
  116. header-align="center"
  117. align="center"
  118. :show-tooltip-when-overflow="true"
  119. label="物料规格"
  120. >
  121. </el-table-column>
  122. <el-table-column
  123. prop="mapNumber"
  124. header-align="center"
  125. align="center"
  126. :show-tooltip-when-overflow="true"
  127. label="主图号"
  128. >
  129. </el-table-column>
  130. <el-table-column
  131. prop="materials"
  132. header-align="center"
  133. align="center"
  134. :show-tooltip-when-overflow="true"
  135. label="材料"
  136. >
  137. </el-table-column>
  138. <el-table-column
  139. prop="cnt"
  140. header-align="center"
  141. align="center"
  142. :show-tooltip-when-overflow="true"
  143. label="单套数量"
  144. >
  145. </el-table-column>
  146. <el-table-column
  147. prop="unit"
  148. header-align="center"
  149. align="center"
  150. :show-tooltip-when-overflow="true"
  151. label="单位"
  152. >
  153. </el-table-column>
  154. <el-table-column
  155. prop="size"
  156. header-align="center"
  157. align="center"
  158. :show-tooltip-when-overflow="true"
  159. label="物料尺寸"
  160. >
  161. </el-table-column>
  162. <el-table-column
  163. prop="developedSize"
  164. header-align="center"
  165. align="center"
  166. :show-tooltip-when-overflow="true"
  167. label="展开尺寸"
  168. >
  169. </el-table-column>
  170. <el-table-column
  171. prop="surfaceTreatment"
  172. header-align="center"
  173. align="center"
  174. :show-tooltip-when-overflow="true"
  175. label="表面处理"
  176. >
  177. </el-table-column>
  178. <el-table-column
  179. prop="notes"
  180. header-align="center"
  181. align="center"
  182. :show-tooltip-when-overflow="true"
  183. label="备注"
  184. >
  185. </el-table-column>
  186. <!-- 初次报价 -->
  187. <div v-if="type === 'first'">
  188. <el-table-column
  189. prop="notes"
  190. header-align="center"
  191. align="center"
  192. min-width="160px"
  193. fixed="right"
  194. label="原材料费"
  195. >
  196. <template slot-scope="scope">
  197. <el-input-number size="mini" :precision=2 :controls=false placeholder="请输入" v-model="scope.row.materialPrice" @change="inputNumChangeHandle"></el-input-number>
  198. </template>
  199. </el-table-column>
  200. <el-table-column
  201. prop="notes"
  202. header-align="center"
  203. align="center"
  204. min-width="160px"
  205. fixed="right"
  206. label="生产加工费"
  207. >
  208. <template slot-scope="scope">
  209. <el-input-number size="mini" :precision=2 :controls=false placeholder="请输入" v-model="scope.row.processPrice" @change="inputNumChangeHandle"></el-input-number>
  210. </template>
  211. </el-table-column>
  212. <el-table-column
  213. prop="notes"
  214. header-align="center"
  215. align="center"
  216. min-width="160px"
  217. fixed="right"
  218. label="热表处理费"
  219. >
  220. <template slot-scope="scope">
  221. <el-input-number size="mini" :precision=2 :controls=false placeholder="请输入" v-model="scope.row.handlePrice" @change="inputNumChangeHandle"></el-input-number>
  222. </template>
  223. </el-table-column>
  224. </div>
  225. </el-table>
  226. </el-row>
  227. <div v-if="type === 'first'" style="margin: 25px 0 0 0">
  228. <el-row>
  229. <el-col :span="8" :offset="16">
  230. <el-form-item label="小计">
  231. <el-input-number v-model="dataForm.materialCost" disabled :precision=2 :controls=false></el-input-number>
  232. </el-form-item>
  233. </el-col>
  234. </el-row>
  235. <el-row>
  236. <el-col :span="8" :offset="16">
  237. <el-form-item label="模具费">
  238. <el-input-number v-model="dataForm.mouldPrice" @change="inputNumChangeHandle" :precision=2 :controls=false placeholder="请输入"></el-input-number>
  239. </el-form-item>
  240. </el-col>
  241. </el-row>
  242. <el-row>
  243. <el-col :span="8" :offset="16">
  244. <el-form-item label="管理费(%)">
  245. <el-input-number v-model="dataForm.managePrice" @change="inputNumChangeHandle" :precision=0 :controls=false placeholder="请输入"></el-input-number>
  246. </el-form-item>
  247. </el-col>
  248. </el-row>
  249. <el-row>
  250. <el-col :span="8" :offset="16">
  251. <el-form-item label="税率(%)">
  252. <el-input-number v-model="dataForm.ratePrice" @change="inputNumChangeHandle" :precision=0 :controls=false></el-input-number>
  253. </el-form-item>
  254. </el-col>
  255. </el-row>
  256. <el-row>
  257. <el-col :span="8" :offset="16">
  258. <el-form-item label="合计">
  259. <el-input-number v-model="dataForm.totalPrice" disabled :precision=2 :controls=false></el-input-number>
  260. </el-form-item>
  261. </el-col>
  262. </el-row>
  263. </div>
  264. </div>
  265. <div>
  266. <div class="title"><span style="color: red">* </span>任务工单派发</div>
  267. <el-row>
  268. <el-table :data="dataForm.workInfoList" border style="width: 100%">
  269. <el-table-column
  270. label="序号"
  271. type="index"
  272. width="50"
  273. align="center"
  274. >
  275. </el-table-column>
  276. <el-table-column
  277. prop="taskType"
  278. header-align="center"
  279. align="center"
  280. min-width="100"
  281. width="120"
  282. label="工单类型"
  283. >
  284. <template slot-scope="scope">
  285. <span>{{
  286. taskTypeOption.findIndex(
  287. (t) => t.value == scope.row.taskType
  288. ) > -1
  289. ? taskTypeOption.find((t) => t.value == scope.row.taskType)
  290. .label
  291. : ""
  292. }}</span>
  293. </template>
  294. </el-table-column>
  295. <el-table-column
  296. prop="taskName"
  297. header-align="center"
  298. align="center"
  299. :show-tooltip-when-overflow="true"
  300. label="工单名称"
  301. >
  302. </el-table-column>
  303. <el-table-column
  304. prop="ranks"
  305. header-align="center"
  306. align="center"
  307. width="120"
  308. label="级别"
  309. >
  310. <template slot-scope="scope">
  311. <span>{{
  312. rankTypeOption.findIndex((t) => t.value == scope.row.ranks) >
  313. -1
  314. ? rankTypeOption.find((t) => t.value == scope.row.ranks)
  315. .label
  316. : ""
  317. }}</span>
  318. </template>
  319. </el-table-column>
  320. <el-table-column
  321. prop="content"
  322. header-align="center"
  323. align="center"
  324. min-width="100"
  325. label="工单内容"
  326. :show-tooltip-when-overflow="true"
  327. >
  328. </el-table-column>
  329. <el-table-column
  330. prop="receiver"
  331. header-align="center"
  332. align="center"
  333. width="150"
  334. label="任务接收人"
  335. >
  336. <template slot-scope="scope">
  337. <span>{{ scope.row.receiverName }}</span>
  338. </template>
  339. </el-table-column>
  340. <el-table-column
  341. prop="attachListVo"
  342. header-align="center"
  343. align="center"
  344. width="150"
  345. label="任务附件"
  346. >
  347. <template slot-scope="scope">
  348. <el-button
  349. :disabled="
  350. !scope.row.attachList || scope.row.attachList.length === 0
  351. "
  352. type="text"
  353. size="small"
  354. @click="attachDetails(scope.row.attachList)"
  355. >查看</el-button
  356. >
  357. </template>
  358. </el-table-column>
  359. <el-table-column
  360. prop="notes"
  361. header-align="center"
  362. align="center"
  363. :show-tooltip-when-overflow="true"
  364. label="备注"
  365. >
  366. </el-table-column>
  367. <el-table-column
  368. fixed="right"
  369. header-align="center"
  370. align="center"
  371. width="100"
  372. label="操作"
  373. >
  374. <template slot-scope="scope">
  375. <el-button
  376. type="text"
  377. size="small"
  378. @click="updateWorderHandle(scope.row)"
  379. >编辑</el-button
  380. >
  381. <el-button
  382. style="color: red"
  383. type="text"
  384. size="small"
  385. @click="removeWorkInfoItem(scope.$index)"
  386. >删除</el-button
  387. >
  388. </template>
  389. </el-table-column>
  390. </el-table>
  391. </el-row>
  392. <el-row style="text-align: center; margin-top: 10px">
  393. <el-button
  394. type="primary"
  395. icon="el-icon-plus"
  396. @click="inBound"
  397. disabled
  398. ></el-button>
  399. </el-row>
  400. </div>
  401. </el-form>
  402. <span slot="footer" class="dialog-footer">
  403. <el-button @click="onChose">取消</el-button>
  404. <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
  405. </span>
  406. <worder-add-or-update-dialog
  407. v-if="worderVisible"
  408. ref="worder"
  409. @submit="addWorderItem"
  410. />
  411. <attach-detail-dialog ref="attachDetail" @onChose="onChose" />
  412. </div>
  413. </template>
  414. <script>
  415. import { getCoCode } from '@/api/cus'
  416. import { getProductList, getProductAllDetail } from '@/api/product'
  417. import { getDetail } from '@/api/quoted'
  418. import {
  419. productTypeOption,
  420. taskTypeOption,
  421. rankTypeOption
  422. } from '@/utils/enums'
  423. import WorderAddOrUpdateDialog from '../worder/add-or-update-dialog'
  424. import AttachDetailDialog from '../common/attach-detail-dialog'
  425. export default {
  426. name: 'quoted-add-or-update',
  427. components: { WorderAddOrUpdateDialog, AttachDetailDialog },
  428. props: {},
  429. data () {
  430. return {
  431. id: 0,
  432. type: '',
  433. title: '',
  434. worderVisible: false,
  435. coOption: [], // 沟通编码下拉数据
  436. productTypeOption: productTypeOption,
  437. taskTypeOption: taskTypeOption,
  438. rankTypeOption: rankTypeOption,
  439. productIdOption: [], // 物料下拉数据
  440. productId: '', // 当前选择的物料Id
  441. productList: [], // 物料table
  442. productSearchLoading: false,
  443. dataForm: {
  444. materialCost: 0,
  445. quotedPriceProductList: [], // 报价物料清单
  446. workInfoList: []
  447. },
  448. dataRule: {
  449. coId: [
  450. { required: true, message: '请选择沟通信息', trigger: 'change' }
  451. ],
  452. projectName: [
  453. { required: true, message: '请输入项目名称', trigger: 'blur' }
  454. ],
  455. type: [
  456. { required: true, message: '请选择项目类别', trigger: 'change' }
  457. ],
  458. productId: [
  459. {
  460. required: true,
  461. message: '请选择关联的物料清单',
  462. trigger: 'change'
  463. }
  464. ]
  465. }
  466. }
  467. },
  468. watch: {},
  469. computed: {},
  470. created () {
  471. },
  472. mounted () {},
  473. activated () {},
  474. methods: {
  475. async init (id, type) {
  476. this.id = id || 0
  477. this.type = type
  478. this.setTitle(type)
  479. await this.getCoCode()
  480. await this.getProductList()
  481. if (this.id) {
  482. this.getDetail(this.id)
  483. }
  484. },
  485. onChose () {
  486. this.worderVisible = false
  487. this.$emit('onChose')
  488. },
  489. setTitle (type) {
  490. if (type === 'first') {
  491. this.title = '初次报价'
  492. } else if (type === 'second') {
  493. this.title = '精准报价'
  494. }
  495. },
  496. getDetail (priceId) {
  497. getDetail(priceId).then(({ data }) => {
  498. if (data && data.code === '200') {
  499. this.dataForm = data.data
  500. if (this.dataForm.managePrice) {
  501. this.dataForm.managePrice = this.dataForm.managePrice * 100
  502. }
  503. if (this.dataForm.ratePrice) {
  504. this.dataForm.ratePrice = this.dataForm.ratePrice * 100
  505. }
  506. if (this.dataForm.productId) {
  507. this.productIdChangeHandle(this.dataForm.productId)
  508. }
  509. }
  510. })
  511. },
  512. getCoCode () {
  513. getCoCode().then(({ data }) => {
  514. if (data && data.code === '200') {
  515. this.coOption = data.data
  516. }
  517. })
  518. },
  519. async getProductList (productName) {
  520. let params = {
  521. current: 1,
  522. size: 20,
  523. productName: productName
  524. }
  525. await getProductList(params).then(({ data }) => {
  526. if (data && data.code === '200') {
  527. this.productIdOption = []
  528. data.data.records.forEach((item) => {
  529. this.productIdOption.push({
  530. label: item.productName,
  531. value: item.productId
  532. })
  533. })
  534. }
  535. })
  536. },
  537. async productIdQueryHandle (queryVal) {
  538. this.productSearchLoading = true
  539. await this.getProductList(queryVal)
  540. this.productSearchLoading = false
  541. },
  542. productIdChangeHandle (val) {
  543. if (val) {
  544. getProductAllDetail(val).then(({ data }) => {
  545. if (data && data.code === '200') {
  546. this.productList = data.data
  547. if (this.dataForm.quotedPriceProductList == null || this.dataForm.quotedPriceProductList.length === 0) {
  548. this.productList.forEach((item) => {
  549. this.dataForm.quotedPriceProductList.push({
  550. productId: item.productId
  551. })
  552. item.id = this.dataForm.quotedPriceProductList.find(t => t.productId === item.productId).id
  553. })
  554. } else {
  555. this.dataForm.quotedPriceProductList.forEach(item => {
  556. let tempItem = this.productList.find(t => t.productId === item.productId)
  557. if (tempItem) {
  558. item.productName = tempItem.productName
  559. item.productSpec = tempItem.productSpec
  560. item.mapNumber = tempItem.mapNumber
  561. item.materials = tempItem.materials
  562. item.cnt = tempItem.cnt
  563. item.unit = tempItem.unit
  564. item.size = tempItem.size
  565. item.developedSize = tempItem.developedSize
  566. item.surfaceTreatment = tempItem.surfaceTreatment
  567. item.notes = tempItem.notes
  568. }
  569. })
  570. }
  571. // 触发自动计算
  572. this.inputNumChangeHandle()
  573. }
  574. })
  575. } else {
  576. this.productList = []
  577. }
  578. },
  579. removeWorkInfoItem (index) {
  580. this.dataForm.workInfoList.splice(index, 1)
  581. },
  582. inBound () {
  583. this.worderVisible = true
  584. this.$nextTick(() => {
  585. this.$refs.worder.init(1)
  586. })
  587. },
  588. addWorderItem (item) {
  589. if (!item.recordId) {
  590. item.recordId = Math.round(Math.random() * 1000000)
  591. }
  592. if (
  593. this.dataForm.workInfoList.findIndex(
  594. (item1) => item1.recordId === item.recordId
  595. ) === -1
  596. ) {
  597. this.dataForm.workInfoList.push({
  598. ...item
  599. })
  600. }
  601. },
  602. updateWorderHandle (row) {
  603. this.worderVisible = true
  604. this.$nextTick(() => {
  605. this.$refs.worder.init(1, row)
  606. })
  607. },
  608. attachDetails (attachList) {
  609. this.$refs.attachDetail.init(attachList)
  610. },
  611. inputNumChangeHandle (currentValue, oldValue) {
  612. // 计算报价小计
  613. let tempMaterialCost = 0
  614. this.dataForm.quotedPriceProductList.forEach(item => {
  615. tempMaterialCost += item.handlePrice + item.materialPrice + item.processPrice
  616. })
  617. this.dataForm.materialCost = tempMaterialCost
  618. // 计算总价
  619. this.dataForm.totalPrice = (tempMaterialCost + this.dataForm.mouldPrice) * (1 + this.dataForm.managePrice / 100) * (1 + this.dataForm.ratePrice / 100)
  620. },
  621. dataFormSubmit () {
  622. if (this.type === 'first') {
  623. this.first()
  624. }
  625. },
  626. // 初次报价
  627. first () {
  628. this.$refs['dataForm'].validate((valid) => {
  629. if (valid) {
  630. let param = {
  631. priceId: this.dataForm.priceId,
  632. remark: this.dataForm.remark,
  633. managePrice: this.dataForm.managePrice / 100,
  634. mouldPrice: this.dataForm.mouldPrice,
  635. ratePrice: this.dataForm.ratePrice / 100,
  636. materialCost: this.dataForm.materialCost,
  637. totalPrice: this.dataForm.totalPrice,
  638. quotedPriceProductFirstParamsList: this.dataForm.quotedPriceProductList.map(item => {
  639. let temp = {
  640. id: item.id,
  641. priceId: this.id,
  642. productId: item.productId,
  643. materialPrice: item.materialPrice,
  644. processPrice: item.processPrice,
  645. handlePrice: item.handlePrice
  646. }
  647. return temp
  648. })
  649. }
  650. this.$http({
  651. url: this.$http.adornUrl(`/biz-service/quoted/updateFirst`),
  652. method: 'post',
  653. data: this.$http.adornData({ ...param, orgId: this.orgId })
  654. }).then(({ data }) => {
  655. if (data && data.code === '200') {
  656. this.$message({
  657. message: '操作成功',
  658. type: 'success',
  659. duration: 1500,
  660. onClose: () => {
  661. this.onChose()
  662. this.$emit('refreshDataList')
  663. }
  664. })
  665. } else {
  666. this.$message.error(data.msg)
  667. }
  668. })
  669. }
  670. })
  671. }
  672. }
  673. }
  674. </script>
  675. <style lang="scss" scoped>
  676. .title {
  677. padding: 10px 0;
  678. }
  679. /deep/ .my_input > .el-input__inner{
  680. text-align: center;
  681. }
  682. </style>